use rbox::enums::PlaylistType;
use rbox::masterdb::{DjmdPlaylist, DjmdSongPlaylist, MasterDb, MasterPlaylistXml};
use rbox::model_traits::{validate_seq_numbers, TreeSeq};
mod common;
const SECONDS_THRESH: i64 = 10;
#[test]
fn test_open_master_db() -> anyhow::Result<()> {
let db_path = common::setup_master_db_path(6);
let _db = MasterDb::new(db_path.path())?;
Ok(())
}
#[test]
fn test_get_local_usn() -> anyhow::Result<()> {
let db_path = common::setup_master_db_path(6);
let mut db = MasterDb::new(db_path.path())?;
let usn = db.get_local_usn()?;
assert!(usn > 0);
Ok(())
}
#[test]
fn test_get_albums() -> anyhow::Result<()> {
let db_path = common::setup_master_db_path(6);
let mut db = MasterDb::new(db_path.path())?;
let _album = db.get_albums()?;
Ok(())
}
#[test]
fn test_get_album_by_id() -> anyhow::Result<()> {
let db_path = common::setup_master_db_path(6);
let mut db = MasterDb::new(db_path.path())?;
let album = db.get_album_by_id("1234")?;
assert!(album.is_none());
Ok(())
}
#[test]
fn test_get_album_by_name() -> anyhow::Result<()> {
let db_path = common::setup_master_db_path(6);
let mut db = MasterDb::new(db_path.path())?;
let name = "Name".to_string();
let item = db.get_album_by_name("Name")?;
assert!(item.is_none());
db.create_album(name, None, None, None)?;
let item = db.get_album_by_name("Name")?;
assert!(item.is_some());
Ok(())
}
#[test]
fn test_create_album() -> anyhow::Result<()> {
let db_path = common::setup_master_db_path(6);
let mut db = MasterDb::new(db_path.path())?;
let old_usn = db.get_local_usn()?;
let name = "New Album".to_string();
let artist = None;
let image_path = None;
let compilation = None;
let new_album = db.create_album(name.clone(), artist, image_path, compilation)?;
let new_usn = db.get_local_usn()?;
assert_eq!(new_album.name, name);
assert_eq!(new_usn, old_usn + 1);
assert_eq!(new_album.rb_local_usn.unwrap(), new_usn);
let album = db.get_album_by_id(new_album.id.as_str())?;
assert!(album.is_some());
Ok(())
}
#[test]
fn test_update_album() -> anyhow::Result<()> {
let db_path = common::setup_master_db_path(6);
let mut db = MasterDb::new(db_path.path())?;
let mut album = db.create_album("New Album".to_string(), None, None, None)?;
let old_usn = db.get_local_usn()?;
let id = album.id.clone();
let new_name = "Updated Album".to_string();
album.name = new_name.clone();
let updated = db.update_album(&mut album);
let new_usn = db.get_local_usn()?;
assert!(updated.is_ok());
assert_eq!(new_usn, old_usn + 1);
assert_eq!(updated?.rb_local_usn.unwrap(), new_usn);
let updated_album = db.get_album_by_id(id.as_str())?;
assert!(updated_album.is_some());
assert_eq!(updated_album.unwrap().name, new_name);
Ok(())
}
#[test]
fn test_delete_album() -> anyhow::Result<()> {
let db_path = common::setup_master_db_path(6);
let mut db = MasterDb::new(db_path.path())?;
let album = db.create_album("New Album".to_string(), None, None, None)?;
let contents = db.get_contents()?;
let cid = contents[0].id.clone();
let mut content = db
.get_content_by_id(cid.as_str())?
.expect("get content failed");
content.album_id = Some(album.id.clone());
db.update_content(&content)?;
let linked_content = db.get_content_by_id(cid.as_str())?;
assert_eq!(linked_content.unwrap().album_id, Some(album.id.clone()));
let old_usn = db.get_local_usn()?;
let id = album.id.clone();
let deleted = db.delete_album(id.as_str());
let new_usn = db.get_local_usn()?;
assert!(deleted.is_ok());
assert_eq!(new_usn, old_usn + 1);
let deleted_album = db.get_album_by_id(id.as_str())?;
assert!(deleted_album.is_none());
let orphaned_content = db.get_content_by_id(cid.as_str())?;
assert!(orphaned_content.is_some());
assert!(orphaned_content.unwrap().album_id.is_none());
Ok(())
}
#[test]
fn test_get_artist() -> anyhow::Result<()> {
let db_path = common::setup_master_db_path(6);
let mut db = MasterDb::new(db_path.path())?;
let _items = db.get_artists()?;
Ok(())
}
#[test]
fn test_get_artist_by_id() -> anyhow::Result<()> {
let db_path = common::setup_master_db_path(6);
let mut db = MasterDb::new(db_path.path())?;
let item = db.get_artist_by_id("1234")?;
assert!(item.is_none());
let items = db.get_artists()?;
let artist = items[0].id.clone();
let item = db.get_artist_by_id(artist.as_str())?;
assert!(item.is_some());
Ok(())
}
#[test]
fn test_get_artist_by_name() -> anyhow::Result<()> {
let db_path = common::setup_master_db_path(6);
let mut db = MasterDb::new(db_path.path())?;
let name = "Name".to_string();
let item = db.get_artist_by_name("Name")?;
assert!(item.is_none());
db.create_artist(name)?;
let item = db.get_artist_by_name("Name")?;
assert!(item.is_some());
Ok(())
}
#[test]
fn test_create_artist() -> anyhow::Result<()> {
let db_path = common::setup_master_db_path(6);
let mut db = MasterDb::new(db_path.path())?;
let old_usn = db.get_local_usn()?;
let name = "New Artist".to_string();
let new_item = db.create_artist(name.clone())?;
let new_usn = db.get_local_usn()?;
assert_eq!(new_item.name, name);
assert_eq!(new_usn, old_usn + 1);
assert_eq!(new_item.rb_local_usn.unwrap(), new_usn);
let item = db.get_artist_by_id(new_item.id.as_str())?;
assert!(item.is_some());
Ok(())
}
#[test]
fn test_update_artist() -> anyhow::Result<()> {
let db_path = common::setup_master_db_path(6);
let mut db = MasterDb::new(db_path.path())?;
let mut item = db.create_artist("New Artist".to_string())?;
let old_usn = db.get_local_usn()?;
let id = item.id.clone();
let new_name = "Updated Artist".to_string();
item.name = new_name.clone();
let updated = db.update_artist(&mut item);
let new_usn = db.get_local_usn()?;
assert!(updated.is_ok());
assert_eq!(new_usn, old_usn + 1);
assert_eq!(updated?.rb_local_usn.unwrap(), new_usn);
let updated_item = db.get_artist_by_id(id.as_str())?;
assert!(updated_item.is_some());
assert_eq!(updated_item.unwrap().name, new_name);
Ok(())
}
#[test]
fn test_delete_artist() -> anyhow::Result<()> {
let db_path = common::setup_master_db_path(6);
let mut db = MasterDb::new(db_path.path())?;
let item = db.create_artist("New Artist".to_string())?;
let contents = db.get_contents()?;
let cid = contents[0].id.clone();
let mut content = db
.get_content_by_id(cid.as_str())?
.expect("get content failed");
content.artist_id = Some(item.id.clone());
content.org_artist_id = Some(item.id.clone());
db.update_content(&content)?;
let linked_content = db.get_content_by_id(cid.as_str())?;
assert_eq!(linked_content.unwrap().artist_id, Some(item.id.clone()));
let old_usn = db.get_local_usn()?;
let id = item.id.clone();
let deleted = db.delete_artist(id.as_str());
let new_usn = db.get_local_usn()?;
assert!(deleted.is_ok(), "delete failed: {:?}", deleted);
assert_eq!(new_usn, old_usn + 1);
let deleted_album = db.get_artist_by_id(id.as_str())?;
assert!(deleted_album.is_none());
let orphaned_content = db.get_content_by_id(cid.as_str())?;
assert!(orphaned_content.is_some());
let orphaned = orphaned_content.clone().unwrap();
assert!(orphaned.artist_id.is_none());
assert!(orphaned.org_artist_id.is_none());
Ok(())
}
#[test]
fn test_get_content() -> anyhow::Result<()> {
let db_path = common::setup_master_db_path(6);
let mut db = MasterDb::new(db_path.path())?;
let _items = db.get_contents()?;
Ok(())
}
#[test]
fn test_get_content_by_id() -> anyhow::Result<()> {
let db_path = common::setup_master_db_path(6);
let mut db = MasterDb::new(db_path.path())?;
let item = db.get_content_by_id("1234")?;
assert!(item.is_none());
let items = db.get_contents()?;
let reference = items[0].id.clone();
let item = db.get_content_by_id(reference.as_str())?;
assert!(item.is_some());
Ok(())
}
#[test]
fn test_get_content_by_path() -> anyhow::Result<()> {
let db_path = common::setup_master_db_path(6);
let mut db = MasterDb::new(db_path.path())?;
let item = db.get_content_by_path("invalid/path")?;
assert!(item.is_none());
let items = db.get_contents()?;
let reference = items[0].folder_path.clone().expect("No folder path");
let item = db.get_content_by_path(reference.as_str())?;
assert!(item.is_some());
Ok(())
}
#[test]
fn test_get_genre() -> anyhow::Result<()> {
let db_path = common::setup_master_db_path(6);
let mut db = MasterDb::new(db_path.path())?;
let _items = db.get_genres()?;
Ok(())
}
#[test]
fn test_get_genre_by_id() -> anyhow::Result<()> {
let db_path = common::setup_master_db_path(6);
let mut db = MasterDb::new(db_path.path())?;
let item = db.get_genre_by_id("1234")?;
assert!(item.is_none());
Ok(())
}
#[test]
fn test_get_genre_by_name() -> anyhow::Result<()> {
let db_path = common::setup_master_db_path(6);
let mut db = MasterDb::new(db_path.path())?;
let name = "Name".to_string();
let item = db.get_genre_by_name("Name")?;
assert!(item.is_none());
db.create_genre(name)?;
let item = db.get_genre_by_name("Name")?;
assert!(item.is_some());
Ok(())
}
#[test]
fn test_create_genre() -> anyhow::Result<()> {
let db_path = common::setup_master_db_path(6);
let mut db = MasterDb::new(db_path.path())?;
let old_usn = db.get_local_usn()?;
let name = "New Genre".to_string();
let new_item = db.create_genre(name.clone())?;
let new_usn = db.get_local_usn()?;
assert_eq!(new_item.name, name);
assert_eq!(new_usn, old_usn + 1);
assert_eq!(new_item.rb_local_usn.unwrap(), new_usn);
let item = db.get_genre_by_id(new_item.id.as_str())?;
assert!(item.is_some());
Ok(())
}
#[test]
fn test_update_genre() -> anyhow::Result<()> {
let db_path = common::setup_master_db_path(6);
let mut db = MasterDb::new(db_path.path())?;
let mut item = db.create_genre("New Genre".to_string())?;
let old_usn = db.get_local_usn()?;
let id = item.id.clone();
let new_name = "Updated Genre".to_string();
item.name = new_name.clone();
let updated = db.update_genre(&mut item);
let new_usn = db.get_local_usn()?;
assert!(updated.is_ok());
assert_eq!(new_usn, old_usn + 1);
assert_eq!(updated?.rb_local_usn.unwrap(), new_usn);
let updated_item = db.get_genre_by_id(id.as_str())?;
assert!(updated_item.is_some());
assert_eq!(updated_item.unwrap().name, new_name);
Ok(())
}
#[test]
fn test_delete_genre() -> anyhow::Result<()> {
let db_path = common::setup_master_db_path(6);
let mut db = MasterDb::new(db_path.path())?;
let item = db.create_genre("New Genre".to_string())?;
let contents = db.get_contents()?;
let cid = contents[0].id.clone();
let mut content = db
.get_content_by_id(cid.as_str())?
.expect("get content failed");
content.genre_id = Some(item.id.clone());
db.update_content(&content)?;
let linked_content = db.get_content_by_id(cid.as_str())?;
assert_eq!(linked_content.unwrap().genre_id, Some(item.id.clone()));
let old_usn = db.get_local_usn()?;
let id = item.id.clone();
let deleted = db.delete_genre(id.as_str());
let new_usn = db.get_local_usn()?;
assert!(deleted.is_ok());
assert_eq!(new_usn, old_usn + 1);
let deleted = db.get_genre_by_id(id.as_str())?;
assert!(deleted.is_none());
let orphaned_content = db.get_content_by_id(cid.as_str())?;
assert!(orphaned_content.is_some());
let orphaned = orphaned_content.clone().unwrap();
assert!(orphaned.genre_id.is_none());
Ok(())
}
#[test]
fn test_get_key() -> anyhow::Result<()> {
let db_path = common::setup_master_db_path(6);
let mut db = MasterDb::new(db_path.path())?;
let _items = db.get_keys()?;
Ok(())
}
#[test]
fn test_get_key_by_id() -> anyhow::Result<()> {
let db_path = common::setup_master_db_path(6);
let mut db = MasterDb::new(db_path.path())?;
let item = db.get_key_by_id("1234")?;
assert!(item.is_none());
Ok(())
}
#[test]
fn test_get_key_by_name() -> anyhow::Result<()> {
let db_path = common::setup_master_db_path(6);
let mut db = MasterDb::new(db_path.path())?;
let name = "Name".to_string();
let item = db.get_key_by_name("Name")?;
assert!(item.is_none());
db.create_key(name)?;
let item = db.get_key_by_name("Name")?;
assert!(item.is_some());
Ok(())
}
#[test]
fn test_create_key() -> anyhow::Result<()> {
let db_path = common::setup_master_db_path(6);
let mut db = MasterDb::new(db_path.path())?;
let old_usn = db.get_local_usn()?;
let name = "New Key".to_string();
let new_item = db.create_key(name.clone())?;
let new_usn = db.get_local_usn()?;
assert_eq!(new_item.name, name);
assert_eq!(new_usn, old_usn + 1);
assert_eq!(new_item.rb_local_usn.unwrap(), new_usn);
let item = db.get_key_by_id(new_item.id.as_str())?;
assert!(item.is_some());
Ok(())
}
#[test]
fn test_update_key() -> anyhow::Result<()> {
let db_path = common::setup_master_db_path(6);
let mut db = MasterDb::new(db_path.path())?;
let mut item = db.create_key("New Key".to_string())?;
let old_usn = db.get_local_usn()?;
let id = item.id.clone();
let new_name = "Updated Key".to_string();
item.name = new_name.clone();
let updated = db.update_key(&mut item);
let new_usn = db.get_local_usn()?;
assert!(updated.is_ok());
assert_eq!(new_usn, old_usn + 1);
assert_eq!(updated?.rb_local_usn.unwrap(), new_usn);
let updated_item = db.get_key_by_id(id.as_str())?;
assert!(updated_item.is_some());
assert_eq!(updated_item.unwrap().name, new_name);
Ok(())
}
#[test]
fn test_delete_key() -> anyhow::Result<()> {
let db_path = common::setup_master_db_path(6);
let mut db = MasterDb::new(db_path.path())?;
let item = db.create_key("New Key".to_string())?;
let contents = db.get_contents()?;
let cid = contents[0].id.clone();
let mut content = db
.get_content_by_id(cid.as_str())?
.expect("get content failed");
content.key_id = Some(item.id.clone());
db.update_content(&content)?;
let linked_content = db.get_content_by_id(cid.as_str())?;
assert_eq!(linked_content.unwrap().key_id, Some(item.id.clone()));
let old_usn = db.get_local_usn()?;
let id = item.id.clone();
let deleted = db.delete_key(id.as_str());
let new_usn = db.get_local_usn()?;
assert!(deleted.is_ok());
assert_eq!(new_usn, old_usn + 1);
let deleted = db.get_key_by_id(id.as_str())?;
assert!(deleted.is_none());
let orphaned_content = db.get_content_by_id(cid.as_str())?;
assert!(orphaned_content.is_some());
let orphaned = orphaned_content.clone().unwrap();
assert!(orphaned.key_id.is_none());
Ok(())
}
#[test]
fn test_get_label() -> anyhow::Result<()> {
let db_path = common::setup_master_db_path(6);
let mut db = MasterDb::new(db_path.path())?;
let _items = db.get_labels()?;
Ok(())
}
#[test]
fn test_get_label_by_id() -> anyhow::Result<()> {
let db_path = common::setup_master_db_path(6);
let mut db = MasterDb::new(db_path.path())?;
let item = db.get_label_by_id("1234")?;
assert!(item.is_none());
Ok(())
}
#[test]
fn test_get_label_by_name() -> anyhow::Result<()> {
let db_path = common::setup_master_db_path(6);
let mut db = MasterDb::new(db_path.path())?;
let name = "Name".to_string();
let item = db.get_label_by_name("Name")?;
assert!(item.is_none());
db.create_label(name)?;
let item = db.get_label_by_name("Name")?;
assert!(item.is_some());
Ok(())
}
#[test]
fn test_create_label() -> anyhow::Result<()> {
let db_path = common::setup_master_db_path(6);
let mut db = MasterDb::new(db_path.path())?;
let old_usn = db.get_local_usn()?;
let name = "New Label".to_string();
let new_item = db.create_label(name.clone())?;
let new_usn = db.get_local_usn()?;
assert_eq!(new_item.name, name);
assert_eq!(new_usn, old_usn + 1);
assert_eq!(new_item.rb_local_usn.unwrap(), new_usn);
let item = db.get_label_by_id(new_item.id.as_str())?;
assert!(item.is_some());
Ok(())
}
#[test]
fn test_update_label() -> anyhow::Result<()> {
let db_path = common::setup_master_db_path(6);
let mut db = MasterDb::new(db_path.path())?;
let mut item = db.create_label("New Label".to_string())?;
let old_usn = db.get_local_usn()?;
let id = item.id.clone();
let new_name = "Updated Label".to_string();
item.name = new_name.clone();
let updated = db.update_label(&mut item);
let new_usn = db.get_local_usn()?;
assert!(updated.is_ok());
assert_eq!(new_usn, old_usn + 1);
assert_eq!(updated?.rb_local_usn.unwrap(), new_usn);
let updated_item = db.get_label_by_id(id.as_str())?;
assert!(updated_item.is_some());
assert_eq!(updated_item.unwrap().name, new_name);
Ok(())
}
#[test]
fn test_delete_label() -> anyhow::Result<()> {
let db_path = common::setup_master_db_path(6);
let mut db = MasterDb::new(db_path.path())?;
let item = db.create_label("New Label".to_string())?;
let contents = db.get_contents()?;
let cid = contents[0].id.clone();
let mut content = db
.get_content_by_id(cid.as_str())?
.expect("get content failed");
content.label_id = Some(item.id.clone());
db.update_content(&content)?;
let linked_content = db.get_content_by_id(cid.as_str())?;
assert_eq!(linked_content.unwrap().label_id, Some(item.id.clone()));
let old_usn = db.get_local_usn()?;
let id = item.id.clone();
let deleted = db.delete_label(id.as_str());
let new_usn = db.get_local_usn()?;
assert!(deleted.is_ok());
assert_eq!(new_usn, old_usn + 1);
let deleted = db.get_label_by_id(id.as_str())?;
assert!(deleted.is_none());
let orphaned_content = db.get_content_by_id(cid.as_str())?;
assert!(orphaned_content.is_some());
let orphaned = orphaned_content.clone().unwrap();
assert!(orphaned.label_id.is_none());
Ok(())
}
fn assert_playlist_seq(items: Vec<DjmdPlaylist>) {
let seq_nums = items.iter().map(|item| item.seq).collect::<Vec<i32>>();
assert!(
validate_seq_numbers(&seq_nums, 1),
"Seq number mismatch: {seq_nums:?}"
);
}
fn assert_all_playlist_seqs(db: &mut MasterDb) -> anyhow::Result<()> {
let playlists = db.get_playlists()?;
let mut conn = db.pool.get()?;
for playlist in playlists {
let kind: PlaylistType = playlist.attribute.try_into().unwrap();
if kind != PlaylistType::Folder {
continue;
}
let is_ok = DjmdPlaylist::validate_seq_numbers(&mut conn, &playlist.id)?;
assert!(
is_ok,
"Seq number validation failed for playlist {}",
playlist.id
);
}
Ok(())
}
fn assert_playlist_song_seq(items: Vec<DjmdSongPlaylist>) {
let seq_nums = items.iter().map(|item| item.track_no).collect::<Vec<i32>>();
let n = items.len() as i32;
for i in 0..n {
let item = &items[i as usize];
assert_eq!(item.track_no, i + 1, "Seq number mismatch: {seq_nums:?}");
}
}
fn check_playlist_xml(db: &mut MasterDb) -> anyhow::Result<bool> {
let xml = MasterPlaylistXml::load(db.playlist_xml_path().unwrap());
for playlist in db.get_playlists()? {
let playlist_xml = xml.get_playlist(playlist.id.clone());
if let Some(playlist_xml) = playlist_xml {
if playlist.id != "100000" {
let ts = playlist_xml.timestamp;
let diff = playlist.updated_at.naive_utc() - ts;
if diff.num_seconds().abs() > SECONDS_THRESH {
eprintln!(
"Difference in timestamps for playlist {}: {} seconds",
playlist.id,
diff.num_seconds()
);
return Ok(false);
}
if playlist_xml.parent_id != playlist.parent_id {
eprintln!("Parent ID mismatch for playlist {}", playlist.id);
return Ok(false);
}
}
} else {
eprintln!("Playlist {} not found in XML", playlist.id);
return Ok(false);
}
}
for playlist_xml in xml.get_playlists() {
let id = &playlist_xml.id;
let item = db.get_playlist_by_id(id)?;
if item.is_none() {
eprintln!("Playlist {} found in XML but not in DB", id);
return Ok(false);
}
}
Ok(true)
}
fn assert_playlist_xml(db: &mut MasterDb) {
let res = check_playlist_xml(db).expect("Failed to check playlist XML");
assert!(res);
}
#[test]
fn test_get_playlist() -> anyhow::Result<()> {
let db_path = common::setup_master_db_path(6);
let mut db = MasterDb::new(db_path.path())?;
let _items = db.get_playlists()?;
Ok(())
}
#[test]
fn test_get_playlist_children() -> anyhow::Result<()> {
let db_path = common::setup_master_db_path(6);
let mut db = MasterDb::new(db_path.path())?;
let _items = db.get_playlist_children("root")?;
Ok(())
}
#[test]
fn test_get_playlist_by_id() -> anyhow::Result<()> {
let db_path = common::setup_master_db_path(6);
let mut db = MasterDb::new(db_path.path())?;
let item = db.get_playlist_by_id("1234")?;
assert!(item.is_none());
Ok(())
}
#[test]
fn test_create_playlist() -> anyhow::Result<()> {
let tmp_dir = common::setup_master_db_dir_path(6);
let mut db = MasterDb::new(tmp_dir.path().join("rekordbox").join("master.db"))?;
let old_usn = db.get_local_usn()?;
let name = "Name".to_string();
let attr = PlaylistType::List;
let parent_id = "root".to_string();
let seq = None;
let new_item =
db.create_playlist_node(name.clone(), attr, Some(parent_id.clone()), seq, None, None)?;
let new_usn = db.get_local_usn()?;
assert_eq!(new_item.name, name, "Name mismatch");
assert_eq!(new_item.parent_id, parent_id.clone(), "Parent ID mismatch");
assert_eq!(new_usn, old_usn + 2, "USN mismatch");
assert_eq!(
new_item.rb_local_usn.unwrap(),
new_usn,
"Local USN mismatch"
);
let item_opt = db.get_playlist_by_id(new_item.id.as_str())?;
assert!(item_opt.is_some());
let item = item_opt.unwrap();
let items = db.get_playlist_children(parent_id.as_str())?;
let n = items.len() as i32;
assert_eq!(item.seq, n, "Seq number mismatch");
assert_playlist_seq(items);
assert_playlist_xml(&mut db);
Ok(())
}
#[test]
fn test_create_playlist_seq() -> anyhow::Result<()> {
let tmp_dir = common::setup_master_db_dir_path(6);
let mut db = MasterDb::new(tmp_dir.path().join("rekordbox").join("master.db"))?;
let name = "Name".to_string();
let attr = PlaylistType::List;
let parent_id = "root".to_string();
let seq = 1;
let new_item = db.create_playlist_node(
name.clone(),
attr,
Some(parent_id.clone()),
Some(seq),
None,
None,
)?;
let item = db.get_playlist_by_id(new_item.id.as_str())?;
assert!(item.is_some());
let items = db.get_playlist_children(parent_id.as_str())?;
item.unwrap().seq = seq;
assert_playlist_seq(items);
Ok(())
}
#[test]
fn test_create_playlist_folder() -> anyhow::Result<()> {
let tmp_dir = common::setup_master_db_dir_path(6);
let mut db = MasterDb::new(tmp_dir.path().join("rekordbox").join("master.db"))?;
let old_usn = db.get_local_usn()?;
let name = "Name".to_string();
let attr = PlaylistType::Folder;
let parent_id = "root".to_string();
let seq = None;
let new_item =
db.create_playlist_node(name.clone(), attr, Some(parent_id.clone()), seq, None, None)?;
let new_usn = db.get_local_usn()?;
assert_eq!(new_item.name, name);
assert_eq!(new_item.parent_id, parent_id.clone());
assert_eq!(new_usn, old_usn + 2);
assert_eq!(new_item.rb_local_usn.unwrap(), new_usn);
let item_opt = db.get_playlist_by_id(new_item.id.as_str())?;
assert!(item_opt.is_some());
let item = item_opt.unwrap();
let items = db.get_playlist_children(parent_id.as_str())?;
let n = items.len() as i32;
assert_eq!(item.seq, n);
assert_playlist_seq(items);
assert_playlist_xml(&mut db);
let sub_name = "Name".to_string();
let sub_parent_id = Some(new_item.clone().id);
let sub_item = db.create_playlist_node(
sub_name.clone(),
PlaylistType::List,
sub_parent_id,
None,
None,
None,
)?;
assert_eq!(sub_item.parent_id, new_item.id);
assert_eq!(sub_item.seq, 1);
assert_playlist_xml(&mut db);
Ok(())
}
#[test]
fn test_create_playlist_song() -> anyhow::Result<()> {
let tmp_dir = common::setup_master_db_dir_path(6);
let mut db = MasterDb::new(tmp_dir.path().join("rekordbox").join("master.db"))?;
let pl = db.create_playlist("Playlist".to_string(), None, None, None, None)?;
let contents = db.get_contents()?;
let cid1 = contents[0].id.clone();
let cid2 = contents[1].id.clone();
let cid3 = contents[2].id.clone();
let cid4 = contents[3].id.clone();
let song = db.create_playlist_song(&pl.id, &cid1, None)?;
assert_eq!(song.playlist_id, pl.id.clone());
assert_eq!(song.content_id, cid1.clone());
assert_eq!(song.track_no, 1);
let song = db.create_playlist_song(&pl.id, &cid2, None)?;
assert_eq!(song.playlist_id, pl.id.clone());
assert_eq!(song.content_id, cid2.clone());
assert_eq!(song.track_no, 2);
let song = db.create_playlist_song(&pl.id, &cid3, Some(2))?;
assert_eq!(song.playlist_id, pl.id.clone());
assert_eq!(song.content_id, cid3.clone());
let songs = db.get_playlist_songs(&pl.id)?;
let content_ids: Vec<String> = songs.iter().map(|s| s.content_id.clone()).collect();
assert_eq!(content_ids, vec![cid1, cid3, cid2]);
assert_playlist_xml(&mut db);
let res = db.create_playlist_song(&pl.id, &cid4, Some(0));
assert!(res.is_err(), "Expected error on invalid seq");
let res = db.create_playlist_song(&pl.id, &cid4, Some(5));
assert!(res.is_err(), "Expected error on invalid seq");
Ok(())
}
#[test]
fn test_delete_playlist() -> anyhow::Result<()> {
let tmp_dir = common::setup_master_db_dir_path(6);
let mut db = MasterDb::new(tmp_dir.path().join("rekordbox").join("master.db"))?;
let folder = db.create_playlist_folder("Folder".to_string(), None, None)?;
let pid = Some(folder.id.clone());
let _pl1 = db.create_playlist("Sub 1".to_string(), pid.clone(), None, None, None)?;
let pl2 = db.create_playlist("Sub 2".to_string(), pid.clone(), None, None, None)?;
let pl3 = db.create_playlist("Sub 3".to_string(), pid.clone(), None, None, None)?;
let contents = db.get_contents()?;
let cid1 = contents[0].id.clone();
let cid2 = contents[1].id.clone();
let cid3 = contents[2].id.clone();
let song1 = db.create_playlist_song(&pl3.id, &cid1, None)?;
let song2 = db.create_playlist_song(&pl3.id, &cid2, None)?;
let song3 = db.create_playlist_song(&pl3.id, &cid3, None)?;
let old_usn = db.get_local_usn()?;
let deleted = db.delete_playlist(&pl2.id)?;
assert_eq!(deleted, 1);
let res = db.get_playlist_by_id(&pl2.id)?;
assert!(res.is_none());
let new_usn = db.get_local_usn()?;
assert_eq!(new_usn, old_usn + 1);
let playlists = db.get_playlist_children(folder.id.as_str())?;
assert_playlist_seq(playlists);
assert_playlist_xml(&mut db);
let deleted = db.delete_playlist(&pl3.id)?;
assert_eq!(deleted, 1);
let res = db.get_playlist_song_by_id(&song1.id)?;
assert!(res.is_none());
let res = db.get_playlist_song_by_id(&song2.id)?;
assert!(res.is_none());
let res = db.get_playlist_song_by_id(&song3.id)?;
assert!(res.is_none());
Ok(())
}
#[test]
fn test_delete_playlist_folder() -> anyhow::Result<()> {
let tmp_dir = common::setup_master_db_dir_path(6);
let mut db = MasterDb::new(tmp_dir.path().join("rekordbox").join("master.db"))?;
let folder = db.create_playlist_folder("Folder".to_string(), None, None)?;
let pid = Some(folder.id.clone());
let pl1 = db.create_playlist("Sub 1".to_string(), pid.clone(), None, None, None)?;
let pl2 = db.create_playlist("Sub 2".to_string(), pid.clone(), None, None, None)?;
let pl3 = db.create_playlist("Sub 3".to_string(), pid.clone(), None, None, None)?;
let contents = db.get_contents()?;
let cid1 = contents[0].id.clone();
let cid2 = contents[1].id.clone();
let cid3 = contents[2].id.clone();
let song1 = db.create_playlist_song(&pl3.id, &cid1, None)?;
let song2 = db.create_playlist_song(&pl3.id, &cid2, None)?;
let song3 = db.create_playlist_song(&pl3.id, &cid3, None)?;
let old_usn = db.get_local_usn()?;
let deleted = db.delete_playlist(&folder.id)?;
assert_eq!(deleted, 4);
let new_usn = db.get_local_usn()?;
assert_eq!(new_usn, old_usn + 4);
let res1 = db.get_playlist_by_id(&pl1.id)?;
assert!(res1.is_none());
let res2 = db.get_playlist_by_id(&pl2.id)?;
assert!(res2.is_none());
let res3 = db.get_playlist_by_id(&pl3.id)?;
assert!(res3.is_none());
assert_playlist_xml(&mut db);
let res = db.get_playlist_song_by_id(&song1.id)?;
assert!(res.is_none());
let res = db.get_playlist_song_by_id(&song2.id)?;
assert!(res.is_none());
let res = db.get_playlist_song_by_id(&song3.id)?;
assert!(res.is_none());
Ok(())
}
#[test]
pub fn test_delete_playlist_song() -> anyhow::Result<()> {
let tmp_dir = common::setup_master_db_dir_path(6);
let mut db = MasterDb::new(tmp_dir.path().join("rekordbox").join("master.db"))?;
let pl = db.create_playlist("Playlist".to_string(), None, None, None, None)?;
let contents = db.get_contents()?;
let cid1 = contents[0].id.clone();
let cid2 = contents[1].id.clone();
let cid3 = contents[2].id.clone();
let song1 = db.create_playlist_song(&pl.id, &cid1, None)?;
let song2 = db.create_playlist_song(&pl.id, &cid2, None)?;
let song3 = db.create_playlist_song(&pl.id, &cid3, None)?;
let old_usn = db.get_local_usn()?;
let deleted = db.delete_playlist_song(&song2.id)?;
assert_eq!(deleted, 1);
let res = db.get_playlist_song_by_id(&song2.id)?;
assert!(res.is_none());
let res = db.get_playlist_song_by_id(&song1.id)?;
assert!(res.is_some());
let res = db.get_playlist_song_by_id(&song3.id)?;
assert!(res.is_some());
let new_usn = db.get_local_usn()?;
assert_eq!(new_usn, old_usn + 1);
let songs = db.get_playlist_songs(&pl.id)?;
assert_playlist_song_seq(songs);
assert_playlist_xml(&mut db);
Ok(())
}
#[test]
pub fn test_move_playlist_seq() -> anyhow::Result<()> {
let tmp_dir = common::setup_master_db_dir_path(6);
let mut db = MasterDb::new(tmp_dir.path().join("rekordbox").join("master.db"))?;
let root = db.create_playlist_folder("folder".into(), None, None)?;
let f1 = db.create_playlist_folder("f1".into(), Some(root.id.clone()), None)?;
let _f2 = db.create_playlist_folder("f2".into(), Some(root.id.clone()), None)?;
let p1 = db.create_playlist("pl1".into(), Some(root.id.clone()), None, None, None)?;
let p2 = db.create_playlist("pl2".into(), Some(root.id.clone()), None, None, None)?;
let p3 = db.create_playlist("pl3".into(), Some(root.id.clone()), None, None, None)?;
let _p4 = db.create_playlist("pl4".into(), Some(root.id.clone()), None, None, None)?;
let _p5 = db.create_playlist("subpl1".into(), Some(f1.id.clone()), None, None, None)?;
let _p6 = db.create_playlist("subpl2".into(), Some(f1.id.clone()), None, None, None)?;
let _p7 = db.create_playlist("subpl3".into(), Some(f1.id.clone()), None, None, None)?;
let _p8 = db.create_playlist("subpl4".into(), Some(f1.id.clone()), None, None, None)?;
let children = db.get_playlist_children(&root.id)?;
let names: Vec<String> = children.iter().map(|p| p.name.clone()).collect();
assert_eq!(names, vec!["f1", "f2", "pl1", "pl2", "pl3", "pl4"]);
db.move_playlist(&p1.id, Some(5), None)?;
let children = db.get_playlist_children(&root.id)?;
let names: Vec<String> = children.iter().map(|p| p.name.clone()).collect();
assert_eq!(names, vec!["f1", "f2", "pl2", "pl3", "pl1", "pl4"]);
assert_playlist_seq(children);
db.move_playlist(&p2.id, Some(6), None)?;
let children = db.get_playlist_children(&root.id)?;
let names: Vec<String> = children.iter().map(|p| p.name.clone()).collect();
assert_eq!(names, vec!["f1", "f2", "pl3", "pl1", "pl4", "pl2"]);
assert_playlist_seq(children);
db.move_playlist(&p3.id, Some(2), None)?;
let children = db.get_playlist_children(&root.id)?;
let names: Vec<String> = children.iter().map(|p| p.name.clone()).collect();
assert_eq!(names, vec!["f1", "pl3", "f2", "pl1", "pl4", "pl2"]);
assert_playlist_seq(children);
db.move_playlist(&p1.id, Some(1), None)?;
let children = db.get_playlist_children(&root.id)?;
let names: Vec<String> = children.iter().map(|p| p.name.clone()).collect();
assert_eq!(names, vec!["pl1", "f1", "pl3", "f2", "pl4", "pl2"]);
assert_playlist_seq(children);
let res = db.move_playlist(&p2.id, Some(0), None);
assert!(res.is_err());
let res = db.move_playlist(&p2.id, Some(7), None);
assert!(res.is_err());
assert_playlist_xml(&mut db);
Ok(())
}
#[test]
pub fn test_move_playlist_parent() -> anyhow::Result<()> {
let tmp_dir = common::setup_master_db_dir_path(6);
let mut db = MasterDb::new(tmp_dir.path().join("rekordbox").join("master.db"))?;
let root = db.create_playlist_folder("folder".into(), None, None)?;
let f1 = db.create_playlist_folder("f1".into(), Some(root.id.clone()), None)?;
let _f2 = db.create_playlist_folder("f2".into(), Some(root.id.clone()), None)?;
let p1 = db.create_playlist("pl1".into(), Some(root.id.clone()), None, None, None)?;
let p2 = db.create_playlist("pl2".into(), Some(root.id.clone()), None, None, None)?;
let p3 = db.create_playlist("pl3".into(), Some(root.id.clone()), None, None, None)?;
let p4 = db.create_playlist("pl4".into(), Some(root.id.clone()), None, None, None)?;
let _p5 = db.create_playlist("subpl1".into(), Some(f1.id.clone()), None, None, None)?;
let _p6 = db.create_playlist("subpl2".into(), Some(f1.id.clone()), None, None, None)?;
let _p7 = db.create_playlist("subpl3".into(), Some(f1.id.clone()), None, None, None)?;
let _p8 = db.create_playlist("subpl4".into(), Some(f1.id.clone()), None, None, None)?;
let children = db.get_playlist_children(&root.id)?;
let names: Vec<String> = children.iter().map(|p| p.name.clone()).collect();
assert_eq!(names, vec!["f1", "f2", "pl1", "pl2", "pl3", "pl4"]);
let children = db.get_playlist_children(&f1.id)?;
let names: Vec<String> = children.iter().map(|p| p.name.clone()).collect();
assert_eq!(names, vec!["subpl1", "subpl2", "subpl3", "subpl4"]);
db.move_playlist(&p1.id, None, Some(f1.id.clone()))?;
let children = db.get_playlist_children(&root.id)?;
let names: Vec<String> = children.iter().map(|p| p.name.clone()).collect();
assert_eq!(names, vec!["f1", "f2", "pl2", "pl3", "pl4"]);
assert_playlist_seq(children);
let children = db.get_playlist_children(&f1.id)?;
let names: Vec<String> = children.iter().map(|p| p.name.clone()).collect();
assert_eq!(names, vec!["subpl1", "subpl2", "subpl3", "subpl4", "pl1"]);
assert_playlist_seq(children);
db.move_playlist(&p2.id, Some(3), Some(f1.id.clone()))?;
let children = db.get_playlist_children(&root.id)?;
let names: Vec<String> = children.iter().map(|p| p.name.clone()).collect();
assert_eq!(names, vec!["f1", "f2", "pl3", "pl4"]);
assert_playlist_seq(children);
let children = db.get_playlist_children(&f1.id)?;
let names: Vec<String> = children.iter().map(|p| p.name.clone()).collect();
assert_eq!(
names,
vec!["subpl1", "subpl2", "pl2", "subpl3", "subpl4", "pl1"]
);
assert_playlist_seq(children);
db.move_playlist(&p3.id, Some(1), Some(f1.id.clone()))?;
let children = db.get_playlist_children(&root.id)?;
let names: Vec<String> = children.iter().map(|p| p.name.clone()).collect();
assert_eq!(names, vec!["f1", "f2", "pl4"]);
assert_playlist_seq(children);
let children = db.get_playlist_children(&f1.id)?;
let names: Vec<String> = children.iter().map(|p| p.name.clone()).collect();
assert_eq!(
names,
vec!["pl3", "subpl1", "subpl2", "pl2", "subpl3", "subpl4", "pl1"]
);
assert_playlist_seq(children);
let res = db.move_playlist(&p4.id, None, Some("1234".into()));
assert!(res.is_err(), "invalid parent expected");
let res = db.move_playlist(&p4.id, Some(0), Some(f1.id.clone()));
assert!(res.is_err(), "invalid seq expected: seq=0");
let count = db.get_playlist_children(&f1.id)?.len();
let res = db.move_playlist(&p4.id, Some(9), Some(f1.id.clone()));
assert!(res.is_err(), "invalid seq expected: seq=9, count={count}");
assert_playlist_xml(&mut db);
Ok(())
}
#[test]
pub fn test_move_all_playlists() -> anyhow::Result<()> {
let tmp_dir = common::setup_master_db_dir_path(6);
let mut db = MasterDb::new(tmp_dir.path().join("rekordbox").join("master.db"))?;
let root = db.create_playlist_folder("folder".into(), None, None)?;
let f1 = db.create_playlist_folder("f1".into(), Some(root.id.clone()), None)?;
let f2 = db.create_playlist_folder("f2".into(), Some(root.id.clone()), None)?;
let p1 = db.create_playlist("pl1".into(), Some(root.id.clone()), None, None, None)?;
let _p2 = db.create_playlist("pl2".into(), Some(root.id.clone()), None, None, None)?;
let p3 = db.create_playlist("pl3".into(), Some(root.id.clone()), None, None, None)?;
let _p4 = db.create_playlist("pl4".into(), Some(root.id.clone()), None, None, None)?;
let _p5 = db.create_playlist("subpl1".into(), Some(f1.id.clone()), None, None, None)?;
let p6 = db.create_playlist("subpl2".into(), Some(f1.id.clone()), None, None, None)?;
let p7 = db.create_playlist("subpl3".into(), Some(f1.id.clone()), None, None, None)?;
let _p8 = db.create_playlist("subpl4".into(), Some(f1.id.clone()), None, None, None)?;
assert_all_playlist_seqs(&mut db)?;
let ids = vec![
p1.id.as_str(),
p3.id.as_str(),
p6.id.as_str(),
p7.id.as_str(),
];
db.move_playlists(ids, f2.id.as_str(), None)?;
assert_all_playlist_seqs(&mut db)?;
assert_playlist_xml(&mut db);
Ok(())
}
#[test]
pub fn test_move_playlist_song() -> anyhow::Result<()> {
let tmp_dir = common::setup_master_db_dir_path(6);
let mut db = MasterDb::new(tmp_dir.path().join("rekordbox").join("master.db"))?;
let pl = db.create_playlist("Playlist".to_string(), None, None, None, None)?;
let contents = db.get_contents()?;
let cid1 = contents[0].id.clone();
let cid2 = contents[1].id.clone();
let cid3 = contents[2].id.clone();
let cid4 = contents[3].id.clone();
let cid5 = contents[4].id.clone();
let song1 = db.create_playlist_song(&pl.id, &cid1, None)?;
let song2 = db.create_playlist_song(&pl.id, &cid2, None)?;
let song3 = db.create_playlist_song(&pl.id, &cid3, None)?;
let song4 = db.create_playlist_song(&pl.id, &cid4, None)?;
let song5 = db.create_playlist_song(&pl.id, &cid5, None)?;
let sid1 = song1.id.clone();
let sid2 = song2.id.clone();
let sid3 = song3.id.clone();
let sid4 = song4.id.clone();
let sid5 = song5.id.clone();
let songs = db.get_playlist_songs(&pl.id)?;
let song_ids: Vec<String> = songs.iter().map(|s| s.id.clone()).collect();
assert_eq!(
song_ids,
vec![
sid1.clone(),
sid2.clone(),
sid3.clone(),
sid4.clone(),
sid5.clone()
]
);
assert_playlist_song_seq(songs);
db.move_playlist_song(&song4.id, 2)?;
let songs = db.get_playlist_songs(&pl.id)?;
let song_ids: Vec<String> = songs.iter().map(|s| s.id.clone()).collect();
assert_eq!(
song_ids,
vec![
sid1.clone(),
sid4.clone(),
sid2.clone(),
sid3.clone(),
sid5.clone()
]
);
assert_playlist_song_seq(songs);
db.move_playlist_song(&song4.id, 4)?;
let songs = db.get_playlist_songs(&pl.id)?;
let song_ids: Vec<String> = songs.iter().map(|s| s.id.clone()).collect();
assert_eq!(
song_ids,
vec![
sid1.clone(),
sid2.clone(),
sid3.clone(),
sid4.clone(),
sid5.clone()
]
);
assert_playlist_song_seq(songs);
db.move_playlist_song(&song2.id, 3)?;
let songs = db.get_playlist_songs(&pl.id)?;
let song_ids: Vec<String> = songs.iter().map(|s| s.id.clone()).collect();
assert_eq!(
song_ids,
vec![
sid1.clone(),
sid3.clone(),
sid2.clone(),
sid4.clone(),
sid5.clone()
]
);
assert_playlist_song_seq(songs);
db.move_playlist_song(&song4.id, 1)?;
let songs = db.get_playlist_songs(&pl.id)?;
let song_ids: Vec<String> = songs.iter().map(|s| s.id.clone()).collect();
assert_eq!(
song_ids,
vec![
sid4.clone(),
sid1.clone(),
sid3.clone(),
sid2.clone(),
sid5.clone()
]
);
assert_playlist_song_seq(songs);
db.move_playlist_song(&song1.id, 5)?;
let songs = db.get_playlist_songs(&pl.id)?;
let song_ids: Vec<String> = songs.iter().map(|s| s.id.clone()).collect();
assert_eq!(
song_ids,
vec![
sid4.clone(),
sid3.clone(),
sid2.clone(),
sid5.clone(),
sid1.clone()
]
);
assert_playlist_song_seq(songs);
let res = db.move_playlist_song(&song2.id, 0);
assert!(res.is_err());
let res = db.move_playlist_song(&song2.id, 6);
assert!(res.is_err());
assert_playlist_xml(&mut db);
Ok(())
}
#[test]
pub fn test_move_all_playlist_songs() -> anyhow::Result<()> {
let tmp_dir = common::setup_master_db_dir_path(6);
let mut db = MasterDb::new(tmp_dir.path().join("rekordbox").join("master.db"))?;
let pl = db.create_playlist("Playlist".to_string(), None, None, None, None)?;
let contents = db.get_contents()?;
let cid1 = contents[0].id.clone();
let cid2 = contents[1].id.clone();
let cid3 = contents[2].id.clone();
let cid4 = contents[3].id.clone();
let cid5 = contents[4].id.clone();
let song1 = db.create_playlist_song(&pl.id, &cid1, None)?;
let song2 = db.create_playlist_song(&pl.id, &cid2, None)?;
let song3 = db.create_playlist_song(&pl.id, &cid3, None)?;
let song4 = db.create_playlist_song(&pl.id, &cid4, None)?;
let song5 = db.create_playlist_song(&pl.id, &cid5, None)?;
let sid1 = song1.id.clone();
let sid2 = song2.id.clone();
let sid3 = song3.id.clone();
let sid4 = song4.id.clone();
let sid5 = song5.id.clone();
let songs = db.get_playlist_songs(&pl.id)?;
let song_ids: Vec<String> = songs.iter().map(|s| s.id.clone()).collect();
assert_eq!(
song_ids,
vec![
sid1.clone(),
sid2.clone(),
sid3.clone(),
sid4.clone(),
sid5.clone()
]
);
assert_playlist_song_seq(songs);
db.move_playlist_songs(vec![&song3.id, &song5.id], 2)?;
let songs = db.get_playlist_songs(&pl.id)?;
let song_ids: Vec<String> = songs.iter().map(|s| s.id.clone()).collect();
assert_eq!(
song_ids,
vec![
sid1.clone(),
sid3.clone(),
sid5.clone(),
sid2.clone(),
sid4.clone(),
]
);
assert_playlist_song_seq(songs);
Ok(())
}
#[test]
fn test_get_related_tracks() -> anyhow::Result<()> {
let db_path = common::setup_master_db_path(6);
let mut db = MasterDb::new(db_path.path())?;
let _items = db.get_related_tracks()?;
let db_path = common::setup_master_db_path(7);
let mut db = MasterDb::new(db_path.path())?;
let _items = db.get_related_tracks()?;
Ok(())
}
#[test]
fn test_get_sampler() -> anyhow::Result<()> {
let db_path = common::setup_master_db_path(6);
let mut db = MasterDb::new(db_path.path())?;
let _items = db.get_samplers()?;
let db_path = common::setup_master_db_path(7);
let mut db = MasterDb::new(db_path.path())?;
let _items = db.get_samplers()?;
Ok(())
}