# ────────────────────────────────────────────────────────────────────────────── # test-extract_param.R — tests for extract_param() and extract_draws() # # These functions require a fitted bvarnet object (Stan fit), which is # heavy and slow to produce. This file uses mock objects to test the # structure and logic without running MCMC. Full integration tests with # real Stan fits should be gated behind skip_on_cran(). # make_mock_bvarnet() is defined in helper-fixtures.R and auto-sourced. # ────────────────────────────────────────────────────────────────────────────── # Also note: extract_draws is internal. When sourced (test_dir), it lives in the # global env; when the package is loaded (devtools::test), use bvarnet:::. # The helper always sources local R files so plain extract_draws() works here. # ═══════════════════════════════════════════════════════════════════════════════ # §1 extract_draws() — class and family validation # ═══════════════════════════════════════════════════════════════════════════════ test_that("extract_draws rejects non-bvarnet objects", { expect_error( extract_draws(list(a = 1), "beta"), "inherits" ) }) test_that("extract_draws validates parameter argument", { mock_obj <- structure(list(), class = "bvarnet") expect_error( extract_draws(mock_obj, "invalid_param"), "arg" ) }) test_that("extract_draws rejects sigma for non-gaussian family", { mock_obj <- make_mock_bvarnet("bernoulli") expect_error( extract_draws(mock_obj, "sigma"), "gaussian" ) }) test_that("extract_draws rejects kappa for non-ordinal family", { mock_obj <- make_mock_bvarnet("bernoulli") expect_error( extract_draws(mock_obj, "kappa"), "ordinal" ) }) test_that("extract_draws rejects sd_u when n_re = 0", { mock_obj <- make_mock_bvarnet("gaussian") # n_re = 0 by default expect_error( extract_draws(mock_obj, "sd_u"), "no random effects" ) }) # ═══════════════════════════════════════════════════════════════════════════════ # §2 extract_param() — class validation # ═══════════════════════════════════════════════════════════════════════════════ test_that("extract_param rejects non-bvarnet objects", { expect_error( extract_param(list(a = 1)), "inherits" ) }) # ═══════════════════════════════════════════════════════════════════════════════ # §3 compare_to_truth() — class validation # ═══════════════════════════════════════════════════════════════════════════════ test_that("compare_to_truth rejects non-bvarnet fit object", { expect_error( compare_to_truth(list(a = 1), list()), "inherits" ) }) # ═══════════════════════════════════════════════════════════════════════════════ # §4 extract_param() — return structure # ═══════════════════════════════════════════════════════════════════════════════ test_that("extract_param returns a plain data.frame for bernoulli", { obj <- make_mock_bvarnet("bernoulli") res <- extract_param(obj) expect_true(is.data.frame(res)) expect_identical(class(res), "data.frame") # not classed }) test_that("extract_param result has all required columns", { obj <- make_mock_bvarnet("bernoulli") res <- extract_param(obj) expected_cols <- c("type", "predictor", "outcome", "mean", "median", "q5", "q95", "rhat", "ess_bulk", "ess_tail") expect_true(all(expected_cols %in% names(res))) }) test_that("extract_param includes beta and phi rows for bernoulli", { obj <- make_mock_bvarnet("bernoulli") res <- extract_param(obj) expect_true(any(res$type %in% c("Intercept", "Fixed Effect"))) expect_true(any(res$type == "Autoregressive")) expect_true(any(res$type == "Cross-lagged")) }) test_that("extract_param does not include sigma/kappa for bernoulli", { obj <- make_mock_bvarnet("bernoulli") res <- extract_param(obj) expect_false(any(res$type == "Residual SD")) expect_false(any(res$type == "Threshold")) }) test_that("extract_param includes sigma rows for gaussian", { obj <- make_mock_bvarnet("gaussian") res <- extract_param(obj) expect_true(any(res$type == "Residual SD")) expect_equal(sum(res$type == "Residual SD"), obj$standata$p) }) test_that("extract_param includes kappa rows for ordinal", { obj <- make_mock_bvarnet("ordinal") res <- extract_param(obj) expect_true(any(res$type == "Threshold")) # p=2, C-1=2 cutpoints: expect 4 threshold rows expect_equal(sum(res$type == "Threshold"), obj$standata$p * (obj$standata$C - 1L)) }) test_that("extract_param retains FE rows for pure ordinal (no sentinel filtering)", { obj <- make_mock_bvarnet("ordinal") res <- extract_param(obj) # Pure ordinal: beta[1,j] is x_1, not an intercept sentinel fe_rows <- res[res$type == "Fixed Effect", ] expect_equal(nrow(fe_rows), obj$standata$p) expect_true(all(fe_rows$predictor == "x_1")) expect_false(any(is.na(fe_rows$mean))) # No Intercept rows expected expect_equal(sum(res$type == "Intercept"), 0L) }) test_that("extract_param filtering by type works", { obj <- make_mock_bvarnet("bernoulli") res <- extract_param(obj) ar_rows <- subset(res, type == "Autoregressive") cl_rows <- subset(res, type == "Cross-lagged") expect_true(nrow(ar_rows) > 0) expect_true(nrow(cl_rows) > 0) expect_true(all(ar_rows$type == "Autoregressive")) expect_true(all(cl_rows$type == "Cross-lagged")) }) test_that("extract_param rhat and ess columns are numeric", { obj <- make_mock_bvarnet("bernoulli") res <- extract_param(obj) expect_true(is.numeric(res$rhat)) expect_true(is.numeric(res$ess_bulk)) expect_true(is.numeric(res$ess_tail)) }) test_that("extract_param predictor labels use variable names from standata", { obj <- make_mock_bvarnet("bernoulli") res <- extract_param(obj) intercept_rows <- subset(res, type == "Intercept") expect_true(all(intercept_rows$predictor == "Intercept")) phi_rows <- subset(res, type %in% c("Autoregressive", "Cross-lagged")) expect_true(all(grepl("lag1_y_[0-9]+", phi_rows$predictor))) }) # ═══════════════════════════════════════════════════════════════════════════════ # §N — extract_param() type= argument # ═══════════════════════════════════════════════════════════════════════════════ test_that("extract_param type=NULL returns all rows (backward compat)", { obj <- make_mock_bvarnet("gaussian") full <- extract_param(obj) with_null <- extract_param(obj, type = NULL) expect_equal(full, with_null) }) test_that("extract_param type='Threshold' returns only threshold rows for ordinal", { obj <- make_mock_bvarnet("ordinal") res <- extract_param(obj, type = "Threshold") expect_true(is.data.frame(res)) expect_true(nrow(res) > 0L) expect_true(all(res$type == "Threshold")) }) test_that("extract_param type='Residual SD' returns only residual SD rows for gaussian", { obj <- make_mock_bvarnet("gaussian") res <- extract_param(obj, type = "Residual SD") expect_true(is.data.frame(res)) expect_equal(nrow(res), obj$standata$p) expect_true(all(res$type == "Residual SD")) }) test_that("extract_param type= returns empty data.frame when type absent in model", { obj <- make_mock_bvarnet("bernoulli") res <- extract_param(obj, type = "Threshold") expect_true(is.data.frame(res)) expect_equal(nrow(res), 0L) }) test_that("extract_param type= accepts multiple types", { obj <- make_mock_bvarnet("gaussian") res <- extract_param(obj, type = c("Autoregressive", "Cross-lagged")) expect_true(all(res$type %in% c("Autoregressive", "Cross-lagged"))) expect_true(nrow(res) > 0L) }) test_that("extract_param type= errors on unknown type value", { obj <- make_mock_bvarnet("bernoulli") expect_error( extract_param(obj, type = "NotAType"), "Unknown type value" ) })