Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 3219a10

Browse files
authoredFeb 21, 2021
Rollup merge of #81300 - ssomers:btree_cleanup_leak_tests, r=Mark-Simulacrum
BTree: share panicky test code & test panic during clear, clone Bases almost all tests of panic on the same, richer definition, and extends it to cloning to test panic during clone. r? ```@Mark-Simulacrum```
2 parents a31c162 + 3e1d602 commit 3219a10

File tree

7 files changed

+337
-217
lines changed

7 files changed

+337
-217
lines changed
 

‎library/alloc/src/collections/btree/map/tests.rs

Lines changed: 154 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
use super::super::{node, DeterministicRng};
1+
use super::super::testing::crash_test::{CrashTestDummy, Panic};
2+
use super::super::testing::ord_chaos::{Cyclic3, Governed, Governor};
3+
use super::super::testing::rng::DeterministicRng;
24
use super::Entry::{Occupied, Vacant};
35
use super::*;
46
use crate::boxed::Box;
@@ -15,9 +17,6 @@ use std::ops::RangeBounds;
1517
use std::panic::{catch_unwind, AssertUnwindSafe};
1618
use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
1719

18-
mod ord_chaos;
19-
use ord_chaos::{Cyclic3, Governed, Governor};
20-
2120
// Capacity of a tree with a single level,
2221
// i.e., a tree who's root is a leaf node at height 0.
2322
const NODE_CAPACITY: usize = node::CAPACITY;
@@ -1136,103 +1135,78 @@ mod test_drain_filter {
11361135

11371136
#[test]
11381137
fn drop_panic_leak() {
1139-
static PREDS: AtomicUsize = AtomicUsize::new(0);
1140-
static DROPS: AtomicUsize = AtomicUsize::new(0);
1141-
1142-
struct D;
1143-
impl Drop for D {
1144-
fn drop(&mut self) {
1145-
if DROPS.fetch_add(1, SeqCst) == 1 {
1146-
panic!("panic in `drop`");
1147-
}
1148-
}
1149-
}
1150-
1151-
// Keys are multiples of 4, so that each key is counted by a hexadecimal digit.
1152-
let mut map = (0..3).map(|i| (i * 4, D)).collect::<BTreeMap<_, _>>();
1138+
let a = CrashTestDummy::new(0);
1139+
let b = CrashTestDummy::new(1);
1140+
let c = CrashTestDummy::new(2);
1141+
let mut map = BTreeMap::new();
1142+
map.insert(a.spawn(Panic::Never), ());
1143+
map.insert(b.spawn(Panic::InDrop), ());
1144+
map.insert(c.spawn(Panic::Never), ());
11531145

1154-
catch_unwind(move || {
1155-
drop(map.drain_filter(|i, _| {
1156-
PREDS.fetch_add(1usize << i, SeqCst);
1157-
true
1158-
}))
1159-
})
1160-
.unwrap_err();
1146+
catch_unwind(move || drop(map.drain_filter(|dummy, _| dummy.query(true)))).unwrap_err();
11611147

1162-
assert_eq!(PREDS.load(SeqCst), 0x011);
1163-
assert_eq!(DROPS.load(SeqCst), 3);
1148+
assert_eq!(a.queried(), 1);
1149+
assert_eq!(b.queried(), 1);
1150+
assert_eq!(c.queried(), 0);
1151+
assert_eq!(a.dropped(), 1);
1152+
assert_eq!(b.dropped(), 1);
1153+
assert_eq!(c.dropped(), 1);
11641154
}
11651155

11661156
#[test]
11671157
fn pred_panic_leak() {
1168-
static PREDS: AtomicUsize = AtomicUsize::new(0);
1169-
static DROPS: AtomicUsize = AtomicUsize::new(0);
1170-
1171-
struct D;
1172-
impl Drop for D {
1173-
fn drop(&mut self) {
1174-
DROPS.fetch_add(1, SeqCst);
1175-
}
1176-
}
1177-
1178-
// Keys are multiples of 4, so that each key is counted by a hexadecimal digit.
1179-
let mut map = (0..3).map(|i| (i * 4, D)).collect::<BTreeMap<_, _>>();
1180-
1181-
catch_unwind(AssertUnwindSafe(|| {
1182-
drop(map.drain_filter(|i, _| {
1183-
PREDS.fetch_add(1usize << i, SeqCst);
1184-
match i {
1185-
0 => true,
1186-
_ => panic!(),
1187-
}
1188-
}))
1189-
}))
1190-
.unwrap_err();
1191-
1192-
assert_eq!(PREDS.load(SeqCst), 0x011);
1193-
assert_eq!(DROPS.load(SeqCst), 1);
1158+
let a = CrashTestDummy::new(0);
1159+
let b = CrashTestDummy::new(1);
1160+
let c = CrashTestDummy::new(2);
1161+
let mut map = BTreeMap::new();
1162+
map.insert(a.spawn(Panic::Never), ());
1163+
map.insert(b.spawn(Panic::InQuery), ());
1164+
map.insert(c.spawn(Panic::InQuery), ());
1165+
1166+
catch_unwind(AssertUnwindSafe(|| drop(map.drain_filter(|dummy, _| dummy.query(true)))))
1167+
.unwrap_err();
1168+
1169+
assert_eq!(a.queried(), 1);
1170+
assert_eq!(b.queried(), 1);
1171+
assert_eq!(c.queried(), 0);
1172+
assert_eq!(a.dropped(), 1);
1173+
assert_eq!(b.dropped(), 0);
1174+
assert_eq!(c.dropped(), 0);
11941175
assert_eq!(map.len(), 2);
1195-
assert_eq!(map.first_entry().unwrap().key(), &4);
1196-
assert_eq!(map.last_entry().unwrap().key(), &8);
1176+
assert_eq!(map.first_entry().unwrap().key().id(), 1);
1177+
assert_eq!(map.last_entry().unwrap().key().id(), 2);
11971178
map.check();
11981179
}
11991180

12001181
// Same as above, but attempt to use the iterator again after the panic in the predicate
12011182
#[test]
12021183
fn pred_panic_reuse() {
1203-
static PREDS: AtomicUsize = AtomicUsize::new(0);
1204-
static DROPS: AtomicUsize = AtomicUsize::new(0);
1205-
1206-
struct D;
1207-
impl Drop for D {
1208-
fn drop(&mut self) {
1209-
DROPS.fetch_add(1, SeqCst);
1210-
}
1211-
}
1212-
1213-
// Keys are multiples of 4, so that each key is counted by a hexadecimal digit.
1214-
let mut map = (0..3).map(|i| (i * 4, D)).collect::<BTreeMap<_, _>>();
1184+
let a = CrashTestDummy::new(0);
1185+
let b = CrashTestDummy::new(1);
1186+
let c = CrashTestDummy::new(2);
1187+
let mut map = BTreeMap::new();
1188+
map.insert(a.spawn(Panic::Never), ());
1189+
map.insert(b.spawn(Panic::InQuery), ());
1190+
map.insert(c.spawn(Panic::InQuery), ());
12151191

12161192
{
1217-
let mut it = map.drain_filter(|i, _| {
1218-
PREDS.fetch_add(1usize << i, SeqCst);
1219-
match i {
1220-
0 => true,
1221-
_ => panic!(),
1222-
}
1223-
});
1193+
let mut it = map.drain_filter(|dummy, _| dummy.query(true));
12241194
catch_unwind(AssertUnwindSafe(|| while it.next().is_some() {})).unwrap_err();
12251195
// Iterator behaviour after a panic is explicitly unspecified,
12261196
// so this is just the current implementation:
12271197
let result = catch_unwind(AssertUnwindSafe(|| it.next()));
12281198
assert!(matches!(result, Ok(None)));
12291199
}
12301200

1231-
assert_eq!(PREDS.load(SeqCst), 0x011);
1232-
assert_eq!(DROPS.load(SeqCst), 1);
1201+
assert_eq!(a.queried(), 1);
1202+
assert_eq!(b.queried(), 1);
1203+
assert_eq!(c.queried(), 0);
1204+
assert_eq!(a.dropped(), 1);
1205+
assert_eq!(b.dropped(), 0);
1206+
assert_eq!(c.dropped(), 0);
12331207
assert_eq!(map.len(), 2);
1234-
assert_eq!(map.first_entry().unwrap().key(), &4);
1235-
assert_eq!(map.last_entry().unwrap().key(), &8);
1208+
assert_eq!(map.first_entry().unwrap().key().id(), 1);
1209+
assert_eq!(map.last_entry().unwrap().key().id(), 2);
12361210
map.check();
12371211
}
12381212
}
@@ -1439,6 +1413,43 @@ fn test_bad_zst() {
14391413
m.check();
14401414
}
14411415

