blob: 7e222a6410ffa9bb65c143ddc39175402ec583a5 [file] [log] [blame]
Jakub Kotura425e552020-12-21 17:28:15 +01001//! The purpose of these tests is to cover corner cases of iterators
2//! and adaptors.
3//!
4//! In particular we test the tedious size_hint and exact size correctness.
5
6use quickcheck as qc;
7use std::default::Default;
Joel Galenson6f798712021-04-01 17:03:06 -07008use std::num::Wrapping;
Jakub Kotura425e552020-12-21 17:28:15 +01009use std::ops::Range;
10use std::cmp::{max, min, Ordering};
Joel Galenson6f798712021-04-01 17:03:06 -070011use std::collections::{HashMap, HashSet};
Jakub Kotura425e552020-12-21 17:28:15 +010012use itertools::Itertools;
13use itertools::{
14 multizip,
15 EitherOrBoth,
16 iproduct,
17 izip,
18};
19use itertools::free::{
20 cloned,
21 enumerate,
22 multipeek,
Joel Galenson6f798712021-04-01 17:03:06 -070023 peek_nth,
Jakub Kotura425e552020-12-21 17:28:15 +010024 put_back,
25 put_back_n,
26 rciter,
27 zip,
28 zip_eq,
29};
30
31use rand::Rng;
32use rand::seq::SliceRandom;
33use quickcheck::TestResult;
34
35/// Trait for size hint modifier types
36trait HintKind: Copy + Send + qc::Arbitrary {
37 fn loosen_bounds(&self, org_hint: (usize, Option<usize>)) -> (usize, Option<usize>);
38}
39
40/// Exact size hint variant that leaves hints unchanged
41#[derive(Clone, Copy, Debug)]
42struct Exact {}
43
44impl HintKind for Exact {
45 fn loosen_bounds(&self, org_hint: (usize, Option<usize>)) -> (usize, Option<usize>) {
46 org_hint
47 }
48}
49
50impl qc::Arbitrary for Exact {
51 fn arbitrary<G: qc::Gen>(_: &mut G) -> Self {
52 Exact {}
53 }
54}
55
56/// Inexact size hint variant to simulate imprecise (but valid) size hints
57///
58/// Will always decrease the lower bound and increase the upper bound
59/// of the size hint by set amounts.
60#[derive(Clone, Copy, Debug)]
61struct Inexact {
62 underestimate: usize,
63 overestimate: usize,
64}
65
66impl HintKind for Inexact {
67 fn loosen_bounds(&self, org_hint: (usize, Option<usize>)) -> (usize, Option<usize>) {
68 let (org_lower, org_upper) = org_hint;
69 (org_lower.saturating_sub(self.underestimate),
70 org_upper.and_then(move |x| x.checked_add(self.overestimate)))
71 }
72}
73
74impl qc::Arbitrary for Inexact {
75 fn arbitrary<G: qc::Gen>(g: &mut G) -> Self {
76 let ue_value = usize::arbitrary(g);
77 let oe_value = usize::arbitrary(g);
78 // Compensate for quickcheck using extreme values too rarely
79 let ue_choices = &[0, ue_value, usize::max_value()];
80 let oe_choices = &[0, oe_value, usize::max_value()];
81 Inexact {
82 underestimate: *ue_choices.choose(g).unwrap(),
83 overestimate: *oe_choices.choose(g).unwrap(),
84 }
85 }
86
87 fn shrink(&self) -> Box<dyn Iterator<Item=Self>> {
88 let underestimate_value = self.underestimate;
89 let overestimate_value = self.overestimate;
90 Box::new(
91 underestimate_value.shrink().flat_map(move |ue_value|
92 overestimate_value.shrink().map(move |oe_value|
93 Inexact {
94 underestimate: ue_value,
95 overestimate: oe_value,
96 }
97 )
98 )
99 )
100 }
101}
102
103/// Our base iterator that we can impl Arbitrary for
104///
105/// By default we'll return inexact bounds estimates for size_hint
106/// to make tests harder to pass.
107///
108/// NOTE: Iter is tricky and is not fused, to help catch bugs.
109/// At the end it will return None once, then return Some(0),
110/// then return None again.
111#[derive(Clone, Debug)]
112struct Iter<T, SK: HintKind = Inexact> {
113 iterator: Range<T>,
114 // fuse/done flag
115 fuse_flag: i32,
116 hint_kind: SK,
117}
118
119impl<T, HK> Iter<T, HK> where HK: HintKind
120{
121 fn new(it: Range<T>, hint_kind: HK) -> Self {
122 Iter {
123 iterator: it,
124 fuse_flag: 0,
125 hint_kind,
126 }
127 }
128}
129
130impl<T, HK> Iterator for Iter<T, HK>
131 where Range<T>: Iterator,
132 <Range<T> as Iterator>::Item: Default,
133 HK: HintKind,
134{
135 type Item = <Range<T> as Iterator>::Item;
136
137 fn next(&mut self) -> Option<Self::Item>
138 {
139 let elt = self.iterator.next();
140 if elt.is_none() {
141 self.fuse_flag += 1;
142 // check fuse flag
143 if self.fuse_flag == 2 {
144 return Some(Default::default())
145 }
146 }
147 elt
148 }
149
150 fn size_hint(&self) -> (usize, Option<usize>)
151 {
152 let org_hint = self.iterator.size_hint();
153 self.hint_kind.loosen_bounds(org_hint)
154 }
155}
156
157impl<T, HK> DoubleEndedIterator for Iter<T, HK>
158 where Range<T>: DoubleEndedIterator,
159 <Range<T> as Iterator>::Item: Default,
160 HK: HintKind
161{
162 fn next_back(&mut self) -> Option<Self::Item> { self.iterator.next_back() }
163}
164
165impl<T> ExactSizeIterator for Iter<T, Exact> where Range<T>: ExactSizeIterator,
166 <Range<T> as Iterator>::Item: Default,
167{ }
168
169impl<T, HK> qc::Arbitrary for Iter<T, HK>
170 where T: qc::Arbitrary,
171 HK: HintKind,
172{
173 fn arbitrary<G: qc::Gen>(g: &mut G) -> Self
174 {
175 Iter::new(T::arbitrary(g)..T::arbitrary(g), HK::arbitrary(g))
176 }
177
178 fn shrink(&self) -> Box<dyn Iterator<Item=Iter<T, HK>>>
179 {
180 let r = self.iterator.clone();
181 let hint_kind = self.hint_kind;
182 Box::new(
183 r.start.shrink().flat_map(move |a|
184 r.end.shrink().map(move |b|
185 Iter::new(a.clone()..b, hint_kind)
186 )
187 )
188 )
189 }
190}
191
192/// A meta-iterator which yields `Iter<i32>`s whose start/endpoints are
193/// increased or decreased linearly on each iteration.
194#[derive(Clone, Debug)]
195struct ShiftRange<HK = Inexact> {
196 range_start: i32,
197 range_end: i32,
198 start_step: i32,
199 end_step: i32,
200 iter_count: u32,
201 hint_kind: HK,
202}
203
204impl<HK> Iterator for ShiftRange<HK> where HK: HintKind {
205 type Item = Iter<i32, HK>;
206
207 fn next(&mut self) -> Option<Self::Item> {
208 if self.iter_count == 0 {
209 return None;
210 }
211
212 let iter = Iter::new(self.range_start..self.range_end, self.hint_kind);
213
214 self.range_start += self.start_step;
215 self.range_end += self.end_step;
216 self.iter_count -= 1;
217
218 Some(iter)
219 }
220}
221
222impl ExactSizeIterator for ShiftRange<Exact> { }
223
224impl<HK> qc::Arbitrary for ShiftRange<HK>
225 where HK: HintKind
226{
227 fn arbitrary<G: qc::Gen>(g: &mut G) -> Self {
228 const MAX_STARTING_RANGE_DIFF: i32 = 32;
229 const MAX_STEP_MODULO: i32 = 8;
230 const MAX_ITER_COUNT: u32 = 3;
231
232 let range_start = qc::Arbitrary::arbitrary(g);
233 let range_end = range_start + g.gen_range(0, MAX_STARTING_RANGE_DIFF + 1);
234 let start_step = g.gen_range(-MAX_STEP_MODULO, MAX_STEP_MODULO + 1);
235 let end_step = g.gen_range(-MAX_STEP_MODULO, MAX_STEP_MODULO + 1);
236 let iter_count = g.gen_range(0, MAX_ITER_COUNT + 1);
237 let hint_kind = qc::Arbitrary::arbitrary(g);
238
239 ShiftRange {
240 range_start,
241 range_end,
242 start_step,
243 end_step,
244 iter_count,
245 hint_kind,
246 }
247 }
248}
249
250fn correct_count<I, F>(get_it: F) -> bool
251where
252 I: Iterator,
253 F: Fn() -> I
254{
255 let mut counts = vec![get_it().count()];
256
257 'outer: loop {
258 let mut it = get_it();
259
260 for _ in 0..(counts.len() - 1) {
261 if let None = it.next() {
262 panic!("Iterator shouldn't be finished, may not be deterministic");
263 }
264 }
265
266 if let None = it.next() {
267 break 'outer;
268 }
269
270 counts.push(it.count());
271 }
272
273 let total_actual_count = counts.len() - 1;
274
275 for (i, returned_count) in counts.into_iter().enumerate() {
276 let actual_count = total_actual_count - i;
277 if actual_count != returned_count {
278 println!("Total iterations: {} True count: {} returned count: {}", i, actual_count, returned_count);
279
280 return false;
281 }
282 }
283
284 true
285}
286
287fn correct_size_hint<I: Iterator>(mut it: I) -> bool {
288 // record size hint at each iteration
289 let initial_hint = it.size_hint();
290 let mut hints = Vec::with_capacity(initial_hint.0 + 1);
291 hints.push(initial_hint);
292 while let Some(_) = it.next() {
293 hints.push(it.size_hint())
294 }
295
296 let mut true_count = hints.len(); // start off +1 too much
297
298 // check all the size hints
299 for &(low, hi) in &hints {
300 true_count -= 1;
301 if low > true_count ||
302 (hi.is_some() && hi.unwrap() < true_count)
303 {
304 println!("True size: {:?}, size hint: {:?}", true_count, (low, hi));
305 //println!("All hints: {:?}", hints);
306 return false
307 }
308 }
309 true
310}
311
312fn exact_size<I: ExactSizeIterator>(mut it: I) -> bool {
313 // check every iteration
314 let (mut low, mut hi) = it.size_hint();
315 if Some(low) != hi { return false; }
316 while let Some(_) = it.next() {
317 let (xlow, xhi) = it.size_hint();
318 if low != xlow + 1 { return false; }
319 low = xlow;
320 hi = xhi;
321 if Some(low) != hi { return false; }
322 }
323 let (low, hi) = it.size_hint();
324 low == 0 && hi == Some(0)
325}
326
327// Exact size for this case, without ExactSizeIterator
328fn exact_size_for_this<I: Iterator>(mut it: I) -> bool {
329 // check every iteration
330 let (mut low, mut hi) = it.size_hint();
331 if Some(low) != hi { return false; }
332 while let Some(_) = it.next() {
333 let (xlow, xhi) = it.size_hint();
334 if low != xlow + 1 { return false; }
335 low = xlow;
336 hi = xhi;
337 if Some(low) != hi { return false; }
338 }
339 let (low, hi) = it.size_hint();
340 low == 0 && hi == Some(0)
341}
342
343/*
344 * NOTE: Range<i8> is broken!
345 * (all signed ranges are)
346#[quickcheck]
347fn size_range_i8(a: Iter<i8>) -> bool {
348 exact_size(a)
349}
350
351#[quickcheck]
352fn size_range_i16(a: Iter<i16>) -> bool {
353 exact_size(a)
354}
355
356#[quickcheck]
357fn size_range_u8(a: Iter<u8>) -> bool {
358 exact_size(a)
359}
360 */
361
362macro_rules! quickcheck {
363 // accept several property function definitions
364 // The property functions can use pattern matching and `mut` as usual
365 // in the function arguments, but the functions can not be generic.
366 {$($(#$attr:tt)* fn $fn_name:ident($($arg:tt)*) -> $ret:ty { $($code:tt)* })*} => (
367 $(
368 #[test]
369 $(#$attr)*
370 fn $fn_name() {
371 fn prop($($arg)*) -> $ret {
372 $($code)*
373 }
374 ::quickcheck::quickcheck(quickcheck!(@fn prop [] $($arg)*));
375 }
376 )*
377 );
378 // parse argument list (with patterns allowed) into prop as fn(_, _) -> _
379 (@fn $f:ident [$($t:tt)*]) => {
380 $f as fn($($t),*) -> _
381 };
382 (@fn $f:ident [$($p:tt)*] : $($tail:tt)*) => {
383 quickcheck!(@fn $f [$($p)* _] $($tail)*)
384 };
385 (@fn $f:ident [$($p:tt)*] $t:tt $($tail:tt)*) => {
386 quickcheck!(@fn $f [$($p)*] $($tail)*)
387 };
388}
389
390quickcheck! {
391
392 fn size_product(a: Iter<u16>, b: Iter<u16>) -> bool {
393 correct_size_hint(a.cartesian_product(b))
394 }
395 fn size_product3(a: Iter<u16>, b: Iter<u16>, c: Iter<u16>) -> bool {
396 correct_size_hint(iproduct!(a, b, c))
397 }
398
399 fn correct_cartesian_product3(a: Iter<u16>, b: Iter<u16>, c: Iter<u16>,
400 take_manual: usize) -> ()
401 {
402 // test correctness of iproduct through regular iteration (take)
403 // and through fold.
404 let ac = a.clone();
405 let br = &b.clone();
406 let cr = &c.clone();
407 let answer: Vec<_> = ac.flat_map(move |ea| br.clone().flat_map(move |eb| cr.clone().map(move |ec| (ea, eb, ec)))).collect();
408 let mut product_iter = iproduct!(a, b, c);
409 let mut actual = Vec::new();
410
411 actual.extend((&mut product_iter).take(take_manual));
412 if actual.len() == take_manual {
413 product_iter.fold((), |(), elt| actual.push(elt));
414 }
415 assert_eq!(answer, actual);
416 }
417
418 fn size_multi_product(a: ShiftRange) -> bool {
419 correct_size_hint(a.multi_cartesian_product())
420 }
421 fn correct_multi_product3(a: ShiftRange, take_manual: usize) -> () {
422 // Fix no. of iterators at 3
423 let a = ShiftRange { iter_count: 3, ..a };
424
425 // test correctness of MultiProduct through regular iteration (take)
426 // and through fold.
427 let mut iters = a.clone();
428 let i0 = iters.next().unwrap();
429 let i1r = &iters.next().unwrap();
430 let i2r = &iters.next().unwrap();
431 let answer: Vec<_> = i0.flat_map(move |ei0| i1r.clone().flat_map(move |ei1| i2r.clone().map(move |ei2| vec![ei0, ei1, ei2]))).collect();
432 let mut multi_product = a.clone().multi_cartesian_product();
433 let mut actual = Vec::new();
434
435 actual.extend((&mut multi_product).take(take_manual));
436 if actual.len() == take_manual {
437 multi_product.fold((), |(), elt| actual.push(elt));
438 }
439 assert_eq!(answer, actual);
440
441 assert_eq!(answer.into_iter().last(), a.clone().multi_cartesian_product().last());
442 }
443
444 #[allow(deprecated)]
445 fn size_step(a: Iter<i16, Exact>, s: usize) -> bool {
446 let mut s = s;
447 if s == 0 {
448 s += 1; // never zero
449 }
450 let filt = a.clone().dedup();
451 correct_size_hint(filt.step(s)) &&
452 exact_size(a.step(s))
453 }
454
455 #[allow(deprecated)]
456 fn equal_step(a: Iter<i16>, s: usize) -> bool {
457 let mut s = s;
458 if s == 0 {
459 s += 1; // never zero
460 }
461 let mut i = 0;
462 itertools::equal(a.clone().step(s), a.filter(|_| {
463 let keep = i % s == 0;
464 i += 1;
465 keep
466 }))
467 }
468
469 #[allow(deprecated)]
470 fn equal_step_vec(a: Vec<i16>, s: usize) -> bool {
471 let mut s = s;
472 if s == 0 {
473 s += 1; // never zero
474 }
475 let mut i = 0;
476 itertools::equal(a.iter().step(s), a.iter().filter(|_| {
477 let keep = i % s == 0;
478 i += 1;
479 keep
480 }))
481 }
482
483 fn size_multipeek(a: Iter<u16, Exact>, s: u8) -> bool {
484 let mut it = multipeek(a);
485 // peek a few times
486 for _ in 0..s {
487 it.peek();
488 }
489 exact_size(it)
490 }
491
Joel Galenson6f798712021-04-01 17:03:06 -0700492 fn size_peek_nth(a: Iter<u16, Exact>, s: u8) -> bool {
493 let mut it = peek_nth(a);
494 // peek a few times
495 for n in 0..s {
496 it.peek_nth(n as usize);
497 }
498 exact_size(it)
499 }
500
Jakub Kotura425e552020-12-21 17:28:15 +0100501 fn equal_merge(a: Vec<i16>, b: Vec<i16>) -> bool {
502 let mut sa = a.clone();
503 let mut sb = b.clone();
504 sa.sort();
505 sb.sort();
506 let mut merged = sa.clone();
507 merged.extend(sb.iter().cloned());
508 merged.sort();
509 itertools::equal(&merged, sa.iter().merge(&sb))
510 }
511 fn size_merge(a: Iter<u16>, b: Iter<u16>) -> bool {
512 correct_size_hint(a.merge(b))
513 }
514 fn size_zip(a: Iter<i16, Exact>, b: Iter<i16, Exact>, c: Iter<i16, Exact>) -> bool {
515 let filt = a.clone().dedup();
516 correct_size_hint(multizip((filt, b.clone(), c.clone()))) &&
517 exact_size(multizip((a, b, c)))
518 }
519 fn size_zip_rc(a: Iter<i16>, b: Iter<i16>) -> bool {
520 let rc = rciter(a.clone());
521 correct_size_hint(multizip((&rc, &rc, b)))
522 }
523
524 fn size_zip_macro(a: Iter<i16, Exact>, b: Iter<i16, Exact>, c: Iter<i16, Exact>) -> bool {
525 let filt = a.clone().dedup();
526 correct_size_hint(izip!(filt, b.clone(), c.clone())) &&
527 exact_size(izip!(a, b, c))
528 }
529 fn equal_kmerge(a: Vec<i16>, b: Vec<i16>, c: Vec<i16>) -> bool {
530 use itertools::free::kmerge;
531 let mut sa = a.clone();
532 let mut sb = b.clone();
533 let mut sc = c.clone();
534 sa.sort();
535 sb.sort();
536 sc.sort();
537 let mut merged = sa.clone();
538 merged.extend(sb.iter().cloned());
539 merged.extend(sc.iter().cloned());
540 merged.sort();
541 itertools::equal(merged.into_iter(), kmerge(vec![sa, sb, sc]))
542 }
543
544 // Any number of input iterators
545 fn equal_kmerge_2(mut inputs: Vec<Vec<i16>>) -> bool {
546 use itertools::free::kmerge;
547 // sort the inputs
548 for input in &mut inputs {
549 input.sort();
550 }
551 let mut merged = inputs.concat();
552 merged.sort();
553 itertools::equal(merged.into_iter(), kmerge(inputs))
554 }
555
556 // Any number of input iterators
557 fn equal_kmerge_by_ge(mut inputs: Vec<Vec<i16>>) -> bool {
558 // sort the inputs
559 for input in &mut inputs {
560 input.sort();
561 input.reverse();
562 }
563 let mut merged = inputs.concat();
564 merged.sort();
565 merged.reverse();
566 itertools::equal(merged.into_iter(),
567 inputs.into_iter().kmerge_by(|x, y| x >= y))
568 }
569
570 // Any number of input iterators
571 fn equal_kmerge_by_lt(mut inputs: Vec<Vec<i16>>) -> bool {
572 // sort the inputs
573 for input in &mut inputs {
574 input.sort();
575 }
576 let mut merged = inputs.concat();
577 merged.sort();
578 itertools::equal(merged.into_iter(),
579 inputs.into_iter().kmerge_by(|x, y| x < y))
580 }
581
582 // Any number of input iterators
583 fn equal_kmerge_by_le(mut inputs: Vec<Vec<i16>>) -> bool {
584 // sort the inputs
585 for input in &mut inputs {
586 input.sort();
587 }
588 let mut merged = inputs.concat();
589 merged.sort();
590 itertools::equal(merged.into_iter(),
591 inputs.into_iter().kmerge_by(|x, y| x <= y))
592 }
593 fn size_kmerge(a: Iter<i16>, b: Iter<i16>, c: Iter<i16>) -> bool {
594 use itertools::free::kmerge;
595 correct_size_hint(kmerge(vec![a, b, c]))
596 }
597 fn equal_zip_eq(a: Vec<i32>, b: Vec<i32>) -> bool {
598 let len = std::cmp::min(a.len(), b.len());
599 let a = &a[..len];
600 let b = &b[..len];
601 itertools::equal(zip_eq(a, b), zip(a, b))
602 }
603 fn size_zip_longest(a: Iter<i16, Exact>, b: Iter<i16, Exact>) -> bool {
604 let filt = a.clone().dedup();
605 let filt2 = b.clone().dedup();
606 correct_size_hint(filt.zip_longest(b.clone())) &&
607 correct_size_hint(a.clone().zip_longest(filt2)) &&
608 exact_size(a.zip_longest(b))
609 }
610 fn size_2_zip_longest(a: Iter<i16>, b: Iter<i16>) -> bool {
611 let it = a.clone().zip_longest(b.clone());
612 let jt = a.clone().zip_longest(b.clone());
613 itertools::equal(a.clone(),
614 it.filter_map(|elt| match elt {
615 EitherOrBoth::Both(x, _) => Some(x),
616 EitherOrBoth::Left(x) => Some(x),
617 _ => None,
618 }
619 ))
620 &&
621 itertools::equal(b.clone(),
622 jt.filter_map(|elt| match elt {
623 EitherOrBoth::Both(_, y) => Some(y),
624 EitherOrBoth::Right(y) => Some(y),
625 _ => None,
626 }
627 ))
628 }
629 fn size_interleave(a: Iter<i16>, b: Iter<i16>) -> bool {
630 correct_size_hint(a.interleave(b))
631 }
632 fn exact_interleave(a: Iter<i16, Exact>, b: Iter<i16, Exact>) -> bool {
633 exact_size_for_this(a.interleave(b))
634 }
635 fn size_interleave_shortest(a: Iter<i16>, b: Iter<i16>) -> bool {
636 correct_size_hint(a.interleave_shortest(b))
637 }
638 fn exact_interleave_shortest(a: Vec<()>, b: Vec<()>) -> bool {
639 exact_size_for_this(a.iter().interleave_shortest(&b))
640 }
641 fn size_intersperse(a: Iter<i16>, x: i16) -> bool {
642 correct_size_hint(a.intersperse(x))
643 }
644 fn equal_intersperse(a: Vec<i32>, x: i32) -> bool {
645 let mut inter = false;
646 let mut i = 0;
647 for elt in a.iter().cloned().intersperse(x) {
648 if inter {
649 if elt != x { return false }
650 } else {
651 if elt != a[i] { return false }
652 i += 1;
653 }
654 inter = !inter;
655 }
656 true
657 }
658
659 fn equal_combinations_2(a: Vec<u8>) -> bool {
660 let mut v = Vec::new();
661 for (i, x) in enumerate(&a) {
662 for y in &a[i + 1..] {
663 v.push((x, y));
664 }
665 }
666 itertools::equal(a.iter().tuple_combinations::<(_, _)>(), v)
667 }
668
669 fn collect_tuple_matches_size(a: Iter<i16>) -> bool {
670 let size = a.clone().count();
671 a.collect_tuple::<(_, _, _)>().is_some() == (size == 3)
672 }
673
674 fn correct_permutations(vals: HashSet<i32>, k: usize) -> () {
675 // Test permutations only on iterators of distinct integers, to prevent
676 // false positives.
677
678 const MAX_N: usize = 5;
679
680 let n = min(vals.len(), MAX_N);
681 let vals: HashSet<i32> = vals.into_iter().take(n).collect();
682
683 let perms = vals.iter().permutations(k);
684
685 let mut actual = HashSet::new();
686
687 for perm in perms {
688 assert_eq!(perm.len(), k);
689
690 let all_items_valid = perm.iter().all(|p| vals.contains(p));
691 assert!(all_items_valid, "perm contains value not from input: {:?}", perm);
692
693 // Check that all perm items are distinct
694 let distinct_len = {
695 let perm_set: HashSet<_> = perm.iter().collect();
696 perm_set.len()
697 };
698 assert_eq!(perm.len(), distinct_len);
699
700 // Check that the perm is new
701 assert!(actual.insert(perm.clone()), "perm already encountered: {:?}", perm);
702 }
703 }
704
705 fn permutations_lexic_order(a: usize, b: usize) -> () {
706 let a = a % 6;
707 let b = b % 6;
708
709 let n = max(a, b);
710 let k = min (a, b);
711
712 let expected_first: Vec<usize> = (0..k).collect();
713 let expected_last: Vec<usize> = ((n - k)..n).rev().collect();
714
715 let mut perms = (0..n).permutations(k);
716
717 let mut curr_perm = match perms.next() {
718 Some(p) => p,
719 None => { return; }
720 };
721
722 assert_eq!(expected_first, curr_perm);
723
724 while let Some(next_perm) = perms.next() {
725 assert!(
726 next_perm > curr_perm,
727 "next perm isn't greater-than current; next_perm={:?} curr_perm={:?} n={}",
728 next_perm, curr_perm, n
729 );
730
731 curr_perm = next_perm;
732 }
733
734 assert_eq!(expected_last, curr_perm);
735
736 }
737
738 fn permutations_count(n: usize, k: usize) -> bool {
739 let n = n % 6;
740
741 correct_count(|| (0..n).permutations(k))
742 }
743
744 fn permutations_size(a: Iter<i32>, k: usize) -> bool {
745 correct_size_hint(a.take(5).permutations(k))
746 }
747
748 fn permutations_k0_yields_once(n: usize) -> () {
749 let k = 0;
750 let expected: Vec<Vec<usize>> = vec![vec![]];
751 let actual = (0..n).permutations(k).collect_vec();
752
753 assert_eq!(expected, actual);
754 }
755}
756
757quickcheck! {
Joel Galenson6f798712021-04-01 17:03:06 -0700758 fn dedup_via_coalesce(a: Vec<i32>) -> bool {
759 let mut b = a.clone();
760 b.dedup();
761 itertools::equal(
762 &b,
763 a
764 .iter()
765 .coalesce(|x, y| {
766 if x==y {
767 Ok(x)
768 } else {
769 Err((x, y))
770 }
771 })
772 .fold(vec![], |mut v, n| {
773 v.push(n);
774 v
775 })
776 )
777 }
778}
779
780quickcheck! {
Jakub Kotura425e552020-12-21 17:28:15 +0100781 fn equal_dedup(a: Vec<i32>) -> bool {
782 let mut b = a.clone();
783 b.dedup();
784 itertools::equal(&b, a.iter().dedup())
785 }
786}
787
788quickcheck! {
789 fn equal_dedup_by(a: Vec<(i32, i32)>) -> bool {
790 let mut b = a.clone();
791 b.dedup_by(|x, y| x.0==y.0);
792 itertools::equal(&b, a.iter().dedup_by(|x, y| x.0==y.0))
793 }
794}
795
796quickcheck! {
797 fn size_dedup(a: Vec<i32>) -> bool {
798 correct_size_hint(a.iter().dedup())
799 }
800}
801
802quickcheck! {
803 fn size_dedup_by(a: Vec<(i32, i32)>) -> bool {
804 correct_size_hint(a.iter().dedup_by(|x, y| x.0==y.0))
805 }
806}
807
808quickcheck! {
809 fn exact_repeatn((n, x): (usize, i32)) -> bool {
810 let it = itertools::repeat_n(x, n);
811 exact_size(it)
812 }
813}
814
815quickcheck! {
816 fn size_put_back(a: Vec<u8>, x: Option<u8>) -> bool {
817 let mut it = put_back(a.into_iter());
818 match x {
819 Some(t) => it.put_back(t),
820 None => {}
821 }
822 correct_size_hint(it)
823 }
824}
825
826quickcheck! {
827 fn size_put_backn(a: Vec<u8>, b: Vec<u8>) -> bool {
828 let mut it = put_back_n(a.into_iter());
829 for elt in b {
830 it.put_back(elt)
831 }
832 correct_size_hint(it)
833 }
834}
835
836quickcheck! {
837 fn size_tee(a: Vec<u8>) -> bool {
838 let (mut t1, mut t2) = a.iter().tee();
839 t1.next();
840 t1.next();
841 t2.next();
842 exact_size(t1) && exact_size(t2)
843 }
844}
845
846quickcheck! {
847 fn size_tee_2(a: Vec<u8>) -> bool {
848 let (mut t1, mut t2) = a.iter().dedup().tee();
849 t1.next();
850 t1.next();
851 t2.next();
852 correct_size_hint(t1) && correct_size_hint(t2)
853 }
854}
855
856quickcheck! {
857 fn size_take_while_ref(a: Vec<u8>, stop: u8) -> bool {
858 correct_size_hint(a.iter().take_while_ref(|x| **x != stop))
859 }
860}
861
862quickcheck! {
863 fn equal_partition(a: Vec<i32>) -> bool {
864 let mut a = a;
865 let mut ap = a.clone();
866 let split_index = itertools::partition(&mut ap, |x| *x >= 0);
867 let parted = (0..split_index).all(|i| ap[i] >= 0) &&
868 (split_index..a.len()).all(|i| ap[i] < 0);
869
870 a.sort();
871 ap.sort();
872 parted && (a == ap)
873 }
874}
875
876quickcheck! {
877 fn size_combinations(it: Iter<i16>) -> bool {
878 correct_size_hint(it.tuple_combinations::<(_, _)>())
879 }
880}
881
882quickcheck! {
883 fn equal_combinations(it: Iter<i16>) -> bool {
884 let values = it.clone().collect_vec();
885 let mut cmb = it.tuple_combinations();
886 for i in 0..values.len() {
887 for j in i+1..values.len() {
888 let pair = (values[i], values[j]);
889 if pair != cmb.next().unwrap() {
890 return false;
891 }
892 }
893 }
894 cmb.next() == None
895 }
896}
897
898quickcheck! {
899 fn size_pad_tail(it: Iter<i8>, pad: u8) -> bool {
900 correct_size_hint(it.clone().pad_using(pad as usize, |_| 0)) &&
901 correct_size_hint(it.dropping(1).rev().pad_using(pad as usize, |_| 0))
902 }
903}
904
905quickcheck! {
906 fn size_pad_tail2(it: Iter<i8, Exact>, pad: u8) -> bool {
907 exact_size(it.pad_using(pad as usize, |_| 0))
908 }
909}
910
911quickcheck! {
Joel Galenson6f798712021-04-01 17:03:06 -0700912 fn size_powerset(it: Iter<u8, Exact>) -> bool {
913 // Powerset cardinality gets large very quickly, limit input to keep test fast.
914 correct_size_hint(it.take(12).powerset())
915 }
916}
917
918quickcheck! {
Joel Galensonb593e252021-06-21 13:15:57 -0700919 fn size_duplicates(it: Iter<i8>) -> bool {
920 correct_size_hint(it.duplicates())
921 }
922}
923
924quickcheck! {
Jakub Kotura425e552020-12-21 17:28:15 +0100925 fn size_unique(it: Iter<i8>) -> bool {
926 correct_size_hint(it.unique())
927 }
928
929 fn count_unique(it: Vec<i8>, take_first: u8) -> () {
930 let answer = {
931 let mut v = it.clone();
932 v.sort(); v.dedup();
933 v.len()
934 };
935 let mut iter = cloned(&it).unique();
936 let first_count = (&mut iter).take(take_first as usize).count();
937 let rest_count = iter.count();
938 assert_eq!(answer, first_count + rest_count);
939 }
940}
941
942quickcheck! {
943 fn fuzz_group_by_lazy_1(it: Iter<u8>) -> bool {
944 let jt = it.clone();
945 let groups = it.group_by(|k| *k);
946 let res = itertools::equal(jt, groups.into_iter().flat_map(|(_, x)| x));
947 res
948 }
949}
950
951quickcheck! {
952 fn fuzz_group_by_lazy_2(data: Vec<u8>) -> bool {
953 let groups = data.iter().group_by(|k| *k / 10);
954 let res = itertools::equal(data.iter(), groups.into_iter().flat_map(|(_, x)| x));
955 res
956 }
957}
958
959quickcheck! {
960 fn fuzz_group_by_lazy_3(data: Vec<u8>) -> bool {
961 let grouper = data.iter().group_by(|k| *k / 10);
962 let groups = grouper.into_iter().collect_vec();
963 let res = itertools::equal(data.iter(), groups.into_iter().flat_map(|(_, x)| x));
964 res
965 }
966}
967
968quickcheck! {
969 fn fuzz_group_by_lazy_duo(data: Vec<u8>, order: Vec<(bool, bool)>) -> bool {
970 let grouper = data.iter().group_by(|k| *k / 3);
971 let mut groups1 = grouper.into_iter();
972 let mut groups2 = grouper.into_iter();
973 let mut elts = Vec::<&u8>::new();
974 let mut old_groups = Vec::new();
975
976 let tup1 = |(_, b)| b;
977 for &(ord, consume_now) in &order {
978 let iter = &mut [&mut groups1, &mut groups2][ord as usize];
979 match iter.next() {
980 Some((_, gr)) => if consume_now {
981 for og in old_groups.drain(..) {
982 elts.extend(og);
983 }
984 elts.extend(gr);
985 } else {
986 old_groups.push(gr);
987 },
988 None => break,
989 }
990 }
991 for og in old_groups.drain(..) {
992 elts.extend(og);
993 }
994 for gr in groups1.map(&tup1) { elts.extend(gr); }
995 for gr in groups2.map(&tup1) { elts.extend(gr); }
996 itertools::assert_equal(&data, elts);
997 true
998 }
999}
1000
1001quickcheck! {
1002 fn equal_chunks_lazy(a: Vec<u8>, size: u8) -> bool {
1003 let mut size = size;
1004 if size == 0 {
1005 size += 1;
1006 }
1007 let chunks = a.iter().chunks(size as usize);
1008 let it = a.chunks(size as usize);
1009 for (a, b) in chunks.into_iter().zip(it) {
1010 if !itertools::equal(a, b) {
1011 return false;
1012 }
1013 }
1014 true
1015 }
1016}
1017
1018quickcheck! {
1019 fn equal_tuple_windows_1(a: Vec<u8>) -> bool {
1020 let x = a.windows(1).map(|s| (&s[0], ));
1021 let y = a.iter().tuple_windows::<(_,)>();
1022 itertools::equal(x, y)
1023 }
1024
1025 fn equal_tuple_windows_2(a: Vec<u8>) -> bool {
1026 let x = a.windows(2).map(|s| (&s[0], &s[1]));
1027 let y = a.iter().tuple_windows::<(_, _)>();
1028 itertools::equal(x, y)
1029 }
1030
1031 fn equal_tuple_windows_3(a: Vec<u8>) -> bool {
1032 let x = a.windows(3).map(|s| (&s[0], &s[1], &s[2]));
1033 let y = a.iter().tuple_windows::<(_, _, _)>();
1034 itertools::equal(x, y)
1035 }
1036
1037 fn equal_tuple_windows_4(a: Vec<u8>) -> bool {
1038 let x = a.windows(4).map(|s| (&s[0], &s[1], &s[2], &s[3]));
1039 let y = a.iter().tuple_windows::<(_, _, _, _)>();
1040 itertools::equal(x, y)
1041 }
1042
1043 fn equal_tuples_1(a: Vec<u8>) -> bool {
1044 let x = a.chunks(1).map(|s| (&s[0], ));
1045 let y = a.iter().tuples::<(_,)>();
1046 itertools::equal(x, y)
1047 }
1048
1049 fn equal_tuples_2(a: Vec<u8>) -> bool {
1050 let x = a.chunks(2).filter(|s| s.len() == 2).map(|s| (&s[0], &s[1]));
1051 let y = a.iter().tuples::<(_, _)>();
1052 itertools::equal(x, y)
1053 }
1054
1055 fn equal_tuples_3(a: Vec<u8>) -> bool {
1056 let x = a.chunks(3).filter(|s| s.len() == 3).map(|s| (&s[0], &s[1], &s[2]));
1057 let y = a.iter().tuples::<(_, _, _)>();
1058 itertools::equal(x, y)
1059 }
1060
1061 fn equal_tuples_4(a: Vec<u8>) -> bool {
1062 let x = a.chunks(4).filter(|s| s.len() == 4).map(|s| (&s[0], &s[1], &s[2], &s[3]));
1063 let y = a.iter().tuples::<(_, _, _, _)>();
1064 itertools::equal(x, y)
1065 }
1066
1067 fn exact_tuple_buffer(a: Vec<u8>) -> bool {
1068 let mut iter = a.iter().tuples::<(_, _, _, _)>();
1069 (&mut iter).last();
1070 let buffer = iter.into_buffer();
1071 assert_eq!(buffer.len(), a.len() % 4);
1072 exact_size(buffer)
1073 }
1074}
1075
1076// with_position
1077quickcheck! {
1078 fn with_position_exact_size_1(a: Vec<u8>) -> bool {
1079 exact_size_for_this(a.iter().with_position())
1080 }
1081 fn with_position_exact_size_2(a: Iter<u8, Exact>) -> bool {
1082 exact_size_for_this(a.with_position())
1083 }
1084}
1085
1086quickcheck! {
1087 fn correct_group_map_modulo_key(a: Vec<u8>, modulo: u8) -> () {
1088 let modulo = if modulo == 0 { 1 } else { modulo }; // Avoid `% 0`
1089 let count = a.len();
1090 let lookup = a.into_iter().map(|i| (i % modulo, i)).into_group_map();
1091
1092 assert_eq!(lookup.values().flat_map(|vals| vals.iter()).count(), count);
1093
1094 for (&key, vals) in lookup.iter() {
1095 assert!(vals.iter().all(|&val| val % modulo == key));
1096 }
1097 }
1098}
1099
1100/// A peculiar type: Equality compares both tuple items, but ordering only the
1101/// first item. This is so we can check the stability property easily.
1102#[derive(Clone, Debug, PartialEq, Eq)]
1103struct Val(u32, u32);
1104
1105impl PartialOrd<Val> for Val {
1106 fn partial_cmp(&self, other: &Val) -> Option<Ordering> {
1107 self.0.partial_cmp(&other.0)
1108 }
1109}
1110
1111impl Ord for Val {
1112 fn cmp(&self, other: &Val) -> Ordering {
1113 self.0.cmp(&other.0)
1114 }
1115}
1116
1117impl qc::Arbitrary for Val {
1118 fn arbitrary<G: qc::Gen>(g: &mut G) -> Self {
1119 let (x, y) = <(u32, u32)>::arbitrary(g);
1120 Val(x, y)
1121 }
1122 fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
1123 Box::new((self.0, self.1).shrink().map(|(x, y)| Val(x, y)))
1124 }
1125}
1126
1127quickcheck! {
1128 fn minmax(a: Vec<Val>) -> bool {
1129 use itertools::MinMaxResult;
1130
1131
1132 let minmax = a.iter().minmax();
1133 let expected = match a.len() {
1134 0 => MinMaxResult::NoElements,
1135 1 => MinMaxResult::OneElement(&a[0]),
1136 _ => MinMaxResult::MinMax(a.iter().min().unwrap(),
1137 a.iter().max().unwrap()),
1138 };
1139 minmax == expected
1140 }
1141}
1142
1143quickcheck! {
1144 fn minmax_f64(a: Vec<f64>) -> TestResult {
1145 use itertools::MinMaxResult;
1146
1147 if a.iter().any(|x| x.is_nan()) {
1148 return TestResult::discard();
1149 }
1150
1151 let min = cloned(&a).fold1(f64::min);
1152 let max = cloned(&a).fold1(f64::max);
1153
1154 let minmax = cloned(&a).minmax();
1155 let expected = match a.len() {
1156 0 => MinMaxResult::NoElements,
1157 1 => MinMaxResult::OneElement(min.unwrap()),
1158 _ => MinMaxResult::MinMax(min.unwrap(), max.unwrap()),
1159 };
1160 TestResult::from_bool(minmax == expected)
1161 }
1162}
1163
1164quickcheck! {
1165 #[allow(deprecated)]
1166 fn tree_fold1_f64(mut a: Vec<f64>) -> TestResult {
1167 fn collapse_adjacent<F>(x: Vec<f64>, mut f: F) -> Vec<f64>
1168 where F: FnMut(f64, f64) -> f64
1169 {
1170 let mut out = Vec::new();
1171 for i in (0..x.len()).step(2) {
1172 if i == x.len()-1 {
1173 out.push(x[i])
1174 } else {
1175 out.push(f(x[i], x[i+1]));
1176 }
1177 }
1178 out
1179 }
1180
1181 if a.iter().any(|x| x.is_nan()) {
1182 return TestResult::discard();
1183 }
1184
1185 let actual = a.iter().cloned().tree_fold1(f64::atan2);
1186
1187 while a.len() > 1 {
1188 a = collapse_adjacent(a, f64::atan2);
1189 }
1190 let expected = a.pop();
1191
1192 TestResult::from_bool(actual == expected)
1193 }
1194}
1195
1196quickcheck! {
1197 fn exactly_one_i32(a: Vec<i32>) -> TestResult {
1198 let ret = a.iter().cloned().exactly_one();
1199 match a.len() {
1200 1 => TestResult::from_bool(ret.unwrap() == a[0]),
1201 _ => TestResult::from_bool(ret.unwrap_err().eq(a.iter().cloned())),
1202 }
1203 }
1204}
Joel Galenson6f798712021-04-01 17:03:06 -07001205
1206quickcheck! {
Joel Galensonb593e252021-06-21 13:15:57 -07001207 fn at_most_one_i32(a: Vec<i32>) -> TestResult {
1208 let ret = a.iter().cloned().at_most_one();
1209 match a.len() {
1210 0 => TestResult::from_bool(ret.unwrap() == None),
1211 1 => TestResult::from_bool(ret.unwrap() == Some(a[0])),
1212 _ => TestResult::from_bool(ret.unwrap_err().eq(a.iter().cloned())),
1213 }
1214 }
1215}
1216
1217quickcheck! {
Joel Galenson6f798712021-04-01 17:03:06 -07001218 fn consistent_grouping_map_with_by(a: Vec<u8>, modulo: u8) -> () {
1219 let modulo = if modulo == 0 { 1 } else { modulo }; // Avoid `% 0`
1220
1221 let lookup_grouping_map = a.iter().copied().map(|i| (i % modulo, i)).into_grouping_map().collect::<Vec<_>>();
1222 let lookup_grouping_map_by = a.iter().copied().into_grouping_map_by(|i| i % modulo).collect::<Vec<_>>();
1223
1224 assert_eq!(lookup_grouping_map, lookup_grouping_map_by);
1225 }
1226
1227 fn correct_grouping_map_by_aggregate_modulo_key(a: Vec<u8>, modulo: u8) -> () {
1228 let modulo = if modulo < 2 { 2 } else { modulo } as u64; // Avoid `% 0`
1229 let lookup = a.iter()
1230 .map(|&b| b as u64) // Avoid overflows
1231 .into_grouping_map_by(|i| i % modulo)
1232 .aggregate(|acc, &key, val| {
1233 assert!(val % modulo == key);
1234 if val % (modulo - 1) == 0 {
1235 None
1236 } else {
1237 Some(acc.unwrap_or(0) + val)
1238 }
1239 });
1240
1241 let group_map_lookup = a.iter()
1242 .map(|&b| b as u64)
1243 .map(|i| (i % modulo, i))
1244 .into_group_map()
1245 .into_iter()
1246 .filter_map(|(key, vals)| {
1247 vals.into_iter().fold(None, |acc, val| {
1248 if val % (modulo - 1) == 0 {
1249 None
1250 } else {
1251 Some(acc.unwrap_or(0) + val)
1252 }
1253 }).map(|new_val| (key, new_val))
1254 })
1255 .collect::<HashMap<_,_>>();
1256 assert_eq!(lookup, group_map_lookup);
1257
1258 for m in 0..modulo {
1259 assert_eq!(
1260 lookup.get(&m).copied(),
1261 a.iter()
1262 .map(|&b| b as u64)
1263 .filter(|&val| val % modulo == m)
1264 .fold(None, |acc, val| {
1265 if val % (modulo - 1) == 0 {
1266 None
1267 } else {
1268 Some(acc.unwrap_or(0) + val)
1269 }
1270 })
1271 );
1272 }
1273 }
1274
1275 fn correct_grouping_map_by_fold_modulo_key(a: Vec<u8>, modulo: u8) -> () {
1276 let modulo = if modulo == 0 { 1 } else { modulo } as u64; // Avoid `% 0`
1277 let lookup = a.iter().map(|&b| b as u64) // Avoid overflows
1278 .into_grouping_map_by(|i| i % modulo)
1279 .fold(0u64, |acc, &key, val| {
1280 assert!(val % modulo == key);
1281 acc + val
1282 });
1283
1284 let group_map_lookup = a.iter()
1285 .map(|&b| b as u64)
1286 .map(|i| (i % modulo, i))
1287 .into_group_map()
1288 .into_iter()
1289 .map(|(key, vals)| (key, vals.into_iter().fold(0u64, |acc, val| acc + val)))
1290 .collect::<HashMap<_,_>>();
1291 assert_eq!(lookup, group_map_lookup);
1292
1293 for (&key, &sum) in lookup.iter() {
1294 assert_eq!(sum, a.iter().map(|&b| b as u64).filter(|&val| val % modulo == key).sum::<u64>());
1295 }
1296 }
1297
1298 fn correct_grouping_map_by_fold_first_modulo_key(a: Vec<u8>, modulo: u8) -> () {
1299 let modulo = if modulo == 0 { 1 } else { modulo } as u64; // Avoid `% 0`
1300 let lookup = a.iter().map(|&b| b as u64) // Avoid overflows
1301 .into_grouping_map_by(|i| i % modulo)
1302 .fold_first(|acc, &key, val| {
1303 assert!(val % modulo == key);
1304 acc + val
1305 });
1306
1307 // TODO: Swap `fold1` with stdlib's `fold_first` when it's stabilized
1308 let group_map_lookup = a.iter()
1309 .map(|&b| b as u64)
1310 .map(|i| (i % modulo, i))
1311 .into_group_map()
1312 .into_iter()
1313 .map(|(key, vals)| (key, vals.into_iter().fold1(|acc, val| acc + val).unwrap()))
1314 .collect::<HashMap<_,_>>();
1315 assert_eq!(lookup, group_map_lookup);
1316
1317 for (&key, &sum) in lookup.iter() {
1318 assert_eq!(sum, a.iter().map(|&b| b as u64).filter(|&val| val % modulo == key).sum::<u64>());
1319 }
1320 }
1321
1322 fn correct_grouping_map_by_collect_modulo_key(a: Vec<u8>, modulo: u8) -> () {
1323 let modulo = if modulo == 0 { 1 } else { modulo }; // Avoid `% 0`
1324 let lookup_grouping_map = a.iter().copied().into_grouping_map_by(|i| i % modulo).collect::<Vec<_>>();
1325 let lookup_group_map = a.iter().copied().map(|i| (i % modulo, i)).into_group_map();
1326
1327 assert_eq!(lookup_grouping_map, lookup_group_map);
1328 }
1329
1330 fn correct_grouping_map_by_max_modulo_key(a: Vec<u8>, modulo: u8) -> () {
1331 let modulo = if modulo == 0 { 1 } else { modulo }; // Avoid `% 0`
1332 let lookup = a.iter().copied().into_grouping_map_by(|i| i % modulo).max();
1333
1334 let group_map_lookup = a.iter().copied()
1335 .map(|i| (i % modulo, i))
1336 .into_group_map()
1337 .into_iter()
1338 .map(|(key, vals)| (key, vals.into_iter().max().unwrap()))
1339 .collect::<HashMap<_,_>>();
1340 assert_eq!(lookup, group_map_lookup);
1341
1342 for (&key, &max) in lookup.iter() {
1343 assert_eq!(Some(max), a.iter().copied().filter(|&val| val % modulo == key).max());
1344 }
1345 }
1346
1347 fn correct_grouping_map_by_max_by_modulo_key(a: Vec<u8>, modulo: u8) -> () {
1348 let modulo = if modulo == 0 { 1 } else { modulo }; // Avoid `% 0`
1349 let lookup = a.iter().copied().into_grouping_map_by(|i| i % modulo).max_by(|_, v1, v2| v1.cmp(v2));
1350
1351 let group_map_lookup = a.iter().copied()
1352 .map(|i| (i % modulo, i))
1353 .into_group_map()
1354 .into_iter()
1355 .map(|(key, vals)| (key, vals.into_iter().max_by(|v1, v2| v1.cmp(v2)).unwrap()))
1356 .collect::<HashMap<_,_>>();
1357 assert_eq!(lookup, group_map_lookup);
1358
1359 for (&key, &max) in lookup.iter() {
1360 assert_eq!(Some(max), a.iter().copied().filter(|&val| val % modulo == key).max_by(|v1, v2| v1.cmp(v2)));
1361 }
1362 }
1363
1364 fn correct_grouping_map_by_max_by_key_modulo_key(a: Vec<u8>, modulo: u8) -> () {
1365 let modulo = if modulo == 0 { 1 } else { modulo }; // Avoid `% 0`
1366 let lookup = a.iter().copied().into_grouping_map_by(|i| i % modulo).max_by_key(|_, &val| val);
1367
1368 let group_map_lookup = a.iter().copied()
1369 .map(|i| (i % modulo, i))
1370 .into_group_map()
1371 .into_iter()
1372 .map(|(key, vals)| (key, vals.into_iter().max_by_key(|&val| val).unwrap()))
1373 .collect::<HashMap<_,_>>();
1374 assert_eq!(lookup, group_map_lookup);
1375
1376 for (&key, &max) in lookup.iter() {
1377 assert_eq!(Some(max), a.iter().copied().filter(|&val| val % modulo == key).max_by_key(|&val| val));
1378 }
1379 }
1380
1381 fn correct_grouping_map_by_min_modulo_key(a: Vec<u8>, modulo: u8) -> () {
1382 let modulo = if modulo == 0 { 1 } else { modulo }; // Avoid `% 0`
1383 let lookup = a.iter().copied().into_grouping_map_by(|i| i % modulo).min();
1384
1385 let group_map_lookup = a.iter().copied()
1386 .map(|i| (i % modulo, i))
1387 .into_group_map()
1388 .into_iter()
1389 .map(|(key, vals)| (key, vals.into_iter().min().unwrap()))
1390 .collect::<HashMap<_,_>>();
1391 assert_eq!(lookup, group_map_lookup);
1392
1393 for (&key, &min) in lookup.iter() {
1394 assert_eq!(Some(min), a.iter().copied().filter(|&val| val % modulo == key).min());
1395 }
1396 }
1397
1398 fn correct_grouping_map_by_min_by_modulo_key(a: Vec<u8>, modulo: u8) -> () {
1399 let modulo = if modulo == 0 { 1 } else { modulo }; // Avoid `% 0`
1400 let lookup = a.iter().copied().into_grouping_map_by(|i| i % modulo).min_by(|_, v1, v2| v1.cmp(v2));
1401
1402 let group_map_lookup = a.iter().copied()
1403 .map(|i| (i % modulo, i))
1404 .into_group_map()
1405 .into_iter()
1406 .map(|(key, vals)| (key, vals.into_iter().min_by(|v1, v2| v1.cmp(v2)).unwrap()))
1407 .collect::<HashMap<_,_>>();
1408 assert_eq!(lookup, group_map_lookup);
1409
1410 for (&key, &min) in lookup.iter() {
1411 assert_eq!(Some(min), a.iter().copied().filter(|&val| val % modulo == key).min_by(|v1, v2| v1.cmp(v2)));
1412 }
1413 }
1414
1415 fn correct_grouping_map_by_min_by_key_modulo_key(a: Vec<u8>, modulo: u8) -> () {
1416 let modulo = if modulo == 0 { 1 } else { modulo }; // Avoid `% 0`
1417 let lookup = a.iter().copied().into_grouping_map_by(|i| i % modulo).min_by_key(|_, &val| val);
1418
1419 let group_map_lookup = a.iter().copied()
1420 .map(|i| (i % modulo, i))
1421 .into_group_map()
1422 .into_iter()
1423 .map(|(key, vals)| (key, vals.into_iter().min_by_key(|&val| val).unwrap()))
1424 .collect::<HashMap<_,_>>();
1425 assert_eq!(lookup, group_map_lookup);
1426
1427 for (&key, &min) in lookup.iter() {
1428 assert_eq!(Some(min), a.iter().copied().filter(|&val| val % modulo == key).min_by_key(|&val| val));
1429 }
1430 }
1431
1432 fn correct_grouping_map_by_minmax_modulo_key(a: Vec<u8>, modulo: u8) -> () {
1433 let modulo = if modulo == 0 { 1 } else { modulo }; // Avoid `% 0`
1434 let lookup = a.iter().copied().into_grouping_map_by(|i| i % modulo).minmax();
1435
1436 let group_map_lookup = a.iter().copied()
1437 .map(|i| (i % modulo, i))
1438 .into_group_map()
1439 .into_iter()
1440 .map(|(key, vals)| (key, vals.into_iter().minmax()))
1441 .collect::<HashMap<_,_>>();
1442 assert_eq!(lookup, group_map_lookup);
1443
1444 for (&key, &minmax) in lookup.iter() {
1445 assert_eq!(minmax, a.iter().copied().filter(|&val| val % modulo == key).minmax());
1446 }
1447 }
1448
1449 fn correct_grouping_map_by_minmax_by_modulo_key(a: Vec<u8>, modulo: u8) -> () {
1450 let modulo = if modulo == 0 { 1 } else { modulo }; // Avoid `% 0`
1451 let lookup = a.iter().copied().into_grouping_map_by(|i| i % modulo).minmax_by(|_, v1, v2| v1.cmp(v2));
1452
1453 let group_map_lookup = a.iter().copied()
1454 .map(|i| (i % modulo, i))
1455 .into_group_map()
1456 .into_iter()
1457 .map(|(key, vals)| (key, vals.into_iter().minmax_by(|v1, v2| v1.cmp(v2))))
1458 .collect::<HashMap<_,_>>();
1459 assert_eq!(lookup, group_map_lookup);
1460
1461 for (&key, &minmax) in lookup.iter() {
1462 assert_eq!(minmax, a.iter().copied().filter(|&val| val % modulo == key).minmax_by(|v1, v2| v1.cmp(v2)));
1463 }
1464 }
1465
1466 fn correct_grouping_map_by_minmax_by_key_modulo_key(a: Vec<u8>, modulo: u8) -> () {
1467 let modulo = if modulo == 0 { 1 } else { modulo }; // Avoid `% 0`
1468 let lookup = a.iter().copied().into_grouping_map_by(|i| i % modulo).minmax_by_key(|_, &val| val);
1469
1470 let group_map_lookup = a.iter().copied()
1471 .map(|i| (i % modulo, i))
1472 .into_group_map()
1473 .into_iter()
1474 .map(|(key, vals)| (key, vals.into_iter().minmax_by_key(|&val| val)))
1475 .collect::<HashMap<_,_>>();
1476 assert_eq!(lookup, group_map_lookup);
1477
1478 for (&key, &minmax) in lookup.iter() {
1479 assert_eq!(minmax, a.iter().copied().filter(|&val| val % modulo == key).minmax_by_key(|&val| val));
1480 }
1481 }
1482
1483 fn correct_grouping_map_by_sum_modulo_key(a: Vec<u8>, modulo: u8) -> () {
1484 let modulo = if modulo == 0 { 1 } else { modulo } as u64; // Avoid `% 0`
1485 let lookup = a.iter().map(|&b| b as u64) // Avoid overflows
1486 .into_grouping_map_by(|i| i % modulo)
1487 .sum();
1488
1489 let group_map_lookup = a.iter().map(|&b| b as u64)
1490 .map(|i| (i % modulo, i))
1491 .into_group_map()
1492 .into_iter()
1493 .map(|(key, vals)| (key, vals.into_iter().sum()))
1494 .collect::<HashMap<_,_>>();
1495 assert_eq!(lookup, group_map_lookup);
1496
1497 for (&key, &sum) in lookup.iter() {
1498 assert_eq!(sum, a.iter().map(|&b| b as u64).filter(|&val| val % modulo == key).sum::<u64>());
1499 }
1500 }
1501
1502 fn correct_grouping_map_by_product_modulo_key(a: Vec<u8>, modulo: u8) -> () {
1503 let modulo = Wrapping(if modulo == 0 { 1 } else { modulo } as u64); // Avoid `% 0`
1504 let lookup = a.iter().map(|&b| Wrapping(b as u64)) // Avoid overflows
1505 .into_grouping_map_by(|i| i % modulo)
1506 .product();
1507
1508 let group_map_lookup = a.iter().map(|&b| Wrapping(b as u64))
1509 .map(|i| (i % modulo, i))
1510 .into_group_map()
1511 .into_iter()
1512 .map(|(key, vals)| (key, vals.into_iter().product::<Wrapping<u64>>()))
1513 .collect::<HashMap<_,_>>();
1514 assert_eq!(lookup, group_map_lookup);
1515
1516 for (&key, &prod) in lookup.iter() {
1517 assert_eq!(
1518 prod,
1519 a.iter()
1520 .map(|&b| Wrapping(b as u64))
1521 .filter(|&val| val % modulo == key)
1522 .product::<Wrapping<u64>>()
1523 );
1524 }
1525 }
1526
1527 // This should check that if multiple elements are equally minimum or maximum
1528 // then `max`, `min` and `minmax` pick the first minimum and the last maximum.
1529 // This is to be consistent with `std::iter::max` and `std::iter::min`.
1530 fn correct_grouping_map_by_min_max_minmax_order_modulo_key() -> () {
1531 use itertools::MinMaxResult;
1532
1533 let lookup = (0..=10)
1534 .into_grouping_map_by(|_| 0)
1535 .max_by(|_, _, _| Ordering::Equal);
1536
1537 assert_eq!(lookup[&0], 10);
1538
1539 let lookup = (0..=10)
1540 .into_grouping_map_by(|_| 0)
1541 .min_by(|_, _, _| Ordering::Equal);
1542
1543 assert_eq!(lookup[&0], 0);
1544
1545 let lookup = (0..=10)
1546 .into_grouping_map_by(|_| 0)
1547 .minmax_by(|_, _, _| Ordering::Equal);
1548
1549 assert_eq!(lookup[&0], MinMaxResult::MinMax(0, 10));
1550 }
1551}
1552
1553quickcheck! {
1554 #[test]
1555 fn counts(nums: Vec<isize>) -> TestResult {
1556 let counts = nums.iter().counts();
1557 for (&item, &count) in counts.iter() {
1558 if count <= 0 {
1559 return TestResult::failed();
1560 }
1561 if count != nums.iter().filter(|&x| x == item).count() {
1562 return TestResult::failed();
1563 }
1564 }
1565 for item in nums.iter() {
1566 if !counts.contains_key(item) {
1567 return TestResult::failed();
1568 }
1569 }
1570 TestResult::passed()
1571 }
1572}
1573
1574quickcheck! {
1575 fn test_double_ended_zip_2(a: Vec<u8>, b: Vec<u8>) -> TestResult {
1576 let mut x =
1577 multizip((a.clone().into_iter(), b.clone().into_iter()))
1578 .collect_vec();
1579 x.reverse();
1580
1581 let y =
1582 multizip((a.into_iter(), b.into_iter()))
1583 .rfold(Vec::new(), |mut vec, e| { vec.push(e); vec });
1584
1585 TestResult::from_bool(itertools::equal(x, y))
1586 }
1587
1588 fn test_double_ended_zip_3(a: Vec<u8>, b: Vec<u8>, c: Vec<u8>) -> TestResult {
1589 let mut x =
1590 multizip((a.clone().into_iter(), b.clone().into_iter(), c.clone().into_iter()))
1591 .collect_vec();
1592 x.reverse();
1593
1594 let y =
1595 multizip((a.into_iter(), b.into_iter(), c.into_iter()))
1596 .rfold(Vec::new(), |mut vec, e| { vec.push(e); vec });
1597
1598 TestResult::from_bool(itertools::equal(x, y))
1599 }
1600}
Joel Galensonb593e252021-06-21 13:15:57 -07001601
1602
1603fn is_fused<I: Iterator>(mut it: I) -> bool
1604{
1605 while let Some(_) = it.next() {}
1606 for _ in 0..10{
1607 if it.next().is_some(){
1608 return false;
1609 }
1610 }
1611 true
1612}
1613
1614quickcheck! {
1615 fn fused_combination(a: Iter<i16>) -> bool
1616 {
1617 is_fused(a.clone().combinations(1)) &&
1618 is_fused(a.combinations(3))
1619 }
1620
1621 fn fused_combination_with_replacement(a: Iter<i16>) -> bool
1622 {
1623 is_fused(a.clone().combinations_with_replacement(1)) &&
1624 is_fused(a.combinations_with_replacement(3))
1625 }
1626
1627 fn fused_tuple_combination(a: Iter<i16>) -> bool
1628 {
1629 is_fused(a.clone().fuse().tuple_combinations::<(_,)>()) &&
1630 is_fused(a.fuse().tuple_combinations::<(_,_,_)>())
1631 }
1632
1633 fn fused_unique(a: Iter<i16>) -> bool
1634 {
1635 is_fused(a.fuse().unique())
1636 }
1637
1638 fn fused_unique_by(a: Iter<i16>) -> bool
1639 {
1640 is_fused(a.fuse().unique_by(|x| x % 100))
1641 }
1642
1643 fn fused_interleave_shortest(a: Iter<i16>, b: Iter<i16>) -> bool
1644 {
1645 !is_fused(a.clone().interleave_shortest(b.clone())) &&
1646 is_fused(a.fuse().interleave_shortest(b.fuse()))
1647 }
1648
1649 fn fused_product(a: Iter<i16>, b: Iter<i16>) -> bool
1650 {
1651 is_fused(a.fuse().cartesian_product(b.fuse()))
1652 }
1653
1654 fn fused_merge(a: Iter<i16>, b: Iter<i16>) -> bool
1655 {
1656 is_fused(a.fuse().merge(b.fuse()))
1657 }
1658
1659 fn fused_filter_ok(a: Iter<i16>) -> bool
1660 {
1661 is_fused(a.map(|x| if x % 2 == 0 {Ok(x)} else {Err(x)} )
1662 .filter_ok(|x| x % 3 == 0)
1663 .fuse())
1664 }
1665
1666 fn fused_filter_map_ok(a: Iter<i16>) -> bool
1667 {
1668 is_fused(a.map(|x| if x % 2 == 0 {Ok(x)} else {Err(x)} )
1669 .filter_map_ok(|x| if x % 3 == 0 {Some(x / 3)} else {None})
1670 .fuse())
1671 }
1672
1673 fn fused_positions(a: Iter<i16>) -> bool
1674 {
1675 !is_fused(a.clone().positions(|x|x%2==0)) &&
1676 is_fused(a.fuse().positions(|x|x%2==0))
1677 }
1678
1679 fn fused_update(a: Iter<i16>) -> bool
1680 {
1681 !is_fused(a.clone().update(|x|*x+=1)) &&
1682 is_fused(a.fuse().update(|x|*x+=1))
1683 }
1684
1685 fn fused_tuple_windows(a: Iter<i16>) -> bool
1686 {
1687 is_fused(a.fuse().tuple_windows::<(_,_)>())
1688 }
1689
1690 fn fused_pad_using(a: Iter<i16>) -> bool
1691 {
1692 is_fused(a.fuse().pad_using(100,|_|0))
1693 }
1694}
1695