Skip to main content

googletest/matchers/
unordered_elements_are_matcher.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 container whose elements in any order have a 1:1 correspondence
20/// with the provided element matchers.
21///
22/// ```
23/// # use googletest::prelude::*;
24/// # fn should_pass() -> Result<()> {
25/// verify_that!(vec![3, 2, 1], unordered_elements_are![eq(&1), ge(&2), anything()])?;   // Passes
26/// #     Ok(())
27/// # }
28/// # fn should_fail_1() -> Result<()> {
29/// verify_that!(vec![1], unordered_elements_are![eq(&1), ge(&2)])?;              // Fails: container has wrong size
30/// #     Ok(())
31/// # }
32/// # fn should_fail_2() -> Result<()> {
33/// verify_that!(vec![3, 2, 1], unordered_elements_are![eq(&1), ge(&4), eq(&2)])?; // Fails: second matcher not matched
34/// #     Ok(())
35/// # }
36/// # fn should_fail_3() -> Result<()> {
37/// verify_that!(vec![3, 2, 1], unordered_elements_are![ge(&3), ge(&3), ge(&3)])?; // Fails: no 1:1 correspondence
38/// #     Ok(())
39/// # }
40/// # should_pass().unwrap();
41/// # should_fail_1().unwrap_err();
42/// # should_fail_2().unwrap_err();
43/// # should_fail_3().unwrap_err();
44/// ```
45///
46/// The actual value must be a container such as a `&Vec`, an array, or a
47/// slice. More precisely, the actual value must implement [`IntoIterator`].
48///
49/// This can also be omitted in [`verify_that!`] macros and replaced with curly
50/// brackets.
51///
52/// ```
53/// # use googletest::prelude::*;
54///  verify_that!(vec![1, 2], {eq(&2), eq(&1)})
55/// #     .unwrap();
56/// ```
57///
58/// Note: This behavior is only possible in [`verify_that!`] macros. In any
59/// other cases, it is still necessary to use the
60/// [`unordered_elements_are!`][crate::matchers::unordered_elements_are] macro.
61///
62/// ```compile_fail
63/// # use googletest::prelude::*;
64/// verify_that!(vec![vec![1,2], vec![3]], {{eq(2), eq(1)}, {eq(3)}})
65/// # .unwrap();
66/// ```
67///
68/// Use this instead:
69/// ```
70/// # use googletest::prelude::*;
71/// verify_that!(vec![vec![1,2], vec![3]],
72///   {unordered_elements_are![eq(&2), eq(&1)], unordered_elements_are![eq(&3)]})
73/// # .unwrap();
74/// ```
75///
76///  If an inner matcher is `eq(...)`, it can be omitted:
77///
78/// ```
79/// # use googletest::prelude::*;
80///
81/// verify_that!(vec![1,2,3], unordered_elements_are![lt(&2), gt(&1), &3])
82/// #     .unwrap();
83/// ```
84///
85/// The matcher proceeds in three stages:
86///
87/// 1. It first checks whether the actual value is of the right size to possibly
88///    be matched by each of the given matchers. If not, then it immediately
89///    fails explaining that the size is incorrect.
90///
91/// 2. It then checks whether each matcher matches at least one corresponding
92///    element in the actual container and each element in the actual container
93///    is matched by at least one matcher. If not, it fails with a message
94///    indicating which matcher respectively container elements had no
95///    counterparts.
96///
97/// 3. Finally, it checks whether the mapping of matchers to corresponding
98///    actual elements is a 1-1 correspondence and fails if that is not the
99///    case. The failure message then shows the best matching it could find,
100///    including which matchers did not have corresponding unique elements in
101///    the container and which container elements had no corresponding matchers.
102///
103/// [`IntoIterator`]: std::iter::IntoIterator
104/// [`Iterator`]: std::iter::Iterator
105/// [`Iterator::collect`]: std::iter::Iterator::collect
106/// [`Vec`]: std::vec::Vec
107#[macro_export]
108#[doc(hidden)]
109macro_rules! __unordered_elements_are {
110    ($(,)?) => {{
111        $crate::matchers::__internal_unstable_do_not_depend_on_these::
112        UnorderedElementsAreMatcher::new(
113            (),
114            $crate::matchers::__internal_unstable_do_not_depend_on_these::
115            Requirements::PerfectMatch)
116    }};
117
118    ($($matcher:expr),* $(,)?) => {{
119        $crate::matchers::__internal_unstable_do_not_depend_on_these::
120        UnorderedElementsAreMatcher::new(
121            ($(
122                $crate::matcher_support::__internal_unstable_do_not_depend_on_these::auto_eq!(
123                    $matcher
124                )
125            ,)*),
126            $crate::matchers::__internal_unstable_do_not_depend_on_these::
127            Requirements::PerfectMatch)
128    }};
129}
130
131/// Matches a container containing elements matched by the given matchers.
132///
133/// To match, each given matcher must have a corresponding element in the
134/// container which it matches. There must be a mapping uniquely matching each
135/// matcher to a container element. The container can, however, contain
136/// additional elements that don't correspond to any matcher.
137///
138/// Put another way, `contains_each!` matches if there is a subset of the actual
139/// container which
140/// [`unordered_elements_are`][crate::matchers::unordered_elements_are] would
141/// match.
142///
143/// ```
144/// # use googletest::prelude::*;
145/// # fn should_pass() -> Result<()> {
146/// verify_that!(vec![3, 2, 1], contains_each![eq(&2), ge(&3)])?;   // Passes
147/// verify_that!(vec![3, 2, 1], contains_each![ge(&2), ge(&2)])?;   // Passes
148/// #     Ok(())
149/// # }
150/// # fn should_fail_1() -> Result<()> {
151/// verify_that!(vec![1], contains_each![eq(&1), ge(&2)])?;         // Fails: container too small
152/// #     Ok(())
153/// # }
154/// # fn should_fail_2() -> Result<()> {
155/// verify_that!(vec![3, 2, 1], contains_each![eq(&1), ge(&4)])?;   // Fails: second matcher unmatched
156/// #     Ok(())
157/// # }
158/// # fn should_fail_3() -> Result<()> {
159/// verify_that!(vec![3, 2, 1], contains_each![ge(&3), ge(&3), ge(&3)])?; // Fails: no matching
160/// #     Ok(())
161/// # }
162/// # should_pass().unwrap();
163/// # should_fail_1().unwrap_err();
164/// # should_fail_2().unwrap_err();
165/// # should_fail_3().unwrap_err();
166/// ```
167///
168/// The actual value must be a container such as a `&Vec`, an array, or a
169/// slice. More precisely, the actual value must implement [`IntoIterator`].
170///
171///  If an inner matcher is `eq(...)`, it can be omitted:
172///
173/// ```
174/// # use googletest::prelude::*;
175///
176/// verify_that!(vec![1,2,3], contains_each![lt(&2), &3])
177/// #     .unwrap();
178/// ```
179///
180/// The matcher proceeds in three stages:
181///
182/// 1. It first checks whether the actual value is large enough to possibly be
183///    matched by each of the given matchers. If not, then it immediately fails
184///    explaining that the size is too small.
185///
186/// 2. It then checks whether each matcher matches at least one corresponding
187///    element in the actual container and fails if that is not the case. The
188///    failure message indicates which matcher had no corresponding element.
189///
190/// 3. Finally, it checks whether the mapping of matchers to corresponding
191///    actual elements is 1-1 and fails if that is not the case. The failure
192///    message then shows the best matching it could find, including which
193///    matchers did not have corresponding unique elements in the container.
194///
195/// [`IntoIterator`]: std::iter::IntoIterator
196/// [`Iterator`]: std::iter::Iterator
197/// [`Iterator::collect`]: std::iter::Iterator::collect
198/// [`Vec`]: std::vec::Vec
199#[macro_export]
200#[doc(hidden)]
201macro_rules! __contains_each {
202    ($(,)?) => {{
203        $crate::matchers::__internal_unstable_do_not_depend_on_these::
204        UnorderedElementsAreMatcher::new(
205            (),
206            $crate::matchers::__internal_unstable_do_not_depend_on_these::Requirements::Superset)
207    }};
208
209    ($($matcher:expr),* $(,)?) => {{
210        $crate::matchers::__internal_unstable_do_not_depend_on_these::
211        UnorderedElementsAreMatcher::new(
212            ($(
213                $crate::matcher_support::__internal_unstable_do_not_depend_on_these::auto_eq!(
214                    $matcher
215                )
216            ,)*),
217            $crate::matchers::__internal_unstable_do_not_depend_on_these::Requirements::Superset)
218    }}
219}
220
221/// Matches a container all of whose elements are matched by the given matchers.
222///
223/// To match, each element in the container must have a corresponding matcher
224/// which matches it. There must be a 1-1 mapping from container elements to
225/// matchers, so that no matcher has more than one corresponding element.
226///
227/// There may, however, be matchers not corresponding to any elements in the
228/// container.
229///
230/// Put another way, `is_contained_in!` matches if there is a subset of the
231/// matchers which would match with
232/// [`unordered_elements_are`][crate::matchers::unordered_elements_are].
233///
234/// ```
235/// # use googletest::prelude::*;
236/// # fn should_pass() -> Result<()> {
237/// verify_that!(vec![2, 1], is_contained_in![eq(&1), ge(&2)])?;   // Passes
238/// verify_that!(vec![2, 1], is_contained_in![ge(&1), ge(&1)])?;   // Passes
239/// #     Ok(())
240/// # }
241/// # fn should_fail_1() -> Result<()> {
242/// verify_that!(vec![1, 2, 3], is_contained_in![eq(&1), ge(&2)])?; // Fails: container too large
243/// #     Ok(())
244/// # }
245/// # fn should_fail_2() -> Result<()> {
246/// verify_that!(vec![2, 1], is_contained_in![eq(&1), ge(&4)])?;    // Fails: second matcher unmatched
247/// #     Ok(())
248/// # }
249/// # fn should_fail_3() -> Result<()> {
250/// verify_that!(vec![3, 1], is_contained_in![ge(&3), ge(&3), ge(&3)])?; // Fails: no matching
251/// #     Ok(())
252/// # }
253/// # should_pass().unwrap();
254/// # should_fail_1().unwrap_err();
255/// # should_fail_2().unwrap_err();
256/// # should_fail_3().unwrap_err();
257/// ```
258///
259/// The actual value must be a container such as a `&Vec`, an array, or a slice.
260/// More precisely, the actual value must implement [`IntoIterator`].
261///
262///  If an inner matcher is `eq(...)`, it can be omitted:
263///
264/// ```
265/// # use googletest::prelude::*;
266///
267/// verify_that!(vec![1,2,3], is_contained_in![lt(&2), &3, &4, gt(&0)])
268/// #     .unwrap();
269/// ```
270///
271/// The matcher proceeds in three stages:
272///
273/// 1. It first checks whether the actual value is too large to possibly be
274///    matched by each of the given matchers. If so, it immediately fails
275///    explaining that the size is too large.
276///
277/// 2. It then checks whether each actual container element is matched by at
278///    least one matcher and fails if that is not the case. The failure message
279///    indicates which element had no corresponding matcher.
280///
281/// 3. Finally, it checks whether the mapping of elements to corresponding
282///    matchers is 1-1 and fails if that is not the case. The failure message
283///    then shows the best matching it could find, including which container
284///    elements did not have corresponding matchers.
285///
286/// [`IntoIterator`]: std::iter::IntoIterator
287/// [`Iterator`]: std::iter::Iterator
288/// [`Iterator::collect`]: std::iter::Iterator::collect
289/// [`Vec`]: std::vec::Vec
290#[macro_export]
291#[doc(hidden)]
292macro_rules! __is_contained_in {
293    ($(,)?) => {{
294        $crate::matchers::__internal_unstable_do_not_depend_on_these::
295        UnorderedElementsAreMatcher::new(
296            (), $crate::matchers::__internal_unstable_do_not_depend_on_these::Requirements::Subset)
297    }};
298
299    ($($matcher:expr),* $(,)?) => {{
300        $crate::matchers::__internal_unstable_do_not_depend_on_these::
301        UnorderedElementsAreMatcher::new(
302            ($(
303                $crate::matcher_support::__internal_unstable_do_not_depend_on_these::auto_eq!(
304                    $matcher
305                )
306            ,)*),
307            $crate::matchers::__internal_unstable_do_not_depend_on_these::Requirements::Subset)
308    }}
309}
310
311/// Module for use only by the macros in this module.
312///
313/// **For internal use only. API stablility is not guaranteed!**
314#[doc(hidden)]
315pub mod internal {
316    use crate::description::Description;
317    use crate::matcher::{Matcher, MatcherBase, MatcherResult};
318    use crate::matcher_support::match_matrix::internal::{MatchMatrix, Requirements};
319    use std::fmt::Debug;
320
321    /// A trait for a tuple of matchers.
322    pub trait MatcherTuple<T: Debug + Copy> {
323        /// Turn the tuple into a vector of matchers.
324        fn to_matchers(&self) -> Vec<Box<dyn Matcher<T> + '_>>;
325    }
326
327    // Base case, no matchers.
328    impl<T: Debug + Copy> MatcherTuple<T> for () {
329        fn to_matchers(&self) -> Vec<Box<dyn Matcher<T> + '_>> {
330            vec![]
331        }
332    }
333
334    // A macro for generating a MatcherTuple implementation for a given number
335    // of matchers.
336    macro_rules! matcher_tuple_n {
337        // Given list of (field_number, matcher) pairs, generate a MatcherTuple
338        // implementation.
339        ($([$field_number:tt, $matcher_type:ident]),*) => {
340            impl<T: Debug + Copy, $($matcher_type: Matcher<T>),*> MatcherTuple<T>
341            for ($($matcher_type,)*) {
342                // Our implementation of to_matchers just converts our tuple into a vector of
343                // matchers by expanding self.0, self.1, etc.
344                fn to_matchers(&self) -> Vec<Box<dyn Matcher<T> + '_>> {
345                    vec![$(Box::new(&self.$field_number)),*]
346                }
347            }
348        };
349    }
350
351    matcher_tuple_n!([0, M0]);
352    matcher_tuple_n!([0, M0], [1, M1]);
353    matcher_tuple_n!([0, M0], [1, M1], [2, M2]);
354    matcher_tuple_n!([0, M0], [1, M1], [2, M2], [3, M3]);
355    matcher_tuple_n!([0, M0], [1, M1], [2, M2], [3, M3], [4, M4]);
356    matcher_tuple_n!([0, M0], [1, M1], [2, M2], [3, M3], [4, M4], [5, M5]);
357    matcher_tuple_n!([0, M0], [1, M1], [2, M2], [3, M3], [4, M4], [5, M5], [6, M6]);
358    matcher_tuple_n!([0, M0], [1, M1], [2, M2], [3, M3], [4, M4], [5, M5], [6, M6], [7, M7]);
359    matcher_tuple_n!(
360        [0, M0],
361        [1, M1],
362        [2, M2],
363        [3, M3],
364        [4, M4],
365        [5, M5],
366        [6, M6],
367        [7, M7],
368        [8, M8]
369    );
370    matcher_tuple_n!(
371        [0, M0],
372        [1, M1],
373        [2, M2],
374        [3, M3],
375        [4, M4],
376        [5, M5],
377        [6, M6],
378        [7, M7],
379        [8, M8],
380        [9, M9]
381    );
382    matcher_tuple_n!(
383        [0, M0],
384        [1, M1],
385        [2, M2],
386        [3, M3],
387        [4, M4],
388        [5, M5],
389        [6, M6],
390        [7, M7],
391        [8, M8],
392        [9, M9],
393        [10, M10]
394    );
395    matcher_tuple_n!(
396        [0, M0],
397        [1, M1],
398        [2, M2],
399        [3, M3],
400        [4, M4],
401        [5, M5],
402        [6, M6],
403        [7, M7],
404        [8, M8],
405        [9, M9],
406        [10, M10],
407        [11, M11]
408    );
409
410    /// This struct is meant to be used only through the
411    /// `unordered_elements_are![...]` macro.
412    ///
413    /// **For internal use only. API stablility is not guaranteed!**
414    #[doc(hidden)]
415    #[derive(MatcherBase)]
416    pub struct UnorderedElementsAreMatcher<M> {
417        matchers: M,
418        requirements: Requirements,
419    }
420
421    impl<M> UnorderedElementsAreMatcher<M> {
422        pub fn new(matchers: M, requirements: Requirements) -> Self {
423            Self { matchers, requirements }
424        }
425    }
426
427    // This matcher performs the checks in three different steps in both `matches`
428    // and `explain_match`. This is useful for performance but also to produce
429    // an actionable error message.
430    // 1. `UnorderedElementsAreMatcher` verifies that both collections have the same
431    // size
432    // 2. `UnorderedElementsAreMatcher` verifies that each actual element matches at
433    // least one expected element and vice versa.
434    // 3. `UnorderedElementsAreMatcher` verifies that a perfect matching exists
435    // using Ford-Fulkerson.
436    impl<T: Debug + Copy, ContainerT: Debug + Copy, M> Matcher<ContainerT>
437        for UnorderedElementsAreMatcher<M>
438    where
439        ContainerT: IntoIterator<Item = T>,
440        M: MatcherTuple<T>,
441    {
442        fn matches(&self, actual: ContainerT) -> MatcherResult {
443            let matchers = self.matchers.to_matchers();
444            let match_matrix = MatchMatrix::generate(actual, &matchers);
445            match_matrix.is_match_for(self.requirements).into()
446        }
447
448        fn explain_match(&self, actual: ContainerT) -> Description {
449            let matchers = self.matchers.to_matchers();
450            if let Some(size_mismatch_explanation) =
451                self.requirements.explain_size_mismatch(actual, matchers.len())
452            {
453                return size_mismatch_explanation;
454            }
455
456            let match_matrix = MatchMatrix::generate(actual, &matchers);
457            if let Some(unmatchable_explanation) =
458                match_matrix.explain_unmatchable(self.requirements)
459            {
460                return unmatchable_explanation;
461            }
462
463            let best_match = match_matrix.find_best_match();
464            best_match
465                .get_explanation(actual, &matchers, self.requirements)
466                .unwrap_or("whose elements all match".into())
467        }
468
469        fn describe(&self, matcher_result: MatcherResult) -> Description {
470            let matchers = self.matchers.to_matchers();
471            format!(
472                "{} elements matching in any order:\n{}",
473                if matcher_result.into() { "contains" } else { "doesn't contain" },
474                matchers
475                    .iter()
476                    .map(|matcher| matcher.describe(MatcherResult::Match))
477                    .collect::<Description>()
478                    .enumerate()
479                    .indent()
480            )
481            .into()
482        }
483    }
484}
485
486#[cfg(test)]
487mod tests {
488    use crate as googletest;
489    use crate::description::Description;
490    use crate::matcher::MatcherResult;
491    use crate::prelude::*;
492    use indoc::indoc;
493    use std::collections::{HashMap, HashSet};
494
495    #[test]
496    fn has_correct_description_for_map() -> googletest::Result<()> {
497        // UnorderedElementsAreMatcher maintains references to the matchers, so the
498        // constituent matchers must live longer. Inside a verify_that! macro, the
499        // compiler takes care of that, but when the matcher is created separately,
500        // we must create the constitute matchers separately so that they
501        // aren't dropped too early.
502        let matchers = ((eq(&2), eq(&"Two")), (eq(&1), eq(&"One")), (eq(&3), eq(&"Three")));
503        let matcher = unordered_elements_are![
504            (matchers.0 .0, matchers.0 .1),
505            (matchers.1 .0, matchers.1 .1),
506            (matchers.2 .0, matchers.2 .1)
507        ];
508        verify_that!(
509            Matcher::<&HashMap<i32, String>>::describe(&matcher, MatcherResult::Match),
510            displays_as(eq(indoc!(
511                "
512                contains elements matching in any order:
513                  0. is a tuple whose values respectively match:
514                       is equal to 2
515                       is equal to \"Two\"
516                  1. is a tuple whose values respectively match:
517                       is equal to 1
518                       is equal to \"One\"
519                  2. is a tuple whose values respectively match:
520                       is equal to 3
521                       is equal to \"Three\""
522            )))
523        )
524    }
525
526    #[test]
527    fn unordered_elements_are_description_no_full_match_with_map() -> googletest::Result<()> {
528        // UnorderedElementsAreMatcher maintains references to the matchers, so the
529        // constituent matchers must live longer. Inside a verify_that! macro, the
530        // compiler takes care of that, but when the matcher is created separately,
531        // we must create the constitute matchers separately so that they
532        // aren't dropped too early.
533        let value: HashMap<u32, u32> = HashMap::from_iter([(0, 1), (1, 1), (2, 2)]);
534        let matchers = ((anything(), eq(&1)), (anything(), eq(&2)), (anything(), eq(&2)));
535        let matcher = unordered_elements_are![
536            (matchers.0 .0, matchers.0 .1),
537            (matchers.1 .0, matchers.1 .1),
538            (matchers.2 .0, matchers.2 .1),
539        ];
540        verify_that!(
541            matcher.explain_match(&value),
542            all![
543                displays_as(contains_regex(
544                    "Actual element \\(2, 2\\) at index [0-2] matched expected element `is a tuple whose values respectively match:\n    is anything\n    is equal to 2` at index [0-2]."
545                )),
546                displays_as(contains_regex(
547                    "Actual element \\(\n      [0-1],\n      [0-1],\n  \\) at index [0-2] did not match any remaining expected element."
548                )),
549                displays_as(contains_substring(
550                    "Expected element `is a tuple whose values respectively match:\n    is anything\n    is equal to 2` at index 2 did not match any remaining actual element."
551                ))
552            ]
553        )
554    }
555
556    // This test verifies that unordered_elements_are can be used as the inner
557    // matcher of another matcher, where the inner matcher is given a reference
558    // to a local variable. If unordered_elements_are stores its matchers in a
559    // Vec with the same type and lifetimes then this fails to compile.
560    #[test]
561    fn works_with_inner_matcher_that_modifies_the_input() -> googletest::Result<()> {
562        // A custom matcher that applies an operation to the input hashmap (filtering
563        // out any keys present in `to_filter`) and then applies the inner
564        // matcher to the modified input.
565        fn matches_filtered<'a, M>(
566            to_filter: &'a HashSet<i32>,
567            inner: M,
568        ) -> impl Matcher<&'a HashSet<i32>>
569        where
570            M: for<'b> Matcher<&'b HashSet<i32>>,
571        {
572            #[derive(MatcherBase)]
573            struct FilteredMatcher<'a, M> {
574                to_filter: &'a HashSet<i32>,
575                inner: M,
576            }
577
578            impl<'a, M> Matcher<&'a HashSet<i32>> for FilteredMatcher<'a, M>
579            where
580                M: for<'b> Matcher<&'b HashSet<i32>>,
581            {
582                fn matches(&self, actual: &'a HashSet<i32>) -> MatcherResult {
583                    let filtered: HashSet<i32> =
584                        actual.iter().filter(|k| !self.to_filter.contains(k)).cloned().collect();
585                    self.inner.matches(&filtered)
586                }
587
588                fn describe(&self, matcher_result: MatcherResult) -> Description {
589                    self.inner.describe(matcher_result)
590                }
591
592                fn explain_match(&self, actual: &'a HashSet<i32>) -> Description {
593                    let filtered: HashSet<i32> =
594                        actual.iter().filter(|k| !self.to_filter.contains(k)).cloned().collect();
595                    self.inner.explain_match(&filtered)
596                }
597            }
598
599            FilteredMatcher { to_filter, inner }
600        }
601
602        let before: HashSet<i32> = HashSet::from([1]);
603        let after: HashSet<i32> = HashSet::from([1, 2]);
604
605        verify_that!(&after, matches_filtered(&before, unordered_elements_are![eq(&2)]))?;
606
607        Ok(())
608    }
609}