use chromacat::pattern::{CommonParams, PatternConfig, PatternEngine, PatternParams, HorizontalParams};
use chromacat::renderer::{AnimationConfig, Renderer};
use colorgrad::{Color, Gradient};
use std::time::Duration;
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 RendererTest {
engine: PatternEngine,
config: AnimationConfig,
}
impl RendererTest {
fn new() -> Self {
let pattern_config = PatternConfig {
common: CommonParams::default(),
params: PatternParams::Horizontal(HorizontalParams::default()),
};
let engine = PatternEngine::new(
create_test_gradient(),
pattern_config,
80, 24, );
let config = AnimationConfig {
fps: 30,
cycle_duration: Duration::from_secs(1),
infinite: false,
show_progress: true,
smooth: false,
};
Self { engine, config }
}
fn create_renderer(&self) -> Result<Renderer, Box<dyn std::error::Error>> {
let renderer = Renderer::new(self.engine.clone(), self.config.clone())?;
Ok(renderer)
}
}
#[test]
fn test_renderer_creation() {
let test = RendererTest::new();
assert!(test.create_renderer().is_ok());
}
#[test]
fn test_static_rendering() {
let test = RendererTest::new();
let mut renderer = test.create_renderer().unwrap();
assert!(renderer.render_static("Hello, World!").is_ok());
}
#[test]
fn test_animated_rendering() {
let test = RendererTest::new();
let mut renderer = test.create_renderer().unwrap();
assert!(renderer.render_frame("Test", 0.016).is_ok()); }
#[test]
fn test_text_handling() {
let test_cases = vec![
("Simple text", "ascii only"),
("Hello, δΈη!", "unicode text"),
("π π π¨", "emojis"),
("Multi\nline\ntext", "multiline"),
(" Leading spaces ", "whitespace"),
("Very long text that should wrap automatically when it reaches the terminal width limit", "wrapping"),
("\t\tTabbed\ttext", "tabs"),
("Mixed π¨βπ©βπ§βπ¦ family emoji", "complex emoji"),
("", "empty string"),
];
let test = RendererTest::new();
let mut renderer = test.create_renderer().unwrap();
for (text, case) in test_cases {
assert!(
renderer.render_static(text).is_ok(),
"Failed to render {}: {}",
case,
text
);
}
}
#[test]
fn test_animation_timing() {
let test = RendererTest::new();
let renderer = test.create_renderer().unwrap();
let expected = Duration::from_nanos(1_000_000_000u64 / 30);
let actual = renderer.frame_duration();
let difference = if actual > expected {
actual - expected
} else {
expected - actual
};
assert!(
difference < Duration::from_micros(1),
"Frame duration {:?} differs from expected {:?} by {:?}",
actual,
expected,
difference
);
assert!(!renderer.is_infinite());
assert_eq!(renderer.cycle_duration(), Duration::from_secs(1));
}
#[test]
fn test_animation_progress() {
let test = RendererTest::new();
let mut renderer = test.create_renderer().unwrap();
let progress_points = [
0.0, 0.5, 0.999, ];
for seconds in progress_points {
assert!(
renderer.render_frame("Animation Test", seconds).is_ok(),
"Failed to render at {} seconds",
seconds
);
}
}
#[test]
fn test_unicode_width() {
let test = RendererTest::new();
let mut renderer = test.create_renderer().unwrap();
let test_cases = vec![
"Hello", "δΈη", "π¨βπ©βπ§βπ¦", "Ξ± Ξ² Ξ³", "π³οΈβπ", "ο½ο½ο½ο½width", ];
for text in test_cases {
assert!(
renderer.render_static(text).is_ok(),
"Failed to handle width of: {}",
text
);
}
}
#[test]
fn test_large_text_performance() {
let test = RendererTest::new();
let mut renderer = test.create_renderer().unwrap();
let large_text = (0..1000)
.map(|i| format!("Line {}\n", i))
.collect::<String>();
let start = std::time::Instant::now();
renderer.render_static(&large_text).unwrap();
let duration = start.elapsed();
assert!(
duration < Duration::from_secs(1),
"Rendering took too long: {:?}",
duration
);
}
#[test]
fn test_animation_performance() {
let test = RendererTest::new();
let mut renderer = test.create_renderer().unwrap();
let frame_count = 10; let delta_seconds = 0.016;
let start = std::time::Instant::now();
for _ in 0..frame_count {
renderer.render_frame("Animation test", delta_seconds).unwrap();
}
let duration = start.elapsed();
let max_allowed_duration = Duration::from_millis((frame_count * 50) as u64); assert!(
duration < max_allowed_duration,
"Animation too slow: {:?} (allowed: {:?})",
duration,
max_allowed_duration
);
}