Add integration tests

This commit is contained in:
Wojciech Kozlowski 2023-04-09 22:56:12 +02:00
parent 5c7579ba23
commit 16045a6c85
12 changed files with 635 additions and 28 deletions

7
Cargo.lock generated
View File

@ -98,12 +98,19 @@ checksum = "cd550e73688e6d578f0ac2119e32b797a327631a42f9433e59d02e139c8df60d"
name = "musichoard" name = "musichoard"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"once_cell",
"serde", "serde",
"serde_json", "serde_json",
"tempfile", "tempfile",
"uuid", "uuid",
] ]
[[package]]
name = "once_cell"
version = "1.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.54" version = "1.0.54"

View File

@ -11,4 +11,5 @@ serde_json = "1.0"
uuid = { version = "1.3", features = ["serde"] } uuid = { version = "1.3", features = ["serde"] }
[dev-dependencies] [dev-dependencies]
once_cell = "1.17"
tempfile = "3.5" tempfile = "3.5"

View File

@ -1,7 +1,7 @@
//! Module for storing MusicHoard data in a JSON file database. //! Module for storing MusicHoard data in a JSON file database.
use std::fs::{read_to_string, write}; use std::fs;
use std::path::PathBuf; use std::path::{PathBuf, Path};
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use serde::Serialize; use serde::Serialize;
@ -56,8 +56,8 @@ pub struct DatabaseJsonFile {
impl DatabaseJsonFile { impl DatabaseJsonFile {
/// Create a database instance that will read/write to the provided path. /// Create a database instance that will read/write to the provided path.
pub fn new(path: PathBuf) -> Self { pub fn new(path: &Path) -> Self {
DatabaseJsonFile { path } DatabaseJsonFile { path: path.to_path_buf() }
} }
} }
@ -65,11 +65,11 @@ impl DatabaseJsonBackend for DatabaseJsonFile {
fn read(&self) -> Result<String, std::io::Error> { fn read(&self) -> Result<String, std::io::Error> {
// Read entire file to memory as for now this is faster than a buffered read from disk: // 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 // 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> { 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 { mod tests {
use super::*; use super::*;
use crate::{tests::test_data, Artist}; use crate::{tests::COLLECTION, Artist};
struct DatabaseJsonTest { struct DatabaseJsonTest {
json: String, json: String,
@ -154,7 +154,7 @@ mod tests {
#[test] #[test]
fn write() { fn write() {
let write_data = test_data(); let write_data = COLLECTION.to_owned();
let backend = DatabaseJsonTest { let backend = DatabaseJsonTest {
json: artists_to_json(&write_data), json: artists_to_json(&write_data),
}; };
@ -166,7 +166,7 @@ mod tests {
#[test] #[test]
fn read() { fn read() {
let expected = test_data(); let expected = COLLECTION.to_owned();
let backend = DatabaseJsonTest { let backend = DatabaseJsonTest {
json: artists_to_json(&expected), json: artists_to_json(&expected),
}; };
@ -181,13 +181,13 @@ mod tests {
#[test] #[test]
fn reverse() { fn reverse() {
let expected = test_data(); let expected = COLLECTION.to_owned();
let backend = DatabaseJsonTest { let backend = DatabaseJsonTest {
json: artists_to_json(&expected), json: artists_to_json(&expected),
}; };
let mut database = DatabaseJson::new(Box::new(backend)); let mut database = DatabaseJson::new(Box::new(backend));
let write_data = test_data(); let write_data = COLLECTION.to_owned();
let mut read_data: Vec<Artist> = vec![]; let mut read_data: Vec<Artist> = vec![];
database.write(&write_data).unwrap(); database.write(&write_data).unwrap();
database.read(&mut read_data).unwrap(); database.read(&mut read_data).unwrap();

View File

@ -10,7 +10,7 @@ pub mod library;
pub type Mbid = Uuid; pub type Mbid = Uuid;
/// A single track on an album. /// A single track on an album.
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq)] #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub struct Track { pub struct Track {
pub number: u32, pub number: u32,
pub title: String, pub title: String,
@ -18,27 +18,27 @@ pub struct Track {
} }
/// The album identifier. /// The album identifier.
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Clone, Hash)] #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, Hash)]
pub struct AlbumId { pub struct AlbumId {
pub year: u32, pub year: u32,
pub title: String, pub title: String,
} }
/// An album is a collection of tracks that were released together. /// 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 struct Album {
pub id: AlbumId, pub id: AlbumId,
pub tracks: Vec<Track>, pub tracks: Vec<Track>,
} }
/// The artist identifier. /// The artist identifier.
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Clone, Hash)] #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, Hash)]
pub struct ArtistId { pub struct ArtistId {
pub name: String, pub name: String,
} }
/// An artist. /// An artist.
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq)] #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub struct Artist { pub struct Artist {
pub id: ArtistId, pub id: ArtistId,
pub albums: Vec<Album>, pub albums: Vec<Album>,
@ -48,7 +48,9 @@ pub struct Artist {
mod tests { mod tests {
use super::*; use super::*;
pub fn test_data() -> Vec<Artist> { use once_cell::sync::Lazy;
pub static COLLECTION: Lazy<Vec<Artist>> = Lazy::new(|| {
vec![ vec![
Artist { Artist {
id: ArtistId { id: ArtistId {
@ -128,5 +130,5 @@ mod tests {
}], }],
}, },
] ]
} });
} }

View File

@ -4,7 +4,7 @@
use std::{ use std::{
collections::{HashMap, HashSet}, collections::{HashMap, HashSet},
fmt::Display, fmt::Display,
process::Command, process::Command, path::{PathBuf, Path},
}; };
use crate::{Album, AlbumId, Artist, ArtistId, Track}; use crate::{Album, AlbumId, Artist, ArtistId, Track};
@ -117,7 +117,7 @@ impl Library for Beets {
macro_rules! list_format_separator { macro_rules! list_format_separator {
() => { () => {
"-*^-" " -*^- "
}; };
} }
@ -151,8 +151,11 @@ impl LibraryPrivate for Beets {
let mut album_ids = HashMap::<ArtistId, HashSet<AlbumId>>::new(); let mut album_ids = HashMap::<ArtistId, HashSet<AlbumId>>::new();
for line in list_output.iter() { 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 { if split.len() != 6 {
return Err(Error::InvalidData(line.to_string())); return Err(Error::InvalidData(line.to_string()));
} }
@ -221,25 +224,32 @@ impl LibraryPrivate for Beets {
/// Executor for executing beets commands on the local system. /// Executor for executing beets commands on the local system.
pub struct SystemExecutor { pub struct SystemExecutor {
bin: String, bin: String,
config: Option<PathBuf>,
} }
impl SystemExecutor { impl SystemExecutor {
pub fn new(bin: &str) -> SystemExecutor { pub fn new(bin: &str, path: Option<&Path>) -> SystemExecutor {
SystemExecutor { SystemExecutor {
bin: bin.to_string(), bin: bin.to_string(),
config: path.map(|p| p.to_path_buf()),
} }
} }
} }
impl Default for SystemExecutor { impl Default for SystemExecutor {
fn default() -> Self { fn default() -> Self {
SystemExecutor::new("beet") SystemExecutor::new("beet", None)
} }
} }
impl BeetsExecutor for SystemExecutor { impl BeetsExecutor for SystemExecutor {
fn exec(&mut self, arguments: &[String]) -> Result<Vec<String>, Error> { fn exec(&mut self, arguments: &[String]) -> Result<Vec<String>, 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)?; let output = std::str::from_utf8(&output.stdout)?;
Ok(output.split('\n').map(|s| s.to_string()).collect()) Ok(output.split('\n').map(|s| s.to_string()).collect())
} }
@ -249,7 +259,7 @@ impl BeetsExecutor for SystemExecutor {
mod tests { mod tests {
use super::*; use super::*;
use crate::tests::test_data; use crate::tests::COLLECTION;
struct TestExecutor { struct TestExecutor {
arguments: Option<Vec<String>>, arguments: Option<Vec<String>>,
@ -333,7 +343,7 @@ mod tests {
#[test] #[test]
fn test_list_ordered() { fn test_list_ordered() {
let expected = test_data(); let expected = COLLECTION.to_owned();
let output = artists_to_beets_string(&expected); let output = artists_to_beets_string(&expected);
let executor = TestExecutor { let executor = TestExecutor {
@ -348,7 +358,7 @@ mod tests {
#[test] #[test]
fn test_list_unordered() { fn test_list_unordered() {
let mut expected = test_data(); let mut expected = COLLECTION.to_owned();
let mut output = artists_to_beets_string(&expected); let mut output = artists_to_beets_string(&expected);
let last = output.len() - 1; let last = output.len() - 1;
output.swap(0, last); output.swap(0, last);
@ -377,7 +387,7 @@ mod tests {
#[test] #[test]
fn test_list_album_title_year_clash() { 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.year = expected[1].albums[0].id.year;
expected[0].albums[0].id.title = expected[1].albums[0].id.title.clone(); expected[0].albums[0].id.title = expected[1].albums[0].id.title.clone();

56
tests/database/json.rs Normal file
View File

@ -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<Artist> = 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<Artist> = vec![];
database.read(&mut read_data).unwrap();
assert_eq!(write_data, read_data);
}

1
tests/database/mod.rs Normal file
View File

@ -0,0 +1 @@
mod json;

1
tests/files/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
library

View File

@ -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":"Bolno 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 [rerecorded]"},"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":"Devils 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"]}]}]}]

442
tests/lib.rs Normal file
View File

@ -0,0 +1,442 @@
mod database;
mod library;
use musichoard::{Album, AlbumId, Artist, ArtistId, Track};
use once_cell::sync::Lazy;
static COLLECTION: Lazy<Vec<Artist>> = 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("Bolno 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 [rerecorded]"),
},
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("Devils 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")],
},
],
},
],
},
]
});

85
tests/library/beets.rs Normal file
View File

@ -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<Artist> = 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<Artist> = 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<Artist> = 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<Artist> = 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<Artist> = COLLECTION[1..].to_owned();
assert_eq!(output, expected);
}

1
tests/library/mod.rs Normal file
View File

@ -0,0 +1 @@
mod beets;