use std::path::PathBuf;
pub fn examples_dir() -> PathBuf {
PathBuf::from("examples")
}
#[test]
fn test_parse_main_config() {
let config_content = r#"
audio:
device: "test_device"
sample_rate: 44100
midi:
device: "test_midi"
dmx:
dim_speed_modifier: 0.25
playback_delay: "500ms"
universes:
- universe: 1
name: "light-show"
lighting:
current_venue: "main_stage"
groups:
front_wash:
name: "front_wash"
constraints:
- AllOf: ["wash", "front"]
- MinCount: 4
- MaxCount: 8
back_wash:
name: "back_wash"
constraints:
- AllOf: ["wash", "back"]
- MinCount: 2
- MaxCount: 6
directories:
fixture_types: "lighting/fixture_types"
venues: "lighting/venues"
controllers: []
track_mappings:
click: [1]
cue: [2]
songs: "songs"
"#;
use std::io::Write;
let mut temp_file =
std::fs::File::create("test_config.yaml").expect("Failed to create temp file");
temp_file
.write_all(config_content.as_bytes())
.expect("Failed to write config");
drop(temp_file);
let config = crate::config::Player::deserialize(std::path::Path::new("test_config.yaml"))
.expect("Failed to parse main config");
assert!(config.audio().is_some());
assert!(config.midi().is_some());
assert!(config.dmx().is_some());
let dmx_config = config.dmx().unwrap();
assert!(dmx_config.lighting().is_some());
let lighting_config = dmx_config.lighting().unwrap();
assert_eq!(lighting_config.current_venue(), Some("main_stage"));
assert!(lighting_config.directories().is_some());
let groups = lighting_config.groups();
assert!(groups.contains_key("front_wash"));
assert!(groups.contains_key("back_wash"));
std::fs::remove_file("test_config.yaml").ok();
}
#[test]
fn test_parse_songs_with_lighting() {
let song_config = crate::config::Song::new(
"Test Song",
None,
None,
None,
None,
Some(vec![
crate::config::LightingShow::new("lighting/main_show.light".to_string()),
crate::config::LightingShow::new("lighting/outro.light".to_string()),
]),
vec![],
std::collections::HashMap::new(),
Vec::new(),
);
assert!(song_config.lighting().is_some());
let lighting_shows = song_config.lighting().unwrap();
assert_eq!(lighting_shows.len(), 2);
let show_files: Vec<&str> = lighting_shows.iter().map(|s| s.file()).collect();
assert!(show_files.contains(&"lighting/main_show.light"));
assert!(show_files.contains(&"lighting/outro.light"));
let main_show = lighting_shows
.iter()
.find(|s| s.file() == "lighting/main_show.light")
.unwrap();
assert_eq!(main_show.file(), "lighting/main_show.light");
let outro_show = lighting_shows
.iter()
.find(|s| s.file() == "lighting/outro.light")
.unwrap();
assert_eq!(outro_show.file(), "lighting/outro.light");
}
#[test]
fn test_parse_dsl_lighting_shows() {
let simple_content = r#"show "Test Show" {
@00:00.000
front_wash: static color: "blue", duration: 5s, dimmer: 60%
}"#;
let simple_shows = crate::lighting::parser::parse_light_shows(simple_content)
.expect("Failed to parse simple DSL");
assert_eq!(simple_shows.len(), 1);
let show = simple_shows.get("Test Show").expect("Test Show not found");
assert_eq!(show.name, "Test Show");
assert_eq!(show.cues.len(), 1);
let first_cue = &show.cues[0];
assert_eq!(first_cue.time.as_secs(), 0);
assert_eq!(first_cue.effects.len(), 1);
let first_effect = &first_cue.effects[0];
assert_eq!(first_effect.groups, vec!["front_wash"]);
match &first_effect.effect_type {
crate::lighting::effects::EffectType::Static { parameters, .. } => {
assert!(parameters.contains_key("dimmer"));
assert!(
parameters.contains_key("red")
|| parameters.contains_key("green")
|| parameters.contains_key("blue")
);
}
_ => panic!("Expected static effect"),
}
}
#[test]
fn test_parse_outro_lighting_show() {
let simple_outro = r#"show "Outro Show" {
@00:00.000
all_fixtures: static color: "blue", duration: 5s, dimmer: 20%
}"#;
let shows = crate::lighting::parser::parse_light_shows(simple_outro)
.expect("Failed to parse outro lighting show");
assert_eq!(shows.len(), 1);
let show = shows.get("Outro Show").expect("Outro Show not found");
assert_eq!(show.name, "Outro Show");
assert_eq!(show.cues.len(), 1);
let first_cue = &show.cues[0];
assert_eq!(first_cue.time.as_secs(), 0);
assert_eq!(first_cue.effects.len(), 1);
let first_effect = &first_cue.effects[0];
assert_eq!(first_effect.groups, vec!["all_fixtures"]);
}
#[test]
fn test_complete_integration_flow() {
let config_path = examples_dir().join("mtrack.yaml");
let config = crate::config::Player::deserialize(&config_path).expect("Failed to parse config");
let songs_dir = examples_dir().join("songs");
let songs = crate::songs::get_all_songs(&songs_dir).expect("Failed to load songs");
let songs_list = songs.list();
let song_names: Vec<String> = songs_list.iter().map(|s| s.name().to_string()).collect();
if song_names.contains(&"DSL Light Show Song".to_string()) {
let dsl_song = songs
.get("DSL Light Show Song")
.expect("DSL light show song not found");
assert!(!dsl_song.dsl_lighting_shows().is_empty());
let lighting_shows = dsl_song.dsl_lighting_shows();
for lighting_show in lighting_shows {
let show_path = lighting_show.file_path();
let content = std::fs::read_to_string(show_path).expect("Failed to read show file");
let shows =
crate::lighting::parser::parse_light_shows(&content).expect("Failed to parse show");
assert!(!shows.is_empty());
}
}
let dmx_config = config.dmx().unwrap();
assert!(dmx_config.lighting().is_some());
let lighting_config = dmx_config.lighting().unwrap();
assert_eq!(lighting_config.current_venue(), Some("main_stage"));
let groups = lighting_config.groups();
assert!(groups.contains_key("front_wash"));
assert!(groups.contains_key("back_wash"));
assert!(groups.contains_key("movers"));
assert!(groups.contains_key("strobes"));
assert!(groups.contains_key("all_lights"));
let directories = lighting_config.directories().unwrap();
assert_eq!(directories.fixture_types(), Some("lighting/fixture_types"));
assert_eq!(directories.venues(), Some("lighting/venues"));
}
#[test]
fn test_all_example_songs_load() {
let songs_dir = examples_dir().join("songs");
let songs = crate::songs::get_all_songs(&songs_dir).expect("Failed to load songs");
let songs_list = songs.list();
assert!(!songs_list.is_empty());
let song_names: Vec<String> = songs_list.iter().map(|s| s.name().to_string()).collect();
println!("Actual songs found: {:?}", song_names);
let expected_songs = vec![
"A really fast one",
"Another cool song",
"Outro tape",
"Sound check",
];
for expected_song in expected_songs {
assert!(
song_names.contains(&expected_song.to_string()),
"Missing song: {}",
expected_song
);
}
if song_names.contains(&"DSL Light Show Song".to_string()) {
let dsl_song = songs.get("DSL Light Show Song").unwrap();
assert!(!dsl_song.dsl_lighting_shows().is_empty());
}
for song in songs_list {
if song.name() != "DSL Light Show Song" {
assert!(!song.name().is_empty());
}
}
}
#[test]
fn test_parse_playlist() {
let playlist_path = examples_dir().join("playlist.yaml");
let playlist =
crate::config::Playlist::deserialize(&playlist_path).expect("Failed to parse playlist");
assert!(!playlist.songs().is_empty());
let songs = playlist.songs();
assert!(songs.contains(&"A really cool song".to_string()));
assert!(songs.contains(&"Sound check".to_string()));
}
#[test]
fn test_song_with_lighting_shows() {
let song_config = crate::config::Song::new(
"Shieldbrother",
None,
None,
None,
None,
Some(vec![crate::config::LightingShow::new(
"show.light".to_string(),
)]),
vec![],
std::collections::HashMap::new(),
Vec::new(),
);
assert!(song_config.lighting().is_some());
let lighting_shows = song_config.lighting().unwrap();
assert_eq!(lighting_shows.len(), 1);
let show = &lighting_shows[0];
assert_eq!(show.file(), "show.light");
let dsl_content = r#"show "Shieldbrother" {
@00:00.000
front_wash: static color: "blue", duration: 5s, dimmer: 60%
@00:05.000
front_wash: static color: "red", duration: 5s, dimmer: 80%
}"#;
let shows = crate::lighting::parser::parse_light_shows(dsl_content).unwrap();
assert_eq!(shows.len(), 1);
assert!(shows.contains_key("Shieldbrother"));
let show = shows.get("Shieldbrother").unwrap();
assert_eq!(show.name, "Shieldbrother");
assert_eq!(show.cues.len(), 2);
}