Clean up interfaces #62
@ -1,178 +0,0 @@
|
||||
//! Module for managing the music collection, i.e. "The Music Hoard".
|
||||
|
||||
use std::fmt;
|
||||
|
||||
use crate::{
|
||||
database::{self, Database},
|
||||
library::{self, Library, Query},
|
||||
Artist,
|
||||
};
|
||||
|
||||
/// The collection type.
|
||||
pub type Collection = Vec<Artist>;
|
||||
|
||||
/// Error type for collection manager.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum Error {
|
||||
/// The [`CollectionManager`] failed to read/write from/to the library.
|
||||
LibraryError(String),
|
||||
/// The [`CollectionManager`] failed to read/write from/to the database.
|
||||
DatabaseError(String),
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
Self::LibraryError(ref s) => write!(f, "failed to read/write from/to the library: {s}"),
|
||||
Self::DatabaseError(ref s) => {
|
||||
write!(f, "failed to read/write from/to the database: {s}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<library::Error> for Error {
|
||||
fn from(err: library::Error) -> Error {
|
||||
Error::LibraryError(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<database::Error> for Error {
|
||||
fn from(err: database::Error) -> Error {
|
||||
Error::DatabaseError(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
pub trait CollectionManager {
|
||||
/// Rescan the library and integrate any updates into the collection.
|
||||
fn rescan_library(&mut self) -> Result<(), Error>;
|
||||
|
||||
/// Save the collection state to the database.
|
||||
fn save_to_database(&mut self) -> Result<(), Error>;
|
||||
|
||||
/// Get the current collection.
|
||||
fn get_collection(&self) -> &Collection;
|
||||
}
|
||||
|
||||
/// The collection manager. It is responsible for pulling information from both the library and the
|
||||
/// database, ensuring its consistent and writing back any changes.
|
||||
pub struct MhCollectionManager<LIB, DB> {
|
||||
library: LIB,
|
||||
database: DB,
|
||||
collection: Collection,
|
||||
}
|
||||
|
||||
impl<LIB: Library, DB: Database> MhCollectionManager<LIB, DB> {
|
||||
/// Create a new [`CollectionManager`] with the provided [`Library`] and [`Database`].
|
||||
pub fn new(library: LIB, database: DB) -> Self {
|
||||
MhCollectionManager {
|
||||
library,
|
||||
database,
|
||||
collection: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<LIB: Library, DB: Database> CollectionManager for MhCollectionManager<LIB, DB> {
|
||||
fn rescan_library(&mut self) -> Result<(), Error> {
|
||||
self.collection = self.library.list(&Query::new())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn save_to_database(&mut self) -> Result<(), Error> {
|
||||
self.database.write(&self.collection)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_collection(&self) -> &Collection {
|
||||
&self.collection
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use mockall::predicate;
|
||||
|
||||
use crate::{
|
||||
collection::Collection,
|
||||
database::{self, MockDatabase},
|
||||
library::{self, MockLibrary, Query},
|
||||
tests::COLLECTION,
|
||||
};
|
||||
|
||||
use super::{CollectionManager, Error, MhCollectionManager};
|
||||
|
||||
#[test]
|
||||
fn read_get_write() {
|
||||
let mut library = MockLibrary::new();
|
||||
let mut database = MockDatabase::new();
|
||||
|
||||
let library_input = Query::new();
|
||||
let library_result = Ok(COLLECTION.to_owned());
|
||||
|
||||
let database_input = COLLECTION.to_owned();
|
||||
let database_result = Ok(());
|
||||
|
||||
library
|
||||
.expect_list()
|
||||
.with(predicate::eq(library_input))
|
||||
.times(1)
|
||||
.return_once(|_| library_result);
|
||||
|
||||
database
|
||||
.expect_write()
|
||||
.with(predicate::eq(database_input))
|
||||
.times(1)
|
||||
.return_once(|_: &Collection| database_result);
|
||||
|
||||
let mut collection_manager = MhCollectionManager::new(library, database);
|
||||
|
||||
collection_manager.rescan_library().unwrap();
|
||||
assert_eq!(collection_manager.get_collection(), &*COLLECTION);
|
||||
collection_manager.save_to_database().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn library_error() {
|
||||
let mut library = MockLibrary::new();
|
||||
let database = MockDatabase::new();
|
||||
|
||||
let library_result = Err(library::Error::Invalid(String::from("invalid data")));
|
||||
|
||||
library
|
||||
.expect_list()
|
||||
.times(1)
|
||||
.return_once(|_| library_result);
|
||||
|
||||
let mut collection_manager = MhCollectionManager::new(library, database);
|
||||
|
||||
let actual_err = collection_manager.rescan_library().unwrap_err();
|
||||
let expected_err =
|
||||
Error::LibraryError(library::Error::Invalid(String::from("invalid data")).to_string());
|
||||
|
||||
assert_eq!(actual_err, expected_err);
|
||||
assert_eq!(actual_err.to_string(), expected_err.to_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn database_error() {
|
||||
let library = MockLibrary::new();
|
||||
let mut database = MockDatabase::new();
|
||||
|
||||
let database_result = Err(database::Error::IoError(String::from("I/O error")));
|
||||
|
||||
database
|
||||
.expect_write()
|
||||
.times(1)
|
||||
.return_once(|_: &Collection| database_result);
|
||||
|
||||
let mut collection_manager = MhCollectionManager::new(library, database);
|
||||
|
||||
let actual_err = collection_manager.save_to_database().unwrap_err();
|
||||
let expected_err =
|
||||
Error::DatabaseError(database::Error::IoError(String::from("I/O error")).to_string());
|
||||
|
||||
assert_eq!(actual_err, expected_err);
|
||||
assert_eq!(actual_err.to_string(), expected_err.to_string());
|
||||
}
|
||||
}
|
156
src/lib.rs
156
src/lib.rs
@ -1,12 +1,15 @@
|
||||
//! MusicHoard - a music collection manager.
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
pub mod collection;
|
||||
pub mod database;
|
||||
pub mod library;
|
||||
|
||||
use std::fmt;
|
||||
|
||||
use database::Database;
|
||||
use library::{Library, Query};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
/// [MusicBrainz Identifier](https://musicbrainz.org/doc/MusicBrainz_Identifier) (MBID).
|
||||
pub type Mbid = Uuid;
|
||||
|
||||
@ -53,15 +56,160 @@ pub struct Artist {
|
||||
pub albums: Vec<Album>,
|
||||
}
|
||||
|
||||
/// The collection type. Currently, a collection is a list of artists.
|
||||
pub type Collection = Vec<Artist>;
|
||||
|
||||
/// Error type for `musichoard`.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum Error {
|
||||
/// The [`MusicHoard`] failed to read/write from/to the library.
|
||||
LibraryError(String),
|
||||
/// The [`MusicHoard`] failed to read/write from/to the database.
|
||||
DatabaseError(String),
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
Self::LibraryError(ref s) => write!(f, "failed to read/write from/to the library: {s}"),
|
||||
Self::DatabaseError(ref s) => {
|
||||
write!(f, "failed to read/write from/to the database: {s}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<library::Error> for Error {
|
||||
fn from(err: library::Error) -> Error {
|
||||
Error::LibraryError(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<database::Error> for Error {
|
||||
fn from(err: database::Error) -> Error {
|
||||
Error::DatabaseError(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
/// The Music Hoard. It is responsible for pulling information from both the library and the
|
||||
/// database, ensuring its consistent and writing back any changes.
|
||||
pub struct MusicHoard<LIB, DB> {
|
||||
library: LIB,
|
||||
database: DB,
|
||||
collection: Collection,
|
||||
}
|
||||
|
||||
impl<LIB: Library, DB: Database> MusicHoard<LIB, DB> {
|
||||
/// Create a new [`MusicHoard`] with the provided [`Library`] and [`Database`].
|
||||
pub fn new(library: LIB, database: DB) -> Self {
|
||||
MusicHoard {
|
||||
library,
|
||||
database,
|
||||
collection: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rescan_library(&mut self) -> Result<(), Error> {
|
||||
self.collection = self.library.list(&Query::new())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn save_to_database(&mut self) -> Result<(), Error> {
|
||||
self.database.write(&self.collection)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_collection(&self) -> &Collection {
|
||||
&self.collection
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[macro_use]
|
||||
mod testlib;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use mockall::predicate;
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
use crate::{database::MockDatabase, library::MockLibrary};
|
||||
|
||||
use super::*;
|
||||
|
||||
pub static COLLECTION: Lazy<Vec<Artist>> = Lazy::new(|| collection!());
|
||||
|
||||
#[test]
|
||||
fn read_get_write() {
|
||||
let mut library = MockLibrary::new();
|
||||
let mut database = MockDatabase::new();
|
||||
|
||||
let library_input = Query::new();
|
||||
let library_result = Ok(COLLECTION.to_owned());
|
||||
|
||||
let database_input = COLLECTION.to_owned();
|
||||
let database_result = Ok(());
|
||||
|
||||
library
|
||||
.expect_list()
|
||||
.with(predicate::eq(library_input))
|
||||
.times(1)
|
||||
.return_once(|_| library_result);
|
||||
|
||||
database
|
||||
.expect_write()
|
||||
.with(predicate::eq(database_input))
|
||||
.times(1)
|
||||
.return_once(|_: &Collection| database_result);
|
||||
|
||||
let mut music_hoard = MusicHoard::new(library, database);
|
||||
|
||||
music_hoard.rescan_library().unwrap();
|
||||
assert_eq!(music_hoard.get_collection(), &*COLLECTION);
|
||||
music_hoard.save_to_database().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn library_error() {
|
||||
let mut library = MockLibrary::new();
|
||||
let database = MockDatabase::new();
|
||||
|
||||
let library_result = Err(library::Error::Invalid(String::from("invalid data")));
|
||||
|
||||
library
|
||||
.expect_list()
|
||||
.times(1)
|
||||
.return_once(|_| library_result);
|
||||
|
||||
let mut music_hoard = MusicHoard::new(library, database);
|
||||
|
||||
let actual_err = music_hoard.rescan_library().unwrap_err();
|
||||
let expected_err =
|
||||
Error::LibraryError(library::Error::Invalid(String::from("invalid data")).to_string());
|
||||
|
||||
assert_eq!(actual_err, expected_err);
|
||||
assert_eq!(actual_err.to_string(), expected_err.to_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn database_error() {
|
||||
let library = MockLibrary::new();
|
||||
let mut database = MockDatabase::new();
|
||||
|
||||
let database_result = Err(database::Error::IoError(String::from("I/O error")));
|
||||
|
||||
database
|
||||
.expect_write()
|
||||
.times(1)
|
||||
.return_once(|_: &Collection| database_result);
|
||||
|
||||
let mut music_hoard = MusicHoard::new(library, database);
|
||||
|
||||
let actual_err = music_hoard.save_to_database().unwrap_err();
|
||||
let expected_err =
|
||||
Error::DatabaseError(database::Error::IoError(String::from("I/O error")).to_string());
|
||||
|
||||
assert_eq!(actual_err, expected_err);
|
||||
assert_eq!(actual_err.to_string(), expected_err.to_string());
|
||||
}
|
||||
}
|
||||
|
18
src/main.rs
18
src/main.rs
@ -5,7 +5,6 @@ use ratatui::{backend::CrosstermBackend, Terminal};
|
||||
use structopt::StructOpt;
|
||||
|
||||
use musichoard::{
|
||||
collection::MhCollectionManager,
|
||||
database::{
|
||||
json::{backend::JsonDatabaseFileBackend, JsonDatabase},
|
||||
Database,
|
||||
@ -17,6 +16,7 @@ use musichoard::{
|
||||
},
|
||||
Library,
|
||||
},
|
||||
MusicHoard,
|
||||
};
|
||||
|
||||
mod tui;
|
||||
@ -40,7 +40,7 @@ struct Opt {
|
||||
}
|
||||
|
||||
fn with<LIB: Library, DB: Database>(lib: LIB, db: DB) {
|
||||
let collection_manager = MhCollectionManager::new(lib, db);
|
||||
let music_hoard = MusicHoard::new(lib, db);
|
||||
|
||||
// Initialize the terminal user interface.
|
||||
let backend = CrosstermBackend::new(io::stdout());
|
||||
@ -50,7 +50,7 @@ fn with<LIB: Library, DB: Database>(lib: LIB, db: DB) {
|
||||
let listener = TuiEventListener::new(channel.sender());
|
||||
let handler = TuiEventHandler::new(channel.receiver());
|
||||
|
||||
let ui = MhUi::new(collection_manager).expect("failed to initialise ui");
|
||||
let ui = MhUi::new(music_hoard).expect("failed to initialise ui");
|
||||
|
||||
// Run the TUI application.
|
||||
Tui::run(terminal, ui, handler, listener).expect("failed to run tui");
|
||||
@ -85,21 +85,9 @@ mod testlib;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use mockall::mock;
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
use musichoard::collection::{self, Collection, CollectionManager};
|
||||
use musichoard::*;
|
||||
|
||||
pub static COLLECTION: Lazy<Vec<Artist>> = Lazy::new(|| collection!());
|
||||
|
||||
mock! {
|
||||
pub CollectionManager {}
|
||||
|
||||
impl CollectionManager for CollectionManager {
|
||||
fn rescan_library(&mut self) -> Result<(), collection::Error>;
|
||||
fn save_to_database(&mut self) -> Result<(), collection::Error>;
|
||||
fn get_collection(&self) -> &Collection;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
30
src/tui/lib.rs
Normal file
30
src/tui/lib.rs
Normal file
@ -0,0 +1,30 @@
|
||||
use musichoard::{MusicHoard, library::Library, database::Database, Collection};
|
||||
|
||||
#[cfg(test)]
|
||||
use mockall::automock;
|
||||
|
||||
use super::Error;
|
||||
|
||||
#[cfg_attr(test, automock)]
|
||||
pub trait IMusicHoard {
|
||||
fn rescan_library(&mut self) -> Result<(), Error>;
|
||||
fn get_collection(&self) -> &Collection;
|
||||
}
|
||||
|
||||
impl From<musichoard::Error> for Error {
|
||||
fn from(err: musichoard::Error) -> Error {
|
||||
Error::Lib(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
// GRCOV_EXCL_START
|
||||
impl<LIB: Library, DB: Database> IMusicHoard for MusicHoard<LIB, DB> {
|
||||
fn rescan_library(&mut self) -> Result<(), Error> {
|
||||
Ok(MusicHoard::rescan_library(self)?)
|
||||
}
|
||||
|
||||
fn get_collection(&self) -> &Collection {
|
||||
MusicHoard::get_collection(self)
|
||||
}
|
||||
}
|
||||
// GRCOV_EXCL_STOP
|
@ -1,16 +1,17 @@
|
||||
use crossterm::event::{DisableMouseCapture, EnableMouseCapture};
|
||||
use crossterm::terminal::{self, EnterAlternateScreen, LeaveAlternateScreen};
|
||||
use musichoard::collection;
|
||||
use ratatui::backend::Backend;
|
||||
use ratatui::Terminal;
|
||||
use std::io;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
pub mod event;
|
||||
pub mod handler;
|
||||
pub mod listener;
|
||||
pub mod ui;
|
||||
|
||||
mod lib;
|
||||
|
||||
use crossterm::event::{DisableMouseCapture, EnableMouseCapture};
|
||||
use crossterm::terminal::{self, EnterAlternateScreen, LeaveAlternateScreen};
|
||||
use ratatui::backend::Backend;
|
||||
use ratatui::Terminal;
|
||||
use std::io;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use self::event::EventError;
|
||||
use self::handler::EventHandler;
|
||||
use self::listener::EventListener;
|
||||
@ -18,18 +19,12 @@ use self::ui::Ui;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum Error {
|
||||
Collection(String),
|
||||
Lib(String),
|
||||
Io(String),
|
||||
Event(String),
|
||||
ListenerPanic,
|
||||
}
|
||||
|
||||
impl From<collection::Error> for Error {
|
||||
fn from(err: collection::Error) -> Error {
|
||||
Error::Collection(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<io::Error> for Error {
|
||||
fn from(err: io::Error) -> Error {
|
||||
Error::Io(err.to_string())
|
||||
@ -160,14 +155,15 @@ impl<B: Backend, UI: Ui> Tui<B, UI> {
|
||||
mod tests {
|
||||
use std::{io, thread};
|
||||
|
||||
use musichoard::collection::{self, Collection};
|
||||
use musichoard::Collection;
|
||||
use ratatui::{backend::TestBackend, Terminal};
|
||||
|
||||
use crate::tests::{MockCollectionManager, COLLECTION};
|
||||
use crate::tests::COLLECTION;
|
||||
|
||||
use super::{
|
||||
event::EventError,
|
||||
handler::MockEventHandler,
|
||||
lib::MockIMusicHoard,
|
||||
listener::MockEventListener,
|
||||
ui::{MhUi, Ui},
|
||||
Error, Tui,
|
||||
@ -178,17 +174,13 @@ mod tests {
|
||||
Terminal::new(backend).unwrap()
|
||||
}
|
||||
|
||||
pub fn ui(collection: Collection) -> MhUi<MockCollectionManager> {
|
||||
let mut collection_manager = MockCollectionManager::new();
|
||||
pub fn ui(collection: Collection) -> MhUi<MockIMusicHoard> {
|
||||
let mut music_hoard = MockIMusicHoard::new();
|
||||
|
||||
collection_manager
|
||||
.expect_rescan_library()
|
||||
.returning(|| Ok(()));
|
||||
collection_manager
|
||||
.expect_get_collection()
|
||||
.return_const(collection);
|
||||
music_hoard.expect_rescan_library().returning(|| Ok(()));
|
||||
music_hoard.expect_get_collection().return_const(collection);
|
||||
|
||||
MhUi::new(collection_manager).unwrap()
|
||||
MhUi::new(music_hoard).unwrap()
|
||||
}
|
||||
|
||||
fn listener() -> MockEventListener {
|
||||
@ -202,11 +194,11 @@ mod tests {
|
||||
listener
|
||||
}
|
||||
|
||||
fn handler() -> MockEventHandler<MhUi<MockCollectionManager>> {
|
||||
fn handler() -> MockEventHandler<MhUi<MockIMusicHoard>> {
|
||||
let mut handler = MockEventHandler::new();
|
||||
handler
|
||||
.expect_handle_next_event()
|
||||
.return_once(|ui: &mut MhUi<MockCollectionManager>| {
|
||||
.return_once(|ui: &mut MhUi<MockIMusicHoard>| {
|
||||
ui.quit();
|
||||
Ok(())
|
||||
});
|
||||
@ -292,12 +284,12 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn errors() {
|
||||
let collection_err: Error = collection::Error::DatabaseError(String::from("")).into();
|
||||
let lib_err: Error = musichoard::Error::DatabaseError(String::from("")).into();
|
||||
let io_err: Error = io::Error::new(io::ErrorKind::Interrupted, "error").into();
|
||||
let event_err: Error = EventError::Recv.into();
|
||||
let listener_err = Error::ListenerPanic;
|
||||
|
||||
assert!(!format!("{:?}", collection_err).is_empty());
|
||||
assert!(!format!("{:?}", lib_err).is_empty());
|
||||
assert!(!format!("{:?}", io_err).is_empty());
|
||||
assert!(!format!("{:?}", event_err).is_empty());
|
||||
assert!(!format!("{:?}", listener_err).is_empty());
|
||||
|
@ -1,7 +1,4 @@
|
||||
use musichoard::{
|
||||
collection::{Collection, CollectionManager},
|
||||
Album, Artist, Track, TrackFormat,
|
||||
};
|
||||
use musichoard::{Album, Artist, Collection, Track, TrackFormat};
|
||||
use ratatui::{
|
||||
backend::Backend,
|
||||
layout::{Alignment, Rect},
|
||||
@ -10,7 +7,7 @@ use ratatui::{
|
||||
Frame,
|
||||
};
|
||||
|
||||
use super::Error;
|
||||
use super::{lib::IMusicHoard, Error};
|
||||
|
||||
struct TrackSelection {
|
||||
state: ListState,
|
||||
@ -239,8 +236,8 @@ impl Selection {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MhUi<CM> {
|
||||
collection_manager: CM,
|
||||
pub struct MhUi<MH> {
|
||||
music_hoard: MH,
|
||||
selection: Selection,
|
||||
running: bool,
|
||||
}
|
||||
@ -428,12 +425,12 @@ impl<'a, 'b> TrackState<'a, 'b> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<CM: CollectionManager> MhUi<CM> {
|
||||
pub fn new(mut collection_manager: CM) -> Result<Self, Error> {
|
||||
collection_manager.rescan_library()?;
|
||||
let selection = Selection::new(Some(collection_manager.get_collection()));
|
||||
impl<MH: IMusicHoard> MhUi<MH> {
|
||||
pub fn new(mut music_hoard: MH) -> Result<Self, Error> {
|
||||
music_hoard.rescan_library()?;
|
||||
let selection = Selection::new(Some(music_hoard.get_collection()));
|
||||
Ok(MhUi {
|
||||
collection_manager,
|
||||
music_hoard,
|
||||
selection,
|
||||
running: true,
|
||||
})
|
||||
@ -525,7 +522,7 @@ pub trait Ui {
|
||||
fn render<B: Backend>(&mut self, frame: &mut Frame<'_, B>);
|
||||
}
|
||||
|
||||
impl<CM: CollectionManager> Ui for MhUi<CM> {
|
||||
impl<MH: IMusicHoard> Ui for MhUi<MH> {
|
||||
fn is_running(&self) -> bool {
|
||||
self.running
|
||||
}
|
||||
@ -544,19 +541,19 @@ impl<CM: CollectionManager> Ui for MhUi<CM> {
|
||||
|
||||
fn increment_selection(&mut self) {
|
||||
self.selection
|
||||
.increment_selection(self.collection_manager.get_collection());
|
||||
.increment_selection(self.music_hoard.get_collection());
|
||||
}
|
||||
|
||||
fn decrement_selection(&mut self) {
|
||||
self.selection
|
||||
.decrement_selection(self.collection_manager.get_collection());
|
||||
.decrement_selection(self.music_hoard.get_collection());
|
||||
}
|
||||
|
||||
fn render<B: Backend>(&mut self, frame: &mut Frame<'_, B>) {
|
||||
let active = self.selection.active;
|
||||
let areas = FrameArea::new(frame.size());
|
||||
|
||||
let artists = self.collection_manager.get_collection();
|
||||
let artists = self.music_hoard.get_collection();
|
||||
let artist_selection = &mut self.selection.artist;
|
||||
let artist_state = ArtistState::new(
|
||||
active == Category::Artist,
|
||||
@ -600,7 +597,8 @@ impl<CM: CollectionManager> Ui for MhUi<CM> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::tests::{MockCollectionManager, COLLECTION};
|
||||
use crate::tests::COLLECTION;
|
||||
use crate::tui::lib::MockIMusicHoard;
|
||||
use crate::tui::tests::{terminal, ui};
|
||||
|
||||
use super::*;
|
||||
@ -759,17 +757,17 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn ui_running() {
|
||||
let mut collection_manager = MockCollectionManager::new();
|
||||
let mut music_hoard = MockIMusicHoard::new();
|
||||
|
||||
collection_manager
|
||||
music_hoard
|
||||
.expect_rescan_library()
|
||||
.times(1)
|
||||
.return_once(|| Ok(()));
|
||||
collection_manager
|
||||
music_hoard
|
||||
.expect_get_collection()
|
||||
.return_const(COLLECTION.to_owned());
|
||||
|
||||
let mut ui = MhUi::new(collection_manager).unwrap();
|
||||
let mut ui = MhUi::new(music_hoard).unwrap();
|
||||
assert!(ui.is_running());
|
||||
|
||||
ui.quit();
|
||||
@ -778,17 +776,17 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn ui_modifiers() {
|
||||
let mut collection_manager = MockCollectionManager::new();
|
||||
let mut music_hoard = MockIMusicHoard::new();
|
||||
|
||||
collection_manager
|
||||
music_hoard
|
||||
.expect_rescan_library()
|
||||
.times(1)
|
||||
.return_once(|| Ok(()));
|
||||
collection_manager
|
||||
music_hoard
|
||||
.expect_get_collection()
|
||||
.return_const(COLLECTION.to_owned());
|
||||
|
||||
let mut ui = MhUi::new(collection_manager).unwrap();
|
||||
let mut ui = MhUi::new(music_hoard).unwrap();
|
||||
assert!(ui.is_running());
|
||||
|
||||
assert_eq!(ui.selection.active, Category::Artist);
|
||||
@ -877,19 +875,17 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn app_no_tracks() {
|
||||
let mut collection_manager = MockCollectionManager::new();
|
||||
let mut music_hoard = MockIMusicHoard::new();
|
||||
let mut collection = COLLECTION.to_owned();
|
||||
collection[0].albums[0].tracks = vec![];
|
||||
|
||||
collection_manager
|
||||
music_hoard
|
||||
.expect_rescan_library()
|
||||
.times(1)
|
||||
.return_once(|| Ok(()));
|
||||
collection_manager
|
||||
.expect_get_collection()
|
||||
.return_const(collection);
|
||||
music_hoard.expect_get_collection().return_const(collection);
|
||||
|
||||
let mut app = MhUi::new(collection_manager).unwrap();
|
||||
let mut app = MhUi::new(music_hoard).unwrap();
|
||||
assert!(app.is_running());
|
||||
|
||||
assert_eq!(app.selection.active, Category::Artist);
|
||||
@ -915,19 +911,17 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn app_no_albums() {
|
||||
let mut collection_manager = MockCollectionManager::new();
|
||||
let mut music_hoard = MockIMusicHoard::new();
|
||||
let mut collection = COLLECTION.to_owned();
|
||||
collection[0].albums = vec![];
|
||||
|
||||
collection_manager
|
||||
music_hoard
|
||||
.expect_rescan_library()
|
||||
.times(1)
|
||||
.return_once(|| Ok(()));
|
||||
collection_manager
|
||||
.expect_get_collection()
|
||||
.return_const(collection);
|
||||
music_hoard.expect_get_collection().return_const(collection);
|
||||
|
||||
let mut app = MhUi::new(collection_manager).unwrap();
|
||||
let mut app = MhUi::new(music_hoard).unwrap();
|
||||
assert!(app.is_running());
|
||||
|
||||
assert_eq!(app.selection.active, Category::Artist);
|
||||
@ -966,18 +960,16 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn app_no_artists() {
|
||||
let mut collection_manager = MockCollectionManager::new();
|
||||
let mut music_hoard = MockIMusicHoard::new();
|
||||
let collection = vec![];
|
||||
|
||||
collection_manager
|
||||
music_hoard
|
||||
.expect_rescan_library()
|
||||
.times(1)
|
||||
.return_once(|| Ok(()));
|
||||
collection_manager
|
||||
.expect_get_collection()
|
||||
.return_const(collection);
|
||||
music_hoard.expect_get_collection().return_const(collection);
|
||||
|
||||
let mut app = MhUi::new(collection_manager).unwrap();
|
||||
let mut app = MhUi::new(music_hoard).unwrap();
|
||||
assert!(app.is_running());
|
||||
|
||||
assert_eq!(app.selection.active, Category::Artist);
|
||||
|
Loading…
Reference in New Issue
Block a user