use crate::error::MatchError;
use crate::expectation::Expectation;
pub trait BehaveMatch<T> {
fn matches(&self, actual: &T) -> bool;
fn description(&self) -> &str;
}
impl<T> BehaveMatch<T> for Box<dyn BehaveMatch<T>> {
fn matches(&self, actual: &T) -> bool {
(**self).matches(actual)
}
fn description(&self) -> &str {
(**self).description()
}
}
impl<T: core::fmt::Debug> Expectation<T> {
#[allow(clippy::needless_pass_by_value)]
pub fn to_match(&self, custom: impl BehaveMatch<T>) -> Result<(), MatchError> {
let is_match = custom.matches(self.value());
self.check(is_match, custom.description())
}
}
#[cfg(test)]
mod tests {
use super::*;
struct IsEven;
#[allow(clippy::unnecessary_literal_bound)]
impl BehaveMatch<i32> for IsEven {
fn matches(&self, actual: &i32) -> bool {
actual % 2 == 0
}
fn description(&self) -> &str {
"to be even"
}
}
#[test]
fn custom_matcher_pass() {
assert!(Expectation::new(4, "4").to_match(IsEven).is_ok());
}
#[test]
fn custom_matcher_fail() {
assert!(Expectation::new(3, "3").to_match(IsEven).is_err());
}
#[test]
fn custom_matcher_negated_pass() {
assert!(Expectation::new(3, "3").negate().to_match(IsEven).is_ok());
}
#[test]
fn custom_matcher_negated_fail() {
assert!(Expectation::new(4, "4").negate().to_match(IsEven).is_err());
}
}