data.table::setDTthreads(1) # For CRAN
obs_test <- obs(y ~ x + w, family = "gaussian")
set.seed(0)
timepoints <- 10
individuals <- 5
total_obs <- timepoints * individuals
test_data <- data.frame(
time = 1:timepoints,
group = gl(individuals, timepoints),
offset = sample(50:100, size = total_obs, replace = TRUE),
trials = sample(50:100, size = total_obs, replace = TRUE)
) |>
dplyr::mutate(
y1 = as.factor(sample(5, size = total_obs, replace = TRUE)),
y2 = rnorm(n = total_obs, mean = 1, sd = 2),
y3 = rbinom(n = total_obs, size = trials, prob = 0.75),
y4 = rbinom(n = total_obs, size = 1, prob = 0.66),
y5 = rnbinom(n = total_obs, size = 100, prob = 0.33),
y6 = rpois(n = total_obs, lambda = log(offset) + 1),
y7 = rexp(n = total_obs, rate = 0.1),
y8 = rgamma(n = total_obs, shape = 2, rate = 2 * exp(-5)),
y9 = rbeta(n = total_obs, 6, 4),
x1 = sample(letters[1:4], size = total_obs, replace = TRUE),
x2 = rnorm(total_obs),
x3 = as.factor(sample(4, size = total_obs, replace = TRUE))
)
# Formula errors ----------------------------------------------------------
test_that("missing formula fails", {
expect_error(
obs(),
"Argument `formula` is missing\\."
)
})
test_that("missing family fails", {
expect_error(
obs(y ~ x),
"Argument `family` is missing\\."
)
})
test_that("nonformula to dynamiteformula fails", {
expect_error(
obs(formula = numeric(), family = "gaussian"),
"Argument `formula` must be a <formula> object\\."
)
})
test_that("noncharacter family fails", {
expect_error(
obs(y ~ x, family = data.frame()),
"Argument `family` must be a single <character> string\\."
)
})
test_that("unsupported family fails", {
expect_error(
obs(y ~ x, family = "unknown_distr"),
'Family "unknown_distr" is not supported\\.'
)
})
test_that("as-is use fails", {
expect_error(
obs(y ~ I(x), family = "gaussian"),
"`I\\(\\.\\)` is not supported by `dynamiteformula\\(\\)`\\."
)
})
test_that("duplicate response definition fails", {
expect_error(
obs_test + obs_test,
"Multiple definitions for response variable `y`\\."
)
})
test_that("duplicate spline definition fails", {
expect_error(
obs_test + splines() + splines(),
"Multiple definitions for splines\\."
)
})
test_that("duplicate lags definition fails", {
expect_error(
obs_test + lags() + lags(),
"Multiple definitions for lags\\."
)
})
test_that("adding dynamiteformulas with existing lag definitions fails", {
obs_lhs <- obs_test + lags(k = 1)
obs_rhs <- obs(z ~ x, family = "gaussian") + lags(k = 2)
expect_error(
obs_lhs + obs_rhs,
"Both dynamiteformulas contain a lags definition\\."
)
})
test_that("adding dynamiteformulas with existing splines definitions fails", {
obs_lhs <- obs_test + splines()
obs_rhs <- obs(z ~ x, family = "gaussian") + splines()
expect_error(
obs_lhs + obs_rhs,
"Both dynamiteformulas contain a splines definition\\."
)
})
# test_that("simultaneity fails", {
# obs_lhs <-
# obs(q ~ w + e + r + lag(i), family = "gaussian") +
# obs(t ~ y + u, family = "gaussian") +
# obs(i ~ o + p + a + lag(f), family = "gaussian")
# obs_rhs <-
# obs(f ~ h + l + lag(x), family = "gaussian") +
# obs(x ~ q + z, family = "gaussian")
# expect_error(
# obs_rhs + obs_lhs,
# paste0(
# "Simultaneous regression is not supported:\n",
# "x Response variable `q` appears in the formula of `x`\\."
# )
# )
# # should fail for deterministic as well
# expect_error(
# obs(y ~ x, family = "gaussian") + aux(integer(x) ~ y),
# paste0(
# "Simultaneous regression is not supported:\n",
# "x Response variable `x` appears in the formula of `y`\\."
# )
# )
# })
test_that("cyclic dependency fails", {
obs_lhs <- obs(y ~ x, family = "gaussian") +
obs(z ~ y, family = "gaussian")
obs_rhs <- aux(numeric(w) ~ z + 1) +
obs(x ~ z, family = "gaussian")
expect_error(
obs_lhs + obs_rhs,
"The model must be acyclic\\."
)
})
test_that("contemporaneous self dependency within a channel fails", {
expect_error(
obs(y ~ y, family = "gaussian"),
paste0(
"Contemporaneous self-dependency found in model formula:\n",
"x Variable `y` appears on both sides of the formula for \\(y\\)\\."
)
)
expect_error(
obs(c(y, x) ~ y | 1, family = "mvgaussian"),
paste0(
"Contemporaneous self-dependency found in model formula:\n",
"x Variable `y` appears on both sides of the formula for \\(y, x\\)\\."
)
)
})
test_that("adding nondynamiteformula to dynamiteformula fails", {
expect_error(
obs_test + 1.0,
paste(
"Unable to add an object of class <numeric>",
"to an object of class <dynamiteformula>\\."
)
)
})
test_that("plus method fails for nondynamiteformula", {
expect_error(
`+.dynamiteformula`(data.frame(), numeric()),
paste(
"Method `\\+\\.dynamiteformula\\(\\)` is not supported",
"for <data.frame> objects\\."
)
)
})
test_that("negative lb_tau fails", {
expect_error(
obs_test + splines(lb_tau = -1.0),
"Argument `lb_tau` must be a <numeric> vector of non-negative values\\."
)
})
test_that("time-varying definitions without splines fails", {
obs_varying <- obs(y ~ 1 + varying(~ -1 + x), family = "gaussian")
test_data <- data.frame(
y = c(1, 2, 3),
x = c(0.5, -1, 0.25),
z = c(1, 2, 3)
)
expect_error(
dynamite(obs_varying, test_data, time = "z"),
paste(
"Model for response variable `y` contains time-varying definitions",
"but splines have not been defined\\."
)
)
})
test_that("noncentered definition throws error if not of correct length", {
expect_error(
obs_all_alpha <- obs(y1 ~ -1 + varying(~x1), family = "categorical") +
obs(x3 ~ varying(~ -1 + x1), family = "categorical") +
obs(y2 ~ -1 + x2 + varying(~1), family = "gaussian") +
obs(y3 ~ lag(x3) + trials(trials), family = "binomial") +
obs(y4 ~ x1 + varying(~ -1 + x2), family = "bernoulli") +
obs(y9 ~ -1 + x1 + varying(~x2), family = "beta") +
splines(df = 5, noncentered = rep(TRUE, 3)),
NA
)
expect_error(
dynamite(obs_all_alpha, test_data, "time", "group"),
paste(
"Length of the `noncentered` argument of `splines\\(\\)` function",
"is not equal to 1 or 6, the number of the channels\\."
)
)
})
test_that("lb_tau definition throws error if not of correct length", {
expect_error(
obs_all_alpha <- obs(y1 ~ -1 + varying(~x1), family = "categorical") +
obs(x3 ~ varying(~ -1 + x1), family = "categorical") +
obs(y2 ~ -1 + x2 + varying(~1), family = "gaussian") +
obs(y3 ~ lag(x3) + trials(trials), family = "binomial") +
obs(y4 ~ x1 + varying(~ -1 + x2), family = "bernoulli") +
obs(y9 ~ -1 + x1 + varying(~x2), family = "beta") +
splines(df = 5, lb_tau = rep(1, 3)),
NA
)
expect_error(
dynamite(obs_all_alpha, test_data, "time", "group"),
paste(
"Length of the `lb_tau` argument of `splines\\(\\)` function is not",
"equal to 1 or 6, the number of the channels\\."
)
)
})
test_that("pure deterministic formula to dynamite fails", {
expect_error(
dynamite(
dformula = aux(numeric(d) ~ lag(d, 1)),
data = data.frame(y = c(1, 1), x = c(1, 1), z = c(1, 2)),
group = "x",
time = "z"
),
"Argument `dformula` must contain at least one stochastic channel\\."
)
})
test_that("latent factor errors with invalid responses", {
expect_error(
dynamite(
obs(y ~ x, family = "gaussian") + lfactor(responses = 1),
data = data.frame(y = rnorm(4), x = runif(4), id = 1, time = 1:4),
time = "time",
group = "id",
debug = list(no_compile = TRUE)
),
"Argument `responses` must be a <character> vector\\."
)
expect_error(
dynamite(
obs(y ~ x, family = "gaussian") + lfactor(responses = "x"),
data = data.frame(y = rnorm(4), x = runif(4), id = 1, time = 1:4),
time = "time",
group = "id",
debug = list(no_compile = TRUE)
),
paste0(
"Argument `responses` of `lfactor\\(\\)` contains variable `x`:\n",
"x No such response variables in the model\\."
)
)
})
test_that("latent factor errors with nonlogical value for nonzero_lambda", {
expect_error(
dynamite(
obs(y ~ x, family = "gaussian") + lfactor(nonzero_lambda = 1),
data = data.frame(y = rnorm(4), x = runif(4), id = 1, time = 1:4),
time = "time",
group = "id",
debug = list(no_compile = TRUE)
),
"Argument `nonzero_lambda` must be a <logical> vector\\."
)
})
test_that("Random effect errors with single group", {
expect_error(
dynamite(
obs(y ~ x + random(~1), family = "gaussian"),
data = data.frame(y = rnorm(4), x = runif(4), id = 1, time = 1:4),
time = "time",
group = "id",
debug = list(no_compile = TRUE)
),
"Cannot estimate random effects using only one group\\."
)
})
test_that("Latent factor errors with single group", {
expect_error(
dynamite(
obs(y ~ x, family = "gaussian") + lfactor(),
data = data.frame(y = rnorm(4), x = runif(4), id = 1, time = 1:4),
time = "time",
group = "id",
debug = list(no_compile = TRUE)
),
"Cannot estimate latent factors using only one group\\."
)
})
test_that("latent factor fails with nonlogical value for noncentered_psi", {
expect_error(
dynamite(
obs(y ~ x, family = "gaussian") + lfactor(noncentered_psi = 1),
data = data.frame(y = rnorm(4), x = runif(4), id = 1, time = 1:4),
time = "time",
group = "id",
debug = list(no_compile = TRUE)
),
"Argument `noncentered_psi` must be a single <logical> value\\."
)
})
test_that("latent factor fails with nonlogical value for correlated", {
expect_error(
dynamite(
obs(y ~ x, family = "gaussian") + lfactor(correlated = 1),
data = data.frame(y = rnorm(4), x = runif(4), id = 1, time = 1:4),
time = "time",
group = "id",
debug = list(no_compile = TRUE)
),
"Argument `correlated` must be a single <logical> value\\."
)
})
test_that("update fails with incompatible formula", {
expect_error(
update(
multichannel_example_fit,
obs(y ~ x, family = "gaussian"),
debug = list(no_compile = TRUE)
),
"Can't find variable `x` in `data`\\."
)
})
test_that("multivariate family fails with single response", {
expect_error(
obs(y1 ~ x, family = "mvgaussian"),
"A multivariate channel must have more than one response variable\\."
)
})
test_that("univariate family fails with multiple response variables", {
expect_error(
obs(c(y1, y2) ~ x, family = "gaussian"),
"A univariate channel must have only one response variable\\."
)
})
test_that("invalid number of formula components fails", {
expect_error(
obs(c(y1, y2) ~ x | x | x, family = "mvgaussian"),
paste0(
"Number of component formulas must be 1 ",
"or the number of dimensions: 2\n",
"x 3 formulas were provided\\."
)
)
expect_error(
obs(y1 ~ x | x, family = "gaussian"),
"A univariate channel must have only one formula component\\."
)
})
test_that("multinomial family fails with multiple formula components", {
expect_error(
obs(c(y1, y2, y3) ~ 1 + trials(n) | x | x, family = "multinomial"),
"A multinomial channel must have only one formula component\\."
)
})
test_that("cumulative channel fails without an intercept", {
expect_error(
obs(y ~ -1, family = "cumulative"),
paste0(
"A time-constant or a time-varying intercept must be specified ",
"for a cumulative channel\\."
)
)
})
# Formula specials errors -------------------------------------------------
test_that("no intercept or predictors fails if no lfactor", {
expect_error(
dynamite(
obs(y ~ -1, family = "gaussian"),
data = gaussian_example,
time = "time",
group = "id"
),
paste0(
"Invalid formula for response variable `y`:\n",
"x There are no predictors, intercept terms, or latent factors\\."
)
)
})
test_that("binomial channel without a trials term fails", {
expect_error(
obs(y ~ x, family = "binomial"),
"Formula for a binomial channel must include a trials term\\."
)
})
test_that("multinomial channel without a trials term fails", {
expect_error(
obs(c(y1, y2) ~ 1, family = "multinomial"),
"Formula for a multinomial channel must include a trials term\\."
)
})
test_that("deterministic fixed fails", {
expect_error(
aux(numeric(y) ~ fixed(~x)),
paste0(
"The use of `fixed\\(\\)` is not meaningful ",
"for deterministic channels:\n",
"x Time-invariant definition was found in ",
"`numeric\\(y\\) ~ fixed\\(~x\\)`\\."
)
)
})
test_that("deterministic varying fails", {
expect_error(
aux(numeric(y) ~ varying(~x)),
paste0(
"The use of `varying\\(\\)` is not meaningful ",
"for deterministic channels:\n",
"x Time-varying definition was found in ",
"`numeric\\(y\\) ~ varying\\(~x\\)`\\."
)
)
})
test_that("multiple special components fail", {
expect_error(
obs(y ~ fixed(~1) + fixed(~x), family = "gaussian"),
"Multiple `fixed\\(\\)` terms are not supported\\."
)
expect_error(
obs(y ~ varying(~1) + varying(~x), family = "gaussian"),
"Multiple `varying\\(\\)` terms are not supported\\."
)
expect_error(
obs(y ~ random(~1) + random(~x), family = "gaussian"),
"Multiple `random\\(\\)` terms are not supported\\."
)
})
test_that("specials with multiple arguments fail", {
expect_error(
obs(y ~ fixed(~1, 2), family = "gaussian"),
"A `fixed\\(\\)` term must have a single formula argument\\."
)
expect_error(
obs(y ~ varying(~1, 2), family = "gaussian"),
"A `varying\\(\\)` term must have a single formula argument\\."
)
expect_error(
obs(y ~ random(~1, 2), family = "gaussian"),
"A `random\\(\\)` term must have a single formula argument\\."
)
})
test_that("nested specials fail", {
err <- paste0(
"A model formula must not contain nested ",
"`fixed\\(\\)`, `varying\\(\\)`, or `random\\(\\)` terms\\."
)
expect_error(
obs(y ~ random(~1 + random(~1)), family = "gaussian"),
err
)
expect_error(
obs(y ~ varying(~1 + varying(~1)), family = "gaussian"),
err
)
expect_error(
obs(y ~ fixed(~1 + fixed(~1)), family = "gaussian"),
err
)
expect_error(
obs(y ~ random(~1 + varying(~1)), family = "gaussian"),
err
)
expect_error(
obs(y ~ varying(~1 + random(~1)), family = "gaussian"),
err
)
})
test_that("specials that cannot be evaluated fail", {
expect_error(
dynamite(
obs(y ~ 1 + trials(log(-lag(y))), family = "binomial"),
data = data.frame(y = 1:3, z = 1:3),
time = "z"
),
paste0(
"Unable to evaluate `trials\\(\\)` for response variable `y`:\n",
"x .+"
)
)
expect_error(
dynamite(
obs(y ~ 1 + offset(log(-lag(x))), family = "poisson"),
data = data.frame(y = 1:3, z = 1:3),
time = "z"
),
paste0(
"Unable to evaluate `offset\\(\\)` for response variable `y`:\n",
"x .+"
)
)
})
test_that("test that specials with invalid values fail", {
expect_error(
dynamite(
obs(y ~ 1 + trials(n), family = "binomial"),
data = data.frame(y = 1:3, z = 1:3, n = factor(1:3)),
time = "z"
),
paste0(
"Invalid `trials\\(\\)` definition for response variable `y`:\n",
"x Number of trials cannot be a <factor>\\."
)
)
expect_error(
dynamite(
obs(y ~ 1 + trials(n), family = "binomial"),
data = data.frame(y = 1:3, z = 1:3, n = -(1:3)),
time = "z"
),
paste0(
"Invalid `trials\\(\\)` definition for response variable `y`:\n",
"x Number of trials must contain only positive integers\\."
)
)
expect_error(
dynamite(
obs(y ~ 1 + offset(n), family = "poisson"),
data = data.frame(y = 1:3, z = 1:3, n = factor(1:3)),
time = "z"
),
paste0(
"Invalid `offset\\(\\)` definition for response variable `y`:\n",
"x Offset cannot be a <factor>\\."
)
)
})
# Data errors -------------------------------------------------------------
test_that("missing data object fails", {
expect_error(
dynamite(dformula = obs_test),
"Argument `data` is missing\\."
)
})
test_that("missing time variable fails", {
expect_error(
dynamite(dformula = obs_test, data = data.frame(z = 1), group = "z"),
"Argument `time` is missing\\."
)
})
test_that("data is not data.frame fails", {
expect_error(
dynamite(dformula = obs_test, data = list(), time = "z"),
"Argument `data` must be a <data.frame> object\\."
)
})
test_that("group variable not in data fails", {
expect_error(
dynamite(
dformula = obs_test,
data = data.frame(y = 1, x = 1), time = "x", group = "z"
),
"Can't find grouping variable `z` in `data`\\."
)
})
test_that("time variable not in data fails", {
expect_error(
dynamite(
dformula = obs_test,
data = data.frame(y = 1, x = 1),
time = "z"
),
"Can't find time index variable `z` in `data`\\."
)
})
test_that("single time point fails", {
expect_error(
dynamite(
dformula = obs_test,
data = data.frame(y = 1, x = 1, z = 1),
time = "z",
group = "x"
),
"There must be at least two time points in the data."
)
})
test_that("duplicated time points fail", {
# groups
expect_error(
dynamite(
dformula = obs(y ~ x, family = "gaussian"),
data = data.frame(
y = rep(1, 9),
x = gl(3, 3),
z = c(1, 2, 2, 1, 2, 3, 1, 3, 3)
),
time = "z",
group = "x",
debug = list(no_compile = TRUE)
),
paste0(
"Each time index must correspond to a single observation per group:\n",
"x Groups `1` and `3` of `x` have duplicate observations\\."
)
)
# no groups
expect_error(
dynamite(
dformula = obs(y ~ x, family = "gaussian"),
data = data.frame(
y = rep(1, 3),
z = c(1, 2, 2)
),
time = "z",
debug = list(no_compile = TRUE)
),
paste0(
"Each time index must correspond to a single observation per group:\n",
"x Group `1` of `.group` has duplicate observations\\."
)
)
})
test_that("missing lag variable fails", {
expect_error(
dynamite(
dformula = obs(y ~ lag(d, 1), family = "gaussian"),
data = data.frame(y = c(1, 1), x = c(1, 1), z = c(1, 2)),
time = "z",
group = "x",
debug = list(no_compile = TRUE)
),
paste0(
"Unable to construct lagged values of `d`:\n",
"x Can't find such variables in `data`\\."
)
)
})
test_that("missing predictor fails", {
expect_error(
dynamite(
dformula = obs(y ~ w, family = "gaussian"),
data = data.frame(y = c(1, 1), x = c(1, 1), z = c(1, 2)),
time = "z",
group = "x",
debug = list(no_compile = TRUE)
),
"Can't find variable `w` in `data`\\."
)
})
test_that("invalid deterministic channel definition fails", {
expect_error(
dynamite(
dformula = obs(y ~ x, family = "gaussian") +
aux(integer(d) ~ 1 + w),
data = data.frame(y = c(1, 1), x = c(1, 1), z = c(1, 2)),
time = "z",
group = "x",
debug = list(no_compile = TRUE)
),
paste0(
"Unable to evaluate definitions of deterministic channels:\n",
"x object 'w' not found"
)
)
})
test_that("irregular time intervals fails", {
data_irreg <- data.frame(
y = c(1, 2, 3, 4, 5),
x = c(1, 1, 1, 2, 2),
t = c(2, 5, 7, 3.5, 5.75)
)
expect_error(
dynamite(obs_test, data = data_irreg, group = "x", time = "t"),
"Observations must occur at regular time intervals\\."
)
})
# Data type errors --------------------------------------------------------
#' @srrstats {G2.11, G2.12} Tests for unsupported column types.
test_that("invalid column types fail", {
test_data <- data.frame(y = c(1i, 2i), x = c(1, 1), z = c(1, 2))
test_data$w <- c(list(a = 1), list(b = 2))
test_data$d <- as.raw(c(40, 20))
expect_error(
dynamite(
dformula = obs(y ~ x, family = "gaussian"),
data = test_data,
time = "z",
group = "x",
debug = list(no_compile = TRUE)
),
paste0(
"Columns `y`, `w`, and `d` of `data` are invalid:\n",
"x Column types <complex/list/raw> are not supported\\."
)
)
})
test_that("non-finite values in data fail", {
test_data <- data.frame(
y = c(1, Inf), x = c(1, 1),
z = c(1, 2), w = c(-Inf, 2), u = c(1, Inf)
)
expect_error(
dynamite(
dformula = obs(y ~ x, family = "gaussian"),
data = test_data,
time = "z",
group = "x",
debug = list(no_compile = TRUE)
),
"Non-finite values were found in variables `y`, `w`, and `u` of `data`\\."
)
})
test_that("non-factor categorical response fails", {
test_data <- data.frame(y = c(0, 1), x = c(1, 1), z = c(1, 2))
expect_error(
dynamite(
dformula = obs(y ~ 1, family = "categorical"),
data = test_data,
time = "z",
group = "x",
debug = list(no_compile = TRUE)
),
paste0(
"Response variable `y` is invalid:\n",
"x Categorical family supports only <factor> variables\\."
)
)
})
test_that("factor types for non-categorical families fails", {
test_data <- data.frame(
y = factor(c(0, 1)),
w = c(1, 2),
x = c(1, 1),
z = c(1, 2)
)
families <- c(
"gaussian",
"exponential",
"gamma",
"beta",
"bernoulli",
"binomial",
"poisson",
"negbin",
"student"
)
for (f in families) {
form <- ifelse_(identical(f, "binomial"), y ~ 1 + trials(x), y ~ 1)
expect_error(
dynamite(
dformula = obs(form, family = f),
data = test_data,
time = "z",
group = "x",
debug = list(no_compile = TRUE)
),
paste0(
"Response variable `y` is invalid:\n",
"x .+ family is not supported for <factor> variables\\."
)
)
}
mvfamilies <- c(
"mvgaussian",
"multinomial"
)
for (f in mvfamilies) {
form <- ifelse_(
identical(f, "multinomial"),
c(y, w) ~ 1 + trials(x),
c(y, w) ~ 1
)
expect_error(
dynamite(
dformula = obs(form, family = f),
data = test_data,
time = "z",
group = "x",
debug = list(no_compile = TRUE)
),
paste0(
"Response variable `.+` is invalid:\n",
"x .+ family is not supported for <factor> variables\\."
)
)
}
})
test_that("negative values for distributions with positive support fails", {
test_data <- data.frame(y = c(-1, -2), w = c(1, 2), x = c(1, 1), z = c(1, 2))
families <- c(
"exponential",
"gamma",
"binomial",
"negbin",
"poisson"
)
for (f in families) {
form <- ifelse_(identical(f, "binomial"), y ~ 1 + trials(x), y ~ 1)
expect_error(
dynamite(
dformula = obs(form, family = f),
data = test_data,
time = "z",
group = "x",
debug = list(no_compile = TRUE)
),
paste0(
"Response variable `y` is invalid:\n",
"x .+ family supports only non-negative .+\\."
)
)
}
expect_error(
dynamite(
dformula = obs(c(y, w) ~ 1 + trials(c(2, 3)), family = "multinomial"),
data = test_data,
time = "z",
group = "x",
debug = list(no_compile = TRUE)
),
paste0(
"Response variable `y_w` is invalid:\n",
"x Multinomial family supports only non-negative .+\\."
)
)
})
test_that("bernoulli without 0/1 values fails", {
test_data <- data.frame(y = c(2, 3), x = c(1, 1), z = c(1, 2))
expect_error(
dynamite(
dformula = obs(y ~ 1, family = "bernoulli"),
data = test_data,
time = "z",
group = "x",
debug = list(no_compile = TRUE)
),
paste0(
"Response variable `y` is invalid:\n",
"x Bernoulli family supports only 0/1 integers\\."
)
)
})
test_that("beta without (0, 1) values fails", {
test_data <- data.frame(y = c(2, 3), x = c(1, 1), z = c(1, 2))
expect_error(
dynamite(
dformula = obs(y ~ 1, family = "beta"),
data = test_data,
time = "z",
group = "x",
debug = list(no_compile = TRUE)
),
paste0(
"Response variable `y` is invalid:\n",
"x Beta family supports only values on the open interval \\(0, 1\\)\\."
)
)
})
# Lag errors --------------------------------------------------------------
test_that("invalid lagged value definition fails", {
expect_error(
complete_lags(quote(lag(y, a:b))),
"Invalid shift value expression `a:b`\\."
)
})
test_that("non coerceable shift value fails", {
expect_error(
complete_lags(quote(lag(y, "a"))),
'Unable to coerce shift value to <integer> in `lag\\(y, "a"\\)`\\.'
)
})
test_that("multiple shift values fail", {
expect_error(
complete_lags(quote(lag(y, 1:2))),
paste0(
"Shift value must be a single <integer> in `lag\\(\\)`:\n",
"x Multiple shift values were found in `lag\\(y, 1:2\\)`\\."
)
)
})
test_that("negative lag shift value fails", {
expect_error(
complete_lags(quote(lag(y, -1))),
paste0(
"Shift value must be positive in `lag\\(\\)`:\n",
"x Nonpositive shift value was found in `lag\\(y, -1\\)`\\."
)
)
})
test_that("too many arguments to lag fails", {
expect_error(
complete_lags(quote(lag(y, 1, 2))),
paste0(
"Invalid lag definition `lag\\(y, 1, 2\\)`:\n",
"x Too many arguments supplied to `lag\\(\\)`\\."
)
)
})
# Output errors -----------------------------------------------------------
test_that("output for missing argument fails", {
methods <- c(
"as.data.frame",
"as_draws_df",
"confint",
"coef",
"fitted",
"formula",
"hmc_diagnostics",
"lfo",
"loo",
"mcmc_diagnostics",
"ndraws",
"nobs",
"plot",
"predict",
"print",
"summary",
"update"
)
for (m in methods) {
call_fun <- paste0(m, ".dynamitefit")
expect_error(
do.call(call_fun, args = list()),
"Argument `.+` is missing"
)
}
})
test_that("output for non dynamitefit objects fails", {
methods <- c(
"as.data.frame",
"as_draws_df",
"confint",
"coef",
"fitted",
"formula",
"hmc_diagnostics",
"lfo",
"loo",
"mcmc_diagnostics",
"ndraws",
"nobs",
"plot",
"predict",
"print",
"summary",
"update"
)
object_arg_methods <- c(
"coef",
"confint",
"fitted",
"nobs",
"predict",
"summary",
"update"
)
for (m in methods) {
args <- ifelse_(
m %in% object_arg_methods,
list(object = 1L),
list(x = 1L)
)
call_fun <- paste0(m, ".dynamitefit")
expect_error(
do.call(call_fun, args = args),
"Argument `.+` must be a <dynamitefit> object\\."
)
}
})
test_that("output without Stan fit fails", {
methods <- c(
"as.data.frame",
"as_draws_df",
"fitted",
"lfo",
"loo",
"predict",
"ndraws"
)
object_arg_methods <- c(
"fitted",
"predict"
)
fit <- gaussian_example_fit
fit$stanfit <- NULL
for (m in methods) {
args <- ifelse_(
m %in% object_arg_methods,
list(object = fit),
list(x = fit)
)
expect_error(
do.call(paste0(!!m, ".dynamitefit"), args = args),
"No Stan model fit is available\\."
)
}
})
test_that("invalid responses fail", {
expect_error(
as.data.table(gaussian_example_fit, responses = "resp"),
paste0(
"Argument `responses` contains invalid response variable names\\.\n",
"x Response variable \"resp\" is not recognized\\.\n",
"i The response variable of the model is \"y\"\\."
)
)
})
test_that("invalid parameters fail", {
expect_error(
as.data.table(gaussian_example_fit, parameter = "test"),
paste0(
"Argument `parameters` contains invalid parameter names\\.\n",
"x Parameter \"test\" is not recognized\\.\n",
"i Use `get_parameter_names\\(\\)` to check available parameters\\."
)
)
})
test_that("invalid types fail", {
expect_error(
as.data.table(gaussian_example_fit, types = c("aa", "bb")),
paste0(
"Argument `types` contains invalid types\\.\n",
"x Types \"aa\" and \"bb\" are not recognized\\.\n",
"i Use `get_parameter_types\\(\\)` to check available types\\."
)
)
})
test_that("not found parameters fail", {
expect_error(
as.data.table(categorical_example_fit, types = "delta"),
paste0(
"No parameters of type `delta` were found for any of the response ",
"channels `x` and `y`\\."
)
)
})
test_that("invalid confint level fails", {
expect_error(
confint.dynamitefit(gaussian_example_fit, level = -0.1),
"Argument `level` must be a single <numeric> value between 0 and 1\\."
)
})
test_that("Invalid code blocks fail", {
expect_error(
get_code(gaussian_example_fit, blocks = mean),
"Argument `blocks` must be a <character> vector or NULL\\."
)
expect_error(
get_code(gaussian_example_fit, blocks = "block"),
paste0(
"Invalid Stan blocks provided: block\n",
"i Argument `blocks` must be NULL or a subset of .*"
)
)
})
# Predict errors ----------------------------------------------------------
gaussian_example_small <- gaussian_example |> dplyr::filter(.data$time < 6)
# test_that("newdata without group variable fails when there are groups", {
# gaussian_example_nogroup <- gaussian_example_small |>
# dplyr::select(!"id")
# expect_error(
# predict(gaussian_example_fit, newdata = gaussian_example_nogroup),
# "Can't find grouping variable `id` in `newdata`\\."
# )
# })
test_that("newdata with new groups fails when there are groups", {
gaussian_example_newgroup <- rbind(
gaussian_example_small,
data.frame(y = 1, x = 1, z = 0, id = 101, time = 1)
)
expect_error(
predict(gaussian_example_fit, newdata = gaussian_example_newgroup),
paste0(
"Grouping variable `id` contains unknown levels:\n",
"x Level \"101\" is not present in the original data\\."
)
)
})
test_that("newdata without time variable fails", {
gaussian_example_notime <- gaussian_example_small |>
dplyr::select(!"time")
expect_error(
predict(gaussian_example_fit, newdata = gaussian_example_notime),
"Can't find time index variable `time` in `newdata`\\."
)
})
test_that("newdata with new time points fails", {
gaussian_example_newtime <- rbind(
gaussian_example_small,
data.frame(y = 1, x = 1, z = 0, id = 1, time = 31)
)
expect_error(
predict(gaussian_example_fit, newdata = gaussian_example_newtime),
paste0(
"Time index variable `time` contains unknown time points:\n",
"x Time point \"31\" is not present in the original data\\."
)
)
})
test_that("newdata with duplicated time points fails", {
# groups
gaussian_example_duplicated <- rbind(
gaussian_example_small,
data.frame(y = 1, x = 1, z = 0, id = 1, time = 1)
)
expect_error(
predict(gaussian_example_fit, newdata = gaussian_example_duplicated),
paste0(
"Each time index must correspond to a single observation per group:\n",
"x Group `1` of `id` has duplicate observations\\."
)
)
# no groups
gaussian_example_duplicated <- rbind(
gaussian_example_small |>
dplyr::filter(.data$id == 1) |>
dplyr::select(!"id"),
data.frame(y = 1, x = 1, z = 0, time = 1)
)
expect_error(
predict(gaussian_example_single_fit, newdata = gaussian_example_duplicated),
paste0(
"Each time index must correspond to a single observation per group:\n",
"x Group `1` of `.group` has duplicate observations\\."
)
)
})
test_that("new group levels can't be included if new_levels is 'none'", {
gaussian_example_new_levels <- rbind(
gaussian_example,
data.frame(
y = c(0.5, rep(NA, 29L)),
x = rnorm(30),
z = rbinom(30, 1, 0.7),
id = 226L, time = seq.int(1, 30)
)
)
expect_error(
predict(
gaussian_example_fit,
newdata = gaussian_example_new_levels,
type = "response", n_draws = 2, new_levels = "none"
),
paste(
"Grouping variable `id` contains unknown levels:\nx Level \"226\"",
"is not present in the original data\\.\ni Note: argument `new_levels`",
"is \"none\" which disallows new levels\\."
)
)
})
test_that("newdata with unknown factor levels fails", {
categorical_example_newlevel <- categorical_example |>
dplyr::mutate(x = dplyr::recode(x, "C" = "D"))
expect_error(
predict(categorical_example_fit, newdata = categorical_example_newlevel),
paste0(
"<factor> variable `x` in `newdata` has new levels:\n",
"x Level \"D\" is not present in the original data\\."
)
)
})
test_that("newdata with missing response fails", {
gaussian_example_misresp <- gaussian_example_small |> dplyr::select(!"y")
expect_error(
predict(gaussian_example_fit, newdata = gaussian_example_misresp),
"Can't find response variable `y` in `newdata`."
)
})
test_that("newdata that is not a data.frame fails", {
expect_error(
predict(gaussian_example_fit, newdata = 1L),
"Argument `newdata` must be a <data.frame> object\\."
)
})
test_that("non-integer n_draws fails", {
expect_error(
predict(gaussian_example_fit, n_draws = data.frame()),
"Argument `n_draws` must be a positive <integer>\\."
)
})
test_that("negative n_draws fails", {
expect_error(
predict(gaussian_example_fit, n_draws = -1L),
"Argument `n_draws` must be a positive <integer>\\."
)
})
test_that("non-logical expand fails", {
expect_error(
predict(gaussian_example_fit, expand = data.frame()),
"Argument `expand` must be a single <logical> value\\."
)
})
test_that("invalid funs fails", {
expect_error(
predict(gaussian_example_fit, funs = 1L),
"Argument `funs` must be a <list>\\."
)
expect_error(
predict(gaussian_example_fit, funs = list(1L)),
"Argument `funs` must be named\\."
)
expect_error(
predict(gaussian_example_fit, funs = list(w = 1L)),
"The names of `funs` must be response variables of the model\\."
)
expect_error(
predict(gaussian_example_fit, funs = list(y = 1L)),
"Each element of `funs` must be a <list>\\."
)
expect_error(
predict(gaussian_example_fit, funs = list(y = list(1L))),
"Each element of `funs` must be named\\."
)
expect_error(
predict(gaussian_example_fit, funs = list(y = list(fun = 1L))),
"Each element of `funs` must contain only functions\\."
)
})
# Prior errors ------------------------------------------------------------
p <- get_priors(gaussian_example_fit)
f <- obs(y ~ -1 + random(~1) + z + varying(~ x + lag(y)), family = "gaussian") +
splines(df = 20)
test_that("incomplete priors fails", {
p2 <- p[-1, ]
expect_error(
dynamite(
f,
data = gaussian_example,
time = "time",
group = "id",
priors = p2,
debug = list(no_compile = TRUE)
),
paste0(
"Argument `priors` must contain all relevant parameters:\n",
"x Prior for parameter `sigma_nu_y_alpha` is not defined\\."
)
)
expect_error(
update(gaussian_example_fit,
priors = p2,
debug = list(no_compile = TRUE)
),
paste0(
"Argument `priors` must contain all relevant parameters:\n",
"x Prior for parameter `sigma_nu_y_alpha` is not defined\\."
)
)
})
test_that("irrevelant parameters fails", {
p2 <- rbind(p, data.frame(
parameter = "extra",
response = "y",
prior = "normal(0, 1.0)",
type = "alpha",
category = ""
))
expect_error(
dynamite(
f,
data = gaussian_example,
time = "time",
group = "id",
priors = p2,
debug = list(no_compile = TRUE)
),
paste0(
"Argument `priors` must contain only relevant parameters:\n",
"x Found a prior for parameter `extra` ",
"but the model does not contain such a parameter\\."
)
)
})
test_that("unsupported prior distribution fails", {
p$prior[5] <- "aaa"
expect_error(
dynamite(
f,
data = gaussian_example,
time = "time",
group = "id",
priors = p,
debug = list(no_compile = TRUE)
),
paste0(
"Found an unsupported prior distribution in `priors`:\n",
"x Distribution `aaa` is not available\\."
)
)
})
test_that("constrained prior for unconstrained parameter fails", {
p$prior[5] <- "gamma(2, 1)"
expect_error(
dynamite(
f,
data = gaussian_example,
time = "time",
group = "id",
priors = p,
debug = list(no_compile = TRUE)
),
paste0(
"Priors for parameters \"alpha\", \"beta\", and \"delta\" ",
"should have unconstrained support:\n",
"x Found an unconstrained distribution ",
"`gamma` for parameter `delta_y_x`\\."
)
)
})
# Plot errors ----------------------------------------------------------
test_that("plot errors when the input is not a dynamitefit object", {
expect_error(
plot.dynamitefit(1, types = "beta"),
"Argument `x` must be a <dynamitefit> object."
)
})
# Model errors ------------------------------------------------------------
test_that("multinomial model fails if stan version < 2.24", {
set.seed(1)
n_id <- 10L
n_time <- 5L
d <- data.frame(
y1 = sample(10, size = n_id * n_time, replace = TRUE),
y2 = sample(15, size = n_id * n_time, replace = TRUE),
y3 = sample(20, size = n_id * n_time, replace = TRUE),
z = rnorm(n_id * n_time),
time = seq_len(n_time),
id = rep(seq_len(n_id), each = n_time)
)
d$n <- d$y1 + d$y2 + d$y3
f <- obs(
c(y1, y2, y3) ~ z + lag(y1) + lag(y2) + lag(y3) + trials(n),
family = "multinomial"
)
expect_error(
mockthat::with_mock(
stan_version = function(...) "2.23",
dynamite(
dformula = f,
data = d,
time = "time",
group = "id",
backend = "rstan"
)
),
paste0(
"Multinomial family is not supported for this version of rstan\\.\n",
"i Please install a newer version of rstan\\."
)
)
})
# Stan errors -------------------------------------------------------------
test_that("Stan backend argument conversion duplicates fail", {
dots <- list(iter = 1000, iter_sampling = 1000)
expect_error(
check_stan_args(dots, verbose = FALSE, backend = "rstan"),
paste0(
"Conflict in argument syntax conversion from cmdstanr to rstan\\.\n",
"x Argument `iter` has been multiply specified\\."
)
)
dots <- list(
iter = 1000,
iter_sampling = 1000,
cores = 3,
parallel_chains = 4
)
expect_error(
check_stan_args(dots, verbose = FALSE, backend = "cmdstanr"),
paste0(
"Conflict in argument syntax conversion from rstan to cmdstanr\\.\n",
"x Arguments `iter_sampling` and `parallel_chains` have been multiply ",
"specified\\."
)
)
})
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.