use super::*;
#[test]
fn build_desired_emits_cover_jpg_next_to_audio() {
let a = art_clip("id-a");
let clips = [&a];
let desired = build_desired(
&clips,
AudioFormat::Flac,
&modes_for(&clips, SourceMode::Mirror),
&no_contexts(),
&no_collisions(),
ArtifactToggles::default(),
&NamingConfig::default(),
);
let base = desired[0].path.strip_suffix(".flac").unwrap();
assert_eq!(desired[0].artifacts.len(), 1);
let jpg = &desired[0].artifacts[0];
assert_eq!(jpg.kind, ArtifactKind::CoverJpg);
assert_eq!(jpg.path, format!("{base}.jpg"));
assert_eq!(jpg.source_url, a.selected_image_url().unwrap());
assert_eq!(jpg.hash, art_hash(&a));
}
#[test]
fn build_desired_omits_cover_jpg_when_art_is_empty() {
let a = clip("id-a", "Song", "alice");
assert!(a.selected_image_url().is_none());
let clips = [&a];
let desired = build_desired(
&clips,
AudioFormat::Flac,
&modes_for(&clips, SourceMode::Mirror),
&no_contexts(),
&no_collisions(),
ArtifactToggles {
animated_covers: true,
..Default::default()
},
&NamingConfig::default(),
);
assert!(desired[0].artifacts.is_empty());
}
#[test]
fn animated_covers_embed_via_art_hash_not_a_webp_sidecar() {
let with_video = Clip {
video_cover_url: "https://cdn.suno.ai/id-a/video.mp4".to_owned(),
..art_clip("id-a")
};
let clips = [&with_video];
let off = build_desired(
&clips,
AudioFormat::Flac,
&modes_for(&clips, SourceMode::Mirror),
&no_contexts(),
&no_collisions(),
ArtifactToggles::default(),
&NamingConfig::default(),
);
assert_eq!(off[0].artifacts.len(), 1);
assert_eq!(off[0].artifacts[0].kind, ArtifactKind::CoverJpg);
assert_eq!(off[0].art_hash, crate::hash::art_hash(&with_video));
let on = build_desired(
&clips,
AudioFormat::Flac,
&modes_for(&clips, SourceMode::Mirror),
&no_contexts(),
&no_collisions(),
ArtifactToggles {
animated_covers: true,
..Default::default()
},
&NamingConfig::default(),
);
assert!(
on[0]
.artifacts
.iter()
.all(|art| art.kind != ArtifactKind::CoverWebp)
);
assert_eq!(
on[0]
.artifacts
.iter()
.filter(|a| a.kind == ArtifactKind::CoverJpg)
.count(),
1
);
assert_ne!(
on[0].art_hash, off[0].art_hash,
"embed intent drifts the art hash"
);
assert_eq!(
on[0].art_hash,
crate::hash::embedded_art_hash(&with_video, true, &WebpEncodeSettings::default())
);
let no_video = art_clip("id-b");
let clips = [&no_video];
let on_novideo = build_desired(
&clips,
AudioFormat::Flac,
&modes_for(&clips, SourceMode::Mirror),
&no_contexts(),
&no_collisions(),
ArtifactToggles {
animated_covers: true,
..Default::default()
},
&NamingConfig::default(),
);
assert!(
on_novideo[0]
.artifacts
.iter()
.all(|art| art.kind != ArtifactKind::CoverWebp)
);
assert_eq!(on_novideo[0].art_hash, crate::hash::art_hash(&no_video));
let clips = [&with_video];
let alac = build_desired(
&clips,
AudioFormat::Alac,
&modes_for(&clips, SourceMode::Mirror),
&no_contexts(),
&no_collisions(),
ArtifactToggles {
animated_covers: true,
..Default::default()
},
&NamingConfig::default(),
);
assert_eq!(alac[0].art_hash, crate::hash::art_hash(&with_video));
}
#[test]
fn build_desired_emits_video_mp4_only_when_enabled_and_video_present() {
let with_video = Clip {
video_url: "https://cdn.suno.ai/id-a/video.mp4".to_owned(),
..art_clip("id-a")
};
let clips = [&with_video];
let desired = build_desired(
&clips,
AudioFormat::Flac,
&modes_for(&clips, SourceMode::Mirror),
&no_contexts(),
&no_collisions(),
ArtifactToggles::default(),
&NamingConfig::default(),
);
assert!(
desired[0]
.artifacts
.iter()
.all(|art| art.kind != ArtifactKind::VideoMp4)
);
let desired = build_desired(
&clips,
AudioFormat::Flac,
&modes_for(&clips, SourceMode::Mirror),
&no_contexts(),
&no_collisions(),
ArtifactToggles {
video: true,
..Default::default()
},
&NamingConfig::default(),
);
let base = desired[0].path.strip_suffix(".flac").unwrap();
let video = desired[0]
.artifacts
.iter()
.find(|art| art.kind == ArtifactKind::VideoMp4)
.expect("video expected");
assert_eq!(video.path, format!("{base}.mp4"));
assert_eq!(video.source_url, with_video.video_url);
assert_eq!(video.hash, art_url_hash(&with_video.video_url));
assert!(video.content.is_none());
let no_video = art_clip("id-b");
let clips = [&no_video];
let desired = build_desired(
&clips,
AudioFormat::Flac,
&modes_for(&clips, SourceMode::Mirror),
&no_contexts(),
&no_collisions(),
ArtifactToggles {
video: true,
..Default::default()
},
&NamingConfig::default(),
);
assert!(
desired[0]
.artifacts
.iter()
.all(|art| art.kind != ArtifactKind::VideoMp4)
);
}
#[test]
fn build_desired_emits_details_sidecar_only_when_enabled() {
use crate::extras::render_clip_details;
use crate::hash::content_hash;
let a = clip("id-a", "Song", "alice");
let clips = [&a];
let off = build_desired(
&clips,
AudioFormat::Flac,
&modes_for(&clips, SourceMode::Mirror),
&no_contexts(),
&no_collisions(),
ArtifactToggles::default(),
&NamingConfig::default(),
);
assert!(
off[0]
.artifacts
.iter()
.all(|art| art.kind != ArtifactKind::DetailsTxt)
);
let on = build_desired(
&clips,
AudioFormat::Flac,
&modes_for(&clips, SourceMode::Mirror),
&no_contexts(),
&no_collisions(),
ArtifactToggles {
details: true,
..Default::default()
},
&NamingConfig::default(),
);
let base = on[0].path.strip_suffix(".flac").unwrap();
let details = on[0]
.artifacts
.iter()
.find(|art| art.kind == ArtifactKind::DetailsTxt)
.expect("details sidecar expected");
assert_eq!(details.path, format!("{base}.details.txt"));
assert_eq!(details.source_url, "");
let body = render_clip_details(&a, &LineageContext::own_root(&a));
assert_eq!(details.content.as_deref(), Some(body.as_str()));
assert_eq!(details.hash, content_hash(&body));
}
#[test]
fn build_desired_emits_lyrics_sidecar_only_when_enabled_and_present() {
let with_lyrics = Clip {
lyrics: "la la la".to_owned(),
..clip("id-a", "Song", "alice")
};
let clips = [&with_lyrics];
let off = build_desired(
&clips,
AudioFormat::Flac,
&modes_for(&clips, SourceMode::Mirror),
&no_contexts(),
&no_collisions(),
ArtifactToggles::default(),
&NamingConfig::default(),
);
assert!(
off[0]
.artifacts
.iter()
.all(|art| art.kind != ArtifactKind::LyricsTxt)
);
let on = build_desired(
&clips,
AudioFormat::Flac,
&modes_for(&clips, SourceMode::Mirror),
&no_contexts(),
&no_collisions(),
ArtifactToggles {
lyrics: true,
..Default::default()
},
&NamingConfig::default(),
);
let base = on[0].path.strip_suffix(".flac").unwrap();
let lyrics = on[0]
.artifacts
.iter()
.find(|art| art.kind == ArtifactKind::LyricsTxt)
.expect("lyrics sidecar expected");
assert_eq!(lyrics.path, format!("{base}.lyrics.txt"));
assert_eq!(lyrics.source_url, "");
assert_eq!(lyrics.content.as_deref(), Some("la la la\n"));
assert_eq!(lyrics.hash, content_hash("la la la\n"));
}
#[test]
fn build_desired_emits_lrc_sidecar_only_when_enabled() {
let with_lyrics = Clip {
lyrics: "la la la".to_owned(),
..clip("id-a", "Song", "alice")
};
let clips = [&with_lyrics];
let off = build_desired(
&clips,
AudioFormat::Flac,
&modes_for(&clips, SourceMode::Mirror),
&no_contexts(),
&no_collisions(),
ArtifactToggles::default(),
&NamingConfig::default(),
);
assert!(
off[0]
.artifacts
.iter()
.all(|art| art.kind != ArtifactKind::Lrc)
);
let on = build_desired(
&clips,
AudioFormat::Flac,
&modes_for(&clips, SourceMode::Mirror),
&no_contexts(),
&no_collisions(),
ArtifactToggles {
lrc: true,
..Default::default()
},
&NamingConfig::default(),
);
let base = on[0].path.strip_suffix(".flac").unwrap();
let lrc = on[0]
.artifacts
.iter()
.find(|art| art.kind == ArtifactKind::Lrc)
.expect("lrc sidecar expected");
assert_eq!(lrc.path, format!("{base}.lrc"));
assert_eq!(lrc.source_url, "");
assert_eq!(lrc.content, None);
assert_eq!(lrc.hash, synced_lrc_source_hash(&with_lyrics.id));
}
#[test]
fn build_desired_emits_lrc_sidecar_from_prompt_when_feed_omits_lyrics() {
let prompt_only = Clip {
prompt: "the sung words live here".to_owned(),
..clip("id-a", "Song", "alice")
};
assert!(prompt_only.lyrics.is_empty());
let clips = [&prompt_only];
let desired = build_desired(
&clips,
AudioFormat::Flac,
&modes_for(&clips, SourceMode::Mirror),
&no_contexts(),
&no_collisions(),
ArtifactToggles {
lrc: true,
..Default::default()
},
&NamingConfig::default(),
);
let lrc = desired[0]
.artifacts
.iter()
.find(|art| art.kind == ArtifactKind::Lrc)
.expect("lrc sidecar expected");
assert_eq!(lrc.content, None);
assert_eq!(lrc.hash, synced_lrc_source_hash(&prompt_only.id));
}
#[test]
fn build_desired_emits_lrc_sidecar_even_when_feed_has_no_lyrics_or_prompt() {
let bare = clip("id-a", "Song", "alice");
assert!(bare.lyrics.is_empty() && bare.prompt.is_empty());
let clips = [&bare];
let desired = build_desired(
&clips,
AudioFormat::Flac,
&modes_for(&clips, SourceMode::Mirror),
&no_contexts(),
&no_collisions(),
ArtifactToggles {
lrc: true,
..Default::default()
},
&NamingConfig::default(),
);
let lrc = desired[0]
.artifacts
.iter()
.find(|art| art.kind == ArtifactKind::Lrc)
.expect("lrc sidecar expected even with no feed lyrics/prompt");
assert_eq!(lrc.content, None);
assert_eq!(lrc.hash, synced_lrc_source_hash(&bare.id));
}
#[test]
fn build_desired_omits_lyrics_sidecar_when_clip_has_no_lyrics() {
let no_lyrics = clip("id-a", "Song", "alice");
assert!(no_lyrics.lyrics.is_empty());
let clips = [&no_lyrics];
let desired = build_desired(
&clips,
AudioFormat::Flac,
&modes_for(&clips, SourceMode::Mirror),
&no_contexts(),
&no_collisions(),
ArtifactToggles {
lyrics: true,
..Default::default()
},
&NamingConfig::default(),
);
assert!(
desired[0]
.artifacts
.iter()
.all(|art| art.kind != ArtifactKind::LyricsTxt)
);
}
#[test]
fn build_desired_text_sidecars_are_independent() {
let full = Clip {
lyrics: "words".to_owned(),
..art_clip("id-a")
};
let clips = [&full];
let desired = build_desired(
&clips,
AudioFormat::Flac,
&modes_for(&clips, SourceMode::Mirror),
&no_contexts(),
&no_collisions(),
ArtifactToggles {
details: true,
lyrics: true,
..Default::default()
},
&NamingConfig::default(),
);
let base = desired[0].path.strip_suffix(".flac").unwrap();
let kinds: BTreeSet<ArtifactKind> = desired[0].artifacts.iter().map(|a| a.kind).collect();
assert!(kinds.contains(&ArtifactKind::CoverJpg));
assert!(kinds.contains(&ArtifactKind::DetailsTxt));
assert!(kinds.contains(&ArtifactKind::LyricsTxt));
let path_of_kind = |k: ArtifactKind| {
desired[0]
.artifacts
.iter()
.find(|a| a.kind == k)
.unwrap()
.path
.clone()
};
assert_eq!(
path_of_kind(ArtifactKind::DetailsTxt),
format!("{base}.details.txt")
);
assert_eq!(
path_of_kind(ArtifactKind::LyricsTxt),
format!("{base}.lyrics.txt")
);
}