use crate::{
description::Description,
matcher::{Describable, Matcher, MatcherResult},
};
use std::fmt::Debug;
pub fn not<InnerMatcherT>(inner: InnerMatcherT) -> __internal::NotMatcher<InnerMatcherT> {
__internal::NotMatcher { inner }
}
pub mod __internal {
use super::*;
#[doc(hidden)]
pub struct NotMatcher<InnerMatcherT> {
pub(super) inner: InnerMatcherT,
}
impl<T: Debug + ?Sized, InnerMatcherT: Matcher<T>> Matcher<T> for NotMatcher<InnerMatcherT> {
fn matches(&self, actual: &T) -> MatcherResult {
match self.inner.matches(actual) {
MatcherResult::Match => MatcherResult::NoMatch,
MatcherResult::NoMatch => MatcherResult::Match,
}
}
fn explain_match(&self, actual: &T) -> Description {
self.inner.explain_match(actual)
}
}
impl<InnerMatcherT: Describable> Describable for NotMatcher<InnerMatcherT> {
fn describe(&self, matcher_result: MatcherResult) -> Description {
self.inner.describe(if matcher_result.into() {
MatcherResult::NoMatch
} else {
MatcherResult::Match
})
}
}
}
#[cfg(test)]
mod tests {
use super::not;
use crate::matcher::{Matcher, MatcherResult};
use crate::prelude::*;
use indoc::indoc;
#[test]
fn matches_when_inner_matcher_does_not_match() -> TestResult<()> {
let matcher = not(eq(1));
let result = matcher.matches(&0);
verify_that!(result, eq(MatcherResult::Match))
}
#[test]
fn does_not_match_when_inner_matcher_matches() -> TestResult<()> {
let matcher = not(eq(1));
let result = matcher.matches(&1);
verify_that!(result, eq(MatcherResult::NoMatch))
}
#[test]
fn match_explanation_references_actual_value() -> TestResult<()> {
let result = verify_that!([1], not(container_eq([1])));
verify_that!(
result,
err(displays_as(contains_substring(indoc!(
"
Actual: [1],
which contains all the elements
"
))))
)
}
}