use chromacat::pattern::{
PatternConfig, PatternEngine, PatternParams,
CheckerboardParams, DiagonalParams, DiamondParams, HorizontalParams,
PerlinParams, PlasmaParams, RippleParams, SpiralParams, WaveParams,
};
use colorgrad::{Color, Gradient};
struct MockGradient;
impl Gradient for MockGradient {
fn at(&self, t: f32) -> Color {
Color::new(t, t, t, 1.0_f32)
}
}
fn create_test_gradient() -> Box<dyn Gradient + Send + Sync> {
Box::new(MockGradient)
}
struct PatternTest {
width: usize,
height: usize,
}
impl PatternTest {
fn new() -> Self {
Self {
width: 100,
height: 100,
}
}
fn create_engine(&self, params: PatternParams) -> PatternEngine {
let config = PatternConfig::new(params);
PatternEngine::new(create_test_gradient(), config, self.width, self.height)
}
fn assert_pattern_bounds(&self, engine: &PatternEngine) {
for y in 0..self.height {
for x in 0..self.width {
let value = engine.get_value_at(x, y).unwrap();
assert!(
(0.0..=1.0).contains(&value),
"Pattern value out of bounds at ({}, {}): {}",
x,
y,
value
);
}
}
}
}
#[test]
fn test_all_patterns_bounds() {
let test = PatternTest::new();
let patterns = vec![
PatternParams::Horizontal(HorizontalParams::default()),
PatternParams::Diagonal(DiagonalParams::default()),
PatternParams::Plasma(PlasmaParams::default()),
PatternParams::Ripple(RippleParams::default()),
PatternParams::Wave(WaveParams::default()),
PatternParams::Spiral(SpiralParams::default()),
PatternParams::Checkerboard(CheckerboardParams::default()),
PatternParams::Diamond(DiamondParams::default()),
PatternParams::Perlin(PerlinParams::default()),
];
for params in patterns {
let engine = test.create_engine(params.clone());
test.assert_pattern_bounds(&engine);
}
}
#[test]
fn test_pattern_animation() {
let test = PatternTest::new();
let animated_patterns = vec![
PatternParams::Wave(WaveParams::default()),
PatternParams::Ripple(RippleParams::default()),
PatternParams::Spiral(SpiralParams::default()),
PatternParams::Plasma(PlasmaParams::default()),
];
for pattern in animated_patterns {
eprintln!("\nDEBUG: Testing animation for pattern: {:?}", pattern);
let mut config = PatternConfig::new(pattern.clone());
config.common.speed = 1.0;
let mut engine = PatternEngine::new(create_test_gradient(), config, test.width, test.height);
let initial = engine.get_value_at(50, 50).unwrap();
eprintln!("DEBUG: Initial value: {}", initial);
eprintln!("DEBUG: Current time: {}", engine.time());
engine.update(1.0);
eprintln!("DEBUG: Updated time to: {}", engine.time());
let animated = engine.get_value_at(50, 50).unwrap();
eprintln!("DEBUG: Animated value: {}", animated);
assert_ne!(
initial, animated,
"Pattern {:?} should produce different values after animation",
pattern
);
}
}
#[test]
fn test_pattern_determinism() {
let test = PatternTest::new();
let patterns = vec![
PatternParams::Horizontal(HorizontalParams::default()),
PatternParams::Diagonal(DiagonalParams::default()),
PatternParams::Checkerboard(CheckerboardParams::default()),
PatternParams::Diamond(DiamondParams::default()),
PatternParams::Perlin(PerlinParams::default()),
];
for params in patterns {
let engine = test.create_engine(params.clone());
let first = engine.get_value_at(50, 50).unwrap();
let second = engine.get_value_at(50, 50).unwrap();
assert_eq!(
first, second,
"Pattern {:?} should produce consistent values for same coordinates",
params
);
}
}