1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
use crate::core::{Format, FormattedFailure, Formatter, MatchFailure, Matcher};
use crate::matchers::not::NotMatcher;

/// A formatter for [`FormattedFailure`] values.
///
/// This formatter just writes a pre-formatted value via [`Formatter::write_fmt`]. It's mostly
/// useful for combinator matchers which need to print the output of the matchers they compose.
///
/// If you need to print multiple [`FormattedFailure`] values, use [`SomeFailuresFormat`].
///
/// [`SomeFailuresFormat`]: crate::format::SomeFailuresFormat
#[non_exhaustive]
#[derive(Debug, Default)]
pub struct FailureFormat;

impl FailureFormat {
    /// Create a new [`FailureFormat`].
    pub fn new() -> Self {
        Self
    }
}

impl Format for FailureFormat {
    type Value = MatchFailure<FormattedFailure>;

    fn fmt(&self, f: &mut Formatter, value: Self::Value) -> crate::Result<()> {
        f.write_fmt(value.into_inner());
        Ok(())
    }
}

/// Negates the matcher passed to it.
///
/// This does the same thing as [`Assertion::to_not`].
///
/// # Examples
///
/// ```
/// use xpct::{expect, not, equal};
///
/// expect!("foo").to(not(equal("bar")));
/// ```
///
/// [`Assertion::to_not`]: crate::core::Assertion::to_not
pub fn not<'a, In, PosOut, NegOut>(
    matcher: Matcher<'a, In, PosOut, NegOut>,
) -> Matcher<'a, In, NegOut, PosOut>
where
    In: 'a,
    PosOut: 'a,
    NegOut: 'a,
{
    Matcher::transform(NotMatcher::new(matcher), FailureFormat::new())
}

#[cfg(test)]
mod tests {
    use super::not;
    use crate::{be_true, expect};

    #[test]
    fn succeeds_when_matcher_ok() {
        expect!(false).to(not(be_true()));
    }

    #[test]
    fn succeeds_when_matcher_fails() {
        expect!(true).to_not(not(be_true()));
    }

    #[test]
    #[should_panic]
    fn fails_when_matcher_ok() {
        expect!(false).to_not(not(be_true()));
    }

    #[test]
    #[should_panic]
    fn fails_when_matcher_fails() {
        expect!(true).to(not(be_true()));
    }
}