# ---- Helpers ---- # Minimal plan: exactly one domain on, everything else off make_minimal_plan <- function(...) { planAnalysis( analysisWindows = defineAnalysisWindows( startDays = c(-30), endDays = c(-1) ), useBaseFeatures = list( condition_occurrence = list(include = TRUE, type = "start"), drug_exposure = list(include = FALSE), condition_era = list(include = FALSE), drug_era = list(include = FALSE), procedure_occurrence = list(include = FALSE), observation = list(include = FALSE), device_exposure = list(include = FALSE), visit_occurrence = list(include = FALSE), measurement = list(include = FALSE) ), useCohortFeatures = list(include = FALSE), useConceptSetFeatures = list(include = FALSE), ... ) } # =========================================================================== # planAnalysis — basic return # =========================================================================== test_that("planAnalysis returns characterizationSettings with correct structure", { plan <- make_minimal_plan() expect_s3_class(plan, "characterizationSettings") expect_true(all( c("analysisWindows", "useBaseFeatures", "useCohortFeatures", "useConceptSetFeatures") %in% names(plan) )) }) test_that("planAnalysis stores windows correctly", { plan <- make_minimal_plan() expect_length(plan$analysisWindows, 1L) }) # =========================================================================== # planAnalysis — base features validation # =========================================================================== test_that("planAnalysis errors on unknown domain", { expect_error( planAnalysis( analysisWindows = defineAnalysisWindows(startDays = -30, endDays = -1), useBaseFeatures = list(bogus_table = list(include = TRUE)), useCohortFeatures = list(include = FALSE), useConceptSetFeatures = list(include = FALSE) ), "Unknown domain" ) }) test_that("planAnalysis allows disabled domain with minimal config", { plan <- planAnalysis( analysisWindows = defineAnalysisWindows(startDays = -30, endDays = -1), useBaseFeatures = list( drug_exposure = list(include = FALSE) ), useCohortFeatures = list(include = FALSE), useConceptSetFeatures = list(include = FALSE) ) expect_s3_class(plan, "characterizationSettings") }) test_that("planAnalysis validates type for applicable domains", { expect_error( planAnalysis( analysisWindows = defineAnalysisWindows(startDays = -30, endDays = -1), useBaseFeatures = list( condition_era = list(include = TRUE, type = "INVALID") ), useCohortFeatures = list(include = FALSE), useConceptSetFeatures = list(include = FALSE) ), "start.*overlap|Must be element" ) }) test_that("planAnalysis warns when type set on non-applicable domain", { expect_warning( planAnalysis( analysisWindows = defineAnalysisWindows(startDays = -30, endDays = -1), useBaseFeatures = list( procedure_occurrence = list(include = TRUE, type = "start") ), useCohortFeatures = list(include = FALSE), useConceptSetFeatures = list(include = FALSE) ), "type.*ignored" ) }) test_that("planAnalysis errors on ATC for non-drug domain", { expect_error( planAnalysis( analysisWindows = defineAnalysisWindows(startDays = -30, endDays = -1), useBaseFeatures = list( condition_occurrence = list(include = TRUE, atc = TRUE, atcLevels = 3L) ), useCohortFeatures = list(include = FALSE), useConceptSetFeatures = list(include = FALSE) ), "atc = TRUE.*only valid for drug" ) }) test_that("planAnalysis validates ATC levels range", { expect_error( planAnalysis( analysisWindows = defineAnalysisWindows(startDays = -30, endDays = -1), useBaseFeatures = list( drug_exposure = list(include = TRUE, atc = TRUE, atcLevels = 6L) ), useCohortFeatures = list(include = FALSE), useConceptSetFeatures = list(include = FALSE) ), "not <= 5|out of range|upper" ) }) test_that("planAnalysis accepts valid ATC config for drug domains", { plan <- planAnalysis( analysisWindows = defineAnalysisWindows(startDays = -30, endDays = -1), useBaseFeatures = list( drug_exposure = list(include = TRUE, atc = TRUE, atcLevels = c(3L, 5L)) ), useCohortFeatures = list(include = FALSE), useConceptSetFeatures = list(include = FALSE) ) expect_true(plan$useBaseFeatures$drug_exposure$atc) expect_equal(plan$useBaseFeatures$drug_exposure$atcLevels, c(3L, 5L)) }) # =========================================================================== # planAnalysis — cohort features validation # =========================================================================== test_that("planAnalysis errors when cohortIds missing but include=TRUE", { expect_error( planAnalysis( analysisWindows = defineAnalysisWindows(startDays = -30, endDays = -1), useBaseFeatures = list(drug_exposure = list(include = FALSE)), useCohortFeatures = list( include = TRUE, type = "start", cohortIds = NULL, cohortTable = "t", covariateSchema = "s" ), useConceptSetFeatures = list(include = FALSE) ), "cohortIds.*must be provided" ) }) test_that("planAnalysis accepts valid cohort features", { plan <- planAnalysis( analysisWindows = defineAnalysisWindows(startDays = -30, endDays = -1), useBaseFeatures = list(drug_exposure = list(include = FALSE)), useCohortFeatures = list( include = TRUE, type = "start", cohortIds = c(101L, 102L), cohortNames = c("A", "B"), cohortTable = "my_cohort", covariateSchema = "results" ), useConceptSetFeatures = list(include = FALSE) ) expect_true(plan$useCohortFeatures$include) expect_equal(plan$useCohortFeatures$cohortIds, c(101L, 102L)) }) test_that("planAnalysis errors cohortNames length mismatch", { expect_error( planAnalysis( analysisWindows = defineAnalysisWindows(startDays = -30, endDays = -1), useBaseFeatures = list(drug_exposure = list(include = FALSE)), useCohortFeatures = list( include = TRUE, type = "start", cohortIds = c(101L, 102L), cohortNames = c("OnlyOne"), cohortTable = "t", covariateSchema = "s" ), useConceptSetFeatures = list(include = FALSE) ), "cohortNames|Must have length 2" ) }) # =========================================================================== # planAnalysis — concept set features validation # =========================================================================== test_that("planAnalysis accepts valid concept set features", { plan <- planAnalysis( analysisWindows = defineAnalysisWindows(startDays = -30, endDays = -1), useBaseFeatures = list(drug_exposure = list(include = FALSE)), useCohortFeatures = list(include = FALSE), useConceptSetFeatures = list( include = TRUE, type = "binary", conceptSets = list( diabetes = list( items = list( list(concept = list(CONCEPT_ID = 201820L), includeDescendants = TRUE) ), tables = "condition_occurrence" ) ) ) ) expect_true(plan$useConceptSetFeatures$include) }) test_that("planAnalysis errors on unknown table in concept set", { expect_error( planAnalysis( analysisWindows = defineAnalysisWindows(startDays = -30, endDays = -1), useBaseFeatures = list(drug_exposure = list(include = FALSE)), useCohortFeatures = list(include = FALSE), useConceptSetFeatures = list( include = TRUE, type = "binary", conceptSets = list( test = list( items = list(list(concept = list(CONCEPT_ID = 1L))), tables = "fake_table" ) ) ) ), "Unknown table" ) }) test_that("planAnalysis errors on invalid concept set type", { expect_error( planAnalysis( analysisWindows = defineAnalysisWindows(startDays = -30, endDays = -1), useBaseFeatures = list(drug_exposure = list(include = FALSE)), useCohortFeatures = list(include = FALSE), useConceptSetFeatures = list( include = TRUE, type = "INVALID", conceptSets = list( test = list( items = list(list(concept = list(CONCEPT_ID = 1L))), tables = "condition_occurrence" ) ) ) ), "binary.*counts|Must be element" ) }) test_that("planAnalysis errors when concept set missing CONCEPT_ID", { expect_error( planAnalysis( analysisWindows = defineAnalysisWindows(startDays = -30, endDays = -1), useBaseFeatures = list(drug_exposure = list(include = FALSE)), useCohortFeatures = list(include = FALSE), useConceptSetFeatures = list( include = TRUE, type = "binary", conceptSets = list( test = list( items = list(list(concept = list())), tables = "condition_occurrence" ) ) ) ), "CONCEPT_ID.*required" ) }) # =========================================================================== # print.characterizationSettings # =========================================================================== test_that("print.characterizationSettings produces output", { plan <- make_minimal_plan() output <- capture.output(print(plan)) expect_true(any(grepl("Characterization Analysis Plan", output))) expect_true(any(grepl("Analysis Windows", output))) expect_true(any(grepl("Base Feature Domains", output))) }) test_that("print.characterizationSettings returns invisibly", { plan <- make_minimal_plan() result <- withVisible(print(plan)) expect_false(result$visible) expect_s3_class(result$value, "characterizationSettings") })