tests/testthat/test-extractRegimeVCVs.R

# tests/testthat/test-extractRegimeVCVs.R

# testthat::local_edition(3)

# Helpers
mock_model_output <- function(Pinv, params_named) {
  stopifnot(is.matrix(Pinv), is.numeric(params_named), !is.null(names(params_named)))
  list(
    param = params_named,
    sigma = list(Pinv = Pinv)
  )
}

# Group: missing-component handling

# Test: Returns NULL when required components are missing (checks return value)
test_that("Returns NULL when required components are missing", {
  # Missing 'param'
  m1 <- list(sigma = list(Pinv = diag(2)))
  expect_null(extractRegimeVCVs(m1))

  # Missing 'sigma'
  m2 <- list(param = c(r1 = 1))
  expect_null(extractRegimeVCVs(m2))

  # Missing 'Pinv' inside sigma
  m3 <- list(param = c(r1 = 1), sigma = list())
  expect_null(extractRegimeVCVs(m3))
})

# Group: scaling behavior
# Test: Single-regime: returns list of one matrix equal to base Pinv (checks return value)
test_that("Single-regime: returns list of one matrix equal to base Pinv", {
  Pinv <- matrix(c(2, 0.3,
                   0.3, 1), nrow = 2, byrow = TRUE)
  params <- c(r1 = 1.5)

  model_out <- mock_model_output(Pinv, params)
  vcv_list  <- extractRegimeVCVs(model_out)

  expect_type(vcv_list, "list")
  expect_equal(names(vcv_list), "r1")
  expect_true(is.matrix(vcv_list[[1]]))
  expect_equal(dim(vcv_list[[1]]), dim(Pinv))
  expect_equal(vcv_list[[1]], Pinv)
})

# Test: Multi-regime: later regimes are scaled by param/base_param ratio
test_that("Multi-regime: later regimes are scaled by param/base_param ratio", {
  Pinv <- matrix(c(1, 0.2,
                   0.2, 0.5), nrow = 2, byrow = TRUE)
  # base_param = 2; others scaled vs 2
  params <- c(r1 = 2, r2 = 3, r3 = 0.5)

  model_out <- mock_model_output(Pinv, params)
  vcv_list  <- extractRegimeVCVs(model_out)

  expect_equal(names(vcv_list), c("r1", "r2", "r3"))
  expect_true(all(vapply(vcv_list, is.matrix, logical(1))))
  expect_true(all(vapply(vcv_list, function(m) all(dim(m) == dim(Pinv)), logical(1))))

  # r1: unscaled
  expect_equal(vcv_list$r1, Pinv)

  # r2: scaled by 3/2
  expect_equal(vcv_list$r2, Pinv * (3/2))

  # r3: scaled by 0.5/2 = 0.25
  expect_equal(vcv_list$r3, Pinv * 0.25)
})

# Group: numeric edge cases
# Test: Works with non-identity, non-diagonal base matrix and preserves numeric type (smoke test with valid inputs)
test_that("Works with non-identity, non-diagonal base matrix and preserves numeric type", {
  Pinv <- matrix(c(4, 1, 0.5,
                   1, 3, 0.2,
                   0.5, 0.2, 2),
                 nrow = 3, byrow = TRUE)
  params <- c(A = 1, B = 4)

  model_out <- mock_model_output(Pinv, params)
  vcv_list  <- extractRegimeVCVs(model_out)

  expect_equal(names(vcv_list), c("A", "B"))
  expect_equal(vcv_list$A, Pinv)              # base unchanged
  expect_equal(vcv_list$B, Pinv * (4/1))      # scaled by 4
  expect_true(is.numeric(vcv_list$B[1, 1]))
})

# Test: Handles tiny floating ratios without precision blow-ups (edge-case input)
test_that("Handles tiny floating ratios without precision blow-ups", {
  Pinv <- diag(2)
  params <- c(baseline = 1e6, slow = 1e-6)  # ratio = 1e-12

  model_out <- mock_model_output(Pinv, params)
  vcv_list  <- extractRegimeVCVs(model_out)

  expect_equal(vcv_list$baseline, Pinv)
  expect_equal(vcv_list$slow, Pinv * 1e-12, tolerance = 1e-18)
})

# Group: alternate entry points
# Test: extractRegimeVCVs returns NULL when required components are missing (checks return value)
test_that("extractRegimeVCVs returns NULL when required components are missing", {
  testthat::expect_null(extractRegimeVCVs(list()))

  # has param but missing sigma$Pinv
  testthat::expect_null(extractRegimeVCVs(list(
    param = c(r1 = 1),
    sigma = list()
  )))

  # has sigma$Pinv but missing param
  testthat::expect_null(extractRegimeVCVs(list(
    sigma = list(Pinv = diag(2))
  )))
})

# Test: extractRegimeVCVs returns per-regime matrices and scales by param ratio (checks return value)
test_that("extractRegimeVCVs returns per-regime matrices and scales by param ratio", {
  model_output <- list(
    param = c(r1 = 1, r2 = 3),
    sigma = list(Pinv = matrix(c(1, 2,
                                 3, 4), nrow = 2))
  )

  out <- extractRegimeVCVs(model_output)

  testthat::expect_true(is.list(out))
  testthat::expect_true(all(c("r1", "r2") %in% names(out)))
  testthat::expect_true(is.matrix(out[["r1"]]) && is.matrix(out[["r2"]]))

  # First regime is base matrix
  testthat::expect_equal(out[["r1"]], model_output$sigma$Pinv)

  # Second regime scaled by param ratio (r2/r1 = 3)
  testthat::expect_equal(out[["r2"]], model_output$sigma$Pinv * 3)
})

Try the bifrost package in your browser

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

bifrost documentation built on April 17, 2026, 9:07 a.m.