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 /// It is not required to include all named fields in the specification. Omitted
48 /// fields have no effect on the output of the matcher.
49 ///
50 /// ```
51 /// # use googletest::prelude::*;
52 /// # #[derive(Debug)]
53 /// # struct MyStruct {
54 /// #     a_field: String,
55 /// #     another_field: String,
56 /// # }
57 /// #
58 /// # let my_struct = MyStruct {
59 /// #     a_field: "Something to believe in".into(),
60 /// #     another_field: "Something else".into()
61 /// # };
62 /// verify_that!(my_struct, matches_pattern!(MyStruct {
63 ///     a_field: starts_with("Something"),
64 ///     // another_field is missing, so it may be anything.
65 /// }))
66 /// #     .unwrap();
67 /// ```
68 ///
69 /// One can use it recursively to match nested structures:
70 ///
71 /// ```
72 /// # use googletest::prelude::*;
73 /// #[derive(Debug)]
74 /// struct MyStruct {
75 ///     a_nested_struct: MyInnerStruct,
76 /// }
77 ///
78 /// #[derive(Debug)]
79 /// struct MyInnerStruct {
80 ///     a_field: String,
81 /// }
82 ///
83 /// let my_struct = MyStruct {
84 ///     a_nested_struct: MyInnerStruct { a_field: "Something to believe in".into() },
85 /// };
86 /// verify_that!(my_struct, matches_pattern!(MyStruct {
87 ///     a_nested_struct: matches_pattern!(MyInnerStruct {
88 ///         a_field: starts_with("Something"),
89 ///     }),
90 /// }))
91 /// #     .unwrap();
92 /// ```
93 ///
94 /// One can use the alias [`pat`][crate::matchers::pat] to make this less
95 /// verbose:
96 ///
97 /// ```
98 /// # use googletest::prelude::*;
99 /// # #[derive(Debug)]
100 /// # struct MyStruct {
101 /// #     a_nested_struct: MyInnerStruct,
102 /// # }
103 /// #
104 /// # #[derive(Debug)]
105 /// # struct MyInnerStruct {
106 /// #     a_field: String,
107 /// # }
108 /// #
109 /// # let my_struct = MyStruct {
110 /// #     a_nested_struct: MyInnerStruct { a_field: "Something to believe in".into() },
111 /// # };
112 /// verify_that!(my_struct, matches_pattern!(MyStruct {
113 ///     a_nested_struct: pat!(MyInnerStruct {
114 ///         a_field: starts_with("Something"),
115 ///     }),
116 /// }))
117 /// #     .unwrap();
118 /// ```
119 ///
120 /// In addition to fields, one can match on the outputs of methods
121 /// ("properties"):
122 ///
123 /// ```
124 /// # use googletest::prelude::*;
125 /// #[derive(Debug)]
126 /// struct MyStruct {
127 ///     a_field: String,
128 /// }
129 ///
130 /// impl MyStruct {
131 ///     fn get_a_field(&self) -> String { self.a_field.clone() }
132 /// }
133 ///
134 /// let my_struct = MyStruct { a_field: "Something to believe in".into() };
135 /// verify_that!(my_struct, matches_pattern!(MyStruct {
136 ///     get_a_field(): starts_with("Something"),
137 /// }))
138 /// #     .unwrap();
139 /// ```
140 ///
141 /// **Important**: The method should be pure function with a deterministic
142 /// output and no side effects. In particular, in the event of an assertion
143 /// failure, it will be invoked a second time, with the assertion failure output
144 /// reflecting the *second* invocation.
145 ///
146 /// These may also include extra parameters you pass in:
147 ///
148 /// ```
149 /// # use googletest::prelude::*;
150 /// # #[derive(Debug)]
151 /// # struct MyStruct {
152 /// #     a_field: String,
153 /// # }
154 /// #
155 /// impl MyStruct {
156 ///     fn append_to_a_field(&self, suffix: &str) -> String { self.a_field.clone() + suffix }
157 /// }
158 ///
159 /// # let my_struct = MyStruct { a_field: "Something to believe in".into() };
160 /// verify_that!(my_struct, matches_pattern!(MyStruct {
161 ///     append_to_a_field("a suffix"): ends_with("a suffix"),
162 /// }))
163 /// #     .unwrap();
164 /// ```
165 ///
166 /// If the method returns a reference, precede it with a `*`:
167 ///
168 /// ```
169 /// # use googletest::prelude::*;
170 /// # #[derive(Debug)]
171 /// # struct MyStruct {
172 /// #     a_field: String,
173 /// # }
174 /// #
175 /// impl MyStruct {
176 ///     fn get_a_field_ref(&self) -> &String { &self.a_field }
177 /// }
178 ///
179 /// # let my_struct = MyStruct { a_field: "Something to believe in".into() };
180 /// verify_that!(my_struct, matches_pattern!(MyStruct {
181 ///     *get_a_field_ref(): starts_with("Something"),
182 /// }))
183 /// #    .unwrap();
184 /// ```
185 ///
186 /// One can also match tuple structs with up to 10 fields. In this case, all
187 /// fields must have matchers:
188 ///
189 /// ```
190 /// # use googletest::prelude::*;
191 /// #[derive(Debug)]
192 /// struct MyTupleStruct(String, String);
193 ///
194 /// let my_struct = MyTupleStruct("Something".into(), "Some other thing".into());
195 /// verify_that!(
196 ///     my_struct,
197 ///     matches_pattern!(MyTupleStruct(eq("Something"), eq("Some other thing")))
198 /// )
199 /// #    .unwrap();
200 /// ```
201 ///
202 /// One can also match enum values:
203 ///
204 /// ```
205 /// # use googletest::prelude::*;
206 /// #[derive(Debug)]
207 /// enum MyEnum {
208 ///     A(u32),
209 ///     B,
210 /// }
211 ///
212 /// # fn should_pass() -> Result<()> {
213 /// verify_that!(MyEnum::A(123), matches_pattern!(MyEnum::A(eq(123))))?; // Passes
214 /// #     Ok(())
215 /// # }
216 /// # fn should_fail() -> Result<()> {
217 /// verify_that!(MyEnum::B, matches_pattern!(MyEnum::A(eq(123))))?; // Fails - wrong enum variant
218 /// #     Ok(())
219 /// # }
220 /// # should_pass().unwrap();
221 /// # should_fail().unwrap_err();
222 /// ```
223 ///
224 /// This macro does not support plain (non-struct) tuples. Use the macro
225 /// [`tuple`] for that purpose.
226 ///
227 /// Trailing commas are allowed (but not required) in both ordinary and tuple
228 /// structs.
229 ///
230 /// Unfortunately, this matcher does *not* work with methods returning string
231 /// slices:
232 ///
233 /// ```compile_fail
234 /// # use googletest::prelude::*;
235 /// # #[derive(Debug)]
236 /// pub struct MyStruct {
237 ///     a_string: String,
238 /// }
239 /// impl MyStruct {
240 ///     pub fn get_a_string(&self) -> &str { &self.a_string }
241 /// }
242 ///
243 /// let value = MyStruct { a_string: "A string".into() };
244 /// verify_that!(value, matches_pattern!( MyStruct {
245 ///     get_a_string(): eq("A string"),   // Does not compile
246 /// }))
247 /// #    .unwrap();
248 /// ```
249 #[macro_export]
250 #[doc(hidden)]
251 macro_rules! __matches_pattern {
252     ($($t:tt)*) => { $crate::matches_pattern_internal!($($t)*) }
253 }
254 
255 // Internal-only macro created so that the macro definition does not appear in
256 // generated documentation.
257 #[doc(hidden)]
258 #[macro_export]
259 macro_rules! matches_pattern_internal {
260     (
261         [$($struct_name:tt)*],
262         { $field_name:ident : $matcher:expr $(,)? }
263     ) => {
264         $crate::matchers::__internal_unstable_do_not_depend_on_these::is(
265             stringify!($($struct_name)*),
266             all!(field!($($struct_name)*.$field_name, $matcher))
267         )
268     };
269 
270     (
271         [$($struct_name:tt)*],
272         { $property_name:ident($($argument:expr),* $(,)?) : $matcher:expr $(,)? }
273     ) => {
274         $crate::matchers::__internal_unstable_do_not_depend_on_these::is(
275             stringify!($($struct_name)*),
276             all!(property!($($struct_name)*.$property_name($($argument),*), $matcher))
277         )
278     };
279 
280     (
281         [$($struct_name:tt)*],
282         { * $property_name:ident($($argument:expr),* $(,)?) : $matcher:expr $(,)? }
283     ) => {
284         $crate::matchers::__internal_unstable_do_not_depend_on_these::is(
285             stringify!($($struct_name)*),
286             all!(property!(* $($struct_name)*.$property_name($($argument),*), $matcher))
287         )
288     };
289 
290     (
291         [$($struct_name:tt)*],
292         { $field_name:ident : $matcher:expr, $($rest:tt)* }
293     ) => {
294         $crate::matches_pattern_internal!(
295             all!(field!($($struct_name)*.$field_name, $matcher)),
296             [$($struct_name)*],
297             { $($rest)* }
298         )
299     };
300 
301     (
302         [$($struct_name:tt)*],
303         { $property_name:ident($($argument:expr),* $(,)?) : $matcher:expr, $($rest:tt)* }
304     ) => {
305         $crate::matches_pattern_internal!(
306             all!(property!($($struct_name)*.$property_name($($argument),*), $matcher)),
307             [$($struct_name)*],
308             { $($rest)* }
309         )
310     };
311 
312     (
313         [$($struct_name:tt)*],
314         { * $property_name:ident($($argument:expr),* $(,)?) : $matcher:expr, $($rest:tt)* }
315     ) => {
316         $crate::matches_pattern_internal!(
317             all!(property!(* $($struct_name)*.$property_name($($argument),*), $matcher)),
318             [$($struct_name)*],
319             { $($rest)* }
320         )
321     };
322 
323     (
324         all!($($processed:tt)*),
325         [$($struct_name:tt)*],
326         { $field_name:ident : $matcher:expr $(,)? }
327     ) => {
328         $crate::matchers::__internal_unstable_do_not_depend_on_these::is(stringify!($($struct_name)*), all!(
329             $($processed)*,
330             field!($($struct_name)*.$field_name, $matcher)
331         ))
332     };
333 
334     (
335         all!($($processed:tt)*),
336         [$($struct_name:tt)*],
337         { $property_name:ident($($argument:expr),* $(,)?) : $matcher:expr $(,)? }
338     ) => {
339         $crate::matchers::__internal_unstable_do_not_depend_on_these::is(stringify!($($struct_name)*), all!(
340             $($processed)*,
341             property!($($struct_name)*.$property_name($($argument),*), $matcher)
342         ))
343     };
344 
345     (
346         all!($($processed:tt)*),
347         [$($struct_name:tt)*],
348         { * $property_name:ident($($argument:expr),* $(,)?) : $matcher:expr $(,)? }
349     ) => {
350         $crate::matchers::__internal_unstable_do_not_depend_on_these::is(stringify!($($struct_name)*), all!(
351             $($processed)*,
352             property!(* $($struct_name)*.$property_name($($argument),*), $matcher)
353         ))
354     };
355 
356     (
357         all!($($processed:tt)*),
358         [$($struct_name:tt)*],
359         { $field_name:ident : $matcher:expr, $($rest:tt)* }
360     ) => {
361         $crate::matches_pattern_internal!(
362             all!(
363                 $($processed)*,
364                 field!($($struct_name)*.$field_name, $matcher)
365             ),
366             [$($struct_name)*],
367             { $($rest)* }
368         )
369     };
370 
371     (
372         all!($($processed:tt)*),
373         [$($struct_name:tt)*],
374         { $property_name:ident($($argument:expr),* $(,)?) : $matcher:expr, $($rest:tt)* }
375     ) => {
376         $crate::matches_pattern_internal!(
377             all!(
378                 $($processed)*,
379                 property!($($struct_name)*.$property_name($($argument),*), $matcher)
380             ),
381             [$($struct_name)*],
382             { $($rest)* }
383         )
384     };
385 
386     (
387         all!($($processed:tt)*),
388         [$($struct_name:tt)*],
389         { * $property_name:ident($($argument:expr),* $(,)?) : $matcher:expr, $($rest:tt)* }
390     ) => {
391         $crate::matches_pattern_internal!(
392             all!(
393                 $($processed)*,
394                 property!(* $($struct_name)*.$property_name($($argument),*), $matcher)
395             ),
396             [$($struct_name)*],
397             { $($rest)* }
398         )
399     };
400 
401     (
402         [$($struct_name:tt)*],
403     ) => {
404         $crate::matchers::predicate(|v| matches!(v, $($struct_name)*))
405             .with_description(
406                 concat!("is ", stringify!($($struct_name)*)),
407                 concat!("is not ", stringify!($($struct_name)*)),
408             )
409     };
410 
411     (
412         [$($struct_name:tt)*],
413         ($matcher:expr $(,)?)
414     ) => {
415         $crate::matchers::__internal_unstable_do_not_depend_on_these::is(
416             stringify!($($struct_name)*),
417             all!(field!($($struct_name)*.0, $matcher))
418         )
419     };
420 
421     (
422         [$($struct_name:tt)*],
423         ($matcher:expr, $($rest:tt)*)
424     ) => {
425         $crate::matches_pattern_internal!(
426             all!(
427                 field!($($struct_name)*.0, $matcher)
428             ),
429             [$($struct_name)*],
430             1,
431             ($($rest)*)
432         )
433     };
434 
435     (
436         all!($($processed:tt)*),
437         [$($struct_name:tt)*],
438         $field:tt,
439         ($matcher:expr $(,)?)
440     ) => {
441         $crate::matchers::__internal_unstable_do_not_depend_on_these::is(stringify!($($struct_name)*), all!(
442             $($processed)*,
443             field!($($struct_name)*.$field, $matcher)
444         ))
445     };
446 
447     // We need to repeat this once for every supported field position, unfortunately. There appears
448     // to be no way in declarative macros to compute $field + 1 and have the result evaluated to a
449     // token which can be used as a tuple index.
450     (
451         all!($($processed:tt)*),
452         [$($struct_name:tt)*],
453         1,
454         ($matcher:expr, $($rest:tt)*)
455     ) => {
456         $crate::matches_pattern_internal!(
457             all!(
458                 $($processed)*,
459                 field!($($struct_name)*.1, $matcher)
460             ),
461             [$($struct_name)*],
462             2,
463             ($($rest)*)
464         )
465     };
466 
467     (
468         all!($($processed:tt)*),
469         [$($struct_name:tt)*],
470         2,
471         ($matcher:expr, $($rest:tt)*)
472     ) => {
473         $crate::matches_pattern_internal!(
474             all!(
475                 $($processed)*,
476                 field!($($struct_name)*.2, $matcher)
477             ),
478             [$($struct_name)*],
479             3,
480             ($($rest)*)
481         )
482     };
483 
484     (
485         all!($($processed:tt)*),
486         [$($struct_name:tt)*],
487         3,
488         ($matcher:expr, $($rest:tt)*)
489     ) => {
490         $crate::matches_pattern_internal!(
491             all!(
492                 $($processed)*,
493                 field!($($struct_name)*.3, $matcher)
494             ),
495             [$($struct_name)*],
496             4,
497             ($($rest)*)
498         )
499     };
500 
501     (
502         all!($($processed:tt)*),
503         [$($struct_name:tt)*],
504         4,
505         ($matcher:expr, $($rest:tt)*)
506     ) => {
507         $crate::matches_pattern_internal!(
508             all!(
509                 $($processed)*,
510                 field!($($struct_name)*.4, $matcher)
511             ),
512             [$($struct_name)*],
513             5,
514             ($($rest)*)
515         )
516     };
517 
518     (
519         all!($($processed:tt)*),
520         [$($struct_name:tt)*],
521         5,
522         ($matcher:expr, $($rest:tt)*)
523     ) => {
524         $crate::matches_pattern_internal!(
525             all!(
526                 $($processed)*,
527                 field!($($struct_name)*.5, $matcher)
528             ),
529             [$($struct_name)*],
530             6,
531             ($($rest)*)
532         )
533     };
534 
535     (
536         all!($($processed:tt)*),
537         [$($struct_name:tt)*],
538         6,
539         ($matcher:expr, $($rest:tt)*)
540     ) => {
541         $crate::matches_pattern_internal!(
542             all!(
543                 $($processed)*,
544                 field!($($struct_name)*.6, $matcher)
545             ),
546             [$($struct_name)*],
547             7,
548             ($($rest)*)
549         )
550     };
551 
552     (
553         all!($($processed:tt)*),
554         [$($struct_name:tt)*],
555         7,
556         ($matcher:expr, $($rest:tt)*)
557     ) => {
558         $crate::matches_pattern_internal!(
559             all!(
560                 $($processed)*,
561                 field!($($struct_name)*.7, $matcher)
562             ),
563             [$($struct_name)*],
564             8,
565             ($($rest)*)
566         )
567     };
568 
569     (
570         all!($($processed:tt)*),
571         [$($struct_name:tt)*],
572         8,
573         ($matcher:expr, $($rest:tt)*)
574     ) => {
575         $crate::matches_pattern_internal!(
576             all!(
577                 $($processed)*,
578                 field!($($struct_name)*.8, $matcher)
579             ),
580             [$($struct_name)*],
581             9,
582             ($($rest)*)
583         )
584     };
585 
586     ([$($struct_name:tt)*], $first:tt $($rest:tt)*) => {
587         $crate::matches_pattern_internal!([$($struct_name)* $first], $($rest)*)
588     };
589 
590     ($first:tt $($rest:tt)*) => {{
591         #[allow(unused)]
592         use $crate::matchers::{all, field, property};
593         $crate::matches_pattern_internal!([$first], $($rest)*)
594     }};
595 }
596 
597 /// An alias for [`matches_pattern`][crate::matchers::matches_pattern!].
598 #[macro_export]
599 #[doc(hidden)]
600 macro_rules! __pat {
601     ($($t:tt)*) => { $crate::matches_pattern_internal!($($t)*) }
602 }
603