use crate::lighting::effects::*;
use crate::lighting::engine::tests::common::create_test_fixture;
use crate::lighting::engine::EffectEngine;
use std::time::Duration;
#[test]
fn test_chase_fixture_boundaries() {
let mut engine = EffectEngine::new();
let fixture_0 = create_test_fixture("fixture_0", 1, 1);
let fixture_1 = create_test_fixture("fixture_1", 1, 11);
let fixture_2 = create_test_fixture("fixture_2", 1, 21);
engine.register_fixture(fixture_0);
engine.register_fixture(fixture_1);
engine.register_fixture(fixture_2);
let effect = EffectInstance::new(
"test_effect".to_string(),
EffectType::Chase {
pattern: ChasePattern::Linear,
speed: TempoAwareSpeed::Fixed(1.0),
direction: ChaseDirection::LeftToRight,
transition: CycleTransition::Snap,
duration: Duration::from_secs(10),
},
vec![
"fixture_0".to_string(),
"fixture_1".to_string(),
"fixture_2".to_string(),
],
None,
None,
None,
);
engine.start_effect(effect).unwrap();
let count_active = |commands: &[DmxCommand]| -> usize {
let dimmer_channels = [1, 11, 21];
commands
.iter()
.filter(|cmd| dimmer_channels.contains(&cmd.channel) && cmd.value == 255)
.count()
};
let commands = engine.update(Duration::from_millis(0), None).unwrap();
assert_eq!(
count_active(commands),
1,
"At t=0ms exactly one fixture should be active"
);
let commands = engine.update(Duration::from_millis(350), None).unwrap();
assert_eq!(
count_active(commands),
1,
"At t=350ms exactly one fixture should be active"
);
let commands = engine.update(Duration::from_millis(350), None).unwrap();
assert_eq!(
count_active(commands),
1,
"At t=700ms exactly one fixture should be active"
);
let commands = engine.update(Duration::from_millis(350), None).unwrap();
assert_eq!(
count_active(commands),
1,
"At t=1050ms exactly one fixture should be active (wrapped)"
);
}
#[test]
fn test_chase_zero_speed() {
let mut engine = EffectEngine::new();
let fixture_0 = create_test_fixture("fixture_0", 1, 1);
let fixture_1 = create_test_fixture("fixture_1", 1, 11);
let fixture_2 = create_test_fixture("fixture_2", 1, 21);
engine.register_fixture(fixture_0);
engine.register_fixture(fixture_1);
engine.register_fixture(fixture_2);
let effect = EffectInstance::new(
"test_effect".to_string(),
EffectType::Chase {
pattern: ChasePattern::Linear,
speed: TempoAwareSpeed::Fixed(0.0), direction: ChaseDirection::LeftToRight,
transition: CycleTransition::Snap,
duration: Duration::from_secs(10),
},
vec![
"fixture_0".to_string(),
"fixture_1".to_string(),
"fixture_2".to_string(),
],
None,
None,
None,
);
engine.start_effect(effect).unwrap();
let commands = engine.update(Duration::from_millis(0), None).unwrap();
let dimmer_channels = [1, 11, 21];
let active_count = commands
.iter()
.filter(|cmd| dimmer_channels.contains(&cmd.channel) && cmd.value == 255)
.count();
assert_eq!(
active_count, 1,
"Zero speed should have exactly one fixture active"
);
let first_dimmer = commands.iter().find(|cmd| cmd.channel == 1).unwrap();
assert_eq!(first_dimmer.value, 255, "First fixture should be active");
let commands = engine.update(Duration::from_millis(5000), None).unwrap();
let first_dimmer = commands.iter().find(|cmd| cmd.channel == 1).unwrap();
assert_eq!(
first_dimmer.value, 255,
"Zero speed should remain frozen on first fixture"
);
}
#[test]
fn test_chase_empty_fixtures() {
let mut engine = EffectEngine::new();
let effect = EffectInstance::new(
"test_effect".to_string(),
EffectType::Chase {
pattern: ChasePattern::Linear,
speed: TempoAwareSpeed::Fixed(1.0),
direction: ChaseDirection::LeftToRight,
transition: CycleTransition::Snap,
duration: Duration::from_secs(10),
},
vec![], None,
None,
None,
);
engine.start_effect(effect).unwrap();
let commands = engine.update(Duration::from_millis(0), None).unwrap();
assert!(
commands.is_empty(),
"Empty fixture chase should produce no commands"
);
let commands = engine.update(Duration::from_millis(1000), None).unwrap();
assert!(
commands.is_empty(),
"Empty fixture chase should still produce no commands"
);
}
#[test]
fn test_chase_effect() {
let mut engine = EffectEngine::new();
let fixture1 = create_test_fixture("fixture1", 1, 1);
let fixture2 = create_test_fixture("fixture2", 1, 6);
let fixture3 = create_test_fixture("fixture3", 1, 11);
engine.register_fixture(fixture1);
engine.register_fixture(fixture2);
engine.register_fixture(fixture3);
let effect = EffectInstance::new(
"test_effect".to_string(),
EffectType::Chase {
pattern: ChasePattern::Linear,
speed: TempoAwareSpeed::Fixed(1.0),
direction: ChaseDirection::LeftToRight,
transition: CycleTransition::Snap,
duration: Duration::from_secs(10),
},
vec![
"fixture1".to_string(),
"fixture2".to_string(),
"fixture3".to_string(),
],
None,
None,
None,
);
engine.start_effect(effect).unwrap();
let commands = engine.update(Duration::from_millis(16), None).unwrap();
assert!(commands.len() >= 3);
for cmd in commands {
assert!(cmd.channel >= 1 && cmd.channel <= 15); }
}