Files
redshift-rebooted/rewrite/tests/continual_mode_tests.rs
T

441 lines
13 KiB
Rust

/// Tests for continual mode functionality
/// These tests verify the main event loop logic without actually running the infinite loop
use redshift_rebooted::types::{ColorSetting, TransitionScheme, NEUTRAL_TEMP};
/* Helper function to calculate transition progress from elevation.
This is the same logic used in main.rs */
fn get_transition_progress_from_elevation(scheme: &TransitionScheme, elevation: f64) -> f64 {
if elevation < scheme.low {
0.0
} else if elevation < scheme.high {
(scheme.low - elevation) / (scheme.low - scheme.high)
} else {
1.0
}
}
/* Helper function to interpolate transition scheme.
This is the same logic used in main.rs */
fn interpolate_transition_scheme(
scheme: &TransitionScheme,
progress: f64,
result: &mut ColorSetting,
) {
let alpha = progress.max(0.0).min(1.0);
result.temperature = ((1.0 - alpha) * (scheme.night.temperature as f64)
+ alpha * (scheme.day.temperature as f64)) as i32;
result.brightness = ((1.0 - alpha) * (scheme.night.brightness as f64)
+ alpha * (scheme.day.brightness as f64)) as f32;
result.gamma[0] = ((1.0 - alpha) * (scheme.night.gamma[0] as f64)
+ alpha * (scheme.day.gamma[0] as f64)) as f32;
result.gamma[1] = ((1.0 - alpha) * (scheme.night.gamma[1] as f64)
+ alpha * (scheme.day.gamma[1] as f64)) as f32;
result.gamma[2] = ((1.0 - alpha) * (scheme.night.gamma[2] as f64)
+ alpha * (scheme.day.gamma[2] as f64)) as f32;
}
/* Helper function to check if color settings differ significantly */
fn color_setting_diff_is_major(first: &ColorSetting, second: &ColorSetting) -> bool {
(first.temperature - second.temperature).abs() > 25
|| (first.brightness - second.brightness).abs() > 0.1
|| (first.gamma[0] - second.gamma[0]).abs() > 0.1
|| (first.gamma[1] - second.gamma[1]).abs() > 0.1
|| (first.gamma[2] - second.gamma[2]).abs() > 0.1
}
/* Helper function to interpolate between color settings */
fn interpolate_color_settings(
first: &ColorSetting,
second: &ColorSetting,
alpha: f64,
result: &mut ColorSetting,
) {
let alpha = alpha.max(0.0).min(1.0);
result.temperature = ((1.0 - alpha) * (first.temperature as f64)
+ alpha * (second.temperature as f64)) as i32;
result.brightness = ((1.0 - alpha) * (first.brightness as f64)
+ alpha * (second.brightness as f64)) as f32;
result.gamma[0] = ((1.0 - alpha) * (first.gamma[0] as f64)
+ alpha * (second.gamma[0] as f64)) as f32;
result.gamma[1] = ((1.0 - alpha) * (first.gamma[1] as f64)
+ alpha * (second.gamma[1] as f64)) as f32;
result.gamma[2] = ((1.0 - alpha) * (first.gamma[2] as f64)
+ alpha * (second.gamma[2] as f64)) as f32;
}
/* Helper function for cubic easing */
fn ease_fade(t: f64) -> f64 {
t * t * (3.0 - 2.0 * t)
}
#[test]
fn test_transition_progress_at_night() {
let scheme = TransitionScheme::default();
// Elevation well below low threshold (-6.0)
let elevation = -20.0;
let progress = get_transition_progress_from_elevation(&scheme, elevation);
assert_eq!(progress, 0.0, "Should return 0.0 for night period");
}
#[test]
fn test_transition_progress_at_day() {
let scheme = TransitionScheme::default();
// Elevation well above high threshold (3.0)
let elevation = 10.0;
let progress = get_transition_progress_from_elevation(&scheme, elevation);
assert_eq!(progress, 1.0, "Should return 1.0 for day period");
}
#[test]
fn test_transition_progress_at_midpoint() {
let scheme = TransitionScheme::default();
// Elevation at exact midpoint between low (-6.0) and high (3.0)
let elevation = -1.5;
let progress = get_transition_progress_from_elevation(&scheme, elevation);
assert!((progress - 0.5).abs() < 0.01, "Should return ~0.5 at midpoint");
}
#[test]
fn test_transition_progress_at_boundaries() {
let scheme = TransitionScheme::default();
// At low boundary
let progress_low = get_transition_progress_from_elevation(&scheme, scheme.low);
assert_eq!(progress_low, 0.0, "Should return 0.0 at low boundary");
// At high boundary
let progress_high = get_transition_progress_from_elevation(&scheme, scheme.high);
assert_eq!(progress_high, 1.0, "Should return 1.0 at high boundary");
}
#[test]
fn test_transition_progress_increases_with_elevation() {
let scheme = TransitionScheme::default();
let prog1 = get_transition_progress_from_elevation(&scheme, -5.0);
let prog2 = get_transition_progress_from_elevation(&scheme, -3.0);
let prog3 = get_transition_progress_from_elevation(&scheme, -1.0);
assert!(prog1 < prog2, "Progress should increase with elevation");
assert!(prog2 < prog3, "Progress should increase with elevation");
}
#[test]
fn test_interpolate_scheme_at_night() {
let scheme = TransitionScheme::default();
let mut result = ColorSetting::default();
interpolate_transition_scheme(&scheme, 0.0, &mut result);
assert_eq!(result.temperature, scheme.night.temperature);
assert_eq!(result.brightness, scheme.night.brightness);
assert_eq!(result.gamma, scheme.night.gamma);
}
#[test]
fn test_interpolate_scheme_at_day() {
let scheme = TransitionScheme::default();
let mut result = ColorSetting::default();
interpolate_transition_scheme(&scheme, 1.0, &mut result);
assert_eq!(result.temperature, scheme.day.temperature);
assert_eq!(result.brightness, scheme.day.brightness);
assert_eq!(result.gamma, scheme.day.gamma);
}
#[test]
fn test_interpolate_scheme_at_midpoint() {
let mut scheme = TransitionScheme::default();
scheme.night.temperature = 3000;
scheme.day.temperature = 6000;
let mut result = ColorSetting::default();
interpolate_transition_scheme(&scheme, 0.5, &mut result);
let expected_temp = 4500;
assert_eq!(result.temperature, expected_temp, "Should be midpoint temperature");
}
#[test]
fn test_interpolate_scheme_clamps_progress() {
let scheme = TransitionScheme::default();
let mut result1 = ColorSetting::default();
let mut result2 = ColorSetting::default();
// Test clamping below 0.0
interpolate_transition_scheme(&scheme, -0.5, &mut result1);
assert_eq!(result1.temperature, scheme.night.temperature);
// Test clamping above 1.0
interpolate_transition_scheme(&scheme, 1.5, &mut result2);
assert_eq!(result2.temperature, scheme.day.temperature);
}
#[test]
fn test_color_diff_major_temperature() {
let setting1 = ColorSetting {
temperature: 6500,
brightness: 1.0,
gamma: [1.0, 1.0, 1.0],
};
let setting2 = ColorSetting {
temperature: 6400,
brightness: 1.0,
gamma: [1.0, 1.0, 1.0],
};
// Difference is 100K, which is > 25K threshold
assert!(color_setting_diff_is_major(&setting1, &setting2));
}
#[test]
fn test_color_diff_minor_temperature() {
let setting1 = ColorSetting {
temperature: 6500,
brightness: 1.0,
gamma: [1.0, 1.0, 1.0],
};
let setting2 = ColorSetting {
temperature: 6490,
brightness: 1.0,
gamma: [1.0, 1.0, 1.0],
};
// Difference is 10K, which is < 25K threshold
assert!(!color_setting_diff_is_major(&setting1, &setting2));
}
#[test]
fn test_color_diff_major_brightness() {
let setting1 = ColorSetting {
temperature: 6500,
brightness: 1.0,
gamma: [1.0, 1.0, 1.0],
};
let setting2 = ColorSetting {
temperature: 6500,
brightness: 0.8,
gamma: [1.0, 1.0, 1.0],
};
// Difference is 0.2, which is > 0.1 threshold
assert!(color_setting_diff_is_major(&setting1, &setting2));
}
#[test]
fn test_color_diff_major_gamma() {
let setting1 = ColorSetting {
temperature: 6500,
brightness: 1.0,
gamma: [1.0, 1.0, 1.0],
};
let setting2 = ColorSetting {
temperature: 6500,
brightness: 1.0,
gamma: [0.8, 1.0, 1.0],
};
// Gamma R difference is 0.2, which is > 0.1 threshold
assert!(color_setting_diff_is_major(&setting1, &setting2));
}
#[test]
fn test_interpolate_settings_at_start() {
let first = ColorSetting {
temperature: 3000,
brightness: 0.8,
gamma: [0.9, 0.9, 0.9],
};
let second = ColorSetting {
temperature: 6000,
brightness: 1.0,
gamma: [1.0, 1.0, 1.0],
};
let mut result = ColorSetting::default();
interpolate_color_settings(&first, &second, 0.0, &mut result);
assert_eq!(result.temperature, first.temperature);
assert_eq!(result.brightness, first.brightness);
assert_eq!(result.gamma, first.gamma);
}
#[test]
fn test_interpolate_settings_at_end() {
let first = ColorSetting {
temperature: 3000,
brightness: 0.8,
gamma: [0.9, 0.9, 0.9],
};
let second = ColorSetting {
temperature: 6000,
brightness: 1.0,
gamma: [1.0, 1.0, 1.0],
};
let mut result = ColorSetting::default();
interpolate_color_settings(&first, &second, 1.0, &mut result);
assert_eq!(result.temperature, second.temperature);
assert_eq!(result.brightness, second.brightness);
assert_eq!(result.gamma, second.gamma);
}
#[test]
fn test_interpolate_settings_at_midpoint() {
let first = ColorSetting {
temperature: 4000,
brightness: 0.8,
gamma: [0.8, 0.8, 0.8],
};
let second = ColorSetting {
temperature: 6000,
brightness: 1.0,
gamma: [1.0, 1.0, 1.0],
};
let mut result = ColorSetting::default();
interpolate_color_settings(&first, &second, 0.5, &mut result);
assert_eq!(result.temperature, 5000);
assert!((result.brightness - 0.9).abs() < 0.01);
assert!((result.gamma[0] - 0.9).abs() < 0.01);
}
#[test]
fn test_interpolate_settings_clamps_alpha() {
let first = ColorSetting {
temperature: 3000,
brightness: 0.8,
gamma: [0.9, 0.9, 0.9],
};
let second = ColorSetting {
temperature: 6000,
brightness: 1.0,
gamma: [1.0, 1.0, 1.0],
};
let mut result_below = ColorSetting::default();
interpolate_color_settings(&first, &second, -0.5, &mut result_below);
assert_eq!(result_below.temperature, first.temperature);
let mut result_above = ColorSetting::default();
interpolate_color_settings(&first, &second, 1.5, &mut result_above);
assert_eq!(result_above.temperature, second.temperature);
}
#[test]
fn test_ease_fade_at_boundaries() {
assert_eq!(ease_fade(0.0), 0.0, "Should be 0.0 at start");
assert_eq!(ease_fade(1.0), 1.0, "Should be 1.0 at end");
}
#[test]
fn test_ease_fade_at_midpoint() {
let mid = ease_fade(0.5);
assert_eq!(mid, 0.5, "Should be 0.5 at midpoint for cubic ease");
}
#[test]
fn test_ease_fade_is_smooth() {
// Test that easing produces smooth acceleration/deceleration
let t1 = ease_fade(0.25);
let t2 = ease_fade(0.5);
let t3 = ease_fade(0.75);
// Should be monotonically increasing
assert!(t1 < t2);
assert!(t2 < t3);
// Cubic easing should start slow, speed up, then slow down
// So the first quarter should produce less than 0.25 progress
assert!(t1 < 0.25);
// And the last quarter should produce more than 0.25 progress
assert!(t3 > 0.75);
}
#[test]
fn test_ease_fade_symmetric() {
// Cubic ease should be symmetric around midpoint
let early = ease_fade(0.3);
let late = ease_fade(0.7);
assert!((early + late - 1.0).abs() < 0.01, "Should be symmetric");
}
#[test]
fn test_fade_animation_sequence() {
// Simulate a 40-step fade from day to night
let start = ColorSetting {
temperature: NEUTRAL_TEMP,
brightness: 1.0,
gamma: [1.0, 1.0, 1.0],
};
let target = ColorSetting {
temperature: 3500,
brightness: 1.0,
gamma: [1.0, 1.0, 1.0],
};
let fade_length = 40;
let mut temps = Vec::new();
for i in 0..=fade_length {
let frac = i as f64 / fade_length as f64;
let alpha = ease_fade(frac);
let mut current = ColorSetting::default();
interpolate_color_settings(&start, &target, alpha, &mut current);
temps.push(current.temperature);
}
// First temp should be start temp
assert_eq!(temps[0], start.temperature);
// Last temp should be target temp
assert_eq!(temps[fade_length as usize], target.temperature);
// Temps should monotonically decrease
for i in 1..temps.len() {
assert!(temps[i] <= temps[i-1], "Temperature should decrease monotonically");
}
}
#[test]
fn test_major_diff_triggers_fade() {
// This tests the logic for when to start a fade
let current = ColorSetting {
temperature: NEUTRAL_TEMP,
brightness: 1.0,
gamma: [1.0, 1.0, 1.0],
};
let target = ColorSetting {
temperature: 3500,
brightness: 1.0,
gamma: [1.0, 1.0, 1.0],
};
// Temperature difference is 3000K, which should trigger fade
assert!(color_setting_diff_is_major(&current, &target));
}
#[test]
fn test_minor_diff_no_fade() {
let current = ColorSetting {
temperature: 6500,
brightness: 1.0,
gamma: [1.0, 1.0, 1.0],
};
let target = ColorSetting {
temperature: 6510,
brightness: 1.0,
gamma: [1.0, 1.0, 1.0],
};
// Temperature difference is only 10K, should not trigger fade
assert!(!color_setting_diff_is_major(&current, &target));
}