|
| 1 | +# Test to boost coverage for calculate_ef_from_stream function |
| 2 | + |
| 3 | +test_that("calculate_ef_from_stream handles missing required columns", { |
| 4 | + # Test missing velocity data for pace_hr |
| 5 | + stream_no_velocity <- data.frame( |
| 6 | + time = 1:100, |
| 7 | + heartrate = rep(150, 100) |
| 8 | + ) |
| 9 | + |
| 10 | + result <- calculate_ef_from_stream( |
| 11 | + stream_data = stream_no_velocity, |
| 12 | + activity_date = Sys.Date(), |
| 13 | + act_type = "Run", |
| 14 | + ef_metric = "pace_hr" |
| 15 | + ) |
| 16 | + |
| 17 | + expect_equal(result$status, "missing_velocity_data") |
| 18 | + expect_true(is.na(result$ef_value)) |
| 19 | + |
| 20 | + # Test missing power data for power_hr |
| 21 | + stream_no_power <- data.frame( |
| 22 | + time = 1:100, |
| 23 | + heartrate = rep(140, 100) |
| 24 | + ) |
| 25 | + |
| 26 | + result2 <- calculate_ef_from_stream( |
| 27 | + stream_data = stream_no_power, |
| 28 | + activity_date = Sys.Date(), |
| 29 | + act_type = "Ride", |
| 30 | + ef_metric = "power_hr" |
| 31 | + ) |
| 32 | + |
| 33 | + expect_equal(result2$status, "missing_power_data") |
| 34 | + expect_true(is.na(result2$ef_value)) |
| 35 | + |
| 36 | + # Test missing heartrate column |
| 37 | + stream_no_hr <- data.frame( |
| 38 | + time = 1:100, |
| 39 | + distance = 1:100 |
| 40 | + ) |
| 41 | + |
| 42 | + result3 <- calculate_ef_from_stream( |
| 43 | + stream_data = stream_no_hr, |
| 44 | + activity_date = Sys.Date(), |
| 45 | + act_type = "Run", |
| 46 | + ef_metric = "pace_hr" |
| 47 | + ) |
| 48 | + |
| 49 | + expect_equal(result3$status, "missing_hr_data") |
| 50 | + expect_true(is.na(result3$ef_value)) |
| 51 | +}) |
| 52 | + |
| 53 | +test_that("calculate_ef_from_stream handles insufficient data", { |
| 54 | + # Test insufficient data points (< 100) |
| 55 | + small_stream <- data.frame( |
| 56 | + time = 1:50, |
| 57 | + heartrate = rep(150, 50), |
| 58 | + distance = 1:50 |
| 59 | + ) |
| 60 | + |
| 61 | + result <- calculate_ef_from_stream( |
| 62 | + stream_data = small_stream, |
| 63 | + activity_date = Sys.Date(), |
| 64 | + act_type = "Run", |
| 65 | + ef_metric = "pace_hr" |
| 66 | + ) |
| 67 | + |
| 68 | + expect_equal(result$status, "insufficient_data_points") |
| 69 | + expect_true(is.na(result$ef_value)) |
| 70 | +}) |
| 71 | + |
| 72 | +test_that("calculate_ef_from_stream handles low HR coverage", { |
| 73 | + # Create stream with lots of NA heartrate |
| 74 | + stream_low_hr <- data.frame( |
| 75 | + time = 1:200, |
| 76 | + heartrate = c(rep(150, 30), rep(NA, 170)), |
| 77 | + distance = 1:200 * 10 |
| 78 | + ) |
| 79 | + |
| 80 | + result <- calculate_ef_from_stream( |
| 81 | + stream_data = stream_low_hr, |
| 82 | + activity_date = Sys.Date(), |
| 83 | + act_type = "Run", |
| 84 | + ef_metric = "pace_hr", |
| 85 | + min_hr_coverage = 0.7 # Require 70% HR coverage |
| 86 | + ) |
| 87 | + |
| 88 | + expect_true(result$status %in% c("insufficient_hr_data", "insufficient_valid_data", "insufficient_data_points")) |
| 89 | + expect_true(is.na(result$ef_value)) |
| 90 | +}) |
| 91 | + |
| 92 | +test_that("calculate_ef_from_stream handles velocity calculation from distance", { |
| 93 | + # Test with distance column (no velocity_smooth) |
| 94 | + stream_with_distance <- data.frame( |
| 95 | + time = seq(0, 599, by = 1), # 10 minutes of data |
| 96 | + heartrate = rep(150, 600), |
| 97 | + distance = seq(0, 3000, length.out = 600) # 3km in 10 minutes |
| 98 | + ) |
| 99 | + |
| 100 | + result <- calculate_ef_from_stream( |
| 101 | + stream_data = stream_with_distance, |
| 102 | + activity_date = Sys.Date(), |
| 103 | + act_type = "Run", |
| 104 | + ef_metric = "pace_hr", |
| 105 | + min_steady_minutes = 5, |
| 106 | + steady_cv_threshold = 0.1, |
| 107 | + min_hr_coverage = 0.7, |
| 108 | + quality_control = "off" |
| 109 | + ) |
| 110 | + |
| 111 | + expect_true(is.data.frame(result)) |
| 112 | + expect_true("ef_value" %in% names(result)) |
| 113 | +}) |
| 114 | + |
| 115 | +test_that("calculate_ef_from_stream handles velocity_smooth column", { |
| 116 | + # Test with velocity_smooth column |
| 117 | + stream_with_velocity <- data.frame( |
| 118 | + time = seq(0, 599, by = 1), |
| 119 | + heartrate = rep(150, 600), |
| 120 | + velocity_smooth = rep(5.0, 600) # 5 m/s constant |
| 121 | + ) |
| 122 | + |
| 123 | + result <- calculate_ef_from_stream( |
| 124 | + stream_data = stream_with_velocity, |
| 125 | + activity_date = Sys.Date(), |
| 126 | + act_type = "Run", |
| 127 | + ef_metric = "pace_hr", |
| 128 | + min_steady_minutes = 5, |
| 129 | + steady_cv_threshold = 0.1, |
| 130 | + min_hr_coverage = 0.7, |
| 131 | + quality_control = "off" |
| 132 | + ) |
| 133 | + |
| 134 | + expect_true(is.data.frame(result)) |
| 135 | + expect_true("ef_value" %in% names(result)) |
| 136 | +}) |
| 137 | + |
| 138 | +test_that("calculate_ef_from_stream handles power data", { |
| 139 | + # Test power_hr metric |
| 140 | + stream_with_power <- data.frame( |
| 141 | + time = seq(0, 599, by = 1), |
| 142 | + heartrate = rep(140, 600), |
| 143 | + watts = rep(200, 600) # 200W constant |
| 144 | + ) |
| 145 | + |
| 146 | + result <- calculate_ef_from_stream( |
| 147 | + stream_data = stream_with_power, |
| 148 | + activity_date = Sys.Date(), |
| 149 | + act_type = "Ride", |
| 150 | + ef_metric = "power_hr", |
| 151 | + min_steady_minutes = 5, |
| 152 | + steady_cv_threshold = 0.1, |
| 153 | + min_hr_coverage = 0.7, |
| 154 | + quality_control = "off" |
| 155 | + ) |
| 156 | + |
| 157 | + expect_true(is.data.frame(result)) |
| 158 | + expect_true("ef_value" %in% names(result)) |
| 159 | +}) |
| 160 | + |
| 161 | +test_that("calculate_ef_from_stream handles quality control filtering", { |
| 162 | + # Test with unrealistic values that should be filtered out |
| 163 | + stream_bad_values <- data.frame( |
| 164 | + time = seq(0, 599, by = 1), |
| 165 | + heartrate = c(rep(150, 300), rep(250, 300)), # 250 is too high |
| 166 | + velocity_smooth = c(rep(5, 300), rep(20, 300)) # 20 m/s is too fast |
| 167 | + ) |
| 168 | + |
| 169 | + result <- calculate_ef_from_stream( |
| 170 | + stream_data = stream_bad_values, |
| 171 | + activity_date = Sys.Date(), |
| 172 | + act_type = "Run", |
| 173 | + ef_metric = "pace_hr", |
| 174 | + min_steady_minutes = 5, |
| 175 | + steady_cv_threshold = 0.1, |
| 176 | + min_hr_coverage = 0.7, |
| 177 | + quality_control = "filter" |
| 178 | + ) |
| 179 | + |
| 180 | + expect_true(is.data.frame(result)) |
| 181 | + # Should filter out bad values |
| 182 | +}) |
| 183 | + |
| 184 | +test_that("calculate_ef_from_stream handles too short duration", { |
| 185 | + # Test with stream that's too short |
| 186 | + stream_short <- data.frame( |
| 187 | + time = seq(0, 120, by = 1), # Only 2 minutes |
| 188 | + heartrate = rep(150, 121), |
| 189 | + velocity_smooth = rep(5, 121) |
| 190 | + ) |
| 191 | + |
| 192 | + result <- calculate_ef_from_stream( |
| 193 | + stream_data = stream_short, |
| 194 | + activity_date = Sys.Date(), |
| 195 | + act_type = "Run", |
| 196 | + ef_metric = "pace_hr", |
| 197 | + min_steady_minutes = 10, # Require 10 minutes |
| 198 | + steady_cv_threshold = 0.1, |
| 199 | + min_hr_coverage = 0.7, |
| 200 | + quality_control = "off" |
| 201 | + ) |
| 202 | + |
| 203 | + expect_equal(result$status, "too_short") |
| 204 | + expect_true(is.na(result$ef_value)) |
| 205 | +}) |
| 206 | + |
| 207 | +test_that("calculate_ef_from_stream handles non-steady activity", { |
| 208 | + # Test with highly variable data (non-steady) |
| 209 | + set.seed(123) |
| 210 | + stream_variable <- data.frame( |
| 211 | + time = seq(0, 599, by = 1), |
| 212 | + heartrate = rep(150, 600), |
| 213 | + velocity_smooth = runif(600, 3, 8) # Very variable speed |
| 214 | + ) |
| 215 | + |
| 216 | + result <- calculate_ef_from_stream( |
| 217 | + stream_data = stream_variable, |
| 218 | + activity_date = Sys.Date(), |
| 219 | + act_type = "Run", |
| 220 | + ef_metric = "pace_hr", |
| 221 | + min_steady_minutes = 5, |
| 222 | + steady_cv_threshold = 0.05, # Very strict CV threshold |
| 223 | + min_hr_coverage = 0.7, |
| 224 | + quality_control = "off" |
| 225 | + ) |
| 226 | + |
| 227 | + # Might return non_steady or might find some steady periods |
| 228 | + expect_true(is.data.frame(result)) |
| 229 | + expect_true("status" %in% names(result)) |
| 230 | +}) |
| 231 | + |
| 232 | +test_that("calculate_ef_from_stream calculates valid EF for good steady data", { |
| 233 | + # Test with good steady-state data |
| 234 | + stream_steady <- data.frame( |
| 235 | + time = seq(0, 1199, by = 1), # 20 minutes |
| 236 | + heartrate = rnorm(1200, mean = 150, sd = 3), # Stable HR |
| 237 | + velocity_smooth = rnorm(1200, mean = 5, sd = 0.2) # Stable pace |
| 238 | + ) |
| 239 | + |
| 240 | + result <- calculate_ef_from_stream( |
| 241 | + stream_data = stream_steady, |
| 242 | + activity_date = Sys.Date(), |
| 243 | + act_type = "Run", |
| 244 | + ef_metric = "pace_hr", |
| 245 | + min_steady_minutes = 10, |
| 246 | + steady_cv_threshold = 0.1, |
| 247 | + min_hr_coverage = 0.7, |
| 248 | + quality_control = "off" |
| 249 | + ) |
| 250 | + |
| 251 | + expect_true(is.data.frame(result)) |
| 252 | + if (result$status == "ok") { |
| 253 | + expect_true(!is.na(result$ef_value)) |
| 254 | + expect_true(result$ef_value > 0) |
| 255 | + } |
| 256 | +}) |
| 257 | + |
| 258 | +test_that("calculate_ef handles export_dir and stream parsing", { |
| 259 | + skip("Requires real activity files") |
| 260 | + |
| 261 | + # This test would need actual activity files |
| 262 | + # Skipping as it requires complex test setup |
| 263 | +}) |
| 264 | + |
0 commit comments