test_that/matchers/
display_matcher.rs1use crate::description::Description;
17use crate::matcher::{Describable, Matcher, MatcherResult};
18use alloc::string::String;
19use core::fmt::{Debug, Display};
20
21pub fn displays_as<InnerMatcher>(inner: InnerMatcher) -> DisplayMatcher<InnerMatcher> {
38 DisplayMatcher { inner, alternate: false }
39}
40
41pub struct DisplayMatcher<InnerMatcher> {
44 inner: InnerMatcher,
45 alternate: bool,
46}
47
48impl<InnerMatcher> DisplayMatcher<InnerMatcher> {
49 pub fn alternate(mut self) -> Self {
53 self.alternate = true;
54 self
55 }
56}
57
58impl<T: Debug + Display + ?Sized, InnerMatcher: Matcher<String>> Matcher<T>
59 for DisplayMatcher<InnerMatcher>
60{
61 fn matches(&self, actual: &T) -> MatcherResult {
62 let rendered = if self.alternate { format!("{actual:#}") } else { format!("{actual}") };
63 self.inner.matches(&rendered)
64 }
65
66 fn explain_match(&self, actual: &T) -> Description {
67 let rendered = if self.alternate { format!("{actual:#}") } else { format!("{actual}") };
68 let inner_explanation = self.inner.explain_match(&rendered);
69 Description::new()
70 .text("which displays as:")
71 .nested(Description::from(rendered).indent())
72 .append(inner_explanation)
73 }
74}
75
76impl<InnerMatcher: Describable> Describable for DisplayMatcher<InnerMatcher> {
77 fn describe(&self, matcher_result: MatcherResult) -> Description {
78 match matcher_result {
79 MatcherResult::Match => {
80 format!("displays as a string which {}", self.inner.describe(MatcherResult::Match))
81 .into()
82 }
83 MatcherResult::NoMatch => format!(
84 "doesn't display as a string which {}",
85 self.inner.describe(MatcherResult::Match)
86 )
87 .into(),
88 }
89 }
90}
91
92#[cfg(test)]
93mod tests {
94 use super::displays_as;
95 use crate::prelude::*;
96 use core::fmt::{Debug, Display, Error, Formatter};
97 use indoc::indoc;
98 use serial_test::serial;
99
100 #[test]
101 fn display_matches_i32() -> TestResult<()> {
102 let value = 32;
103 verify_that!(value, displays_as(eq("32")))?;
104 Ok(())
105 }
106
107 #[test]
108 fn display_matches_str() -> TestResult<()> {
109 let value = "32";
110 verify_that!(value, displays_as(eq("32")))?;
111 Ok(())
112 }
113
114 #[test]
115 fn display_matches_struct() -> TestResult<()> {
116 #[allow(dead_code)]
117 #[derive(Debug)]
118 struct Struct {
119 a: i32,
120 b: i64,
121 }
122 impl Display for Struct {
123 fn fmt(&self, f: &mut Formatter<'_>) -> core::result::Result<(), Error> {
124 write!(f, "{:?}", self)
125 }
126 }
127 verify_that!(Struct { a: 123, b: 321 }, displays_as(eq("Struct { a: 123, b: 321 }")))?;
128 Ok(())
129 }
130
131 #[test]
132 fn display_matches_struct_with_alternate_rendering() -> TestResult<()> {
133 #[derive(Debug)]
134 struct Struct;
135 impl Display for Struct {
136 fn fmt(&self, f: &mut Formatter<'_>) -> core::result::Result<(), Error> {
137 if f.alternate() { write!(f, "Correct") } else { write!(f, "Not correct") }
138 }
139 }
140
141 verify_that!(Struct, displays_as(eq("Correct")).alternate())
142 }
143
144 #[cfg(feature = "std")]
145 #[test]
146 #[serial]
147 fn display_displays_error_message_with_explanation_from_inner_matcher() -> TestResult<()> {
148 let result = verify_that!("123\n234", displays_as(eq("123\n345")));
149
150 verify_that!(
151 result,
152 err(displays_as(contains_substring(indoc!(
153 r#"
154 Actual: "123\n234",
155 which displays as:
156 123
157 234
158 which isn't equal to "123\n345"
159 Difference(-actual / +expected):
160 123
161 -234
162 +345
163 "#
164 ))))
165 )
166 }
167
168 #[cfg(feature = "std")]
169 #[test]
170 #[serial]
171 fn display_puts_alternate_rendering_in_explanation_when_requested() -> TestResult<()> {
172 #[derive(Debug)]
173 struct Struct;
174 impl Display for Struct {
175 fn fmt(&self, f: &mut Formatter<'_>) -> core::result::Result<(), Error> {
176 if f.alternate() { write!(f, "Correct") } else { write!(f, "Not correct") }
177 }
178 }
179
180 let result = verify_that!(Struct, displays_as(eq("Not correct")).alternate());
181
182 verify_that!(
183 result,
184 err(displays_as(contains_substring(indoc!(
185 r#"
186 Actual: Struct,
187 which displays as:
188 Correct
189 which isn't equal to "Not correct"
190 "#
191 ))))
192 )
193 }
194}