diff --git a/R/search.R b/R/search.R index 02ac2c2..3b1320b 100644 --- a/R/search.R +++ b/R/search.R @@ -120,3 +120,41 @@ cog_gov_search <- function(name = NULL, state = NULL, type = NULL) { WV = "54", WI = "55", WY = "56", AS = "60", GU = "66", MP = "69", PR = "72", VI = "78" ) + +# Validate basket-mode inputs. Returns a list with normalized character +# vectors `name`, `state`, `type`, all of length n = length(name). +# `state` and `type` of length 1 are recycled; lengths must be 1 or n +# otherwise. NULL state/type become a vector of NA_character_. +#' @noRd +.validate_basket_args <- function(name, state, type) { + if (!is.character(name)) { + cli::cli_abort("`name` must be a character vector.") + } + n <- length(name) + + state_norm <- if (is.null(state)) { + rep(NA_character_, n) + } else if (length(state) == 1L) { + rep(as.character(state), n) + } else if (length(state) == n) { + as.character(state) + } else { + cli::cli_abort( + "`state` must be length 1 or {n} (length of `name`); got {length(state)}." + ) + } + + type_norm <- if (is.null(type)) { + rep(NA_character_, n) + } else if (length(type) == 1L) { + rep(as.character(type), n) + } else if (length(type) == n) { + as.character(type) + } else { + cli::cli_abort( + "`type` must be length 1 or {n} (length of `name`); got {length(type)}." + ) + } + + list(name = name, state = state_norm, type = type_norm) +} diff --git a/tests/testthat/test-search.R b/tests/testthat/test-search.R index ddc3ffa..ea19a5f 100644 --- a/tests/testthat/test-search.R +++ b/tests/testthat/test-search.R @@ -72,3 +72,67 @@ test_that("cog_gov_search with no filters returns full registry", { r <- cog_gov_search() expect_gt(nrow(r), 1000L) }) + +# ---- basket mode internal helpers ---- + +test_that(".validate_basket_args recycles state from length 1", { + out <- uscogdata:::.validate_basket_args( + name = c("Broward", "San Diego", "Austin"), + state = "FL", + type = NULL + ) + expect_equal(out$name, c("Broward", "San Diego", "Austin")) + expect_equal(out$state, c("FL", "FL", "FL")) + expect_equal(out$type, c(NA_character_, NA_character_, NA_character_)) +}) + +test_that(".validate_basket_args recycles type from length 1", { + out <- uscogdata:::.validate_basket_args( + name = c("San Diego", "Oakland"), + state = "CA", + type = "city" + ) + expect_equal(out$type, c("city", "city")) +}) + +test_that(".validate_basket_args accepts per-row state and type", { + out <- uscogdata:::.validate_basket_args( + name = c("Broward", "San Diego"), + state = c("FL", "CA"), + type = c(NA, "city") + ) + expect_equal(out$state, c("FL", "CA")) + expect_equal(out$type, c(NA_character_, "city")) +}) + +test_that(".validate_basket_args rejects length-mismatched state", { + expect_error( + uscogdata:::.validate_basket_args( + name = c("Broward", "San Diego", "Austin"), + state = c("FL", "CA"), + type = NULL + ), + regexp = "must be length 1 or 3" + ) +}) + +test_that(".validate_basket_args rejects length-mismatched type", { + expect_error( + uscogdata:::.validate_basket_args( + name = c("Broward", "San Diego"), + state = "FL", + type = c("county", "city", "city") + ), + regexp = "must be length 1 or 2" + ) +}) + +test_that(".validate_basket_args allows NULL state and type", { + out <- uscogdata:::.validate_basket_args( + name = c("Broward", "San Diego"), + state = NULL, + type = NULL + ) + expect_equal(out$state, c(NA_character_, NA_character_)) + expect_equal(out$type, c(NA_character_, NA_character_)) +})