diff --git a/tests/laziness.rs b/tests/laziness.rs new file mode 100644 index 000000000..268157b98 --- /dev/null +++ b/tests/laziness.rs @@ -0,0 +1,262 @@ +#![allow(unstable_name_collisions, deprecated)] + +use itertools::Itertools; + +#[derive(Debug, Clone)] +#[must_use = "iterators are lazy and do nothing unless consumed"] +struct Panicking; + +impl Iterator for Panicking { + type Item = u8; + + fn next(&mut self) -> Option { + panic!("iterator adaptor is not lazy") + } + + fn size_hint(&self) -> (usize, Option) { + (0, Some(0)) + } +} + +impl ExactSizeIterator for Panicking {} + +/// ## Usage example +/// ```compile_fail +/// must_use_tests! { +/// name { +/// Panicking.name(); // Add `let _ =` only if required (encountered error). +/// } +/// // ... +/// } +/// ``` +/// +/// **TODO:** test missing `must_use` attributes better. +macro_rules! must_use_tests { + ($($name:ident $body:block)*) => { + $( + /// `#[deny(unused_must_use)]` should force us to ignore the resulting iterators + /// by adding `let _ = ...;` on every iterator. + /// If it does not, then a `must_use` attribute is missing on the associated struct. + /// + /// However, it's only helpful if we don't add `let _ =` before seeing if there is an error or not. + /// And it does not protect us against removed `must_use` attributes. + /// There is no simple way to test this yet. + #[deny(unused_must_use)] + #[test] + fn $name() $body + )* + }; +} + +must_use_tests! { + // Itertools trait: + interleave { + let _ = Panicking.interleave(Panicking); + } + interleave_shortest { + let _ = Panicking.interleave_shortest(Panicking); + } + intersperse { + let _ = Panicking.intersperse(0); + } + intersperse_with { + let _ = Panicking.intersperse_with(|| 0); + } + zip_longest { + let _ = Panicking.zip_longest(Panicking); + } + zip_eq { + let _ = Panicking.zip_eq(Panicking); + } + batching { + let _ = Panicking.batching(Iterator::next); + } + group_by { + let _ = Panicking.group_by(|x| *x); + } + chunks { + let _ = Panicking.chunks(1); + let _ = Panicking.chunks(2); + } + tuple_windows { + let _ = Panicking.tuple_windows::<(_,)>(); + let _ = Panicking.tuple_windows::<(_, _)>(); + let _ = Panicking.tuple_windows::<(_, _, _)>(); + } + circular_tuple_windows { + let _ = Panicking.circular_tuple_windows::<(_,)>(); + let _ = Panicking.circular_tuple_windows::<(_, _)>(); + let _ = Panicking.circular_tuple_windows::<(_, _, _)>(); + } + tuples { + let _ = Panicking.tuples::<(_,)>(); + let _ = Panicking.tuples::<(_, _)>(); + let _ = Panicking.tuples::<(_, _, _)>(); + } + tee { + let _ = Panicking.tee(); + } + step { + let _ = Panicking.step(2); + } + map_into { + let _ = Panicking.map_into::(); + } + map_ok { + let _ = Panicking.map(Ok::).map_ok(|x| x + 1); + } + filter_ok { + let _ = Panicking.map(Ok::).filter_ok(|x| x % 2 == 0); + } + filter_map_ok { + let _ = Panicking.map(Ok::).filter_map_ok(|x| { + if x % 2 == 0 { + Some(x + 1) + } else { + None + } + }); + } + flatten_ok { + let _ = Panicking.map(|x| Ok::<_, ()>([x])).flatten_ok(); + } + merge { + let _ = Panicking.merge(Panicking); + } + merge_by { + let _ = Panicking.merge_by(Panicking, |_, _| true); + } + merge_join_by { + let _ = Panicking.merge_join_by(Panicking, |_, _| true); + let _ = Panicking.merge_join_by(Panicking, Ord::cmp); + } + kmerge { + let _ = Panicking.map(|_| Panicking).kmerge(); + } + kmerge_by { + let _ = Panicking.map(|_| Panicking).kmerge_by(|_, _| true); + } + cartesian_product { + let _ = Panicking.cartesian_product(Panicking); + } + multi_cartesian_product { + let _ = vec![Panicking, Panicking, Panicking].into_iter().multi_cartesian_product(); + } + coalesce { + let _ = Panicking.coalesce(|x, y| if x == y { Ok(x) } else { Err((x, y)) }); + } + dedup { + let _ = Panicking.dedup(); + } + dedup_by { + let _ = Panicking.dedup_by(|_, _| true); + } + dedup_with_count { + let _ = Panicking.dedup_with_count(); + } + dedup_by_with_count { + let _ = Panicking.dedup_by_with_count(|_, _| true); + } + duplicates { + let _ = Panicking.duplicates(); + } + duplicates_by { + let _ = Panicking.duplicates_by(|x| *x); + } + unique { + let _ = Panicking.unique(); + } + unique_by { + let _ = Panicking.unique_by(|x| *x); + } + peeking_take_while { + let _ = Panicking.peekable().peeking_take_while(|x| x % 2 == 0); + } + take_while_ref { + let _ = Panicking.take_while_ref(|x| x % 2 == 0); + } + take_while_inclusive { + let _ = Panicking.take_while_inclusive(|x| x % 2 == 0); + } + while_some { + let _ = Panicking.map(Some).while_some(); + } + tuple_combinations { + let _ = Panicking.tuple_combinations::<(_,)>(); + let _ = Panicking.tuple_combinations::<(_, _)>(); + let _ = Panicking.tuple_combinations::<(_, _, _)>(); + } + combinations { + let _ = Panicking.combinations(0); + let _ = Panicking.combinations(1); + let _ = Panicking.combinations(2); + } + combinations_with_replacement { + Panicking.combinations_with_replacement(0); + Panicking.combinations_with_replacement(1); + Panicking.combinations_with_replacement(2); + } + permutations { + let _ = Panicking.permutations(0); + let _ = Panicking.permutations(1); + let _ = Panicking.permutations(2); + } + powerset { + let _ = Panicking.powerset(); + } + pad_using { + let _ = Panicking.pad_using(25, |_| 10); + } + with_position { + let _ = Panicking.with_position(); + } + positions { + let _ = Panicking.positions(|v| v % 2 == 0); + } + update { + let _ = Panicking.update(|n| *n += 1); + } + multipeek { + Panicking.multipeek(); + } + // Not iterator themselves but still lazy. + into_grouping_map { + let _ = Panicking.map(|x| (x, x + 1)).into_grouping_map(); + } + into_grouping_map_by { + let _ = Panicking.into_grouping_map_by(|x| *x); + } + // Macros: + iproduct { + let _ = itertools::iproduct!(Panicking); + let _ = itertools::iproduct!(Panicking, Panicking); + let _ = itertools::iproduct!(Panicking, Panicking, Panicking); + } + izip { + let _ = itertools::izip!(Panicking); + let _ = itertools::izip!(Panicking, Panicking); + let _ = itertools::izip!(Panicking, Panicking, Panicking); + } + chain { + let _ = itertools::chain!(Panicking); + let _ = itertools::chain!(Panicking, Panicking); + let _ = itertools::chain!(Panicking, Panicking, Panicking); + } + // Free functions: + multizip { + let _ = itertools::multizip((Panicking, Panicking)); + } + put_back { + itertools::put_back(Panicking); + itertools::put_back(Panicking).with_value(15); + } + peek_nth { + itertools::peek_nth(Panicking); + } + put_back_n { + itertools::put_back_n(Panicking); + } + rciter { + itertools::rciter(Panicking); + } +}