Nothing
# Offline tests for read_datasus_dbc() using synthetic dBase III files built
# by make_dbf() (helper-dbf.R).
rd <- function(path, ...) read_datasus_dbc(path, verbose = FALSE, ...)
pad <- function(x, n) formatC(x, width = n, flag = "-")
padl <- function(x, n) formatC(x, width = n)
basic_fields <- list(
list(name = "NAME", type = "C", len = 5),
list(name = "CNT", type = "N", len = 4),
list(name = "VAL", type = "N", len = 6, dec = 2),
list(name = "RATE", type = "F", len = 6),
list(name = "DT", type = "D", len = 8),
list(name = "OK", type = "L", len = 1)
)
basic_records <- c(
paste0(" ", pad("ana", 5), padl("12", 4), padl("3.50", 6), padl("1.5", 6), "20240115", "T"),
paste0(" ", pad("bruno", 5), padl("-7", 4), padl("10.25", 6), padl("2", 6), "20231231", "F"),
paste0(" ", pad("", 5), padl("", 4), padl("", 6), padl("", 6), pad("", 8), "?")
)
test_that("happy path reads C/N/F/D/L fields with proper types", {
p <- make_dbf(basic_fields, basic_records)
x <- rd(p)
expect_s3_class(x, "tbl_df")
expect_equal(names(x), c("name", "cnt", "val", "rate", "dt", "ok"))
expect_equal(nrow(x), 3L)
expect_identical(x$name, c("ana", "bruno", ""))
expect_identical(x$cnt, c(12L, -7L, NA))
expect_identical(x$val, c(3.5, 10.25, NA))
expect_type(x$rate, "double")
expect_identical(x$rate, c(1.5, 2, NA))
expect_identical(x$dt, c("20240115", "20231231", ""))
expect_identical(x$ok, c(TRUE, FALSE, NA))
})
test_that("parse_dates, col_types, clean_names and n_max work", {
p <- make_dbf(basic_fields, basic_records)
x <- rd(p, parse_dates = TRUE)
expect_s3_class(x$dt, "Date")
expect_equal(x$dt, as.Date(c("2024-01-15", "2023-12-31", NA)))
x <- rd(p, col_types = c(cnt = "character", Val = "integer", dt = "date"))
expect_identical(x$cnt, c("12", "-7", ""))
expect_identical(x$val, c(NA_integer_, NA_integer_, NA_integer_))
expect_equal(x$dt, as.Date(c("2024-01-15", "2023-12-31", NA)))
x <- rd(p, clean_names = FALSE)
expect_equal(names(x), c("NAME", "CNT", "VAL", "RATE", "DT", "OK"))
x <- rd(p, n_max = 2)
expect_equal(nrow(x), 2L)
expect_identical(x$name, c("ana", "bruno"))
x <- rd(p, guess_types = FALSE)
expect_type(x$cnt, "integer")
expect_type(x$val, "double")
})
test_that("encoding is validated and aliases are accepted", {
f <- list(list(name = "TXT", type = "C", len = 4))
p <- make_dbf(f, " caf\xe9")
expect_identical(rd(p)$txt, "caf\u00e9")
expect_identical(rd(p, encoding = "ISO-8859-1")$txt, "caf\u00e9")
expect_identical(rd(p, encoding = "Latin-1")$txt, "caf\u00e9")
expect_identical(Encoding(rd(p, encoding = "LATIN1")$txt), "latin1")
expect_no_error(rd(p, encoding = "utf-8"))
expect_no_error(rd(p, encoding = "unknown"))
expect_error(rd(p, encoding = "CP1252"), "Unsupported")
expect_error(rd(p, encoding = "foo"), "Unsupported")
})
test_that("field lengths exceeding the record length are rejected (item 1)", {
f <- list(
list(name = "A", type = "C", len = 200),
list(name = "B", type = "C", len = 200)
)
# record_len declared as 11 but fields sum to 400
p <- make_dbf(f, strrep(" ", 11), record_len = 11L)
expect_error(rd(p), "exceed the declared record length")
f0 <- list(list(name = "A", type = "C", len = 0))
p0 <- make_dbf(f0, " ", record_len = 1L)
expect_error(rd(p0), "length 0")
fl <- list(list(name = "A", type = "L", len = 0), list(name = "B", type = "C", len = 2))
pl <- make_dbf(fl, " x", record_len = 3L)
expect_error(rd(pl), "length 0")
})
test_that("deleted records are skipped and n_max counts live records (item 4)", {
f <- list(list(name = "ID", type = "N", len = 3))
recs <- c("* 1", " 2", "* 3", " 4", " 5")
p <- make_dbf(f, recs)
expect_identical(rd(p)$id, c(2L, 4L, 5L))
expect_identical(rd(p, n_max = 2)$id, c(2L, 4L))
expect_identical(rd(p, n_max = 1)$id, 2L)
pall <- make_dbf(f, c("* 1", "* 2"))
x <- rd(pall)
expect_equal(nrow(x), 0L)
expect_named(x, "id")
})
test_that("integer overflow and INT_MIN fall back to double / NA (item 5)", {
f <- list(list(name = "N", type = "N", len = 12))
big <- make_dbf(f, c(paste0(" ", padl("2147483648", 12)), paste0(" ", padl("1", 12))))
x <- rd(big)
expect_type(x$n, "double")
expect_identical(x$n, c(2147483648, 1))
imin <- make_dbf(f, c(paste0(" ", padl("-2147483648", 12)), paste0(" ", padl("5", 12))))
x <- rd(imin)
expect_type(x$n, "double")
expect_identical(x$n, c(-2147483648, 5))
huge <- make_dbf(f, paste0(" ", padl("99999999999", 12)))
x <- rd(huge, col_types = c(N = "integer"))
expect_identical(x$n, NA_integer_)
x <- rd(imin, col_types = c(N = "integer"))
expect_identical(x$n, c(NA_integer_, 5L))
imax <- make_dbf(f, paste0(" ", padl("2147483647", 12)))
expect_identical(rd(imax)$n, 2147483647L)
})
test_that("trim_ws = FALSE only affects character fields (item 6)", {
f <- list(
list(name = "C", type = "C", len = 4),
list(name = "N", type = "N", len = 5),
list(name = "D", type = "N", len = 6, dec = 1),
list(name = "L", type = "L", len = 1),
list(name = "DT", type = "D", len = 10)
)
p <- make_dbf(f, paste0(" ", " ab ", "12 ", " 1.5 ", "T", " 20240229 "))
x <- rd(p, trim_ws = FALSE, parse_dates = TRUE)
expect_identical(x$c, " ab ")
expect_identical(x$n, 12L)
expect_identical(x$d, 1.5)
expect_identical(x$l, TRUE)
expect_equal(x$dt, as.Date("2024-02-29"))
x <- rd(p, trim_ws = TRUE)
expect_identical(x$c, "ab")
})
test_that("invalid calendar dates become NA (item 8)", {
f <- list(list(name = "DT", type = "D", len = 8))
p <- make_dbf(f, c(" 20240231", " 20230229", " 20240229", " 20000229",
" 19000229", " 20240431", " 20241231", " 2024130a"))
x <- rd(p, parse_dates = TRUE)
expect_equal(
x$dt,
as.Date(c(NA, NA, "2024-02-29", "2000-02-29", NA, NA, "2024-12-31", NA))
)
})
test_that("declared record count larger than data warns (item 10)", {
f <- list(list(name = "ID", type = "N", len = 3))
p <- make_dbf(f, c(" 1", " 2"), n_records = 5L)
expect_warning(x <- rd(p), "declares 5 records but only 2 are present")
expect_identical(x$id, c(1L, 2L))
})
test_that("select is case-insensitive and warns on unmatched names (item 11)", {
f <- list(
list(name = "Abc", type = "C", len = 2),
list(name = "XYZ", type = "C", len = 2)
)
p <- make_dbf(f, " aaxx")
x <- rd(p, select = "abc")
expect_named(x, "abc")
x <- rd(p, select = "ABC", clean_names = FALSE)
expect_named(x, "Abc")
expect_warning(x <- rd(p, select = c("xyz", "nope", "Other")), "nope")
expect_named(x, "xyz")
expect_no_warning(rd(p, select = c("xyz", "ABC")))
x <- rd(p, col_types = c(abc = "integer"))
expect_type(x$abc, "integer")
})
test_that("truncated plain DBF is read with a warning (item 12)", {
f <- list(list(name = "ID", type = "N", len = 3))
p <- make_dbf(f, c(" 1", " 2", " 3", " 4"))
raw <- readBin(p, "raw", file.info(p)$size)
# header (32 + 32 + 1 = 65 bytes) + 2.5 records, no EOF marker
cut <- tempfile(fileext = ".dbf")
writeBin(raw[seq_len(65 + 4 * 2 + 2)], cut)
expect_warning(x <- rd(cut), "declares 4 records but only 2 are present")
expect_identical(x$id, c(1L, 2L))
})
test_that("garbage input errors cleanly", {
junk <- tempfile(fileext = ".dbc")
writeBin(as.raw(c(0xFF, 0x00, 0x13, 0x37, 0x42)), junk)
expect_error(rd(junk))
expect_error(rd(tempfile()), "not found")
})
test_that("a tiny DBC whose payload exceeds the record area is still decompressed", {
# Literal-only PKWare DCL stream encoding one live record " X" (2 bytes):
# 8-bit literal flag (0), 8-bit dictionary size (4), one raw literal per
# byte (flag bit 0 + 8 data bits), then the end code (length 519).
bits <- c(as.integer(intToBits(0))[1:8], as.integer(intToBits(4))[1:8])
for (b in as.integer(charToRaw(" X"))) bits <- c(bits, 0L, as.integer(intToBits(b))[1:8])
bits <- c(bits, 1L, rep(0L, 7), rep(1L, 8))
bits <- c(bits, rep(0L, (-length(bits)) %% 8L))
payload <- as.raw(colSums(matrix(bits, nrow = 8) * 2^(0:7)))
expect_gt(length(payload), 2L) # compressed payload is larger than the record
plain <- make_dbf(list(list(name = "X", type = "C", len = 1)), " A")
hdr <- readBin(plain, "raw", 65L)
with_crc <- tempfile(fileext = ".dbc")
writeBin(c(hdr, raw(4), payload), with_crc)
expect_equal(read_datasus_dbc(with_crc, verbose = FALSE)$x, "X")
no_crc <- tempfile(fileext = ".dbc")
writeBin(c(hdr, payload), no_crc)
expect_equal(read_datasus_dbc(no_crc, verbose = FALSE)$x, "X")
})
test_that("n_max is floored to a whole number of rows", {
p <- make_dbf(list(list(name = "X", type = "C", len = 1)), c(" A", " B", " C"))
expect_equal(nrow(read_datasus_dbc(p, n_max = 1.5, verbose = FALSE)), 1L)
expect_equal(nrow(read_datasus_dbc(p, n_max = 2, verbose = FALSE)), 2L)
expect_error(read_datasus_dbc(p, n_max = 0.5, verbose = FALSE), "n_max")
})
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.