use std::path::PathBuf;
use db::{Page, Source, TrackFilter};
use reader::models::{Track, TrackId};
fn unique_db() -> PathBuf {
static SEQ: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
let seq = SEQ.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
let nanos = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_nanos();
let pid = std::process::id();
let dir = std::env::temp_dir().join(format!("kopuz-w-{pid}-{nanos}-{seq}"));
std::fs::create_dir_all(&dir).unwrap();
dir.join("kopuz.db")
}
fn local(path: &str, title: &str) -> Track {
Track {
id: TrackId::Local(PathBuf::from(path)),
cover: None,
album_id: "alb".into(),
title: title.into(),
artist: "Artist".into(),
album: "Album".into(),
duration: 123,
khz: 44100,
bitrate: 900,
track_number: Some(2),
disc_number: Some(1),
musicbrainz_release_id: Some("mbr".into()),
musicbrainz_recording_id: None,
musicbrainz_track_id: None,
playlist_item_id: None,
artists: vec!["Artist".into(), "Feat".into()],
}
}
#[tokio::test]
async fn upsert_then_prune() {
let db_path = unique_db();
let db = db::init(&db_path).await.unwrap();
let a = local("/music/a.flac", "A");
let b = local("/music/b.flac", "B");
let c = local("/other/c.flac", "C");
db.upsert_tracks(&Source::Local, &[a.clone(), b.clone(), c.clone()])
.await
.unwrap();
let filter = TrackFilter::new(Source::Local);
assert_eq!(db.tracks_count(&filter).await.unwrap(), 3);
let mut a2 = a.clone();
a2.title = "A (remastered)".into();
db.upsert_tracks(&Source::Local, &[a2]).await.unwrap();
assert_eq!(db.tracks_count(&filter).await.unwrap(), 3);
let page = db
.tracks_page(
&filter,
Page {
offset: 0,
limit: 10,
},
)
.await
.unwrap();
let got = page.iter().find(|t| t.title.starts_with("A")).unwrap();
assert_eq!(got.title, "A (remastered)");
assert_eq!(got.track_number, Some(2));
assert_eq!(got.musicbrainz_release_id.as_deref(), Some("mbr"));
assert_eq!(got.artists, vec!["Artist".to_string(), "Feat".to_string()]);
assert!(matches!(got.id, TrackId::Local(_)));
let keep = vec!["/music/a.flac".to_string(), "/other/c.flac".to_string()];
db.prune_source(&Source::Local, &keep, &[]).await.unwrap();
assert_eq!(db.tracks_count(&filter).await.unwrap(), 2);
let remaining: Vec<String> = db
.tracks_page(
&filter,
Page {
offset: 0,
limit: 10,
},
)
.await
.unwrap()
.iter()
.filter_map(|t| t.id.local_path().map(|p| p.to_string_lossy().into_owned()))
.collect();
assert!(remaining.contains(&"/music/a.flac".to_string()));
assert!(remaining.contains(&"/other/c.flac".to_string()));
assert!(!remaining.contains(&"/music/b.flac".to_string()));
let _ = std::fs::remove_dir_all(db_path.parent().unwrap());
}