use crate::lighting::effects::*;
use crate::lighting::engine::tests::common::create_test_fixture;
use crate::lighting::engine::EffectEngine;
use std::collections::HashMap;
use std::time::Duration;
#[test]
fn test_start_effect_with_elapsed_static_effect() {
let mut engine = EffectEngine::new();
let fixture = create_test_fixture("test_fixture", 1, 1);
engine.register_fixture(fixture);
let mut params = HashMap::new();
params.insert("dimmer".to_string(), 1.0);
let effect = EffectInstance::new(
"test_effect".to_string(),
EffectType::Static {
parameters: params,
duration: Duration::from_secs(5),
},
vec!["test_fixture".to_string()],
None,
None,
None,
);
engine
.start_effect_with_elapsed(effect, Duration::from_millis(500))
.unwrap();
let commands = engine.update(Duration::from_millis(16), None).unwrap();
assert_eq!(commands.len(), 1);
assert_eq!(commands[0].value, 255);
}
#[test]
fn test_start_effect_with_elapsed_dimmer_midpoint() {
let mut engine = EffectEngine::new();
let fixture = create_test_fixture("test_fixture", 1, 1);
engine.register_fixture(fixture);
let effect = EffectInstance::new(
"dimmer".to_string(),
EffectType::Dimmer {
start_level: 0.0,
end_level: 1.0,
duration: Duration::from_secs(2), curve: DimmerCurve::Linear,
},
vec!["test_fixture".to_string()],
None,
None,
None,
);
engine
.start_effect_with_elapsed(effect, Duration::from_secs(1))
.unwrap();
let commands = engine.update(Duration::from_millis(16), None).unwrap();
assert_eq!(commands.len(), 1);
assert!(
(120..=135).contains(&commands[0].value),
"Expected ~50% dimmer value, got {}",
commands[0].value
);
}
#[test]
fn test_start_effect_with_elapsed_dimmer_complete() {
let mut engine = EffectEngine::new();
let fixture = create_test_fixture("test_fixture", 1, 1);
engine.register_fixture(fixture);
let effect = EffectInstance::new(
"dimmer".to_string(),
EffectType::Dimmer {
start_level: 0.0,
end_level: 1.0,
duration: Duration::from_secs(1),
curve: DimmerCurve::Linear,
},
vec!["test_fixture".to_string()],
None,
None,
None,
);
engine
.start_effect_with_elapsed(effect, Duration::from_secs(2))
.unwrap();
let commands = engine.update(Duration::from_millis(16), None).unwrap();
assert_eq!(commands.len(), 0, "Completed dimmer produces no commands");
}
#[test]
fn test_start_effect_with_elapsed_color_cycle() {
let mut engine = EffectEngine::new();
let fixture = create_test_fixture("test_fixture", 1, 1);
engine.register_fixture(fixture);
let colors = vec![
Color::new(255, 0, 0), Color::new(0, 255, 0), Color::new(0, 0, 255), ];
let effect = EffectInstance::new(
"cycle".to_string(),
EffectType::ColorCycle {
colors,
speed: TempoAwareSpeed::Fixed(1.0), direction: CycleDirection::Forward,
transition: CycleTransition::Snap,
duration: Duration::from_secs(10),
},
vec!["test_fixture".to_string()],
None,
None,
None,
);
engine
.start_effect_with_elapsed(effect, Duration::from_millis(500))
.unwrap();
let commands = engine.update(Duration::from_millis(16), None).unwrap();
assert_eq!(commands.len(), 3);
let mut red = 0;
let mut green = 0;
let mut blue = 0;
for cmd in commands {
if cmd.channel == 2 {
red = cmd.value;
} else if cmd.channel == 3 {
green = cmd.value;
} else if cmd.channel == 4 {
blue = cmd.value;
}
}
assert_eq!(red, 0, "Red should be 0 at this point in cycle");
assert_eq!(green, 255, "Green should be full at this point in cycle");
assert_eq!(blue, 0, "Blue should be 0");
}
#[test]
fn test_start_effect_with_elapsed_pulse() {
let mut engine = EffectEngine::new();
let fixture = create_test_fixture("test_fixture", 1, 1);
engine.register_fixture(fixture);
let effect = EffectInstance::new(
"pulse".to_string(),
EffectType::Pulse {
base_level: 0.5,
pulse_amplitude: 0.5,
frequency: TempoAwareFrequency::Fixed(1.0), duration: Duration::from_secs(5),
},
vec!["test_fixture".to_string()],
None,
None,
None,
);
engine
.start_effect_with_elapsed(effect, Duration::from_millis(250))
.unwrap();
let commands = engine.update(Duration::from_millis(16), None).unwrap();
assert_eq!(commands.len(), 1);
assert!(
commands[0].value > 240,
"Pulse should be near max at 90 degrees, got {}",
commands[0].value
);
}
#[test]
fn test_start_effect_with_elapsed_rainbow() {
let mut engine = EffectEngine::new();
let fixture = create_test_fixture("test_fixture", 1, 1);
engine.register_fixture(fixture);
let effect = EffectInstance::new(
"rainbow".to_string(),
EffectType::Rainbow {
speed: TempoAwareSpeed::Fixed(1.0), saturation: 1.0,
brightness: 1.0,
duration: Duration::from_secs(10),
},
vec!["test_fixture".to_string()],
None,
None,
None,
);
engine
.start_effect_with_elapsed(effect, Duration::from_millis(333))
.unwrap();
let commands = engine.update(Duration::from_millis(16), None).unwrap();
assert_eq!(commands.len(), 3);
let mut red = 0;
let mut green = 0;
let mut blue = 0;
for cmd in commands {
if cmd.channel == 2 {
red = cmd.value;
} else if cmd.channel == 3 {
green = cmd.value;
} else if cmd.channel == 4 {
blue = cmd.value;
}
}
assert!(green > red, "Green should dominate at 120 degrees");
assert!(green > blue, "Green should be highest");
}
#[test]
fn test_start_effect_with_elapsed_timed_effect_completion() {
let mut engine = EffectEngine::new();
let fixture = create_test_fixture("test_fixture", 1, 1);
engine.register_fixture(fixture);
let mut params = HashMap::new();
params.insert("dimmer".to_string(), 1.0);
let effect = EffectInstance::new(
"timed".to_string(),
EffectType::Static {
parameters: params,
duration: Duration::from_secs(1),
},
vec!["test_fixture".to_string()],
None,
Some(Duration::from_secs(1)),
None,
);
engine
.start_effect_with_elapsed(effect, Duration::from_millis(1500))
.unwrap();
let commands = engine.update(Duration::from_millis(16), None).unwrap();
assert_eq!(commands.len(), 0);
}
#[test]
fn test_start_effect_with_elapsed_zero_elapsed() {
let mut engine = EffectEngine::new();
let fixture = create_test_fixture("test_fixture", 1, 1);
engine.register_fixture(fixture);
let mut params = HashMap::new();
params.insert("dimmer".to_string(), 0.5);
let effect1 = EffectInstance::new(
"effect1".to_string(),
EffectType::Static {
parameters: params.clone(),
duration: Duration::from_secs(5),
},
vec!["test_fixture".to_string()],
None,
None,
None,
);
engine.start_effect(effect1).unwrap();
let commands1 = engine
.update(Duration::from_millis(16), None)
.unwrap()
.to_vec();
engine.stop_all_effects();
let effect2 = EffectInstance::new(
"effect2".to_string(),
EffectType::Static {
parameters: params,
duration: Duration::from_secs(5),
},
vec!["test_fixture".to_string()],
None,
None,
None,
);
engine
.start_effect_with_elapsed(effect2, Duration::ZERO)
.unwrap();
let commands2 = engine.update(Duration::from_millis(16), None).unwrap();
assert_eq!(commands1.len(), commands2.len());
if !commands1.is_empty() && !commands2.is_empty() {
assert_eq!(commands1[0].value, commands2[0].value);
}
}
#[test]
fn test_start_effect_with_elapsed_conflict_resolution() {
let mut engine = EffectEngine::new();
let fixture = create_test_fixture("test_fixture", 1, 1);
engine.register_fixture(fixture);
let mut bg_params = HashMap::new();
bg_params.insert("dimmer".to_string(), 0.3);
let bg_effect = EffectInstance::new(
"bg".to_string(),
EffectType::Static {
parameters: bg_params,
duration: Duration::from_secs(5),
},
vec!["test_fixture".to_string()],
None,
None,
None,
);
engine.start_effect(bg_effect).unwrap();
engine.update(Duration::from_millis(16), None).unwrap();
let mut fg_params = HashMap::new();
fg_params.insert("dimmer".to_string(), 0.8);
let mut fg_effect = EffectInstance::new(
"fg".to_string(),
EffectType::Static {
parameters: fg_params,
duration: Duration::from_secs(5),
},
vec!["test_fixture".to_string()],
None,
None,
None,
);
fg_effect.layer = EffectLayer::Foreground;
fg_effect.priority = 10;
engine
.start_effect_with_elapsed(fg_effect, Duration::from_millis(500))
.unwrap();
let commands = engine.update(Duration::from_millis(16), None).unwrap();
assert_eq!(commands.len(), 1);
assert_eq!(commands[0].value, 204); }