googletest/matchers/matches_pattern.rs
1// Copyright 2022 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15// There are no visible documentation elements in this module; the declarative
16// macro is documented in the matchers module.
17#![doc(hidden)]
18
19/// Matches a value according to a pattern of matchers.
20///
21/// This takes as an argument a specification similar to a struct or enum
22/// initialiser, where each value is a [`Matcher`][crate::matcher::Matcher]
23/// which is applied to the corresponding field.
24///
25/// This can be used to match arbitrary combinations of fields on structures
26/// using arbitrary matchers:
27///
28/// ```
29/// # use googletest::prelude::*;
30/// #[derive(Debug)]
31/// struct MyStruct {
32/// a_field: String,
33/// another_field: String,
34/// }
35///
36/// let my_struct = MyStruct {
37/// a_field: "Something to believe in".into(),
38/// another_field: "Something else".into()
39/// };
40/// verify_that!(my_struct, matches_pattern!(MyStruct {
41/// a_field: starts_with("Something"),
42/// another_field: ends_with("else"),
43/// }))
44/// # .unwrap();
45/// ```
46///
47/// If any fields are provided in the pattern, then all fields must be
48/// specified, or the pattern must end with `..`, just like regular match
49/// patterns. Omitted fields have no effect on the output of the matcher.
50/// The `..` is unnecessary when no fields are provided and only method
51/// values are checked.
52///
53/// ```
54/// # use googletest::prelude::*;
55/// # #[derive(Debug)]
56/// # struct MyStruct {
57/// # a_field: String,
58/// # another_field: String,
59/// # }
60/// #
61/// # let my_struct = MyStruct {
62/// # a_field: "Something to believe in".into(),
63/// # another_field: "Something else".into()
64/// # };
65/// verify_that!(my_struct, matches_pattern!(MyStruct {
66/// a_field: starts_with("Something"),
67/// .. // another_field is missing, so it may be anything.
68/// }))
69/// # .unwrap();
70/// ```
71///
72/// One can use it recursively to match nested structures:
73///
74/// ```
75/// # use googletest::prelude::*;
76/// #[derive(Debug)]
77/// struct MyStruct {
78/// a_nested_struct: MyInnerStruct,
79/// }
80///
81/// #[derive(Debug)]
82/// struct MyInnerStruct {
83/// a_field: String,
84/// }
85///
86/// let my_struct = MyStruct {
87/// a_nested_struct: MyInnerStruct { a_field: "Something to believe in".into() },
88/// };
89/// verify_that!(my_struct, matches_pattern!(MyStruct {
90/// a_nested_struct: matches_pattern!(MyInnerStruct {
91/// a_field: starts_with("Something"),
92/// }),
93/// }))
94/// # .unwrap();
95/// ```
96///
97/// One can use the alias [`pat`][crate::matchers::pat] to make this less
98/// verbose:
99///
100/// ```
101/// # use googletest::prelude::*;
102/// # #[derive(Debug)]
103/// # struct MyStruct {
104/// # a_nested_struct: MyInnerStruct,
105/// # }
106/// #
107/// # #[derive(Debug)]
108/// # struct MyInnerStruct {
109/// # a_field: String,
110/// # }
111/// #
112/// # let my_struct = MyStruct {
113/// # a_nested_struct: MyInnerStruct { a_field: "Something to believe in".into() },
114/// # };
115/// verify_that!(my_struct, matches_pattern!(MyStruct {
116/// a_nested_struct: pat!(MyInnerStruct {
117/// a_field: starts_with("Something"),
118/// }),
119/// }))
120/// # .unwrap();
121/// ```
122///
123/// In addition to fields, one can match on the outputs of methods
124/// ("properties"):
125///
126/// ```
127/// # use googletest::prelude::*;
128/// #[derive(Debug)]
129/// struct MyStruct {
130/// a_field: String,
131/// }
132///
133/// impl MyStruct {
134/// fn get_a_field(&self) -> String { self.a_field.clone() }
135/// }
136///
137/// let my_struct = MyStruct { a_field: "Something to believe in".into() };
138/// verify_that!(my_struct, matches_pattern!(MyStruct {
139/// get_a_field(): starts_with("Something"),
140/// }))
141/// # .unwrap();
142/// ```
143///
144/// If an inner matcher is `eq(...)`, it can be omitted:
145///
146/// ```
147/// # use googletest::prelude::*;
148/// #[derive(Debug)]
149/// struct MyStruct {
150/// a_field: String,
151/// another_field: String,
152/// }
153///
154/// let my_struct = MyStruct {
155/// a_field: "this".into(),
156/// another_field: "that".into()
157/// };
158/// verify_that!(my_struct, matches_pattern!(MyStruct {
159/// a_field: "this",
160/// another_field: "that",
161/// }))
162/// # .unwrap();
163/// ```
164///
165/// **Important**: The method should be pure function with a deterministic
166/// output and no side effects. In particular, in the event of an assertion
167/// failure, it will be invoked a second time, with the assertion failure output
168/// reflecting the *second* invocation.
169///
170/// These may also include extra litteral parameters you pass in:
171///
172/// ```
173/// # use googletest::prelude::*;
174/// # #[derive(Debug)]
175/// # struct MyStruct {
176/// # a_field: String,
177/// # }
178/// #
179/// impl MyStruct {
180/// fn append_to_a_field(&self, suffix: &str) -> String { self.a_field.clone() + suffix }
181/// }
182///
183/// # let my_struct = MyStruct { a_field: "Something to believe in".into() };
184/// verify_that!(my_struct, matches_pattern!(&MyStruct {
185/// append_to_a_field("a suffix"): ref ends_with("a suffix"),
186/// }))
187/// # .unwrap();
188/// ```
189///
190/// You can precede both field and property matchers with a `ref` to match the
191/// result by reference:
192///
193/// ```
194/// # use googletest::prelude::*;
195/// # #[derive(Debug)]
196/// # struct MyStruct {
197/// # a_field: String,
198/// # }
199/// #
200/// impl MyStruct {
201/// fn get_a_field_ref(&self) -> String { self.a_field.clone() }
202/// }
203///
204/// # let my_struct = MyStruct { a_field: "Something to believe in".into() };
205/// verify_that!(my_struct, matches_pattern!(&MyStruct {
206/// get_a_field_ref(): ref starts_with("Something"),
207/// }))
208/// # .unwrap();
209/// ```
210///
211/// Note that if the `actual` is of type `&ActualT` and the pattern type is
212/// `ActualT`, this is automatically performed. This behavior is similar to the
213/// reference binding mode in pattern matching.
214///
215/// ```
216/// # use googletest::prelude::*;
217/// # #[derive(Debug)]
218/// # struct MyStruct {
219/// # a_field: String,
220/// # }
221/// #
222/// impl MyStruct {
223/// fn get_a_field_ref(&self) -> String { self.a_field.clone() }
224/// }
225///
226/// # let my_struct = MyStruct { a_field: "Something to believe in".into() };
227/// verify_that!(my_struct, matches_pattern!(MyStruct {
228/// get_a_field_ref(): starts_with("Something"),
229/// }))
230/// # .unwrap();
231/// ```
232///
233/// One can also match tuple structs with up to 10 fields. In this case, all
234/// fields must have matchers:
235///
236/// ```
237/// # use googletest::prelude::*;
238/// #[derive(Debug)]
239/// struct MyTupleStruct(String, String);
240///
241/// let my_struct = MyTupleStruct("Something".into(), "Some other thing".into());
242/// verify_that!(
243/// my_struct,
244/// matches_pattern!(&MyTupleStruct(ref eq("Something"), ref eq("Some other thing")))
245/// )
246/// # .unwrap();
247/// ```
248///
249/// The macro also allows matching on specific enum values and supports wildcard
250/// patterns like `MyEnum::Case(_)`.
251///
252/// ```
253/// # use googletest::prelude::*;
254/// #[derive(Debug)]
255/// enum MyEnum {
256/// A(u32),
257/// B,
258/// }
259///
260/// # fn should_pass() -> Result<()> {
261/// verify_that!(MyEnum::A(123), matches_pattern!(&MyEnum::A(eq(123))))?; // Passes
262/// # Ok(())
263/// # }
264/// # fn should_pass_with_wildcard() -> Result<()> {
265/// verify_that!(MyEnum::A(123), matches_pattern!(MyEnum::A(_)))?; // Passes
266/// # Ok(())
267/// # }
268/// # fn should_fail() -> Result<()> {
269/// verify_that!(MyEnum::B, matches_pattern!(&MyEnum::A(eq(123))))?; // Fails - wrong enum variant
270/// # Ok(())
271/// # }
272/// # should_pass().unwrap();
273/// # should_pass_with_wildcard().unwrap();
274/// # should_fail().unwrap_err();
275/// ```
276///
277/// This macro does not support plain (non-struct) tuples. But it should not be
278/// necessary as tuple of matchers are matchers of tuple. In other words, if
279/// `MatcherU: Matcher<U>` and `MatcherT: Matcher<T>`, then `(MatcherU,
280/// MatcherT): Matcher<(U, T)>`.
281///
282/// Trailing commas are allowed (but not required) in both ordinary and tuple
283/// structs.
284///
285/// Note that the default format (rustfmt) can format macros if the macro
286/// argument is parseable Rust code. This is mostly true for this macro with two
287/// exceptions:
288/// * property matching
289/// * `ref` keyword with named fields
290///
291/// An option for formatting large is to avoid these exceptions (by removing the
292/// parenthesis of properties and the `ref` keywords), run `rustfmt` and add
293/// them back.
294#[macro_export]
295#[doc(hidden)]
296macro_rules! __matches_pattern {
297 ($($t:tt)*) => { $crate::matches_pattern_internal!($($t)*) }
298}
299
300// Internal-only macro created so that the macro definition does not appear in
301// generated documentation.
302#[doc(hidden)]
303#[macro_export]
304macro_rules! matches_pattern_internal {
305 ($($tt:tt)*) => {
306 {
307 use $crate::{self as googletest};
308 #[allow(unused)]
309 use $crate::matchers::{all, field, property};
310 $crate::matchers::__internal_unstable_do_not_depend_on_these::__googletest_macro_matches_pattern!($($tt)*)
311 }
312 };
313}
314
315/// An alias for [`matches_pattern`][crate::matchers::matches_pattern!].
316#[macro_export]
317#[doc(hidden)]
318macro_rules! __pat {
319 ($($t:tt)*) => { $crate::matches_pattern_internal!($($t)*) }
320}
321
322#[doc(hidden)]
323pub mod internal {
324 use crate::matcher::{Matcher, MatcherBase};
325 use std::fmt::Debug;
326
327 pub use ::googletest_macro::__googletest_macro_matches_pattern;
328
329 // Specialized implementation of the `predicate` matcher to support ref binding
330 // mode for `matches_pattern`.
331 pub fn pattern_only<T>(
332 matcher_function: fn(&T) -> bool,
333 match_description: &'static str,
334 no_match_description: &'static str,
335 ) -> PatternOnlyMatcher<T> {
336 PatternOnlyMatcher { matcher_function, match_description, no_match_description }
337 }
338
339 #[derive(MatcherBase)]
340 #[doc(hidden)]
341 pub struct PatternOnlyMatcher<T> {
342 matcher_function: fn(&T) -> bool,
343 match_description: &'static str,
344 no_match_description: &'static str,
345 }
346
347 impl<'a, T: Debug> Matcher<&'a T> for PatternOnlyMatcher<T> {
348 fn matches(&self, actual: &'a T) -> crate::matcher::MatcherResult {
349 (self.matcher_function)(actual).into()
350 }
351
352 fn describe(
353 &self,
354 matcher_result: crate::matcher::MatcherResult,
355 ) -> crate::description::Description {
356 match matcher_result {
357 crate::matcher::MatcherResult::Match => self.match_description.into(),
358 crate::matcher::MatcherResult::NoMatch => self.no_match_description.into(),
359 }
360 }
361 }
362
363 impl<T: Debug + Copy> Matcher<T> for PatternOnlyMatcher<T> {
364 fn matches(&self, actual: T) -> crate::matcher::MatcherResult {
365 (self.matcher_function)(&actual).into()
366 }
367
368 fn describe(
369 &self,
370 matcher_result: crate::matcher::MatcherResult,
371 ) -> crate::description::Description {
372 match matcher_result {
373 crate::matcher::MatcherResult::Match => self.match_description.into(),
374 crate::matcher::MatcherResult::NoMatch => self.no_match_description.into(),
375 }
376 }
377 }
378
379 /// A matcher that ensures that the passed-in function compiles with the
380 /// benefit of inference from the value being tested. The passed-in
381 /// matcher is what is actually invoked for matching.
382 ///
383 /// It forwards all description responsibilities to the passed-in matcher.
384 pub fn compile_assert_and_match<T, M>(
385 must_compile_function: fn(&T),
386 matcher: M,
387 ) -> CompileAssertAndMatch<T, M> {
388 CompileAssertAndMatch { must_compile_function, matcher }
389 }
390
391 #[derive(MatcherBase)]
392 #[doc(hidden)]
393 pub struct CompileAssertAndMatch<T, M> {
394 #[allow(dead_code)]
395 must_compile_function: fn(&T),
396 matcher: M,
397 }
398
399 impl<'a, T: Debug, M> Matcher<&'a T> for CompileAssertAndMatch<T, M>
400 where
401 M: Matcher<&'a T>,
402 {
403 fn matches(&self, actual: &'a T) -> crate::matcher::MatcherResult {
404 self.matcher.matches(actual)
405 }
406
407 fn describe(
408 &self,
409 matcher_result: crate::matcher::MatcherResult,
410 ) -> crate::description::Description {
411 self.matcher.describe(matcher_result)
412 }
413
414 fn explain_match(&self, actual: &'a T) -> crate::description::Description {
415 self.matcher.explain_match(actual)
416 }
417 }
418
419 impl<T: Debug + Copy, M> Matcher<T> for CompileAssertAndMatch<T, M>
420 where
421 M: Matcher<T>,
422 {
423 fn matches(&self, actual: T) -> crate::matcher::MatcherResult {
424 self.matcher.matches(actual)
425 }
426
427 fn describe(
428 &self,
429 matcher_result: crate::matcher::MatcherResult,
430 ) -> crate::description::Description {
431 self.matcher.describe(matcher_result)
432 }
433
434 fn explain_match(&self, actual: T) -> crate::description::Description {
435 self.matcher.explain_match(actual)
436 }
437 }
438}
439
440mod compile_fail_tests {
441 /// ```compile_fail
442 /// use ::googletest::prelude::*;
443 /// #[derive(Debug)]
444 /// struct Foo { a: u32 }
445 /// impl Foo {
446 /// fn b() {}
447 /// }
448 /// let actual = Foo { a: 1 };
449 /// verify_that!(actual, matches_pattern!(Foo { a: eq(&1), b(): _ }));
450 /// ```
451 fn _underscore_unsupported_for_methods() {}
452
453 /// ```compile_fail
454 /// use ::googletest::prelude::*;
455 /// #[derive(Debug)]
456 /// struct Foo { a: u32, b: u32 }
457 /// let actual = Foo { a: 1, b: 2 };
458 /// verify_that!(actual, matches_pattern!(Foo { a: eq(&1), .., }));
459 /// ```
460 fn _dot_dot_supported_only_at_end_of_struct_pattern() {}
461
462 /// ```compile_fail
463 /// use ::googletest::prelude::*;
464 /// #[derive(Debug)]
465 /// struct Foo(u32, u32);
466 /// let actual = Foo(1, 2);
467 /// verify_that!(actual, matches_pattern!(Foo(eq(&1), .., )));
468 /// ```
469 fn _dot_dot_supported_only_at_end_of_tuple_struct_pattern() {}
470
471 /// ```compile_fail
472 /// use ::googletest::prelude::*;
473 /// #[derive(Debug)]
474 /// struct Foo { a: u32, b: u32 }
475 /// let actual = Foo { a: 1, b: 2 };
476 /// verify_that!(actual, matches_pattern!(Foo { a: eq(&1) }));
477 /// ```
478 fn _unexhaustive_struct_field_check_requires_dot_dot() {}
479
480 /// ```compile_fail
481 /// use ::googletest::prelude::*;
482 /// #[derive(Debug)]
483 /// enum Foo {
484 /// Bar { a: u32, b: u32 }
485 /// }
486 /// let actual = Foo::Bar { a: 1, b: 2 };
487 /// verify_that!(actual, matches_pattern!(Foo::Bar { a: eq(&1) }));
488 /// ```
489 fn _unexhaustive_enum_struct_field_check_requires_dot_dot() {}
490
491 /// ```compile_fail
492 /// use ::googletest::prelude::*;
493 /// #[derive(Debug)]
494 /// struct Foo(u32, u32, u32);
495 /// let actual = Foo(1, 2, 3);
496 /// verify_that!(actual, matches_pattern!(Foo(eq(&1), eq(&2) )));
497 /// ```
498 fn _unexhaustive_tuple_struct_field_check_requires_dot_dot() {}
499
500 /// ```compile_fail
501 /// use ::googletest::prelude::*;
502 /// verify_that!(1, matches_pattern!(UndefinedSymbol { }));
503 /// ```
504 fn _should_fail_to_compile_unknown_struct_with_no_fields() {}
505
506 /// ```compile_fail
507 /// use ::googletest::prelude::*;
508 /// verify_that!(1, matches_pattern!(UndefinedSymbol { a: 1 }));
509 /// ```
510 fn _should_fail_to_compile_unknown_struct_with_field() {}
511
512 /// ```compile_fail
513 /// use ::googletest::prelude::*;
514 /// verify_that!(1, matches_pattern!(UndefinedSymbol { .. }));
515 /// ```
516 fn _should_fail_to_compile_unknown_struct_with_dot_dot() {}
517
518 /// ```compile_fail
519 /// use ::googletest::prelude::*;
520 /// verify_that!(1, matches_pattern!(UndefinedSymbol( .. )));
521 /// ```
522 fn _should_fail_to_compile_unknown_tuple_struct_with_dot_dot() {}
523}