use crate::{
description::Description,
matcher::{Describable, Matcher, MatcherResult},
matcher_support::{edit_distance, summarize_diff::create_diff},
};
use std::{fmt::Debug, ops::Deref};
pub fn eq_deref_of<ExpectedRefT>(
expected: ExpectedRefT,
) -> __internal::EqDerefOfMatcher<ExpectedRefT> {
__internal::EqDerefOfMatcher { expected }
}
pub mod __internal {
use super::*;
#[doc(hidden)]
pub struct EqDerefOfMatcher<ExpectedRefT> {
pub(crate) expected: ExpectedRefT,
}
impl<ActualT, ExpectedRefT, ExpectedT> Matcher<ActualT> for EqDerefOfMatcher<ExpectedRefT>
where
ActualT: Debug + ?Sized,
ExpectedRefT: Deref<Target = ExpectedT> + Debug,
ExpectedT: PartialEq<ActualT> + Debug,
{
fn matches(&self, actual: &ActualT) -> MatcherResult {
(self.expected.deref() == actual).into()
}
fn explain_match(&self, actual: &ActualT) -> Description {
format!(
"which {}{}",
&self.describe(self.matches(actual)),
create_diff(
&format!("{:#?}", actual),
&format!("{:#?}", self.expected.deref()),
edit_distance::Mode::Exact,
)
)
.into()
}
}
impl<ExpectedRefT: Debug> Describable for EqDerefOfMatcher<ExpectedRefT> {
fn describe(&self, matcher_result: MatcherResult) -> Description {
match matcher_result {
MatcherResult::Match => format!("is equal to {:?}", self.expected).into(),
MatcherResult::NoMatch => format!("isn't equal to {:?}", self.expected).into(),
}
}
}
}
#[cfg(test)]
mod tests {
use super::eq_deref_of;
use crate::prelude::*;
use indoc::indoc;
use serial_test::serial;
#[derive(Debug, PartialEq)]
struct NonCloneNonCopyStruct(i32);
#[test]
fn matches_value_with_ref_to_equal_value() -> TestResult<()> {
verify_that!(NonCloneNonCopyStruct(123), eq_deref_of(&NonCloneNonCopyStruct(123)))
}
#[test]
fn matches_value_with_box_of_equal_value() -> TestResult<()> {
verify_that!(NonCloneNonCopyStruct(123), eq_deref_of(Box::new(NonCloneNonCopyStruct(123))))
}
#[test]
fn does_not_match_value_with_non_equal_value() -> TestResult<()> {
verify_that!(NonCloneNonCopyStruct(123), not(eq_deref_of(&NonCloneNonCopyStruct(234))))
}
#[test]
#[serial]
fn shows_structured_diff() -> TestResult<()> {
#[derive(Debug, PartialEq)]
struct Strukt {
int: i32,
string: String,
}
let result = verify_that!(
Strukt { int: 123, string: "something".into() },
eq_deref_of(Box::new(Strukt { int: 321, string: "someone".into() }))
);
verify_that!(
result,
err(displays_as(contains_substring(indoc! {
"
Actual: Strukt { int: 123, string: \"something\" },
which isn't equal to Strukt { int: 321, string: \"someone\" }
Difference(-actual / +expected):
Strukt {
- int: 123,
+ int: 321,
- string: \"something\",
+ string: \"someone\",
}
"})))
)
}
}