aboutsummaryrefslogtreecommitdiff
path: root/tests/iter_panic.rs
diff options
context:
space:
mode:
Diffstat (limited to 'tests/iter_panic.rs')
-rw-r--r--tests/iter_panic.rs52
1 files changed, 52 insertions, 0 deletions
diff --git a/tests/iter_panic.rs b/tests/iter_panic.rs
new file mode 100644
index 0000000..4885a28
--- /dev/null
+++ b/tests/iter_panic.rs
@@ -0,0 +1,52 @@
+use rayon::prelude::*;
+use rayon::ThreadPoolBuilder;
+use std::ops::Range;
+use std::panic::{self, UnwindSafe};
+use std::sync::atomic::{AtomicUsize, Ordering};
+
+const ITER: Range<i32> = 0..0x1_0000;
+const PANIC: i32 = 0xC000;
+
+fn check(&i: &i32) {
+ if i == PANIC {
+ panic!("boom")
+ }
+}
+
+#[test]
+#[should_panic(expected = "boom")]
+fn iter_panic() {
+ ITER.into_par_iter().for_each(|i| check(&i));
+}
+
+#[test]
+fn iter_panic_fuse() {
+ // We only use a single thread in order to make the behavior
+ // of 'panic_fuse' deterministic
+ let pool = ThreadPoolBuilder::new().num_threads(1).build().unwrap();
+
+ pool.install(|| {
+ fn count(iter: impl ParallelIterator + UnwindSafe) -> usize {
+ let count = AtomicUsize::new(0);
+ let result = panic::catch_unwind(|| {
+ iter.for_each(|_| {
+ count.fetch_add(1, Ordering::Relaxed);
+ });
+ });
+ assert!(result.is_err());
+ count.into_inner()
+ }
+
+ // Without `panic_fuse()`, we'll reach every item except the panicking one.
+ let expected = ITER.len() - 1;
+ let iter = ITER.into_par_iter().with_max_len(1);
+ assert_eq!(count(iter.clone().inspect(check)), expected);
+
+ // With `panic_fuse()` anywhere in the chain, we'll reach fewer items.
+ assert!(count(iter.clone().inspect(check).panic_fuse()) < expected);
+ assert!(count(iter.clone().panic_fuse().inspect(check)) < expected);
+
+ // Try in reverse to be sure we hit the producer case.
+ assert!(count(iter.clone().panic_fuse().inspect(check).rev()) < expected);
+ });
+}