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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
use std::marker::PhantomData;

use crate::core::{style, Format, Formatter, MatchFailure, Matcher, NegFormat};
use crate::matchers::boolean::BeTrueMatcher;

/// A formatter which prints a static string message.
///
/// Use this over [`Expectation`] when there's no point including the actual value in the output. A
/// good example of this is the [`be_true`] matcher, where if the matcher failed, you know the
/// actual value must be `false`.
///
/// # Examples
///
/// ```
/// # use xpct::format::MessageFormat;
/// let format: MessageFormat = MessageFormat::new(
///     "Expected this to be true",
///     "Expected this to be false"
/// );
/// ```
///
/// [`Expectation`]: crate::matchers::Expectation
/// [`be_true`]: crate::be_true
#[derive(Debug)]
pub struct MessageFormat<PosFail = (), NegFail = ()> {
    marker: PhantomData<(PosFail, NegFail)>,
    pos_msg: String,
    neg_msg: String,
}

impl<PosFail, NegFail> MessageFormat<PosFail, NegFail> {
    /// Create a new [`MessageFormat`].
    ///
    /// This accepts two error messages: the one to use in the *positive* case (when we were
    /// expecting the matcher to succeed) and the one to use in the *negative* case (when we were
    /// expecting the matcher to fail).
    pub fn new(pos_msg: impl Into<String>, neg_msg: impl Into<String>) -> Self {
        Self {
            marker: PhantomData,
            pos_msg: pos_msg.into(),
            neg_msg: neg_msg.into(),
        }
    }
}

impl<PosFail, NegFail> Format for MessageFormat<PosFail, NegFail> {
    type Value = MatchFailure<PosFail, NegFail>;

    fn fmt(&self, f: &mut Formatter, value: Self::Value) -> crate::Result<()> {
        f.set_style(style::bad());
        if value.is_pos() {
            f.write_str(&self.pos_msg);
        } else {
            f.write_str(&self.neg_msg);
        }
        f.reset_style();
        f.write_char('\n');

        Ok(())
    }
}

fn bool_format() -> MessageFormat {
    MessageFormat::new("Expected this to be true", "Expected this to be false")
}

/// Succeeds when the actual value is `true`.
///
/// # Examples
///
/// ```
/// use xpct::{expect, be_true};
///
/// expect!(true).to(be_true());
/// expect!(false).to_not(be_true());
/// ```
pub fn be_true() -> Matcher<'static, bool, bool> {
    Matcher::new(BeTrueMatcher::new(), bool_format())
}

/// Succeeds when the actual value is `false`.
///
/// # Examples
///
/// ```
/// use xpct::{expect, be_false};
///
/// expect!(false).to(be_false());
/// expect!(true).to_not(be_false());
/// ```
pub fn be_false() -> Matcher<'static, bool, bool> {
    Matcher::neg(BeTrueMatcher::new(), NegFormat(bool_format()))
}

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

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

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

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

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

    #[test]
    fn succeeds_when_false() {
        expect!(false).to(be_false());
    }

    #[test]
    fn succeeds_when_not_false() {
        expect!(true).to_not(be_false());
    }

    #[test]
    #[should_panic]
    fn fail_when_false() {
        expect!(false).to_not(be_false());
    }

    #[test]
    #[should_panic]
    fn fails_when_not_false() {
        expect!(true).to(be_false());
    }
}