Nothing
# ---- Shape ----------------------------------------------------------------
test_that("gg_ivarpro regression returns long-format tidy frame", {
v <- .varpro_boston()
iv <- .ivarpro_boston()
out <- gg_ivarpro(v, ivarpro_fit = iv)
expect_s3_class(out, "gg_ivarpro")
expect_s3_class(out, "data.frame")
expect_setequal(names(out), c("obs", "variable", "local_imp", "selected"))
expect_true(all(!is.na(out$local_imp))) # NA cells filtered out
expect_true(is.factor(out$variable))
})
test_that("gg_ivarpro classification adds class column", {
v <- .varpro_iris_multiclass_for_ivarpro()
iv <- .ivarpro_iris_multiclass()
out <- gg_ivarpro(v, ivarpro_fit = iv)
expect_s3_class(out, "gg_ivarpro")
expect_true("class" %in% names(out))
expect_setequal(as.character(unique(out$class)), levels(iris$Species))
})
test_that("gg_ivarpro variable factor levels ordered by descending mean(|local_imp|)", {
v <- .varpro_boston()
iv <- .ivarpro_boston()
out <- gg_ivarpro(v, ivarpro_fit = iv)
expect_true(is.factor(out$variable))
expected <- tapply(abs(out$local_imp), out$variable, mean, na.rm = TRUE)
# Reversed-descending: most-important variable is the LAST level (top of
# the plot after coord_flip).
expected_order <- rev(names(sort(expected, decreasing = TRUE)))
expect_equal(levels(out$variable), expected_order)
})
# ---- which_obs ------------------------------------------------------------
test_that("gg_ivarpro which_obs filters to a single observation", {
v <- .varpro_boston()
iv <- .ivarpro_boston()
out <- gg_ivarpro(v, ivarpro_fit = iv, which_obs = 1L)
expect_true(all(out$obs == 1L))
expect_equal(attr(out, "provenance")$which_obs, 1L)
})
test_that("gg_ivarpro which_obs out of range errors with valid range", {
v <- .varpro_boston()
iv <- .ivarpro_boston()
n <- nrow(MASS::Boston)
expect_error(
gg_ivarpro(v, ivarpro_fit = iv, which_obs = n + 1L),
"out of range"
)
})
# ---- which_class ----------------------------------------------------------
test_that("gg_ivarpro binary classification which_class = NULL defaults to last factor level", {
v <- .varpro_iris_binary_for_ivarpro()
iv <- .ivarpro_iris_binary()
out <- gg_ivarpro(v, ivarpro_fit = iv)
prov <- attr(out, "provenance")
expect_equal(prov$which_class, "virginica")
expect_setequal(as.character(unique(out$class)), "virginica")
})
test_that("gg_ivarpro which_class explicit returns single class", {
v <- .varpro_iris_multiclass_for_ivarpro()
iv <- .ivarpro_iris_multiclass()
out <- gg_ivarpro(v, ivarpro_fit = iv, which_class = "setosa")
expect_equal(as.character(unique(out$class)), "setosa")
})
test_that("gg_ivarpro which_class not in levels errors", {
v <- .varpro_iris_multiclass_for_ivarpro()
iv <- .ivarpro_iris_multiclass()
expect_error(
gg_ivarpro(v, ivarpro_fit = iv, which_class = "bogus"),
"is not a level of the response"
)
})
test_that("gg_ivarpro which_class on regression warns and is ignored", {
v <- .varpro_boston()
iv <- .ivarpro_boston()
expect_warning(
out <- gg_ivarpro(v, ivarpro_fit = iv, which_class = "anything"),
"ignored for regression family"
)
expect_false("class" %in% names(out))
})
# ---- cutoff polymorphism --------------------------------------------------
test_that("gg_ivarpro cutoff = NULL is per-class mean(|local_imp|) (named vector)", {
v <- .varpro_iris_multiclass_for_ivarpro()
iv <- .ivarpro_iris_multiclass()
out <- gg_ivarpro(v, ivarpro_fit = iv)
prov <- attr(out, "provenance")
expect_named(prov$cutoff, levels(iris$Species))
for (cls in levels(iris$Species)) {
expect_equal(
prov$cutoff[[cls]],
mean(abs(out$local_imp[out$class == cls])),
tolerance = 1e-10
)
}
})
test_that("gg_ivarpro scalar cutoff broadcasts across classes", {
v <- .varpro_iris_multiclass_for_ivarpro()
iv <- .ivarpro_iris_multiclass()
out <- gg_ivarpro(v, ivarpro_fit = iv, cutoff = 0.5)
prov <- attr(out, "provenance")
expect_equal(unname(prov$cutoff), rep(0.5, 3))
})
test_that("gg_ivarpro regression cutoff is length-1 named numeric", {
v <- .varpro_boston()
iv <- .ivarpro_boston()
out <- gg_ivarpro(v, ivarpro_fit = iv)
prov <- attr(out, "provenance")
expect_named(prov$cutoff, "regr")
expect_length(prov$cutoff, 1L)
})
# ---- ivarpro_fit shape guard ----------------------------------------------
test_that("gg_ivarpro rejects malformed ivarpro_fit", {
v <- .varpro_boston()
expect_error(gg_ivarpro(v, ivarpro_fit = list()),
"does not look like a varPro::ivarpro\\(\\) result")
})
test_that("gg_ivarpro classification ivarpro_fit must be list of K named frames", {
v <- .varpro_iris_multiclass_for_ivarpro()
iv <- .ivarpro_iris_multiclass()
iv_bad <- iv[c("setosa", "versicolor")] # drop one class
expect_error(
gg_ivarpro(v, ivarpro_fit = iv_bad),
"class"
)
})
test_that("gg_ivarpro shape guard catches mismatched row counts (PR #99 Copilot)", {
# Regression: rows mismatch
v_regr <- .varpro_boston()
iv_regr <- .ivarpro_boston()
iv_short <- iv_regr[seq_len(nrow(iv_regr) - 1L), , drop = FALSE]
expect_error(
gg_ivarpro(v_regr, ivarpro_fit = iv_short),
"rows but object trained"
)
# Classification: per-class row count mismatch
v_cls <- .varpro_iris_multiclass_for_ivarpro()
iv_cls <- .ivarpro_iris_multiclass()
iv_cls_bad <- iv_cls
iv_cls_bad$setosa <- iv_cls_bad$setosa[seq_len(nrow(iv_cls_bad$setosa) - 1L), ,
drop = FALSE]
expect_error(
gg_ivarpro(v_cls, ivarpro_fit = iv_cls_bad),
"rows but object trained"
)
# Classification: a per-class element is not a data.frame
iv_cls_bad2 <- iv_cls
iv_cls_bad2$setosa <- as.matrix(iv_cls_bad2$setosa)
expect_error(
gg_ivarpro(v_cls, ivarpro_fit = iv_cls_bad2),
"is not a data.frame"
)
})
# ---- ... + ivarpro_fit warning --------------------------------------------
test_that("gg_ivarpro warns when ... is supplied alongside ivarpro_fit", {
v <- .varpro_boston()
iv <- .ivarpro_boston()
expect_warning(
out <- gg_ivarpro(v, ivarpro_fit = iv, use.loo = TRUE),
"ignored because ivarpro_fit is supplied"
)
expect_s3_class(out, "gg_ivarpro")
})
# ---- family guard ---------------------------------------------------------
test_that("gg_ivarpro errors on regr+ / surv families", {
v <- .varpro_boston()
v_fake <- v
v_fake$family <- "surv"
expect_error(gg_ivarpro(v_fake), "family = 'surv'")
})
# ---- plot dispatch matrix --------------------------------------------------
test_that("plot.gg_ivarpro regression distribution builds", {
v <- .varpro_boston()
iv <- .ivarpro_boston()
p <- plot(gg_ivarpro(v, ivarpro_fit = iv))
expect_s3_class(p, "ggplot")
expect_silent(ggplot2::ggplot_build(p))
})
test_that("plot.gg_ivarpro regression which_obs builds (single panel)", {
v <- .varpro_boston()
iv <- .ivarpro_boston()
p <- plot(gg_ivarpro(v, ivarpro_fit = iv, which_obs = 1L))
expect_s3_class(p, "ggplot")
expect_silent(ggplot2::ggplot_build(p))
})
test_that("plot.gg_ivarpro classification distribution builds (faceted)", {
v <- .varpro_iris_multiclass_for_ivarpro()
iv <- .ivarpro_iris_multiclass()
p <- plot(gg_ivarpro(v, ivarpro_fit = iv))
expect_s3_class(p, "ggplot")
built <- ggplot2::ggplot_build(p)
expect_true(length(unique(built$layout$layout$PANEL)) >= 2L)
})
test_that("plot.gg_ivarpro classification which_obs builds (faceted)", {
v <- .varpro_iris_multiclass_for_ivarpro()
iv <- .ivarpro_iris_multiclass()
p <- plot(gg_ivarpro(v, ivarpro_fit = iv, which_obs = 1L))
expect_s3_class(p, "ggplot")
expect_silent(ggplot2::ggplot_build(p))
})
# ---- print + summary ------------------------------------------------------
test_that("print.gg_ivarpro prints invisibly with header", {
v <- .varpro_boston()
iv <- .ivarpro_boston()
out <- gg_ivarpro(v, ivarpro_fit = iv)
pr <- withVisible(print(out))
expect_false(pr$visible)
expect_identical(pr$value, out)
})
test_that("summary.gg_ivarpro regression returns descending named numeric", {
v <- .varpro_boston()
iv <- .ivarpro_boston()
out <- gg_ivarpro(v, ivarpro_fit = iv)
s <- summary(out)
expect_s3_class(s, "summary.gg_ivarpro")
vals <- as.numeric(unclass(s))
expect_equal(vals, sort(vals, decreasing = TRUE))
})
test_that("summary.gg_ivarpro classification returns per-class list", {
v <- .varpro_iris_multiclass_for_ivarpro()
iv <- .ivarpro_iris_multiclass()
out <- gg_ivarpro(v, ivarpro_fit = iv)
s <- summary(out)
expect_s3_class(s, "summary.gg_ivarpro")
expect_true(is.list(unclass(s)))
expect_setequal(names(unclass(s)), levels(iris$Species))
})
test_that("autoplot.gg_ivarpro matches plot", {
v <- .varpro_boston()
iv <- .ivarpro_boston()
out <- gg_ivarpro(v, ivarpro_fit = iv)
# The aggregate (no which_obs) regression view uses geom_jitter, whose
# Stat re-randomises on every ggplot_build(). Seed both builds so the
# comparison is deterministic — the test is checking that autoplot
# delegates to plot, not testing jitter stability.
set.seed(1L)
d1 <- ggplot2::ggplot_build(plot(out))$data
set.seed(1L)
d2 <- ggplot2::ggplot_build(ggplot2::autoplot(out))$data
expect_equal(d1, d2)
})
# ---- slow: cache equivalence ----------------------------------------------
test_that("gg_ivarpro cached and uncached paths agree (slow)", {
testthat::skip_on_cran()
if (!identical(Sys.getenv("GG_IVARPRO_SLOW_TESTS", "false"), "true")) {
skip("Slow test - set GG_IVARPRO_SLOW_TESTS=true to run")
}
v <- .varpro_boston()
iv <- .ivarpro_boston()
set.seed(20260526L)
uncached <- gg_ivarpro(v)
cached <- gg_ivarpro(v, ivarpro_fit = iv)
strip <- function(df) {
attr(df, "provenance") <- NULL
df
}
expect_equal(strip(as.data.frame(uncached)),
strip(as.data.frame(cached)),
tolerance = 1e-6)
expect_false(attr(uncached, "provenance")$precomputed)
expect_true(attr(cached, "provenance")$precomputed)
})
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.