# Comprehensive tests for all major functions library(testthat) library(Athlytics) library(dplyr) library(ggplot2) # Create comprehensive test data create_test_data <- function(n_days = 60) { data.frame( date = seq(Sys.Date() - n_days, Sys.Date(), by = "day"), type = sample(c("Run", "Ride"), n_days + 1, replace = TRUE), sport_type = sample(c("Run", "Ride"), n_days + 1, replace = TRUE), distance = runif(n_days + 1, 5000, 20000), moving_time = runif(n_days + 1, 1800, 7200), elapsed_time = runif(n_days + 1, 1800, 7200), total_elevation_gain = runif(n_days + 1, 0, 500), average_heartrate = runif(n_days + 1, 120, 180), max_heartrate = runif(n_days + 1, 160, 200), average_watts = runif(n_days + 1, 150, 300), kilojoules = runif(n_days + 1, 500, 2000), activity_id = as.character(seq_len(n_days + 1)), name = paste("Activity", seq_len(n_days + 1)), start_date = seq(Sys.Date() - n_days, Sys.Date(), by = "day"), start_date_local = seq(Sys.Date() - n_days, Sys.Date(), by = "day") ) } test_that("calculate_acwr works with various parameters", { test_data <- create_test_data(100) # Basic test result <- calculate_acwr(test_data) expect_s3_class(result, "data.frame") expect_true("acwr" %in% names(result)) expect_true("acwr_smooth" %in% names(result)) expect_true(nrow(result) > 0) # Test with different metrics result_distance <- calculate_acwr(test_data, load_metric = "distance_km") expect_s3_class(result_distance, "data.frame") # Test with activity type filter result_run <- calculate_acwr(test_data, activity_type = "Run") expect_s3_class(result_run, "data.frame") # Test with date range result_date <- calculate_acwr( test_data, start_date = Sys.Date() - 30, end_date = Sys.Date() ) expect_s3_class(result_date, "data.frame") expect_true(all(result_date$date >= Sys.Date() - 30)) expect_true(all(result_date$date <= Sys.Date())) # Test with different periods result_periods <- calculate_acwr( test_data, acute_period = 3, chronic_period = 21, smoothing_period = 3 ) expect_s3_class(result_periods, "data.frame") }) test_that("calculate_exposure works with various parameters", { test_data <- create_test_data(60) # Basic test result <- calculate_exposure(test_data) expect_s3_class(result, "data.frame") expect_true("atl" %in% names(result)) expect_true("ctl" %in% names(result)) expect_true("acwr" %in% names(result)) # Test with different metrics result_distance <- calculate_exposure(test_data, load_metric = "distance_km") expect_s3_class(result_distance, "data.frame") # Test with activity type filter result_run <- calculate_exposure(test_data, activity_type = c("Run")) expect_s3_class(result_run, "data.frame") # Test with different periods result_periods <- calculate_exposure( test_data, acute_period = 5, chronic_period = 30 ) expect_s3_class(result_periods, "data.frame") }) test_that("calculate_ef works correctly", { test_data <- create_test_data(50) test_data$filename <- paste0("activities/", test_data$activity_id, ".gpx") # Test with valid data (should work without warnings) result <- calculate_ef(test_data) expect_s3_class(result, "data.frame") # Test with data that has no heart rate (should warn) test_data_no_hr <- test_data test_data_no_hr$average_heartrate <- NA expect_warning( result_no_hr <- calculate_ef(test_data_no_hr), "No activities" ) }) test_that("calculate_decoupling works correctly", { test_data <- create_test_data(50) test_data$filename <- paste0("activities/", test_data$activity_id, ".gpx") # Test should handle the case where no stream data is available # Will produce multiple warnings about missing files, then a final warning about no valid data expect_warning( result <- calculate_decoupling(test_data, export_dir = tempdir()), "No valid decoupling" ) }) test_that("plot functions work with data frames", { test_acwr <- calculate_acwr(create_test_data(60)) test_exposure <- calculate_exposure(create_test_data(60)) # Test plot_acwr p1 <- plot_acwr(test_acwr) expect_s3_class(p1, "ggplot") # Test plot_acwr with zones p2 <- plot_acwr(test_acwr, highlight_zones = TRUE) expect_s3_class(p2, "ggplot") # Test plot_exposure p3 <- plot_exposure(test_exposure) expect_s3_class(p3, "ggplot") # Test plot_exposure with risk zones p4 <- plot_exposure(test_exposure, risk_zones = TRUE) expect_s3_class(p4, "ggplot") }) test_that("enhanced plotting functions work", { test_acwr <- calculate_acwr(create_test_data(90)) # Test plot_acwr_enhanced p1 <- plot_acwr_enhanced(test_acwr) expect_s3_class(p1, "ggplot") # Test with confidence intervals p2 <- plot_acwr_enhanced(test_acwr, show_ci = TRUE) expect_s3_class(p2, "ggplot") # Test plot_acwr_comparison with RA and EWMA methods # This function expects two dataframes, not a list test_acwr2 <- calculate_acwr(create_test_data(90), acute_period = 5, chronic_period = 21) p3 <- plot_acwr_comparison( acwr_ra = test_acwr, acwr_ewma = test_acwr2 ) expect_s3_class(p3, "ggplot") }) test_that("cohort_reference functions work", { # Create reference data ref_data <- data.frame( athlete_id = rep(1:10, each = 30), date = rep(seq(Sys.Date() - 29, Sys.Date(), by = "day"), 10), acwr_smooth = rnorm(300, mean = 1.0, sd = 0.3), sport = "Run" # Use single sport to avoid grouping issues in test ) # Test cohort_reference without grouping result <- cohort_reference(ref_data, by = NULL) expect_s3_class(result, "data.frame") expect_true("percentile" %in% names(result)) # Test with different metric result2 <- cohort_reference(ref_data, metric = "acwr_smooth", by = NULL) expect_s3_class(result2, "data.frame") # Test add_reference_bands - it needs a ggplot object individual_data <- data.frame( date = seq(Sys.Date() - 29, Sys.Date(), by = "day"), acwr_smooth = rnorm(30, mean = 1.0, sd = 0.2) ) p <- ggplot(individual_data, aes(x = date, y = acwr_smooth)) + geom_line() p_with_bands <- add_reference_bands(p, result) expect_s3_class(p_with_bands, "ggplot") # Test plot_with_reference individual_data <- data.frame( date = seq(Sys.Date() - 29, Sys.Date(), by = "day"), acwr_smooth = rnorm(30, mean = 1.0, sd = 0.2) ) p <- plot_with_reference(individual_data, result) expect_s3_class(p, "ggplot") }) test_that("load_local_activities works with test export", { skip("Skipping file system test - requires actual export structure") # Note: This test requires a real Strava export structure # In production, load_local_activities should be tested with actual export files # For now, we skip this test in automated testing }) test_that("quality_summary works", { # Create mock flagged stream data (as if from flag_quality) flagged_stream <- data.frame( time = 1:100, distance = cumsum(runif(100, 1, 5)), heartrate = runif(100, 120, 180), flag_hr_spike = sample(c(TRUE, FALSE), 100, replace = TRUE, prob = c(0.1, 0.9)), flag_pw_spike = sample(c(TRUE, FALSE), 100, replace = TRUE, prob = c(0.1, 0.9)), flag_gps_drift = sample(c(TRUE, FALSE), 100, replace = TRUE, prob = c(0.1, 0.9)), flag_any = sample(c(TRUE, FALSE), 100, replace = TRUE, prob = c(0.2, 0.8)), is_steady_state = sample(c(TRUE, FALSE), 100, replace = TRUE, prob = c(0.6, 0.4)), quality_score = runif(100, 0.5, 1.0) ) result <- quality_summary(flagged_stream) expect_type(result, "list") expect_true("total_points" %in% names(result)) expect_true("flagged_points" %in% names(result)) expect_true("quality_score" %in% names(result)) }) test_that("calculate_acwr_ewma is accessible", { # Just check that the function exists (it's internal) expect_true(exists("calculate_acwr_ewma", where = asNamespace("Athlytics"))) }) test_that("all color palette functions work", { # Test each palette expect_length(athlytics_palette_nature(), 9) expect_length(athlytics_palette_academic(), 8) expect_length(athlytics_palette_vibrant(), 8) expect_length(athlytics_palette_science(), 8) expect_length(athlytics_palette_cell(), 8) # Test color functions expect_type(athlytics_colors_acwr_zones(), "list") expect_type(athlytics_colors_training_load(), "list") expect_type(athlytics_colors_ef(), "list") # Test theme theme <- theme_athlytics() expect_s3_class(theme, "theme") # Test scale function scale <- scale_athlytics("nature", "color") expect_true(inherits(scale, "Scale") || is.null(scale)) })