Unit test collection module

This commit is contained in:
Wojciech Kozlowski 2023-04-12 22:09:56 +02:00
parent acebc47946
commit e0da5d20a9
7 changed files with 114 additions and 24 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
/target
/codecov

View File

@ -12,21 +12,23 @@ cargo install grcov
### Generating Code Coverage
```sh
env CARGO_TARGET_DIR=codecov \
cargo clean
env RUSTFLAGS="-C instrument-coverage" \
LLVM_PROFILE_FILE="target/debug/profraw/musichoard-%p-%m.profraw" \
LLVM_PROFILE_FILE="codecov/debug/profraw/musichoard-%p-%m.profraw" \
CARGO_TARGET_DIR=codecov \
cargo test
grcov target/debug/profraw \
--binary-path ./target/debug/ \
grcov codecov/debug/profraw \
--binary-path ./codecov/debug/ \
--output-types html \
--source-dir . \
--ignore-not-existing \
--ignore "tests/*" \
--ignore "src/main.rs" \
--excl-start "mod tests \{" \
--output-path ./target/debug/coverage/
xdg-open target/debug/coverage/index.html
--output-path ./codecov/debug/coverage/
xdg-open codecov/debug/coverage/index.html
```
Note that some changes may not be visible until `target/debug/coverage` is removed and the `grcov`
Note that some changes may not be visible until `codecov/debug/coverage` is removed and the `grcov`
command is rerun.

View File

@ -12,7 +12,7 @@ use crate::{
pub type Collection = Vec<Artist>;
/// Error type for collection manager.
#[derive(Debug)]
#[derive(Debug, PartialEq, Eq)]
pub enum Error {
/// The [`CollectionManager`] failed to read/write from/to the library.
LibraryError(String),
@ -81,3 +81,91 @@ impl CollectionManager {
&self.collection
}
}
#[cfg(test)]
mod tests {
use mockall::predicate;
use crate::{
database::{self, MockDatabase},
library::{self, MockLibrary, Query},
tests::COLLECTION,
};
use super::{CollectionManager, Error};
#[test]
fn read_get_write() {
let mut library = MockLibrary::new();
let mut database = MockDatabase::new();
let library_input = Query::default();
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(|_| database_result);
let mut collection_manager = CollectionManager::new(Box::new(library), Box::new(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::InvalidData(String::from("invalid data")));
library
.expect_list()
.times(1)
.return_once(|_| library_result);
let mut collection_manager = CollectionManager::new(Box::new(library), Box::new(database));
let actual_err = collection_manager.rescan_library().unwrap_err();
let expected_err = Error::LibraryError(
library::Error::InvalidData(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(|_| database_result);
let mut collection_manager = CollectionManager::new(Box::new(library), Box::new(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());
}
}

View File

@ -8,7 +8,7 @@ use crate::collection::Collection;
#[cfg(test)]
use mockall::automock;
use super::{Database, DatabaseRead, DatabaseWrite, Error};
use super::{Database, Error};
impl From<serde_json::Error> for Error {
fn from(err: serde_json::Error) -> Error {
@ -38,15 +38,13 @@ impl JsonDatabase {
}
}
impl DatabaseRead for JsonDatabase {
impl Database for JsonDatabase {
fn read(&self, collection: &mut Collection) -> Result<(), Error> {
let serialized = self.backend.read()?;
*collection = serde_json::from_str(&serialized)?;
Ok(())
}
}
impl DatabaseWrite for JsonDatabase {
fn write(&mut self, collection: &Collection) -> Result<(), Error> {
let serialized = serde_json::to_string(&collection)?;
self.backend.write(&serialized)?;
@ -54,8 +52,6 @@ impl DatabaseWrite for JsonDatabase {
}
}
impl Database for JsonDatabase {}
/// JSON database backend that uses a local file for persistent storage.
pub struct JsonDatabaseFileBackend {
path: PathBuf,

View File

@ -2,6 +2,9 @@
use std::fmt;
#[cfg(test)]
use mockall::automock;
use crate::collection::Collection;
pub mod json;
@ -32,17 +35,12 @@ impl From<std::io::Error> for Error {
}
}
/// Trait for database reads.
pub trait DatabaseRead {
/// Trait for interacting with the database.
#[cfg_attr(test, automock)]
pub trait Database {
/// Read collection from the database.
fn read(&self, collection: &mut Collection) -> Result<(), Error>;
}
/// Trait for database writes.
pub trait DatabaseWrite {
/// Write collection to the database.
fn write(&mut self, collection: &Collection) -> Result<(), Error>;
}
/// Trait for database reads and writes.
pub trait Database: DatabaseRead + DatabaseWrite {}

View File

@ -2,11 +2,15 @@
use std::{num::ParseIntError, str::Utf8Error, fmt};
#[cfg(test)]
use mockall::automock;
use crate::Artist;
pub mod beets;
/// A single query option.
#[derive(Debug, PartialEq, Eq)]
pub enum QueryOption<T> {
/// Inclusive query.
Include(T),
@ -36,7 +40,7 @@ impl<T> Default for QueryOption<T> {
}
/// Options for refining library queries.
#[derive(Default)]
#[derive(Debug, Default, PartialEq, Eq)]
pub struct Query {
album_artist: QueryOption<String>,
album_year: QueryOption<u32>,
@ -142,6 +146,7 @@ impl From<Utf8Error> for Error {
}
/// Trait for interacting with the music library.
#[cfg_attr(test, automock)]
pub trait Library {
/// List lirbary items that match the a specific query.
fn list(&mut self, query: &Query) -> Result<Vec<Artist>, Error>;

View File

@ -3,7 +3,7 @@ use std::{fs, path::PathBuf};
use musichoard::{
database::{
json::{JsonDatabase, JsonDatabaseFileBackend},
DatabaseRead, DatabaseWrite,
Database,
},
Artist,
};