# ────────────────────────────────────────────────────────────────────────────── # test-helpers.R — tests for helper functions (no Stan fit required) # # Tests get_param_names(), build_summary_table(), and the internal # data manipulation utilities. extract_draws() requires a real Stan fit # so is tested separately in test-extract_param.R (skip_on_cran). # ────────────────────────────────────────────────────────────────────────────── # ═══════════════════════════════════════════════════════════════════════════════ # §1 get_param_names() # ═══════════════════════════════════════════════════════════════════════════════ test_that("get_param_names returns correct structure with named columns", { # Create a mock standata-like list sd <- list( p = 3, K = 1, n_fe = 2, n_re = 1, Y = matrix(0, 10, 3, dimnames = list(NULL, c("y1", "y2", "y3"))), X = matrix(0, 10, 2, dimnames = list(NULL, c("Intercept", "x1"))), B = matrix(0, 10, 3, dimnames = list(NULL, c("lag1_y1", "lag1_y2", "lag1_y3"))), Z = matrix(0, 10, 1, dimnames = list(NULL, c("x1"))) ) nm <- bvarnet:::get_param_names(sd) expect_type(nm, "list") expect_named(nm, c("y", "fe", "b", "re")) expect_equal(nm$y, c("y1", "y2", "y3")) expect_equal(nm$fe, c("Intercept", "x1")) expect_equal(nm$b, c("lag1_y1", "lag1_y2", "lag1_y3")) expect_equal(nm$re, "x1") }) test_that("get_param_names uses fallback names when colnames are NULL", { sd <- list( p = 2, K = 1, n_fe = 1, n_re = 0, Y = matrix(0, 10, 2), # no colnames X = matrix(0, 10, 1), B = matrix(0, 10, 2), Z = matrix(0, 10, 0) ) nm <- bvarnet:::get_param_names(sd) expect_equal(nm$y, c("y1", "y2")) expect_equal(nm$fe, "fe1") expect_equal(length(nm$re), 0) }) test_that("get_param_names with n_re = 0 returns empty re vector", { sd <- list(p = 2, K = 1, n_fe = 1, n_re = 0, Y = matrix(0, 5, 2, dimnames = list(NULL, c("a", "b"))), X = matrix(0, 5, 1, dimnames = list(NULL, "Int")), B = matrix(0, 5, 2, dimnames = list(NULL, c("l1_a", "l1_b"))), Z = matrix(0, 5, 0)) nm <- bvarnet:::get_param_names(sd) expect_equal(nm$re, character(0)) }) # ═══════════════════════════════════════════════════════════════════════════════ # §2 build_summary_table() # ═══════════════════════════════════════════════════════════════════════════════ test_that("build_summary_table returns correct data frame structure", { set.seed(500) draws <- matrix(rnorm(200 * 6), nrow = 200, ncol = 6) row_names <- c("pred1", "pred2") col_names <- c("out1", "out2", "out3") tab <- bvarnet:::build_summary_table(draws, row_names, col_names, "TestType") expect_s3_class(tab, "data.frame") expect_equal(nrow(tab), 2 * 3) # nr * nc expect_true(all(c("type", "predictor", "outcome", "mean", "median", "q5", "q95") %in% names(tab))) }) test_that("build_summary_table type column is filled correctly", { draws <- matrix(rnorm(100 * 4), nrow = 100, ncol = 4) tab <- bvarnet:::build_summary_table(draws, c("a", "b"), c("c", "d"), "MyType") expect_true(all(tab$type == "MyType")) }) test_that("build_summary_table predictor × outcome layout is correct", { draws <- matrix(rnorm(100 * 6), nrow = 100, ncol = 6) row_names <- c("r1", "r2", "r3") col_names <- c("c1", "c2") tab <- bvarnet:::build_summary_table(draws, row_names, col_names, "T") # Column order: rows cycle within columns # (r1,c1), (r2,c1), (r3,c1), (r1,c2), (r2,c2), (r3,c2) expect_equal(tab$predictor, rep(row_names, times = 2)) expect_equal(tab$outcome, rep(col_names, each = 3)) }) test_that("build_summary_table q5 <= median <= q95", { set.seed(501) draws <- matrix(rnorm(500 * 4), nrow = 500, ncol = 4) tab <- bvarnet:::build_summary_table(draws, c("a", "b"), c("c", "d"), "T") expect_true(all(tab$q5 <= tab$median)) expect_true(all(tab$median <= tab$q95)) }) test_that("build_summary_table rejects wrong number of columns", { draws <- matrix(rnorm(100 * 5), nrow = 100, ncol = 5) # 5 columns expect_error( bvarnet:::build_summary_table(draws, c("a", "b"), c("c", "d"), "T"), # should fail: nr*nc = 2*2 = 4 != 5 "ncol_draws == nr" ) }) # ═══════════════════════════════════════════════════════════════════════════════ # §3 build_Z() # ═══════════════════════════════════════════════════════════════════════════════ test_that("build_Z returns empty matrix when no RE specified", { X <- matrix(1, 10, 2, dimnames = list(NULL, c("Intercept", "x_1"))) B <- matrix(0, 10, 3, dimnames = list(NULL, paste0("lag1_y_", 1:3))) Z <- bvarnet:::build_Z(X, B) expect_equal(ncol(Z), 0) expect_equal(nrow(Z), 10) }) test_that("build_Z with re_cols selects correct X columns", { X <- matrix(rnorm(30), 10, 3, dimnames = list(NULL, c("Intercept", "x_1", "x_2"))) B <- matrix(0, 10, 2) Z <- bvarnet:::build_Z(X, B, re_cols = c("x_1", "x_2")) expect_equal(ncol(Z), 2) expect_equal(Z[, 1], X[, "x_1"]) expect_equal(Z[, 2], X[, "x_2"]) }) test_that("build_Z with re_temporal includes all B columns", { X <- matrix(1, 10, 1, dimnames = list(NULL, "Intercept")) B <- matrix(rnorm(20), 10, 2, dimnames = list(NULL, c("lag1_y_1", "lag1_y_2"))) Z <- bvarnet:::build_Z(X, B, re_temporal = TRUE) expect_equal(ncol(Z), 2) expect_equal(Z[, 1], B[, 1]) expect_equal(Z[, 2], B[, 2]) }) test_that("build_Z rejects invalid re_cols", { X <- matrix(1, 10, 2, dimnames = list(NULL, c("Intercept", "x_1"))) B <- matrix(0, 10, 2) expect_error( bvarnet:::build_Z(X, B, re_cols = "missing_col"), "re_cols not found" ) }) test_that("build_Z creates Intercept column when absent from X (ordinal case)", { # Ordinal X has no Intercept column (absorbed by kappa cutpoints) X <- matrix(rnorm(20), 10, 2, dimnames = list(NULL, c("x_1", "x_2"))) B <- matrix(0, 10, 3) Z <- bvarnet:::build_Z(X, B, re_cols = "Intercept") expect_equal(ncol(Z), 1) expect_equal(nrow(Z), 10) expect_true(all(Z[, 1] == 1)) expect_equal(colnames(Z), "Intercept") }) test_that("build_Z creates Intercept + selects other re_cols when Intercept absent", { X <- matrix(rnorm(20), 10, 2, dimnames = list(NULL, c("x_1", "x_2"))) B <- matrix(0, 10, 3) Z <- bvarnet:::build_Z(X, B, re_cols = c("Intercept", "x_1")) expect_equal(ncol(Z), 2) expect_true(all(Z[, "Intercept"] == 1)) expect_equal(Z[, "x_1"], X[, "x_1"]) }) # ═══════════════════════════════════════════════════════════════════════════════ # §4 make_term_matrix() # ═══════════════════════════════════════════════════════════════════════════════ test_that("make_term_matrix creates simple interaction from X columns", { X <- matrix(c(rep(1, 5), 1:5, 6:10), 5, 3, dimnames = list(NULL, c("Intercept", "x_1", "x_2"))) B <- matrix(0, 5, 2) M <- bvarnet:::make_term_matrix(X, B, c("x_1", "x_2")) expect_equal(ncol(M), 1) expect_equal(colnames(M), "x_1:x_2") expect_equal(M[, 1], X[, "x_1"] * X[, "x_2"]) }) test_that("make_term_matrix with 'lag' expands across B columns", { X <- matrix(c(rep(1, 5), 1:5), 5, 2, dimnames = list(NULL, c("Intercept", "x_1"))) B <- matrix(rnorm(10), 5, 2, dimnames = list(NULL, c("lag1_y_1", "lag1_y_2"))) M <- bvarnet:::make_term_matrix(X, B, c("lag", "x_1")) expect_equal(ncol(M), 2) expect_equal(colnames(M), c("lag1_y_1:x_1", "lag1_y_2:x_1")) expect_equal(M[, 1], B[, 1] * X[, "x_1"]) }) # ═══════════════════════════════════════════════════════════════════════════════ # §N — print.bvarnet() priors display # ═══════════════════════════════════════════════════════════════════════════════ test_that("print.bvarnet() shows 'all defaults' when no priors are user-set", { obj <- make_mock_bvarnet() out <- capture.output(print(obj)) expect_true(any(grepl("all defaults", out))) }) test_that("print.bvarnet() includes 'phi' in priors summary", { obj <- make_mock_bvarnet() expect_output(print(obj), "phi") }) test_that("print.bvarnet() includes 'Half-' for sd_u in priors when model has REs", { obj <- make_mock_bvarnet(n_re = 1L) expect_output(print(obj), "Half-") }) test_that("print.bvarnet() omits sd_u from priors when model has no REs", { obj <- make_mock_bvarnet() out <- capture.output(print(obj)) priors_line <- out[grepl("Priors", out)] expect_false(any(grepl("sd_u", priors_line))) }) test_that("print.bvarnet() shows 'sigma' in priors for gaussian family", { obj <- make_mock_bvarnet(family = "gaussian") expect_output(print(obj), "sigma") }) test_that("print.bvarnet() shows 'kappa' in priors for ordinal family", { obj <- make_mock_bvarnet(family = "ordinal") expect_output(print(obj), "kappa") }) test_that("print.bvarnet() omits sigma for bernoulli family", { obj <- make_mock_bvarnet(family = "bernoulli") out <- capture.output(print(obj)) expect_false(any(grepl("sigma", out))) }) test_that("print.bvarnet() shows (default) tag for user-set priors", { obj <- make_mock_bvarnet(family = "gaussian") obj$priors$beta <- prior("cauchy", 0, 2) out <- capture.output(print(obj)) # beta should NOT have (default) tag beta_line <- out[grepl("beta", out)] expect_false(any(grepl("\\(default\\)", beta_line))) # phi and sigma should have (default) tag phi_line <- out[grepl("phi", out)] expect_true(any(grepl("\\(default\\)", phi_line))) sigma_line <- out[grepl("sigma", out)] expect_true(any(grepl("\\(default\\)", sigma_line))) }) test_that("print.bvarnet() backward compat: old objects without priors_needed still work", { obj <- make_mock_bvarnet(family = "gaussian") obj$priors_needed <- NULL out <- capture.output(print(obj)) expect_true(any(grepl("beta", out))) expect_true(any(grepl("sigma", out))) })