asserting/iterator/
mod.rs

1//! Implementations of assertions for `Iterator` values.
2
3use crate::assertions::{
4    AssertIteratorContains, AssertIteratorContainsInAnyOrder, AssertIteratorContainsInOrder,
5};
6use crate::colored::{
7    mark_all_items_in_collection, mark_missing, mark_selected_items_in_collection, mark_unexpected,
8};
9use crate::expectations::{
10    iterator_contains, iterator_contains_all_in_order, iterator_contains_all_of,
11    iterator_contains_any_of, iterator_contains_exactly, iterator_contains_exactly_in_any_order,
12    iterator_contains_only, iterator_contains_only_once, iterator_contains_sequence,
13    iterator_ends_with, iterator_starts_with, not, IteratorContains, IteratorContainsAllInOrder,
14    IteratorContainsAllOf, IteratorContainsAnyOf, IteratorContainsExactly,
15    IteratorContainsExactlyInAnyOrder, IteratorContainsOnly, IteratorContainsOnlyOnce,
16    IteratorContainsSequence, IteratorEndsWith, IteratorStartsWith,
17};
18use crate::properties::DefinedOrderProperty;
19use crate::spec::{DiffFormat, Expectation, Expression, FailingStrategy, Invertible, Spec};
20use crate::std::cmp::Ordering;
21use crate::std::fmt::Debug;
22use crate::std::mem;
23use crate::std::{format, string::String, vec, vec::Vec};
24use hashbrown::HashSet;
25
26impl<'a, S, T, E, R> AssertIteratorContains<'a, Vec<T>, E, R> for Spec<'a, S, R>
27where
28    S: IntoIterator<Item = T>,
29    T: PartialEq<E> + Debug,
30    E: Debug,
31    R: FailingStrategy,
32{
33    fn contains(self, expected: E) -> Spec<'a, Vec<T>, R> {
34        self.mapping(Vec::from_iter)
35            .expecting(iterator_contains(expected))
36    }
37
38    fn does_not_contain(self, expected: E) -> Spec<'a, Vec<T>, R> {
39        self.mapping(Vec::from_iter)
40            .expecting(not(iterator_contains(expected)))
41    }
42}
43
44impl<T, E> Expectation<Vec<T>> for IteratorContains<E>
45where
46    T: PartialEq<E> + Debug,
47    E: Debug,
48{
49    fn test(&mut self, subject: &Vec<T>) -> bool {
50        subject.iter().any(|e| e == &self.expected)
51    }
52
53    fn message(
54        &self,
55        expression: &Expression<'_>,
56        actual: &Vec<T>,
57        inverted: bool,
58        format: &DiffFormat,
59    ) -> String {
60        let (not, marked_actual) = if inverted {
61            let found_unexpected = actual
62                .iter()
63                .enumerate()
64                .filter_map(|(idx, element)| {
65                    if element == &self.expected {
66                        Some(idx)
67                    } else {
68                        None
69                    }
70                })
71                .collect();
72            let marked_actual = mark_selected_items_in_collection(
73                actual,
74                &found_unexpected,
75                format,
76                mark_unexpected,
77            );
78            ("not ", marked_actual)
79        } else {
80            let marked_actual = mark_all_items_in_collection(actual, format, mark_unexpected);
81            ("", marked_actual)
82        };
83        let marked_expected = mark_missing(&self.expected, format);
84        format!(
85            "expected {expression} to {not}contain {:?}\n   but was: {marked_actual}\n  expected: {not}{marked_expected}",
86            &self.expected,
87        )
88    }
89}
90
91impl<E> Invertible for IteratorContains<E> {}
92
93impl<'a, S, T, E, R> AssertIteratorContainsInAnyOrder<'a, Vec<T>, E, R> for Spec<'a, S, R>
94where
95    S: IntoIterator<Item = T>,
96    T: PartialEq<<E as IntoIterator>::Item> + Debug,
97    E: IntoIterator,
98    <E as IntoIterator>::Item: Debug,
99    R: FailingStrategy,
100{
101    fn contains_exactly_in_any_order(self, expected: E) -> Spec<'a, Vec<T>, R> {
102        self.mapping(Vec::from_iter)
103            .expecting(iterator_contains_exactly_in_any_order(expected))
104    }
105
106    fn contains_any_of(self, expected: E) -> Spec<'a, Vec<T>, R> {
107        self.mapping(Vec::from_iter)
108            .expecting(iterator_contains_any_of(expected))
109    }
110
111    fn does_not_contain_any_of(self, expected: E) -> Spec<'a, Vec<T>, R> {
112        self.mapping(Vec::from_iter)
113            .expecting(not(iterator_contains_any_of(expected)))
114    }
115
116    fn contains_all_of(self, expected: E) -> Spec<'a, Vec<T>, R> {
117        self.mapping(Vec::from_iter)
118            .expecting(iterator_contains_all_of(expected))
119    }
120
121    fn contains_only(self, expected: E) -> Spec<'a, Vec<T>, R> {
122        self.mapping(Vec::from_iter)
123            .expecting(iterator_contains_only(expected))
124    }
125
126    fn contains_only_once(self, expected: E) -> Spec<'a, Vec<T>, R> {
127        self.mapping(Vec::from_iter)
128            .expecting(iterator_contains_only_once(expected))
129    }
130}
131
132impl<T, E> Expectation<Vec<T>> for IteratorContainsExactlyInAnyOrder<E>
133where
134    T: PartialEq<E> + Debug,
135    E: Debug,
136{
137    fn test(&mut self, subject: &Vec<T>) -> bool {
138        let missing = &mut self.missing;
139        let extra = &mut self.extra;
140        *extra = (0..subject.len()).collect();
141
142        let mut subject_values = subject.iter().enumerate().collect::<Vec<_>>();
143        for (expected_index, expected) in self.expected.iter().enumerate() {
144            if let Some(index) = subject_values
145                .iter()
146                .position(|(_, value)| *value == expected)
147            {
148                let (subject_index, _) = subject_values.remove(index);
149                extra.remove(&subject_index);
150            } else {
151                missing.insert(expected_index);
152            }
153        }
154
155        extra.is_empty() && missing.is_empty()
156    }
157
158    fn message(
159        &self,
160        expression: &Expression<'_>,
161        actual: &Vec<T>,
162        _inverted: bool,
163        format: &DiffFormat,
164    ) -> String {
165        let missing = collect_selected_values(&self.missing, &self.expected);
166        let extra = collect_selected_values(&self.extra, actual);
167        let marked_actual =
168            mark_selected_items_in_collection(actual, &self.extra, format, mark_unexpected);
169        let marked_expected =
170            mark_selected_items_in_collection(&self.expected, &self.missing, format, mark_missing);
171
172        format!(
173            r"expected {expression} to contain exactly in any order {:?}
174   but was: {marked_actual}
175  expected: {marked_expected}
176   missing: {missing:?}
177     extra: {extra:?}",
178            &self.expected
179        )
180    }
181}
182
183impl<T, E> Expectation<Vec<T>> for IteratorContainsAnyOf<E>
184where
185    T: PartialEq<E> + Debug,
186    E: Debug,
187{
188    fn test(&mut self, subject: &Vec<T>) -> bool {
189        for expected in &self.expected {
190            if subject.iter().any(|value| value == expected) {
191                return true;
192            }
193        }
194        false
195    }
196
197    fn message(
198        &self,
199        expression: &Expression<'_>,
200        actual: &Vec<T>,
201        inverted: bool,
202        format: &DiffFormat,
203    ) -> String {
204        let (not, marked_actual, marked_expected) = if inverted {
205            let mut found_in_actual = HashSet::new();
206            let mut found_in_expected = HashSet::new();
207            for (exp_idx, expected_item) in self.expected.iter().enumerate() {
208                let found = actual
209                    .iter()
210                    .enumerate()
211                    .filter_map(|(idx, elem)| {
212                        if elem == expected_item {
213                            Some(idx)
214                        } else {
215                            None
216                        }
217                    })
218                    .collect::<Vec<_>>();
219                if !found.is_empty() {
220                    found_in_actual.extend(found);
221                    found_in_expected.insert(exp_idx);
222                }
223            }
224            let marked_actual = mark_selected_items_in_collection(
225                actual,
226                &found_in_actual,
227                format,
228                mark_unexpected,
229            );
230            let marked_expected = mark_selected_items_in_collection(
231                &self.expected,
232                &found_in_expected,
233                format,
234                mark_missing,
235            );
236            ("not ", marked_actual, marked_expected)
237        } else {
238            let marked_actual = mark_all_items_in_collection(actual, format, mark_unexpected);
239            let marked_expected =
240                mark_all_items_in_collection(&self.expected, format, mark_missing);
241            ("", marked_actual, marked_expected)
242        };
243        format!(
244            r"expected {expression} to {not}contain any of {:?}
245   but was: {marked_actual}
246  expected: {not}{marked_expected}",
247            &self.expected,
248        )
249    }
250}
251
252impl<E> Invertible for IteratorContainsAnyOf<E> {}
253
254impl<T, E> Expectation<Vec<T>> for IteratorContainsAllOf<E>
255where
256    T: PartialEq<E> + Debug,
257    E: Debug,
258{
259    fn test(&mut self, subject: &Vec<T>) -> bool {
260        let missing = &mut self.missing;
261
262        for (expected_index, expected) in self.expected.iter().enumerate() {
263            if !subject.iter().any(|value| value == expected) {
264                missing.insert(expected_index);
265            }
266        }
267
268        missing.is_empty()
269    }
270
271    fn message(
272        &self,
273        expression: &Expression<'_>,
274        actual: &Vec<T>,
275        _inverted: bool,
276        format: &DiffFormat,
277    ) -> String {
278        let mut extra = HashSet::new();
279        for (actual_index, actual) in actual.iter().enumerate() {
280            if !self.expected.iter().any(|expected| actual == expected) {
281                extra.insert(actual_index);
282            }
283        }
284        let marked_actual =
285            mark_selected_items_in_collection(actual, &extra, format, mark_unexpected);
286        let marked_expected =
287            mark_selected_items_in_collection(&self.expected, &self.missing, format, mark_missing);
288        let missing = collect_selected_values(&self.missing, &self.expected);
289
290        format!(
291            r"expected {expression} to contain all of {:?}
292   but was: {marked_actual}
293  expected: {marked_expected}
294   missing: {missing:?}",
295            &self.expected,
296        )
297    }
298}
299
300impl<T, E> Expectation<Vec<T>> for IteratorContainsOnly<E>
301where
302    T: PartialEq<E> + Debug,
303    E: Debug,
304{
305    fn test(&mut self, subject: &Vec<T>) -> bool {
306        let extra = &mut self.extra;
307
308        for (actual_index, value) in subject.iter().enumerate() {
309            if !self.expected.iter().any(|expected| value == expected) {
310                extra.insert(actual_index);
311            }
312        }
313
314        extra.is_empty()
315    }
316
317    fn message(
318        &self,
319        expression: &Expression<'_>,
320        actual: &Vec<T>,
321        _inverted: bool,
322        format: &DiffFormat,
323    ) -> String {
324        let mut missing = HashSet::new();
325        for (expected_index, expected) in self.expected.iter().enumerate() {
326            if !actual.iter().any(|value| value == expected) {
327                missing.insert(expected_index);
328            }
329        }
330        let marked_actual =
331            mark_selected_items_in_collection(actual, &self.extra, format, mark_unexpected);
332        let marked_expected =
333            mark_selected_items_in_collection(&self.expected, &missing, format, mark_missing);
334        let extra = collect_selected_values(&self.extra, actual);
335
336        format!(
337            r"expected {expression} to contain only {:?}
338   but was: {marked_actual}
339  expected: {marked_expected}
340     extra: {extra:?}",
341            &self.expected,
342        )
343    }
344}
345
346impl<T, E> Expectation<Vec<T>> for IteratorContainsOnlyOnce<E>
347where
348    T: PartialEq<E> + Debug,
349    E: Debug,
350{
351    fn test(&mut self, subject: &Vec<T>) -> bool {
352        let extra = &mut self.extra;
353        let duplicates = &mut self.duplicates;
354
355        for (actual_index, value) in subject.iter().enumerate() {
356            if let Some(expected) = self.expected.iter().find(|expected| value == *expected) {
357                if subject.iter().filter(|actual| *actual == expected).count() > 1 {
358                    duplicates.insert(actual_index);
359                }
360            } else {
361                extra.insert(actual_index);
362            }
363        }
364
365        duplicates.is_empty() && extra.is_empty()
366    }
367
368    fn message(
369        &self,
370        expression: &Expression<'_>,
371        actual: &Vec<T>,
372        _inverted: bool,
373        format: &DiffFormat,
374    ) -> String {
375        let actual_duplicates_and_extras = self.duplicates.union(&self.extra).copied().collect();
376        let marked_actual = mark_selected_items_in_collection(
377            actual,
378            &actual_duplicates_and_extras,
379            format,
380            mark_unexpected,
381        );
382        let duplicates = collect_selected_values(&self.duplicates, actual);
383        let mut expected_duplicates_and_missing = HashSet::new();
384        for (expected_index, expected) in self.expected.iter().enumerate() {
385            if duplicates.iter().any(|duplicate| *duplicate == expected)
386                || !actual.iter().any(|actual| actual == expected)
387            {
388                expected_duplicates_and_missing.insert(expected_index);
389            }
390        }
391        let marked_expected = mark_selected_items_in_collection(
392            &self.expected,
393            &expected_duplicates_and_missing,
394            format,
395            mark_missing,
396        );
397        let extra = collect_selected_values(&self.extra, actual);
398
399        format!(
400            r"expected {expression} to contain only once {:?}
401     but was: {marked_actual}
402    expected: {marked_expected}
403       extra: {extra:?}
404  duplicates: {duplicates:?}",
405            &self.expected,
406        )
407    }
408}
409
410impl<'a, S, T, E, R> AssertIteratorContainsInOrder<'a, Vec<T>, E, R> for Spec<'a, S, R>
411where
412    S: IntoIterator<Item = T>,
413    <S as IntoIterator>::IntoIter: DefinedOrderProperty,
414    E: IntoIterator,
415    <E as IntoIterator>::IntoIter: DefinedOrderProperty,
416    <E as IntoIterator>::Item: Debug,
417    T: PartialEq<<E as IntoIterator>::Item> + Debug,
418    R: FailingStrategy,
419{
420    fn contains_exactly(self, expected: E) -> Spec<'a, Vec<T>, R> {
421        self.mapping(Vec::from_iter)
422            .expecting(iterator_contains_exactly(expected))
423    }
424
425    fn contains_sequence(self, expected: E) -> Spec<'a, Vec<T>, R> {
426        self.mapping(Vec::from_iter)
427            .expecting(iterator_contains_sequence(expected))
428    }
429
430    fn contains_all_in_order(self, expected: E) -> Spec<'a, Vec<T>, R> {
431        self.mapping(Vec::from_iter)
432            .expecting(iterator_contains_all_in_order(expected))
433    }
434
435    fn starts_with(self, expected: E) -> Spec<'a, Vec<T>, R> {
436        self.mapping(Vec::from_iter)
437            .expecting(iterator_starts_with(expected))
438    }
439
440    fn ends_with(self, expected: E) -> Spec<'a, Vec<T>, R> {
441        self.mapping(Vec::from_iter)
442            .expecting(iterator_ends_with(expected))
443    }
444}
445
446impl<T, E> Expectation<Vec<T>> for IteratorContainsExactly<E>
447where
448    T: PartialEq<E> + Debug,
449    E: Debug,
450{
451    fn test(&mut self, subject: &Vec<T>) -> bool {
452        let mut maybe_extras = Vec::new();
453        let mut maybe_missing = Vec::new();
454        let mut expected_iter = self.expected.iter().enumerate();
455        let mut subject_iter = subject.iter().enumerate();
456        loop {
457            match (expected_iter.next(), subject_iter.next()) {
458                (Some((expected_index, expected_value)), Some((subject_index, actual_value))) => {
459                    if actual_value == expected_value {
460                        continue;
461                    }
462                    maybe_missing.push((expected_index, expected_value));
463                    maybe_extras.push((subject_index, actual_value));
464                },
465                (Some(expected), None) => maybe_missing.push(expected),
466                (None, Some(actual)) => maybe_extras.push(actual),
467                (None, None) => break,
468            }
469        }
470
471        let missing = &mut self.missing;
472        let extra = &mut self.extra;
473        let out_of_order = &mut self.out_of_order;
474
475        for (expected_index, expected_value) in maybe_missing {
476            if let Some(index) = maybe_extras
477                .iter()
478                .position(|(_, value)| *value == expected_value)
479            {
480                let (subject_index, _) = maybe_extras.remove(index);
481                out_of_order.insert(subject_index);
482            } else {
483                missing.insert(expected_index);
484            }
485        }
486        for (subject_index, _) in maybe_extras {
487            extra.insert(subject_index);
488        }
489
490        out_of_order.is_empty() && extra.is_empty() && missing.is_empty()
491    }
492
493    fn message(
494        &self,
495        expression: &Expression<'_>,
496        actual: &Vec<T>,
497        _inverted: bool,
498        format: &DiffFormat,
499    ) -> String {
500        let out_of_order = collect_selected_values(&self.out_of_order, actual);
501        let mut expected_indices = self.missing.clone();
502        for (expected_index, expected) in self.expected.iter().enumerate() {
503            if out_of_order.iter().any(|actual| *actual == expected) {
504                expected_indices.insert(expected_index);
505            }
506        }
507        let marked_expected = mark_selected_items_in_collection(
508            &self.expected,
509            &expected_indices,
510            format,
511            mark_missing,
512        );
513        let actual_indices = self.extra.union(&self.out_of_order).copied().collect();
514        let marked_actual =
515            mark_selected_items_in_collection(actual, &actual_indices, format, mark_unexpected);
516
517        let missing = collect_selected_values(&self.missing, &self.expected);
518        let extra = collect_selected_values(&self.extra, actual);
519
520        format!(
521            r"expected {expression} to contain exactly in order {:?}
522       but was: {marked_actual}
523      expected: {marked_expected}
524       missing: {missing:?}
525         extra: {extra:?}
526  out-of-order: {out_of_order:?}",
527            &self.expected,
528        )
529    }
530}
531
532impl<T, E> Expectation<Vec<T>> for IteratorContainsSequence<E>
533where
534    T: PartialEq<E> + Debug,
535    E: Debug,
536{
537    fn test(&mut self, subject: &Vec<T>) -> bool {
538        let subject_length = subject.len();
539        let sequence_length = self.expected.len();
540        let possible_sequence_starts = if sequence_length >= subject_length {
541            vec![0]
542        } else {
543            (0..=subject_length - sequence_length).collect()
544        };
545        let best_missing = &mut self.missing;
546        let best_extra = &mut self.extra;
547        let mut best_match_count = 0;
548        let mut missing = HashSet::new();
549        let mut extra = HashSet::new();
550        let mut match_count = 0;
551        for start_index in possible_sequence_starts {
552            let mut expected_iter = self.expected.iter().enumerate();
553            let mut subject_iter = subject.iter().enumerate().skip(start_index);
554            loop {
555                match (expected_iter.next(), subject_iter.next()) {
556                    (
557                        Some((expected_index, expected_value)),
558                        Some((subject_index, actual_value)),
559                    ) => {
560                        if actual_value == expected_value {
561                            match_count += 1;
562                            continue;
563                        }
564                        missing.insert(expected_index);
565                        extra.insert(subject_index);
566                    },
567                    (Some((expected_index, _)), None) => {
568                        missing.insert(expected_index);
569                    },
570                    (None, _) => break,
571                }
572            }
573            if missing.is_empty() && extra.is_empty() {
574                *best_missing = HashSet::new();
575                *best_extra = HashSet::new();
576                return true;
577            }
578            match match_count.cmp(&best_match_count) {
579                Ordering::Less => {
580                    missing.clear();
581                    extra.clear();
582                },
583                Ordering::Equal => {
584                    best_missing.extend(mem::replace(&mut missing, HashSet::new()));
585                    best_extra.extend(mem::replace(&mut extra, HashSet::new()));
586                },
587                Ordering::Greater => {
588                    best_match_count = match_count;
589                    *best_missing = mem::replace(&mut missing, HashSet::new());
590                    *best_extra = mem::replace(&mut extra, HashSet::new());
591                },
592            }
593            match_count = 0;
594        }
595        false
596    }
597
598    fn message(
599        &self,
600        expression: &Expression<'_>,
601        actual: &Vec<T>,
602        _inverted: bool,
603        format: &DiffFormat,
604    ) -> String {
605        let marked_actual =
606            mark_selected_items_in_collection(actual, &self.extra, format, mark_unexpected);
607        let marked_expected =
608            mark_selected_items_in_collection(&self.expected, &self.missing, format, mark_missing);
609        let missing = collect_selected_values(&self.missing, &self.expected);
610        let extra = collect_selected_values(&self.extra, actual);
611
612        format!(
613            r"expected {expression} to contain the sequence {:?}
614   but was: {marked_actual}
615  expected: {marked_expected}
616   missing: {missing:?}
617     extra: {extra:?}",
618            &self.expected,
619        )
620    }
621}
622
623impl<T, E> Expectation<Vec<T>> for IteratorContainsAllInOrder<E>
624where
625    T: PartialEq<E> + Debug,
626    E: Debug,
627{
628    fn test(&mut self, subject: &Vec<T>) -> bool {
629        let missing = &mut self.missing;
630        let mut last_match_index = 0;
631        for (expected_index, expected) in self.expected.iter().enumerate() {
632            if let Some((subject_index, _)) = subject
633                .iter()
634                .enumerate()
635                .skip(last_match_index)
636                .find(|(_, actual)| *actual == expected)
637            {
638                last_match_index = subject_index + 1;
639            } else {
640                missing.insert(expected_index);
641            }
642        }
643        missing.is_empty()
644    }
645
646    fn message(
647        &self,
648        expression: &Expression<'_>,
649        actual: &Vec<T>,
650        _inverted: bool,
651        format: &DiffFormat,
652    ) -> String {
653        let marked_expected =
654            mark_selected_items_in_collection(&self.expected, &self.missing, format, mark_missing);
655        let missing = collect_selected_values(&self.missing, &self.expected);
656
657        format!(
658            r"expected {expression} to contain all of {:?} in order
659   but was: {actual:?}
660  expected: {marked_expected}
661   missing: {missing:?}",
662            &self.expected,
663        )
664    }
665}
666
667impl<T, E> Expectation<Vec<T>> for IteratorStartsWith<E>
668where
669    T: PartialEq<E> + Debug,
670    E: Debug,
671{
672    fn test(&mut self, subject: &Vec<T>) -> bool {
673        let missing = &mut self.missing;
674        let extra = &mut self.extra;
675        let mut expected_iter = self.expected.iter().enumerate();
676        let mut subject_iter = subject.iter().enumerate();
677        loop {
678            match (expected_iter.next(), subject_iter.next()) {
679                (Some((expected_index, expected)), Some((subject_index, actual))) => {
680                    if actual == expected {
681                        continue;
682                    }
683                    missing.insert(expected_index);
684                    extra.insert(subject_index);
685                },
686                (Some((expected_index, _)), None) => {
687                    missing.insert(expected_index);
688                },
689                (None, _) => break,
690            }
691        }
692        extra.is_empty() && missing.is_empty()
693    }
694
695    fn message(
696        &self,
697        expression: &Expression<'_>,
698        actual: &Vec<T>,
699        _inverted: bool,
700        format: &DiffFormat,
701    ) -> String {
702        let marked_actual =
703            mark_selected_items_in_collection(actual, &self.extra, format, mark_unexpected);
704        let marked_expected =
705            mark_selected_items_in_collection(&self.expected, &self.missing, format, mark_missing);
706        let missing = collect_selected_values(&self.missing, &self.expected);
707        let extra = collect_selected_values(&self.extra, actual);
708
709        format!(
710            r"expected {expression} to start with {:?}
711   but was: {marked_actual}
712  expected: {marked_expected}
713   missing: {missing:?}
714     extra: {extra:?}",
715            &self.expected,
716        )
717    }
718}
719
720impl<T, E> Expectation<Vec<T>> for IteratorEndsWith<E>
721where
722    T: PartialEq<E> + Debug,
723    E: Debug,
724{
725    fn test(&mut self, subject: &Vec<T>) -> bool {
726        let missing = &mut self.missing;
727        let extra = &mut self.extra;
728        let mut expected_iter = self.expected.iter().enumerate().rev();
729        let mut subject_iter = subject.iter().enumerate().rev();
730        loop {
731            match (expected_iter.next(), subject_iter.next()) {
732                (Some((expected_index, expected)), Some((subject_index, actual))) => {
733                    if actual == expected {
734                        continue;
735                    }
736                    missing.insert(expected_index);
737                    extra.insert(subject_index);
738                },
739                (Some((expected_index, _)), None) => {
740                    missing.insert(expected_index);
741                },
742                (None, _) => break,
743            }
744        }
745        extra.is_empty() && missing.is_empty()
746    }
747
748    fn message(
749        &self,
750        expression: &Expression<'_>,
751        actual: &Vec<T>,
752        _inverted: bool,
753        format: &DiffFormat,
754    ) -> String {
755        let marked_actual =
756            mark_selected_items_in_collection(actual, &self.extra, format, mark_unexpected);
757        let marked_expected =
758            mark_selected_items_in_collection(&self.expected, &self.missing, format, mark_missing);
759        let missing = collect_selected_values(&self.missing, &self.expected);
760        let extra = collect_selected_values(&self.extra, actual);
761
762        format!(
763            r"expected {expression} to end with {:?}
764   but was: {marked_actual}
765  expected: {marked_expected}
766   missing: {missing:?}
767     extra: {extra:?}",
768            &self.expected,
769        )
770    }
771}
772
773pub fn collect_selected_values<'a, T>(indices: &HashSet<usize>, collection: &'a [T]) -> Vec<&'a T> {
774    collection
775        .iter()
776        .enumerate()
777        .filter_map(|(idx, value)| {
778            if indices.contains(&idx) {
779                Some(value)
780            } else {
781                None
782            }
783        })
784        .collect()
785}
786
787#[cfg(test)]
788mod tests;