diff --git a/src/core/database/json/testmod.rs b/src/core/database/json/testmod.rs index 11cbd3b..ef5ea55 100644 --- a/src/core/database/json/testmod.rs +++ b/src/core/database/json/testmod.rs @@ -26,6 +26,11 @@ pub static DATABASE_JSON: &str = "[\ \"id\":{\"number\":3,\"title\":\"track a.a.3\"},\ \"artist\":[\"artist a.a.3\"],\ \"quality\":{\"format\":\"Flac\",\"bitrate\":1061}\ + },\ + {\ + \"id\":{\"number\":4,\"title\":\"track a.a.4\"},\ + \"artist\":[\"artist a.a.4\"],\ + \"quality\":{\"format\":\"Flac\",\"bitrate\":1042}\ }\ ]\ },\ @@ -88,6 +93,36 @@ pub static DATABASE_JSON: &str = "[\ \"quality\":{\"format\":\"Mp3\",\"bitrate\":320}\ }\ ]\ + },\ + {\ + \"id\":{\"year\":2009,\"title\":\"album_title b.c\"},\ + \"tracks\":[\ + {\ + \"id\":{\"number\":1,\"title\":\"track b.c.1\"},\ + \"artist\":[\"artist b.c.1\"],\ + \"quality\":{\"format\":\"Mp3\",\"bitrate\":190}\ + },\ + {\ + \"id\":{\"number\":2,\"title\":\"track b.c.2\"},\ + \"artist\":[\"artist b.c.2.1\",\"artist b.c.2.2\"],\ + \"quality\":{\"format\":\"Mp3\",\"bitrate\":120}\ + }\ + ]\ + },\ + {\ + \"id\":{\"year\":2015,\"title\":\"album_title b.d\"},\ + \"tracks\":[\ + {\ + \"id\":{\"number\":1,\"title\":\"track b.d.1\"},\ + \"artist\":[\"artist b.d.1\"],\ + \"quality\":{\"format\":\"Mp3\",\"bitrate\":190}\ + },\ + {\ + \"id\":{\"number\":2,\"title\":\"track b.d.2\"},\ + \"artist\":[\"artist b.d.2.1\",\"artist b.d.2.2\"],\ + \"quality\":{\"format\":\"Mp3\",\"bitrate\":120}\ + }\ + ]\ }\ ]\ },\ @@ -132,5 +167,47 @@ pub static DATABASE_JSON: &str = "[\ ]\ }\ ]\ + },\ + {\ + \"id\":{\"name\":\"album_artist d\"},\ + \"sort\":null,\ + \"properties\":{\ + \"musicbrainz\":null,\ + \"musicbutler\":[],\ + \"bandcamp\":[],\ + \"qobuz\":null\ + },\ + \"albums\":[\ + {\ + \"id\":{\"year\":1995,\"title\":\"album_title d.a\"},\ + \"tracks\":[\ + {\ + \"id\":{\"number\":1,\"title\":\"track d.a.1\"},\ + \"artist\":[\"artist d.a.1\"],\ + \"quality\":{\"format\":\"Mp3\",\"bitrate\":120}\ + },\ + {\ + \"id\":{\"number\":2,\"title\":\"track d.a.2\"},\ + \"artist\":[\"artist d.a.2.1\",\"artist d.a.2.2\"],\ + \"quality\":{\"format\":\"Mp3\",\"bitrate\":120}\ + }\ + ]\ + },\ + {\ + \"id\":{\"year\":2028,\"title\":\"album_title d.b\"},\ + \"tracks\":[\ + {\ + \"id\":{\"number\":1,\"title\":\"track d.b.1\"},\ + \"artist\":[\"artist d.b.1\"],\ + \"quality\":{\"format\":\"Flac\",\"bitrate\":841}\ + },\ + {\ + \"id\":{\"number\":2,\"title\":\"track d.b.2\"},\ + \"artist\":[\"artist d.b.2.1\",\"artist d.b.2.2\"],\ + \"quality\":{\"format\":\"Flac\",\"bitrate\":756}\ + }\ + ]\ + }\ + ]\ }\ ]"; diff --git a/src/core/library/beets/testmod.rs b/src/core/library/beets/testmod.rs index 5d28afb..e52045b 100644 --- a/src/core/library/beets/testmod.rs +++ b/src/core/library/beets/testmod.rs @@ -5,15 +5,24 @@ pub static LIBRARY_BEETS: Lazy> = Lazy::new(|| -> Vec { String::from("album_artist a -*^- -*^- 1998 -*^- album_title a.a -*^- 1 -*^- track a.a.1 -*^- artist a.a.1 -*^- FLAC -*^- 992"), String::from("album_artist a -*^- -*^- 1998 -*^- album_title a.a -*^- 2 -*^- track a.a.2 -*^- artist a.a.2.1; artist a.a.2.2 -*^- MP3 -*^- 320"), String::from("album_artist a -*^- -*^- 1998 -*^- album_title a.a -*^- 3 -*^- track a.a.3 -*^- artist a.a.3 -*^- FLAC -*^- 1061"), + String::from("album_artist a -*^- -*^- 1998 -*^- album_title a.a -*^- 4 -*^- track a.a.4 -*^- artist a.a.4 -*^- FLAC -*^- 1042"), String::from("album_artist a -*^- -*^- 2015 -*^- album_title a.b -*^- 1 -*^- track a.b.1 -*^- artist a.b.1 -*^- FLAC -*^- 1004"), String::from("album_artist a -*^- -*^- 2015 -*^- album_title a.b -*^- 2 -*^- track a.b.2 -*^- artist a.b.2 -*^- FLAC -*^- 1077"), String::from("album_artist b -*^- -*^- 2003 -*^- album_title b.a -*^- 1 -*^- track b.a.1 -*^- artist b.a.1 -*^- MP3 -*^- 190"), String::from("album_artist b -*^- -*^- 2003 -*^- album_title b.a -*^- 2 -*^- track b.a.2 -*^- artist b.a.2.1; artist b.a.2.2 -*^- MP3 -*^- 120"), String::from("album_artist b -*^- -*^- 2008 -*^- album_title b.b -*^- 1 -*^- track b.b.1 -*^- artist b.b.1 -*^- FLAC -*^- 1077"), String::from("album_artist b -*^- -*^- 2008 -*^- album_title b.b -*^- 2 -*^- track b.b.2 -*^- artist b.b.2.1; artist b.b.2.2 -*^- MP3 -*^- 320"), + String::from("album_artist b -*^- -*^- 2009 -*^- album_title b.c -*^- 1 -*^- track b.c.1 -*^- artist b.c.1 -*^- MP3 -*^- 190"), + String::from("album_artist b -*^- -*^- 2009 -*^- album_title b.c -*^- 2 -*^- track b.c.2 -*^- artist b.c.2.1; artist b.c.2.2 -*^- MP3 -*^- 120"), + String::from("album_artist b -*^- -*^- 2015 -*^- album_title b.d -*^- 1 -*^- track b.d.1 -*^- artist b.d.1 -*^- MP3 -*^- 190"), + String::from("album_artist b -*^- -*^- 2015 -*^- album_title b.d -*^- 2 -*^- track b.d.2 -*^- artist b.d.2.1; artist b.d.2.2 -*^- MP3 -*^- 120"), String::from("album_artist c -*^- -*^- 1985 -*^- album_title c.a -*^- 1 -*^- track c.a.1 -*^- artist c.a.1 -*^- MP3 -*^- 320"), String::from("album_artist c -*^- -*^- 1985 -*^- album_title c.a -*^- 2 -*^- track c.a.2 -*^- artist c.a.2.1; artist c.a.2.2 -*^- MP3 -*^- 120"), String::from("album_artist c -*^- -*^- 2018 -*^- album_title c.b -*^- 1 -*^- track c.b.1 -*^- artist c.b.1 -*^- FLAC -*^- 1041"), - String::from("album_artist c -*^- -*^- 2018 -*^- album_title c.b -*^- 2 -*^- track c.b.2 -*^- artist c.b.2.1; artist c.b.2.2 -*^- FLAC -*^- 756") + String::from("album_artist c -*^- -*^- 2018 -*^- album_title c.b -*^- 2 -*^- track c.b.2 -*^- artist c.b.2.1; artist c.b.2.2 -*^- FLAC -*^- 756"), + String::from("album_artist d -*^- -*^- 1995 -*^- album_title d.a -*^- 1 -*^- track d.a.1 -*^- artist d.a.1 -*^- MP3 -*^- 120"), + String::from("album_artist d -*^- -*^- 1995 -*^- album_title d.a -*^- 2 -*^- track d.a.2 -*^- artist d.a.2.1; artist d.a.2.2 -*^- MP3 -*^- 120"), + String::from("album_artist d -*^- -*^- 2028 -*^- album_title d.b -*^- 1 -*^- track d.b.1 -*^- artist d.b.1 -*^- FLAC -*^- 841"), + String::from("album_artist d -*^- -*^- 2028 -*^- album_title d.b -*^- 2 -*^- track d.b.2 -*^- artist d.b.2.1; artist d.b.2.2 -*^- FLAC -*^- 756") ] }); diff --git a/src/core/library/testmod.rs b/src/core/library/testmod.rs index a0a5af4..f86be94 100644 --- a/src/core/library/testmod.rs +++ b/src/core/library/testmod.rs @@ -40,6 +40,17 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { track_format: Format::Flac, track_bitrate: 1061, }, + Item { + album_artist: String::from("album_artist a"), + album_artist_sort: None, + album_year: 1998, + album_title: String::from("album_title a.a"), + track_number: 4, + track_title: String::from("track a.a.4"), + track_artist: vec![String::from("artist a.a.4")], + track_format: Format::Flac, + track_bitrate: 1042, + }, Item { album_artist: String::from("album_artist a"), album_artist_sort: None, @@ -112,6 +123,56 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { track_format: Format::Mp3, track_bitrate: 320, }, + Item { + album_artist: String::from("album_artist b"), + album_artist_sort: None, + album_year: 2009, + album_title: String::from("album_title b.c"), + track_number: 1, + track_title: String::from("track b.c.1"), + track_artist: vec![String::from("artist b.c.1")], + track_format: Format::Mp3, + track_bitrate: 190, + }, + Item { + album_artist: String::from("album_artist b"), + album_artist_sort: None, + album_year: 2009, + album_title: String::from("album_title b.c"), + track_number: 2, + track_title: String::from("track b.c.2"), + track_artist: vec![ + String::from("artist b.c.2.1"), + String::from("artist b.c.2.2"), + ], + track_format: Format::Mp3, + track_bitrate: 120, + }, + Item { + album_artist: String::from("album_artist b"), + album_artist_sort: None, + album_year: 2015, + album_title: String::from("album_title b.d"), + track_number: 1, + track_title: String::from("track b.d.1"), + track_artist: vec![String::from("artist b.d.1")], + track_format: Format::Mp3, + track_bitrate: 190, + }, + Item { + album_artist: String::from("album_artist b"), + album_artist_sort: None, + album_year: 2015, + album_title: String::from("album_title b.d"), + track_number: 2, + track_title: String::from("track b.d.2"), + track_artist: vec![ + String::from("artist b.d.2.1"), + String::from("artist b.d.2.2"), + ], + track_format: Format::Mp3, + track_bitrate: 120, + }, Item { album_artist: String::from("album_artist c"), album_artist_sort: None, @@ -162,5 +223,55 @@ pub static LIBRARY_ITEMS: Lazy> = Lazy::new(|| -> Vec { track_format: Format::Flac, track_bitrate: 756, }, + Item { + album_artist: String::from("album_artist d"), + album_artist_sort: None, + album_year: 1995, + album_title: String::from("album_title d.a"), + track_number: 1, + track_title: String::from("track d.a.1"), + track_artist: vec![String::from("artist d.a.1")], + track_format: Format::Mp3, + track_bitrate: 120, + }, + Item { + album_artist: String::from("album_artist d"), + album_artist_sort: None, + album_year: 1995, + album_title: String::from("album_title d.a"), + track_number: 2, + track_title: String::from("track d.a.2"), + track_artist: vec![ + String::from("artist d.a.2.1"), + String::from("artist d.a.2.2"), + ], + track_format: Format::Mp3, + track_bitrate: 120, + }, + Item { + album_artist: String::from("album_artist d"), + album_artist_sort: None, + album_year: 2028, + album_title: String::from("album_title d.b"), + track_number: 1, + track_title: String::from("track d.b.1"), + track_artist: vec![String::from("artist d.b.1")], + track_format: Format::Flac, + track_bitrate: 841, + }, + Item { + album_artist: String::from("album_artist d"), + album_artist_sort: None, + album_year: 2028, + album_title: String::from("album_title d.b"), + track_number: 2, + track_title: String::from("track d.b.2"), + track_artist: vec![ + String::from("artist d.b.2.1"), + String::from("artist d.b.2.2"), + ], + track_format: Format::Flac, + track_bitrate: 756, + }, ] }); diff --git a/src/tests.rs b/src/tests.rs index 84b1372..e952266 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -55,6 +55,17 @@ macro_rules! library_collection { bitrate: 1061, }, }, + Track { + id: TrackId { + number: 4, + title: "track a.a.4".to_string(), + }, + artist: vec!["artist a.a.4".to_string()], + quality: Quality { + format: Format::Flac, + bitrate: 1042, + }, + }, ], }, Album { @@ -167,6 +178,72 @@ macro_rules! library_collection { }, ], }, + Album { + id: AlbumId { + year: 2009, + title: "album_title b.c".to_string(), + }, + tracks: vec![ + Track { + id: TrackId { + number: 1, + title: "track b.c.1".to_string(), + }, + artist: vec!["artist b.c.1".to_string()], + quality: Quality { + format: Format::Mp3, + bitrate: 190, + }, + }, + Track { + id: TrackId { + number: 2, + title: "track b.c.2".to_string(), + }, + artist: vec![ + "artist b.c.2.1".to_string(), + "artist b.c.2.2".to_string(), + ], + quality: Quality { + format: Format::Mp3, + bitrate: 120, + }, + }, + ], + }, + Album { + id: AlbumId { + year: 2015, + title: "album_title b.d".to_string(), + }, + tracks: vec![ + Track { + id: TrackId { + number: 1, + title: "track b.d.1".to_string(), + }, + artist: vec!["artist b.d.1".to_string()], + quality: Quality { + format: Format::Mp3, + bitrate: 190, + }, + }, + Track { + id: TrackId { + number: 2, + title: "track b.d.2".to_string(), + }, + artist: vec![ + "artist b.d.2.1".to_string(), + "artist b.d.2.2".to_string(), + ], + quality: Quality { + format: Format::Mp3, + bitrate: 120, + }, + }, + ], + }, ], }, Artist { @@ -249,6 +326,86 @@ macro_rules! library_collection { }, ], }, + Artist { + id: ArtistId { + name: "album_artist d".to_string(), + }, + sort: None, + properties: ArtistProperties { + musicbrainz: None, + musicbutler: vec![], + bandcamp: vec![], + qobuz: None, + }, + albums: vec![ + Album { + id: AlbumId { + year: 1995, + title: "album_title d.a".to_string(), + }, + tracks: vec![ + Track { + id: TrackId { + number: 1, + title: "track d.a.1".to_string(), + }, + artist: vec!["artist d.a.1".to_string()], + quality: Quality { + format: Format::Mp3, + bitrate: 120, + }, + }, + Track { + id: TrackId { + number: 2, + title: "track d.a.2".to_string(), + }, + artist: vec![ + "artist d.a.2.1".to_string(), + "artist d.a.2.2".to_string(), + ], + quality: Quality { + format: Format::Mp3, + bitrate: 120, + }, + }, + ], + }, + Album { + id: AlbumId { + year: 2028, + title: "album_title d.b".to_string(), + }, + tracks: vec![ + Track { + id: TrackId { + number: 1, + title: "track d.b.1".to_string(), + }, + artist: vec!["artist d.b.1".to_string()], + quality: Quality { + format: Format::Flac, + bitrate: 841, + }, + }, + Track { + id: TrackId { + number: 2, + title: "track d.b.2".to_string(), + }, + artist: vec![ + "artist d.b.2.1".to_string(), + "artist d.b.2.2".to_string(), + ], + quality: Quality { + format: Format::Flac, + bitrate: 756, + }, + }, + ], + }, + ], + }, ] }; } @@ -318,6 +475,8 @@ macro_rules! full_collection { qobuz: None, }; + // Nothing for artist_d + collection }}; } diff --git a/src/tui/app/selection.rs b/src/tui/app/selection.rs index 129275f..629f935 100644 --- a/src/tui/app/selection.rs +++ b/src/tui/app/selection.rs @@ -47,7 +47,6 @@ pub struct TrackSelection { pub state: WidgetState, } -#[derive(Clone, Debug)] pub enum Delta { Line, Page, @@ -465,6 +464,44 @@ mod tests { sel.increment(tracks, Delta::Line); } assert_eq!(sel.state.list.selected(), Some(tracks.len() - 1)); + } + + #[test] + fn track_delta_page() { + let tracks = &COLLECTION[0].albums[0].tracks; + assert!(tracks.len() > 1); + + let empty = TrackSelection::initialise(&[]); + assert_eq!(empty.state.list.selected(), None); + + let mut sel = TrackSelection::initialise(tracks); + assert_eq!(sel.state.list.selected(), Some(0)); + + assert!(tracks.len() >= 4); + sel.state.height = 3; + + sel.decrement(tracks, Delta::Page); + assert_eq!(sel.state.list.selected(), Some(0)); + + sel.increment(tracks, Delta::Page); + assert_eq!(sel.state.list.selected(), Some(2)); + + sel.decrement(tracks, Delta::Page); + assert_eq!(sel.state.list.selected(), Some(0)); + + for _ in 0..(tracks.len() + 5) { + sel.increment(tracks, Delta::Page); + } + assert_eq!(sel.state.list.selected(), Some(tracks.len() - 1)); + } + + #[test] + fn track_reinitialise() { + let tracks = &COLLECTION[0].albums[0].tracks; + assert!(tracks.len() > 1); + + let mut sel = TrackSelection::initialise(tracks); + sel.state.list.select(Some(tracks.len() - 1)); // Re-initialise. let expected = sel.clone(); @@ -529,6 +566,64 @@ mod tests { sel.increment(albums, Delta::Line); assert_eq!(sel.state.list.selected(), Some(albums.len() - 1)); assert_eq!(sel.track.state.list.selected(), Some(1)); + } + + #[test] + fn album_delta_page() { + let albums = &COLLECTION[1].albums; + assert!(albums.len() > 1); + + let empty = AlbumSelection::initialise(&[]); + assert_eq!(empty.state.list.selected(), None); + + let mut sel = AlbumSelection::initialise(albums); + assert_eq!(sel.state.list.selected(), Some(0)); + assert_eq!(sel.track.state.list.selected(), Some(0)); + + assert!(albums.len() >= 4); + sel.state.height = 3; + + sel.increment_track(albums, Delta::Line); + assert_eq!(sel.state.list.selected(), Some(0)); + assert_eq!(sel.track.state.list.selected(), Some(1)); + + // Verify that decrement that doesn't change index does not reset track. + sel.decrement(albums, Delta::Page); + assert_eq!(sel.state.list.selected(), Some(0)); + assert_eq!(sel.track.state.list.selected(), Some(1)); + + sel.increment(albums, Delta::Page); + assert_eq!(sel.state.list.selected(), Some(2)); + assert_eq!(sel.track.state.list.selected(), Some(0)); + + sel.decrement(albums, Delta::Page); + assert_eq!(sel.state.list.selected(), Some(0)); + assert_eq!(sel.track.state.list.selected(), Some(0)); + + for _ in 0..(albums.len() + 5) { + sel.increment(albums, Delta::Page); + } + assert_eq!(sel.state.list.selected(), Some(albums.len() - 1)); + assert_eq!(sel.track.state.list.selected(), Some(0)); + + sel.increment_track(albums, Delta::Line); + assert_eq!(sel.state.list.selected(), Some(albums.len() - 1)); + assert_eq!(sel.track.state.list.selected(), Some(1)); + + // Verify that increment that doesn't change index does not reset track. + sel.increment(albums, Delta::Page); + assert_eq!(sel.state.list.selected(), Some(albums.len() - 1)); + assert_eq!(sel.track.state.list.selected(), Some(1)); + } + + #[test] + fn album_reinitialise() { + let albums = &COLLECTION[0].albums; + assert!(albums.len() > 1); + + let mut sel = AlbumSelection::initialise(albums); + sel.state.list.select(Some(albums.len() - 1)); + sel.track.state.list.select(Some(1)); // Re-initialise. let expected = sel.clone(); @@ -593,6 +688,64 @@ mod tests { sel.increment(artists, Delta::Line); assert_eq!(sel.state.list.selected(), Some(artists.len() - 1)); assert_eq!(sel.album.state.list.selected(), Some(1)); + } + + #[test] + fn artist_delta_page() { + let artists = &COLLECTION; + assert!(artists.len() > 1); + + let empty = ArtistSelection::initialise(&[]); + assert_eq!(empty.state.list.selected(), None); + + let mut sel = ArtistSelection::initialise(artists); + assert_eq!(sel.state.list.selected(), Some(0)); + assert_eq!(sel.album.state.list.selected(), Some(0)); + + assert!(artists.len() >= 4); + sel.state.height = 3; + + sel.increment_album(artists, Delta::Line); + assert_eq!(sel.state.list.selected(), Some(0)); + assert_eq!(sel.album.state.list.selected(), Some(1)); + + // Verify that decrement that doesn't change index does not reset album. + sel.decrement(artists, Delta::Page); + assert_eq!(sel.state.list.selected(), Some(0)); + assert_eq!(sel.album.state.list.selected(), Some(1)); + + sel.increment(artists, Delta::Page); + assert_eq!(sel.state.list.selected(), Some(2)); + assert_eq!(sel.album.state.list.selected(), Some(0)); + + sel.decrement(artists, Delta::Page); + assert_eq!(sel.state.list.selected(), Some(0)); + assert_eq!(sel.album.state.list.selected(), Some(0)); + + for _ in 0..(artists.len() + 5) { + sel.increment(artists, Delta::Page); + } + assert_eq!(sel.state.list.selected(), Some(artists.len() - 1)); + assert_eq!(sel.album.state.list.selected(), Some(0)); + + sel.increment_album(artists, Delta::Line); + assert_eq!(sel.state.list.selected(), Some(artists.len() - 1)); + assert_eq!(sel.album.state.list.selected(), Some(1)); + + // Verify that increment that doesn't change index does not reset album. + sel.increment(artists, Delta::Page); + assert_eq!(sel.state.list.selected(), Some(artists.len() - 1)); + assert_eq!(sel.album.state.list.selected(), Some(1)); + } + + #[test] + fn artist_reinitialise() { + let artists = &COLLECTION; + assert!(artists.len() > 1); + + let mut sel = ArtistSelection::initialise(artists); + sel.state.list.select(Some(artists.len() - 1)); + sel.album.state.list.select(Some(1)); // Re-initialise. let expected = sel.clone();