tests/testthat/test-config-reload.R

# Test config file automatic reload functionality
# This test suite validates that simulate() detects and reloads changed config files

library(testthat)
library(jsonlite)

test_that("session_env has config tracking variables", {
  # Load core functions
  if (file.exists("R/core.R")) {
    source("R/core.R")
  } else if (file.exists("../../R/core.R")) {
    source("../../R/core.R")
  }

  skip_if_not(exists("session_env"), "session_env not available")

  # Check that tracking variables exist
  expect_true(exists("config_file_path", envir = session_env),
              "session_env should have config_file_path")
  expect_true(exists("config_file_mtime", envir = session_env),
              "session_env should have config_file_mtime")
})

test_that("get_input stores config file info in session_env", {
  # Load input functions
  if (file.exists("R/input.R")) {
    source("R/input.R")
  } else if (file.exists("../../R/input.R")) {
    source("../../R/input.R")
  }

  # Load core to get session_env
  if (file.exists("R/core.R")) {
    source("R/core.R")
  } else if (file.exists("../../R/core.R")) {
    source("../../R/core.R")
  }

  skip_if_not(exists("get_input", mode = "function"),
              "get_input function not available")
  skip_if_not(exists("session_env"), "session_env not available")

  # Try to load input (may fail if config missing, that's OK)
  result <- tryCatch({
    input <- get_input(jurisdiction = "canada")
    "success"
  }, error = function(e) {
    e$message
  })

  # If it succeeded, check that session_env was populated
  if (result == "success") {
    expect_true(!is.null(session_env$config_file_path),
                "session_env$config_file_path should be set after get_input")
    expect_true(!is.null(session_env$config_file_mtime),
                "session_env$config_file_mtime should be set after get_input")
    expect_true(file.exists(session_env$config_file_path),
                "stored config file path should exist")
  }
})

test_that("simulate detects config file changes", {
  # This is an integration test that requires a working config file
  # Skip if we can't find config files

  # Load functions
  if (file.exists("R/input.R")) {
    source("R/input.R")
  } else if (file.exists("../../R/input.R")) {
    source("../../R/input.R")
  }

  if (file.exists("R/core.R")) {
    source("R/core.R")
  } else if (file.exists("../../R/core.R")) {
    source("../../R/core.R")
  }

  skip_if_not(exists("get_input", mode = "function"),
              "get_input function not available")
  skip_if_not(exists("session_env"), "session_env not available")

  # Try to get initial config
  result <- tryCatch({
    input <- get_input(jurisdiction = "canada")
    "success"
  }, error = function(e) {
    e$message
  })

  skip_if(result != "success", "Config file not available for testing")

  # Store original values
  original_path <- session_env$config_file_path
  original_mtime <- session_env$config_file_mtime

  expect_true(!is.null(original_path), "Original path should be set")
  expect_true(!is.null(original_mtime), "Original mtime should be set")

  # Simulate a file change by manually updating the mtime
  # (We don't want to actually modify the config file in tests)
  session_env$config_file_mtime <- original_mtime - 3600  # 1 hour ago

  # Create a mock check for file modification
  if (file.exists(original_path)) {
    current_mtime <- file.info(original_path)$mtime

    # Check that the modification check logic would work
    expect_true(current_mtime != session_env$config_file_mtime,
                "Modified mtime should differ from current file mtime")
  }

  # Restore original state
  session_env$config_file_mtime <- original_mtime
})

test_that("config file message formatting is correct", {
  # Load functions
  if (file.exists("R/core.R")) {
    source("R/core.R")
  } else if (file.exists("../../R/core.R")) {
    source("../../R/core.R")
  }

  skip_if_not(exists("simulate", mode = "function"),
              "simulate function not available")

  # Check that simulate function has the config change detection code
  simulate_source <- if (file.exists("R/core.R")) {
    "R/core.R"
  } else {
    "../../R/core.R"
  }

  skip_if_not(file.exists(simulate_source), "Core source file not found")

  source_lines <- readLines(simulate_source)
  source_text <- paste(source_lines, collapse = "\n")

  # Check for config change detection logic
  expect_true(grepl("config_changed", source_text),
              "simulate should have config_changed variable")
  expect_true(grepl("config_file_mtime", source_text),
              "simulate should check config_file_mtime")
  expect_true(grepl("Config file has been modified", source_text),
              "simulate should have config modified message")
  expect_true(grepl("Reloaded config from", source_text),
              "simulate should have config reload message")
})

