# test-download.R # Tests for download_wid(), wid_query(), wid_filter(), wid_fetch(), and cache. # ── new_wid_df / print ──────────────────────────────────────────────────────── test_that("new_wid_df attaches correct class", { df <- data.frame(country = "US", variable = "sptinc992j", percentile = "p99p100", year = "2000", value = 0.2, age = "992", pop = "j", stringsAsFactors = FALSE) out <- widr:::new_wid_df(df) expect_s3_class(out, "wid_df") expect_s3_class(out, "data.frame") }) test_that("print.wid_df emits header", { expect_output(print(.wid()), "") }) test_that("wid_df passes through tidyverse-style subset", { d <- .wid(3L) expect_s3_class(d[d$year == "2020", ], "data.frame") }) # ── download_wid argument validation ───────────────────────────────────────── test_that("download_wid errors when both indicators and areas are 'all'", { expect_error(download_wid(), "`indicators` or `areas`") expect_error(download_wid(indicators = "all", areas = "all"), "`indicators` or `areas`") }) test_that("download_wid warns on years outside [1800, 2100]", { testthat::with_mocked_bindings( `.cache` = function(a, ...) NULL, `.fetch` = function(...) NULL, { expect_warning( download_wid("sptinc992j", areas = "US", years = 1700L, cache = FALSE), "outside" ) } ) }) test_that("download_wid warns on malformed area codes", { testthat::with_mocked_bindings( `.cache` = function(a, ...) NULL, `.fetch` = function(...) NULL, { expect_warning( download_wid("sptinc992j", areas = "us", cache = FALSE), "invalid" ) } ) }) test_that("download_wid normalises ages != 'all'", { captured <- list() testthat::with_mocked_bindings( `.cache` = function(a, ...) NULL, `.fetch` = function(indicators, areas, perc, ages, pop, no_extrapolation, verbose) { captured$ages <<- ages .wid() }, { download_wid("sptinc992j", areas = "US", ages = 992L, cache = FALSE) expect_equal(captured$ages, "992") } ) }) test_that("download_wid normalises pop != 'all'", { captured <- list() testthat::with_mocked_bindings( `.cache` = function(a, ...) NULL, `.fetch` = function(indicators, areas, perc, ages, pop, no_extrapolation, verbose) { captured$pop <<- pop .wid() }, { download_wid("sptinc992j", areas = "US", pop = "j", cache = FALSE) expect_equal(captured$pop, "j") } ) }) # ── download_wid return value ───────────────────────────────────────────────── test_that("download_wid returns wid_df on cache hit", { mock <- .wid() testthat::with_mocked_bindings( `.cache` = function(a, ...) if (a == "get") mock else NULL, { result <- download_wid("sptinc992j", areas = "US") expect_s3_class(result, "wid_df") } ) }) test_that("download_wid returns wid_df when .fetch returns a wid_df stub", { mock <- .wid() testthat::with_mocked_bindings( `.cache` = function(a, ...) NULL, `.fetch` = function(...) mock, { result <- download_wid("sptinc992j", areas = "US", cache = FALSE) expect_s3_class(result, "wid_df") } ) }) test_that("download_wid returns empty wid_df when .fetch yields NULL", { testthat::with_mocked_bindings( `.cache` = function(a, ...) NULL, `.fetch` = function(...) NULL, { expect_warning( result <- download_wid("sptinc992j", areas = "US", cache = FALSE), NA # .fetch warns internally; download_wid itself does not ) expect_s3_class(result, "wid_df") expect_equal(nrow(result), 0L) } ) }) test_that("download_wid filters years after fetch", { rows <- rbind( data.frame(country = "US", variable = "sptinc992j", percentile = "p99p100", year = "2019", value = 0.20, age = "992", pop = "j", stringsAsFactors = FALSE), data.frame(country = "US", variable = "sptinc992j", percentile = "p99p100", year = "2020", value = 0.21, age = "992", pop = "j", stringsAsFactors = FALSE) ) testthat::with_mocked_bindings( `.cache` = function(a, ...) NULL, `.fetch` = function(...) rows, { result <- download_wid("sptinc992j", areas = "US", years = 2020L, cache = FALSE) expect_equal(nrow(result), 1L) expect_equal(result$year, "2020") } ) }) test_that("download_wid returns wid_df — tidyverse compatible", { mock <- .wid() testthat::with_mocked_bindings( `.cache` = function(a, ...) NULL, `.fetch` = function(...) mock, { result <- download_wid("sptinc992j", areas = "US", cache = FALSE) expect_true(is.data.frame(result)) expect_s3_class(result, "wid_df") expect_false(is.list(result) && !is.data.frame(result)) } ) }) # ── verbose messaging ───────────────────────────────────────────────────────── test_that("download_wid emits verbose message", { mock <- .wid() testthat::with_mocked_bindings( `.cache` = function(a, ...) NULL, `.fetch` = function(...) mock, { expect_message( download_wid("sptinc992j", areas = "US", cache = FALSE, verbose = TRUE), "Fetching" ) } ) }) # ── include_extrapolations flag ─────────────────────────────────────────────── test_that("download_wid passes include_extrapolations=FALSE as no_extrapolation=TRUE", { captured <- list() testthat::with_mocked_bindings( `.cache` = function(a, ...) NULL, `.fetch` = function(indicators, areas, perc, ages, pop, no_extrapolation, verbose) { captured$no_extrapolation <<- no_extrapolation .wid() }, { download_wid("sptinc992j", areas = "US", include_extrapolations = FALSE, cache = FALSE) expect_true(captured$no_extrapolation) } ) }) # ── caching ─────────────────────────────────────────────────────────────────── test_that("download_wid stores result in cache after fetch", { mock <- .wid() saved <- list() testthat::with_mocked_bindings( `.cache` = function(a, key = NULL, value = NULL) { if (a == "get") return(NULL) if (a == "set") { saved$value <<- value; return(invisible(value)) } }, `.fetch` = function(...) mock, { download_wid("sptinc992j", areas = "US", cache = TRUE) expect_s3_class(saved$value, "wid_df") } ) }) # ── metadata attribute ──────────────────────────────────────────────────────── test_that("download_wid metadata=TRUE attaches wid_meta attribute", { mock <- .wid() meta_df <- data.frame(variable = "sptinc992j", country = "US", source = "Tax records", stringsAsFactors = FALSE) testthat::with_mocked_bindings( `.cache` = function(a, ...) NULL, `.fetch` = function(...) mock, `.get_variables_areas` = function(...) data.frame( variable = "sptinc", country = "US", percentile = "p99p100", age = "992", pop = "j", stringsAsFactors = FALSE), `.fetch_meta` = function(...) meta_df, { result <- download_wid("sptinc992j", areas = "US", metadata = TRUE, cache = FALSE) expect_s3_class(result, "wid_df") expect_false(is.null(attr(result, "wid_meta"))) } ) }) test_that("download_wid metadata=TRUE with empty catalogue sets NULL wid_meta", { testthat::with_mocked_bindings( `.cache` = function(a, ...) NULL, `.fetch` = function(...) NULL, `.get_variables_areas` = function(...) NULL, { suppressWarnings( result <- download_wid("sptinc992j", areas = "US", metadata = TRUE, cache = FALSE) ) expect_s3_class(result, "wid_df") expect_null(attr(result, "wid_meta")) } ) }) # ── .fetch internals ────────────────────────────────────────────────────────── test_that(".fetch warns when .get_variables_areas returns empty", { testthat::with_mocked_bindings( `.get_variables_areas` = function(...) NULL, { expect_warning( widr:::.fetch("sptinc992j", "US", "all", "992", "j", FALSE, FALSE), "No data found" ) } ) }) test_that(".fetch warns when .filter_vars removes all rows", { # Variables are returned from catalogue but none match the requested percentile. vars <- data.frame( variable = "sptinc992j", country = "US", percentile = "p99p100", age = "992", pop = "j", stringsAsFactors = FALSE ) testthat::with_mocked_bindings( `.get_variables_areas` = function(...) vars, `.filter_vars` = function(...) vars[0L, ], # empty after filter { expect_warning( widr:::.fetch("sptinc992j", "US", "p0p50", "992", "j", FALSE, FALSE), "No data after" ) } ) }) test_that(".fetch warns when .chunk_fetch returns no rows", { vars <- data.frame( variable = "sptinc992j", country = "US", percentile = "p99p100", age = "992", pop = "j", stringsAsFactors = FALSE ) testthat::with_mocked_bindings( `.get_variables_areas` = function(...) vars, `.chunk_fetch` = function(...) NULL, { expect_warning( widr:::.fetch("sptinc992j", "US", "all", "992", "j", FALSE, FALSE), "API returned no data" ) } ) }) test_that(".fetch verbose=TRUE emits catalogue and variable count messages", { vars <- data.frame( variable = "sptinc992j", country = "US", percentile = "p99p100", age = "992", pop = "j", api_code = "sptinc992j_p99p100_992_j", stringsAsFactors = FALSE ) testthat::with_mocked_bindings( `.get_variables_areas` = function(...) vars, `.chunk_fetch` = function(...) data.frame( indicator = "sptinc992j_p99p100_992_j", country = "US", year = "2000", value = 0.2, stringsAsFactors = FALSE), `.parse_indicator` = function(df) { df$variable <- "sptinc992j" df$percentile <- "p99p100" df$indicator <- NULL df }, { msgs <- character(0L) withCallingHandlers( widr:::.fetch("sptinc992j", "US", "all", "992", "j", FALSE, TRUE), message = function(m) { msgs <<- c(msgs, conditionMessage(m)) invokeRestart("muffleMessage") } ) expect_true(any(grepl("catalogue|variable", msgs, ignore.case = TRUE))) } ) }) # ── wid_query / wid_filter / wid_fetch ─────────────────────────────────────── test_that("wid_query defaults match download_wid formals", { q <- wid_query() expect_equal(q$areas, "all") expect_equal(q$years, "all") expect_equal(q$ages, "992") expect_true(q$cache) expect_false(q$verbose) }) test_that("wid_query sets parameters", { q <- wid_query(indicators = "sptinc992j", areas = "US") expect_equal(q$indicators, "sptinc992j") expect_equal(q$areas, "US") }) test_that("wid_query warns on unknown params", { expect_warning(wid_query(foo = "bar"), "Unknown parameter") }) test_that("wid_filter updates fields and preserves others", { q <- wid_query(areas = "US", years = 2000:2010) q2 <- wid_filter(q, areas = c("US", "FR")) expect_equal(q2$areas, c("US", "FR")) expect_equal(q2$years, 2000:2010) }) test_that("wid_filter errors on non-query", { expect_error(wid_filter(list()), "inherits") }) test_that("wid_fetch executes query and returns wid_df", { mock <- .wid() testthat::with_mocked_bindings( `.cache` = function(a, ...) NULL, `.fetch` = function(...) mock, { q <- wid_query(indicators = "sptinc992j", areas = "US", cache = FALSE) expect_s3_class(wid_fetch(q), "wid_df") } ) }) test_that("wid_fetch applies overrides", { mock <- .wid() testthat::with_mocked_bindings( `.cache` = function(a, ...) NULL, `.fetch` = function(...) mock, { q <- wid_query(indicators = "sptinc992j", cache = FALSE) expect_s3_class(wid_fetch(q, areas = "FR"), "wid_df") } ) }) test_that("print.wid_query outputs header", { expect_output(print(wid_query(areas = "US")), "") }) test_that("print.wid_query truncates long vectors", { expect_output(print(wid_query(years = 1900:2100)), "\\.\\.\\.") }) # ── cache (wid_cache / wid_cache_list / wid_cache_clear) ───────────────────── test_that("wid_cache round-trips data", { tmp <- tempfile() on.exit(unlink(tmp, recursive = TRUE)) assignInNamespace(".CACHE_DIR", tmp, "widr") key <- widr:::.cache_key("test") wid_cache("set", key, 42L) expect_equal(wid_cache("get", key), 42L) }) test_that("wid_cache returns NULL for missing key", { tmp <- tempfile() on.exit(unlink(tmp, recursive = TRUE)) assignInNamespace(".CACHE_DIR", tmp, "widr") expect_null(wid_cache("get", "nosuchkey")) }) test_that("wid_cache_clear removes files", { tmp <- tempfile() on.exit(unlink(tmp, recursive = TRUE)) assignInNamespace(".CACHE_DIR", tmp, "widr") wid_cache("set", "k1", 1L) wid_cache("set", "k2", 2L) n <- wid_cache_clear() expect_equal(n, 2L) expect_length(wid_cache_list(), 0L) }) test_that("wid_cache errors on unknown action", { expect_error(wid_cache("bad"), "Unknown action") })