tests/testthat/test-spec_construct.R

# Tests for artoo_spec() construction and is_artoo_spec().

test_that("artoo_spec() builds a valid spec from each bundled pair", {
  adam <- artoo_spec(
    cdisc_adam_datasets,
    cdisc_adam_variables,
    codelists = cdisc_codelists
  )
  expect_true(is_artoo_spec(adam))
  expect_setequal(spec_datasets(adam), "ADSL")
  expect_identical(spec_standard(adam), "ADaMIG 1.1")

  sdtm <- artoo_spec(
    cdisc_sdtm_datasets,
    cdisc_sdtm_variables,
    codelists = cdisc_codelists
  )
  expect_setequal(spec_datasets(sdtm), "DM")
  expect_identical(spec_standard(sdtm), "SDTMIG 3.1.2")
})

test_that("mixing the ADaM and SDTM demo tables aborts (one spec, one standard)", {
  expect_error(
    artoo_spec(
      rbind(cdisc_adam_datasets, cdisc_sdtm_datasets),
      rbind(cdisc_adam_variables, cdisc_sdtm_variables),
      codelists = cdisc_codelists
    ),
    class = "artoo_error_spec"
  )
})

test_that("artoo_spec() coerces a tibble slot to a plain data frame", {
  skip_if_not_installed("tibble")
  spec <- artoo_spec(
    tibble::tibble(dataset = "DM", label = "Demographics"),
    tibble::tibble(dataset = "DM", variable = "AGE", data_type = "integer")
  )
  expect_s3_class(spec@datasets, "data.frame")
  expect_false(inherits(spec@datasets, "tbl_df"))
})

test_that("artoo_spec() fills missing optional columns with typed NAs", {
  spec <- artoo_spec(
    data.frame(dataset = "DM"),
    data.frame(dataset = "DM", variable = "AGE", data_type = "integer")
  )
  expect_true("length" %in% names(spec@variables))
  expect_type(spec@variables$length, "integer")
  expect_true(is.na(spec@variables$length))
})

test_that("artoo_spec() canonicalises variable types", {
  spec <- artoo_spec(
    data.frame(dataset = "DM"),
    data.frame(
      dataset = "DM",
      variable = c("A", "B"),
      data_type = c("text", "float")
    )
  )
  expect_equal(spec@variables$data_type, c("string", "float"))
})

test_that("artoo_spec() requires datasets and variables", {
  expect_error(artoo_spec(), class = "artoo_error_input")
  expect_error(
    artoo_spec(data.frame(dataset = "DM")),
    class = "artoo_error_input"
  )
})

test_that("artoo_spec() aborts on a missing required column", {
  expect_error(
    artoo_spec(
      data.frame(dataset = "DM"),
      data.frame(variable = "AGE", data_type = "integer") # no `dataset`
    ),
    class = "artoo_error_spec"
  )
})

test_that("artoo_spec() rejects a variable referencing an unknown dataset", {
  expect_error(
    artoo_spec(
      data.frame(dataset = "DM"),
      data.frame(dataset = "AE", variable = "AETERM", data_type = "string")
    ),
    class = "artoo_error_spec"
  )
})

test_that("artoo_spec() rejects an unresolved codelist reference", {
  expect_error(
    artoo_spec(
      data.frame(dataset = "DM"),
      data.frame(
        dataset = "DM",
        variable = "SEX",
        data_type = "string",
        codelist_id = "C99999"
      )
    ),
    class = "artoo_error_spec"
  )
})

test_that("artoo_spec() rejects an unknown variable type", {
  expect_error(
    artoo_spec(
      data.frame(dataset = "DM"),
      data.frame(dataset = "DM", variable = "A", data_type = "widget")
    ),
    class = "artoo_error_type"
  )
})

test_that("is_artoo_spec() is FALSE for non-specs", {
  expect_false(is_artoo_spec(mtcars))
  expect_false(is_artoo_spec(NULL))
})

# ---- single-standard model (@standard) -----------------------------------

test_that("an explicit standard lands on @standard", {
  spec <- artoo_spec(
    data.frame(dataset = "ADSL"),
    data.frame(dataset = "ADSL", variable = "AGE", data_type = "integer"),
    standard = "ADaMIG 1.1"
  )
  expect_identical(spec_standard(spec), "ADaMIG 1.1")
})

test_that("a P21-style datasets$standard column is consumed into @standard", {
  spec <- artoo_spec(
    data.frame(dataset = c("DM", "VS"), standard = "SDTMIG 3.2"),
    data.frame(
      dataset = c("DM", "VS"),
      variable = c("USUBJID", "VSTESTCD"),
      data_type = "string"
    )
  )
  expect_identical(spec_standard(spec), "SDTMIG 3.2")
  expect_false("standard" %in% names(spec@datasets))
})

test_that("a Define-style study$standard field is consumed into @standard", {
  spec <- artoo_spec(
    data.frame(dataset = "DM"),
    data.frame(dataset = "DM", variable = "USUBJID", data_type = "string"),
    study = data.frame(studyid = "CDISC01", standard = "SDTMIG 3.2")
  )
  expect_identical(spec_standard(spec), "SDTMIG 3.2")
  expect_false("standard" %in% names(spec@study))
  expect_identical(spec_study(spec, "study_name"), "CDISC01")
})

