use std::collections::BTreeSet;
use crate::manifest::Manifest;
pub fn untracked_audio(manifest: &Manifest, on_disk: &[String]) -> Vec<String> {
let tracked: BTreeSet<&str> = manifest
.iter()
.flat_map(|(_, entry)| std::iter::once(entry.path.as_str()).chain(entry.artifact_paths()))
.collect();
let mut orphans: Vec<String> = on_disk
.iter()
.filter(|path| !tracked.contains(path.as_str()))
.cloned()
.collect();
orphans.sort();
orphans.dedup();
orphans
}
#[cfg(test)]
mod tests {
use super::*;
use crate::AudioFormat;
use crate::manifest::{ArtifactState, ManifestEntry};
fn entry(path: &str) -> ManifestEntry {
ManifestEntry {
path: path.to_owned(),
format: AudioFormat::Flac,
..Default::default()
}
}
#[test]
fn lists_audio_not_in_any_tracked_path() {
let mut manifest = Manifest::new();
manifest.insert("a", entry("Artist/Album/a.flac"));
let on_disk = vec![
"Artist/Album/a.flac".to_owned(),
"Moved/somewhere else.flac".to_owned(),
];
assert_eq!(
untracked_audio(&manifest, &on_disk),
vec!["Moved/somewhere else.flac".to_owned()]
);
}
#[test]
fn excludes_tracked_audio_and_stems() {
let mut manifest = Manifest::new();
let mut e = entry("a.flac");
e.stems.insert(
"voc".to_owned(),
ArtifactState {
path: "a.stems/voc.wav".to_owned(),
hash: "h".to_owned(),
},
);
manifest.insert("a", e);
let on_disk = vec!["a.flac".to_owned(), "a.stems/voc.wav".to_owned()];
assert!(untracked_audio(&manifest, &on_disk).is_empty());
}
#[test]
fn empty_when_every_file_is_tracked() {
let mut manifest = Manifest::new();
manifest.insert("a", entry("a.flac"));
manifest.insert("b", entry("b.mp3"));
let on_disk = vec!["a.flac".to_owned(), "b.mp3".to_owned()];
assert!(untracked_audio(&manifest, &on_disk).is_empty());
}
#[test]
fn output_is_sorted_and_deduplicated() {
let manifest = Manifest::new();
let on_disk = vec![
"z.flac".to_owned(),
"a.flac".to_owned(),
"a.flac".to_owned(),
"m.mp3".to_owned(),
];
assert_eq!(
untracked_audio(&manifest, &on_disk),
vec!["a.flac".to_owned(), "m.mp3".to_owned(), "z.flac".to_owned()]
);
}
#[test]
fn empty_manifest_reports_all_on_disk_audio() {
let manifest = Manifest::new();
assert!(untracked_audio(&manifest, &[]).is_empty());
assert_eq!(
untracked_audio(&manifest, &["only.flac".to_owned()]),
vec!["only.flac".to_owned()]
);
}
}