tests/testthat/test-metadata.R

test_that("metadata cache avoids repeated API calls", {
  calls <- 0L
  local_mocked_bindings(
    boj_fetch_json = function(...) {
      calls <<- calls + 1L
      fixture_payload(resultset = fixture_metadata("en"))
    },
    .package = "bojapi"
  )
  cache_dir <- tempfile("bojapi-cache-")
  first <- boj_metadata("FM08", cache_dir = cache_dir, wait = 0)
  second <- boj_metadata("FM08", cache_dir = cache_dir, wait = 0)
  expect_equal(calls, 1L)
  expect_equal(first, second, ignore_attr = TRUE)
})

test_that("metadata cache writes replace completed files without leftovers", {
  cache_dir <- tempfile("bojapi-cache-")
  dir.create(cache_dir)
  cache_path <- bojapi:::boj_metadata_cache_file("FM08", "en", cache_dir)
  metadata <- bojapi:::boj_parse_metadata(fixture_metadata("en"), "FM08", "en")

  expect_true(bojapi:::boj_write_metadata_cache(metadata, cache_path))
  updated <- metadata
  updated$name[[1L]] <- "updated"
  expect_true(bojapi:::boj_write_metadata_cache(updated, cache_path))

  expect_identical(readRDS(cache_path)$name[[1L]], "updated")
  files <- setdiff(list.files(cache_dir, all.files = TRUE), c(".", ".."))
  expect_identical(files, basename(cache_path))
})

test_that("expired and invalid metadata cache entries are removed", {
  cache_dir <- tempfile("bojapi-cache-")
  dir.create(cache_dir)
  metadata <- bojapi:::boj_parse_metadata(fixture_metadata("en"), "FM08", "en")

  expired <- bojapi:::boj_metadata_cache_file("FM08", "en", cache_dir)
  saveRDS(metadata, expired)
  Sys.setFileTime(expired, Sys.time() - 3600)
  expect_null(bojapi:::boj_read_metadata_cache(expired, max_age = 60))
  expect_false(file.exists(expired))

  corrupt <- bojapi:::boj_metadata_cache_file("BP01", "en", cache_dir)
  writeBin(charToRaw("not an RDS file"), corrupt)
  expect_null(bojapi:::boj_read_metadata_cache(corrupt, max_age = 60))
  expect_false(file.exists(corrupt))

  wrong_schema <- bojapi:::boj_metadata_cache_file("CO", "en", cache_dir)
  partial <- metadata[, c("db", "series_code", "name", "frequency", "is_series", "lang")]
  saveRDS(partial, wrong_schema)
  expect_null(bojapi:::boj_read_metadata_cache(wrong_schema, max_age = 60))
  expect_false(file.exists(wrong_schema))
})

test_that("metadata cache cleanup never recursively removes directories", {
  cache_dir <- tempfile("bojapi-cache-")
  dir.create(cache_dir)
  cache_path <- bojapi:::boj_metadata_cache_file("FM08", "en", cache_dir)
  dir.create(cache_path)
  marker <- file.path(cache_path, "keep.txt")
  file.create(marker)

  expect_warning(
    expect_null(bojapi:::boj_read_metadata_cache(cache_path, max_age = 60)),
    "Refusing to remove a directory"
  )
  expect_true(dir.exists(cache_path))
  expect_true(file.exists(marker))
})

test_that("boj_cache can prune and clear selected cache entries", {
  cache_dir <- tempfile("bojapi-cache-")
  dir.create(cache_dir)
  metadata <- bojapi:::boj_parse_metadata(fixture_metadata("en"), "FM08", "en")

  fresh <- bojapi:::boj_metadata_cache_file("FM08", "en", cache_dir)
  expired <- bojapi:::boj_metadata_cache_file("BP01", "jp", cache_dir)
  invalid <- bojapi:::boj_metadata_cache_file("CO", "en", cache_dir)
  unrelated <- file.path(cache_dir, "unrelated.rds")
  saveRDS(metadata, fresh)
  saveRDS(metadata, expired)
  Sys.setFileTime(expired, Sys.time() - 3600)
  saveRDS(list(not = "metadata"), invalid)
  saveRDS(list(keep = TRUE), unrelated)

  pruned <- boj_cache(action = "prune", max_age = 60, cache_dir = cache_dir)
  expect_setequal(pruned$file, basename(c(fresh, expired, invalid)))
  expect_identical(pruned$status[pruned$file == basename(fresh)], "kept")
  expect_identical(pruned$reason[pruned$file == basename(fresh)], "fresh")
  expect_identical(pruned$status[pruned$file == basename(expired)], "removed")
  expect_identical(pruned$reason[pruned$file == basename(expired)], "expired")
  expect_identical(pruned$status[pruned$file == basename(invalid)], "removed")
  expect_identical(pruned$reason[pruned$file == basename(invalid)], "invalid")
  expect_true(file.exists(fresh))
  expect_false(file.exists(expired))
  expect_false(file.exists(invalid))
  expect_true(file.exists(unrelated))

  cleared <- boj_cache("FM08", lang = "en", action = "clear", cache_dir = cache_dir)
  expect_identical(cleared$status, "removed")
  expect_identical(cleared$reason, "clear")
  expect_false(file.exists(fresh))

  missing <- boj_cache("FM08", lang = "en", action = "clear", cache_dir = cache_dir)
  expect_identical(missing$status, "missing")
})

test_that("boj_cache validates its management action", {
  expect_error(boj_cache(action = "delete"), class = "boj_parameter_error")
})

test_that("metadata can omit hierarchy headings", {
  local_mocked_bindings(
    boj_fetch_json = function(...) fixture_payload(resultset = fixture_metadata("en")),
    .package = "bojapi"
  )
  out <- boj_metadata("FM08", cache = FALSE, include_groups = FALSE, wait = 0)
  expect_true(all(out$is_series))
  expect_equal(nrow(out), 1L)
})

test_that("boj_search supports literal and regular expression searches", {
  metadata <- bojapi:::boj_parse_metadata(fixture_metadata("en"), "FM08", "en")
  literal <- boj_search("U.S. Dollar", metadata = metadata)
  expect_equal(literal$series_code, "FXERM07")

  regex <- boj_search("dollar|euro", metadata = metadata, regex = TRUE)
  expect_equal(nrow(regex), 1L)

  groups <- boj_search("Daily", metadata = metadata, include_groups = TRUE)
  expect_false(groups$is_series[[1L]])
})

test_that("database registry and credit are complete", {
  expect_equal(nrow(boj_databases()), 50L)
  expect_true(all(c("FM08", "CO", "FF", "BIS") %in% boj_databases()$db))
  credit <- boj_api_credit("en")
  expect_match(credit$credit, "does not guarantee", fixed = TRUE)
  expect_identical(credit$email, "post.rsd17@boj.or.jp")
})

Try the bojapi package in your browser

Any scripts or data that you put into this service are public.

bojapi documentation built on July 24, 2026, 5:07 p.m.