tests/testthat/test-input-functions.R

# Test input configuration functions (simplified version)
# This test suite validates the core input system with a focus on what we can actually test

library(testthat)
library(jsonlite)

# Test that the function exists and has the right signature
test_that("get_input function has correct signature", {
  # Load the function
  if (file.exists("R/input.R")) {
    source("R/input.R")
  } else if (file.exists("../../R/input.R")) {
    source("../../R/input.R")
  }
  
  skip_if_not(exists("get_input", mode = "function"), "get_input function not available")
  
  # Check function signature
  params <- names(formals(get_input))
  expect_true("age0" %in% params, "Function should have age0 parameter")
  expect_true("time_horizon" %in% params, "Function should have time_horizon parameter")
  expect_true("jurisdiction" %in% params, "Function should have jurisdiction parameter")
  
  # Check default values
  defaults <- formals(get_input)
  expect_equal(defaults$age0, 40)
  expect_equal(defaults$time_horizon, 20)
  expect_equal(defaults$jurisdiction, "canada")
})

# Test config file discovery (independent of function execution)
test_that("config files exist and have valid JSON", {
  # Find config files using multiple possible paths
  config_files <- c()
  
  # Try different possible locations
  possible_paths <- c(
    system.file("config", package = "epicR"),
    file.path(dirname(dirname(getwd())), "inst", "config"),
    "inst/config",
    "../../inst/config"
  )
  
  for (config_dir in possible_paths) {
    if (dir.exists(config_dir)) {
      files <- list.files(config_dir, pattern = "^config_.*\\.json$", full.names = TRUE)
      config_files <- c(config_files, files)
      break
    }
  }
  
  skip_if(length(config_files) == 0, "No config files found")
  
  # Test each config file
  for (config_file in config_files) {
    # Test JSON validity
    expect_error({
      config <- jsonlite::fromJSON(config_file, simplifyVector = FALSE)
    }, regexp = NA, info = paste("Config file should be valid JSON:", basename(config_file)))
    
    # Test basic structure
    if (exists("config")) {
      expect_true("jurisdiction" %in% names(config), 
                  paste("Config should have jurisdiction field:", basename(config_file)))
      
      # Test that it has the main sections we expect
      expected_sections <- c("global_parameters", "agent", "smoking", "COPD")
      for (section in expected_sections) {
        expect_true(section %in% names(config),
                    paste("Config should have", section, "section:", basename(config_file)))
      }
    }
  }
})

# Test config structure consistency
test_that("Canada and US configs have consistent structure", {
  # Find config files
  config_files <- c()
  possible_paths <- c(
    system.file("config", package = "epicR"),
    file.path(dirname(dirname(getwd())), "inst", "config"),
    "inst/config",
    "../../inst/config"
  )
  
  canada_file <- NULL
  us_file <- NULL
  
  for (config_dir in possible_paths) {
    if (dir.exists(config_dir)) {
      canada_candidate <- file.path(config_dir, "config_canada.json")
      us_candidate <- file.path(config_dir, "config_us.json")
      
      if (file.exists(canada_candidate)) canada_file <- canada_candidate
      if (file.exists(us_candidate)) us_file <- us_candidate
      
      if (!is.null(canada_file) && !is.null(us_file)) break
    }
  }
  
  skip_if(is.null(canada_file) || is.null(us_file), "Both config files must exist")
  
  # Load both configs
  canada_config <- jsonlite::fromJSON(canada_file, simplifyVector = FALSE)
  us_config <- jsonlite::fromJSON(us_file, simplifyVector = FALSE)
  
  # Remove jurisdiction for comparison
  canada_config$jurisdiction <- NULL
  us_config$jurisdiction <- NULL
  
  # Compare section names
  canada_sections <- sort(names(canada_config))
  us_sections <- sort(names(us_config))
  
  expect_equal(canada_sections, us_sections)
  
  # Test that both have reasonable number of sections
  expect_true(length(canada_sections) > 10, 
              "Should have substantial number of sections")
})

# Test placeholder detection logic (without actually loading configs)
test_that("placeholder detection logic works", {
  # Load the function
  if (file.exists("R/input.R")) {
    source("R/input.R")
  } else if (file.exists("../../R/input.R")) {
    source("../../R/input.R")
  }
  
  skip_if_not(exists("get_input", mode = "function"), "get_input function not available")
  
  # Test that the function properly rejects nonexistent jurisdictions
  expect_error(
    get_input(jurisdiction = "nonexistent"),
    regexp = "Configuration file.*not found",
    info = "Should fail with clear error for invalid jurisdiction"
  )
})

