test_that("Constructor validates params", { expect_error(new_temporal_detector(time_col = 123)) expect_error(new_temporal_detector(time_col = "time", lookahead_window = 0)) expect_error(new_temporal_detector(time_col = "time", lookahead_window = -1)) det <- new_temporal_detector(time_col = "time", lookahead_window = 2) expect_s3_class(det, c("temporal_detector", "detector")) }) test_that("Errors on invalid time_col", { det <- new_temporal_detector(time_col = "time", lookahead_window = 1) df <- data.frame(date = Sys.Date() + 1:10, value = 1:10) split <- c(rep("train", 5), rep("test", 5)) expect_error(new_temporal_detector(time_col = NULL), "time_col must be") expect_error(new_temporal_detector(time_col = 123), "time_col must be") det_missing <- new_temporal_detector(time_col = "nonexistent") expect_error(run_detector(det_missing, df, split = split), "time_col not found") df2 <- data.frame(time = as.character(1:10), value = 1:10) det2 <- new_temporal_detector(time_col = "time", lookahead_window = 1) expect_error(run_detector(det2, df2, split = split)) }) test_that("Detects temporal leakage with correct severity", { # Use lookahead_window = 1 (not 0) det <- new_temporal_detector(time_col = "date", lookahead_window = 1) # Low: no overlap df_low <- data.frame( date = seq.Date(as.Date("2020-01-01"), by = "day", length.out = 20), value = 1:20 ) split_low <- c(rep("train", 10), rep("test", 10)) res_low <- run_detector(det, df_low, split = split_low) expect_equal(res_low$issues$severity, "low") # Medium: 5-19 test points within training period df_med <- data.frame( date = c(seq.Date(as.Date("2020-01-01"), by = "day", length.out = 10), seq.Date(as.Date("2020-01-05"), by = "day", length.out = 10)), value = 1:20 ) split_med <- c(rep("train", 10), rep("test", 10)) res_med <- run_detector(det, df_med, split = split_med) expect_true(res_med$issues$severity %in% c("medium", "high")) # High: 20+ test points within training period df_high <- data.frame( date = c(seq.Date(as.Date("2020-01-01"), by = "day", length.out = 50), seq.Date(as.Date("2020-01-01"), by = "day", length.out = 50)), value = 1:100 ) split_high <- c(rep("train", 50), rep("test", 50)) res_high <- run_detector(det, df_high, split = split_high) expect_equal(res_high$issues$severity, "high") }) test_that("Handles edge cases", { det <- new_temporal_detector(time_col = "date", lookahead_window = 1) empty_df <- data.frame(date = as.Date(character(0))) result <- run_detector(det, empty_df, split = character(0)) expect_equal(result$issues$severity, "low") df_all_test <- data.frame(date = as.Date("2025-01-01") + 0:2) res <- run_detector(det, df_all_test, split = rep("test", 3)) expect_equal(res$issues$severity, "low") }) test_that("Config argument accepted", { det <- new_temporal_detector(time_col = "date", lookahead_window = 1) df <- data.frame(date = Sys.Date() + 0:4) split <- c("train", "train", "test", "test", "test") res <- run_detector(det, df, split = split, config = list(debug = TRUE)) expect_true("issues" %in% names(res)) })