## ============================================================================= ## arimasel tests: modernization features (seasonal, xreg, CV, seasonal diagnostics) ## ============================================================================= context("cart_arima seasonal search") test_that("cart_arima with seasonal argument returns seasonal model strings", { res <- cart_arima(.x_seas, p_set = 0:1, d_set = 0L, q_set = 0:1, seasonal = list(P = 0:1, D = 0L, Q = 0:1, period = 12)) expect_s3_class(res, "cartARIMA") expect_true(all(grepl("\\[12\\]$", res$full_table$Model))) }) test_that("cart_arima seasonal n_total equals full seasonal cartesian product", { res <- cart_arima(.x_seas, p_set = 0:1, d_set = 0L, q_set = 0:1, seasonal = list(P = 0:1, D = 0L, Q = 0:1, period = 12)) expect_equal(res$n_total, 2L * 1L * 2L * 2L * 1L * 2L) }) test_that("cart_arima errors on invalid seasonal period", { expect_error( cart_arima(.x_seas, p_set = 0:1, d_set = 0L, q_set = 0:1, seasonal = list(period = 1L)), "period" ) }) test_that("cart_arima without seasonal still works (backward compatible)", { res <- cart_arima(.x_stat, p_set = 0:1, d_set = 0L, q_set = 0:1) expect_null(res$seasonal) }) ## --------------------------------------------------------------------------- # context("cart_arima xreg support") test_that("cart_arima accepts xreg and stores it", { res <- cart_arima(.x_xreg_y, p_set = 0:1, d_set = 0L, q_set = 0:1, xreg = .x_xreg_z) expect_s3_class(res, "cartARIMA") expect_false(is.null(res$xreg)) }) test_that("cart_arima errors when xreg length mismatches x", { expect_error( cart_arima(.x_xreg_y, p_set = 0:1, d_set = 0L, q_set = 0:1, xreg = .x_xreg_z[1:10, , drop = FALSE]), "same number of rows" ) }) test_that("arima_forecast requires newxreg when model was fit with xreg", { res <- cart_arima(.x_xreg_y, p_set = 0:1, d_set = 0L, q_set = 0:1, xreg = .x_xreg_z) expect_error(arima_forecast(res, h = 3L, plot = FALSE), "newxreg") }) test_that("arima_forecast with valid newxreg returns forecasts of length h", { res <- cart_arima(.x_xreg_y, p_set = 0:1, d_set = 0L, q_set = 0:1, xreg = .x_xreg_z) new_z <- matrix(rnorm(3), ncol = 1) fc <- arima_forecast(res, h = 3L, newxreg = new_z, plot = FALSE) expect_length(fc$mean, 3L) }) ## --------------------------------------------------------------------------- # context("arima_forecast prediction interval correctness") test_that("arima_forecast lower is always <= upper (regression test)", { res <- cart_arima(.x_stat, p_set = 0:1, d_set = 0L, q_set = 0:1) fc <- arima_forecast(res, h = 6L, plot = FALSE, level = c(50, 80, 95, 99)) expect_true(all(fc$lower <= fc$upper)) }) test_that("wider confidence levels produce wider intervals", { res <- cart_arima(.x_stat, p_set = 0:1, d_set = 0L, q_set = 0:1) fc <- arima_forecast(res, h = 5L, plot = FALSE, level = c(80, 95)) width_80 <- fc$upper[, "80%"] - fc$lower[, "80%"] width_95 <- fc$upper[, "95%"] - fc$lower[, "95%"] expect_true(all(width_95 >= width_80)) }) ## --------------------------------------------------------------------------- # context("fitted.cartARIMA (regression test)") test_that("fitted() returns a finite numeric vector", { res <- cart_arima(.x_stat, p_set = 0:1, d_set = 0L, q_set = 0:1) fv <- fitted(res) expect_true(is.numeric(fv)) expect_true(all(is.finite(fv))) expect_equal(length(fv), res$n_obs) }) test_that("plot(type = 'fitted') does not error (regression test for ts-class dispatch bug)", { ## graphics::lines() must not be handed a "ts"-classed x-axis alongside a ## separate plain-numeric y vector: on some R versions this dispatches to ## stats:::lines.ts() and raises "invalid plot type" inside plot.xy(). res <- cart_arima(.x_stat, p_set = 0:1, d_set = 0L, q_set = 0:1) pdf(NULL) on.exit(dev.off()) expect_silent(plot(res, type = "fitted")) }) test_that("arima_forecast plotting does not error (regression test for ts-class dispatch bug)", { res <- cart_arima(.x_stat, p_set = 0:1, d_set = 0L, q_set = 0:1) pdf(NULL) on.exit(dev.off()) expect_silent(arima_forecast(res, h = 5L, plot = TRUE)) }) ## --------------------------------------------------------------------------- # context("seasonal_strength / suggest_D") test_that("seasonal_strength returns values in [0, 1]", { s <- seasonal_strength(.x_seas) expect_true(s$seasonal_strength >= 0 && s$seasonal_strength <= 1) expect_true(s$trend_strength >= 0 && s$trend_strength <= 1) }) test_that("seasonal_strength errors without a period for non-ts input", { expect_error(seasonal_strength(as.numeric(.x_seas)), "period") }) test_that("suggest_D returns 0 or 1", { D <- suggest_D(.x_seas) expect_true(D %in% c(0L, 1L)) }) ## --------------------------------------------------------------------------- # context("arima_cv") test_that("arima_cv returns an arimaCV object with accuracy table", { res <- cart_arima(.x_ar11, p_set = 0:1, d_set = 0L, q_set = 0:1) cv <- arima_cv(res, h = 1L, initial = 60L) expect_s3_class(cv, "arimaCV") expect_true("RMSE" %in% names(cv$accuracy)) expect_gt(cv$n_folds, 0L) }) test_that("arima_cv accuracy has one row per horizon", { res <- cart_arima(.x_ar11, p_set = 0:1, d_set = 0L, q_set = 0:1) cv <- arima_cv(res, h = 3L, initial = 60L) expect_equal(nrow(cv$accuracy), 3L) }) test_that("arima_cv errors when initial leaves no room for evaluation", { res <- cart_arima(.x_ar11, p_set = 0:1, d_set = 0L, q_set = 0:1) expect_error(arima_cv(res, h = 1L, initial = 100L), "no observations") }) test_that("print.arimaCV runs without error", { res <- cart_arima(.x_ar11, p_set = 0:1, d_set = 0L, q_set = 0:1) cv <- arima_cv(res, h = 1L, initial = 60L) expect_output(print(cv), "Rolling-Origin Cross-Validation") })