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;