# Test that helper functions are defined (by checking the source)
test_that("helper functions are defined in source", {
  skip_if_not(file.exists("R/input.R") || file.exists("../../R/input.R"), 
              "Source file not available")
  
  source_file <- if (file.exists("R/input.R")) "R/input.R" else "../../R/input.R"
  source_lines <- readLines(source_file)
  source_text <- paste(source_lines, collapse = "\n")
  
  # Check that key helper functions are defined
  expect_true(grepl("convert_config_value.*<-.*function", source_text),
              "convert_config_value function should be defined")
  
  expect_true(grepl("create_matrix_from_config.*<-.*function", source_text),
              "create_matrix_from_config function should be defined")
  
  expect_true(grepl("get_metadata.*<-.*function", source_text),
              "get_metadata function should be defined")
  
  # Check for placeholder detection logic
  expect_true(grepl("PLACEHOLDER_", source_text),
              "Should have placeholder detection logic")
})

# Test metadata structure in config files
test_that("config files have proper metadata structure", {
  # Find a config file
  canada_file <- NULL
  possible_paths <- c(
    system.file("config", package = "epicR"),
    file.path(dirname(dirname(getwd())), "inst", "config"),
    "inst/config",
    "../../inst/config"
  )
  
  for (config_dir in possible_paths) {
    if (dir.exists(config_dir)) {
      candidate <- file.path(config_dir, "config_canada.json")
      if (file.exists(candidate)) {
        canada_file <- candidate
        break
      }
    }
  }
  
  skip_if(is.null(canada_file), "Canada config file not found")
  
  config <- jsonlite::fromJSON(canada_file, simplifyVector = FALSE)
  
  # Check that metadata entries exist
  metadata_count <- 0
  param_count <- 0
  
  # Count in global_parameters section
  if ("global_parameters" %in% names(config)) {
    section <- config$global_parameters
    for (key in names(section)) {
      if (endsWith(key, "_metadata")) {
        metadata_count <- metadata_count + 1
        # Check metadata structure
        metadata <- section[[key]]
        expect_true(is.list(metadata), paste("Metadata should be list:", key))
        expect_true("help" %in% names(metadata), paste("Metadata should have help:", key))
        expect_true("ref" %in% names(metadata), paste("Metadata should have ref:", key))
      } else {
        param_count <- param_count + 1
      }
    }
  }
  
  # Should have substantial metadata
  expect_true(metadata_count >= 5, "Should have substantial metadata entries")
  expect_equal(metadata_count, param_count)
})

# Performance and basic functionality test
test_that("function loading and basic structure is reasonable", {
  # Load the function
  if (file.exists("R/input.R")) {
    source("R/input.R")
  } else if (file.exists("../../R/input.R")) {
    source("../../R/input.R")
  }
  
  skip_if_not(exists("get_input", mode = "function"), "get_input function not available")
  
  # Test that function exists and can be called (we'll let it fail gracefully on missing files)
  expect_true(is.function(get_input), "get_input should be a function")
  
  # Test parameter validation
  expect_true(length(formals(get_input)) >= 5, "Function should have multiple parameters")
  
  # Test that function either works or fails gracefully
  # If config files are found, it should work (or fail on placeholders for US)
  # If config files are missing, it should fail with clear error message
  result <- tryCatch({
    input <- get_input()
    "success"
  }, error = function(e) {
    e$message
  })
  
  # Either it works (returns input) or fails with a reasonable error message
  expect_true(
    result == "success" || grepl("Configuration file.*not found|PLACEHOLDER", result),
    paste("Function should either work or fail gracefully. Got:", result)
  )
})

# Test that we can detect the structure we need for testing
test_that("test environment can access necessary files", {
  # Should be able to find either the source file or config files
  has_source <- file.exists("R/input.R") || file.exists("../../R/input.R")
  
  has_configs <- FALSE
  possible_paths <- c(
    system.file("config", package = "epicR"),
    file.path(dirname(dirname(getwd())), "inst", "config"),
    "inst/config",
    "../../inst/config"
  )
  
  for (config_dir in possible_paths) {
    if (dir.exists(config_dir) && 
        file.exists(file.path(config_dir, "config_canada.json"))) {
      has_configs <- TRUE
      break
    }
  }
  
  expect_true(has_source || has_configs, 
              "Test environment should have access to either source or config files")
})

Try the epicR package in your browser

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

epicR documentation built on March 8, 2026, 5:06 p.m.