test_that("artoo_spec() canonicalises study fields to the ODM vocabulary", {
  # The P21 Define sheet's verbatim attribute names (StudyName,
  # StudyDescription, ProtocolName) land as the canonical snake_case
  # fields; unknown fields (Language) pass through verbatim.
  spec <- artoo_spec(
    data.frame(dataset = "DM"),
    data.frame(dataset = "DM", variable = "USUBJID", data_type = "string"),
    study = data.frame(
      StudyName = "CDISC01",
      StudyDescription = "A study",
      ProtocolName = "CDISC01-01",
      Language = "en",
      stringsAsFactors = FALSE,
      check.names = FALSE
    )
  )
  st <- spec_study(spec)
  expect_identical(st$study_name, "CDISC01")
  expect_identical(st$study_description, "A study")
  expect_identical(st$protocol_name, "CDISC01-01")
  expect_identical(st$Language, "en")
  expect_false(any(
    c("StudyName", "StudyDescription", "ProtocolName") %in% names(st)
  ))
})

test_that("artoo_spec() accepts studyid as a study_name alias", {
  spec <- artoo_spec(
    data.frame(dataset = "DM"),
    data.frame(dataset = "DM", variable = "USUBJID", data_type = "string"),
    study = data.frame(studyid = "CDISCPILOT01", stringsAsFactors = FALSE)
  )
  expect_identical(spec_study(spec, "study_name"), "CDISCPILOT01")
  expect_false("studyid" %in% names(spec_study(spec)))
})

test_that("agreeing study-name aliases collapse to the one value", {
  spec <- artoo_spec(
    data.frame(dataset = "DM"),
    data.frame(dataset = "DM", variable = "USUBJID", data_type = "string"),
    study = data.frame(
      studyid = "CDISC01",
      StudyName = "CDISC01",
      stringsAsFactors = FALSE,
      check.names = FALSE
    )
  )
  expect_identical(spec_study(spec, "study_name"), "CDISC01")
})

test_that("conflicting study-name fields abort at construction", {
  expect_error(
    artoo_spec(
      data.frame(dataset = "DM"),
      data.frame(dataset = "DM", variable = "USUBJID", data_type = "string"),
      study = data.frame(
        studyid = "CDISC01",
        StudyName = "OTHER",
        stringsAsFactors = FALSE,
        check.names = FALSE
      )
    ),
    class = "artoo_error_spec"
  )
  expect_snapshot(
    error = TRUE,
    artoo_spec(
      data.frame(dataset = "DM"),
      data.frame(dataset = "DM", variable = "USUBJID", data_type = "string"),
      study = data.frame(
        studyid = "CDISC01",
        StudyName = "OTHER",
        stringsAsFactors = FALSE,
        check.names = FALSE
      )
    )
  )
})

test_that("agreeing sources resolve to the one standard", {
  spec <- artoo_spec(
    data.frame(dataset = "ADSL", standard = "ADaMIG 1.1"),
    data.frame(dataset = "ADSL", variable = "AGE", data_type = "integer"),
    study = data.frame(standard = "ADaMIG 1.1"),
    standard = "ADaMIG 1.1"
  )
  expect_identical(spec_standard(spec), "ADaMIG 1.1")
})

test_that("mixing standards aborts at construction", {
  expect_error(
    artoo_spec(
      data.frame(
        dataset = c("ADSL", "DM"),
        standard = c("ADaMIG 1.1", "SDTMIG 3.2")
      ),
      data.frame(
        dataset = c("ADSL", "DM"),
        variable = c("AGE", "USUBJID"),
        data_type = c("integer", "string")
      )
    ),
    class = "artoo_error_spec"
  )
  expect_snapshot(
    error = TRUE,
    artoo_spec(
      data.frame(
        dataset = c("ADSL", "DM"),
        standard = c("ADaMIG 1.1", "SDTMIG 3.2")
      ),
      data.frame(
        dataset = c("ADSL", "DM"),
        variable = c("AGE", "USUBJID"),
        data_type = c("integer", "string")
      )
    )
  )
})

test_that("no standard anywhere resolves to NA", {
  spec <- artoo_spec(
    data.frame(dataset = "DM"),
    data.frame(dataset = "DM", variable = "USUBJID", data_type = "string")
  )
  expect_identical(spec_standard(spec), NA_character_)
})

test_that("blank and NA standards are ignored during resolution", {
  spec <- artoo_spec(
    data.frame(dataset = c("DM", "VS"), standard = c("SDTMIG 3.2", NA)),
    data.frame(
      dataset = c("DM", "VS"),
      variable = c("USUBJID", "VSTESTCD"),
      data_type = "string"
    ),
    study = data.frame(standard = "  ")
  )
  expect_identical(spec_standard(spec), "SDTMIG 3.2")
})

Try the artoo package in your browser

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

artoo documentation built on July 23, 2026, 1:08 a.m.