test(cold-paths): cover 3 lines in mama/rsi/sine_wave (#58)
* test(cold-paths): cover phase fallback in mama/sine_wave and rsi naive helper saturation * fix(rsi): drop redundant closure in test helper
This commit is contained in:
@@ -369,13 +369,13 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn flat_input_uses_phase_fallback() {
|
||||
// A perfectly constant series leaves every smooth/detrender slot at
|
||||
// the same value, so `i1` collapses to zero and the phase calc takes
|
||||
// the `self.prev_phase` fallback rather than `atan(q1/i1)`. Stretch
|
||||
// the run long enough to clear the 50-bar warmup with comfortable
|
||||
// margin and confirm the indicator still emits.
|
||||
// Zero inputs make every smooth/detrender term arithmetically exact
|
||||
// zero, so `i1 == 0.0` and the phase calculation takes the
|
||||
// `self.prev_phase` fallback rather than `atan(q1/i1)`. A non-zero
|
||||
// constant like `50.0` leaves a sub-EPSILON cancellation residue
|
||||
// that flips the branch back to the `atan` path on real hardware.
|
||||
let mut mama = Mama::classic();
|
||||
let out = mama.batch(&[50.0_f64; 200]);
|
||||
let out = mama.batch(&[0.0_f64; 200]);
|
||||
assert!(out.iter().flatten().count() > 100);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,6 +230,20 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
/// Cover the `100.0` branch (line 169) of the test-helper `rsi_naive`:
|
||||
/// strictly increasing prices give `avg_loss == 0` while `avg_gain > 0`,
|
||||
/// the textbook overbought saturation case. Random proptest inputs
|
||||
/// virtually never satisfy `al == 0 && ag != 0`, so this needs an
|
||||
/// explicit monotone series.
|
||||
#[test]
|
||||
fn naive_helper_monotone_up_yields_100() {
|
||||
let prices: Vec<f64> = (1..=20).map(f64::from).collect();
|
||||
let ks = rsi_naive(&prices, 5);
|
||||
for r in ks.into_iter().skip(5) {
|
||||
assert_eq!(r.expect("ready after period+1 inputs"), 100.0);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn warmup_period_is_period_plus_one() {
|
||||
let rsi = Rsi::new(14).unwrap();
|
||||
|
||||
@@ -218,11 +218,13 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn flat_input_uses_phase_fallback() {
|
||||
// A constant series leaves the detrender chain at zero, so the `i1`
|
||||
// arm is `i1.abs() <= EPSILON` for every bar and the phase calculation
|
||||
// takes the `self.last_phase` fallback rather than `atan(q1/i1)`.
|
||||
// Zero inputs make every smooth/detrender term arithmetically exact
|
||||
// zero (no IEEE-754 cancellation residue), so `i1 == 0.0` and the
|
||||
// phase calculation deterministically takes the `self.last_phase`
|
||||
// fallback rather than `atan(q1/i1)`. A non-zero constant like
|
||||
// `100.0` leaves a sub-EPSILON residue that flips the branch back.
|
||||
let mut sw = SineWave::new();
|
||||
let _ = sw.batch(&[100.0_f64; 120]);
|
||||
let _ = sw.batch(&[0.0_f64; 120]);
|
||||
assert!(sw.value().is_some());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user