Compare commits
4 Commits
0cc477fb05
...
780e6b8350
Author | SHA1 | Date | |
---|---|---|---|
780e6b8350 | |||
6a9919fac9 | |||
2b72726428 | |||
369b4ecf98 |
49
src/external/musicbrainz/api/lookup.rs
vendored
49
src/external/musicbrainz/api/lookup.rs
vendored
@ -162,19 +162,9 @@ mod tests {
|
||||
release_groups: Some(vec![de_release_group.clone()]),
|
||||
};
|
||||
|
||||
let release_group = MbReleaseGroupMeta {
|
||||
id: de_release_group.id.0,
|
||||
title: de_release_group.title.into(),
|
||||
first_release_date: de_release_group.first_release_date.0,
|
||||
primary_type: de_release_group.primary_type.0,
|
||||
secondary_types: de_release_group
|
||||
.secondary_types
|
||||
.as_ref()
|
||||
.map(|v| v.into_iter().map(|st| st.0).collect()),
|
||||
};
|
||||
let response = LookupArtistResponse {
|
||||
meta: de_meta.into(),
|
||||
release_groups: vec![release_group],
|
||||
release_groups: vec![de_release_group.into()],
|
||||
};
|
||||
|
||||
http.expect_get()
|
||||
@ -191,4 +181,41 @@ mod tests {
|
||||
|
||||
assert_eq!(result, response);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lookup_release_group() {
|
||||
let mbid = "00000000-0000-0000-0000-000000000000";
|
||||
let mut http = MockIMusicBrainzHttp::new();
|
||||
let url = format!("https://musicbrainz.org/ws/2/release-group/{mbid}",);
|
||||
|
||||
let de_meta = SerdeMbReleaseGroupMeta {
|
||||
id: SerdeMbid("11111111-1111-1111-1111-111111111111".try_into().unwrap()),
|
||||
title: String::from("an album"),
|
||||
first_release_date: SerdeAlbumDate((1986, 4).into()),
|
||||
primary_type: SerdeAlbumPrimaryType(AlbumPrimaryType::Album),
|
||||
secondary_types: Some(vec![SerdeAlbumSecondaryType(
|
||||
AlbumSecondaryType::Compilation,
|
||||
)]),
|
||||
};
|
||||
let de_response = DeserializeLookupReleaseGroupResponse {
|
||||
meta: de_meta.clone(),
|
||||
};
|
||||
|
||||
let response = LookupReleaseGroupResponse {
|
||||
meta: de_meta.into(),
|
||||
};
|
||||
|
||||
http.expect_get()
|
||||
.times(1)
|
||||
.with(predicate::eq(url))
|
||||
.return_once(|_| Ok(de_response));
|
||||
|
||||
let mut client = MusicBrainzClient::new(http);
|
||||
|
||||
let mbid: Mbid = "00000000-0000-0000-0000-000000000000".try_into().unwrap();
|
||||
let request = LookupReleaseGroupRequest::new(&mbid);
|
||||
let result = client.lookup_release_group(request).unwrap();
|
||||
|
||||
assert_eq!(result, response);
|
||||
}
|
||||
}
|
||||
|
@ -19,12 +19,12 @@ use crate::tui::{
|
||||
},
|
||||
};
|
||||
|
||||
pub type FetchReceiver = mpsc::Receiver<MbApiResult>;
|
||||
pub struct FetchState {
|
||||
fetch_rx: FetchReceiver,
|
||||
lookup_rx: Option<FetchReceiver>,
|
||||
}
|
||||
|
||||
pub type FetchReceiver = mpsc::Receiver<MbApiResult>;
|
||||
impl FetchState {
|
||||
pub fn new(fetch_rx: FetchReceiver) -> Self {
|
||||
FetchState {
|
||||
@ -38,7 +38,7 @@ impl FetchState {
|
||||
let result = lookup_rx.try_recv();
|
||||
match result {
|
||||
Ok(_) | Err(TryRecvError::Empty) => return result,
|
||||
_ => {
|
||||
Err(TryRecvError::Disconnected) => {
|
||||
self.lookup_rx.take();
|
||||
}
|
||||
}
|
||||
@ -214,12 +214,47 @@ mod tests {
|
||||
machine::tests::{inner, music_hoard},
|
||||
Delta, IApp, IAppAccess, IAppInteractBrowse, MatchStateInfo, MissOption, SearchOption,
|
||||
},
|
||||
lib::interface::musicbrainz::{self, api::Match, daemon::MockIMbJobSender},
|
||||
lib::interface::musicbrainz::{
|
||||
self,
|
||||
api::{Lookup, Match},
|
||||
daemon::MockIMbJobSender,
|
||||
},
|
||||
testmod::COLLECTION,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
||||
fn mbid() -> Mbid {
|
||||
"00000000-0000-0000-0000-000000000000".try_into().unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn try_recv() {
|
||||
let (fetch_tx, fetch_rx) = mpsc::channel();
|
||||
let (lookup_tx, lookup_rx) = mpsc::channel();
|
||||
|
||||
let mut fetch = FetchState::new(fetch_rx);
|
||||
fetch.lookup_rx.replace(lookup_rx);
|
||||
|
||||
let artist = COLLECTION[3].meta.clone();
|
||||
|
||||
let matches: Vec<Match<ArtistMeta>> = vec![];
|
||||
let fetch_result = MatchStateInfo::artist_search(artist.clone(), matches);
|
||||
fetch_tx.send(Ok(fetch_result.clone())).unwrap();
|
||||
|
||||
assert_eq!(fetch.try_recv(), Err(TryRecvError::Empty));
|
||||
|
||||
let lookup = Lookup::new(artist.clone());
|
||||
let lookup_result = MatchStateInfo::artist_lookup(artist.clone(), lookup);
|
||||
lookup_tx.send(Ok(lookup_result.clone())).unwrap();
|
||||
|
||||
assert_eq!(fetch.try_recv(), Ok(Ok(lookup_result)));
|
||||
|
||||
assert_eq!(fetch.try_recv(), Err(TryRecvError::Empty));
|
||||
drop(lookup_tx);
|
||||
assert_eq!(fetch.try_recv(), Ok(Ok(fetch_result)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fetch_no_artist() {
|
||||
let app = AppMachine::app_fetch_new(inner(music_hoard(vec![])));
|
||||
@ -265,6 +300,31 @@ mod tests {
|
||||
assert!(matches!(app, AppState::Match(_)));
|
||||
}
|
||||
|
||||
fn lookup_album_expectation(job_sender: &mut MockIMbJobSender, album: &AlbumMeta) {
|
||||
let requests = VecDeque::from([MbParams::lookup_release_group(album.clone(), mbid())]);
|
||||
job_sender
|
||||
.expect_submit_foreground_job()
|
||||
.with(predicate::always(), predicate::eq(requests))
|
||||
.times(1)
|
||||
.return_once(|_, _| Ok(()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lookup_album() {
|
||||
let mut mb_job_sender = MockIMbJobSender::new();
|
||||
|
||||
let album = COLLECTION[1].albums[0].meta.clone();
|
||||
lookup_album_expectation(&mut mb_job_sender, &album);
|
||||
|
||||
let music_hoard = music_hoard(COLLECTION.to_owned());
|
||||
let inner = AppInner::new(music_hoard, mb_job_sender);
|
||||
|
||||
let (_fetch_tx, fetch_rx) = mpsc::channel();
|
||||
let fetch = FetchState::new(fetch_rx);
|
||||
|
||||
AppMachine::app_lookup_album(inner, fetch, &album, mbid());
|
||||
}
|
||||
|
||||
fn search_artist_expectation(job_sender: &mut MockIMbJobSender, artist: &ArtistMeta) {
|
||||
let requests = VecDeque::from([MbParams::search_artist(artist.clone())]);
|
||||
job_sender
|
||||
@ -294,6 +354,31 @@ mod tests {
|
||||
assert!(matches!(app, AppState::Match(_)));
|
||||
}
|
||||
|
||||
fn lookup_artist_expectation(job_sender: &mut MockIMbJobSender, artist: &ArtistMeta) {
|
||||
let requests = VecDeque::from([MbParams::lookup_artist(artist.clone(), mbid())]);
|
||||
job_sender
|
||||
.expect_submit_foreground_job()
|
||||
.with(predicate::always(), predicate::eq(requests))
|
||||
.times(1)
|
||||
.return_once(|_, _| Ok(()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lookup_artist() {
|
||||
let mut mb_job_sender = MockIMbJobSender::new();
|
||||
|
||||
let artist = COLLECTION[3].meta.clone();
|
||||
lookup_artist_expectation(&mut mb_job_sender, &artist);
|
||||
|
||||
let music_hoard = music_hoard(COLLECTION.to_owned());
|
||||
let inner = AppInner::new(music_hoard, mb_job_sender);
|
||||
|
||||
let (_fetch_tx, fetch_rx) = mpsc::channel();
|
||||
let fetch = FetchState::new(fetch_rx);
|
||||
|
||||
AppMachine::app_lookup_artist(inner, fetch, &artist, mbid());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fetch_artist_job_sender_err() {
|
||||
let mut mb_job_sender = MockIMbJobSender::new();
|
||||
@ -310,6 +395,26 @@ mod tests {
|
||||
assert!(matches!(app, AppState::Error(_)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lookup_artist_job_sender_err() {
|
||||
let mut mb_job_sender = MockIMbJobSender::new();
|
||||
|
||||
mb_job_sender
|
||||
.expect_submit_foreground_job()
|
||||
.return_once(|_, _| Err(DaemonError::JobChannelDisconnected));
|
||||
|
||||
let artist = COLLECTION[3].meta.clone();
|
||||
|
||||
let music_hoard = music_hoard(COLLECTION.to_owned());
|
||||
let inner = AppInner::new(music_hoard, mb_job_sender);
|
||||
|
||||
let (_fetch_tx, fetch_rx) = mpsc::channel();
|
||||
let fetch = FetchState::new(fetch_rx);
|
||||
|
||||
let app = AppMachine::app_lookup_artist(inner, fetch, &artist, mbid());
|
||||
assert!(matches!(app, AppState::Error(_)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn recv_ok_fetch_ok() {
|
||||
let (tx, rx) = mpsc::channel::<MbApiResult>();
|
||||
|
@ -64,20 +64,12 @@ impl IAppInput for AppInputMode {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::tui::app::{
|
||||
machine::tests::{mb_job_sender, music_hoard_init},
|
||||
machine::tests::{input_event, mb_job_sender, music_hoard_init},
|
||||
IApp,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
||||
fn input_event(c: char) -> InputEvent {
|
||||
crossterm::event::KeyEvent::new(
|
||||
crossterm::event::KeyCode::Char(c),
|
||||
crossterm::event::KeyModifiers::empty(),
|
||||
)
|
||||
.into()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn handle_input() {
|
||||
let mut app = App::new(music_hoard_init(vec![]), mb_job_sender());
|
||||
|
@ -86,14 +86,14 @@ impl MatchStateInfo {
|
||||
}
|
||||
}
|
||||
|
||||
fn push_cannot_have_mbid(&mut self) {
|
||||
pub fn push_cannot_have_mbid(&mut self) {
|
||||
match self {
|
||||
Self::Artist(a) => a.push_cannot_have_mbid(),
|
||||
Self::Album(a) => a.push_cannot_have_mbid(),
|
||||
}
|
||||
}
|
||||
|
||||
fn push_manual_input_mbid(&mut self) {
|
||||
pub fn push_manual_input_mbid(&mut self) {
|
||||
match self {
|
||||
Self::Artist(a) => a.push_manual_input_mbid(),
|
||||
Self::Album(a) => a.push_manual_input_mbid(),
|
||||
@ -218,8 +218,9 @@ impl IAppInteractMatch for AppMachine<MatchState> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::sync::mpsc;
|
||||
use std::{collections::VecDeque, sync::mpsc};
|
||||
|
||||
use mockall::predicate;
|
||||
use musichoard::collection::{
|
||||
album::{AlbumDate, AlbumId, AlbumMeta, AlbumPrimaryType, AlbumSecondaryType},
|
||||
artist::{ArtistId, ArtistMeta},
|
||||
@ -227,10 +228,13 @@ mod tests {
|
||||
|
||||
use crate::tui::{
|
||||
app::{
|
||||
machine::tests::{inner, music_hoard},
|
||||
machine::tests::{inner, inner_with_mb, input_event, music_hoard},
|
||||
IApp, IAppAccess, IAppInput,
|
||||
},
|
||||
lib::interface::musicbrainz::api::Match,
|
||||
lib::interface::musicbrainz::{
|
||||
api::{Lookup, Match},
|
||||
daemon::{MbParams, MockIMbJobSender},
|
||||
},
|
||||
};
|
||||
|
||||
use super::*;
|
||||
@ -245,6 +249,15 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Lookup<T> {
|
||||
pub fn new(item: T) -> Self {
|
||||
Lookup {
|
||||
item,
|
||||
disambiguation: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn artist_match() -> MatchStateInfo {
|
||||
let artist = ArtistMeta::new(ArtistId::new("Artist"));
|
||||
|
||||
@ -259,6 +272,12 @@ mod tests {
|
||||
MatchStateInfo::artist_search(artist, list)
|
||||
}
|
||||
|
||||
fn artist_lookup() -> MatchStateInfo {
|
||||
let artist = ArtistMeta::new(ArtistId::new("Artist"));
|
||||
let lookup = Lookup::new(artist.clone());
|
||||
MatchStateInfo::artist_lookup(artist, lookup)
|
||||
}
|
||||
|
||||
fn album_match() -> MatchStateInfo {
|
||||
let album = AlbumMeta::new(
|
||||
AlbumId::new("Album"),
|
||||
@ -279,6 +298,17 @@ mod tests {
|
||||
MatchStateInfo::album_search(album, list)
|
||||
}
|
||||
|
||||
fn album_lookup() -> MatchStateInfo {
|
||||
let album = AlbumMeta::new(
|
||||
AlbumId::new("Album"),
|
||||
AlbumDate::new(Some(1990), Some(5), None),
|
||||
Some(AlbumPrimaryType::Album),
|
||||
vec![AlbumSecondaryType::Live, AlbumSecondaryType::Compilation],
|
||||
);
|
||||
let lookup = Lookup::new(album.clone());
|
||||
MatchStateInfo::album_lookup(album, lookup)
|
||||
}
|
||||
|
||||
fn fetch_state() -> FetchState {
|
||||
let (_, rx) = mpsc::channel();
|
||||
FetchState::new(rx)
|
||||
@ -329,7 +359,7 @@ mod tests {
|
||||
assert_eq!(public_matches.state, &widget_state);
|
||||
}
|
||||
|
||||
fn match_state_flow(mut matches_info: MatchStateInfo) {
|
||||
fn match_state_flow(mut matches_info: MatchStateInfo, len: usize) {
|
||||
// tx must exist for rx to return Empty rather than Disconnected.
|
||||
#[allow(unused_variables)]
|
||||
let (tx, rx) = mpsc::channel();
|
||||
@ -350,27 +380,30 @@ mod tests {
|
||||
assert_eq!(matches.state.current.as_ref(), Some(&matches_info));
|
||||
assert_eq!(matches.state.state.list.selected(), Some(0));
|
||||
|
||||
let matches = matches.next_match().unwrap_match();
|
||||
let mut matches = matches;
|
||||
for ii in 1..len {
|
||||
matches = matches.next_match().unwrap_match();
|
||||
|
||||
assert_eq!(matches.state.current.as_ref(), Some(&matches_info));
|
||||
assert_eq!(matches.state.state.list.selected(), Some(1));
|
||||
assert_eq!(matches.state.current.as_ref(), Some(&matches_info));
|
||||
assert_eq!(matches.state.state.list.selected(), Some(ii));
|
||||
}
|
||||
|
||||
// Next is CannotHaveMBID
|
||||
let matches = matches.next_match().unwrap_match();
|
||||
|
||||
assert_eq!(matches.state.current.as_ref(), Some(&matches_info));
|
||||
assert_eq!(matches.state.state.list.selected(), Some(2));
|
||||
assert_eq!(matches.state.state.list.selected(), Some(len));
|
||||
|
||||
// Next is ManualInputMbid
|
||||
let matches = matches.next_match().unwrap_match();
|
||||
|
||||
assert_eq!(matches.state.current.as_ref(), Some(&matches_info));
|
||||
assert_eq!(matches.state.state.list.selected(), Some(3));
|
||||
assert_eq!(matches.state.state.list.selected(), Some(len + 1));
|
||||
|
||||
let matches = matches.next_match().unwrap_match();
|
||||
|
||||
assert_eq!(matches.state.current.as_ref(), Some(&matches_info));
|
||||
assert_eq!(matches.state.state.list.selected(), Some(3));
|
||||
assert_eq!(matches.state.state.list.selected(), Some(len + 1));
|
||||
|
||||
// Go prev_match first as selecting on manual input does not go back to fetch.
|
||||
let matches = matches.prev_match().unwrap_match();
|
||||
@ -379,12 +412,22 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn artist_matches_flow() {
|
||||
match_state_flow(artist_match());
|
||||
match_state_flow(artist_match(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn artist_lookup_flow() {
|
||||
match_state_flow(artist_lookup(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn album_matches_flow() {
|
||||
match_state_flow(album_match());
|
||||
match_state_flow(album_match(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn album_lookup_flow() {
|
||||
match_state_flow(album_lookup(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -430,4 +473,73 @@ mod tests {
|
||||
let input = app.mode().unwrap_input();
|
||||
input.confirm().unwrap_error();
|
||||
}
|
||||
|
||||
fn mbid() -> Mbid {
|
||||
"00000000-0000-0000-0000-000000000000".try_into().unwrap()
|
||||
}
|
||||
|
||||
fn input_mbid(mut app: App) -> App {
|
||||
let mbid = mbid().uuid().to_string();
|
||||
for c in mbid.chars() {
|
||||
let input = app.mode().unwrap_input();
|
||||
app = input.input(input_event(c));
|
||||
}
|
||||
app
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn select_manual_input_artist() {
|
||||
let mut mb_job_sender = MockIMbJobSender::new();
|
||||
let artist = ArtistMeta::new(ArtistId::new("Artist"));
|
||||
let requests = VecDeque::from([MbParams::lookup_artist(artist.clone(), mbid())]);
|
||||
mb_job_sender
|
||||
.expect_submit_foreground_job()
|
||||
.with(predicate::always(), predicate::eq(requests))
|
||||
.return_once(|_, _| Ok(()));
|
||||
|
||||
let matches_vec: Vec<Match<ArtistMeta>> = vec![];
|
||||
let artist_match = MatchStateInfo::artist_search(artist.clone(), matches_vec);
|
||||
let matches = AppMachine::match_state(
|
||||
inner_with_mb(music_hoard(vec![]), mb_job_sender),
|
||||
match_state(Some(artist_match)),
|
||||
);
|
||||
|
||||
// There are no matches which means that the second option should be manual input.
|
||||
let matches = matches.next_match().unwrap_match();
|
||||
let matches = matches.next_match().unwrap_match();
|
||||
|
||||
let mut app = matches.select();
|
||||
app = input_mbid(app);
|
||||
|
||||
let input = app.mode().unwrap_input();
|
||||
input.confirm();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn select_manual_input_album() {
|
||||
let mut mb_job_sender = MockIMbJobSender::new();
|
||||
let album = AlbumMeta::new("Album", 1990, None, vec![]);
|
||||
let requests = VecDeque::from([MbParams::lookup_release_group(album.clone(), mbid())]);
|
||||
mb_job_sender
|
||||
.expect_submit_foreground_job()
|
||||
.with(predicate::always(), predicate::eq(requests))
|
||||
.return_once(|_, _| Ok(()));
|
||||
|
||||
let matches_vec: Vec<Match<AlbumMeta>> = vec![];
|
||||
let album_match = MatchStateInfo::album_search(album.clone(), matches_vec);
|
||||
let matches = AppMachine::match_state(
|
||||
inner_with_mb(music_hoard(vec![]), mb_job_sender),
|
||||
match_state(Some(album_match)),
|
||||
);
|
||||
|
||||
// There are no matches which means that the second option should be manual input.
|
||||
let matches = matches.next_match().unwrap_match();
|
||||
let matches = matches.next_match().unwrap_match();
|
||||
|
||||
let mut app = matches.select();
|
||||
app = input_mbid(app);
|
||||
|
||||
let input = app.mode().unwrap_input();
|
||||
input.confirm();
|
||||
}
|
||||
}
|
||||
|
@ -222,7 +222,7 @@ mod tests {
|
||||
use musichoard::collection::Collection;
|
||||
|
||||
use crate::tui::{
|
||||
app::{AppState, IApp, IAppInput, IAppInteractBrowse},
|
||||
app::{AppState, IApp, IAppInput, IAppInteractBrowse, InputEvent},
|
||||
lib::{interface::musicbrainz::daemon::MockIMbJobSender, MockIMusicHoard},
|
||||
};
|
||||
|
||||
@ -355,6 +355,14 @@ mod tests {
|
||||
AppInner::new(music_hoard, mb_job_sender)
|
||||
}
|
||||
|
||||
pub fn input_event(c: char) -> InputEvent {
|
||||
crossterm::event::KeyEvent::new(
|
||||
crossterm::event::KeyCode::Char(c),
|
||||
crossterm::event::KeyModifiers::empty(),
|
||||
)
|
||||
.into()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn input_mode() {
|
||||
let app = App::new(music_hoard_init(vec![]), mb_job_sender());
|
||||
|
138
src/tui/lib/external/musicbrainz/daemon/mod.rs
vendored
138
src/tui/lib/external/musicbrainz/daemon/mod.rs
vendored
@ -110,7 +110,7 @@ impl IMbJobSender for JobSender {
|
||||
result_sender: ResultSender,
|
||||
requests: VecDeque<MbParams>,
|
||||
) -> Result<(), Error> {
|
||||
self.send_foreground_job(result_sender, requests)
|
||||
self.send_job(JobPriority::Foreground, result_sender, requests)
|
||||
}
|
||||
|
||||
fn submit_background_job(
|
||||
@ -118,27 +118,11 @@ impl IMbJobSender for JobSender {
|
||||
result_sender: ResultSender,
|
||||
requests: VecDeque<MbParams>,
|
||||
) -> Result<(), Error> {
|
||||
self.send_background_job(result_sender, requests)
|
||||
self.send_job(JobPriority::Background, result_sender, requests)
|
||||
}
|
||||
}
|
||||
|
||||
impl JobSender {
|
||||
fn send_foreground_job(
|
||||
&self,
|
||||
result_sender: ResultSender,
|
||||
requests: VecDeque<MbParams>,
|
||||
) -> Result<(), Error> {
|
||||
self.send_job(JobPriority::Foreground, result_sender, requests)
|
||||
}
|
||||
|
||||
fn send_background_job(
|
||||
&self,
|
||||
result_sender: ResultSender,
|
||||
requests: VecDeque<MbParams>,
|
||||
) -> Result<(), Error> {
|
||||
self.send_job(JobPriority::Background, result_sender, requests)
|
||||
}
|
||||
|
||||
fn send_job(
|
||||
&self,
|
||||
priority: JobPriority,
|
||||
@ -337,7 +321,7 @@ mod tests {
|
||||
|
||||
use crate::tui::{
|
||||
event::{Event, EventError, MockIFetchCompleteEventSender},
|
||||
lib::interface::musicbrainz::api::{Match, MockIMusicBrainz},
|
||||
lib::interface::musicbrainz::api::{Lookup, Match, MockIMusicBrainz},
|
||||
testmod::COLLECTION,
|
||||
};
|
||||
|
||||
@ -387,12 +371,28 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
fn mbid() -> Mbid {
|
||||
"00000000-0000-0000-0000-000000000000".try_into().unwrap()
|
||||
}
|
||||
|
||||
fn lookup_artist_requests() -> VecDeque<MbParams> {
|
||||
let artist = COLLECTION[3].meta.clone();
|
||||
let mbid = mbid();
|
||||
VecDeque::from([MbParams::lookup_artist(artist, mbid)])
|
||||
}
|
||||
|
||||
fn lookup_release_group_requests() -> VecDeque<MbParams> {
|
||||
let album = COLLECTION[1].albums[0].meta.clone();
|
||||
let mbid = mbid();
|
||||
VecDeque::from([MbParams::lookup_release_group(album, mbid)])
|
||||
}
|
||||
|
||||
fn search_artist_requests() -> VecDeque<MbParams> {
|
||||
let artist = COLLECTION[3].meta.clone();
|
||||
VecDeque::from([MbParams::search_artist(artist)])
|
||||
}
|
||||
|
||||
fn artist_expectations() -> (ArtistMeta, Vec<Match<ArtistMeta>>) {
|
||||
fn search_artist_expectations() -> (ArtistMeta, Vec<Match<ArtistMeta>>) {
|
||||
let artist = COLLECTION[3].meta.clone();
|
||||
|
||||
let artist_match_1 = Match::new(100, artist.clone());
|
||||
@ -420,7 +420,7 @@ mod tests {
|
||||
mbref.unwrap().mbid().clone()
|
||||
}
|
||||
|
||||
fn album_expectations_1() -> (AlbumMeta, Vec<Match<AlbumMeta>>) {
|
||||
fn search_album_expectations_1() -> (AlbumMeta, Vec<Match<AlbumMeta>>) {
|
||||
let album_1 = COLLECTION[1].albums[0].meta.clone();
|
||||
let album_4 = COLLECTION[1].albums[3].meta.clone();
|
||||
|
||||
@ -431,7 +431,7 @@ mod tests {
|
||||
(album_1, matches_1)
|
||||
}
|
||||
|
||||
fn album_expectations_4() -> (AlbumMeta, Vec<Match<AlbumMeta>>) {
|
||||
fn search_album_expectations_4() -> (AlbumMeta, Vec<Match<AlbumMeta>>) {
|
||||
let album_1 = COLLECTION[1].albums[0].meta.clone();
|
||||
let album_4 = COLLECTION[1].albums[3].meta.clone();
|
||||
|
||||
@ -515,6 +515,90 @@ mod tests {
|
||||
assert_eq!(result, Err(JobError::JobQueueEmpty));
|
||||
}
|
||||
|
||||
fn lookup_artist_expectation(
|
||||
musicbrainz: &mut MockIMusicBrainz,
|
||||
mbid: &Mbid,
|
||||
lookup: &Lookup<ArtistMeta>,
|
||||
) {
|
||||
let result = Ok(lookup.clone());
|
||||
musicbrainz
|
||||
.expect_lookup_artist()
|
||||
.with(predicate::eq(mbid.clone()))
|
||||
.times(1)
|
||||
.return_once(|_| result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn execute_lookup_artist() {
|
||||
let mut musicbrainz = musicbrainz();
|
||||
let mbid = mbid();
|
||||
let artist = COLLECTION[3].meta.clone();
|
||||
let lookup = Lookup::new(artist.clone());
|
||||
lookup_artist_expectation(&mut musicbrainz, &mbid, &lookup);
|
||||
|
||||
let mut event_sender = event_sender();
|
||||
fetch_complete_expectation(&mut event_sender, 1);
|
||||
|
||||
let (job_sender, job_receiver) = job_channel();
|
||||
let mut daemon = daemon_with(musicbrainz, job_receiver, event_sender);
|
||||
|
||||
let requests = lookup_artist_requests();
|
||||
let (result_sender, result_receiver) = mpsc::channel();
|
||||
let result = job_sender.submit_foreground_job(result_sender, requests);
|
||||
assert_eq!(result, Ok(()));
|
||||
|
||||
let result = daemon.enqueue_all_pending_jobs();
|
||||
assert_eq!(result, Ok(()));
|
||||
|
||||
let result = daemon.execute_next_job();
|
||||
assert_eq!(result, Ok(()));
|
||||
|
||||
let result = result_receiver.try_recv().unwrap();
|
||||
assert_eq!(result, Ok(MatchStateInfo::artist_lookup(artist, lookup)));
|
||||
}
|
||||
|
||||
fn lookup_release_group_expectation(
|
||||
musicbrainz: &mut MockIMusicBrainz,
|
||||
mbid: &Mbid,
|
||||
lookup: &Lookup<AlbumMeta>,
|
||||
) {
|
||||
let result = Ok(lookup.clone());
|
||||
musicbrainz
|
||||
.expect_lookup_release_group()
|
||||
.with(predicate::eq(mbid.clone()))
|
||||
.times(1)
|
||||
.return_once(|_| result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn execute_lookup_release_group() {
|
||||
let mut musicbrainz = musicbrainz();
|
||||
let mbid = mbid();
|
||||
let album = COLLECTION[1].albums[0].meta.clone();
|
||||
let lookup = Lookup::new(album.clone());
|
||||
lookup_release_group_expectation(&mut musicbrainz, &mbid, &lookup);
|
||||
|
||||
let mut event_sender = event_sender();
|
||||
fetch_complete_expectation(&mut event_sender, 1);
|
||||
|
||||
let (job_sender, job_receiver) = job_channel();
|
||||
let mut daemon = daemon_with(musicbrainz, job_receiver, event_sender);
|
||||
|
||||
let requests = lookup_release_group_requests();
|
||||
let (result_sender, result_receiver) = mpsc::channel();
|
||||
let result = job_sender.submit_foreground_job(result_sender, requests);
|
||||
assert_eq!(result, Ok(()));
|
||||
|
||||
let result = daemon.enqueue_all_pending_jobs();
|
||||
assert_eq!(result, Ok(()));
|
||||
|
||||
let result = daemon.execute_next_job();
|
||||
assert_eq!(result, Ok(()));
|
||||
|
||||
let result = result_receiver.try_recv().unwrap();
|
||||
assert_eq!(result, Ok(MatchStateInfo::album_lookup(album, lookup)));
|
||||
}
|
||||
|
||||
fn search_artist_expectation(
|
||||
musicbrainz: &mut MockIMusicBrainz,
|
||||
artist: &ArtistMeta,
|
||||
@ -531,7 +615,7 @@ mod tests {
|
||||
#[test]
|
||||
fn execute_search_artist() {
|
||||
let mut musicbrainz = musicbrainz();
|
||||
let (artist, matches) = artist_expectations();
|
||||
let (artist, matches) = search_artist_expectations();
|
||||
search_artist_expectation(&mut musicbrainz, &artist, &matches);
|
||||
|
||||
let mut event_sender = event_sender();
|
||||
@ -575,8 +659,8 @@ mod tests {
|
||||
fn execute_search_release_groups() {
|
||||
let mut musicbrainz = musicbrainz();
|
||||
let arid = album_arid_expectation();
|
||||
let (album_1, matches_1) = album_expectations_1();
|
||||
let (album_4, matches_4) = album_expectations_4();
|
||||
let (album_1, matches_1) = search_album_expectations_1();
|
||||
let (album_4, matches_4) = search_album_expectations_4();
|
||||
|
||||
let mut seq = Sequence::new();
|
||||
search_release_group_expectation(&mut musicbrainz, &mut seq, &arid, &album_1, &matches_1);
|
||||
@ -613,7 +697,7 @@ mod tests {
|
||||
fn execute_search_release_groups_result_disconnect() {
|
||||
let mut musicbrainz = musicbrainz();
|
||||
let arid = album_arid_expectation();
|
||||
let (album_1, matches_1) = album_expectations_1();
|
||||
let (album_1, matches_1) = search_album_expectations_1();
|
||||
|
||||
let mut seq = Sequence::new();
|
||||
search_release_group_expectation(&mut musicbrainz, &mut seq, &arid, &album_1, &matches_1);
|
||||
@ -643,7 +727,7 @@ mod tests {
|
||||
#[test]
|
||||
fn execute_search_artist_event_disconnect() {
|
||||
let mut musicbrainz = musicbrainz();
|
||||
let (artist, matches) = artist_expectations();
|
||||
let (artist, matches) = search_artist_expectations();
|
||||
search_artist_expectation(&mut musicbrainz, &artist, &matches);
|
||||
|
||||
let mut event_sender = event_sender();
|
||||
|
@ -206,8 +206,8 @@ mod tests {
|
||||
};
|
||||
|
||||
use crate::tui::{
|
||||
app::{AppPublic, AppPublicInner, Delta, MatchStatePublic, MissOption, SearchOption},
|
||||
lib::interface::musicbrainz::api::Match,
|
||||
app::{AppPublic, AppPublicInner, Delta, MatchStatePublic},
|
||||
lib::interface::musicbrainz::api::{Lookup, Match},
|
||||
testmod::COLLECTION,
|
||||
tests::terminal,
|
||||
};
|
||||
@ -250,20 +250,6 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
fn artist_matches(matching: ArtistMeta, list: Vec<Match<ArtistMeta>>) -> MatchStateInfo {
|
||||
let mut list: Vec<SearchOption<ArtistMeta>> = list.into_iter().map(Into::into).collect();
|
||||
list.push(SearchOption::None(MissOption::CannotHaveMbid));
|
||||
list.push(SearchOption::None(MissOption::ManualInputMbid));
|
||||
MatchStateInfo::artist_search(matching, list)
|
||||
}
|
||||
|
||||
fn album_matches(matching: AlbumMeta, list: Vec<Match<AlbumMeta>>) -> MatchStateInfo {
|
||||
let mut list: Vec<SearchOption<AlbumMeta>> = list.into_iter().map(Into::into).collect();
|
||||
list.push(SearchOption::None(MissOption::CannotHaveMbid));
|
||||
list.push(SearchOption::None(MissOption::ManualInputMbid));
|
||||
MatchStateInfo::album_search(matching, list)
|
||||
}
|
||||
|
||||
fn draw_test_suite(collection: &Collection, selection: &mut Selection) {
|
||||
let mut terminal = terminal();
|
||||
|
||||
@ -354,76 +340,92 @@ mod tests {
|
||||
terminal.draw(|frame| Ui::render(&mut app, frame)).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn draw_artist_matches() {
|
||||
let collection = &COLLECTION;
|
||||
let mut selection = Selection::new(collection);
|
||||
|
||||
let mut terminal = terminal();
|
||||
|
||||
let artist = ArtistMeta::new(ArtistId::new("an artist"));
|
||||
let artist_match = Match {
|
||||
score: 80,
|
||||
item: artist.clone(),
|
||||
disambiguation: None,
|
||||
};
|
||||
let list = vec![artist_match.clone(), artist_match.clone()];
|
||||
let artist_matches = artist_matches(artist, list);
|
||||
|
||||
let mut widget_state = WidgetState::default();
|
||||
widget_state.list.select(Some(0));
|
||||
|
||||
let mut app = AppPublic {
|
||||
inner: public_inner(collection, &mut selection),
|
||||
state: AppState::Match(MatchStatePublic {
|
||||
info: Some(&artist_matches),
|
||||
state: &mut widget_state,
|
||||
}),
|
||||
input: None,
|
||||
};
|
||||
terminal.draw(|frame| Ui::render(&mut app, frame)).unwrap();
|
||||
|
||||
let input = tui_input::Input::default();
|
||||
app.input = Some(&input);
|
||||
terminal.draw(|frame| Ui::render(&mut app, frame)).unwrap();
|
||||
fn artist_meta() -> ArtistMeta {
|
||||
ArtistMeta::new(ArtistId::new("an artist"))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn draw_album_matches() {
|
||||
let collection = &COLLECTION;
|
||||
let mut selection = Selection::new(collection);
|
||||
fn artist_matches() -> MatchStateInfo {
|
||||
let artist = artist_meta();
|
||||
let artist_match = Match::new(80, artist.clone());
|
||||
let list = vec![artist_match.clone(), artist_match.clone()];
|
||||
|
||||
let mut terminal = terminal();
|
||||
let mut info = MatchStateInfo::artist_search(artist, list);
|
||||
info.push_cannot_have_mbid();
|
||||
info.push_manual_input_mbid();
|
||||
info
|
||||
}
|
||||
|
||||
let album = AlbumMeta::new(
|
||||
fn artist_lookup() -> MatchStateInfo {
|
||||
let artist = artist_meta();
|
||||
let artist_lookup = Lookup::new(artist.clone());
|
||||
|
||||
let mut info = MatchStateInfo::artist_lookup(artist, artist_lookup);
|
||||
info.push_cannot_have_mbid();
|
||||
info.push_manual_input_mbid();
|
||||
info
|
||||
}
|
||||
|
||||
fn album_meta() -> AlbumMeta {
|
||||
AlbumMeta::new(
|
||||
AlbumId::new("An Album"),
|
||||
AlbumDate::new(Some(1990), Some(5), None),
|
||||
Some(AlbumPrimaryType::Album),
|
||||
vec![AlbumSecondaryType::Live, AlbumSecondaryType::Compilation],
|
||||
);
|
||||
let album_match = Match {
|
||||
score: 80,
|
||||
item: album.clone(),
|
||||
disambiguation: None,
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
fn album_matches() -> MatchStateInfo {
|
||||
let album = album_meta();
|
||||
let album_match = Match::new(80, album.clone());
|
||||
let list = vec![album_match.clone(), album_match.clone()];
|
||||
let album_matches = album_matches(album, list);
|
||||
|
||||
let mut widget_state = WidgetState::default();
|
||||
widget_state.list.select(Some(0));
|
||||
let mut info = MatchStateInfo::album_search(album, list);
|
||||
info.push_cannot_have_mbid();
|
||||
info.push_manual_input_mbid();
|
||||
info
|
||||
}
|
||||
|
||||
let mut app = AppPublic {
|
||||
inner: public_inner(collection, &mut selection),
|
||||
state: AppState::Match(MatchStatePublic {
|
||||
info: Some(&album_matches),
|
||||
state: &mut widget_state,
|
||||
}),
|
||||
input: None,
|
||||
};
|
||||
terminal.draw(|frame| Ui::render(&mut app, frame)).unwrap();
|
||||
fn album_lookup() -> MatchStateInfo {
|
||||
let album = album_meta();
|
||||
let album_lookup = Lookup::new(album.clone());
|
||||
|
||||
let input = tui_input::Input::default();
|
||||
app.input = Some(&input);
|
||||
terminal.draw(|frame| Ui::render(&mut app, frame)).unwrap();
|
||||
let mut info = MatchStateInfo::album_lookup(album, album_lookup);
|
||||
info.push_cannot_have_mbid();
|
||||
info.push_manual_input_mbid();
|
||||
info
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn draw_matche_state_suite() {
|
||||
let collection = &COLLECTION;
|
||||
let mut selection = Selection::new(collection);
|
||||
|
||||
let mut terminal = terminal();
|
||||
|
||||
let match_state_infos = vec![
|
||||
artist_matches(),
|
||||
album_matches(),
|
||||
artist_lookup(),
|
||||
album_lookup(),
|
||||
];
|
||||
|
||||
for info in match_state_infos.iter() {
|
||||
let mut widget_state = WidgetState::default();
|
||||
widget_state.list.select(Some(0));
|
||||
|
||||
let mut app = AppPublic {
|
||||
inner: public_inner(collection, &mut selection),
|
||||
state: AppState::Match(MatchStatePublic {
|
||||
info: Some(info),
|
||||
state: &mut widget_state,
|
||||
}),
|
||||
input: None,
|
||||
};
|
||||
terminal.draw(|frame| Ui::render(&mut app, frame)).unwrap();
|
||||
|
||||
let input = tui_input::Input::default();
|
||||
app.input = Some(&input);
|
||||
terminal.draw(|frame| Ui::render(&mut app, frame)).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user