Skip to content

Commit 6814180

Browse files
Test laziness
Ignore the 3 failing tests (for now). `ChunkBy` and `IntoChunks` are not iterators themselves but implement `IntoIterator` instead. Then `Groups` and `Chunks` are iterators. All four are lazy and must be used.
1 parent b1be1e4 commit 6814180

File tree

1 file changed

+274
-0
lines changed

1 file changed

+274
-0
lines changed

tests/laziness.rs

+274
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,274 @@
1+
#![allow(unstable_name_collisions)]
2+
3+
use itertools::Itertools;
4+
5+
#[derive(Debug, Clone)]
6+
#[must_use = "iterators are lazy and do nothing unless consumed"]
7+
struct Panicking;
8+
9+
impl Iterator for Panicking {
10+
type Item = u8;
11+
12+
fn next(&mut self) -> Option<u8> {
13+
panic!("iterator adaptor is not lazy")
14+
}
15+
16+
fn size_hint(&self) -> (usize, Option<usize>) {
17+
(0, Some(0))
18+
}
19+
}
20+
21+
impl ExactSizeIterator for Panicking {}
22+
23+
/// ## Usage example
24+
/// ```compile_fail
25+
/// must_use_tests! {
26+
/// name {
27+
/// Panicking.name(); // Add `let _ =` only if required (encountered error).
28+
/// }
29+
/// // ...
30+
/// }
31+
/// ```
32+
///
33+
/// **TODO:** test missing `must_use` attributes better, maybe with a new lint.
34+
macro_rules! must_use_tests {
35+
($($(#[$attr:meta])* $name:ident $body:block)*) => {
36+
$(
37+
/// `#[deny(unused_must_use)]` should force us to ignore the resulting iterators
38+
/// by adding `let _ = ...;` on every iterator.
39+
/// If it does not, then a `must_use` attribute is missing on the associated struct.
40+
///
41+
/// However, it's only helpful if we don't add `let _ =` before seeing if there is an error or not.
42+
/// And it does not protect us against removed `must_use` attributes.
43+
/// There is no simple way to test this yet.
44+
#[deny(unused_must_use)]
45+
#[test]
46+
$(#[$attr])*
47+
fn $name() $body
48+
)*
49+
};
50+
}
51+
52+
must_use_tests! {
53+
// Itertools trait:
54+
interleave {
55+
let _ = Panicking.interleave(Panicking);
56+
}
57+
interleave_shortest {
58+
let _ = Panicking.interleave_shortest(Panicking);
59+
}
60+
intersperse {
61+
let _ = Panicking.intersperse(0);
62+
}
63+
intersperse_with {
64+
let _ = Panicking.intersperse_with(|| 0);
65+
}
66+
zip_longest {
67+
let _ = Panicking.zip_longest(Panicking);
68+
}
69+
zip_eq {
70+
let _ = Panicking.zip_eq(Panicking);
71+
}
72+
batching {
73+
let _ = Panicking.batching(Iterator::next);
74+
}
75+
chunk_by {
76+
// ChunkBy
77+
let _ = Panicking.chunk_by(|x| *x);
78+
// Groups
79+
let _ = Panicking.chunk_by(|x| *x).into_iter();
80+
}
81+
chunks {
82+
// IntoChunks
83+
let _ = Panicking.chunks(1);
84+
let _ = Panicking.chunks(2);
85+
// Chunks
86+
let _ = Panicking.chunks(1).into_iter();
87+
let _ = Panicking.chunks(2).into_iter();
88+
}
89+
tuple_windows {
90+
let _ = Panicking.tuple_windows::<(_,)>();
91+
let _ = Panicking.tuple_windows::<(_, _)>();
92+
let _ = Panicking.tuple_windows::<(_, _, _)>();
93+
}
94+
circular_tuple_windows {
95+
let _ = Panicking.circular_tuple_windows::<(_,)>();
96+
let _ = Panicking.circular_tuple_windows::<(_, _)>();
97+
let _ = Panicking.circular_tuple_windows::<(_, _, _)>();
98+
}
99+
tuples {
100+
let _ = Panicking.tuples::<(_,)>();
101+
let _ = Panicking.tuples::<(_, _)>();
102+
let _ = Panicking.tuples::<(_, _, _)>();
103+
}
104+
tee {
105+
let _ = Panicking.tee();
106+
}
107+
#[allow(deprecated)]
108+
step {
109+
let _ = Panicking.step(2);
110+
}
111+
map_into {
112+
let _ = Panicking.map_into::<u16>();
113+
}
114+
map_ok {
115+
let _ = Panicking.map(Ok::<u8, ()>).map_ok(|x| x + 1);
116+
}
117+
filter_ok {
118+
let _ = Panicking.map(Ok::<u8, ()>).filter_ok(|x| x % 2 == 0);
119+
}
120+
filter_map_ok {
121+
let _ = Panicking.map(Ok::<u8, ()>).filter_map_ok(|x| {
122+
if x % 2 == 0 {
123+
Some(x + 1)
124+
} else {
125+
None
126+
}
127+
});
128+
}
129+
flatten_ok {
130+
let _ = Panicking.map(|x| Ok::<_, ()>([x])).flatten_ok();
131+
}
132+
merge {
133+
let _ = Panicking.merge(Panicking);
134+
}
135+
merge_by {
136+
let _ = Panicking.merge_by(Panicking, |_, _| true);
137+
}
138+
merge_join_by {
139+
let _ = Panicking.merge_join_by(Panicking, |_, _| true);
140+
let _ = Panicking.merge_join_by(Panicking, Ord::cmp);
141+
}
142+
#[ignore]
143+
kmerge {
144+
let _ = Panicking.map(|_| Panicking).kmerge();
145+
}
146+
#[ignore]
147+
kmerge_by {
148+
let _ = Panicking.map(|_| Panicking).kmerge_by(|_, _| true);
149+
}
150+
cartesian_product {
151+
let _ = Panicking.cartesian_product(Panicking);
152+
}
153+
multi_cartesian_product {
154+
let _ = vec![Panicking, Panicking, Panicking].into_iter().multi_cartesian_product();
155+
}
156+
coalesce {
157+
let _ = Panicking.coalesce(|x, y| if x == y { Ok(x) } else { Err((x, y)) });
158+
}
159+
dedup {
160+
let _ = Panicking.dedup();
161+
}
162+
dedup_by {
163+
let _ = Panicking.dedup_by(|_, _| true);
164+
}
165+
dedup_with_count {
166+
let _ = Panicking.dedup_with_count();
167+
}
168+
dedup_by_with_count {
169+
let _ = Panicking.dedup_by_with_count(|_, _| true);
170+
}
171+
duplicates {
172+
let _ = Panicking.duplicates();
173+
}
174+
duplicates_by {
175+
let _ = Panicking.duplicates_by(|x| *x);
176+
}
177+
unique {
178+
let _ = Panicking.unique();
179+
}
180+
unique_by {
181+
let _ = Panicking.unique_by(|x| *x);
182+
}
183+
peeking_take_while {
184+
let _ = Panicking.peekable().peeking_take_while(|x| x % 2 == 0);
185+
}
186+
take_while_ref {
187+
let _ = Panicking.take_while_ref(|x| x % 2 == 0);
188+
}
189+
take_while_inclusive {
190+
let _ = Panicking.take_while_inclusive(|x| x % 2 == 0);
191+
}
192+
while_some {
193+
let _ = Panicking.map(Some).while_some();
194+
}
195+
#[ignore]
196+
tuple_combinations {
197+
let _ = Panicking.tuple_combinations::<(_,)>();
198+
let _ = Panicking.tuple_combinations::<(_, _)>();
199+
let _ = Panicking.tuple_combinations::<(_, _, _)>();
200+
}
201+
combinations {
202+
let _ = Panicking.combinations(0);
203+
let _ = Panicking.combinations(1);
204+
let _ = Panicking.combinations(2);
205+
}
206+
combinations_with_replacement {
207+
let _ = Panicking.combinations_with_replacement(0);
208+
let _ = Panicking.combinations_with_replacement(1);
209+
let _ = Panicking.combinations_with_replacement(2);
210+
}
211+
permutations {
212+
let _ = Panicking.permutations(0);
213+
let _ = Panicking.permutations(1);
214+
let _ = Panicking.permutations(2);
215+
}
216+
powerset {
217+
let _ = Panicking.powerset();
218+
}
219+
pad_using {
220+
let _ = Panicking.pad_using(25, |_| 10);
221+
}
222+
with_position {
223+
let _ = Panicking.with_position();
224+
}
225+
positions {
226+
let _ = Panicking.positions(|v| v % 2 == 0);
227+
}
228+
update {
229+
let _ = Panicking.update(|n| *n += 1);
230+
}
231+
multipeek {
232+
let _ = Panicking.multipeek();
233+
}
234+
// Not iterator themselves but still lazy.
235+
into_grouping_map {
236+
let _ = Panicking.map(|x| (x, x + 1)).into_grouping_map();
237+
}
238+
into_grouping_map_by {
239+
let _ = Panicking.into_grouping_map_by(|x| *x);
240+
}
241+
// Macros:
242+
iproduct {
243+
let _ = itertools::iproduct!(Panicking);
244+
let _ = itertools::iproduct!(Panicking, Panicking);
245+
let _ = itertools::iproduct!(Panicking, Panicking, Panicking);
246+
}
247+
izip {
248+
let _ = itertools::izip!(Panicking);
249+
let _ = itertools::izip!(Panicking, Panicking);
250+
let _ = itertools::izip!(Panicking, Panicking, Panicking);
251+
}
252+
chain {
253+
let _ = itertools::chain!(Panicking);
254+
let _ = itertools::chain!(Panicking, Panicking);
255+
let _ = itertools::chain!(Panicking, Panicking, Panicking);
256+
}
257+
// Free functions:
258+
multizip {
259+
let _ = itertools::multizip((Panicking, Panicking));
260+
}
261+
put_back {
262+
let _ = itertools::put_back(Panicking);
263+
let _ = itertools::put_back(Panicking).with_value(15);
264+
}
265+
peek_nth {
266+
let _ = itertools::peek_nth(Panicking);
267+
}
268+
put_back_n {
269+
let _ = itertools::put_back_n(Panicking);
270+
}
271+
rciter {
272+
let _ = itertools::rciter(Panicking);
273+
}
274+
}

0 commit comments

Comments
 (0)