1#![cfg(test)]
2#![allow(unused_assignments)]
3
4// These tests are primarily targeting "abusive" producers that will
5// try to drive the "collect consumer" incorrectly. These should
6// result in panics.
7
8use super::collect_with_consumer;
9use crate::iter::plumbing::*;
10use rayon_core::join;
11
12use std::fmt;
13use std::panic;
14use std::sync::atomic::{AtomicUsize, Ordering};
15use std::thread::Result as ThreadResult;
16
17/// Promises to produce 2 items, but then produces 3. Does not do any
18/// splits at all.
19#[test]
20#[should_panic(expected = "too many values")]
21fn produce_too_many_items() {
22 let mut v = vec![];
23 collect_with_consumer(&mut v, 2, |consumer| {
24 let mut folder = consumer.into_folder();
25 folder = folder.consume(22);
26 folder = folder.consume(23);
27 folder = folder.consume(24);
28 unreachable!("folder does not complete")
29 });
30}
31
32/// Produces fewer items than promised. Does not do any
33/// splits at all.
34#[test]
35#[should_panic(expected = "expected 5 total writes, but got 2")]
36fn produce_fewer_items() {
37 let mut v = vec![];
38 collect_with_consumer(&mut v, 5, |consumer| {
39 let mut folder = consumer.into_folder();
40 folder = folder.consume(22);
41 folder = folder.consume(23);
42 folder.complete()
43 });
44}
45
46// Complete is not called by the consumer. Hence,the collection vector is not fully initialized.
47#[test]
48#[should_panic(expected = "expected 4 total writes, but got 2")]
49fn left_produces_items_with_no_complete() {
50 let mut v = vec![];
51 collect_with_consumer(&mut v, 4, |consumer| {
52 let (left_consumer, right_consumer, _) = consumer.split_at(2);
53 let mut left_folder = left_consumer.into_folder();
54 let mut right_folder = right_consumer.into_folder();
55 left_folder = left_folder.consume(0).consume(1);
56 right_folder = right_folder.consume(2).consume(3);
57 right_folder.complete()
58 });
59}
60
61// Complete is not called by the right consumer. Hence,the
62// collection vector is not fully initialized.
63#[test]
64#[should_panic(expected = "expected 4 total writes, but got 2")]
65fn right_produces_items_with_no_complete() {
66 let mut v = vec![];
67 collect_with_consumer(&mut v, 4, |consumer| {
68 let (left_consumer, right_consumer, _) = consumer.split_at(2);
69 let mut left_folder = left_consumer.into_folder();
70 let mut right_folder = right_consumer.into_folder();
71 left_folder = left_folder.consume(0).consume(1);
72 right_folder = right_folder.consume(2).consume(3);
73 left_folder.complete()
74 });
75}
76
77// Complete is not called by the consumer. Hence,the collection vector is not fully initialized.
78#[test]
79#[cfg_attr(not(panic = "unwind"), ignore)]
80fn produces_items_with_no_complete() {
81 let counter = DropCounter::default();
82 let mut v = vec![];
83 let panic_result = panic::catch_unwind(panic::AssertUnwindSafe(|| {
84 collect_with_consumer(&mut v, 2, |consumer| {
85 let mut folder = consumer.into_folder();
86 folder = folder.consume(counter.element());
87 folder = folder.consume(counter.element());
88 panic!("folder does not complete");
89 });
90 }));
91 assert!(v.is_empty());
92 assert_is_panic_with_message(&panic_result, "folder does not complete");
93 counter.assert_drop_count();
94}
95
96// The left consumer produces too many items while the right
97// consumer produces correct number.
98#[test]
99#[should_panic(expected = "too many values")]
100fn left_produces_too_many_items() {
101 let mut v = vec![];
102 collect_with_consumer(&mut v, 4, |consumer| {
103 let (left_consumer, right_consumer, _) = consumer.split_at(2);
104 let mut left_folder = left_consumer.into_folder();
105 let mut right_folder = right_consumer.into_folder();
106 left_folder = left_folder.consume(0).consume(1).consume(2);
107 right_folder = right_folder.consume(2).consume(3);
108 let _ = right_folder.complete();
109 unreachable!("folder does not complete");
110 });
111}
112
113// The right consumer produces too many items while the left
114// consumer produces correct number.
115#[test]
116#[should_panic(expected = "too many values")]
117fn right_produces_too_many_items() {
118 let mut v = vec![];
119 collect_with_consumer(&mut v, 4, |consumer| {
120 let (left_consumer, right_consumer, _) = consumer.split_at(2);
121 let mut left_folder = left_consumer.into_folder();
122 let mut right_folder = right_consumer.into_folder();
123 left_folder = left_folder.consume(0).consume(1);
124 right_folder = right_folder.consume(2).consume(3).consume(4);
125 let _ = left_folder.complete();
126 unreachable!("folder does not complete");
127 });
128}
129
130// The left consumer produces fewer items while the right
131// consumer produces correct number.
132#[test]
133#[should_panic(expected = "expected 4 total writes, but got 1")]
134fn left_produces_fewer_items() {
135 let mut v = vec![];
136 collect_with_consumer(&mut v, 4, |consumer| {
137 let reducer = consumer.to_reducer();
138 let (left_consumer, right_consumer, _) = consumer.split_at(2);
139 let mut left_folder = left_consumer.into_folder();
140 let mut right_folder = right_consumer.into_folder();
141 left_folder = left_folder.consume(0);
142 right_folder = right_folder.consume(2).consume(3);
143 let left_result = left_folder.complete();
144 let right_result = right_folder.complete();
145 reducer.reduce(left_result, right_result)
146 });
147}
148
149// The left and right consumer produce the correct number but
150// only left result is returned
151#[test]
152#[should_panic(expected = "expected 4 total writes, but got 2")]
153fn only_left_result() {
154 let mut v = vec![];
155 collect_with_consumer(&mut v, 4, |consumer| {
156 let (left_consumer, right_consumer, _) = consumer.split_at(2);
157 let mut left_folder = left_consumer.into_folder();
158 let mut right_folder = right_consumer.into_folder();
159 left_folder = left_folder.consume(0).consume(1);
160 right_folder = right_folder.consume(2).consume(3);
161 let left_result = left_folder.complete();
162 let _ = right_folder.complete();
163 left_result
164 });
165}
166
167// The left and right consumer produce the correct number but
168// only right result is returned
169#[test]
170#[should_panic(expected = "expected 4 total writes, but got 2")]
171fn only_right_result() {
172 let mut v = vec![];
173 collect_with_consumer(&mut v, 4, |consumer| {
174 let (left_consumer, right_consumer, _) = consumer.split_at(2);
175 let mut left_folder = left_consumer.into_folder();
176 let mut right_folder = right_consumer.into_folder();
177 left_folder = left_folder.consume(0).consume(1);
178 right_folder = right_folder.consume(2).consume(3);
179 let _ = left_folder.complete();
180 right_folder.complete()
181 });
182}
183
184// The left and right consumer produce the correct number but reduce
185// in the wrong order.
186#[test]
187#[should_panic(expected = "expected 4 total writes, but got 2")]
188fn reducer_does_not_preserve_order() {
189 let mut v = vec![];
190 collect_with_consumer(&mut v, 4, |consumer| {
191 let reducer = consumer.to_reducer();
192 let (left_consumer, right_consumer, _) = consumer.split_at(2);
193 let mut left_folder = left_consumer.into_folder();
194 let mut right_folder = right_consumer.into_folder();
195 left_folder = left_folder.consume(0).consume(1);
196 right_folder = right_folder.consume(2).consume(3);
197 let left_result = left_folder.complete();
198 let right_result = right_folder.complete();
199 reducer.reduce(right_result, left_result)
200 });
201}
202
203// The right consumer produces fewer items while the left
204// consumer produces correct number.
205#[test]
206#[should_panic(expected = "expected 4 total writes, but got 3")]
207fn right_produces_fewer_items() {
208 let mut v = vec![];
209 collect_with_consumer(&mut v, 4, |consumer| {
210 let reducer = consumer.to_reducer();
211 let (left_consumer, right_consumer, _) = consumer.split_at(2);
212 let mut left_folder = left_consumer.into_folder();
213 let mut right_folder = right_consumer.into_folder();
214 left_folder = left_folder.consume(0).consume(1);
215 right_folder = right_folder.consume(2);
216 let left_result = left_folder.complete();
217 let right_result = right_folder.complete();
218 reducer.reduce(left_result, right_result)
219 });
220}
221
222// The left consumer panics and the right stops short, like `panic_fuse()`.
223// We should get the left panic without finishing `collect_with_consumer`.
224#[test]
225#[should_panic(expected = "left consumer panic")]
226fn left_panics() {
227 let mut v = vec![];
228 collect_with_consumer(&mut v, 4, |consumer| {
229 let reducer = consumer.to_reducer();
230 let (left_consumer, right_consumer, _) = consumer.split_at(2);
231 let (left_result, right_result) = join(
232 || {
233 let mut left_folder = left_consumer.into_folder();
234 left_folder = left_folder.consume(0);
235 panic!("left consumer panic");
236 },
237 || {
238 let mut right_folder = right_consumer.into_folder();
239 right_folder = right_folder.consume(2);
240 right_folder.complete() // early return
241 },
242 );
243 reducer.reduce(left_result, right_result)
244 });
245 unreachable!();
246}
247
248// The right consumer panics and the left stops short, like `panic_fuse()`.
249// We should get the right panic without finishing `collect_with_consumer`.
250#[test]
251#[should_panic(expected = "right consumer panic")]
252fn right_panics() {
253 let mut v = vec![];
254 collect_with_consumer(&mut v, 4, |consumer| {
255 let reducer = consumer.to_reducer();
256 let (left_consumer, right_consumer, _) = consumer.split_at(2);
257 let (left_result, right_result) = join(
258 || {
259 let mut left_folder = left_consumer.into_folder();
260 left_folder = left_folder.consume(0);
261 left_folder.complete() // early return
262 },
263 || {
264 let mut right_folder = right_consumer.into_folder();
265 right_folder = right_folder.consume(2);
266 panic!("right consumer panic");
267 },
268 );
269 reducer.reduce(left_result, right_result)
270 });
271 unreachable!();
272}
273
274// The left consumer produces fewer items while the right
275// consumer produces correct number; check that created elements are dropped
276#[test]
277#[cfg_attr(not(panic = "unwind"), ignore)]
278fn left_produces_fewer_items_drops() {
279 let counter = DropCounter::default();
280 let mut v = vec![];
281 let panic_result = panic::catch_unwind(panic::AssertUnwindSafe(|| {
282 collect_with_consumer(&mut v, 4, |consumer| {
283 let reducer = consumer.to_reducer();
284 let (left_consumer, right_consumer, _) = consumer.split_at(2);
285 let mut left_folder = left_consumer.into_folder();
286 let mut right_folder = right_consumer.into_folder();
287 left_folder = left_folder.consume(counter.element());
288 right_folder = right_folder
289 .consume(counter.element())
290 .consume(counter.element());
291 let left_result = left_folder.complete();
292 let right_result = right_folder.complete();
293 reducer.reduce(left_result, right_result)
294 });
295 }));
296 assert!(v.is_empty());
297 assert_is_panic_with_message(&panic_result, "expected 4 total writes, but got 1");
298 counter.assert_drop_count();
299}
300
301/// This counter can create elements, and then count and verify
302/// the number of which have actually been dropped again.
303#[derive(Default)]
304struct DropCounter {
305 created: AtomicUsize,
306 dropped: AtomicUsize,
307}
308
309struct Element<'a>(&'a AtomicUsize);
310
311impl DropCounter {
312 fn created(&self) -> usize {
313 self.created.load(Ordering::SeqCst)
314 }
315
316 fn dropped(&self) -> usize {
317 self.dropped.load(Ordering::SeqCst)
318 }
319
320 fn element(&self) -> Element<'_> {
321 self.created.fetch_add(1, Ordering::SeqCst);
322 Element(&self.dropped)
323 }
324
325 fn assert_drop_count(&self) {
326 assert_eq!(
327 self.created(),
328 self.dropped(),
329 "Expected {} dropped elements, but found {}",
330 self.created(),
331 self.dropped()
332 );
333 }
334}
335
336impl<'a> Drop for Element<'a> {
337 fn drop(&mut self) {
338 self.0.fetch_add(1, Ordering::SeqCst);
339 }
340}
341
342/// Assert that the result from catch_unwind is a panic that contains expected message
343fn assert_is_panic_with_message<T>(result: &ThreadResult<T>, expected: &str)
344where
345 T: fmt::Debug,
346{
347 match result {
348 Ok(value) => {
349 panic!(
350 "assertion failure: Expected panic, got successful {:?}",
351 value
352 );
353 }
354 Err(error) => {
355 let message_str = error.downcast_ref::<&'static str>().cloned();
356 let message_string = error.downcast_ref::<String>().map(String::as_str);
357 if let Some(message) = message_str.or(message_string) {
358 if !message.contains(expected) {
359 panic!(
360 "assertion failure: Expected {:?}, but found panic with {:?}",
361 expected, message
362 );
363 }
364 // assertion passes
365 } else {
366 panic!(
367 "assertion failure: Expected {:?}, but found panic with unknown value",
368 expected
369 );
370 }
371 }
372 }
373}
374