1use 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;