Offer cacheAs on the other query functions as well
frequencyQuery(), corpusStats(), collocationScoreQuery() and
textMetadata() take a cacheAs file too now, not because they are slow -
they are not, next to a collocation analysis running for hours - but
because a file of one's own is what keeps an analysis reproducible. KorAP
corpora grow, so the same query returns different numbers next year, and
the scores computed from them may change with the package; a result kept
next to the script stays what it was, and the script runs without a
server at all.
The parameter is documented as what it is, next to the connection's
cache, which is a transparent speed-up one can throw away.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Change-Id: I9bac8931e7a38a91adcbfe58ef4cb5bcdaaf3c47
diff --git a/tests/testthat/test-cache-as.R b/tests/testthat/test-cache-as.R
new file mode 100644
index 0000000..2a15b75
--- /dev/null
+++ b/tests/testthat/test-cache-as.R
@@ -0,0 +1,92 @@
+test_that("cacheAsFileName appends .rds where it is missing", {
+ expect_equal(RKorAPClient:::cacheAsFileName("analysis"), "analysis.rds")
+ expect_equal(RKorAPClient:::cacheAsFileName("analysis.rds"), "analysis.rds")
+ expect_equal(RKorAPClient:::cacheAsFileName("analysis.RDS"), "analysis.RDS")
+})
+
+test_that("a cache file is written and read back, without contacting the server", {
+ skip_if_offline()
+ kco <- KorAPConnection(accessToken = NULL, verbose = FALSE)
+ dir <- file.path(tempdir(), "cacheAsTest")
+ dir.create(dir, showWarnings = FALSE)
+ on.exit(unlink(dir, recursive = TRUE), add = TRUE)
+
+ # every query function that takes cacheAs, so that one added later without a
+ # cache file of its own does not go unnoticed
+ queries <- list(
+ "frequencyQuery" = function(f) frequencyQuery(kco, "Ameisenplage", cacheAs = f),
+ "corpusStats" = function(f) corpusStats(kco, vc = "pubDate since 2020", as.df = TRUE, cacheAs = f),
+ "collocationScoreQuery" = function(f) collocationScoreQuery(kco, "Grund", "triftiger", cacheAs = f),
+ "textMetadata" = function(f) textMetadata(kco, "WPD17/L79/98721", cacheAs = f)
+ )
+
+ for (name in names(queries)) {
+ query <- queries[[name]]
+ file <- file.path(dir, name)
+
+ fresh <- query(file)
+ expect_true(file.exists(paste0(file, ".rds")), info = name)
+
+ fromCache <- local({
+ testthat::local_mocked_bindings(
+ apiCall = function(...) stop("server must not be contacted"),
+ .package = "RKorAPClient"
+ )
+ query(file)
+ })
+ expect_equal(fromCache, fresh, info = name)
+
+ # what produced the result lives in the file only, not in the value
+ expect_null(attr(fromCache, RKorAPClient:::cacheAsAttribute), info = name)
+ expect_equal(
+ attr(readRDS(paste0(file, ".rds")), RKorAPClient:::cacheAsAttribute)$scoreVersion,
+ RKorAPClient:::cacheAsScoreVersion,
+ info = name
+ )
+ }
+})
+
+test_that("a cache file written before the scores were corrected is refused", {
+ skip_if_offline()
+ kco <- KorAPConnection(accessToken = NULL, verbose = FALSE)
+ file <- tempfile(fileext = ".rds")
+ on.exit(unlink(file), add = TRUE)
+
+ frequencyQuery(kco, "Ameisenplage", cacheAs = file)
+ aged <- readRDS(file)
+ record <- attr(aged, RKorAPClient:::cacheAsAttribute)
+ # as a file from before the corrections has it: an older score generation, and
+ # an older version to go with it
+ record$scoreVersion <- "1.3.0"
+ record$packageVersion <- "1.3.0"
+ attr(aged, RKorAPClient:::cacheAsAttribute) <- record
+ saveRDS(aged, file)
+
+ expect_warning(frequencyQuery(kco, "Ameisenplage", cacheAs = file), "1\\.3\\.0")
+ # and the refused file is replaced by a current one, so the warning comes once
+ expect_silent(frequencyQuery(kco, "Ameisenplage", cacheAs = file))
+})
+
+test_that("a query that differs is recomputed rather than read back", {
+ skip_if_offline()
+ kco <- KorAPConnection(accessToken = NULL, verbose = FALSE)
+ file <- tempfile(fileext = ".rds")
+ on.exit(unlink(file), add = TRUE)
+
+ frequencyQuery(kco, "Ameisenplage", cacheAs = file)
+ expect_warning(frequencyQuery(kco, "Heuschreckenplage", cacheAs = file), "query")
+})
+
+test_that("verbosity is not part of what a cache file records", {
+ skip_if_offline()
+ kco <- KorAPConnection(accessToken = NULL, verbose = FALSE)
+ file <- tempfile(fileext = ".rds")
+ on.exit(unlink(file), add = TRUE)
+
+ corpusStats(kco, vc = "pubDate since 2020", as.df = TRUE, cacheAs = file)
+ # how loud a query is does not change what it returns, so it must not make
+ # the file be thrown away
+ expect_silent(
+ corpusStats(kco, vc = "pubDate since 2020", as.df = TRUE, verbose = TRUE, cacheAs = file)
+ )
+})