Nothing
# Tests for chunkVector --------------------------------------------------------
# ------------------------------------------------------------------
# Test: chunkVector returns a single chunk when n_chunks <= 1
# Input:
# - x = 1:10
# - n_chunks = 1
# Behaviour:
# - returns list(x) (one chunk containing all elements)
# Expectations:
# - output is a list of length 1
# - the only element equals x exactly
# Why:
# - ensures the "no chunking" path is stable and predictable.
# ------------------------------------------------------------------
test_that("chunkVector returns single chunk when n_chunks <= 1", {
x <- 1:10
out <- chunkVector(x, n_chunks = 1)
expect_type(out, "list")
expect_length(out, 1)
expect_identical(out[[1]], x)
})
# ------------------------------------------------------------------
# Test: chunkVector splits into multiple chunks and preserves all elements
# Input:
# - x = 1:10
# - n_chunks = 2, 3
# Behaviour:
# - splits x into n_chunks chunks
# Expectations:
# - output is a list with requested length
# - unlisted output contains exactly the original elements
# Why:
# - verifies chunking doesn't drop or duplicate elements.
# ------------------------------------------------------------------
test_that("chunkVector splits into multiple chunks and preserves elements", {
x <- 1:10
out2 <- chunkVector(x, n_chunks = 2)
expect_type(out2, "list")
expect_length(out2, 2)
expect_identical(sort(unlist(out2)), x)
out3 <- chunkVector(x, n_chunks = 3)
expect_type(out3, "list")
expect_length(out3, 3)
expect_identical(sort(unlist(out3)), x)
})
# Tests for convertVector2Matrix -----------------------------------------------
# ------------------------------------------------------------------
# Test: convertVector2Matrix converts a vector to a 1-row matrix
# Input:
# - vector = c(1,2,3,4)
# Behaviour:
# - wraps into a matrix and transposes to 1 x length(vector)
# Expectations:
# - result is a matrix with dim (1,4)
# - content equals the original vector
# Why:
# - many downstream functions assume matrix input.
# ------------------------------------------------------------------
test_that("convertVector2Matrix converts vector to 1-row matrix", {
v <- 1:4
out <- convertVector2Matrix(v)
expect_true(is.matrix(out))
expect_equal(dim(out), c(1, 4))
expect_identical(as.integer(out[1, ]), v)
})
# ------------------------------------------------------------------
# Test: convertVector2Matrix returns matrix unchanged
# Input:
# - matrix input
# Behaviour:
# - should not modify an existing matrix
# Expectations:
# - identical to the original matrix
# Why:
# - prevents accidental reshaping when caller already provides a matrix.
# ------------------------------------------------------------------
test_that("convertVector2Matrix leaves matrices unchanged", {
m <- matrix(1:6, nrow = 2)
out <- convertVector2Matrix(m)
expect_true(is.matrix(out))
expect_identical(out, m)
})
# Tests for createHashTable + getHashValues ------------------------------------
# ------------------------------------------------------------------
# Test: createHashTable stores key-value pairs retrievable via getHashValues
# Input:
# - keys = c("a","b","c")
# - values = list(10,20,30)
# Behaviour:
# - creates hash and assigns values to keys
# Expectations:
# - returned object is an environment
# - getHashValues returns values in the requested key order
# Why:
# - mapUniqueTrials relies on retrieval from hashed keys.
# ------------------------------------------------------------------
test_that("createHashTable and getHashValues store and retrieve values", {
keys <- c("a", "b", "c")
vals <- list(10, 20, 30)
h <- createHashTable(keys, vals)
expect_true(is.environment(h))
out <- getHashValues(c("b", "a"), h)
expect_type(out, "list")
expect_equal(out, list(20, 10))
})
# Tests for getHashKeys ---------------------------------------------------------
# ------------------------------------------------------------------
# Test: getHashKeys uses default x1..xp names if colnames are missing
# Input:
# - 2x2 matrix without colnames
# Behaviour:
# - returns character keys "x1:<val>|x2:<val>" per row
# Expectations:
# - correct key strings for each row
# Why:
# - hashing must be stable even when matrices lack colnames.
# ------------------------------------------------------------------
test_that("getHashKeys uses default x* names without colnames", {
x <- matrix(c(1, 2, 3, 4), nrow = 2, byrow = TRUE)
out <- getHashKeys(x)
expect_type(out, "character")
expect_length(out, 2)
expect_identical(out[1], "x1:1|x2:2")
expect_identical(out[2], "x1:3|x2:4")
})
# ------------------------------------------------------------------
# Test: getHashKeys uses existing colnames when present
# Input:
# - 2x2 matrix with colnames c("A","B")
# Behaviour:
# - returns "A:<val>|B:<val>" per row
# Expectations:
# - correct key strings for each row
# Why:
# - ensures keys remain consistent when names exist.
# ------------------------------------------------------------------
test_that("getHashKeys uses colnames when present", {
x <- matrix(c(1, 2, 3, 4), nrow = 2, byrow = TRUE)
colnames(x) <- c("A", "B")
out <- getHashKeys(x)
expect_identical(out[1], "A:1|B:2")
expect_identical(out[2], "A:3|B:4")
})
# Tests for cummulativeMovingAverage -------------------------------------------
# ------------------------------------------------------------------
# Test: cummulativeMovingAverage returns running mean
# Input:
# - x = c(2,4,6,8)
# Behaviour:
# - returns cumsum(x) / seq_along(x)
# Expectations:
# - equals c(2,3,4,5)
# Why:
# - check for helper used in summaries.
# ------------------------------------------------------------------
test_that("cummulativeMovingAverage returns running mean", {
x <- c(2, 4, 6, 8)
out <- cummulativeMovingAverage(x)
expect_equal(out, c(2, 3, 4, 5))
})
# Tests for firstUpper ----------------------------------------------------------
# ------------------------------------------------------------------
# Test: firstUpper capitalizes only the first character
# Input:
# - "hello", "Hello", "h"
# Behaviour:
# - replaces first character with uppercase
# Expectations:
# - correct transformed strings
# Why:
# - ensures string formatting is deterministic.
# ------------------------------------------------------------------
test_that("firstUpper capitalizes first character", {
expect_identical(firstUpper("hello"), "Hello")
expect_identical(firstUpper("Hello"), "Hello")
expect_identical(firstUpper("h"), "H")
})
# Tests for getBlankString ------------------------------------------------------
# ------------------------------------------------------------------
# Test: getBlankString returns a string of spaces of requested length
# Input:
# - length = 0, 3, 10
# Behaviour:
# - concatenates that many " " characters
# Expectations:
# - correct string and nchar
# Why:
# - used for formatting and alignment in text outputs.
# ------------------------------------------------------------------
test_that("getBlankString returns requested number of spaces", {
out0 <- getBlankString(0)
expect_type(out0, "character")
expect_length(out0, 0)
out5 <- getBlankString(5)
expect_identical(out5, " ")
expect_type(out5, "character")
expect_length(out5, 1)
})
# Tests for getListLevel --------------------------------------------------------
# ------------------------------------------------------------------
# Test: getListLevel returns nesting depth
# Input:
# - non-list and nested lists
# Behaviour:
# - returns 0 for non-list; otherwise 1 + depth of first element
# Expectations:
# - correct depths for 0..3 levels
# Why:
# - scaleRoundList relies on correct depth to traverse lists.
# ------------------------------------------------------------------
test_that("getListLevel returns correct nesting depth", {
expect_identical(getListLevel(1), 0)
expect_identical(getListLevel(list(1)), 1)
expect_identical(getListLevel(list(list(1))), 2)
expect_identical(getListLevel(list(list(list(1)))), 3)
})
# Tests for getRowIndexOfVectorInMatrix ----------------------------------------
# ------------------------------------------------------------------
# Test: getRowIndexOfVectorInMatrix finds exact matching row
# Input:
# - matrix with known rows
# - vectors equal to those rows
# Behaviour:
# - returns the indices of rows where all columns match
# Expectations:
# - correct row index returned; empty integer for no match
# Why:
# - used to map trial patterns to unique rows.
# ------------------------------------------------------------------
test_that("getRowIndexOfVectorInMatrix finds matching rows", {
m <- matrix(
c(1, 2,
3, 4,
1, 9),
ncol = 2,
byrow = TRUE
)
expect_identical(getRowIndexOfVectorInMatrix(c(1, 2), m), 1L)
expect_identical(getRowIndexOfVectorInMatrix(c(3, 4), m), 2L)
expect_identical(getRowIndexOfVectorInMatrix(c(1, 9), m), 3L)
expect_length(getRowIndexOfVectorInMatrix(c(7, 7), m), 0)
})
# ------------------------------------------------------------------
# Test: getRowIndexOfVectorInMatrix errors if vector length != ncol(matrix)
# Input:
# - vector of wrong length
# Behaviour:
# - stops with informative error
# Expectations:
# - error is thrown
# Why:
# - prevents silent partial matching / wrong indexing.
# ------------------------------------------------------------------
test_that("getRowIndexOfVectorInMatrix errors on length mismatch", {
m <- matrix(1:4, ncol = 2)
expect_error(
getRowIndexOfVectorInMatrix(c(1, 2, 3), m),
"length of the vector must be equal"
)
})
# Tests for invLogit ------------------------------------------------------------
# ------------------------------------------------------------------
# Test: invLogit matches stats::binomial()$linkinv and inverts logit
# Input:
# - theta = 0 and theta = logit(p)
# Behaviour:
# - returns inverse logit
# Expectations:
# - invLogit(0) = 0.5
# - invLogit(logit(p)) = p
# Why:
# - core link utilities must be numerically correct.
# ------------------------------------------------------------------
test_that("invLogit returns correct inverse-logit values", {
expect_equal(invLogit(0), 0.5)
p <- c(0.1, 0.25, 0.8)
expect_equal(invLogit(logit(p)), p, tolerance = 1e-12)
})
# ------------------------------------------------------------------
# Test: invLogit validates inputs
# Input:
# - missing theta, non-numeric theta
# Behaviour:
# - stops with the documented error
# Expectations:
# - error thrown
# Why:
# - input validation prevents silent misuse.
# ------------------------------------------------------------------
test_that("invLogit errors for missing or non-numeric input", {
expect_error(invLogit(), "Please provide a numeric")
expect_error(invLogit("x"), "Please provide a numeric")
})
# Tests for logit ---------------------------------------------------------------
# ------------------------------------------------------------------
# Test: logit matches stats::binomial()$linkfun and inverts invLogit
# Input:
# - p = 0.5 and random p values in (0,1)
# Behaviour:
# - returns log(p/(1-p))
# Expectations:
# - logit(0.5) = 0
# - invLogit(logit(p)) = p
# Why:
# - correctness of link function is fundamental for Berry/ExNex models.
# ------------------------------------------------------------------
test_that("logit returns correct log-odds and inverts invLogit", {
expect_equal(logit(0.5), 0)
p <- c(0.1, 0.25, 0.8)
expect_equal(invLogit(logit(p)), p, tolerance = 1e-12)
})
# ------------------------------------------------------------------
# Test: logit validates inputs
# Input:
# - missing p, non-numeric p, p outside [0,1]
# Behaviour:
# - stops with the documented error
# Expectations:
# - error thrown
# Why:
# - prevents invalid probability inputs leaking into models.
# ------------------------------------------------------------------
test_that("logit errors for invalid input", {
expect_error(logit(), "Please provide a numeric")
expect_error(logit("x"), "Please provide a numeric")
expect_error(logit(c(-0.1, 0.2)), "Please provide a numeric")
expect_error(logit(c(0.2, 1.2)), "Please provide a numeric")
})
# Tests for listPerMethod ------------------------------------------------------
# ------------------------------------------------------------------
# Test: listPerMethod reshapes scenario-first lists into method-first lists
# Input:
# - analyses_list created via simulateScenarios() + performAnalyses()
# - estimates_per_method from getEstimates() (method-first)
# - scenario-first object reconstructed from estimates_per_method
# Behaviour:
# - listPerMethod() should convert scenario-first -> method-first
# Expectations:
# - Output equals estimates_per_method (same methods, same scenarios, same matrices)
# Why:
# - Verifies listPerMethod performs pure reshaping on real package outputs.
# ------------------------------------------------------------------
test_that("listPerMethod reshapes scenario-first lists into method-first lists", {
skip_if_not_installed("foreach")
foreach::registerDoSEQ()
set.seed(123)
method_names <- c("pooled", "stratified")
target_rates <- c(0.5, 0.5)
scen <- simulateScenarios(
n_subjects_list = list(c(10, 10), c(20, 20)),
response_rates_list = list(c(0.4, 0.4), c(0.6, 0.6)),
n_trials = 2
)
analyses <- performAnalyses(
scenario_list = scen,
evidence_levels = c(0.05, 0.5, 0.95),
target_rates = target_rates,
method_names = method_names,
n_mcmc_iterations = 200,
verbose = FALSE
)
estimates_per_method <- getEstimates(
analyses_list = analyses,
point_estimator = "median",
alpha_level = 0.10
)
method_names_from_obj <- names(estimates_per_method)
scenario_names <- names(estimates_per_method[[1]])
expect_true(all(grepl("^scenario_[0-9]+$", scenario_names)))
scenario_first <- vector("list", length = length(scenario_names))
names(scenario_first) <- scenario_names
for (s in scenario_names) {
scenario_first[[s]] <- lapply(
method_names_from_obj,
function(m) estimates_per_method[[m]][[s]]
)
names(scenario_first[[s]]) <- method_names_from_obj
}
reshaped <- listPerMethod(scenario_first)
expect_setequal(names(reshaped), method_names_from_obj)
expect_setequal(names(reshaped[[method_names_from_obj[1]]]), scenario_names)
for (m in method_names_from_obj) {
for (s in scenario_names) {
expect_equal(reshaped[[m]][[s]], estimates_per_method[[m]][[s]])
}
}
})
# Tests for roundList -----------------------------------------------------------
# ------------------------------------------------------------------
# Test: roundList rounds numerics for nesting levels 1..3
# Input:
# - list structures with depths 1, 2, 3
# Behaviour:
# - rounds each numeric entry to round_digits
# Expectations:
# - correct rounded outputs
# Why:
# - ensures list traversal is correct for supported nesting depths.
# ------------------------------------------------------------------
test_that("roundList rounds list entries for levels 1..3", {
l1 <- list(1.234, 2.345)
expect_equal(roundList(l1, round_digits = 1, list_levels = 1), list(1.2, 2.3))
l2 <- list(a = list(1.234), b = list(2.345))
expect_equal(roundList(l2, round_digits = 2, list_levels = 2), list(a = list(1.23), b = list(2.35)))
l3 <- list(a = list(b = list(1.234)))
expect_equal(roundList(l3, round_digits = 0, list_levels = 3), list(a = list(b = list(1))))
})
# ------------------------------------------------------------------
# Test: roundList errors for non-numeric entries and unsupported depth
# Input:
# - list containing non-numeric
# - list_levels > 3
# Behaviour:
# - stops with informative error
# Expectations:
# - error thrown
# Why:
# - avoids silently returning wrong types.
# ------------------------------------------------------------------
test_that("roundList errors for non-numerics and unsupported depth", {
expect_error(roundList(list("x"), round_digits = 1, list_levels = 1), "must contain numerics")
expect_error(roundList(list(1), round_digits = 1, list_levels = 4), "greater than 3")
})
# Tests for scaleList -----------------------------------------------------------
# ------------------------------------------------------------------
# Test: scaleList scales numerics for nesting levels 1..3
# Input:
# - list structures with depths 1, 2, 3
# Behaviour:
# - multiplies each numeric by scale_param
# Expectations:
# - correct scaled outputs
# Why:
# - used by scaleRoundList; must behave deterministically.
# ------------------------------------------------------------------
test_that("scaleList scales list entries for levels 1..3", {
l1 <- list(1, 2)
expect_equal(scaleList(l1, scale_param = 10, list_levels = 1), list(10, 20))
l2 <- list(a = list(1), b = list(2))
expect_equal(scaleList(l2, scale_param = 0.5, list_levels = 2), list(a = list(0.5), b = list(1)))
l3 <- list(a = list(b = list(2)))
expect_equal(scaleList(l3, scale_param = 3, list_levels = 3), list(a = list(b = list(6))))
})
# ------------------------------------------------------------------
# Test: scaleList errors for non-numeric entries and unsupported depth
# Input:
# - list containing non-numeric
# - list_levels > 3
# Behaviour:
# - stops with informative error
# Expectations:
# - error thrown
# Why:
# - protects against silent type coercion.
# ------------------------------------------------------------------
test_that("scaleList errors for non-numerics and unsupported depth", {
expect_error(scaleList(list("x"), scale_param = 2, list_levels = 1), "must contain numerics")
expect_error(scaleList(list(1), scale_param = 1, list_levels = 4), "greater than 3")
})
# Tests for scaleRoundList ------------------------------------------------------
# ------------------------------------------------------------------
# Test: scaleRoundList applies scaling then rounding
# Input:
# - list of numerics
# Behaviour:
# - scales by scale_param then rounds to round_digits
# Expectations:
# - correct scaled+rounded values
# Why:
# - user-facing helper; expected to behave consistently.
# ------------------------------------------------------------------
test_that("scaleRoundList scales then rounds list entries", {
skip_if_not_installed("checkmate")
l <- list(1.234, 2.345)
out <- scaleRoundList(list = l, scale_param = 10, round_digits = 1)
expect_equal(out, list(12.3, 23.5))
})
# ------------------------------------------------------------------
# Test: scaleRoundList returns unchanged list if round_digits is NULL
# Input:
# - list of numerics, round_digits = NULL
# Behaviour:
# - scales by scale_param, does no rounding when round_digits is NULL
# Expectations:
# - equals scaled values (or original if scale_param = 1)
# Why:
# - matches documented behaviour and avoids surprising rounding.
# ------------------------------------------------------------------
test_that("scaleRoundList skips rounding when round_digits is NULL", {
skip_if_not_installed("checkmate")
l <- list(1.234, 2.345)
out <- scaleRoundList(list = l, scale_param = 1, round_digits = NULL)
expect_equal(out, l)
})
# ------------------------------------------------------------------
# Test: scaleRoundList validates inputs
# Input:
# - missing list / non-list
# - invalid scale_param
# - invalid round_digits
# Behaviour:
# - stops with informative errors
# Expectations:
# - error thrown
# Why:
# - ensures correct user-facing input checks.
# ------------------------------------------------------------------
test_that("scaleRoundList errors for invalid inputs", {
skip_if_not_installed("checkmate")
expect_error(scaleRoundList(), "Please provide a list")
expect_error(scaleRoundList(list = 1), "Please provide a list")
l <- list(1.234)
expect_error(scaleRoundList(list = l, scale_param = -1))
expect_error(scaleRoundList(list = l, round_digits = -1))
})
# Tests for substrRight ---------------------------------------------------------
# ------------------------------------------------------------------
# Test: substrRight returns rightmost n characters
# Input:
# - x = "abcdef", n = 1,2,6
# Behaviour:
# - returns substring from the right
# Expectations:
# - correct suffixes
# Why:
# - used for parsing parameter/cohort suffix indices.
# ------------------------------------------------------------------
test_that("substrRight returns rightmost n characters", {
expect_identical(substrRight("abcdef", 1), "f")
expect_identical(substrRight("abcdef", 2), "ef")
expect_identical(substrRight("abcdef", 6), "abcdef")
})
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.