asserting/map/
mod.rs

1use crate::assertions::{AssertMapContainsKey, AssertMapContainsValue};
2use crate::colored::{
3    mark_all_entries_in_map, mark_missing, mark_selected_entries_in_map,
4    mark_selected_items_in_collection, mark_unexpected_string,
5};
6use crate::expectations::{
7    map_contains_exactly_keys, map_contains_key, map_contains_keys, map_contains_value,
8    map_contains_values, map_does_not_contain_keys, map_does_not_contain_values, not,
9    MapContainsExactlyKeys, MapContainsKey, MapContainsKeys, MapContainsValue, MapContainsValues,
10    MapDoesNotContainKeys, MapDoesNotContainValues,
11};
12use crate::iterator::collect_selected_values;
13use crate::properties::MapProperties;
14use crate::spec::{DiffFormat, Expectation, Expression, FailingStrategy, Invertible, Spec};
15use crate::std::fmt::Debug;
16use crate::std::format;
17use crate::std::string::String;
18use crate::std::vec::Vec;
19use hashbrown::HashSet;
20
21impl<S, E, R> AssertMapContainsKey<E> for Spec<'_, S, R>
22where
23    S: MapProperties + Debug,
24    <S as MapProperties>::Key: PartialEq<E> + Debug,
25    <S as MapProperties>::Value: Debug,
26    E: Debug,
27    R: FailingStrategy,
28{
29    fn contains_key(self, expected_key: E) -> Self {
30        self.expecting(map_contains_key(expected_key))
31    }
32
33    fn does_not_contain_key(self, expected_key: E) -> Self {
34        self.expecting(not(map_contains_key(expected_key)))
35    }
36
37    fn contains_keys(self, expected_keys: impl IntoIterator<Item = E>) -> Self {
38        self.expecting(map_contains_keys(expected_keys))
39    }
40
41    fn does_not_contain_keys(self, expected_keys: impl IntoIterator<Item = E>) -> Self {
42        self.expecting(map_does_not_contain_keys(expected_keys))
43    }
44
45    fn contains_exactly_keys(self, expected_keys: impl IntoIterator<Item = E>) -> Self {
46        self.expecting(map_contains_exactly_keys(expected_keys))
47    }
48}
49
50impl<M, E> Expectation<M> for MapContainsKey<E>
51where
52    M: MapProperties,
53    <M as MapProperties>::Key: PartialEq<E> + Debug,
54    <M as MapProperties>::Value: Debug,
55    E: Debug,
56{
57    fn test(&mut self, subject: &M) -> bool {
58        subject.keys_property().any(|k| k == &self.expected_key)
59    }
60
61    fn message(
62        &self,
63        expression: &Expression<'_>,
64        actual: &M,
65        inverted: bool,
66        format: &DiffFormat,
67    ) -> String {
68        let expected_key = &self.expected_key;
69        let actual_entries: Vec<_> = actual.entries_property().collect();
70        let (not, marked_actual) = if inverted {
71            let found: HashSet<usize> = actual_entries
72                .iter()
73                .enumerate()
74                .filter_map(|(index, (k, _))| {
75                    if *k == &self.expected_key {
76                        Some(index)
77                    } else {
78                        None
79                    }
80                })
81                .collect();
82            let selected_entries_marked = mark_selected_entries_in_map(
83                &actual_entries,
84                &found,
85                format,
86                mark_unexpected_string,
87            );
88            ("not ", selected_entries_marked)
89        } else {
90            let all_entries_marked =
91                mark_all_entries_in_map(&actual_entries, format, mark_unexpected_string);
92            ("", all_entries_marked)
93        };
94        let marked_expected = mark_missing(&self.expected_key, format);
95        format!("expected {expression} to {not}contain the key {expected_key:?}\n   but was: {marked_actual}\n  expected: {not}{marked_expected}")
96    }
97}
98
99impl<E> Invertible for MapContainsKey<E> {}
100
101impl<M, E> Expectation<M> for MapContainsKeys<E>
102where
103    M: MapProperties,
104    <M as MapProperties>::Key: PartialEq<E> + Debug,
105    <M as MapProperties>::Value: Debug,
106    E: Debug,
107{
108    fn test(&mut self, subject: &M) -> bool {
109        let keys = subject.keys_property().collect::<Vec<_>>();
110        let missing = &mut self.missing;
111        for (expected_index, expected_key) in self.expected_keys.iter().enumerate() {
112            if !keys.iter().any(|k| *k == expected_key) {
113                missing.insert(expected_index);
114            }
115        }
116        missing.is_empty()
117    }
118
119    fn message(
120        &self,
121        expression: &Expression<'_>,
122        actual: &M,
123        _inverted: bool,
124        format: &DiffFormat,
125    ) -> String {
126        let expected_keys = &self.expected_keys;
127        let missing = &self.missing;
128        let actual_entries: Vec<_> = actual.entries_property().collect();
129        let mut extra_entries = HashSet::new();
130        for (actual_index, actual_entry) in actual_entries.iter().enumerate() {
131            if !expected_keys
132                .iter()
133                .any(|expected| actual_entry.0 == expected)
134            {
135                extra_entries.insert(actual_index);
136            }
137        }
138        let marked_actual = mark_selected_entries_in_map(
139            &actual_entries,
140            &extra_entries,
141            format,
142            mark_unexpected_string,
143        );
144        let marked_expected =
145            mark_selected_items_in_collection(expected_keys, missing, format, mark_missing);
146        let missing_keys = collect_selected_values(missing, expected_keys);
147
148        format!(
149            r"expected {expression} to contain the keys {expected_keys:?}
150   but was: {marked_actual}
151  expected: {marked_expected}
152   missing: {missing_keys:?}"
153        )
154    }
155}
156
157impl<M, E> Expectation<M> for MapDoesNotContainKeys<E>
158where
159    M: MapProperties,
160    <M as MapProperties>::Key: PartialEq<E> + Debug,
161    <M as MapProperties>::Value: Debug,
162    E: Debug,
163{
164    fn test(&mut self, subject: &M) -> bool {
165        let keys = subject.keys_property().collect::<Vec<_>>();
166        let extra = &mut self.extra;
167        for (expected_index, expected_key) in self.expected_keys.iter().enumerate() {
168            if keys.iter().any(|k| *k == expected_key) {
169                extra.insert(expected_index);
170            }
171        }
172        extra.is_empty()
173    }
174
175    fn message(
176        &self,
177        expression: &Expression<'_>,
178        actual: &M,
179        _inverted: bool,
180        format: &DiffFormat,
181    ) -> String {
182        let expected_keys = &self.expected_keys;
183        let extra = &self.extra;
184        let actual_entries: Vec<_> = actual.entries_property().collect();
185        let actual_keys: Vec<_> = actual.keys_property().collect();
186        let mut found = HashSet::new();
187        for (actual_index, actual_key) in actual_keys.iter().enumerate() {
188            if expected_keys.iter().any(|expected| *actual_key == expected) {
189                found.insert(actual_index);
190            }
191        }
192        let marked_actual =
193            mark_selected_entries_in_map(&actual_entries, &found, format, mark_unexpected_string);
194        let marked_expected =
195            mark_selected_items_in_collection(expected_keys, extra, format, mark_missing);
196        let extra_keys = collect_selected_values(&found, &actual_keys);
197
198        format!(
199            r"expected {expression} to not contain the keys {expected_keys:?}
200   but was: {marked_actual}
201  expected: {marked_expected}
202     extra: {extra_keys:?}"
203        )
204    }
205}
206
207impl<M, E> Expectation<M> for MapContainsExactlyKeys<E>
208where
209    M: MapProperties,
210    <M as MapProperties>::Key: PartialEq<E> + Debug,
211    <M as MapProperties>::Value: Debug,
212    E: Debug,
213{
214    fn test(&mut self, subject: &M) -> bool {
215        let actual_keys = subject.keys_property().collect::<Vec<_>>();
216        let expected_keys = &self.expected_keys;
217        let missing = &mut self.missing;
218        let extra = &mut self.extra;
219        *extra = (0..actual_keys.len()).collect();
220        for (expected_index, expected_key) in expected_keys.iter().enumerate() {
221            if let Some(actual_index) = actual_keys.iter().position(|k| *k == expected_key) {
222                extra.remove(&actual_index);
223            } else {
224                missing.insert(expected_index);
225            }
226        }
227        missing.is_empty() && extra.is_empty()
228    }
229
230    fn message(
231        &self,
232        expression: &Expression<'_>,
233        actual: &M,
234        _inverted: bool,
235        format: &DiffFormat,
236    ) -> String {
237        let expected_keys = &self.expected_keys;
238        let missing = &self.missing;
239        let extra = &self.extra;
240        let actual_entries: Vec<_> = actual.entries_property().collect();
241        let actual_keys: Vec<_> = actual.keys_property().collect();
242
243        let marked_actual =
244            mark_selected_entries_in_map(&actual_entries, extra, format, mark_unexpected_string);
245        let marked_expected =
246            mark_selected_items_in_collection(expected_keys, missing, format, mark_missing);
247        let missing_keys = collect_selected_values(missing, expected_keys);
248        let extra_keys = collect_selected_values(extra, &actual_keys);
249
250        format!(
251            r"expected {expression} to contain exactly the keys {expected_keys:?}
252   but was: {marked_actual}
253  expected: {marked_expected}
254   missing: {missing_keys:?}
255     extra: {extra_keys:?}"
256        )
257    }
258}
259
260impl<S, E, R> AssertMapContainsValue<E> for Spec<'_, S, R>
261where
262    S: MapProperties,
263    <S as MapProperties>::Key: Debug,
264    <S as MapProperties>::Value: PartialEq<E> + Debug,
265    E: Debug,
266    R: FailingStrategy,
267{
268    fn contains_value(self, expected_value: E) -> Self {
269        self.expecting(map_contains_value(expected_value))
270    }
271
272    fn does_not_contain_value(self, expected_value: E) -> Self {
273        self.expecting(not(map_contains_value(expected_value)))
274    }
275
276    fn contains_values(self, expected_values: impl IntoIterator<Item = E>) -> Self {
277        self.expecting(map_contains_values(expected_values))
278    }
279
280    fn does_not_contain_values(self, expected_values: impl IntoIterator<Item = E>) -> Self {
281        self.expecting(map_does_not_contain_values(expected_values))
282    }
283}
284
285impl<M, E> Expectation<M> for MapContainsValue<E>
286where
287    M: MapProperties,
288    <M as MapProperties>::Key: Debug,
289    <M as MapProperties>::Value: PartialEq<E> + Debug,
290    E: Debug,
291{
292    fn test(&mut self, subject: &M) -> bool {
293        subject.values_property().any(|v| v == &self.expected_value)
294    }
295
296    fn message(
297        &self,
298        expression: &Expression<'_>,
299        actual: &M,
300        inverted: bool,
301        format: &DiffFormat,
302    ) -> String {
303        let expected_value = &self.expected_value;
304        let actual_entries: Vec<_> = actual.entries_property().collect();
305        let (not, marked_actual) = if inverted {
306            let found: HashSet<usize> = actual_entries
307                .iter()
308                .enumerate()
309                .filter_map(|(index, (_, v))| {
310                    if *v == &self.expected_value {
311                        Some(index)
312                    } else {
313                        None
314                    }
315                })
316                .collect();
317            let selected_entries_marked = mark_selected_entries_in_map(
318                &actual_entries,
319                &found,
320                format,
321                mark_unexpected_string,
322            );
323            ("not ", selected_entries_marked)
324        } else {
325            let all_entries_marked =
326                mark_all_entries_in_map(&actual_entries, format, mark_unexpected_string);
327            ("", all_entries_marked)
328        };
329        let marked_expected = mark_missing(&self.expected_value, format);
330
331        format!("expected {expression} to {not}contain the value {expected_value:?}\n   but was: {marked_actual}\n  expected: {not}{marked_expected}")
332    }
333}
334
335impl<E> Invertible for MapContainsValue<E> {}
336
337impl<M, E> Expectation<M> for MapContainsValues<E>
338where
339    M: MapProperties,
340    <M as MapProperties>::Key: Debug,
341    <M as MapProperties>::Value: PartialEq<E> + Debug,
342    E: Debug,
343{
344    fn test(&mut self, subject: &M) -> bool {
345        let values = subject.values_property().collect::<Vec<_>>();
346        let missing = &mut self.missing;
347        for (expected_index, expected_value) in self.expected_values.iter().enumerate() {
348            if !values.iter().any(|v| *v == expected_value) {
349                missing.insert(expected_index);
350            }
351        }
352        missing.is_empty()
353    }
354
355    fn message(
356        &self,
357        expression: &Expression<'_>,
358        actual: &M,
359        _inverted: bool,
360        format: &DiffFormat,
361    ) -> String {
362        let expected_values = &self.expected_values;
363        let missing = &self.missing;
364        let actual_entries: Vec<_> = actual.entries_property().collect();
365        let mut extra_entries = HashSet::new();
366        for (actual_index, actual_entry) in actual_entries.iter().enumerate() {
367            if !expected_values
368                .iter()
369                .any(|expected| actual_entry.1 == expected)
370            {
371                extra_entries.insert(actual_index);
372            }
373        }
374        let marked_actual = mark_selected_entries_in_map(
375            &actual_entries,
376            &extra_entries,
377            format,
378            mark_unexpected_string,
379        );
380        let marked_expected =
381            mark_selected_items_in_collection(expected_values, missing, format, mark_missing);
382        let missing_values = collect_selected_values(missing, expected_values);
383
384        format!(
385            r"expected {expression} to contain the values {expected_values:?}
386   but was: {marked_actual}
387  expected: {marked_expected}
388   missing: {missing_values:?}"
389        )
390    }
391}
392
393impl<M, E> Expectation<M> for MapDoesNotContainValues<E>
394where
395    M: MapProperties,
396    <M as MapProperties>::Key: Debug,
397    <M as MapProperties>::Value: PartialEq<E> + Debug,
398    E: Debug,
399{
400    fn test(&mut self, subject: &M) -> bool {
401        let values = subject.values_property().collect::<Vec<_>>();
402        let extra = &mut self.extra;
403        for (expected_index, expected_value) in self.expected_values.iter().enumerate() {
404            if values.iter().any(|v| *v == expected_value) {
405                extra.insert(expected_index);
406            }
407        }
408        extra.is_empty()
409    }
410
411    fn message(
412        &self,
413        expression: &Expression<'_>,
414        actual: &M,
415        _inverted: bool,
416        format: &DiffFormat,
417    ) -> String {
418        let expected_values = &self.expected_values;
419        let extra = &self.extra;
420        let actual_entries: Vec<_> = actual.entries_property().collect();
421        let actual_values: Vec<_> = actual.values_property().collect();
422        let mut found = HashSet::new();
423        for (actual_index, actual_value) in actual_values.iter().enumerate() {
424            if expected_values
425                .iter()
426                .any(|expected| *actual_value == expected)
427            {
428                found.insert(actual_index);
429            }
430        }
431        let marked_actual =
432            mark_selected_entries_in_map(&actual_entries, &found, format, mark_unexpected_string);
433        let marked_expected =
434            mark_selected_items_in_collection(expected_values, extra, format, mark_missing);
435        let extra_values = collect_selected_values(&found, &actual_values);
436
437        format!(
438            r"expected {expression} to not contain the values {expected_values:?}
439   but was: {marked_actual}
440  expected: {marked_expected}
441     extra: {extra_values:?}"
442        )
443    }
444}
445
446mod hashbrown_impls {
447    use crate::properties::MapProperties;
448    use crate::std::iter::Iterator;
449    use hashbrown::HashMap;
450
451    impl<K, V, H> MapProperties for HashMap<K, V, H> {
452        type Key = K;
453        type Value = V;
454
455        fn keys_property(&self) -> impl Iterator<Item = &<Self as MapProperties>::Key> {
456            self.keys()
457        }
458
459        fn values_property(&self) -> impl Iterator<Item = &Self::Value> {
460            self.values()
461        }
462
463        fn entries_property(&self) -> impl Iterator<Item = (&Self::Key, &Self::Value)> {
464            self.iter()
465        }
466    }
467
468    impl<K, V, H> MapProperties for &HashMap<K, V, H> {
469        type Key = K;
470        type Value = V;
471
472        fn keys_property(&self) -> impl Iterator<Item = &<Self as MapProperties>::Key> {
473            self.keys()
474        }
475
476        fn values_property(&self) -> impl Iterator<Item = &Self::Value> {
477            self.values()
478        }
479
480        fn entries_property(&self) -> impl Iterator<Item = (&Self::Key, &Self::Value)> {
481            self.iter()
482        }
483    }
484
485    impl<K, V, H> MapProperties for &mut HashMap<K, V, H> {
486        type Key = K;
487        type Value = V;
488
489        fn keys_property(&self) -> impl Iterator<Item = &<Self as MapProperties>::Key> {
490            self.keys()
491        }
492
493        fn values_property(&self) -> impl Iterator<Item = &Self::Value> {
494            self.values()
495        }
496
497        fn entries_property(&self) -> impl Iterator<Item = (&Self::Key, &Self::Value)> {
498            self.iter()
499        }
500    }
501}
502
503#[cfg(feature = "std")]
504mod std_hashmap_impls {
505    use crate::properties::MapProperties;
506    use crate::std::iter::Iterator;
507    use std::collections::HashMap;
508
509    impl<K, V, H> MapProperties for HashMap<K, V, H> {
510        type Key = K;
511        type Value = V;
512
513        fn keys_property(&self) -> impl Iterator<Item = &<Self as MapProperties>::Key> {
514            self.keys()
515        }
516
517        fn values_property(&self) -> impl Iterator<Item = &Self::Value> {
518            self.values()
519        }
520
521        fn entries_property(&self) -> impl Iterator<Item = (&Self::Key, &Self::Value)> {
522            self.iter()
523        }
524    }
525
526    impl<K, V, H> MapProperties for &HashMap<K, V, H> {
527        type Key = K;
528        type Value = V;
529
530        fn keys_property(&self) -> impl Iterator<Item = &<Self as MapProperties>::Key> {
531            self.keys()
532        }
533
534        fn values_property(&self) -> impl Iterator<Item = &Self::Value> {
535            self.values()
536        }
537
538        fn entries_property(&self) -> impl Iterator<Item = (&Self::Key, &Self::Value)> {
539            self.iter()
540        }
541    }
542
543    impl<K, V, H> MapProperties for &mut HashMap<K, V, H> {
544        type Key = K;
545        type Value = V;
546
547        fn keys_property(&self) -> impl Iterator<Item = &<Self as MapProperties>::Key> {
548            self.keys()
549        }
550
551        fn values_property(&self) -> impl Iterator<Item = &Self::Value> {
552            self.values()
553        }
554
555        fn entries_property(&self) -> impl Iterator<Item = (&Self::Key, &Self::Value)> {
556            self.iter()
557        }
558    }
559}
560
561mod btree_map_impls {
562    use crate::properties::MapProperties;
563    use crate::std::collections::BTreeMap;
564    use crate::std::iter::Iterator;
565
566    impl<K, V> MapProperties for BTreeMap<K, V> {
567        type Key = K;
568        type Value = V;
569
570        fn keys_property(&self) -> impl Iterator<Item = &<Self as MapProperties>::Key> {
571            self.keys()
572        }
573
574        fn values_property(&self) -> impl Iterator<Item = &Self::Value> {
575            self.values()
576        }
577
578        fn entries_property(&self) -> impl Iterator<Item = (&Self::Key, &Self::Value)> {
579            self.iter()
580        }
581    }
582
583    impl<K, V> MapProperties for &BTreeMap<K, V> {
584        type Key = K;
585        type Value = V;
586
587        fn keys_property(&self) -> impl Iterator<Item = &<Self as MapProperties>::Key> {
588            self.keys()
589        }
590
591        fn values_property(&self) -> impl Iterator<Item = &Self::Value> {
592            self.values()
593        }
594
595        fn entries_property(&self) -> impl Iterator<Item = (&Self::Key, &Self::Value)> {
596            self.iter()
597        }
598    }
599
600    impl<K, V> MapProperties for &mut BTreeMap<K, V> {
601        type Key = K;
602        type Value = V;
603
604        fn keys_property(&self) -> impl Iterator<Item = &<Self as MapProperties>::Key> {
605            self.keys()
606        }
607
608        fn values_property(&self) -> impl Iterator<Item = &Self::Value> {
609            self.values()
610        }
611
612        fn entries_property(&self) -> impl Iterator<Item = (&Self::Key, &Self::Value)> {
613            self.iter()
614        }
615    }
616}
617
618#[cfg(test)]
619mod tests;