1#[macro_export]
34macro_rules! __result_of {
35 ($function: expr, $matcher: expr) => {{
36 $crate::matchers::__internal_unstable_do_not_depend_on_these::result_of(
37 $function,
38 $matcher,
39 stringify!($function),
40 )
41 }};
42}
43
44#[macro_export]
69macro_rules! __result_of_ref {
70 ($function: expr, $matcher: expr) => {{
71 $crate::matchers::__internal_unstable_do_not_depend_on_these::result_of_ref(
72 $function,
73 $matcher,
74 stringify!($function),
75 )
76 }};
77}
78
79#[doc(hidden)]
83pub mod internal {
84 use crate::description::Description;
85 use crate::matcher::{Matcher, MatcherBase, MatcherResult};
86 use std::fmt::Debug;
87
88 pub fn result_of<Callable, InnerMatcher>(
89 callable: Callable,
90 inner_matcher: InnerMatcher,
91 callable_description: &'static str,
92 ) -> ResultOfMatcher<Callable, InnerMatcher> {
93 ResultOfMatcher { callable, inner_matcher, callable_description }
94 }
95
96 #[derive(MatcherBase)]
97 pub struct ResultOfMatcher<Callable, InnerMatcher> {
98 callable: Callable,
99 inner_matcher: InnerMatcher,
100 callable_description: &'static str,
101 }
102
103 impl<I: Copy + Debug, T: Debug + Copy, CallableT: Fn(I) -> T, InnerMatcherT: Matcher<T>>
104 Matcher<I> for ResultOfMatcher<CallableT, InnerMatcherT>
105 {
106 fn matches(&self, actual: I) -> MatcherResult {
107 self.inner_matcher.matches((self.callable)(actual))
108 }
109
110 fn describe(&self, matcher_result: MatcherResult) -> Description {
111 Description::new()
112 .text(format!("by applying {},", self.callable_description))
113 .nested(self.inner_matcher.describe(matcher_result))
114 }
115
116 fn explain_match(&self, actual: I) -> Description {
117 let actual_result = (self.callable)(actual);
118 Description::new()
119 .text(format!("which, results into {actual_result:?}",))
120 .nested(self.describe(self.matches(actual)))
121 }
122 }
123
124 pub fn result_of_ref<Callable, InnerMatcher>(
125 callable: Callable,
126 inner_matcher: InnerMatcher,
127 callable_description: &'static str,
128 ) -> ResultOfRefMatcher<Callable, InnerMatcher> {
129 ResultOfRefMatcher { callable, inner_matcher, callable_description }
130 }
131 #[derive(MatcherBase)]
132 pub struct ResultOfRefMatcher<Callable, InnerMatcher> {
133 callable: Callable,
134 inner_matcher: InnerMatcher,
135 callable_description: &'static str,
136 }
137
138 impl<
139 I: Copy + Debug,
140 T: Debug,
141 Callable: Fn(I) -> T,
142 InnerMatcherT: for<'a> Matcher<&'a T>,
143 > Matcher<I> for ResultOfRefMatcher<Callable, InnerMatcherT>
144 {
145 fn matches(&self, actual: I) -> MatcherResult {
146 self.inner_matcher.matches(&(self.callable)(actual))
147 }
148
149 fn describe(&self, matcher_result: MatcherResult) -> Description {
150 Description::new()
151 .text(format!("by applying {},", self.callable_description))
152 .nested(self.inner_matcher.describe(matcher_result))
153 }
154
155 fn explain_match(&self, actual: I) -> Description {
156 let actual_result = (self.callable)(actual);
157 Description::new()
158 .text(format!("which, results into {actual_result:?}",))
159 .nested(self.describe(self.matches(actual)))
160 }
161 }
162}
163
164#[cfg(test)]
165mod tests {
166 use crate::prelude::*;
167 use crate::Result;
168 use indoc::indoc;
169
170 #[test]
171 fn result_of_match_with_value() -> Result<()> {
172 verify_that!(1, result_of!(|value| value + 1, eq(2)))
173 }
174
175 #[test]
176 fn result_of_match_with_value_function() -> Result<()> {
177 fn inc_by_one(value: i32) -> i32 {
178 value + 1
179 }
180 verify_that!(1, result_of!(inc_by_one, eq(2)))
181 }
182
183 #[test]
184 fn result_of_match_with_different_value() -> Result<()> {
185 let result = verify_that!(0, result_of!(|value| value - 1, eq(2)));
186 verify_that!(
187 result,
188 err(displays_as(contains_substring(indoc!(
189 "
190 Value of: 0
191 Expected: by applying |value| value - 1,
192 is equal to 2
193 Actual: 0,
194 which, results into -1
195 by applying |value| value - 1,
196 isn't equal to 2
197 "
198 ))))
199 )
200 }
201
202 #[test]
203 fn result_of_match_with_different_value_block_closure() -> Result<()> {
204 let result = verify_that!(0, result_of!(|value| { value - 1 }, eq(2)));
205 verify_that!(
206 result,
207 err(displays_as(contains_substring(indoc!(
208 "
209 Value of: 0
210 Expected: by applying |value| { value - 1 },
211 is equal to 2
212 Actual: 0,
213 which, results into -1
214 by applying |value| { value - 1 },
215 isn't equal to 2
216 "
217 ))))
218 )
219 }
220
221 #[test]
222 fn result_of_match_with_different_value_multiline_closure() -> Result<()> {
223 let result = verify_that!(
224 0,
225 result_of!(
226 |value| {
227 let dec = value - 1;
228 let inc = dec + 1;
229 inc - 2
230 },
231 eq(2)
232 )
233 );
234 verify_that!(
235 result,
236 err(displays_as(contains_substring(indoc!(
237 "
238 Value of: 0
239 Expected: by applying |value| { let dec = value - 1; let inc = dec + 1; inc - 2 },
240 is equal to 2
241 Actual: 0,
242 which, results into -2
243 by applying |value| { let dec = value - 1; let inc = dec + 1; inc - 2 },
244 isn't equal to 2
245 "
246 ))))
247 )
248 }
249
250 #[test]
251 fn result_of_match_with_different_value_function() -> Result<()> {
252 fn dec_by_one(value: i32) -> i32 {
253 value - 1
254 }
255 let result = verify_that!(0, result_of!(dec_by_one, eq(2)));
256 verify_that!(
257 result,
258 err(displays_as(contains_substring(indoc!(
259 "
260 Value of: 0
261 Expected: by applying dec_by_one,
262 is equal to 2
263 Actual: 0,
264 which, results into -1
265 by applying dec_by_one,
266 isn't equal to 2
267 "
268 ))))
269 )
270 }
271
272 #[test]
273 fn result_of_ref_match_with_string_reference() -> Result<()> {
274 verify_that!("hello", result_of_ref!(|s: &str| s.to_uppercase(), eq("HELLO")))
275 }
276
277 #[test]
278 fn result_of_ref_match_with_string_reference_function() -> Result<()> {
279 fn to_upper_case<S: AsRef<str>>(s: S) -> String {
280 s.as_ref().to_uppercase()
281 }
282 verify_that!("hello", result_of_ref!(to_upper_case, eq("HELLO")))
283 }
284
285 #[test]
286 fn result_of_ref_match_with_copy_types() -> Result<()> {
287 verify_that!(100, result_of_ref!(|value| value + 1, eq(&101)))
288 }
289
290 #[test]
291 fn result_of_ref_match_with_different_value() -> Result<()> {
292 let result = verify_that!("world", result_of_ref!(|s: &str| s.to_uppercase(), eq("HELLO")));
293 verify_that!(
294 result,
295 err(displays_as(contains_substring(indoc!(
296 r#"
297 Value of: "world"
298 Expected: by applying |s: &str| s.to_uppercase(),
299 is equal to "HELLO"
300 Actual: "world",
301 which, results into "WORLD"
302 by applying |s: &str| s.to_uppercase(),
303 isn't equal to "HELLO""#
304 ))))
305 )
306 }
307
308 #[test]
309 fn result_of_ref_match_with_different_value_block_closure() -> Result<()> {
310 let result =
311 verify_that!("world", result_of_ref!(|s: &str| { s.to_uppercase() }, eq("HELLO")));
312 verify_that!(
313 result,
314 err(displays_as(contains_substring(indoc!(
315 r#"
316 Value of: "world"
317 Expected: by applying |s: &str| { s.to_uppercase() },
318 is equal to "HELLO"
319 Actual: "world",
320 which, results into "WORLD"
321 by applying |s: &str| { s.to_uppercase() },
322 isn't equal to "HELLO"
323 "#
324 ))))
325 )
326 }
327
328 #[test]
329 fn result_of_ref_match_with_different_value_function() -> Result<()> {
330 fn to_upper_case<S: AsRef<str>>(s: S) -> String {
331 s.as_ref().to_uppercase()
332 }
333 let result = verify_that!("world", result_of_ref!(to_upper_case, eq("HELLO")));
334 verify_that!(
335 result,
336 err(displays_as(contains_substring(indoc!(
337 r#"
338 Value of: "world"
339 Expected: by applying to_upper_case,
340 is equal to "HELLO"
341 Actual: "world",
342 which, results into "WORLD"
343 by applying to_upper_case,
344 isn't equal to "HELLO"
345 "#
346 ))))
347 )
348 }
349
350 #[test]
351 fn result_of_ref_match_different_with_closure_variable() -> Result<()> {
352 let to_upper_case = |s: &str| s.to_uppercase();
353 let result = verify_that!("world", result_of_ref!(to_upper_case, eq("HELLO")));
354 verify_that!(
355 result,
356 err(displays_as(contains_substring(indoc!(
357 r#"
358 Value of: "world"
359 Expected: by applying to_upper_case,
360 is equal to "HELLO"
361 Actual: "world",
362 which, results into "WORLD"
363 by applying to_upper_case,
364 isn't equal to "HELLO"
365 "#
366 ))))
367 )
368 }
369
370 #[test]
371 fn result_of_ref_match_different_with_method_literal() -> Result<()> {
372 let result = verify_that!("world", result_of_ref!(str::to_uppercase, eq("HELLO")));
373 verify_that!(
374 result,
375 err(displays_as(contains_substring(indoc!(
376 r#"
377 Value of: "world"
378 Expected: by applying str::to_uppercase,
379 is equal to "HELLO"
380 Actual: "world",
381 which, results into "WORLD"
382 by applying str::to_uppercase,
383 isn't equal to "HELLO"
384 "#
385 ))))
386 )
387 }
388
389 #[test]
390 fn result_of_ref_match_different_with_function_return_closure() -> Result<()> {
391 fn upper_case() -> impl Fn(&str) -> String {
392 |s: &str| s.to_uppercase()
393 }
394 let result = verify_that!("world", result_of_ref!(upper_case(), eq("HELLO")));
395 verify_that!(
396 result,
397 err(displays_as(contains_substring(indoc!(
398 r#"
399 Value of: "world"
400 Expected: by applying upper_case(),
401 is equal to "HELLO"
402 Actual: "world",
403 which, results into "WORLD"
404 by applying upper_case(),
405 isn't equal to "HELLO"
406 "#
407 ))))
408 )
409 }
410
411 #[test]
412 fn test_describe_simple() -> Result<()> {
413 let matcher = result_of!(|x| x + 1, eq(2));
414 let description = matcher.describe(matcher.matches(0));
415 verify_that!(
416 description,
417 displays_as(eq(indoc!(
418 r#"
419 by applying |x| x + 1,
420 isn't equal to 2"#
421 )))
422 )
423 }
424
425 #[test]
426 fn test_describe_complicated() -> Result<()> {
427 let matcher = result_of_ref!(
428 |s: &str| s.chars().collect::<Vec<_>>(),
429 each(predicate(char::is_ascii_alphabetic))
430 );
431 let description = matcher.describe(matcher.matches("A quick brown fox"));
432 verify_that!(
433 description,
434 displays_as(eq(indoc!(
435 r#"
436 by applying |s: &str| s.chars().collect::<Vec<_>>(),
437 contains no element that matches"#
438 )))
439 )
440 }
441}