use crate::description::Description;
use crate::internal::test_outcome::TestAssertionFailure;
use crate::matchers::__internal_unstable_do_not_depend_on_these::ConjunctionMatcher;
use crate::matchers::__internal_unstable_do_not_depend_on_these::DisjunctionMatcher;
pub use googletest_macro::MatcherBase;
use std::fmt::Debug;
pub trait Matcher<ActualT: Debug + Copy>: MatcherBase {
fn matches(&self, actual: ActualT) -> MatcherResult;
fn describe(&self, matcher_result: MatcherResult) -> Description;
fn explain_match(&self, actual: ActualT) -> Description {
format!("which {}", self.describe(self.matches(actual))).into()
}
}
pub trait MatcherBase {
fn and<Right>(self, right: Right) -> ConjunctionMatcher<Self, Right>
where
Self: Sized,
{
ConjunctionMatcher::new(self, right)
}
fn or<Right>(self, right: Right) -> DisjunctionMatcher<Self, Right>
where
Self: Sized,
{
DisjunctionMatcher::new(self, right)
}
}
const PRETTY_PRINT_LENGTH_THRESHOLD: usize = 60;
#[track_caller]
pub(crate) fn create_assertion_failure<T: Debug + Copy>(
matcher: &impl Matcher<T>,
actual: T,
actual_expr: &'static str,
) -> TestAssertionFailure {
let actual_formatted = format!("{actual:?}");
let actual_formatted = if actual_formatted.len() > PRETTY_PRINT_LENGTH_THRESHOLD {
format!("{actual:#?}")
} else {
actual_formatted
};
TestAssertionFailure::create(format!(
"\
Value of: {actual_expr}
Expected: {}
Actual: {actual_formatted},
{}",
matcher.describe(MatcherResult::Match),
matcher.explain_match(actual).indent(),
))
}
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum MatcherResult {
Match,
NoMatch,
}
impl From<bool> for MatcherResult {
fn from(b: bool) -> Self {
if b {
MatcherResult::Match
} else {
MatcherResult::NoMatch
}
}
}
impl From<MatcherResult> for bool {
fn from(matcher_result: MatcherResult) -> Self {
matcher_result.is_match()
}
}
impl MatcherResult {
pub fn is_match(self) -> bool {
matches!(self, MatcherResult::Match)
}
pub fn is_no_match(self) -> bool {
matches!(self, MatcherResult::NoMatch)
}
}
impl<M: ?Sized + MatcherBase> MatcherBase for &M {}
impl<T: Debug + Copy, M: Matcher<T>> Matcher<T> for &M {
fn matches(&self, actual: T) -> MatcherResult {
(*self).matches(actual)
}
fn describe(&self, matcher_result: MatcherResult) -> Description {
(*self).describe(matcher_result)
}
fn explain_match(&self, actual: T) -> Description {
(*self).explain_match(actual)
}
}
#[cfg(test)]
mod tests {
use crate::prelude::*;
use crate::Result;
#[test]
fn ref_matchers_can_be_reused() -> Result<()> {
let matcher = eq(1);
verify_that!(1, &matcher)?;
verify_that!(1, &matcher)
}
#[test]
fn ref_matchers_as_inner_matcher() -> Result<()> {
let matcher = gt(1);
verify_that!([2, 3, 4, 5], [&matcher, &matcher, &matcher, &matcher])
}
}