• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Test specializations of methods with default impls match the behavior of the
2 //! default impls.
3 //!
4 //! **NOTE:** Due to performance limitations, these tests are not run with miri!
5 //! They cannot be relied upon to discover soundness issues.
6 
7 #![cfg(not(miri))]
8 #![allow(unstable_name_collisions)]
9 
10 use itertools::Itertools;
11 use quickcheck::Arbitrary;
12 use quickcheck::{quickcheck, TestResult};
13 use rand::Rng;
14 use std::fmt::Debug;
15 
16 struct Unspecialized<I>(I);
17 
18 impl<I> Iterator for Unspecialized<I>
19 where
20     I: Iterator,
21 {
22     type Item = I::Item;
23 
24     #[inline(always)]
next(&mut self) -> Option<Self::Item>25     fn next(&mut self) -> Option<Self::Item> {
26         self.0.next()
27     }
28 }
29 
30 impl<I> DoubleEndedIterator for Unspecialized<I>
31 where
32     I: DoubleEndedIterator,
33 {
34     #[inline(always)]
next_back(&mut self) -> Option<Self::Item>35     fn next_back(&mut self) -> Option<Self::Item> {
36         self.0.next_back()
37     }
38 }
39 
test_specializations<I>(it: &I) where I::Item: Eq + Debug + Clone, I: Iterator + Clone,40 fn test_specializations<I>(it: &I)
41 where
42     I::Item: Eq + Debug + Clone,
43     I: Iterator + Clone,
44 {
45     macro_rules! check_specialized {
46         ($src:expr, |$it:pat| $closure:expr) => {
47             // Many iterators special-case the first elements, so we test specializations for iterators that have already been advanced.
48             let mut src = $src.clone();
49             for _ in 0..5 {
50                 let $it = src.clone();
51                 let v1 = $closure;
52                 let $it = Unspecialized(src.clone());
53                 let v2 = $closure;
54                 assert_eq!(v1, v2);
55                 src.next();
56             }
57         }
58     }
59     check_specialized!(it, |i| i.count());
60     check_specialized!(it, |i| i.last());
61     check_specialized!(it, |i| i.collect::<Vec<_>>());
62     check_specialized!(it, |i| {
63         let mut parameters_from_fold = vec![];
64         let fold_result = i.fold(vec![], |mut acc, v: I::Item| {
65             parameters_from_fold.push((acc.clone(), v.clone()));
66             acc.push(v);
67             acc
68         });
69         (parameters_from_fold, fold_result)
70     });
71     check_specialized!(it, |mut i| {
72         let mut parameters_from_all = vec![];
73         let first = i.next();
74         let all_result = i.all(|x| {
75             parameters_from_all.push(x.clone());
76             Some(x) == first
77         });
78         (parameters_from_all, all_result)
79     });
80     let size = it.clone().count();
81     for n in 0..size + 2 {
82         check_specialized!(it, |mut i| i.nth(n));
83     }
84     // size_hint is a bit harder to check
85     let mut it_sh = it.clone();
86     for n in 0..size + 2 {
87         let len = it_sh.clone().count();
88         let (min, max) = it_sh.size_hint();
89         assert_eq!(size - n.min(size), len);
90         assert!(min <= len);
91         if let Some(max) = max {
92             assert!(len <= max);
93         }
94         it_sh.next();
95     }
96 }
97 
test_double_ended_specializations<I>(it: &I) where I::Item: Eq + Debug + Clone, I: DoubleEndedIterator + Clone,98 fn test_double_ended_specializations<I>(it: &I)
99 where
100     I::Item: Eq + Debug + Clone,
101     I: DoubleEndedIterator + Clone,
102 {
103     macro_rules! check_specialized {
104         ($src:expr, |$it:pat| $closure:expr) => {
105             // Many iterators special-case the first elements, so we test specializations for iterators that have already been advanced.
106             let mut src = $src.clone();
107             for step in 0..8 {
108                 let $it = src.clone();
109                 let v1 = $closure;
110                 let $it = Unspecialized(src.clone());
111                 let v2 = $closure;
112                 assert_eq!(v1, v2);
113                 if step % 2 == 0 {
114                     src.next();
115                 } else {
116                     src.next_back();
117                 }
118             }
119         }
120     }
121     check_specialized!(it, |i| {
122         let mut parameters_from_rfold = vec![];
123         let rfold_result = i.rfold(vec![], |mut acc, v: I::Item| {
124             parameters_from_rfold.push((acc.clone(), v.clone()));
125             acc.push(v);
126             acc
127         });
128         (parameters_from_rfold, rfold_result)
129     });
130     let size = it.clone().count();
131     for n in 0..size + 2 {
132         check_specialized!(it, |mut i| i.nth_back(n));
133     }
134 }
135 
136 quickcheck! {
137     fn interleave(v: Vec<u8>, w: Vec<u8>) -> () {
138         test_specializations(&v.iter().interleave(w.iter()));
139     }
140 
141     fn interleave_shortest(v: Vec<u8>, w: Vec<u8>) -> () {
142         test_specializations(&v.iter().interleave_shortest(w.iter()));
143     }
144 
145     fn batching(v: Vec<u8>) -> () {
146         test_specializations(&v.iter().batching(Iterator::next));
147     }
148 
149     fn tuple_windows(v: Vec<u8>) -> () {
150         test_specializations(&v.iter().tuple_windows::<(_,)>());
151         test_specializations(&v.iter().tuple_windows::<(_, _)>());
152         test_specializations(&v.iter().tuple_windows::<(_, _, _)>());
153     }
154 
155     fn circular_tuple_windows(v: Vec<u8>) -> () {
156         test_specializations(&v.iter().circular_tuple_windows::<(_,)>());
157         test_specializations(&v.iter().circular_tuple_windows::<(_, _)>());
158         test_specializations(&v.iter().circular_tuple_windows::<(_, _, _)>());
159     }
160 
161     fn tuples(v: Vec<u8>) -> () {
162         test_specializations(&v.iter().tuples::<(_,)>());
163         test_specializations(&v.iter().tuples::<(_, _)>());
164         test_specializations(&v.iter().tuples::<(_, _, _)>());
165     }
166 
167     fn cartesian_product(a: Vec<u8>, b: Vec<u8>) -> TestResult {
168         if a.len() * b.len() > 100 {
169             return TestResult::discard();
170         }
171         test_specializations(&a.iter().cartesian_product(&b));
172         TestResult::passed()
173     }
174 
175     fn multi_cartesian_product(a: Vec<u8>, b: Vec<u8>, c: Vec<u8>) -> TestResult {
176         if a.len() * b.len() * c.len() > 100 {
177             return TestResult::discard();
178         }
179         test_specializations(&vec![a, b, c].into_iter().multi_cartesian_product());
180         TestResult::passed()
181     }
182 
183     fn coalesce(v: Vec<u8>) -> () {
184         test_specializations(&v.iter().coalesce(|x, y| if x == y { Ok(x) } else { Err((x, y)) }))
185     }
186 
187     fn dedup(v: Vec<u8>) -> () {
188         test_specializations(&v.iter().dedup())
189     }
190 
191     fn dedup_by(v: Vec<u8>) -> () {
192         test_specializations(&v.iter().dedup_by(PartialOrd::ge))
193     }
194 
195     fn dedup_with_count(v: Vec<u8>) -> () {
196         test_specializations(&v.iter().dedup_with_count())
197     }
198 
199     fn dedup_by_with_count(v: Vec<u8>) -> () {
200         test_specializations(&v.iter().dedup_by_with_count(PartialOrd::ge))
201     }
202 
203     fn duplicates(v: Vec<u8>) -> () {
204         let it = v.iter().duplicates();
205         test_specializations(&it);
206         test_double_ended_specializations(&it);
207     }
208 
209     fn duplicates_by(v: Vec<u8>) -> () {
210         let it = v.iter().duplicates_by(|x| *x % 10);
211         test_specializations(&it);
212         test_double_ended_specializations(&it);
213     }
214 
215     fn unique(v: Vec<u8>) -> () {
216         let it = v.iter().unique();
217         test_specializations(&it);
218         test_double_ended_specializations(&it);
219     }
220 
221     fn unique_by(v: Vec<u8>) -> () {
222         let it = v.iter().unique_by(|x| *x % 50);
223         test_specializations(&it);
224         test_double_ended_specializations(&it);
225     }
226 
227     fn take_while_inclusive(v: Vec<u8>) -> () {
228         test_specializations(&v.iter().copied().take_while_inclusive(|&x| x < 100));
229     }
230 
231     fn while_some(v: Vec<u8>) -> () {
232         test_specializations(&v.iter().map(|&x| if x < 100 { Some(2 * x) } else { None }).while_some());
233     }
234 
235     fn pad_using(v: Vec<u8>) -> () {
236         use std::convert::TryFrom;
237         let it = v.iter().copied().pad_using(10, |i| u8::try_from(5 * i).unwrap_or(u8::MAX));
238         test_specializations(&it);
239         test_double_ended_specializations(&it);
240     }
241 
242     fn with_position(v: Vec<u8>) -> () {
243         test_specializations(&v.iter().with_position());
244     }
245 
246     fn positions(v: Vec<u8>) -> () {
247         let it = v.iter().positions(|x| x % 5 == 0);
248         test_specializations(&it);
249         test_double_ended_specializations(&it);
250     }
251 
252     fn update(v: Vec<u8>) -> () {
253         let it = v.iter().copied().update(|x| *x = x.wrapping_mul(7));
254         test_specializations(&it);
255         test_double_ended_specializations(&it);
256     }
257 
258     fn tuple_combinations(v: Vec<u8>) -> TestResult {
259         if v.len() > 10 {
260             return TestResult::discard();
261         }
262         test_specializations(&v.iter().tuple_combinations::<(_,)>());
263         test_specializations(&v.iter().tuple_combinations::<(_, _)>());
264         test_specializations(&v.iter().tuple_combinations::<(_, _, _)>());
265         TestResult::passed()
266     }
267 
268     fn intersperse(v: Vec<u8>) -> () {
269         test_specializations(&v.into_iter().intersperse(0));
270     }
271 
272     fn intersperse_with(v: Vec<u8>) -> () {
273         test_specializations(&v.into_iter().intersperse_with(|| 0));
274     }
275 
276     fn array_combinations(v: Vec<u8>) -> TestResult {
277         if v.len() > 10 {
278             return TestResult::discard();
279         }
280         test_specializations(&v.iter().array_combinations::<1>());
281         test_specializations(&v.iter().array_combinations::<2>());
282         test_specializations(&v.iter().array_combinations::<3>());
283         TestResult::passed()
284     }
285 
286     fn combinations(a: Vec<u8>, n: u8) -> TestResult {
287         if n > 3 || a.len() > 8 {
288             return TestResult::discard();
289         }
290         test_specializations(&a.iter().combinations(n as usize));
291         TestResult::passed()
292     }
293 
294     fn combinations_with_replacement(a: Vec<u8>, n: u8) -> TestResult {
295         if n > 3 || a.len() > 7 {
296             return TestResult::discard();
297         }
298         test_specializations(&a.iter().combinations_with_replacement(n as usize));
299         TestResult::passed()
300     }
301 
302     fn permutations(a: Vec<u8>, n: u8) -> TestResult {
303         if n > 3 || a.len() > 8 {
304             return TestResult::discard();
305         }
306         test_specializations(&a.iter().permutations(n as usize));
307         TestResult::passed()
308     }
309 
310     fn powerset(a: Vec<u8>) -> TestResult {
311         if a.len() > 6 {
312             return TestResult::discard();
313         }
314         test_specializations(&a.iter().powerset());
315         TestResult::passed()
316     }
317 
318     fn zip_longest(a: Vec<u8>, b: Vec<u8>) -> () {
319         let it = a.into_iter().zip_longest(b);
320         test_specializations(&it);
321         test_double_ended_specializations(&it);
322     }
323 
324     fn zip_eq(a: Vec<u8>) -> () {
325         test_specializations(&a.iter().zip_eq(a.iter().rev()))
326     }
327 
328     fn multizip(a: Vec<u8>) -> () {
329         let it = itertools::multizip((a.iter(), a.iter().rev(), a.iter().take(50)));
330         test_specializations(&it);
331         test_double_ended_specializations(&it);
332     }
333 
334     fn izip(a: Vec<u8>, b: Vec<u8>) -> () {
335         test_specializations(&itertools::izip!(b.iter(), a, b.iter().rev()));
336     }
337 
338     fn iproduct(a: Vec<u8>, b: Vec<u8>, c: Vec<u8>) -> TestResult {
339         if a.len() * b.len() * c.len() > 200 {
340             return TestResult::discard();
341         }
342         test_specializations(&itertools::iproduct!(a, b.iter(), c));
343         TestResult::passed()
344     }
345 
346     fn repeat_n(element: i8, n: u8) -> () {
347         let it = itertools::repeat_n(element, n as usize);
348         test_specializations(&it);
349         test_double_ended_specializations(&it);
350     }
351 
352     fn exactly_one_error(v: Vec<u8>) -> TestResult {
353         // Use `at_most_one` would be similar.
354         match v.iter().exactly_one() {
355             Ok(_) => TestResult::discard(),
356             Err(it) => {
357                 test_specializations(&it);
358                 TestResult::passed()
359             }
360         }
361     }
362 }
363 
364 quickcheck! {
365     fn put_back_qc(test_vec: Vec<i32>) -> () {
366         test_specializations(&itertools::put_back(test_vec.iter()));
367         let mut pb = itertools::put_back(test_vec.into_iter());
368         pb.put_back(1);
369         test_specializations(&pb);
370     }
371 
372     fn put_back_n(v: Vec<u8>, n: u8) -> () {
373         let mut it = itertools::put_back_n(v);
374         for k in 0..n {
375             it.put_back(k);
376         }
377         test_specializations(&it);
378     }
379 
380     fn multipeek(v: Vec<u8>, n: u8) -> () {
381         let mut it = v.into_iter().multipeek();
382         for _ in 0..n {
383             it.peek();
384         }
385         test_specializations(&it);
386     }
387 
388     fn peek_nth_with_peek(v: Vec<u8>, n: u8) -> () {
389         let mut it = itertools::peek_nth(v);
390         for _ in 0..n {
391             it.peek();
392         }
393         test_specializations(&it);
394     }
395 
396     fn peek_nth_with_peek_nth(v: Vec<u8>, n: u8) -> () {
397         let mut it = itertools::peek_nth(v);
398         it.peek_nth(n as usize);
399         test_specializations(&it);
400     }
401 
402     fn peek_nth_with_peek_mut(v: Vec<u8>, n: u8) -> () {
403         let mut it = itertools::peek_nth(v);
404         for _ in 0..n {
405             if let Some(x) = it.peek_mut() {
406                 *x = x.wrapping_add(50);
407             }
408         }
409         test_specializations(&it);
410     }
411 
412     fn peek_nth_with_peek_nth_mut(v: Vec<u8>, n: u8) -> () {
413         let mut it = itertools::peek_nth(v);
414         if let Some(x) = it.peek_nth_mut(n as usize) {
415             *x = x.wrapping_add(50);
416         }
417         test_specializations(&it);
418     }
419 }
420 
421 quickcheck! {
422     fn merge(a: Vec<u8>, b: Vec<u8>) -> () {
423         test_specializations(&a.into_iter().merge(b))
424     }
425 
426     fn merge_by(a: Vec<u8>, b: Vec<u8>) -> () {
427         test_specializations(&a.into_iter().merge_by(b, PartialOrd::ge))
428     }
429 
430     fn merge_join_by_ordering(i1: Vec<u8>, i2: Vec<u8>) -> () {
431         test_specializations(&i1.into_iter().merge_join_by(i2, Ord::cmp));
432     }
433 
434     fn merge_join_by_bool(i1: Vec<u8>, i2: Vec<u8>) -> () {
435         test_specializations(&i1.into_iter().merge_join_by(i2, PartialOrd::ge));
436     }
437 
438     fn kmerge(a: Vec<i8>, b: Vec<i8>, c: Vec<i8>) -> () {
439         test_specializations(&vec![a, b, c]
440             .into_iter()
441             .map(|v| v.into_iter().sorted())
442             .kmerge());
443     }
444 
445     fn kmerge_by(a: Vec<i8>, b: Vec<i8>, c: Vec<i8>) -> () {
446         test_specializations(&vec![a, b, c]
447             .into_iter()
448             .map(|v| v.into_iter().sorted_by_key(|a| a.abs()))
449             .kmerge_by(|a, b| a.abs() < b.abs()));
450     }
451 }
452 
453 quickcheck! {
454     fn map_into(v: Vec<u8>) -> () {
455         let it = v.into_iter().map_into::<u32>();
456         test_specializations(&it);
457         test_double_ended_specializations(&it);
458     }
459 
460     fn map_ok(v: Vec<Result<u8, char>>) -> () {
461         let it = v.into_iter().map_ok(|u| u.checked_add(1));
462         test_specializations(&it);
463         test_double_ended_specializations(&it);
464     }
465 
466     fn filter_ok(v: Vec<Result<u8, char>>) -> () {
467         let it = v.into_iter().filter_ok(|&i| i < 20);
468         test_specializations(&it);
469         test_double_ended_specializations(&it);
470     }
471 
472     fn filter_map_ok(v: Vec<Result<u8, char>>) -> () {
473         let it = v.into_iter().filter_map_ok(|i| if i < 20 { Some(i * 2) } else { None });
474         test_specializations(&it);
475         test_double_ended_specializations(&it);
476     }
477 
478     // `SmallIter2<u8>` because `Vec<u8>` is too slow and we get bad coverage from a singleton like Option<u8>
479     fn flatten_ok(v: Vec<Result<SmallIter2<u8>, char>>) -> () {
480         let it = v.into_iter().flatten_ok();
481         test_specializations(&it);
482         test_double_ended_specializations(&it);
483     }
484 }
485 
486 quickcheck! {
487     // TODO Replace this function by a normal call to test_specializations
488     fn process_results(v: Vec<Result<u8, u8>>) -> () {
489         helper(v.iter().copied());
490         helper(v.iter().copied().filter(Result::is_ok));
491 
492         fn helper(it: impl DoubleEndedIterator<Item = Result<u8, u8>> + Clone) {
493             macro_rules! check_results_specialized {
494                 ($src:expr, |$it:pat| $closure:expr) => {
495                     assert_eq!(
496                         itertools::process_results($src.clone(), |$it| $closure),
497                         itertools::process_results($src.clone(), |i| {
498                             let $it = Unspecialized(i);
499                             $closure
500                         }),
501                     )
502                 }
503             }
504 
505             check_results_specialized!(it, |i| i.count());
506             check_results_specialized!(it, |i| i.last());
507             check_results_specialized!(it, |i| i.collect::<Vec<_>>());
508             check_results_specialized!(it, |i| i.rev().collect::<Vec<_>>());
509             check_results_specialized!(it, |i| {
510                 let mut parameters_from_fold = vec![];
511                 let fold_result = i.fold(vec![], |mut acc, v| {
512                     parameters_from_fold.push((acc.clone(), v));
513                     acc.push(v);
514                     acc
515                 });
516                 (parameters_from_fold, fold_result)
517             });
518             check_results_specialized!(it, |i| {
519                 let mut parameters_from_rfold = vec![];
520                 let rfold_result = i.rfold(vec![], |mut acc, v| {
521                     parameters_from_rfold.push((acc.clone(), v));
522                     acc.push(v);
523                     acc
524                 });
525                 (parameters_from_rfold, rfold_result)
526             });
527             check_results_specialized!(it, |mut i| {
528                 let mut parameters_from_all = vec![];
529                 let first = i.next();
530                 let all_result = i.all(|x| {
531                     parameters_from_all.push(x);
532                     Some(x)==first
533                 });
534                 (parameters_from_all, all_result)
535             });
536             let size = it.clone().count();
537             for n in 0..size + 2 {
538                 check_results_specialized!(it, |mut i| i.nth(n));
539             }
540             for n in 0..size + 2 {
541                 check_results_specialized!(it, |mut i| i.nth_back(n));
542             }
543         }
544     }
545 }
546 
547 /// Like `VecIntoIter<T>` with maximum 2 elements.
548 #[derive(Debug, Clone, Default)]
549 enum SmallIter2<T> {
550     #[default]
551     Zero,
552     One(T),
553     Two(T, T),
554 }
555 
556 impl<T: Arbitrary> Arbitrary for SmallIter2<T> {
arbitrary<G: quickcheck::Gen>(g: &mut G) -> Self557     fn arbitrary<G: quickcheck::Gen>(g: &mut G) -> Self {
558         match g.gen_range(0u8, 3) {
559             0 => Self::Zero,
560             1 => Self::One(T::arbitrary(g)),
561             2 => Self::Two(T::arbitrary(g), T::arbitrary(g)),
562             _ => unreachable!(),
563         }
564     }
565     // maybe implement shrink too, maybe not
566 }
567 
568 impl<T> Iterator for SmallIter2<T> {
569     type Item = T;
570 
next(&mut self) -> Option<Self::Item>571     fn next(&mut self) -> Option<Self::Item> {
572         match std::mem::take(self) {
573             Self::Zero => None,
574             Self::One(val) => Some(val),
575             Self::Two(val, second) => {
576                 *self = Self::One(second);
577                 Some(val)
578             }
579         }
580     }
581 
size_hint(&self) -> (usize, Option<usize>)582     fn size_hint(&self) -> (usize, Option<usize>) {
583         let len = match self {
584             Self::Zero => 0,
585             Self::One(_) => 1,
586             Self::Two(_, _) => 2,
587         };
588         (len, Some(len))
589     }
590 }
591 
592 impl<T> DoubleEndedIterator for SmallIter2<T> {
next_back(&mut self) -> Option<Self::Item>593     fn next_back(&mut self) -> Option<Self::Item> {
594         match std::mem::take(self) {
595             Self::Zero => None,
596             Self::One(val) => Some(val),
597             Self::Two(first, val) => {
598                 *self = Self::One(first);
599                 Some(val)
600             }
601         }
602     }
603 }
604