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 /// dereferenced slice. More precisely, a shared borrow of the actual value must
48 /// implement [`IntoIterator`].
49 ///
50 /// This can also match against [`HashMap`][std::collections::HashMap] and
51 /// similar collections. The arguments are a sequence of pairs of matchers
52 /// corresponding to the keys and their respective values.
53 ///
54 /// ```
55 /// # use googletest::prelude::*;
56 /// # use std::collections::HashMap;
57 /// let value: HashMap<u32, &'static str> =
58 ///     HashMap::from_iter([(1, "One"), (2, "Two"), (3, "Three")]);
59 /// verify_that!(
60 ///     value,
61 ///     unordered_elements_are![(eq(2), eq("Two")), (eq(1), eq("One")), (eq(3), eq("Three"))]
62 /// )
63 /// #     .unwrap();
64 /// ```
65 ///
66 /// This can also be omitted in [`verify_that!`] macros and replaced with curly
67 /// brackets.
68 ///
69 /// ```
70 /// # use googletest::prelude::*;
71 ///  verify_that!(vec![1, 2], {eq(2), eq(1)})
72 /// #     .unwrap();
73 /// ```
74 ///
75 /// Note: This behavior is only possible in [`verify_that!`] macros. In any
76 /// other cases, it is still necessary to use the
77 /// [`unordered_elements_are!`][crate::matchers::unordered_elements_are] macro.
78 ///
79 /// ```compile_fail
80 /// # use googletest::prelude::*;
81 /// verify_that!(vec![vec![1,2], vec![3]], {{eq(2), eq(1)}, {eq(3)}})
82 /// # .unwrap();
83 /// ```
84 ///
85 /// Use this instead:
86 /// ```
87 /// # use googletest::prelude::*;
88 /// verify_that!(vec![vec![1,2], vec![3]],
89 ///   {unordered_elements_are![eq(2), eq(1)], unordered_elements_are![eq(3)]})
90 /// # .unwrap();
91 /// ```
92 ///
93 /// This matcher does not support matching directly against an [`Iterator`]. To
94 /// match against an iterator, use [`Iterator::collect`] to build a [`Vec`].
95 ///
96 /// The matcher proceeds in three stages:
97 ///
98 /// 1. It first checks whether the actual value is of the right size to possibly
99 ///    be matched by each of the given matchers. If not, then it immediately
100 ///    fails explaining that the size is incorrect.
101 ///
102 /// 2. It then checks whether each matcher matches at least one corresponding
103 ///    element in the actual container and each element in the actual container
104 ///    is matched by at least one matcher. If not, it fails with a message
105 ///    indicating which matcher respectively container elements had no
106 ///    counterparts.
107 ///
108 /// 3. Finally, it checks whether the mapping of matchers to corresponding
109 ///    actual elements is a 1-1 correspondence and fails if that is not the
110 ///    case. The failure message then shows the best matching it could find,
111 ///    including which matchers did not have corresponding unique elements in
112 ///    the container and which container elements had no corresponding matchers.
113 ///
114 /// [`IntoIterator`]: std::iter::IntoIterator
115 /// [`Iterator`]: std::iter::Iterator
116 /// [`Iterator::collect`]: std::iter::Iterator::collect
117 /// [`Vec`]: std::vec::Vec
118 #[macro_export]
119 #[doc(hidden)]
120 macro_rules! __unordered_elements_are {
121     ($(,)?) => {{
122         use $crate::matchers::__internal_unstable_do_not_depend_on_these::{
123             UnorderedElementsAreMatcher, Requirements
124         };
125         UnorderedElementsAreMatcher::new([], Requirements::PerfectMatch)
126     }};
127 
128     // TODO: Consider an alternative map-like syntax here similar to that used in
129     // https://crates.io/crates/maplit.
130     ($(($key_matcher:expr, $value_matcher:expr)),* $(,)?) => {{
131         use $crate::matchers::__internal_unstable_do_not_depend_on_these::{
132             UnorderedElementsOfMapAreMatcher, Requirements
133         };
134         UnorderedElementsOfMapAreMatcher::new(
135             [$((Box::new($key_matcher), Box::new($value_matcher))),*],
136             Requirements::PerfectMatch
137         )
138     }};
139 
140     ($($matcher:expr),* $(,)?) => {{
141         use $crate::matchers::__internal_unstable_do_not_depend_on_these::{
142             UnorderedElementsAreMatcher, Requirements
143         };
144         UnorderedElementsAreMatcher::new([$(Box::new($matcher)),*], Requirements::PerfectMatch)
145     }};
146 }
147 
148 /// Matches a container containing elements matched by the given matchers.
149 ///
150 /// To match, each given matcher must have a corresponding element in the
151 /// container which it matches. There must be a mapping uniquely matching each
152 /// matcher to a container element. The container can, however, contain
153 /// additional elements that don't correspond to any matcher.
154 ///
155 /// Put another way, `contains_each!` matches if there is a subset of the actual
156 /// container which
157 /// [`unordered_elements_are`][crate::matchers::unordered_elements_are] would
158 /// match.
159 ///
160 /// ```
161 /// # use googletest::prelude::*;
162 /// # fn should_pass() -> Result<()> {
163 /// verify_that!(vec![3, 2, 1], contains_each![eq(2), ge(3)])?;   // Passes
164 /// verify_that!(vec![3, 2, 1], contains_each![ge(2), ge(2)])?;   // Passes
165 /// #     Ok(())
166 /// # }
167 /// # fn should_fail_1() -> Result<()> {
168 /// verify_that!(vec![1], contains_each![eq(1), ge(2)])?;         // Fails: container too small
169 /// #     Ok(())
170 /// # }
171 /// # fn should_fail_2() -> Result<()> {
172 /// verify_that!(vec![3, 2, 1], contains_each![eq(1), ge(4)])?;   // Fails: second matcher unmatched
173 /// #     Ok(())
174 /// # }
175 /// # fn should_fail_3() -> Result<()> {
176 /// verify_that!(vec![3, 2, 1], contains_each![ge(3), ge(3), ge(3)])?; // Fails: no matching
177 /// #     Ok(())
178 /// # }
179 /// # should_pass().unwrap();
180 /// # should_fail_1().unwrap_err();
181 /// # should_fail_2().unwrap_err();
182 /// # should_fail_3().unwrap_err();
183 /// ```
184 ///
185 /// The actual value must be a container such as a `Vec`, an array, or a
186 /// dereferenced slice. More precisely, a shared borrow of the actual value must
187 /// implement [`IntoIterator`].
188 ///
189 /// This can also match against [`HashMap`][std::collections::HashMap] and
190 /// similar collections. The arguments are a sequence of pairs of matchers
191 /// corresponding to the keys and their respective values.
192 ///
193 /// ```
194 /// # use googletest::prelude::*;
195 /// # use std::collections::HashMap;
196 /// let value: HashMap<u32, &'static str> =
197 ///     HashMap::from_iter([(1, "One"), (2, "Two"), (3, "Three")]);
198 /// verify_that!(value, contains_each![(eq(2), eq("Two")), (eq(1), eq("One"))])
199 /// #     .unwrap();
200 /// ```
201 ///
202 /// This matcher does not support matching directly against an [`Iterator`]. To
203 /// match against an iterator, use [`Iterator::collect`] to build a [`Vec`].
204 ///
205 /// The matcher proceeds in three stages:
206 ///
207 /// 1. It first checks whether the actual value is large enough to possibly be
208 ///    matched by each of the given matchers. If not, then it immediately fails
209 ///    explaining that the size is too small.
210 ///
211 /// 2. It then checks whether each matcher matches at least one corresponding
212 ///    element in the actual container and fails if that is not the case. The
213 ///    failure message indicates which matcher had no corresponding element.
214 ///
215 /// 3. Finally, it checks whether the mapping of matchers to corresponding
216 ///    actual elements is 1-1 and fails if that is not the case. The failure
217 ///    message then shows the best matching it could find, including which
218 ///    matchers did not have corresponding unique elements in the container.
219 ///
220 /// [`IntoIterator`]: std::iter::IntoIterator
221 /// [`Iterator`]: std::iter::Iterator
222 /// [`Iterator::collect`]: std::iter::Iterator::collect
223 /// [`Vec`]: std::vec::Vec
224 #[macro_export]
225 #[doc(hidden)]
226 macro_rules! __contains_each {
227     ($(,)?) => {{
228         use $crate::matchers::__internal_unstable_do_not_depend_on_these::{
229             UnorderedElementsAreMatcher, Requirements
230         };
231         UnorderedElementsAreMatcher::new([], Requirements::Superset)
232     }};
233 
234     // TODO: Consider an alternative map-like syntax here similar to that used in
235     // https://crates.io/crates/maplit.
236     ($(($key_matcher:expr, $value_matcher:expr)),* $(,)?) => {{
237         use $crate::matchers::__internal_unstable_do_not_depend_on_these::{
238             UnorderedElementsOfMapAreMatcher, Requirements
239         };
240         UnorderedElementsOfMapAreMatcher::new(
241             [$((Box::new($key_matcher), Box::new($value_matcher))),*],
242             Requirements::Superset
243         )
244     }};
245 
246     ($($matcher:expr),* $(,)?) => {{
247         use $crate::matchers::__internal_unstable_do_not_depend_on_these::{
248             UnorderedElementsAreMatcher, Requirements
249         };
250         UnorderedElementsAreMatcher::new([$(Box::new($matcher)),*], Requirements::Superset)
251     }}
252 }
253 
254 /// Matches a container all of whose elements are matched by the given matchers.
255 ///
256 /// To match, each element in the container must have a corresponding matcher
257 /// which matches it. There must be a 1-1 mapping from container elements to
258 /// matchers, so that no matcher has more than one corresponding element.
259 ///
260 /// There may, however, be matchers not corresponding to any elements in the
261 /// container.
262 ///
263 /// Put another way, `is_contained_in!` matches if there is a subset of the
264 /// matchers which would match with
265 /// [`unordered_elements_are`][crate::matchers::unordered_elements_are].
266 ///
267 /// ```
268 /// # use googletest::prelude::*;
269 /// # fn should_pass() -> Result<()> {
270 /// verify_that!(vec![2, 1], is_contained_in![eq(1), ge(2)])?;   // Passes
271 /// verify_that!(vec![2, 1], is_contained_in![ge(1), ge(1)])?;   // Passes
272 /// #     Ok(())
273 /// # }
274 /// # fn should_fail_1() -> Result<()> {
275 /// verify_that!(vec![1, 2, 3], is_contained_in![eq(1), ge(2)])?; // Fails: container too large
276 /// #     Ok(())
277 /// # }
278 /// # fn should_fail_2() -> Result<()> {
279 /// verify_that!(vec![2, 1], is_contained_in![eq(1), ge(4)])?;    // Fails: second matcher unmatched
280 /// #     Ok(())
281 /// # }
282 /// # fn should_fail_3() -> Result<()> {
283 /// verify_that!(vec![3, 1], is_contained_in![ge(3), ge(3), ge(3)])?; // Fails: no matching
284 /// #     Ok(())
285 /// # }
286 /// # should_pass().unwrap();
287 /// # should_fail_1().unwrap_err();
288 /// # should_fail_2().unwrap_err();
289 /// # should_fail_3().unwrap_err();
290 /// ```
291 ///
292 /// The actual value must be a container such as a `Vec`, an array, or a
293 /// dereferenced slice. More precisely, a shared borrow of the actual value must
294 /// implement [`IntoIterator`].
295 ///
296 /// This can also match against [`HashMap`][std::collections::HashMap] and
297 /// similar collections. The arguments are a sequence of pairs of matchers
298 /// corresponding to the keys and their respective values.
299 ///
300 /// ```
301 /// # use googletest::prelude::*;
302 /// # use std::collections::HashMap;
303 /// let value: HashMap<u32, &'static str> = HashMap::from_iter([(1, "One"), (2, "Two")]);
304 /// verify_that!(
305 ///     value,
306 ///     is_contained_in![(eq(2), eq("Two")), (eq(1), eq("One")), (eq(3), eq("Three"))]
307 /// )
308 /// #     .unwrap();
309 /// ```
310 ///
311 /// This matcher does not support matching directly against an [`Iterator`]. To
312 /// match against an iterator, use [`Iterator::collect`] to build a [`Vec`].
313 ///
314 /// The matcher proceeds in three stages:
315 ///
316 /// 1. It first checks whether the actual value is too large to possibly be
317 ///    matched by each of the given matchers. If so, it immediately fails
318 ///    explaining that the size is too large.
319 ///
320 /// 2. It then checks whether each actual container element is matched by at
321 ///    least one matcher and fails if that is not the case. The failure message
322 ///    indicates which element had no corresponding matcher.
323 ///
324 /// 3. Finally, it checks whether the mapping of elements to corresponding
325 ///    matchers is 1-1 and fails if that is not the case. The failure message
326 ///    then shows the best matching it could find, including which container
327 ///    elements did not have corresponding matchers.
328 ///
329 /// [`IntoIterator`]: std::iter::IntoIterator
330 /// [`Iterator`]: std::iter::Iterator
331 /// [`Iterator::collect`]: std::iter::Iterator::collect
332 /// [`Vec`]: std::vec::Vec
333 #[macro_export]
334 #[doc(hidden)]
335 macro_rules! __is_contained_in {
336     ($(,)?) => {{
337         use $crate::matchers::__internal_unstable_do_not_depend_on_these::{
338             UnorderedElementsAreMatcher, Requirements
339         };
340         UnorderedElementsAreMatcher::new([], Requirements::Subset)
341     }};
342 
343     // TODO: Consider an alternative map-like syntax here similar to that used in
344     // https://crates.io/crates/maplit.
345     ($(($key_matcher:expr, $value_matcher:expr)),* $(,)?) => {{
346         use $crate::matchers::__internal_unstable_do_not_depend_on_these::{
347             UnorderedElementsOfMapAreMatcher, Requirements
348         };
349         UnorderedElementsOfMapAreMatcher::new(
350             [$((Box::new($key_matcher), Box::new($value_matcher))),*],
351             Requirements::Subset
352         )
353     }};
354 
355     ($($matcher:expr),* $(,)?) => {{
356         use $crate::matchers::__internal_unstable_do_not_depend_on_these::{
357             UnorderedElementsAreMatcher, Requirements
358         };
359         UnorderedElementsAreMatcher::new([$(Box::new($matcher)),*], Requirements::Subset)
360     }}
361 }
362 
363 /// Module for use only by the macros in this module.
364 ///
365 /// **For internal use only. API stablility is not guaranteed!**
366 #[doc(hidden)]
367 pub mod internal {
368     use crate::description::Description;
369     use crate::matcher::{Matcher, MatcherResult};
370     use crate::matcher_support::count_elements::count_elements;
371     use std::collections::HashSet;
372     use std::fmt::{Debug, Display};
373     use std::marker::PhantomData;
374 
375     /// This struct is meant to be used only through the
376     /// `unordered_elements_are![...]` macro.
377     ///
378     /// **For internal use only. API stablility is not guaranteed!**
379     #[doc(hidden)]
380     pub struct UnorderedElementsAreMatcher<'a, ContainerT: ?Sized, T: Debug, const N: usize> {
381         elements: [Box<dyn Matcher<ActualT = T> + 'a>; N],
382         requirements: Requirements,
383         phantom: PhantomData<ContainerT>,
384     }
385 
386     impl<'a, ContainerT: ?Sized, T: Debug, const N: usize>
387         UnorderedElementsAreMatcher<'a, ContainerT, T, N>
388     {
new( elements: [Box<dyn Matcher<ActualT = T> + 'a>; N], requirements: Requirements, ) -> Self389         pub fn new(
390             elements: [Box<dyn Matcher<ActualT = T> + 'a>; N],
391             requirements: Requirements,
392         ) -> Self {
393             Self { elements, requirements, phantom: Default::default() }
394         }
395     }
396 
397     // This matcher performs the checks in three different steps in both `matches`
398     // and `explain_match`. This is useful for performance but also to produce
399     // an actionable error message.
400     // 1. `UnorderedElementsAreMatcher` verifies that both collections have the same
401     // size
402     // 2. `UnorderedElementsAreMatcher` verifies that each actual element matches at
403     // least one expected element and vice versa.
404     // 3. `UnorderedElementsAreMatcher` verifies that a perfect matching exists
405     // using Ford-Fulkerson.
406     impl<'a, T: Debug, ContainerT: Debug + ?Sized, const N: usize> Matcher
407         for UnorderedElementsAreMatcher<'a, ContainerT, T, N>
408     where
409         for<'b> &'b ContainerT: IntoIterator<Item = &'b T>,
410     {
411         type ActualT = ContainerT;
412 
matches(&self, actual: &ContainerT) -> MatcherResult413         fn matches(&self, actual: &ContainerT) -> MatcherResult {
414             let match_matrix = MatchMatrix::generate(actual, &self.elements);
415             match_matrix.is_match_for(self.requirements).into()
416         }
417 
explain_match(&self, actual: &ContainerT) -> Description418         fn explain_match(&self, actual: &ContainerT) -> Description {
419             if let Some(size_mismatch_explanation) =
420                 self.requirements.explain_size_mismatch(actual, N)
421             {
422                 return size_mismatch_explanation;
423             }
424 
425             let match_matrix = MatchMatrix::generate(actual, &self.elements);
426             if let Some(unmatchable_explanation) =
427                 match_matrix.explain_unmatchable(self.requirements)
428             {
429                 return unmatchable_explanation;
430             }
431 
432             let best_match = match_matrix.find_best_match();
433             best_match
434                 .get_explanation(actual, &self.elements, self.requirements)
435                 .unwrap_or("whose elements all match".into())
436         }
437 
describe(&self, matcher_result: MatcherResult) -> Description438         fn describe(&self, matcher_result: MatcherResult) -> Description {
439             format!(
440                 "{} elements matching in any order:\n{}",
441                 if matcher_result.into() { "contains" } else { "doesn't contain" },
442                 self.elements
443                     .iter()
444                     .map(|matcher| matcher.describe(MatcherResult::Match))
445                     .collect::<Description>()
446                     .enumerate()
447                     .indent()
448             )
449             .into()
450         }
451     }
452 
453     type KeyValueMatcher<'a, KeyT, ValueT> =
454         (Box<dyn Matcher<ActualT = KeyT> + 'a>, Box<dyn Matcher<ActualT = ValueT> + 'a>);
455 
456     /// This is the analogue to [UnorderedElementsAreMatcher] for maps and
457     /// map-like collections.
458     ///
459     /// **For internal use only. API stablility is not guaranteed!**
460     #[doc(hidden)]
461     pub struct UnorderedElementsOfMapAreMatcher<'a, ContainerT, KeyT, ValueT, const N: usize>
462     where
463         ContainerT: ?Sized,
464         KeyT: Debug,
465         ValueT: Debug,
466     {
467         elements: [KeyValueMatcher<'a, KeyT, ValueT>; N],
468         requirements: Requirements,
469         phantom: PhantomData<ContainerT>,
470     }
471 
472     impl<'a, ContainerT, KeyT: Debug, ValueT: Debug, const N: usize>
473         UnorderedElementsOfMapAreMatcher<'a, ContainerT, KeyT, ValueT, N>
474     {
new( elements: [KeyValueMatcher<'a, KeyT, ValueT>; N], requirements: Requirements, ) -> Self475         pub fn new(
476             elements: [KeyValueMatcher<'a, KeyT, ValueT>; N],
477             requirements: Requirements,
478         ) -> Self {
479             Self { elements, requirements, phantom: Default::default() }
480         }
481     }
482 
483     impl<'a, KeyT: Debug, ValueT: Debug, ContainerT: Debug + ?Sized, const N: usize> Matcher
484         for UnorderedElementsOfMapAreMatcher<'a, ContainerT, KeyT, ValueT, N>
485     where
486         for<'b> &'b ContainerT: IntoIterator<Item = (&'b KeyT, &'b ValueT)>,
487     {
488         type ActualT = ContainerT;
489 
matches(&self, actual: &ContainerT) -> MatcherResult490         fn matches(&self, actual: &ContainerT) -> MatcherResult {
491             let match_matrix = MatchMatrix::generate_for_map(actual, &self.elements);
492             match_matrix.is_match_for(self.requirements).into()
493         }
494 
explain_match(&self, actual: &ContainerT) -> Description495         fn explain_match(&self, actual: &ContainerT) -> Description {
496             if let Some(size_mismatch_explanation) =
497                 self.requirements.explain_size_mismatch(actual, N)
498             {
499                 return size_mismatch_explanation;
500             }
501 
502             let match_matrix = MatchMatrix::generate_for_map(actual, &self.elements);
503             if let Some(unmatchable_explanation) =
504                 match_matrix.explain_unmatchable(self.requirements)
505             {
506                 return unmatchable_explanation;
507             }
508 
509             let best_match = match_matrix.find_best_match();
510 
511             best_match
512                 .get_explanation_for_map(actual, &self.elements, self.requirements)
513                 .unwrap_or("whose elements all match".into())
514         }
515 
describe(&self, matcher_result: MatcherResult) -> Description516         fn describe(&self, matcher_result: MatcherResult) -> Description {
517             format!(
518                 "{} elements matching in any order:\n{}",
519                 if matcher_result.into() { "contains" } else { "doesn't contain" },
520                 self.elements
521                     .iter()
522                     .map(|(key_matcher, value_matcher)| format!(
523                         "{} => {}",
524                         key_matcher.describe(MatcherResult::Match),
525                         value_matcher.describe(MatcherResult::Match)
526                     ))
527                     .collect::<Description>()
528                     .indent()
529             )
530             .into()
531         }
532     }
533 
534     /// The requirements of the mapping between matchers and actual values by
535     /// which [`UnorderedElemetnsAre`] is deemed to match its input.
536     ///
537     /// **For internal use only. API stablility is not guaranteed!**
538     #[doc(hidden)]
539     #[derive(Clone, Copy)]
540     pub enum Requirements {
541         /// There must be a 1:1 correspondence between the actual values and the
542         /// matchers.
543         PerfectMatch,
544 
545         /// The mapping from matched actual values to their corresponding
546         /// matchers must be surjective.
547         Superset,
548 
549         /// The mapping from matchers to matched actual values must be
550         /// surjective.
551         Subset,
552     }
553 
554     impl Requirements {
explain_size_mismatch<ContainerT: ?Sized>( &self, actual: &ContainerT, expected_size: usize, ) -> Option<Description> where for<'b> &'b ContainerT: IntoIterator,555         fn explain_size_mismatch<ContainerT: ?Sized>(
556             &self,
557             actual: &ContainerT,
558             expected_size: usize,
559         ) -> Option<Description>
560         where
561             for<'b> &'b ContainerT: IntoIterator,
562         {
563             let actual_size = count_elements(actual);
564             match self {
565                 Requirements::PerfectMatch if actual_size != expected_size => Some(
566                     format!("which has size {} (expected {})", actual_size, expected_size).into(),
567                 ),
568 
569                 Requirements::Superset if actual_size < expected_size => Some(
570                     format!("which has size {} (expected at least {})", actual_size, expected_size)
571                         .into(),
572                 ),
573 
574                 Requirements::Subset if actual_size > expected_size => Some(
575                     format!("which has size {} (expected at most {})", actual_size, expected_size)
576                         .into(),
577                 ),
578 
579                 _ => None,
580             }
581         }
582     }
583 
584     impl Display for Requirements {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result585         fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
586             match self {
587                 Requirements::PerfectMatch => {
588                     write!(f, "perfect")
589                 }
590                 Requirements::Superset => {
591                     write!(f, "superset")
592                 }
593                 Requirements::Subset => {
594                     write!(f, "subset")
595                 }
596             }
597         }
598     }
599 
600     /// The bipartite matching graph between actual and expected elements.
601     struct MatchMatrix<const N: usize>(Vec<[MatcherResult; N]>);
602 
603     impl<const N: usize> MatchMatrix<N> {
generate<'a, T: Debug + 'a, ContainerT: Debug + ?Sized>( actual: &ContainerT, expected: &[Box<dyn Matcher<ActualT = T> + 'a>; N], ) -> Self where for<'b> &'b ContainerT: IntoIterator<Item = &'b T>,604         fn generate<'a, T: Debug + 'a, ContainerT: Debug + ?Sized>(
605             actual: &ContainerT,
606             expected: &[Box<dyn Matcher<ActualT = T> + 'a>; N],
607         ) -> Self
608         where
609             for<'b> &'b ContainerT: IntoIterator<Item = &'b T>,
610         {
611             let mut matrix = MatchMatrix(vec![[MatcherResult::NoMatch; N]; count_elements(actual)]);
612             for (actual_idx, actual) in actual.into_iter().enumerate() {
613                 for (expected_idx, expected) in expected.iter().enumerate() {
614                     matrix.0[actual_idx][expected_idx] = expected.matches(actual);
615                 }
616             }
617             matrix
618         }
619 
generate_for_map<'a, KeyT: Debug, ValueT: Debug, ContainerT: Debug + ?Sized>( actual: &ContainerT, expected: &[KeyValueMatcher<'a, KeyT, ValueT>; N], ) -> Self where for<'b> &'b ContainerT: IntoIterator<Item = (&'b KeyT, &'b ValueT)>,620         fn generate_for_map<'a, KeyT: Debug, ValueT: Debug, ContainerT: Debug + ?Sized>(
621             actual: &ContainerT,
622             expected: &[KeyValueMatcher<'a, KeyT, ValueT>; N],
623         ) -> Self
624         where
625             for<'b> &'b ContainerT: IntoIterator<Item = (&'b KeyT, &'b ValueT)>,
626         {
627             let mut matrix = MatchMatrix(vec![[MatcherResult::NoMatch; N]; count_elements(actual)]);
628             for (actual_idx, (actual_key, actual_value)) in actual.into_iter().enumerate() {
629                 for (expected_idx, (expected_key, expected_value)) in expected.iter().enumerate() {
630                     matrix.0[actual_idx][expected_idx] = (expected_key.matches(actual_key).into()
631                         && expected_value.matches(actual_value).into())
632                     .into();
633                 }
634             }
635             matrix
636         }
637 
is_match_for(&self, requirements: Requirements) -> bool638         fn is_match_for(&self, requirements: Requirements) -> bool {
639             match requirements {
640                 Requirements::PerfectMatch => {
641                     !self.find_unmatchable_elements().has_unmatchable_elements()
642                         && self.find_best_match().is_full_match()
643                 }
644                 Requirements::Superset => {
645                     !self.find_unmatched_expected().has_unmatchable_elements()
646                         && self.find_best_match().is_superset_match()
647                 }
648                 Requirements::Subset => {
649                     !self.find_unmatched_actual().has_unmatchable_elements()
650                         && self.find_best_match().is_subset_match()
651                 }
652             }
653         }
654 
explain_unmatchable(&self, requirements: Requirements) -> Option<Description>655         fn explain_unmatchable(&self, requirements: Requirements) -> Option<Description> {
656             let unmatchable_elements = match requirements {
657                 Requirements::PerfectMatch => self.find_unmatchable_elements(),
658                 Requirements::Superset => self.find_unmatched_expected(),
659                 Requirements::Subset => self.find_unmatched_actual(),
660             };
661             unmatchable_elements.get_explanation()
662         }
663 
664         // Verifies that each actual matches at least one expected and that
665         // each expected matches at least one actual.
666         // This is a necessary condition but not sufficient. But it is faster
667         // than `find_best_match()`.
find_unmatchable_elements(&self) -> UnmatchableElements<N>668         fn find_unmatchable_elements(&self) -> UnmatchableElements<N> {
669             let unmatchable_actual =
670                 self.0.iter().map(|row| row.iter().all(|&e| e.is_no_match())).collect();
671             let mut unmatchable_expected = [false; N];
672             for (col_idx, expected) in unmatchable_expected.iter_mut().enumerate() {
673                 *expected = self.0.iter().map(|row| row[col_idx]).all(|e| e.is_no_match());
674             }
675             UnmatchableElements { unmatchable_actual, unmatchable_expected }
676         }
677 
find_unmatched_expected(&self) -> UnmatchableElements<N>678         fn find_unmatched_expected(&self) -> UnmatchableElements<N> {
679             let mut unmatchable_expected = [false; N];
680             for (col_idx, expected) in unmatchable_expected.iter_mut().enumerate() {
681                 *expected = self.0.iter().map(|row| row[col_idx]).all(|e| e.is_no_match());
682             }
683             UnmatchableElements { unmatchable_actual: vec![false; N], unmatchable_expected }
684         }
685 
find_unmatched_actual(&self) -> UnmatchableElements<N>686         fn find_unmatched_actual(&self) -> UnmatchableElements<N> {
687             let unmatchable_actual =
688                 self.0.iter().map(|row| row.iter().all(|e| e.is_no_match())).collect();
689             UnmatchableElements { unmatchable_actual, unmatchable_expected: [false; N] }
690         }
691 
692         // Verifies that a full match exists.
693         //
694         // Uses the well-known Ford-Fulkerson max flow method to find a maximum
695         // bipartite matching. Flow is considered to be from actual to expected.
696         // There is an implicit source node that is connected to all of the actual
697         // nodes, and an implicit sink node that is connected to all of the
698         // expected nodes. All edges have unit capacity.
699         //
700         // Neither the flow graph nor the residual flow graph are represented
701         // explicitly. Instead, they are implied by the information in `self.0` and
702         // the local `actual_match : [Option<usize>; N]` whose elements are initialized
703         // to `None`. This represents the initial state of the algorithm,
704         // where the flow graph is empty, and the residual flow graph has the
705         // following edges:
706         //   - An edge from source to each actual element node
707         //   - An edge from each expected element node to sink
708         //   - An edge from each actual element node to each expected element node, if
709         //     the actual element matches the expected element, i.e.
710         //     `matches!(self.0[actual_id][expected_id], Matches)`
711         //
712         // When the `try_augment(...)` method adds a flow, it sets `actual_match[l] =
713         // Some(r)` for some nodes l and r. This induces the following changes:
714         //   - The edges (source, l), (l, r), and (r, sink) are added to the flow graph.
715         //   - The same three edges are removed from the residual flow graph.
716         //   - The reverse edges (l, source), (r, l), and (sink, r) are added to the
717         //     residual flow graph, which is a directional graph representing unused
718         //     flow capacity.
719         //
720         // When the method augments a flow (changing `actual_match[l]` from `Some(r1)`
721         // to `Some(r2)`), this can be thought of as "undoing" the above steps
722         // with respect to r1 and "redoing" them with respect to r2.
723         //
724         // It bears repeating that the flow graph and residual flow graph are
725         // never represented explicitly, but can be derived by looking at the
726         // information in 'self.0' and in `actual_match`.
727         //
728         // As an optimization, there is a second local `expected_match: [Option<usize>;
729         // N]` which does not provide any new information. Instead, it enables
730         // more efficient queries about edges entering or leaving the expected elements
731         // nodes of the flow or residual flow graphs. The following invariants
732         // are maintained:
733         //
734         // actual_match[a] == None or expected_match[actual_match[a].unwrap()] ==
735         // Some(a)
736         // expected_match[r] == None or actual_match[expected_match[e].unwrap()] ==
737         // Some(e)
738         //
739         // | [ source ]                                                              |
740         // |   |||                                                                   |
741         // |   |||                                                                   |
742         // |   ||\-> actual_match[0]=Some(1) -\   expected_match[0]=None    ---\     |
743         // |   ||                             |                                |     |
744         // |   |\--> actual_match[1]=None     \-> expected_match[1]=Some(0) --\|     |
745         // |   |                                                              ||     |
746         // |   \---> actual_match[2]=Some(2)  --> expected_match[2]=Some(2) -\||     |
747         // |                                                                 |||     |
748         // |         elements                     matchers                   vvv     |
749         // |                                                               [ sink ]  |
750         //
751         // See Also:
752         //   [1] Cormen, et al (2001). "Section 26.2: The Ford-Fulkerson method".
753         //       "Introduction to Algorithms (Second ed.)", pp. 651-664.
754         //   [2] "Ford-Fulkerson algorithm", Wikipedia,
755         //       'http://en.wikipedia.org/wiki/Ford%E2%80%93Fulkerson_algorithm'
find_best_match(&self) -> BestMatch<N>756         fn find_best_match(&self) -> BestMatch<N> {
757             let mut actual_match = vec![None; self.0.len()];
758             let mut expected_match: [Option<usize>; N] = [None; N];
759             // Searches the residual flow graph for a path from each actual node to
760             // the sink in the residual flow graph, and if one is found, add this path
761             // to the graph.
762             // It's okay to search through the actual nodes once. The
763             // edge from the implicit source node to each previously-visited actual
764             // node will have flow if that actual node has any path to the sink
765             // whatsoever. Subsequent augmentations can only add flow to the
766             // network, and cannot take away that previous flow unit from the source.
767             // Since the source-to-actual edge can only carry one flow unit (or,
768             // each actual element can be matched to only one expected element), there is no
769             // need to visit the actual nodes more than once looking for
770             // augmented paths. The flow is known to be possible or impossible
771             // by looking at the node once.
772             for actual_idx in 0..self.0.len() {
773                 assert!(actual_match[actual_idx].is_none());
774                 let mut seen = [false; N];
775                 self.try_augment(actual_idx, &mut seen, &mut actual_match, &mut expected_match);
776             }
777             BestMatch(actual_match)
778         }
779 
780         // Perform a depth-first search from actual node `actual_idx` to the sink by
781         // searching for an unassigned expected node. If a path is found, flow
782         // is added to the network by linking the actual and expected vector elements
783         // corresponding each segment of the path. Returns true if a path to
784         // sink was found, which means that a unit of flow was added to the
785         // network. The 'seen' array elements correspond to expected nodes and are
786         // marked to eliminate cycles from the search.
787         //
788         // Actual nodes will only be explored at most once because they
789         // are accessible from at most one expected node in the residual flow
790         // graph.
791         //
792         // Note that `actual_match[actual_idx]` is the only element of `actual_match`
793         // that `try_augment(...)` will potentially transition from `None` to
794         // `Some(...)`. Any other `actual_match` element holding `None` before
795         // `try_augment(...)` will be holding it when `try_augment(...)`
796         // returns.
797         //
try_augment( &self, actual_idx: usize, seen: &mut [bool; N], actual_match: &mut [Option<usize>], expected_match: &mut [Option<usize>; N], ) -> bool798         fn try_augment(
799             &self,
800             actual_idx: usize,
801             seen: &mut [bool; N],
802             actual_match: &mut [Option<usize>],
803             expected_match: &mut [Option<usize>; N],
804         ) -> bool {
805             for expected_idx in 0..N {
806                 if seen[expected_idx] {
807                     continue;
808                 }
809                 if self.0[actual_idx][expected_idx].is_no_match() {
810                     continue;
811                 }
812                 // There is an edge between `actual_idx` and `expected_idx`.
813                 seen[expected_idx] = true;
814                 // Next a search is performed to determine whether
815                 // this edge is a dead end or leads to the sink.
816                 //
817                 // `expected_match[expected_idx].is_none()` means that there is residual flow
818                 // from expected node at index expected_idx to the sink, so we
819                 // can use that to finish this flow path and return success.
820                 //
821                 // Otherwise, we look for a residual flow starting from
822                 // `expected_match[expected_idx].unwrap()` by calling
823                 // ourselves recursively to see if this ultimately leads to
824                 // sink.
825                 if expected_match[expected_idx].is_none()
826                     || self.try_augment(
827                         expected_match[expected_idx].unwrap(),
828                         seen,
829                         actual_match,
830                         expected_match,
831                     )
832                 {
833                     // We found a residual flow from source to sink. We thus need to add the new
834                     // edge to the current flow.
835                     // Note: this also remove the potential flow that existed by overwriting the
836                     // value in the `expected_match` and `actual_match`.
837                     expected_match[expected_idx] = Some(actual_idx);
838                     actual_match[actual_idx] = Some(expected_idx);
839                     return true;
840                 }
841             }
842             false
843         }
844     }
845 
846     /// The list of elements that do not match any element in the corresponding
847     /// set.
848     /// These lists are represented as fixed sized bit set to avoid
849     /// allocation.
850     /// TODO(bjacotg) Use BitArr!(for N) once generic_const_exprs is stable.
851     struct UnmatchableElements<const N: usize> {
852         unmatchable_actual: Vec<bool>,
853         unmatchable_expected: [bool; N],
854     }
855 
856     impl<const N: usize> UnmatchableElements<N> {
has_unmatchable_elements(&self) -> bool857         fn has_unmatchable_elements(&self) -> bool {
858             self.unmatchable_actual.iter().any(|b| *b)
859                 || self.unmatchable_expected.iter().any(|b| *b)
860         }
861 
get_explanation(&self) -> Option<Description>862         fn get_explanation(&self) -> Option<Description> {
863             let unmatchable_actual = self.unmatchable_actual();
864             let actual_idx = unmatchable_actual
865                 .iter()
866                 .map(|idx| format!("#{}", idx))
867                 .collect::<Vec<_>>()
868                 .join(", ");
869             let unmatchable_expected = self.unmatchable_expected();
870             let expected_idx = unmatchable_expected
871                 .iter()
872                 .map(|idx| format!("#{}", idx))
873                 .collect::<Vec<_>>()
874                 .join(", ");
875             match (unmatchable_actual.len(), unmatchable_expected.len()) {
876                 (0, 0) => None,
877                 (1, 0) => {
878                     Some(format!("whose element {actual_idx} does not match any expected elements").into())
879                 }
880                 (_, 0) => {
881                     Some(format!("whose elements {actual_idx} do not match any expected elements",).into())
882                 }
883                 (0, 1) => Some(format!(
884                     "which has no element matching the expected element {expected_idx}"
885                 ).into()),
886                 (0, _) => Some(format!(
887                     "which has no elements matching the expected elements {expected_idx}"
888                 ).into()),
889                 (1, 1) => Some(format!(
890                     "whose element {actual_idx} does not match any expected elements and no elements match the expected element {expected_idx}"
891                 ).into()),
892                 (_, 1) => Some(format!(
893                     "whose elements {actual_idx} do not match any expected elements and no elements match the expected element {expected_idx}"
894                 ).into()),
895                 (1, _) => Some(format!(
896                     "whose element {actual_idx} does not match any expected elements and no elements match the expected elements {expected_idx}"
897                 ).into()),
898                 (_, _) => Some(format!(
899                     "whose elements {actual_idx} do not match any expected elements and no elements match the expected elements {expected_idx}"
900                 ).into()),
901             }
902         }
903 
unmatchable_actual(&self) -> Vec<usize>904         fn unmatchable_actual(&self) -> Vec<usize> {
905             self.unmatchable_actual
906                 .iter()
907                 .enumerate()
908                 .filter_map(|(idx, b)| if *b { Some(idx) } else { None })
909                 .collect()
910         }
911 
unmatchable_expected(&self) -> Vec<usize>912         fn unmatchable_expected(&self) -> Vec<usize> {
913             self.unmatchable_expected
914                 .iter()
915                 .enumerate()
916                 .filter_map(|(idx, b)| if *b { Some(idx) } else { None })
917                 .collect()
918         }
919     }
920 
921     /// The representation of a match between actual and expected.
922     /// The value at idx represents to which expected the actual at idx is
923     /// matched with. For example, `BestMatch([Some(0), None, Some(1)])`
924     /// means:
925     ///  * The 0th element in actual matches the 0th element in expected.
926     ///  * The 1st element in actual does not match.
927     ///  * The 2nd element in actual matches the 1st element in expected.
928     struct BestMatch<const N: usize>(Vec<Option<usize>>);
929 
930     impl<const N: usize> BestMatch<N> {
is_full_match(&self) -> bool931         fn is_full_match(&self) -> bool {
932             self.0.iter().all(|o| o.is_some())
933         }
934 
is_subset_match(&self) -> bool935         fn is_subset_match(&self) -> bool {
936             self.is_full_match()
937         }
938 
is_superset_match(&self) -> bool939         fn is_superset_match(&self) -> bool {
940             self.get_unmatched_expected().is_empty()
941         }
942 
get_matches(&self) -> impl Iterator<Item = (usize, usize)> + '_943         fn get_matches(&self) -> impl Iterator<Item = (usize, usize)> + '_ {
944             self.0.iter().enumerate().filter_map(|(actual_idx, maybe_expected_idx)| {
945                 maybe_expected_idx.map(|expected_idx| (actual_idx, expected_idx))
946             })
947         }
948 
get_unmatched_actual(&self) -> impl Iterator<Item = usize> + '_949         fn get_unmatched_actual(&self) -> impl Iterator<Item = usize> + '_ {
950             self.0
951                 .iter()
952                 .enumerate()
953                 .filter(|&(_, o)| o.is_none())
954                 .map(|(actual_idx, _)| actual_idx)
955         }
956 
get_unmatched_expected(&self) -> Vec<usize>957         fn get_unmatched_expected(&self) -> Vec<usize> {
958             let matched_expected: HashSet<_> = self.0.iter().flatten().collect();
959             (0..N).filter(|expected_idx| !matched_expected.contains(expected_idx)).collect()
960         }
961 
get_explanation<'a, T: Debug, ContainerT: Debug + ?Sized>( &self, actual: &ContainerT, expected: &[Box<dyn Matcher<ActualT = T> + 'a>; N], requirements: Requirements, ) -> Option<Description> where for<'b> &'b ContainerT: IntoIterator<Item = &'b T>,962         fn get_explanation<'a, T: Debug, ContainerT: Debug + ?Sized>(
963             &self,
964             actual: &ContainerT,
965             expected: &[Box<dyn Matcher<ActualT = T> + 'a>; N],
966             requirements: Requirements,
967         ) -> Option<Description>
968         where
969             for<'b> &'b ContainerT: IntoIterator<Item = &'b T>,
970         {
971             let actual: Vec<_> = actual.into_iter().collect();
972             if self.is_full_match() {
973                 return None;
974             }
975             let mut error_message =
976                 format!("which does not have a {requirements} match with the expected elements.");
977 
978             error_message.push_str("\n  The best match found was: ");
979 
980             let matches = self.get_matches().map(|(actual_idx, expected_idx)|{
981                 format!(
982                     "Actual element {:?} at index {actual_idx} matched expected element `{}` at index {expected_idx}.",
983                     actual[actual_idx],
984                     expected[expected_idx].describe(MatcherResult::Match),
985             )});
986 
987             let unmatched_actual = self.get_unmatched_actual().map(|actual_idx| {
988                 format!(
989                     "Actual element {:#?} at index {actual_idx} did not match any remaining expected element.",
990                     actual[actual_idx]
991                 )
992             });
993 
994             let unmatched_expected = self.get_unmatched_expected().into_iter().map(|expected_idx|{format!(
995                 "Expected element `{}` at index {expected_idx} did not match any remaining actual element.",
996                 expected[expected_idx].describe(MatcherResult::Match)
997             )});
998 
999             let best_match = matches
1000                 .chain(unmatched_actual)
1001                 .chain(unmatched_expected)
1002                 .collect::<Description>()
1003                 .indent();
1004             Some(format!(
1005                 "which does not have a {requirements} match with the expected elements. The best match found was:\n{best_match}"
1006             ).into())
1007         }
1008 
get_explanation_for_map<'a, KeyT: Debug, ValueT: Debug, ContainerT: Debug + ?Sized>( &self, actual: &ContainerT, expected: &[KeyValueMatcher<'a, KeyT, ValueT>; N], requirements: Requirements, ) -> Option<Description> where for<'b> &'b ContainerT: IntoIterator<Item = (&'b KeyT, &'b ValueT)>,1009         fn get_explanation_for_map<'a, KeyT: Debug, ValueT: Debug, ContainerT: Debug + ?Sized>(
1010             &self,
1011             actual: &ContainerT,
1012             expected: &[KeyValueMatcher<'a, KeyT, ValueT>; N],
1013             requirements: Requirements,
1014         ) -> Option<Description>
1015         where
1016             for<'b> &'b ContainerT: IntoIterator<Item = (&'b KeyT, &'b ValueT)>,
1017         {
1018             let actual: Vec<_> = actual.into_iter().collect();
1019             if self.is_full_match() {
1020                 return None;
1021             }
1022             let mut error_message =
1023                 format!("which does not have a {requirements} match with the expected elements.");
1024 
1025             error_message.push_str("\n  The best match found was: ");
1026 
1027             let matches = self.get_matches()
1028                 .map(|(actual_idx, expected_idx)| {
1029                     format!(
1030                         "Actual element {:?} => {:?} at index {actual_idx} matched expected element `{}` => `{}` at index {expected_idx}.",
1031                         actual[actual_idx].0,
1032                         actual[actual_idx].1,
1033                         expected[expected_idx].0.describe(MatcherResult::Match),
1034                         expected[expected_idx].1.describe(MatcherResult::Match),
1035                     )
1036                 });
1037 
1038             let unmatched_actual = self.get_unmatched_actual()
1039                 .map(|actual_idx| {
1040                     format!(
1041                         "Actual element {:#?} => {:#?} at index {actual_idx} did not match any remaining expected element.",
1042                         actual[actual_idx].0,
1043                         actual[actual_idx].1,
1044                     )
1045                 });
1046 
1047             let unmatched_expected = self.get_unmatched_expected()
1048                 .into_iter()
1049                 .map(|expected_idx| {
1050                     format!(
1051                         "Expected element `{}` => `{}` at index {expected_idx} did not match any remaining actual element.",
1052                         expected[expected_idx].0.describe(MatcherResult::Match),
1053                         expected[expected_idx].1.describe(MatcherResult::Match),
1054                     )
1055                 });
1056 
1057             let best_match = matches
1058                 .chain(unmatched_actual)
1059                 .chain(unmatched_expected)
1060                 .collect::<Description>()
1061                 .indent();
1062             Some(format!(
1063                 "which does not have a {requirements} match with the expected elements. The best match found was:\n{best_match}"
1064             ).into())
1065         }
1066     }
1067 }
1068 
1069 #[cfg(test)]
1070 mod tests {
1071     use super::internal::UnorderedElementsOfMapAreMatcher;
1072     use crate::matcher::{Matcher, MatcherResult};
1073     use crate::prelude::*;
1074     use indoc::indoc;
1075     use std::collections::HashMap;
1076 
1077     #[test]
has_correct_description_for_map() -> Result<()>1078     fn has_correct_description_for_map() -> Result<()> {
1079         // UnorderedElementsAreMatcher maintains references to the matchers, so the
1080         // constituent matchers must live longer. Inside a verify_that! macro, the
1081         // compiler takes care of that, but when the matcher is created separately,
1082         // we must create the constitute matchers separately so that they
1083         // aren't dropped too early.
1084         let matchers = ((eq(2), eq("Two")), (eq(1), eq("One")), (eq(3), eq("Three")));
1085         let matcher: UnorderedElementsOfMapAreMatcher<HashMap<i32, &str>, _, _, 3> = unordered_elements_are![
1086             (matchers.0.0, matchers.0.1),
1087             (matchers.1.0, matchers.1.1),
1088             (matchers.2.0, matchers.2.1)
1089         ];
1090         verify_that!(
1091             Matcher::describe(&matcher, MatcherResult::Match),
1092             displays_as(eq(indoc!(
1093                 "
1094                 contains elements matching in any order:
1095                   is equal to 2 => is equal to \"Two\"
1096                   is equal to 1 => is equal to \"One\"
1097                   is equal to 3 => is equal to \"Three\""
1098             )))
1099         )
1100     }
1101 
1102     #[test]
unordered_elements_are_description_no_full_match_with_map() -> Result<()>1103     fn unordered_elements_are_description_no_full_match_with_map() -> Result<()> {
1104         // UnorderedElementsAreMatcher maintains references to the matchers, so the
1105         // constituent matchers must live longer. Inside a verify_that! macro, the
1106         // compiler takes care of that, but when the matcher is created separately,
1107         // we must create the constitute matchers separately so that they
1108         // aren't dropped too early.
1109         let matchers = ((anything(), eq(1)), (anything(), eq(2)), (anything(), eq(2)));
1110         let matcher: UnorderedElementsOfMapAreMatcher<HashMap<u32, u32>, _, _, 3> = unordered_elements_are![
1111             (matchers.0.0, matchers.0.1),
1112             (matchers.1.0, matchers.1.1),
1113             (matchers.2.0, matchers.2.1),
1114         ];
1115         let value: HashMap<u32, u32> = HashMap::from_iter([(0, 1), (1, 1), (2, 2)]);
1116         verify_that!(
1117             matcher.explain_match(&value),
1118             displays_as(contains_regex(
1119                 "Actual element 2 => 2 at index [0-2] matched expected element `is anything` => `is equal to 2` at index [0-2]."
1120             )).and(displays_as(contains_regex(
1121                 "Actual element [0-1] => [0-1] at index [0-2] did not match any remaining expected element."
1122             ))).and(displays_as(contains_substring(
1123                 "Expected element `is anything` => `is equal to 2` at index 2 did not match any remaining actual element."
1124             )))
1125         )
1126     }
1127 }
1128