Enable fetch to apply modifications to the database #221

Merged
wojtek merged 14 commits from 189---enable-fetch-to-apply-modifications-to-the-database into main 2024-09-29 10:44:38 +02:00
3 changed files with 160 additions and 20 deletions
Showing only changes of commit 6145912c35 - Show all commits

View File

@ -333,7 +333,10 @@ mod tests {
use mockall::{predicate, Sequence}; use mockall::{predicate, Sequence};
use crate::{ use crate::{
collection::musicbrainz::{MbArtistRef, MbRefOption}, collection::{
album::{AlbumPrimaryType, AlbumSecondaryType},
musicbrainz::{MbArtistRef, MbRefOption},
},
core::{ core::{
collection::{album::AlbumDate, artist::ArtistId}, collection::{album::AlbumDate, artist::ArtistId},
interface::database::{self, MockIDatabase}, interface::database::{self, MockIDatabase},
@ -447,7 +450,23 @@ mod tests {
} }
#[test] #[test]
fn set_clear_info() { fn collection_error() {
let mut database = MockIDatabase::new();
database.expect_load().times(1).returning(|| Ok(vec![]));
let mut music_hoard = MusicHoard::database(database).unwrap();
let artist_id = ArtistId::new("an artist");
let actual_err = music_hoard
.set_artist_info(&artist_id, ArtistInfo::default())
.unwrap_err();
let expected_err =
Error::CollectionError(format!("artist '{artist_id}' is not in the collection"));
assert_eq!(actual_err, expected_err);
assert_eq!(actual_err.to_string(), expected_err.to_string());
}
#[test]
fn set_clear_artist_info() {
let mut database = MockIDatabase::new(); let mut database = MockIDatabase::new();
database.expect_load().times(1).returning(|| Ok(vec![])); database.expect_load().times(1).returning(|| Ok(vec![]));
database.expect_save().times(3).returning(|_| Ok(())); database.expect_save().times(3).returning(|_| Ok(()));
@ -624,6 +643,65 @@ mod tests {
assert_eq!(music_hoard.collection[0].albums[0].meta.seq, AlbumSeq(0)); assert_eq!(music_hoard.collection[0].albums[0].meta.seq, AlbumSeq(0));
} }
#[test]
fn set_clear_album_info() {
let mut database = MockIDatabase::new();
let artist_id = ArtistId::new("an artist");
let album_id = AlbumId::new("an album");
let album_id_2 = AlbumId::new("another album");
let mut database_result = vec![Artist::new(artist_id.clone())];
database_result[0].albums.push(Album::new(
album_id.clone(),
AlbumDate::default(),
None,
vec![],
));
database
.expect_load()
.times(1)
.return_once(|| Ok(database_result));
database.expect_save().times(2).returning(|_| Ok(()));
let mut music_hoard = MusicHoard::database(database).unwrap();
let meta = &music_hoard.collection[0].albums[0].meta;
assert_eq!(meta.info.musicbrainz, MbRefOption::None);
assert_eq!(meta.info.primary_type, None);
assert_eq!(meta.info.secondary_types, Vec::new());
let info = AlbumInfo::new(
MbRefOption::CannotHaveMbid,
Some(AlbumPrimaryType::Album),
vec![AlbumSecondaryType::Live],
);
// Seting info on an album not belonging to the artist is an error.
assert!(music_hoard
.set_album_info(&artist_id, &album_id_2, info.clone())
.is_err());
let meta = &music_hoard.collection[0].albums[0].meta;
assert_eq!(meta.info, AlbumInfo::default());
// Set info.
assert!(music_hoard
.set_album_info(&artist_id, &album_id, info.clone())
.is_ok());
let meta = &music_hoard.collection[0].albums[0].meta;
assert_eq!(meta.info, info);
// Clearing info on an album that does not exist is an error.
assert!(music_hoard
.clear_album_info(&artist_id, &album_id_2)
.is_err());
// Clear info.
assert!(music_hoard.clear_album_info(&artist_id, &album_id).is_ok());
let meta = &music_hoard.collection[0].albums[0].meta;
assert_eq!(meta.info, AlbumInfo::default());
}
#[test] #[test]
fn load_database() { fn load_database() {
let mut database = MockIDatabase::new(); let mut database = MockIDatabase::new();

View File

@ -20,12 +20,9 @@ use crate::core::collection::{
Collection, Collection,
}; };
use crate::core::{ use crate::core::interface::{
collection,
interface::{
database::{LoadError as DatabaseLoadError, SaveError as DatabaseSaveError}, database::{LoadError as DatabaseLoadError, SaveError as DatabaseSaveError},
library::Error as LibraryError, library::Error as LibraryError,
},
}; };
/// The Music Hoard. It is responsible for pulling information from both the library and the /// The Music Hoard. It is responsible for pulling information from both the library and the
@ -79,12 +76,6 @@ impl Display for Error {
} }
} }
impl From<collection::Error> for Error {
fn from(err: collection::Error) -> Self {
Error::CollectionError(err.to_string())
}
}
impl From<LibraryError> for Error { impl From<LibraryError> for Error {
fn from(err: LibraryError) -> Error { fn from(err: LibraryError) -> Error {
Error::LibraryError(err.to_string()) Error::LibraryError(err.to_string())

View File

@ -346,8 +346,14 @@ mod tests {
} }
} }
fn mbid() -> Mbid {
"00000000-0000-0000-0000-000000000000".try_into().unwrap()
}
fn artist_meta() -> ArtistMeta { fn artist_meta() -> ArtistMeta {
ArtistMeta::new(ArtistId::new("Artist")) let mut meta = ArtistMeta::new(ArtistId::new("Artist"));
meta.info.musicbrainz = MbRefOption::Some(mbid().into());
meta
} }
fn artist_match() -> MatchStateInfo { fn artist_match() -> MatchStateInfo {
@ -375,7 +381,7 @@ mod tests {
AlbumId::new("Album"), AlbumId::new("Album"),
AlbumDate::new(Some(1990), Some(5), None), AlbumDate::new(Some(1990), Some(5), None),
AlbumInfo::new( AlbumInfo::new(
MbRefOption::None, MbRefOption::Some(mbid().into()),
Some(AlbumPrimaryType::Album), Some(AlbumPrimaryType::Album),
vec![AlbumSecondaryType::Live, AlbumSecondaryType::Compilation], vec![AlbumSecondaryType::Live, AlbumSecondaryType::Compilation],
), ),
@ -549,6 +555,75 @@ mod tests {
match_state_flow(album_lookup(), 1); match_state_flow(album_lookup(), 1);
} }
#[test]
fn set_artist_info() {
let matches_info = artist_match();
let (_tx, rx) = mpsc::channel();
let app_matches = MatchState::new(Some(matches_info.clone()), FetchState::new(rx));
let mut music_hoard = music_hoard(vec![]);
match matches_info {
MatchStateInfo::Album(_) => panic!(),
MatchStateInfo::Artist(_) => {
let meta = artist_meta();
music_hoard
.expect_set_artist_info()
.with(eq(meta.id), eq(meta.info))
.times(1)
.return_once(|_, _| Ok(()));
}
}
let matches = AppMachine::match_state(inner(music_hoard), app_matches);
matches.select().unwrap_fetch();
}
#[test]
fn set_album_info() {
let matches_info = album_match();
let (_tx, rx) = mpsc::channel();
let app_matches = MatchState::new(Some(matches_info.clone()), FetchState::new(rx));
let mut music_hoard = music_hoard(vec![]);
match matches_info {
MatchStateInfo::Artist(_) => panic!(),
MatchStateInfo::Album(matches) => {
let meta = album_meta();
music_hoard
.expect_set_album_info()
.with(eq(matches.artist), eq(meta.id), eq(meta.info))
.times(1)
.return_once(|_, _, _| Ok(()));
}
}
let matches = AppMachine::match_state(inner(music_hoard), app_matches);
matches.select().unwrap_fetch();
}
#[test]
fn set_info_error() {
let matches_info = artist_match();
let (_tx, rx) = mpsc::channel();
let app_matches = MatchState::new(Some(matches_info.clone()), FetchState::new(rx));
let mut music_hoard = music_hoard(vec![]);
match matches_info {
MatchStateInfo::Album(_) => panic!(),
MatchStateInfo::Artist(_) => {
music_hoard.expect_set_artist_info().return_once(|_, _| {
Err(musichoard::Error::DatabaseError(String::from("error")))
});
}
}
let matches = AppMachine::match_state(inner(music_hoard), app_matches);
matches.select().unwrap_error();
}
#[test] #[test]
fn abort() { fn abort() {
let mut album_match = album_match(); let mut album_match = album_match();
@ -594,10 +669,6 @@ mod tests {
input.confirm().unwrap_error(); input.confirm().unwrap_error();
} }
fn mbid() -> Mbid {
"00000000-0000-0000-0000-000000000000".try_into().unwrap()
}
fn input_mbid(mut app: App) -> App { fn input_mbid(mut app: App) -> App {
let mbid = mbid().uuid().to_string(); let mbid = mbid().uuid().to_string();
for c in mbid.chars() { for c in mbid.chars() {