# Tests for Bayesian changepoint detection methods # Test file: tests/testthat/test-bayesian.R # Helper function generate_test_data <- function(n = 200, changepoints = 100, means = c(0, 3), sd = 1) { if (length(changepoints) == 1 && changepoints < n) { c(rnorm(changepoints, means[1], sd), rnorm(n - changepoints, means[2], sd)) } else { rnorm(n, means[1], sd) } } # ============================================================================= # BOCPD Tests # ============================================================================= test_that("BOCPD returns proper structure", { set.seed(123) data <- generate_test_data(n = 200, changepoints = 100) result <- detect_bocpd(data, prior = normal_gamma()) expect_type(result, "list") expect_true("changepoints" %in% names(result)) expect_true("posterior" %in% names(result)) expect_true("prob_change" %in% names(result)) }) test_that("BOCPD returns posterior distribution", { set.seed(123) data <- generate_test_data(n = 100, changepoints = 50) result <- detect_bocpd(data, prior = normal_gamma()) expect_true("posterior" %in% names(result)) expect_true("prob_change" %in% names(result)) expect_equal(length(result$prob_change), length(data)) }) test_that("BOCPD works with normal_known_var prior", { set.seed(123) data <- generate_test_data() result <- detect_bocpd(data, prior = normal_known_var(known_var = 1)) expect_type(result, "list") expect_true("changepoints" %in% names(result)) }) test_that("BOCPD works with different hazard priors", { set.seed(123) data <- generate_test_data() result1 <- detect_bocpd(data, hazard = geometric_hazard(lambda = 0.01)) result2 <- detect_bocpd(data, hazard = constant_hazard(lambda = 0.05)) # negbin_hazard uses r and p, not lambda - test it separately result3 <- detect_bocpd(data, hazard = negbin_hazard(r = 5, p = 0.1)) expect_type(result1, "list") expect_type(result2, "list") expect_type(result3, "list") }) test_that("BOCPD threshold affects detection", { set.seed(123) data <- generate_test_data() result_low <- detect_bocpd(data, threshold = 0.3) result_high <- detect_bocpd(data, threshold = 0.9) expect_type(result_low, "list") expect_type(result_high, "list") }) test_that("BOCPD run length truncation works", { set.seed(123) data <- generate_test_data(n = 300, changepoints = 150) result <- detect_bocpd(data, truncate_run_length = 100) expect_type(result, "list") expect_true("posterior" %in% names(result)) }) test_that("BOCPD handles edge cases", { # Very short series set.seed(123) short_data <- rnorm(20) result <- detect_bocpd(short_data) expect_type(result, "list") # Constant data const_data <- rep(5, 100) result <- detect_bocpd(const_data) expect_type(result, "list") }) # ============================================================================= # BOCPD Multivariate Tests # ============================================================================= test_that("BOCPD multivariate detects changepoint", { set.seed(123) # Generate 2D data with changepoint n <- 200 cp <- 100 data <- rbind( matrix(rnorm(cp * 2, mean = 0), ncol = 2), matrix(rnorm((n - cp) * 2, mean = 3), ncol = 2) ) prior <- normal_wishart(mu0 = c(0, 0), kappa0 = 1, nu0 = 4, Psi0 = diag(2)) result <- detect_bocpd(data, prior = prior) expect_type(result, "list") expect_true("changepoints" %in% names(result)) }) # ============================================================================= # Shiryaev-Roberts Tests # ============================================================================= test_that("Shiryaev-Roberts works", { set.seed(123) data <- c(rnorm(100, 0, 1), rnorm(100, 2, 1)) result <- shiryaev_roberts(data) expect_type(result, "list") expect_true("changepoints" %in% names(result)) expect_true("R" %in% names(result)) }) test_that("Shiryaev-Roberts returns R statistic", { set.seed(123) data <- c(rnorm(100, 0, 1), rnorm(100, 2, 1)) result <- shiryaev_roberts(data) expect_true("R" %in% names(result)) expect_equal(length(result$R), length(data)) }) # ============================================================================= # Online Detector Tests # ============================================================================= test_that("regime_detector creates proper object", { detector <- regime_detector(method = "bocpd", prior = normal_gamma()) expect_s3_class(detector, "regime_detector") expect_equal(detector$method, "bocpd") }) test_that("online detector updates work", { detector <- regime_detector(method = "bocpd", prior = normal_gamma()) # update() returns the updated detector, result is in $last_result detector <- update(detector, 1.5) result <- detector$last_result expect_type(result, "list") expect_true("prob_change" %in% names(result)) expect_true("alarm" %in% names(result)) }) test_that("online detector history is list", { detector <- regime_detector(method = "bocpd") for (i in 1:10) { detector <- update(detector, rnorm(1)) } expect_type(detector$history, "list") }) test_that("online reset returns detector", { detector <- regime_detector(method = "bocpd") for (i in 1:5) { detector <- update(detector, rnorm(1)) } detector <- reset(detector) expect_s3_class(detector, "regime_detector") }) test_that("online CUSUM detector works", { detector <- regime_detector(method = "cusum", threshold = 5) # update() returns the updated detector, result is in $last_result detector <- update(detector, 1.5) result <- detector$last_result expect_type(result, "list") expect_true("alarm" %in% names(result)) }) test_that("online Shiryaev detector works", { detector <- regime_detector(method = "shiryaev", threshold = 100) # update() returns the updated detector, result is in $last_result detector <- update(detector, 1.5) result <- detector$last_result expect_type(result, "list") expect_true("R" %in% names(result)) expect_true("alarm" %in% names(result)) })