Make artist the top level
This commit is contained in:
parent
83893f1e7e
commit
3ea5dcce28
@ -77,7 +77,7 @@ impl DatabaseJsonBackend for DatabaseJsonFile {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use crate::{Album, AlbumId, Track};
|
use crate::{tests::test_data, Artist};
|
||||||
|
|
||||||
struct DatabaseJsonTest {
|
struct DatabaseJsonTest {
|
||||||
json: String,
|
json: String,
|
||||||
@ -94,98 +94,69 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_data() -> Vec<Album> {
|
fn artist_to_json(artist: &Artist) -> String {
|
||||||
vec![
|
let album_artist = &artist.id.name;
|
||||||
Album {
|
|
||||||
id: AlbumId {
|
|
||||||
artist: String::from("Artist A"),
|
|
||||||
year: 1998,
|
|
||||||
title: String::from("Release group A"),
|
|
||||||
},
|
|
||||||
tracks: vec![
|
|
||||||
Track {
|
|
||||||
number: 1,
|
|
||||||
title: String::from("Track A.1"),
|
|
||||||
artist: vec![String::from("Artist A.A")],
|
|
||||||
},
|
|
||||||
Track {
|
|
||||||
number: 2,
|
|
||||||
title: String::from("Track A.2"),
|
|
||||||
artist: vec![String::from("Artist A.A")],
|
|
||||||
},
|
|
||||||
Track {
|
|
||||||
number: 3,
|
|
||||||
title: String::from("Track A.3"),
|
|
||||||
artist: vec![String::from("Artist A.A"), String::from("Artist A.B")],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
Album {
|
|
||||||
id: AlbumId {
|
|
||||||
artist: String::from("Artist B"),
|
|
||||||
year: 2008,
|
|
||||||
title: String::from("Release group B"),
|
|
||||||
},
|
|
||||||
tracks: vec![Track {
|
|
||||||
number: 1,
|
|
||||||
title: String::from("Track B.1"),
|
|
||||||
artist: vec![String::from("Artist B.A")],
|
|
||||||
}],
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn album_to_json(album: &Album) -> String {
|
let mut albums: Vec<String> = vec![];
|
||||||
let album_id_artist = &album.id.artist;
|
for album in artist.albums.iter() {
|
||||||
let album_id_year = album.id.year;
|
let album_year = album.id.year;
|
||||||
let album_id_title = &album.id.title;
|
let album_title = &album.id.title;
|
||||||
|
|
||||||
let mut album_tracks: Vec<String> = vec![];
|
let mut tracks: Vec<String> = vec![];
|
||||||
for track in album.tracks.iter() {
|
for track in album.tracks.iter() {
|
||||||
let track_number = track.number;
|
let track_number = track.number;
|
||||||
let track_title = &track.title;
|
let track_title = &track.title;
|
||||||
|
|
||||||
let mut track_artist: Vec<String> = vec![];
|
let mut track_artist: Vec<String> = vec![];
|
||||||
for artist in track.artist.iter() {
|
for artist in track.artist.iter() {
|
||||||
track_artist.push(format!("\"{artist}\""))
|
track_artist.push(format!("\"{artist}\""))
|
||||||
|
}
|
||||||
|
let track_artist = track_artist.join(",");
|
||||||
|
|
||||||
|
tracks.push(format!(
|
||||||
|
"{{\
|
||||||
|
\"number\":{track_number},\
|
||||||
|
\"title\":\"{track_title}\",\
|
||||||
|
\"artist\":[{track_artist}]\
|
||||||
|
}}"
|
||||||
|
));
|
||||||
}
|
}
|
||||||
let track_artist = track_artist.join(",");
|
let tracks = tracks.join(",");
|
||||||
|
|
||||||
album_tracks.push(format!(
|
albums.push(format!(
|
||||||
"{{\
|
"{{\
|
||||||
\"number\":{track_number},\
|
\"id\":{{\
|
||||||
\"title\":\"{track_title}\",\
|
\"year\":{album_year},\
|
||||||
\"artist\":[{track_artist}]\
|
\"title\":\"{album_title}\"\
|
||||||
|
}},\"tracks\":[{tracks}]\
|
||||||
}}"
|
}}"
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
let album_tracks = album_tracks.join(",");
|
let albums = albums.join(",");
|
||||||
|
|
||||||
format!(
|
format!(
|
||||||
"{{\
|
"{{\
|
||||||
\"id\":{{\
|
\"id\":{{\
|
||||||
\"artist\":\"{album_id_artist}\",\
|
\"name\":\"{album_artist}\"\
|
||||||
\"year\":{album_id_year},\
|
}},\"albums\":[{albums}]\
|
||||||
\"title\":\"{album_id_title}\"\
|
|
||||||
}},\"tracks\":[{album_tracks}]\
|
|
||||||
}}"
|
}}"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn albums_to_json(albums: &Vec<Album>) -> String {
|
fn artists_to_json(artists: &Vec<Artist>) -> String {
|
||||||
let mut albums_strings: Vec<String> = vec![];
|
let mut artists_strings: Vec<String> = vec![];
|
||||||
for album in albums.iter() {
|
for artist in artists.iter() {
|
||||||
albums_strings.push(album_to_json(album));
|
artists_strings.push(artist_to_json(artist));
|
||||||
}
|
}
|
||||||
let albums_json = albums_strings.join(",");
|
let artists_json = artists_strings.join(",");
|
||||||
format!("[{albums_json}]")
|
format!("[{artists_json}]")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn write() {
|
fn write() {
|
||||||
let write_data = test_data();
|
let write_data = test_data();
|
||||||
let backend = DatabaseJsonTest {
|
let backend = DatabaseJsonTest {
|
||||||
json: albums_to_json(&write_data),
|
json: artists_to_json(&write_data),
|
||||||
};
|
};
|
||||||
|
|
||||||
DatabaseJson::new(Box::new(backend))
|
DatabaseJson::new(Box::new(backend))
|
||||||
@ -197,10 +168,10 @@ mod tests {
|
|||||||
fn read() {
|
fn read() {
|
||||||
let expected = test_data();
|
let expected = test_data();
|
||||||
let backend = DatabaseJsonTest {
|
let backend = DatabaseJsonTest {
|
||||||
json: albums_to_json(&expected),
|
json: artists_to_json(&expected),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut read_data: Vec<Album> = vec![];
|
let mut read_data: Vec<Artist> = vec![];
|
||||||
DatabaseJson::new(Box::new(backend))
|
DatabaseJson::new(Box::new(backend))
|
||||||
.read(&mut read_data)
|
.read(&mut read_data)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -212,12 +183,12 @@ mod tests {
|
|||||||
fn reverse() {
|
fn reverse() {
|
||||||
let expected = test_data();
|
let expected = test_data();
|
||||||
let backend = DatabaseJsonTest {
|
let backend = DatabaseJsonTest {
|
||||||
json: albums_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 = test_data();
|
||||||
let mut read_data: Vec<Album> = 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();
|
||||||
|
|
||||||
|
101
src/lib.rs
101
src/lib.rs
@ -20,7 +20,6 @@ pub struct Track {
|
|||||||
/// The album identifier.
|
/// The album identifier.
|
||||||
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Clone, Hash)]
|
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Clone, Hash)]
|
||||||
pub struct AlbumId {
|
pub struct AlbumId {
|
||||||
pub artist: String,
|
|
||||||
pub year: u32,
|
pub year: u32,
|
||||||
pub title: String,
|
pub title: String,
|
||||||
}
|
}
|
||||||
@ -31,3 +30,103 @@ pub struct Album {
|
|||||||
pub id: AlbumId,
|
pub id: AlbumId,
|
||||||
pub tracks: Vec<Track>,
|
pub tracks: Vec<Track>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The artist identifier.
|
||||||
|
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Clone, Hash)]
|
||||||
|
pub struct ArtistId {
|
||||||
|
pub name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An artist.
|
||||||
|
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq)]
|
||||||
|
pub struct Artist {
|
||||||
|
pub id: ArtistId,
|
||||||
|
pub albums: Vec<Album>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
pub fn test_data() -> Vec<Artist> {
|
||||||
|
vec![
|
||||||
|
Artist {
|
||||||
|
id: ArtistId {
|
||||||
|
name: "album_artist a".to_string(),
|
||||||
|
},
|
||||||
|
albums: vec![
|
||||||
|
Album {
|
||||||
|
id: AlbumId {
|
||||||
|
year: 1998,
|
||||||
|
title: "album_title a.a".to_string(),
|
||||||
|
},
|
||||||
|
tracks: vec![
|
||||||
|
Track {
|
||||||
|
number: 1,
|
||||||
|
title: "track a.a.1".to_string(),
|
||||||
|
artist: vec!["artist a.a.1".to_string()],
|
||||||
|
},
|
||||||
|
Track {
|
||||||
|
number: 2,
|
||||||
|
title: "track a.a.2".to_string(),
|
||||||
|
artist: vec![
|
||||||
|
"artist a.a.2.1".to_string(),
|
||||||
|
"artist a.a.2.2".to_string(),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
Track {
|
||||||
|
number: 3,
|
||||||
|
title: "track a.a.3".to_string(),
|
||||||
|
artist: vec!["artist a.a.3".to_string()],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
Album {
|
||||||
|
id: AlbumId {
|
||||||
|
year: 2015,
|
||||||
|
title: "album_title a.b".to_string(),
|
||||||
|
},
|
||||||
|
tracks: vec![
|
||||||
|
Track {
|
||||||
|
number: 1,
|
||||||
|
title: "track a.b.1".to_string(),
|
||||||
|
artist: vec!["artist a.b.1".to_string()],
|
||||||
|
},
|
||||||
|
Track {
|
||||||
|
number: 2,
|
||||||
|
title: "track a.b.2".to_string(),
|
||||||
|
artist: vec!["artist a.b.2".to_string()],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
Artist {
|
||||||
|
id: ArtistId {
|
||||||
|
name: "album_artist b.a".to_string(),
|
||||||
|
},
|
||||||
|
albums: vec![Album {
|
||||||
|
id: AlbumId {
|
||||||
|
year: 2003,
|
||||||
|
title: "album_title b.a".to_string(),
|
||||||
|
},
|
||||||
|
tracks: vec![
|
||||||
|
Track {
|
||||||
|
number: 1,
|
||||||
|
title: "track b.a.1".to_string(),
|
||||||
|
artist: vec!["artist b.a.1".to_string()],
|
||||||
|
},
|
||||||
|
Track {
|
||||||
|
number: 2,
|
||||||
|
title: "track b.a.2".to_string(),
|
||||||
|
artist: vec![
|
||||||
|
"artist b.a.2.1".to_string(),
|
||||||
|
"artist b.a.2.2".to_string(),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
//! Module for interacting with the music library via
|
//! Module for interacting with the music library via
|
||||||
//! [beets](https://beets.readthedocs.io/en/stable/).
|
//! [beets](https://beets.readthedocs.io/en/stable/).
|
||||||
|
|
||||||
use std::{collections::HashSet, fmt::Display, process::Command};
|
use std::{
|
||||||
|
collections::{HashMap, HashSet},
|
||||||
|
fmt::Display,
|
||||||
|
process::Command,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{Album, AlbumId, Track};
|
use crate::{Album, AlbumId, Artist, ArtistId, Track};
|
||||||
|
|
||||||
use super::{Error, Library, Query, QueryOption};
|
use super::{Error, Library, Query, QueryOption};
|
||||||
|
|
||||||
@ -94,7 +98,7 @@ trait LibraryPrivate {
|
|||||||
const LIST_FORMAT_ARG: &'static str;
|
const LIST_FORMAT_ARG: &'static str;
|
||||||
|
|
||||||
fn list_cmd_and_args(query: &Query) -> Vec<String>;
|
fn list_cmd_and_args(query: &Query) -> Vec<String>;
|
||||||
fn list_to_albums(list_output: Vec<String>) -> Result<Vec<Album>, Error>;
|
fn list_to_artists(list_output: Vec<String>) -> Result<Vec<Artist>, Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Beets {
|
impl Beets {
|
||||||
@ -104,10 +108,10 @@ impl Beets {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Library for Beets {
|
impl Library for Beets {
|
||||||
fn list(&mut self, query: &Query) -> Result<Vec<Album>, Error> {
|
fn list(&mut self, query: &Query) -> Result<Vec<Artist>, Error> {
|
||||||
let cmd = Self::list_cmd_and_args(query);
|
let cmd = Self::list_cmd_and_args(query);
|
||||||
let output = self.executor.exec(&cmd)?;
|
let output = self.executor.exec(&cmd)?;
|
||||||
Self::list_to_albums(output)
|
Self::list_to_artists(output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,9 +146,9 @@ impl LibraryPrivate for Beets {
|
|||||||
cmd
|
cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list_to_albums(list_output: Vec<String>) -> Result<Vec<Album>, Error> {
|
fn list_to_artists(list_output: Vec<String>) -> Result<Vec<Artist>, Error> {
|
||||||
let mut albums: Vec<Album> = vec![];
|
let mut artists: Vec<Artist> = vec![];
|
||||||
let mut album_ids = 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();
|
let split: Vec<&str> = line.split(Self::LIST_FORMAT_SEPARATOR).collect();
|
||||||
@ -160,8 +164,9 @@ impl LibraryPrivate for Beets {
|
|||||||
let track_title = split[4].to_string();
|
let track_title = split[4].to_string();
|
||||||
let track_artist = split[5].to_string();
|
let track_artist = split[5].to_string();
|
||||||
|
|
||||||
let aid = AlbumId {
|
let artist_id = ArtistId { name: album_artist };
|
||||||
artist: album_artist,
|
|
||||||
|
let album_id = AlbumId {
|
||||||
year: album_year,
|
year: album_year,
|
||||||
title: album_title,
|
title: album_title,
|
||||||
};
|
};
|
||||||
@ -172,20 +177,44 @@ impl LibraryPrivate for Beets {
|
|||||||
artist: track_artist.split("; ").map(|s| s.to_owned()).collect(),
|
artist: track_artist.split("; ").map(|s| s.to_owned()).collect(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if album_ids.contains(&aid) {
|
let artist = if album_ids.contains_key(&artist_id) {
|
||||||
// Beets returns results in order so we look from the back.
|
// Beets returns results in order so we look from the back.
|
||||||
let album = albums.iter_mut().rev().find(|a| a.id == aid).unwrap();
|
artists
|
||||||
|
.iter_mut()
|
||||||
|
.rev()
|
||||||
|
.find(|a| a.id == artist_id)
|
||||||
|
.unwrap()
|
||||||
|
} else {
|
||||||
|
album_ids.insert(artist_id.clone(), HashSet::<AlbumId>::new());
|
||||||
|
artists.push(Artist {
|
||||||
|
id: artist_id.clone(),
|
||||||
|
albums: vec![],
|
||||||
|
});
|
||||||
|
artists.last_mut().unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
if album_ids[&artist_id].contains(&album_id) {
|
||||||
|
// Beets returns results in order so we look from the back.
|
||||||
|
let album = artist
|
||||||
|
.albums
|
||||||
|
.iter_mut()
|
||||||
|
.rev()
|
||||||
|
.find(|a| a.id == album_id)
|
||||||
|
.unwrap();
|
||||||
album.tracks.push(track);
|
album.tracks.push(track);
|
||||||
} else {
|
} else {
|
||||||
album_ids.insert(aid.clone());
|
album_ids
|
||||||
albums.push(Album {
|
.get_mut(&artist_id)
|
||||||
id: aid,
|
.unwrap()
|
||||||
|
.insert(album_id.clone());
|
||||||
|
artist.albums.push(Album {
|
||||||
|
id: album_id,
|
||||||
tracks: vec![track],
|
tracks: vec![track],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(albums)
|
Ok(artists)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,6 +249,8 @@ impl BeetsExecutor for SystemExecutor {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
use crate::tests::test_data;
|
||||||
|
|
||||||
struct TestExecutor {
|
struct TestExecutor {
|
||||||
arguments: Option<Vec<String>>,
|
arguments: Option<Vec<String>>,
|
||||||
output: Option<Result<Vec<String>, Error>>,
|
output: Option<Result<Vec<String>, Error>>,
|
||||||
@ -232,79 +263,35 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_data() -> Vec<Album> {
|
fn artist_to_beets_string(artist: &Artist) -> Vec<String> {
|
||||||
vec![
|
|
||||||
Album {
|
|
||||||
id: AlbumId {
|
|
||||||
artist: "album_artist.a".to_string(),
|
|
||||||
year: 1998,
|
|
||||||
title: "album_title.a".to_string(),
|
|
||||||
},
|
|
||||||
tracks: vec![
|
|
||||||
Track {
|
|
||||||
number: 1,
|
|
||||||
title: "track.a.1".to_string(),
|
|
||||||
artist: vec!["artist.a.1".to_string()],
|
|
||||||
},
|
|
||||||
Track {
|
|
||||||
number: 2,
|
|
||||||
title: "track.a.2".to_string(),
|
|
||||||
artist: vec!["artist.a.2.1".to_string(), "artist.a.2.2".to_string()],
|
|
||||||
},
|
|
||||||
Track {
|
|
||||||
number: 3,
|
|
||||||
title: "track.a.3".to_string(),
|
|
||||||
artist: vec!["artist.a.3".to_string()],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
Album {
|
|
||||||
id: AlbumId {
|
|
||||||
artist: "album_artist.b".to_string(),
|
|
||||||
year: 2003,
|
|
||||||
title: "album_title.b".to_string(),
|
|
||||||
},
|
|
||||||
tracks: vec![
|
|
||||||
Track {
|
|
||||||
number: 1,
|
|
||||||
title: "track.b.1".to_string(),
|
|
||||||
artist: vec!["artist.b.1".to_string()],
|
|
||||||
},
|
|
||||||
Track {
|
|
||||||
number: 2,
|
|
||||||
title: "track.b.2".to_string(),
|
|
||||||
artist: vec!["artist.b.2.1".to_string(), "artist.b.2.2".to_string()],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn album_to_beets_string(album: &Album) -> Vec<String> {
|
|
||||||
let album_artist = &album.id.artist;
|
|
||||||
let album_year = &album.id.year;
|
|
||||||
let album_title = &album.id.title;
|
|
||||||
|
|
||||||
let mut strings = vec![];
|
let mut strings = vec![];
|
||||||
for track in album.tracks.iter() {
|
|
||||||
let track_number = &track.number;
|
|
||||||
let track_title = &track.title;
|
|
||||||
let track_artist = &track.artist.join("; ");
|
|
||||||
|
|
||||||
strings.push(format!(
|
let album_artist = &artist.id.name;
|
||||||
"{album_artist}{0}{album_year}{0}{album_title}{0}\
|
|
||||||
{track_number}{0}{track_title}{0}{track_artist}",
|
for album in artist.albums.iter() {
|
||||||
Beets::LIST_FORMAT_SEPARATOR,
|
let album_year = &album.id.year;
|
||||||
));
|
let album_title = &album.id.title;
|
||||||
|
|
||||||
|
for track in album.tracks.iter() {
|
||||||
|
let track_number = &track.number;
|
||||||
|
let track_title = &track.title;
|
||||||
|
let track_artist = &track.artist.join("; ");
|
||||||
|
|
||||||
|
strings.push(format!(
|
||||||
|
"{album_artist}{0}{album_year}{0}{album_title}{0}\
|
||||||
|
{track_number}{0}{track_title}{0}{track_artist}",
|
||||||
|
Beets::LIST_FORMAT_SEPARATOR,
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
strings
|
strings
|
||||||
}
|
}
|
||||||
|
|
||||||
fn albums_to_beets_string(albums: &Vec<Album>) -> Vec<String> {
|
fn artists_to_beets_string(artists: &Vec<Artist>) -> Vec<String> {
|
||||||
let mut strings = vec![];
|
let mut strings = vec![];
|
||||||
for album in albums.iter() {
|
for artist in artists.iter() {
|
||||||
strings.append(&mut album_to_beets_string(album));
|
strings.append(&mut artist_to_beets_string(artist));
|
||||||
}
|
}
|
||||||
strings
|
strings
|
||||||
}
|
}
|
||||||
@ -340,14 +327,14 @@ mod tests {
|
|||||||
let mut beets = Beets::new(Box::new(executor));
|
let mut beets = Beets::new(Box::new(executor));
|
||||||
let output = beets.list(&Query::default()).unwrap();
|
let output = beets.list(&Query::default()).unwrap();
|
||||||
|
|
||||||
let expected: Vec<Album> = vec![];
|
let expected: Vec<Artist> = vec![];
|
||||||
assert_eq!(output, expected);
|
assert_eq!(output, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_list_ordered() {
|
fn test_list_ordered() {
|
||||||
let expected = test_data();
|
let expected = test_data();
|
||||||
let output = albums_to_beets_string(&expected);
|
let output = artists_to_beets_string(&expected);
|
||||||
|
|
||||||
let executor = TestExecutor {
|
let executor = TestExecutor {
|
||||||
arguments: Some(vec!["ls".to_string(), Beets::LIST_FORMAT_ARG.to_string()]),
|
arguments: Some(vec!["ls".to_string(), Beets::LIST_FORMAT_ARG.to_string()]),
|
||||||
@ -362,18 +349,21 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_list_unordered() {
|
fn test_list_unordered() {
|
||||||
let mut expected = test_data();
|
let mut expected = test_data();
|
||||||
let mut output = albums_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);
|
||||||
|
|
||||||
// Putting the last track first will make its entire album come first in the output.
|
// Putting the last track first will make the entire artist come first in the output.
|
||||||
expected.rotate_right(1);
|
expected.rotate_right(1);
|
||||||
|
|
||||||
|
// Same applies to that artists' albums, but here the artist has only one album.
|
||||||
|
assert_eq!(expected[0].albums.len(), 1);
|
||||||
|
|
||||||
// Same applies to that album's tracks.
|
// Same applies to that album's tracks.
|
||||||
expected[0].tracks.rotate_right(1);
|
expected[0].albums[0].tracks.rotate_right(1);
|
||||||
|
|
||||||
// And the (now) second album's tracks first track comes last.
|
// And the (now) second album's tracks first track comes last.
|
||||||
expected[1].tracks.rotate_left(1);
|
expected[1].albums[0].tracks.rotate_left(1);
|
||||||
|
|
||||||
let executor = TestExecutor {
|
let executor = TestExecutor {
|
||||||
arguments: Some(vec!["ls".to_string(), Beets::LIST_FORMAT_ARG.to_string()]),
|
arguments: Some(vec!["ls".to_string(), Beets::LIST_FORMAT_ARG.to_string()]),
|
||||||
@ -388,10 +378,10 @@ 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 = test_data();
|
||||||
expected[1].id.year = expected[0].id.year;
|
expected[0].albums[0].id.year = expected[1].albums[0].id.year;
|
||||||
expected[1].id.title = expected[0].id.title.clone();
|
expected[0].albums[0].id.title = expected[1].albums[0].id.title.clone();
|
||||||
|
|
||||||
let output = albums_to_beets_string(&expected);
|
let output = artists_to_beets_string(&expected);
|
||||||
|
|
||||||
let executor = TestExecutor {
|
let executor = TestExecutor {
|
||||||
arguments: Some(vec!["ls".to_string(), Beets::LIST_FORMAT_ARG.to_string()]),
|
arguments: Some(vec!["ls".to_string(), Beets::LIST_FORMAT_ARG.to_string()]),
|
||||||
@ -423,7 +413,7 @@ mod tests {
|
|||||||
let mut beets = Beets::new(Box::new(executor));
|
let mut beets = Beets::new(Box::new(executor));
|
||||||
let output = beets.list(&query).unwrap();
|
let output = beets.list(&query).unwrap();
|
||||||
|
|
||||||
let expected: Vec<Album> = vec![];
|
let expected: Vec<Artist> = vec![];
|
||||||
assert_eq!(output, expected);
|
assert_eq!(output, expected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
use std::{num::ParseIntError, str::Utf8Error};
|
use std::{num::ParseIntError, str::Utf8Error};
|
||||||
|
|
||||||
use crate::Album;
|
use crate::Artist;
|
||||||
|
|
||||||
pub mod beets;
|
pub mod beets;
|
||||||
|
|
||||||
@ -129,5 +129,5 @@ impl From<Utf8Error> for Error {
|
|||||||
/// Trait for interacting with the music library.
|
/// Trait for interacting with the music library.
|
||||||
pub trait Library {
|
pub trait Library {
|
||||||
/// List lirbary items that match the a specific query.
|
/// List lirbary items that match the a specific query.
|
||||||
fn list(&mut self, query: &Query) -> Result<Vec<Album>, Error>;
|
fn list(&mut self, query: &Query) -> Result<Vec<Artist>, Error>;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user