Skip to content

Commit

Permalink
test: expand coverage to catch mutants
Browse files Browse the repository at this point in the history
  • Loading branch information
cljoly committed Dec 10, 2023
1 parent 612039f commit 9980716
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 2 deletions.
1 change: 1 addition & 0 deletions rusqlite_migration/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ criterion = { version = "0.5", features = [
] }
iai = "0.1"
insta = "1.34.0"
mutants = "0.0.3"

[[bench]]
name = "criterion"
Expand Down
1 change: 1 addition & 0 deletions rusqlite_migration/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ impl<'u> MigrationsBuilder<'u> {
///
/// Returns [`crate::Error::FileLoad`] in case the subdirectory names are incorrect,
/// or don't contain at least a valid `up.sql` file.
#[cfg_attr(test, mutants::skip)] // Tested at a high level
pub fn from_directory(dir: &'static Dir<'static>) -> Result<Self> {
Ok(Self {
migrations: from_directory(dir)?,
Expand Down
64 changes: 62 additions & 2 deletions rusqlite_migration/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ pub enum Error {
Hook(String),
/// Error returned when loading migrations from directory
FileLoad(String),
/// An unknown error occurred
/// An unknown error occurred. *Note*: such errors are not comparable between one another,
/// much like NaN for floats.
Unrecognized(Box<dyn std::error::Error + Send + Sync + 'static>),
}

Expand All @@ -48,6 +49,9 @@ impl PartialEq for Error {
(Self::ForeignKeyCheck(e1), Self::ForeignKeyCheck(e2)) => e1 == e2,
(Self::Hook(a), Self::Hook(b)) => a == b,
(Self::FileLoad(a), Self::FileLoad(b)) => a == b,
// This makes Unrecognized errors behave like NaN (where NaN != NaN)
(Self::Unrecognized(_), Self::Unrecognized(_)) => false,
// Fallback to comparing enum variants
_ => core::mem::discriminant(self) == core::mem::discriminant(other),
}
}
Expand Down Expand Up @@ -233,6 +237,8 @@ pub type HookResult<E = HookError> = std::result::Result<(), E>;

#[cfg(test)]
mod tests {
use std::num::NonZeroUsize;

use super::*;

// We should be able to convert rusqlite errors transparently
Expand All @@ -251,7 +257,51 @@ mod tests {
));
}

// Two errors with different queries should be considered different
// Check that Unrecognized errors correctly implement PartialEq, namely that
// > a != b if and only if !(a == b).
// from https://doc.rust-lang.org/std/cmp/trait.PartialEq.html
#[test]
fn test_unrecognized_errors() {
let u1 = Error::Unrecognized(Box::new(Error::Hook(String::new())));
let u2 = Error::Unrecognized(Box::new(Error::Hook(String::new())));
let u3 = Error::Unrecognized(Box::new(Error::Hook("1".to_owned())));
let u4 = Error::Unrecognized(Box::new(Error::Hook(String::new())));
let u5 = Error::FileLoad("1".to_owned());
let u6 = Error::Unrecognized(Box::new(Error::Hook(String::new())));

for (e1, e2) in &[(u1, u2), (u3, u4), (u5, u6)] {
assert!(e1 != e2);
assert!(!(e1 == e2));
}
}

#[test]
// Errors on specified schema versions should be equal if and only if all versions are
// equal
fn test_specified_schema_version_error() {
assert_eq!(
Error::SpecifiedSchemaVersion(SchemaVersionError::TargetVersionOutOfRange {
specified: SchemaVersion::Outside(NonZeroUsize::new(10).unwrap()),
highest: SchemaVersion::Inside(NonZeroUsize::new(4).unwrap()),
}),
Error::SpecifiedSchemaVersion(SchemaVersionError::TargetVersionOutOfRange {
specified: SchemaVersion::Outside(NonZeroUsize::new(10).unwrap()),
highest: SchemaVersion::Inside(NonZeroUsize::new(4).unwrap()),
}),
);
assert_ne!(
Error::SpecifiedSchemaVersion(SchemaVersionError::TargetVersionOutOfRange {
specified: SchemaVersion::Outside(NonZeroUsize::new(9).unwrap()),
highest: SchemaVersion::Inside(NonZeroUsize::new(4).unwrap()),
}),
Error::SpecifiedSchemaVersion(SchemaVersionError::TargetVersionOutOfRange {
specified: SchemaVersion::Outside(NonZeroUsize::new(10).unwrap()),
highest: SchemaVersion::Inside(NonZeroUsize::new(4).unwrap()),
}),
);
}

// Two errors with different queries or errors should be considered different
#[test]
fn test_rusqlite_error_query() {
assert_ne!(
Expand All @@ -263,6 +313,16 @@ mod tests {
query: "SSSELECT".to_owned(),
err: rusqlite::Error::InvalidQuery
}
);
assert_ne!(
Error::RusqliteError {
query: "SELECT".to_owned(),
err: rusqlite::Error::MultipleStatement
},
Error::RusqliteError {
query: "SELECT".to_owned(),
err: rusqlite::Error::InvalidQuery
}
)
}

Expand Down
2 changes: 2 additions & 0 deletions rusqlite_migration/src/loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ fn get_name(value: &'static Dir<'static>) -> Result<&'static str> {
)))
}

#[cfg_attr(test, mutants::skip)] // Tested at a high level
fn get_migrations(
name: &'static str,
value: &'static Dir<'static>,
Expand Down Expand Up @@ -90,6 +91,7 @@ impl<'u> From<&MigrationFile> for M<'u> {
}
}

#[cfg_attr(test, mutants::skip)] // Tested at a high level
pub(crate) fn from_directory(dir: &'static Dir<'static>) -> Result<Vec<Option<M<'static>>>> {
let mut migrations: Vec<Option<M>> = vec![None; dir.dirs().count()];

Expand Down
30 changes: 30 additions & 0 deletions rusqlite_migration/src/tests/synch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,36 @@ fn empty_migrations_test() {
}
}

#[test]
fn test_db_version_to_schema_empty() {
let m = Migrations::new(vec![]);

assert_eq!(m.db_version_to_schema(0), SchemaVersion::NoneSet);
assert_eq!(
m.db_version_to_schema(1),
SchemaVersion::Outside(NonZeroUsize::new(1).unwrap())
);
assert_eq!(
m.db_version_to_schema(10),
SchemaVersion::Outside(NonZeroUsize::new(10).unwrap())
);
}

#[test]
fn test_db_version_to_schema_two() {
let m = Migrations::new(vec![m_valid10(), m_valid11()]);

assert_eq!(m.db_version_to_schema(0), SchemaVersion::NoneSet);
assert_eq!(
m.db_version_to_schema(1),
SchemaVersion::Inside(NonZeroUsize::new(1).unwrap())
);
assert_eq!(
m.db_version_to_schema(10),
SchemaVersion::Outside(NonZeroUsize::new(10).unwrap())
);
}

#[test]
fn schema_version_partial_cmp_test() {
assert_eq!(SchemaVersion::NoneSet, SchemaVersion::NoneSet);
Expand Down

0 comments on commit 9980716

Please sign in to comment.