diff --git a/Cargo.lock b/Cargo.lock index d102cbb..0087624 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -98,12 +98,19 @@ checksum = "cd550e73688e6d578f0ac2119e32b797a327631a42f9433e59d02e139c8df60d" name = "musichoard" version = "0.1.0" dependencies = [ + "once_cell", "serde", "serde_json", "tempfile", "uuid", ] +[[package]] +name = "once_cell" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" + [[package]] name = "proc-macro2" version = "1.0.54" diff --git a/Cargo.toml b/Cargo.toml index 306828f..997b3b1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,4 +11,5 @@ serde_json = "1.0" uuid = { version = "1.3", features = ["serde"] } [dev-dependencies] +once_cell = "1.17" tempfile = "3.5" diff --git a/src/database/json.rs b/src/database/json.rs index e2f7278..a122c12 100644 --- a/src/database/json.rs +++ b/src/database/json.rs @@ -1,7 +1,7 @@ //! Module for storing MusicHoard data in a JSON file database. -use std::fs::{read_to_string, write}; -use std::path::PathBuf; +use std::fs; +use std::path::{PathBuf, Path}; use serde::de::DeserializeOwned; use serde::Serialize; @@ -56,8 +56,8 @@ pub struct DatabaseJsonFile { impl DatabaseJsonFile { /// Create a database instance that will read/write to the provided path. - pub fn new(path: PathBuf) -> Self { - DatabaseJsonFile { path } + pub fn new(path: &Path) -> Self { + DatabaseJsonFile { path: path.to_path_buf() } } } @@ -65,11 +65,11 @@ impl DatabaseJsonBackend for DatabaseJsonFile { fn read(&self) -> Result { // Read entire file to memory as for now this is faster than a buffered read from disk: // https://github.com/serde-rs/json/issues/160 - read_to_string(&self.path) + fs::read_to_string(&self.path) } fn write(&mut self, json: &str) -> Result<(), std::io::Error> { - write(&self.path, json) + fs::write(&self.path, json) } } @@ -77,7 +77,7 @@ impl DatabaseJsonBackend for DatabaseJsonFile { mod tests { use super::*; - use crate::{tests::test_data, Artist}; + use crate::{tests::COLLECTION, Artist}; struct DatabaseJsonTest { json: String, @@ -154,7 +154,7 @@ mod tests { #[test] fn write() { - let write_data = test_data(); + let write_data = COLLECTION.to_owned(); let backend = DatabaseJsonTest { json: artists_to_json(&write_data), }; @@ -166,7 +166,7 @@ mod tests { #[test] fn read() { - let expected = test_data(); + let expected = COLLECTION.to_owned(); let backend = DatabaseJsonTest { json: artists_to_json(&expected), }; @@ -181,13 +181,13 @@ mod tests { #[test] fn reverse() { - let expected = test_data(); + let expected = COLLECTION.to_owned(); let backend = DatabaseJsonTest { json: artists_to_json(&expected), }; let mut database = DatabaseJson::new(Box::new(backend)); - let write_data = test_data(); + let write_data = COLLECTION.to_owned(); let mut read_data: Vec = vec![]; database.write(&write_data).unwrap(); database.read(&mut read_data).unwrap(); diff --git a/src/lib.rs b/src/lib.rs index d471250..62cdb85 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,7 +10,7 @@ pub mod library; pub type Mbid = Uuid; /// A single track on an album. -#[derive(Debug, Deserialize, Serialize, PartialEq, Eq)] +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)] pub struct Track { pub number: u32, pub title: String, @@ -18,27 +18,27 @@ pub struct Track { } /// The album identifier. -#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Clone, Hash)] +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, Hash)] pub struct AlbumId { pub year: u32, pub title: String, } /// An album is a collection of tracks that were released together. -#[derive(Debug, Deserialize, Serialize, PartialEq, Eq)] +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)] pub struct Album { pub id: AlbumId, pub tracks: Vec, } /// The artist identifier. -#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Clone, Hash)] +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, Hash)] pub struct ArtistId { pub name: String, } /// An artist. -#[derive(Debug, Deserialize, Serialize, PartialEq, Eq)] +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)] pub struct Artist { pub id: ArtistId, pub albums: Vec, @@ -48,7 +48,9 @@ pub struct Artist { mod tests { use super::*; - pub fn test_data() -> Vec { + use once_cell::sync::Lazy; + + pub static COLLECTION: Lazy> = Lazy::new(|| { vec![ Artist { id: ArtistId { @@ -128,5 +130,5 @@ mod tests { }], }, ] - } + }); } diff --git a/src/library/beets.rs b/src/library/beets.rs index 1140210..3db39d5 100644 --- a/src/library/beets.rs +++ b/src/library/beets.rs @@ -4,7 +4,7 @@ use std::{ collections::{HashMap, HashSet}, fmt::Display, - process::Command, + process::Command, path::{PathBuf, Path}, }; use crate::{Album, AlbumId, Artist, ArtistId, Track}; @@ -117,7 +117,7 @@ impl Library for Beets { macro_rules! list_format_separator { () => { - "-*^-" + " -*^- " }; } @@ -151,8 +151,11 @@ impl LibraryPrivate for Beets { let mut album_ids = HashMap::>::new(); for line in list_output.iter() { - let split: Vec<&str> = line.split(Self::LIST_FORMAT_SEPARATOR).collect(); + if line.is_empty() { + continue; + } + let split: Vec<&str> = line.split(Self::LIST_FORMAT_SEPARATOR).collect(); if split.len() != 6 { return Err(Error::InvalidData(line.to_string())); } @@ -221,25 +224,32 @@ impl LibraryPrivate for Beets { /// Executor for executing beets commands on the local system. pub struct SystemExecutor { bin: String, + config: Option, } impl SystemExecutor { - pub fn new(bin: &str) -> SystemExecutor { + pub fn new(bin: &str, path: Option<&Path>) -> SystemExecutor { SystemExecutor { bin: bin.to_string(), + config: path.map(|p| p.to_path_buf()), } } } impl Default for SystemExecutor { fn default() -> Self { - SystemExecutor::new("beet") + SystemExecutor::new("beet", None) } } impl BeetsExecutor for SystemExecutor { fn exec(&mut self, arguments: &[String]) -> Result, Error> { - let output = Command::new(&self.bin).args(arguments).output()?; + let mut cmd = Command::new(&self.bin); + if let Some(ref path) = self.config { + cmd.arg("--config"); + cmd.arg(path); + } + let output = cmd.args(arguments).output()?; let output = std::str::from_utf8(&output.stdout)?; Ok(output.split('\n').map(|s| s.to_string()).collect()) } @@ -249,7 +259,7 @@ impl BeetsExecutor for SystemExecutor { mod tests { use super::*; - use crate::tests::test_data; + use crate::tests::COLLECTION; struct TestExecutor { arguments: Option>, @@ -333,7 +343,7 @@ mod tests { #[test] fn test_list_ordered() { - let expected = test_data(); + let expected = COLLECTION.to_owned(); let output = artists_to_beets_string(&expected); let executor = TestExecutor { @@ -348,7 +358,7 @@ mod tests { #[test] fn test_list_unordered() { - let mut expected = test_data(); + let mut expected = COLLECTION.to_owned(); let mut output = artists_to_beets_string(&expected); let last = output.len() - 1; output.swap(0, last); @@ -377,7 +387,7 @@ mod tests { #[test] fn test_list_album_title_year_clash() { - let mut expected = test_data(); + let mut expected = COLLECTION.to_owned(); expected[0].albums[0].id.year = expected[1].albums[0].id.year; expected[0].albums[0].id.title = expected[1].albums[0].id.title.clone(); diff --git a/tests/database/json.rs b/tests/database/json.rs new file mode 100644 index 0000000..b342639 --- /dev/null +++ b/tests/database/json.rs @@ -0,0 +1,56 @@ +use std::fs; + +use musichoard::{database::{ + json::{DatabaseJson, DatabaseJsonFile}, + DatabaseRead, DatabaseWrite, +}, Artist}; +use tempfile::NamedTempFile; + +use crate::COLLECTION; + +#[test] +fn write() { + let file = NamedTempFile::new().unwrap(); + + let backend = DatabaseJsonFile::new(file.path()); + let mut database = DatabaseJson::new(Box::new(backend)); + + let write_data = COLLECTION.to_owned(); + database.write(&write_data).unwrap(); + + let expected_path = fs::canonicalize("./tests/files/database/database.json").unwrap(); + let expected = fs::read_to_string(expected_path).unwrap(); + let actual = fs::read_to_string(file.path()).unwrap(); + + assert_eq!(actual, expected); +} + +#[test] +fn read() { + let file_path = fs::canonicalize("./tests/files/database/database.json").unwrap(); + + let backend = DatabaseJsonFile::new(&file_path); + let database = DatabaseJson::new(Box::new(backend)); + + let mut read_data: Vec = vec![]; + database.read(&mut read_data).unwrap(); + + let expected = COLLECTION.to_owned(); + assert_eq!(read_data, expected); +} + +#[test] +fn reverse() { + let file = NamedTempFile::new().unwrap(); + + let backend = DatabaseJsonFile::new(file.path()); + let mut database = DatabaseJson::new(Box::new(backend)); + + let write_data = COLLECTION.to_owned(); + database.write(&write_data).unwrap(); + + let mut read_data: Vec = vec![]; + database.read(&mut read_data).unwrap(); + + assert_eq!(write_data, read_data); +} diff --git a/tests/database/mod.rs b/tests/database/mod.rs new file mode 100644 index 0000000..cff0e90 --- /dev/null +++ b/tests/database/mod.rs @@ -0,0 +1 @@ +mod json; diff --git a/tests/files/.gitignore b/tests/files/.gitignore new file mode 100644 index 0000000..14d6358 --- /dev/null +++ b/tests/files/.gitignore @@ -0,0 +1 @@ +library diff --git a/tests/files/database/database.json b/tests/files/database/database.json new file mode 100644 index 0000000..e60452c --- /dev/null +++ b/tests/files/database/database.json @@ -0,0 +1 @@ +[{"id":{"name":"Аркона"},"albums":[{"id":{"year":2011,"title":"Slovo"},"tracks":[{"number":1,"title":"Az’","artist":["Аркона"]},{"number":2,"title":"Arkaim","artist":["Аркона"]},{"number":3,"title":"Bol’no mne","artist":["Аркона"]},{"number":4,"title":"Leshiy","artist":["Аркона"]},{"number":5,"title":"Zakliatie","artist":["Аркона"]},{"number":6,"title":"Predok","artist":["Аркона"]},{"number":7,"title":"Nikogda","artist":["Аркона"]},{"number":8,"title":"Tam za tumanami","artist":["Аркона"]},{"number":9,"title":"Potomok","artist":["Аркона"]},{"number":10,"title":"Slovo","artist":["Аркона"]},{"number":11,"title":"Odna","artist":["Аркона"]},{"number":12,"title":"Vo moiom sadochke…","artist":["Аркона"]},{"number":13,"title":"Stenka na stenku","artist":["Аркона"]},{"number":14,"title":"Zimushka","artist":["Аркона"]}]}]},{"id":{"name":"Eluveitie"},"albums":[{"id":{"year":2008,"title":"Slania"},"tracks":[{"number":1,"title":"Samon","artist":["Eluveitie"]},{"number":2,"title":"Primordial Breath","artist":["Eluveitie"]},{"number":3,"title":"Inis Mona","artist":["Eluveitie"]},{"number":4,"title":"Gray Sublime Archon","artist":["Eluveitie"]},{"number":5,"title":"Anagantios","artist":["Eluveitie"]},{"number":6,"title":"Bloodstained Ground","artist":["Eluveitie"]},{"number":7,"title":"The Somber Lay","artist":["Eluveitie"]},{"number":8,"title":"Slanias Song","artist":["Eluveitie"]},{"number":9,"title":"Giamonios","artist":["Eluveitie"]},{"number":10,"title":"Tarvos","artist":["Eluveitie"]},{"number":11,"title":"Calling the Rain","artist":["Eluveitie"]},{"number":12,"title":"Elembivos","artist":["Eluveitie"]}]},{"id":{"year":2004,"title":"Vên [re‐recorded]"},"tracks":[{"number":1,"title":"Verja Urit an Bitus","artist":["Eluveitie"]},{"number":2,"title":"Uis Elveti","artist":["Eluveitie"]},{"number":3,"title":"Ôrô","artist":["Eluveitie"]},{"number":4,"title":"Lament","artist":["Eluveitie"]},{"number":5,"title":"Druid","artist":["Eluveitie"]},{"number":6,"title":"Jêzaïg","artist":["Eluveitie"]}]}]},{"id":{"name":"Frontside"},"albums":[{"id":{"year":2001,"title":"…nasze jest królestwo, potęga i chwała na wieki…"},"tracks":[{"number":1,"title":"Intro = Chaos","artist":["Frontside"]},{"number":2,"title":"Modlitwa","artist":["Frontside"]},{"number":3,"title":"Długa droga z piekła","artist":["Frontside"]},{"number":4,"title":"Synowie ognia","artist":["Frontside"]},{"number":5,"title":"1902","artist":["Frontside"]},{"number":6,"title":"Krew za krew","artist":["Frontside"]},{"number":7,"title":"Kulminacja","artist":["Frontside"]},{"number":8,"title":"Judasz","artist":["Frontside"]},{"number":9,"title":"Więzy","artist":["Frontside"]},{"number":10,"title":"Zagubione dusze","artist":["Frontside"]},{"number":11,"title":"Linia życia","artist":["Frontside"]}]}]},{"id":{"name":"Metallica"},"albums":[{"id":{"year":1984,"title":"Ride the Lightning"},"tracks":[{"number":1,"title":"Fight Fire with Fire","artist":["Metallica"]},{"number":2,"title":"Ride the Lightning","artist":["Metallica"]},{"number":3,"title":"For Whom the Bell Tolls","artist":["Metallica"]},{"number":4,"title":"Fade to Black","artist":["Metallica"]},{"number":5,"title":"Trapped under Ice","artist":["Metallica"]},{"number":6,"title":"Escape","artist":["Metallica"]},{"number":7,"title":"Creeping Death","artist":["Metallica"]},{"number":8,"title":"The Call of Ktulu","artist":["Metallica"]}]},{"id":{"year":1999,"title":"S&M"},"tracks":[{"number":1,"title":"The Ecstasy of Gold","artist":["Metallica"]},{"number":2,"title":"The Call of Ktulu","artist":["Metallica"]},{"number":3,"title":"Master of Puppets","artist":["Metallica"]},{"number":4,"title":"Of Wolf and Man","artist":["Metallica"]},{"number":5,"title":"The Thing That Should Not Be","artist":["Metallica"]},{"number":6,"title":"Fuel","artist":["Metallica"]},{"number":7,"title":"The Memory Remains","artist":["Metallica"]},{"number":8,"title":"No Leaf Clover","artist":["Metallica"]},{"number":9,"title":"Hero of the Day","artist":["Metallica"]},{"number":10,"title":"Devil’s Dance","artist":["Metallica"]},{"number":11,"title":"Bleeding Me","artist":["Metallica"]},{"number":12,"title":"Nothing Else Matters","artist":["Metallica"]},{"number":13,"title":"Until It Sleeps","artist":["Metallica"]},{"number":14,"title":"For Whom the Bell Tolls","artist":["Metallica"]},{"number":15,"title":"−Human","artist":["Metallica"]},{"number":16,"title":"Wherever I May Roam","artist":["Metallica"]},{"number":17,"title":"Outlaw Torn","artist":["Metallica"]},{"number":18,"title":"Sad but True","artist":["Metallica"]},{"number":19,"title":"One","artist":["Metallica"]},{"number":20,"title":"Enter Sandman","artist":["Metallica"]},{"number":21,"title":"Battery","artist":["Metallica"]}]}]}] \ No newline at end of file diff --git a/tests/lib.rs b/tests/lib.rs new file mode 100644 index 0000000..c749926 --- /dev/null +++ b/tests/lib.rs @@ -0,0 +1,442 @@ +mod database; +mod library; + +use musichoard::{Album, AlbumId, Artist, ArtistId, Track}; +use once_cell::sync::Lazy; + +static COLLECTION: Lazy> = Lazy::new(|| { + vec![ + Artist { + id: ArtistId { + name: String::from("Аркона"), + }, + albums: vec![Album { + id: AlbumId { + year: 2011, + title: String::from("Slovo"), + }, + tracks: vec![ + Track { + number: 01, + title: String::from("Az’"), + artist: vec![String::from("Аркона")], + }, + Track { + number: 02, + title: String::from("Arkaim"), + artist: vec![String::from("Аркона")], + }, + Track { + number: 03, + title: String::from("Bol’no mne"), + artist: vec![String::from("Аркона")], + }, + Track { + number: 04, + title: String::from("Leshiy"), + artist: vec![String::from("Аркона")], + }, + Track { + number: 05, + title: String::from("Zakliatie"), + artist: vec![String::from("Аркона")], + }, + Track { + number: 06, + title: String::from("Predok"), + artist: vec![String::from("Аркона")], + }, + Track { + number: 07, + title: String::from("Nikogda"), + artist: vec![String::from("Аркона")], + }, + Track { + number: 08, + title: String::from("Tam za tumanami"), + artist: vec![String::from("Аркона")], + }, + Track { + number: 09, + title: String::from("Potomok"), + artist: vec![String::from("Аркона")], + }, + Track { + number: 10, + title: String::from("Slovo"), + artist: vec![String::from("Аркона")], + }, + Track { + number: 11, + title: String::from("Odna"), + artist: vec![String::from("Аркона")], + }, + Track { + number: 12, + title: String::from("Vo moiom sadochke…"), + artist: vec![String::from("Аркона")], + }, + Track { + number: 13, + title: String::from("Stenka na stenku"), + artist: vec![String::from("Аркона")], + }, + Track { + number: 14, + title: String::from("Zimushka"), + artist: vec![String::from("Аркона")], + }, + ], + }], + }, + Artist { + id: ArtistId { + name: String::from("Eluveitie"), + }, + albums: vec![ + Album { + id: AlbumId { + year: 2008, + title: String::from("Slania"), + }, + tracks: vec![ + Track { + number: 01, + title: String::from("Samon"), + artist: vec![String::from("Eluveitie")], + }, + Track { + number: 02, + title: String::from("Primordial Breath"), + artist: vec![String::from("Eluveitie")], + }, + Track { + number: 03, + title: String::from("Inis Mona"), + artist: vec![String::from("Eluveitie")], + }, + Track { + number: 04, + title: String::from("Gray Sublime Archon"), + artist: vec![String::from("Eluveitie")], + }, + Track { + number: 05, + title: String::from("Anagantios"), + artist: vec![String::from("Eluveitie")], + }, + Track { + number: 06, + title: String::from("Bloodstained Ground"), + artist: vec![String::from("Eluveitie")], + }, + Track { + number: 07, + title: String::from("The Somber Lay"), + artist: vec![String::from("Eluveitie")], + }, + Track { + number: 08, + title: String::from("Slanias Song"), + artist: vec![String::from("Eluveitie")], + }, + Track { + number: 09, + title: String::from("Giamonios"), + artist: vec![String::from("Eluveitie")], + }, + Track { + number: 10, + title: String::from("Tarvos"), + artist: vec![String::from("Eluveitie")], + }, + Track { + number: 11, + title: String::from("Calling the Rain"), + artist: vec![String::from("Eluveitie")], + }, + Track { + number: 12, + title: String::from("Elembivos"), + artist: vec![String::from("Eluveitie")], + }, + ], + }, + Album { + id: AlbumId { + year: 2004, + title: String::from("Vên [re‐recorded]"), + }, + tracks: vec![ + Track { + number: 01, + title: String::from("Verja Urit an Bitus"), + artist: vec![String::from("Eluveitie")], + }, + Track { + number: 02, + title: String::from("Uis Elveti"), + artist: vec![String::from("Eluveitie")], + }, + Track { + number: 03, + title: String::from("Ôrô"), + artist: vec![String::from("Eluveitie")], + }, + Track { + number: 04, + title: String::from("Lament"), + artist: vec![String::from("Eluveitie")], + }, + Track { + number: 05, + title: String::from("Druid"), + artist: vec![String::from("Eluveitie")], + }, + Track { + number: 06, + title: String::from("Jêzaïg"), + artist: vec![String::from("Eluveitie")], + }, + ], + }, + ], + }, + Artist { + id: ArtistId { + name: String::from("Frontside"), + }, + albums: vec![Album { + id: AlbumId { + year: 2001, + title: String::from("…nasze jest królestwo, potęga i chwała na wieki…"), + }, + tracks: vec![ + Track { + number: 01, + title: String::from("Intro = Chaos"), + artist: vec![String::from("Frontside")], + }, + Track { + number: 02, + title: String::from("Modlitwa"), + artist: vec![String::from("Frontside")], + }, + Track { + number: 03, + title: String::from("Długa droga z piekła"), + artist: vec![String::from("Frontside")], + }, + Track { + number: 04, + title: String::from("Synowie ognia"), + artist: vec![String::from("Frontside")], + }, + Track { + number: 05, + title: String::from("1902"), + artist: vec![String::from("Frontside")], + }, + Track { + number: 06, + title: String::from("Krew za krew"), + artist: vec![String::from("Frontside")], + }, + Track { + number: 07, + title: String::from("Kulminacja"), + artist: vec![String::from("Frontside")], + }, + Track { + number: 08, + title: String::from("Judasz"), + artist: vec![String::from("Frontside")], + }, + Track { + number: 09, + title: String::from("Więzy"), + artist: vec![String::from("Frontside")], + }, + Track { + number: 10, + title: String::from("Zagubione dusze"), + artist: vec![String::from("Frontside")], + }, + Track { + number: 11, + title: String::from("Linia życia"), + artist: vec![String::from("Frontside")], + }, + ], + }], + }, + Artist { + id: ArtistId { + name: String::from("Metallica"), + }, + albums: vec![ + Album { + id: AlbumId { + year: 1984, + title: String::from("Ride the Lightning"), + }, + tracks: vec![ + Track { + number: 01, + title: String::from("Fight Fire with Fire"), + artist: vec![String::from("Metallica")], + }, + Track { + number: 02, + title: String::from("Ride the Lightning"), + artist: vec![String::from("Metallica")], + }, + Track { + number: 03, + title: String::from("For Whom the Bell Tolls"), + artist: vec![String::from("Metallica")], + }, + Track { + number: 04, + title: String::from("Fade to Black"), + artist: vec![String::from("Metallica")], + }, + Track { + number: 05, + title: String::from("Trapped under Ice"), + artist: vec![String::from("Metallica")], + }, + Track { + number: 06, + title: String::from("Escape"), + artist: vec![String::from("Metallica")], + }, + Track { + number: 07, + title: String::from("Creeping Death"), + artist: vec![String::from("Metallica")], + }, + Track { + number: 08, + title: String::from("The Call of Ktulu"), + artist: vec![String::from("Metallica")], + }, + ], + }, + Album { + id: AlbumId { + year: 1999, + title: String::from("S&M"), + }, + tracks: vec![ + Track { + number: 01, + title: String::from("The Ecstasy of Gold"), + artist: vec![String::from("Metallica")], + }, + Track { + number: 02, + title: String::from("The Call of Ktulu"), + artist: vec![String::from("Metallica")], + }, + Track { + number: 03, + title: String::from("Master of Puppets"), + artist: vec![String::from("Metallica")], + }, + Track { + number: 04, + title: String::from("Of Wolf and Man"), + artist: vec![String::from("Metallica")], + }, + Track { + number: 05, + title: String::from("The Thing That Should Not Be"), + artist: vec![String::from("Metallica")], + }, + Track { + number: 06, + title: String::from("Fuel"), + artist: vec![String::from("Metallica")], + }, + Track { + number: 07, + title: String::from("The Memory Remains"), + artist: vec![String::from("Metallica")], + }, + Track { + number: 08, + title: String::from("No Leaf Clover"), + artist: vec![String::from("Metallica")], + }, + Track { + number: 09, + title: String::from("Hero of the Day"), + artist: vec![String::from("Metallica")], + }, + Track { + number: 10, + title: String::from("Devil’s Dance"), + artist: vec![String::from("Metallica")], + }, + Track { + number: 11, + title: String::from("Bleeding Me"), + artist: vec![String::from("Metallica")], + }, + Track { + number: 12, + title: String::from("Nothing Else Matters"), + artist: vec![String::from("Metallica")], + }, + Track { + number: 13, + title: String::from("Until It Sleeps"), + artist: vec![String::from("Metallica")], + }, + Track { + number: 14, + title: String::from("For Whom the Bell Tolls"), + artist: vec![String::from("Metallica")], + }, + Track { + number: 15, + title: String::from("−Human"), + artist: vec![String::from("Metallica")], + }, + Track { + number: 16, + title: String::from("Wherever I May Roam"), + artist: vec![String::from("Metallica")], + }, + Track { + number: 17, + title: String::from("Outlaw Torn"), + artist: vec![String::from("Metallica")], + }, + Track { + number: 18, + title: String::from("Sad but True"), + artist: vec![String::from("Metallica")], + }, + Track { + number: 19, + title: String::from("One"), + artist: vec![String::from("Metallica")], + }, + Track { + number: 20, + title: String::from("Enter Sandman"), + artist: vec![String::from("Metallica")], + }, + Track { + number: 21, + title: String::from("Battery"), + artist: vec![String::from("Metallica")], + }, + ], + }, + ], + }, + ] +}); diff --git a/tests/library/beets.rs b/tests/library/beets.rs new file mode 100644 index 0000000..d9aca3e --- /dev/null +++ b/tests/library/beets.rs @@ -0,0 +1,85 @@ +use std::fs; + +use musichoard::{ + library::{ + beets::{Beets, SystemExecutor}, + Library, Query, QueryOption, + }, + Artist, +}; + +use crate::COLLECTION; + +#[test] +fn test_no_config_list() { + let executor = SystemExecutor::new("beet", None); + + let mut beets = Beets::new(Box::new(executor)); + let output = beets.list(&Query::default()).unwrap(); + + let expected: Vec = vec![]; + assert_eq!(output, expected); +} + +#[test] +fn test_full_list() { + let executor = SystemExecutor::new( + "beet", + Some(&fs::canonicalize("./tests/files/library/config.yml").unwrap()), + ); + + let mut beets = Beets::new(Box::new(executor)); + let output = beets.list(&Query::default()).unwrap(); + + let expected: Vec = COLLECTION.to_owned(); + assert_eq!(output, expected); +} + +#[test] +fn test_album_artist_query() { + let executor = SystemExecutor::new( + "beet", + Some(&fs::canonicalize("./tests/files/library/config.yml").unwrap()), + ); + + let mut beets = Beets::new(Box::new(executor)); + let output = beets + .list(&Query::default().album_artist(QueryOption::Include(String::from("Аркона")))) + .unwrap(); + + let expected: Vec = COLLECTION[0..1].to_owned(); + assert_eq!(output, expected); +} + +#[test] +fn test_album_title_query() { + let executor = SystemExecutor::new( + "beet", + Some(&fs::canonicalize("./tests/files/library/config.yml").unwrap()), + ); + + let mut beets = Beets::new(Box::new(executor)); + let output = beets + .list(&Query::default().album_title(QueryOption::Include(String::from("Slovo")))) + .unwrap(); + + + let expected: Vec = COLLECTION[0..1].to_owned(); + assert_eq!(output, expected); +} + +#[test] +fn test_exclude_query() { + let executor = SystemExecutor::new( + "beet", + Some(&fs::canonicalize("./tests/files/library/config.yml").unwrap()), + ); + + let mut beets = Beets::new(Box::new(executor)); + let output = beets + .list(&Query::default().album_artist(QueryOption::Exclude(String::from("Аркона")))) + .unwrap(); + + let expected: Vec = COLLECTION[1..].to_owned(); + assert_eq!(output, expected); +} diff --git a/tests/library/mod.rs b/tests/library/mod.rs new file mode 100644 index 0000000..035ac9f --- /dev/null +++ b/tests/library/mod.rs @@ -0,0 +1 @@ +mod beets;