test: bundle fixture corpus + wire local-path test helpers

Adds inst/extdata/fixture_corpus/ — a 3.6 MB two-year (2019/2020) slice
of the published corpus (OH+VT+WY fixture from cog_pipeline test profile
plus all 50 states). Includes canonical_fips_xwalk.parquet,
summary_categories.parquet, docs/, and a trimmed manifest.json.

setup.R now points USCOGDATA_URL at the bundled fixture automatically,
bypassing HTTP / Nextcloud entirely. DuckDB reads local parquet via the
existing .is_local_path() fast-path in manifest.R; no httpfs required.
session is reset between test files via withr::defer(cog_close()).

helper-fixture.R gains fixture_corpus_path(), a richer skip_if_no_corpus()
that checks the bundled fixture first, and with_fixture_corpus() for
tests that need explicit session isolation.

test-spending.R: adjust the inflate-column test to use 2019 (fixture year)
instead of 2015 (absent from fixture).

Result: 181 PASS / 0 FAIL / 0 SKIP — all tests run against real parquet
data with real DuckDB queries and no network dependency.
This commit is contained in:
2026-04-27 12:48:58 -04:00
parent 488d03d74b
commit a640c9cc21
8 changed files with 126 additions and 10 deletions
+25 -3
View File
@@ -1,6 +1,28 @@
# tests/testthat/helper-fixture.R
# Returns the path to the bundled fixture corpus (trailing slash for DuckDB globs).
fixture_corpus_path <- function() {
p <- system.file("extdata/fixture_corpus", package = "uscogdata")
if (nzchar(p)) paste0(p, "/") else ""
}
# Skip a test if no corpus is reachable (bundled fixture or explicit remote URL).
skip_if_no_corpus <- function() {
testthat::skip_if(Sys.getenv("USCOGDATA_FIXTURE_URL", "") == "" &&
!file.exists("~/.cache/R/uscogdata/manifest.json"),
"No fixture corpus available")
p <- fixture_corpus_path()
has_fixture <- nzchar(p) && file.exists(sub("/$", "/manifest.json", p))
has_remote <- nzchar(Sys.getenv("USCOGDATA_FIXTURE_URL", ""))
testthat::skip_if(!has_fixture && !has_remote, "No fixture corpus available")
}
# Run a block against the fixture corpus with a clean session.
# Restores the previous URL and closes the DuckDB connection when done.
with_fixture_corpus <- function(code) {
old_url <- Sys.getenv("USCOGDATA_URL", unset = NA)
uscogdata:::cog_close()
Sys.setenv(USCOGDATA_URL = fixture_corpus_path())
on.exit({
uscogdata:::cog_close()
if (is.na(old_url)) Sys.unsetenv("USCOGDATA_URL") else Sys.setenv(USCOGDATA_URL = old_url)
}, add = TRUE)
force(code)
}
+12 -4
View File
@@ -1,5 +1,13 @@
# tests/testthat/setup.R
# Point tests at a fixture corpus URL if provided.
if (Sys.getenv("USCOGDATA_FIXTURE_URL", "") != "") {
options(uscogdata.url = Sys.getenv("USCOGDATA_FIXTURE_URL"))
}
# Priority: bundled fixture > USCOGDATA_FIXTURE_URL env var > whatever is already set.
local({
p <- system.file("extdata/fixture_corpus", package = "uscogdata")
if (nzchar(p) && file.exists(file.path(p, "manifest.json"))) {
Sys.setenv(USCOGDATA_URL = paste0(p, "/"))
} else if (nzchar(Sys.getenv("USCOGDATA_FIXTURE_URL", ""))) {
Sys.setenv(USCOGDATA_URL = Sys.getenv("USCOGDATA_FIXTURE_URL"))
}
})
# Reset DuckDB session between test files so each file starts clean.
withr::defer(uscogdata:::cog_close(), teardown_env())
+3 -3
View File
@@ -34,11 +34,11 @@ test_that("cog_spending with per_capita adds per-capita nominal column", {
test_that("cog_spending with adjust_to_year adds real column", {
skip_if_no_corpus()
r <- cog_spending("101006006", 2015:2020, "Corrections",
r <- cog_spending("101006006", 2019:2020, "Corrections",
adjust_to_year = 2022L)
expect_true("amt_real" %in% names(r))
r2015 <- dplyr::filter(r, year == 2015L)
expect_true(any(r2015$amt_nominal != r2015$amt_real))
r2019 <- dplyr::filter(r, year == 2019L)
expect_true(any(r2019$amt_nominal != r2019$amt_real))
})
test_that("cog_spending with per_capita + adjust_to_year adds all columns", {