test_that("init_session displays working directory", {
  # Load core functions
  if (file.exists("R/core.R")) {
    source("R/core.R")
  } else if (file.exists("../../R/core.R")) {
    source("../../R/core.R")
  }

  skip_if_not(exists("init_session", mode = "function"),
              "init_session function not available")

  # Check source code for working directory message
  init_source <- if (file.exists("R/core.R")) {
    "R/core.R"
  } else {
    "../../R/core.R"
  }

  skip_if_not(file.exists(init_source), "Core source file not found")

  source_lines <- readLines(init_source)
  source_text <- paste(source_lines, collapse = "\n")

  expect_true(grepl("Working directory", source_text),
              "init_session should display working directory")
  expect_true(grepl("getwd\\(\\)", source_text),
              "init_session should call getwd()")
})

test_that("get_input displays which config file is being used", {
  # Load input functions
  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 that messages are present in the function
  input_source <- if (file.exists("R/input.R")) {
    "R/input.R"
  } else {
    "../../R/input.R"
  }

  skip_if_not(file.exists(input_source), "Input source file not found")

  source_lines <- readLines(input_source)
  source_text <- paste(source_lines, collapse = "\n")

  expect_true(grepl("Using user config file from", source_text),
              "get_input should have user config file message")
  expect_true(grepl("Using package config file from", source_text),
              "get_input should have package config file message")
})

test_that("config file path tracking works across multiple calls", {
  # Load functions
  if (file.exists("R/input.R")) {
    source("R/input.R")
  } else if (file.exists("../../R/input.R")) {
    source("../../R/input.R")
  }

  if (file.exists("R/core.R")) {
    source("R/core.R")
  } else if (file.exists("../../R/core.R")) {
    source("../../R/core.R")
  }

  skip_if_not(exists("get_input", mode = "function"),
              "get_input function not available")
  skip_if_not(exists("session_env"), "session_env not available")

  # Clear session env
  session_env$config_file_path <- NULL
  session_env$config_file_mtime <- NULL

  # Try first call
  result1 <- tryCatch({
    input1 <- get_input(jurisdiction = "canada")
    "success"
  }, error = function(e) {
    e$message
  })

  skip_if(result1 != "success", "Config file not available")

  path1 <- session_env$config_file_path
  mtime1 <- session_env$config_file_mtime

  # Second call should update to same values
  result2 <- tryCatch({
    input2 <- get_input(jurisdiction = "canada")
    "success"
  }, error = function(e) {
    e$message
  })

  expect_equal(result2, "success", "Second call should succeed")
  expect_equal(session_env$config_file_path, path1,
               "Path should remain consistent")
  expect_equal(session_env$config_file_mtime, mtime1,
               "Mtime should be consistent for unchanged file")
})

test_that("config reload logic handles missing files gracefully", {
  # Load functions
  if (file.exists("R/core.R")) {
    source("R/core.R")
  } else if (file.exists("../../R/core.R")) {
    source("../../R/core.R")
  }

  skip_if_not(exists("session_env"), "session_env not available")

  # Set session_env to point to non-existent file
  session_env$config_file_path <- "/tmp/nonexistent_config_12345.json"
  session_env$config_file_mtime <- Sys.time()

  # The check in simulate should handle this gracefully
  # (it checks file.exists before comparing mtimes)
  config_changed <- FALSE
  if (!is.null(session_env$config_file_path) &&
        !is.null(session_env$config_file_mtime) &&
        file.exists(session_env$config_file_path)) {
    config_changed <- TRUE
  }

  expect_false(config_changed,
               "Should not detect change when file doesn't exist")
})

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.