test_that("Crossref search sends supported parameters", {
callback <- function(url, headers, params, timeout) {
expect_identical(url, "https://api.crossref.org/works")
expect_equal(params[["query.bibliographic"]], "gaussian processes")
expect_equal(params$rows, 2L)
expect_equal(params$filter,
"type:journal-article,from-pub-date:2020-01-01,until-pub-date:2026-10-01")
expect_equal(params$mailto, "research@example.org")
expect_equal(params$cursor, "*")
list(message = list(items = list()))
}
response <- fetch_from_crossref(
"gaussian processes", rows = 2L, start_date = "2020-01-01",
end_date = "2026-10-01", work_type = "journal-article",
mailto = "research@example.org", cursor = "*", requester = callback
)
expect_identical(response$message$items, list())
})
test_that("crossref entries preserve incomplete dates and author order", {
entries <- list(
list(title = list("A study"), DOI = "10.1000/a",
abstract = "Content",
author = list(list(given = "Ada", family = "Lovelace"),
list(name = "Research Collective"),
list(given = "Grace", family = "Hopper")),
published = list("date-parts" = list(list(2024, 5)))),
list(title = list("Second"),
published = list("date-parts" = list(list(2020)))),
"invalid entry"
)
result <- process_crossref_entries(entries)
expect_length(result, 2L)
expect_s3_class(result[[1L]], "Article")
expect_identical(result[[1L]]$authors,
c("Ada Lovelace", "Research Collective", "Grace Hopper"))
expect_identical(result[[1L]]$publication_date, "2024-05")
expect_identical(result[[2L]]$publication_date, "2020")
expect_identical(result[[1L]]$abstract, "Content")
})
test_that("cursor search respects result limit and progresses safely", {
requests <- list()
callback <- function(url, headers, params, timeout) {
requests[[length(requests) + 1L]] <<- params
if (length(requests) == 1L) {
return(list(message = list(
items = list(list(title = list("One")),
list(title = list("Two"))),
"next-cursor" = "second"
)))
}
list(message = list(items = list(list(title = list("Three"))),
"next-cursor" = "third"))
}
papers <- search_crossref(
"a topic", max_results = 3L, page_size = 2L,
requester = callback, min_interval = 0
)
expect_length(papers, 3L)
expect_identical(vapply(papers, function(p) p$title, character(1)),
c("One", "Two", "Three"))
expect_equal(requests[[1L]]$rows, 2L)
expect_equal(requests[[2L]]$rows, 1L)
expect_equal(requests[[2L]]$cursor, "second")
})
test_that("short pages stop searching and bad cursors are rejected", {
short <- function(url, headers, params, timeout) {
list(message = list(items = list(list(title = list("Only"))),
"next-cursor" = "ignored"))
}
expect_length(search_crossref(
"topic", max_results = 5L, page_size = 2L,
requester = short, min_interval = 0), 1L)
repeated <- function(url, headers, params, timeout) {
list(message = list(items = list(list(title = list("A"))),
"next-cursor" = "*"))
}
expect_error(search_crossref(
"topic", max_results = 2L, page_size = 1L,
requester = repeated, min_interval = 0), "repeated")
})
test_that("invalid parameters fail without network calls", {
never <- function(url, headers, params, timeout) {
fail("Unexpected HTTP call")
}
expect_error(fetch_from_crossref("", requester = never), "query")
expect_error(fetch_from_crossref("x", rows = 0, requester = never), "rows")
expect_error(fetch_from_crossref("x", start_date = "2026-02-30",
requester = never), "date")
expect_error(fetch_from_crossref("x", start_date = "2026-10-01",
end_date = "2020-01-01",
requester = never), "after")
expect_error(fetch_from_crossref("x", work_type = "Journal Article",
requester = never), "work_type")
expect_error(search_crossref("x", page_size = 1001L, requester = never),
"page_size")
expect_error(search_crossref("x", max_tries = 11L, requester = never),
"max_tries")
expect_error(process_crossref_response(list()), "message")
expect_error(process_crossref_response(list(message = list())), "items")
})