1416+
#[test]
1417+
fn test_clear() {
1418+
let mut map = BTreeMap::new();
1419+
for &len in &[MIN_INSERTS_HEIGHT_1, MIN_INSERTS_HEIGHT_2, 0, NODE_CAPACITY] {
1420+
for i in 0..len {
1421+
map.insert(i, ());
1422+
}
1423+
assert_eq!(map.len(), len);
1424+
map.clear();
1425+
map.check();
1426+
assert!(map.is_empty());
1427+
}
1428+
}
1429+
1430+
#[test]
1431+
fn test_clear_drop_panic_leak() {
1432+
let a = CrashTestDummy::new(0);
1433+
let b = CrashTestDummy::new(1);
1434+
let c = CrashTestDummy::new(2);
1435+
1436+
let mut map = BTreeMap::new();
1437+
map.insert(a.spawn(Panic::Never), ());
1438+
map.insert(b.spawn(Panic::InDrop), ());
1439+
map.insert(c.spawn(Panic::Never), ());
1440+
1441+
catch_unwind(AssertUnwindSafe(|| map.clear())).unwrap_err();
1442+
assert_eq!(a.dropped(), 1);
1443+
assert_eq!(b.dropped(), 1);
1444+
assert_eq!(c.dropped(), 1);
1445+
assert_eq!(map.len(), 0);
1446+
1447+
drop(map);
1448+
assert_eq!(a.dropped(), 1);
1449+
assert_eq!(b.dropped(), 1);
1450+
assert_eq!(c.dropped(), 1);
1451+
}
1452+
14421453
#[test]
14431454
fn test_clone() {
14441455
let mut map = BTreeMap::new();
@@ -1484,6 +1495,35 @@ fn test_clone() {
14841495
map.check();
14851496
}
14861497

1498+
#[test]
1499+
fn test_clone_panic_leak() {
1500+
let a = CrashTestDummy::new(0);
1501+
let b = CrashTestDummy::new(1);
1502+
let c = CrashTestDummy::new(2);
1503+
1504+
let mut map = BTreeMap::new();
1505+
map.insert(a.spawn(Panic::Never), ());
1506+
map.insert(b.spawn(Panic::InClone), ());
1507+
map.insert(c.spawn(Panic::Never), ());
1508+
1509+
catch_unwind(|| map.clone()).unwrap_err();
1510+
assert_eq!(a.cloned(), 1);
1511+
assert_eq!(b.cloned(), 1);
1512+
assert_eq!(c.cloned(), 0);
1513+
assert_eq!(a.dropped(), 1);
1514+
assert_eq!(b.dropped(), 0);
1515+
assert_eq!(c.dropped(), 0);
1516+
assert_eq!(map.len(), 3);
1517+
1518+
drop(map);
1519+
assert_eq!(a.cloned(), 1);
1520+
assert_eq!(b.cloned(), 1);
1521+
assert_eq!(c.cloned(), 0);
1522+
assert_eq!(a.dropped(), 2);
1523+
assert_eq!(b.dropped(), 1);
1524+
assert_eq!(c.dropped(), 1);
1525+
}
1526+
14871527
#[test]
14881528
fn test_clone_from() {
14891529
let mut map1 = BTreeMap::new();
@@ -1901,29 +1941,21 @@ create_append_test!(test_append_1700, 1700);
19011941

19021942
#[test]
19031943
fn test_append_drop_leak() {
1904-
static DROPS: AtomicUsize = AtomicUsize::new(0);
1905-
1906-
struct D;
1907-
1908-
impl Drop for D {
1909-
fn drop(&mut self) {
1910-
if DROPS.fetch_add(1, SeqCst) == 0 {
1911-
panic!("panic in `drop`");
1912-
}
1913-
}
1914-
}
1915-
1944+
let a = CrashTestDummy::new(0);
1945+
let b = CrashTestDummy::new(1);
1946+
let c = CrashTestDummy::new(2);
19161947
let mut left = BTreeMap::new();
19171948
let mut right = BTreeMap::new();
1918-
left.insert(0, D);
1919-
left.insert(1, D); // first to be dropped during append
1920-
left.insert(2, D);
1921-
right.insert(1, D);
1922-
right.insert(2, D);
1949+
left.insert(a.spawn(Panic::Never), ());
1950+
left.insert(b.spawn(Panic::InDrop), ()); // first duplicate key, dropped during append
1951+
left.insert(c.spawn(Panic::Never), ());
1952+
right.insert(b.spawn(Panic::Never), ());
1953+
right.insert(c.spawn(Panic::Never), ());
19231954

19241955
catch_unwind(move || left.append(&mut right)).unwrap_err();
1925-
1926-
assert_eq!(DROPS.load(SeqCst), 4); // Rust issue #47949 ate one little piggy
1956+
assert_eq!(a.dropped(), 1);
1957+
assert_eq!(b.dropped(), 1); // should be 2 were it not for Rust issue #47949
1958+
assert_eq!(c.dropped(), 2);
19271959
}
19281960

19291961
#[test]
@@ -2050,51 +2082,42 @@ fn test_split_off_large_random_sorted() {
20502082

20512083
#[test]
20522084
fn test_into_iter_drop_leak_height_0() {
2053-
static DROPS: AtomicUsize = AtomicUsize::new(0);
2054-
2055-
struct D;
2056-
2057-
impl Drop for D {
2058-
fn drop(&mut self) {
2059-
if DROPS.fetch_add(1, SeqCst) == 3 {
2060-
panic!("panic in `drop`");
2061-
}
2062-
}
2063-
}
2064-
2085+
let a = CrashTestDummy::new(0);
2086+
let b = CrashTestDummy::new(1);
2087+
let c = CrashTestDummy::new(2);
2088+
let d = CrashTestDummy::new(3);
2089+
let e = CrashTestDummy::new(4);
20652090
let mut map = BTreeMap::new();
2066-
map.insert("a", D);
2067-
map.insert("b", D);
2068-
map.insert("c", D);
2069-
map.insert("d", D);
2070-
map.insert("e", D);
2091+
map.insert("a", a.spawn(Panic::Never));
2092+
map.insert("b", b.spawn(Panic::Never));
2093+
map.insert("c", c.spawn(Panic::Never));
2094+
map.insert("d", d.spawn(Panic::InDrop));
2095+
map.insert("e", e.spawn(Panic::Never));
20712096

20722097
catch_unwind(move || drop(map.into_iter())).unwrap_err();
20732098

2074-
assert_eq!(DROPS.load(SeqCst), 5);
2099+
assert_eq!(a.dropped(), 1);
2100+
assert_eq!(b.dropped(), 1);
2101+
assert_eq!(c.dropped(), 1);
2102+
assert_eq!(d.dropped(), 1);
2103+
assert_eq!(e.dropped(), 1);
20752104
}
20762105

20772106
#[test]
20782107
fn test_into_iter_drop_leak_height_1() {
20792108
let size = MIN_INSERTS_HEIGHT_1;
2080-
static DROPS: AtomicUsize = AtomicUsize::new(0);
2081-
static PANIC_POINT: AtomicUsize = AtomicUsize::new(0);
2082-
2083-
struct D;
2084-
impl Drop for D {
2085-
fn drop(&mut self) {
2086-
if DROPS.fetch_add(1, SeqCst) == PANIC_POINT.load(SeqCst) {
2087-
panic!("panic in `drop`");
2088-
}
2089-
}
2090-
}
2091-
20922109
for panic_point in vec![0, 1, size - 2, size - 1] {
2093-
DROPS.store(0, SeqCst);
2094-
PANIC_POINT.store(panic_point, SeqCst);
2095-
let map: BTreeMap<_, _> = (0..size).map(|i| (i, D)).collect();
2110+
let dummies: Vec<_> = (0..size).map(|i| CrashTestDummy::new(i)).collect();
2111+
let map: BTreeMap<_, _> = (0..size)
2112+
.map(|i| {
2113+
let panic = if i == panic_point { Panic::InDrop } else { Panic::Never };
2114+
(dummies[i].spawn(Panic::Never), dummies[i].spawn(panic))
2115+
})
2116+
.collect();
20962117
catch_unwind(move || drop(map.into_iter())).unwrap_err();
2097-
assert_eq!(DROPS.load(SeqCst), size);
2118+
for i in 0..size {
2119+
assert_eq!(dummies[i].dropped(), 2);
2120+
}
20982121
}
20992122
}
21002123

‎library/alloc/src/collections/btree/mod.rs

Lines changed: 1 addition & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -20,32 +20,4 @@ trait Recover<Q: ?Sized> {
2020
}
2121

2222
#[cfg(test)]
23-
/// XorShiftRng
24-
struct DeterministicRng {
25-
count: usize,
26-
x: u32,
27-
y: u32,
28-
z: u32,
29-
w: u32,
30-
}
31-
32-
#[cfg(test)]
33-
impl DeterministicRng {
34-
fn new() -> Self {
35-
DeterministicRng { count: 0, x: 0x193a6754, y: 0xa8a7d469, z: 0x97830e05, w: 0x113ba7bb }
36-
}
37-
38-
/// Guarantees that each returned number is unique.
39-
fn next(&mut self) -> u32 {
40-
self.count += 1;
41-
assert!(self.count <= 70029);
42-
let x = self.x;
43-
let t = x ^ (x << 11);
44-
self.x = self.y;
45-
self.y = self.z;
46-
self.z = self.w;
47-
let w_ = self.w;
48-
self.w = w_ ^ (w_ >> 19) ^ (t ^ (t >> 8));
49-
self.w
50-
}
51-
}
23+
mod testing;

‎library/alloc/src/collections/btree/set/tests.rs

Lines changed: 32 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
use super::super::DeterministicRng;
1+
use super::super::testing::crash_test::{CrashTestDummy, Panic};
2+
use super::super::testing::rng::DeterministicRng;
23
use super::*;
34
use crate::vec::Vec;
45
use std::cmp::Ordering;
56
use std::iter::FromIterator;
67
use std::panic::{catch_unwind, AssertUnwindSafe};
7-
use std::sync::atomic::{AtomicU32, Ordering::SeqCst};
88

99
#[test]
1010
fn test_clone_eq() {
@@ -349,70 +349,45 @@ fn test_drain_filter() {
349349

350350
#[test]
351351
fn test_drain_filter_drop_panic_leak() {
352-
static PREDS: AtomicU32 = AtomicU32::new(0);
353-
static DROPS: AtomicU32 = AtomicU32::new(0);
354-
355-
#[derive(PartialEq, Eq, PartialOrd, Ord)]
356-
struct D(i32);
357-
impl Drop for D {
358-
fn drop(&mut self) {
359-
if DROPS.fetch_add(1, SeqCst) == 1 {
360-
panic!("panic in `drop`");
361-
}
362-
}
363-
}
364-
352+
let a = CrashTestDummy::new(0);
353+
let b = CrashTestDummy::new(1);
354+
let c = CrashTestDummy::new(2);
365355
let mut set = BTreeSet::new();
366-
set.insert(D(0));
367-
set.insert(D(4));
368-
set.insert(D(8));
356+
set.insert(a.spawn(Panic::Never));
357+
set.insert(b.spawn(Panic::InDrop));
358+
set.insert(c.spawn(Panic::Never));
369359

370-
catch_unwind(move || {
371-
drop(set.drain_filter(|d| {
372-
PREDS.fetch_add(1u32 << d.0, SeqCst);
373-
true
374-
}))
375-
})
376-
.ok();
360+
catch_unwind(move || drop(set.drain_filter(|dummy| dummy.query(true)))).ok();
377361

378-
assert_eq!(PREDS.load(SeqCst), 0x011);
379-
assert_eq!(DROPS.load(SeqCst), 3);
362+
assert_eq!(a.queried(), 1);
363+
assert_eq!(b.queried(), 1);
364+
assert_eq!(c.queried(), 0);
365+
assert_eq!(a.dropped(), 1);
366+
assert_eq!(b.dropped(), 1);
367+
assert_eq!(c.dropped(), 1);
380368
}
381369

382370
#[test]
383371
fn test_drain_filter_pred_panic_leak() {
384-
static PREDS: AtomicU32 = AtomicU32::new(0);
385-
static DROPS: AtomicU32 = AtomicU32::new(0);
386-
387-
#[derive(PartialEq, Eq, PartialOrd, Ord)]
388-
struct D(i32);
389-
impl Drop for D {
390-
fn drop(&mut self) {
391-
DROPS.fetch_add(1, SeqCst);
392-
}
393-
}
394-
372+
let a = CrashTestDummy::new(0);
373+
let b = CrashTestDummy::new(1);
374+
let c = CrashTestDummy::new(2);
395375
let mut set = BTreeSet::new();
396-
set.insert(D(0));
397-
set.insert(D(4));
398-
set.insert(D(8));
399-
400-
catch_unwind(AssertUnwindSafe(|| {
401-
drop(set.drain_filter(|d| {
402-
PREDS.fetch_add(1u32 << d.0, SeqCst);
403-
match d.0 {
404-
0 => true,
405-
_ => panic!(),
406-
}
407-
}))
408-
}))
409-
.ok();
410-
411-
assert_eq!(PREDS.load(SeqCst), 0x011);
412-
assert_eq!(DROPS.load(SeqCst), 1);
376+
set.insert(a.spawn(Panic::Never));
377+
set.insert(b.spawn(Panic::InQuery));
378+
set.insert(c.spawn(Panic::InQuery));
379+
380+
catch_unwind(AssertUnwindSafe(|| drop(set.drain_filter(|dummy| dummy.query(true))))).ok();
381+
382+
assert_eq!(a.queried(), 1);
383+
assert_eq!(b.queried(), 1);
384+
assert_eq!(c.queried(), 0);
385+
assert_eq!(a.dropped(), 1);
386+
assert_eq!(b.dropped(), 0);
387+
assert_eq!(c.dropped(), 0);
413388
assert_eq!(set.len(), 2);
414-
assert_eq!(set.first().unwrap().0, 4);
415-
assert_eq!(set.last().unwrap().0, 8);
389+
assert_eq!(set.first().unwrap().id(), 1);
390+
assert_eq!(set.last().unwrap().id(), 2);
416391
}
417392

418393
#[test]
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
use crate::fmt::Debug;
2+
use std::cmp::Ordering;
3+
use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
4+
5+
/// A blueprint for crash test dummy instances that monitor particular events.
6+
/// Some instances may be configured to panic at some point.
7+
/// Events are `clone`, `drop` or some anonymous `query`.
8+
///
9+
/// Crash test dummies are identified and ordered by an id, so they can be used
10+
/// as keys in a BTreeMap. The implementation intentionally uses does not rely
11+
/// on anything defined in the crate, apart from the `Debug` trait.
12+
#[derive(Debug)]
13+
pub struct CrashTestDummy {
14+
id: usize,
15+
cloned: AtomicUsize,
16+
dropped: AtomicUsize,
17+
queried: AtomicUsize,
18+
}
19+
20+
impl CrashTestDummy {
21+
/// Creates a crash test dummy design. The `id` determines order and equality of instances.
22+
pub fn new(id: usize) -> CrashTestDummy {
23+
CrashTestDummy {
24+
id,
25+
cloned: AtomicUsize::new(0),
26+
dropped: AtomicUsize::new(0),
27+
queried: AtomicUsize::new(0),
28+
}
29+
}
30+
31+
/// Creates an instance of a crash test dummy that records what events it experiences
32+
/// and optionally panics.
33+
pub fn spawn(&self, panic: Panic) -> Instance<'_> {
34+
Instance { origin: self, panic }
35+
}
36+
37+
/// Returns how many times instances of the dummy have been cloned.
38+
pub fn cloned(&self) -> usize {
39+
self.cloned.load(SeqCst)
40+
}
41+
42+
/// Returns how many times instances of the dummy have been dropped.
43+
pub fn dropped(&self) -> usize {
44+
self.dropped.load(SeqCst)
45+
}
46+
47+
/// Returns how many times instances of the dummy have had their `query` member invoked.
48+
pub fn queried(&self) -> usize {
49+
self.queried.load(SeqCst)
50+
}
51+
}
52+
53+
#[derive(Debug)]
54+
pub struct Instance<'a> {
55+
origin: &'a CrashTestDummy,
56+
panic: Panic,
57+
}
58+
59+
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
60+
pub enum Panic {
61+
Never,
62+
InClone,
63+
InDrop,
64+
InQuery,
65+
}
66+
67+
impl Instance<'_> {
68+
pub fn id(&self) -> usize {
69+
self.origin.id
70+
}
71+
72+
/// Some anonymous query, the result of which is already given.
73+
pub fn query<R>(&self, result: R) -> R {
74+
self.origin.queried.fetch_add(1, SeqCst);
75+
if self.panic == Panic::InQuery {
76+
panic!("panic in `query`");
77+
}
78+
result
79+
}
80+
}
81+
82+
impl Clone for Instance<'_> {
83+
fn clone(&self) -> Self {
84+
self.origin.cloned.fetch_add(1, SeqCst);
85+
if self.panic == Panic::InClone {
86+
panic!("panic in `clone`");
87+
}
88+
Self { origin: self.origin, panic: Panic::Never }
89+
}
90+
}
91+
92+
impl Drop for Instance<'_> {
93+
fn drop(&mut self) {
94+
self.origin.dropped.fetch_add(1, SeqCst);
95+
if self.panic == Panic::InDrop {
96+
panic!("panic in `drop`");
97+
}
98+
}
99+
}
100+
101+
impl PartialOrd for Instance<'_> {
102+
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
103+
self.id().partial_cmp(&other.id())
104+
}
105+
}
106+
107+
impl Ord for Instance<'_> {
108+
fn cmp(&self, other: &Self) -> Ordering {
109+
self.id().cmp(&other.id())
110+
}
111+
}
112+
113+
impl PartialEq for Instance<'_> {
114+
fn eq(&self, other: &Self) -> bool {
115+
self.id().eq(&other.id())
116+
}
117+
}
118+
119+
impl Eq for Instance<'_> {}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
pub mod crash_test;
2+
pub mod ord_chaos;
3+
pub mod rng;
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/// XorShiftRng
2+
pub struct DeterministicRng {
3+
count: usize,
4+
x: u32,
5+
y: u32,
6+
z: u32,
7+
w: u32,
8+
}
9+
10+
impl DeterministicRng {
11+
pub fn new() -> Self {
12+
DeterministicRng { count: 0, x: 0x193a6754, y: 0xa8a7d469, z: 0x97830e05, w: 0x113ba7bb }
13+
}
14+
15+
/// Guarantees that each returned number is unique.
16+
pub fn next(&mut self) -> u32 {
17+
self.count += 1;
18+
assert!(self.count <= 70029);
19+
let x = self.x;
20+
let t = x ^ (x << 11);
21+
self.x = self.y;
22+
self.y = self.z;
23+
self.z = self.w;
24+
let w_ = self.w;
25+
self.w = w_ ^ (w_ >> 19) ^ (t ^ (t >> 8));
26+
self.w
27+
}
28+
}

0 commit comments

Comments
 (0)
Please sign in to comment.