From 6d2247eac2256b3f6e8d10e3bc9c3b6068d74967 Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Sat, 23 Jan 2021 15:25:56 +0100 Subject: [PATCH 1/2] BTreeMap/BTreeSet: separate off code supporting tests --- .../alloc/src/collections/btree/map/tests.rs | 6 ++-- library/alloc/src/collections/btree/mod.rs | 30 +------------------ .../alloc/src/collections/btree/set/tests.rs | 2 +- .../src/collections/btree/testing/mod.rs | 2 ++ .../btree/{map/tests => testing}/ord_chaos.rs | 0 .../src/collections/btree/testing/rng.rs | 28 +++++++++++++++++ 6 files changed, 34 insertions(+), 34 deletions(-) create mode 100644 library/alloc/src/collections/btree/testing/mod.rs rename library/alloc/src/collections/btree/{map/tests => testing}/ord_chaos.rs (100%) create mode 100644 library/alloc/src/collections/btree/testing/rng.rs diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs index 1993c6e047d..73607a2a638 100644 --- a/library/alloc/src/collections/btree/map/tests.rs +++ b/library/alloc/src/collections/btree/map/tests.rs @@ -1,4 +1,5 @@ -use super::super::{node, DeterministicRng}; +use super::super::testing::ord_chaos::{Cyclic3, Governed, Governor}; +use super::super::testing::rng::DeterministicRng; use super::Entry::{Occupied, Vacant}; use super::*; use crate::boxed::Box; @@ -15,9 +16,6 @@ use std::ops::RangeBounds; use std::panic::{catch_unwind, AssertUnwindSafe}; use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; -mod ord_chaos; -use ord_chaos::{Cyclic3, Governed, Governor}; - // Capacity of a tree with a single level, // i.e., a tree who's root is a leaf node at height 0. const NODE_CAPACITY: usize = node::CAPACITY; diff --git a/library/alloc/src/collections/btree/mod.rs b/library/alloc/src/collections/btree/mod.rs index cf91c17b511..421f842dab0 100644 --- a/library/alloc/src/collections/btree/mod.rs +++ b/library/alloc/src/collections/btree/mod.rs @@ -20,32 +20,4 @@ trait Recover { } #[cfg(test)] -/// XorShiftRng -struct DeterministicRng { - count: usize, - x: u32, - y: u32, - z: u32, - w: u32, -} - -#[cfg(test)] -impl DeterministicRng { - fn new() -> Self { - DeterministicRng { count: 0, x: 0x193a6754, y: 0xa8a7d469, z: 0x97830e05, w: 0x113ba7bb } - } - - /// Guarantees that each returned number is unique. - fn next(&mut self) -> u32 { - self.count += 1; - assert!(self.count <= 70029); - let x = self.x; - let t = x ^ (x << 11); - self.x = self.y; - self.y = self.z; - self.z = self.w; - let w_ = self.w; - self.w = w_ ^ (w_ >> 19) ^ (t ^ (t >> 8)); - self.w - } -} +mod testing; diff --git a/library/alloc/src/collections/btree/set/tests.rs b/library/alloc/src/collections/btree/set/tests.rs index 3762af7236a..9c6fb44af43 100644 --- a/library/alloc/src/collections/btree/set/tests.rs +++ b/library/alloc/src/collections/btree/set/tests.rs @@ -1,4 +1,4 @@ -use super::super::DeterministicRng; +use super::super::testing::rng::DeterministicRng; use super::*; use crate::vec::Vec; use std::cmp::Ordering; diff --git a/library/alloc/src/collections/btree/testing/mod.rs b/library/alloc/src/collections/btree/testing/mod.rs new file mode 100644 index 00000000000..03880e7014e --- /dev/null +++ b/library/alloc/src/collections/btree/testing/mod.rs @@ -0,0 +1,2 @@ +pub mod ord_chaos; +pub mod rng; diff --git a/library/alloc/src/collections/btree/map/tests/ord_chaos.rs b/library/alloc/src/collections/btree/testing/ord_chaos.rs similarity index 100% rename from library/alloc/src/collections/btree/map/tests/ord_chaos.rs rename to library/alloc/src/collections/btree/testing/ord_chaos.rs diff --git a/library/alloc/src/collections/btree/testing/rng.rs b/library/alloc/src/collections/btree/testing/rng.rs new file mode 100644 index 00000000000..ecf543bee03 --- /dev/null +++ b/library/alloc/src/collections/btree/testing/rng.rs @@ -0,0 +1,28 @@ +/// XorShiftRng +pub struct DeterministicRng { + count: usize, + x: u32, + y: u32, + z: u32, + w: u32, +} + +impl DeterministicRng { + pub fn new() -> Self { + DeterministicRng { count: 0, x: 0x193a6754, y: 0xa8a7d469, z: 0x97830e05, w: 0x113ba7bb } + } + + /// Guarantees that each returned number is unique. + pub fn next(&mut self) -> u32 { + self.count += 1; + assert!(self.count <= 70029); + let x = self.x; + let t = x ^ (x << 11); + self.x = self.y; + self.y = self.z; + self.z = self.w; + let w_ = self.w; + self.w = w_ ^ (w_ >> 19) ^ (t ^ (t >> 8)); + self.w + } +} From 3e1d602a6b3ed491e2188176addf41a059c1ff02 Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Sat, 23 Jan 2021 15:25:56 +0100 Subject: [PATCH 2/2] BTreeMap: share panicky test code & test panic during clear, clone --- .../alloc/src/collections/btree/map/tests.rs | 275 ++++++++++-------- .../alloc/src/collections/btree/set/tests.rs | 83 ++---- .../collections/btree/testing/crash_test.rs | 119 ++++++++ .../src/collections/btree/testing/mod.rs | 1 + 4 files changed, 299 insertions(+), 179 deletions(-) create mode 100644 library/alloc/src/collections/btree/testing/crash_test.rs diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs index 73607a2a638..56d6ae57e04 100644 --- a/library/alloc/src/collections/btree/map/tests.rs +++ b/library/alloc/src/collections/btree/map/tests.rs @@ -1,3 +1,4 @@ +use super::super::testing::crash_test::{CrashTestDummy, Panic}; use super::super::testing::ord_chaos::{Cyclic3, Governed, Governor}; use super::super::testing::rng::DeterministicRng; use super::Entry::{Occupied, Vacant}; @@ -1134,91 +1135,62 @@ mod test_drain_filter { #[test] fn drop_panic_leak() { - static PREDS: AtomicUsize = AtomicUsize::new(0); - static DROPS: AtomicUsize = AtomicUsize::new(0); + let a = CrashTestDummy::new(0); + let b = CrashTestDummy::new(1); + let c = CrashTestDummy::new(2); + let mut map = BTreeMap::new(); + map.insert(a.spawn(Panic::Never), ()); + map.insert(b.spawn(Panic::InDrop), ()); + map.insert(c.spawn(Panic::Never), ()); - struct D; - impl Drop for D { - fn drop(&mut self) { - if DROPS.fetch_add(1, SeqCst) == 1 { - panic!("panic in `drop`"); - } - } - } + catch_unwind(move || drop(map.drain_filter(|dummy, _| dummy.query(true)))).unwrap_err(); - // Keys are multiples of 4, so that each key is counted by a hexadecimal digit. - let mut map = (0..3).map(|i| (i * 4, D)).collect::>(); - - catch_unwind(move || { - drop(map.drain_filter(|i, _| { - PREDS.fetch_add(1usize << i, SeqCst); - true - })) - }) - .unwrap_err(); - - assert_eq!(PREDS.load(SeqCst), 0x011); - assert_eq!(DROPS.load(SeqCst), 3); + assert_eq!(a.queried(), 1); + assert_eq!(b.queried(), 1); + assert_eq!(c.queried(), 0); + assert_eq!(a.dropped(), 1); + assert_eq!(b.dropped(), 1); + assert_eq!(c.dropped(), 1); } #[test] fn pred_panic_leak() { - static PREDS: AtomicUsize = AtomicUsize::new(0); - static DROPS: AtomicUsize = AtomicUsize::new(0); + let a = CrashTestDummy::new(0); + let b = CrashTestDummy::new(1); + let c = CrashTestDummy::new(2); + let mut map = BTreeMap::new(); + map.insert(a.spawn(Panic::Never), ()); + map.insert(b.spawn(Panic::InQuery), ()); + map.insert(c.spawn(Panic::InQuery), ()); - struct D; - impl Drop for D { - fn drop(&mut self) { - DROPS.fetch_add(1, SeqCst); - } - } + catch_unwind(AssertUnwindSafe(|| drop(map.drain_filter(|dummy, _| dummy.query(true))))) + .unwrap_err(); - // Keys are multiples of 4, so that each key is counted by a hexadecimal digit. - let mut map = (0..3).map(|i| (i * 4, D)).collect::>(); - - catch_unwind(AssertUnwindSafe(|| { - drop(map.drain_filter(|i, _| { - PREDS.fetch_add(1usize << i, SeqCst); - match i { - 0 => true, - _ => panic!(), - } - })) - })) - .unwrap_err(); - - assert_eq!(PREDS.load(SeqCst), 0x011); - assert_eq!(DROPS.load(SeqCst), 1); + assert_eq!(a.queried(), 1); + assert_eq!(b.queried(), 1); + assert_eq!(c.queried(), 0); + assert_eq!(a.dropped(), 1); + assert_eq!(b.dropped(), 0); + assert_eq!(c.dropped(), 0); assert_eq!(map.len(), 2); - assert_eq!(map.first_entry().unwrap().key(), &4); - assert_eq!(map.last_entry().unwrap().key(), &8); + assert_eq!(map.first_entry().unwrap().key().id(), 1); + assert_eq!(map.last_entry().unwrap().key().id(), 2); map.check(); } // Same as above, but attempt to use the iterator again after the panic in the predicate #[test] fn pred_panic_reuse() { - static PREDS: AtomicUsize = AtomicUsize::new(0); - static DROPS: AtomicUsize = AtomicUsize::new(0); - - struct D; - impl Drop for D { - fn drop(&mut self) { - DROPS.fetch_add(1, SeqCst); - } - } - - // Keys are multiples of 4, so that each key is counted by a hexadecimal digit. - let mut map = (0..3).map(|i| (i * 4, D)).collect::>(); + let a = CrashTestDummy::new(0); + let b = CrashTestDummy::new(1); + let c = CrashTestDummy::new(2); + let mut map = BTreeMap::new(); + map.insert(a.spawn(Panic::Never), ()); + map.insert(b.spawn(Panic::InQuery), ()); + map.insert(c.spawn(Panic::InQuery), ()); { - let mut it = map.drain_filter(|i, _| { - PREDS.fetch_add(1usize << i, SeqCst); - match i { - 0 => true, - _ => panic!(), - } - }); + let mut it = map.drain_filter(|dummy, _| dummy.query(true)); catch_unwind(AssertUnwindSafe(|| while it.next().is_some() {})).unwrap_err(); // Iterator behaviour after a panic is explicitly unspecified, // so this is just the current implementation: @@ -1226,11 +1198,15 @@ mod test_drain_filter { assert!(matches!(result, Ok(None))); } - assert_eq!(PREDS.load(SeqCst), 0x011); - assert_eq!(DROPS.load(SeqCst), 1); + assert_eq!(a.queried(), 1); + assert_eq!(b.queried(), 1); + assert_eq!(c.queried(), 0); + assert_eq!(a.dropped(), 1); + assert_eq!(b.dropped(), 0); + assert_eq!(c.dropped(), 0); assert_eq!(map.len(), 2); - assert_eq!(map.first_entry().unwrap().key(), &4); - assert_eq!(map.last_entry().unwrap().key(), &8); + assert_eq!(map.first_entry().unwrap().key().id(), 1); + assert_eq!(map.last_entry().unwrap().key().id(), 2); map.check(); } } @@ -1437,6 +1413,43 @@ fn test_bad_zst() { m.check(); } +#[test] +fn test_clear() { + let mut map = BTreeMap::new(); + for &len in &[MIN_INSERTS_HEIGHT_1, MIN_INSERTS_HEIGHT_2, 0, NODE_CAPACITY] { + for i in 0..len { + map.insert(i, ()); + } + assert_eq!(map.len(), len); + map.clear(); + map.check(); + assert!(map.is_empty()); + } +} + +#[test] +fn test_clear_drop_panic_leak() { + let a = CrashTestDummy::new(0); + let b = CrashTestDummy::new(1); + let c = CrashTestDummy::new(2); + + let mut map = BTreeMap::new(); + map.insert(a.spawn(Panic::Never), ()); + map.insert(b.spawn(Panic::InDrop), ()); + map.insert(c.spawn(Panic::Never), ()); + + catch_unwind(AssertUnwindSafe(|| map.clear())).unwrap_err(); + assert_eq!(a.dropped(), 1); + assert_eq!(b.dropped(), 1); + assert_eq!(c.dropped(), 1); + assert_eq!(map.len(), 0); + + drop(map); + assert_eq!(a.dropped(), 1); + assert_eq!(b.dropped(), 1); + assert_eq!(c.dropped(), 1); +} + #[test] fn test_clone() { let mut map = BTreeMap::new(); @@ -1482,6 +1495,35 @@ fn test_clone() { map.check(); } +#[test] +fn test_clone_panic_leak() { + let a = CrashTestDummy::new(0); + let b = CrashTestDummy::new(1); + let c = CrashTestDummy::new(2); + + let mut map = BTreeMap::new(); + map.insert(a.spawn(Panic::Never), ()); + map.insert(b.spawn(Panic::InClone), ()); + map.insert(c.spawn(Panic::Never), ()); + + catch_unwind(|| map.clone()).unwrap_err(); + assert_eq!(a.cloned(), 1); + assert_eq!(b.cloned(), 1); + assert_eq!(c.cloned(), 0); + assert_eq!(a.dropped(), 1); + assert_eq!(b.dropped(), 0); + assert_eq!(c.dropped(), 0); + assert_eq!(map.len(), 3); + + drop(map); + assert_eq!(a.cloned(), 1); + assert_eq!(b.cloned(), 1); + assert_eq!(c.cloned(), 0); + assert_eq!(a.dropped(), 2); + assert_eq!(b.dropped(), 1); + assert_eq!(c.dropped(), 1); +} + #[test] fn test_clone_from() { let mut map1 = BTreeMap::new(); @@ -1899,29 +1941,21 @@ create_append_test!(test_append_1700, 1700); #[test] fn test_append_drop_leak() { - static DROPS: AtomicUsize = AtomicUsize::new(0); - - struct D; - - impl Drop for D { - fn drop(&mut self) { - if DROPS.fetch_add(1, SeqCst) == 0 { - panic!("panic in `drop`"); - } - } - } - + let a = CrashTestDummy::new(0); + let b = CrashTestDummy::new(1); + let c = CrashTestDummy::new(2); let mut left = BTreeMap::new(); let mut right = BTreeMap::new(); - left.insert(0, D); - left.insert(1, D); // first to be dropped during append - left.insert(2, D); - right.insert(1, D); - right.insert(2, D); + left.insert(a.spawn(Panic::Never), ()); + left.insert(b.spawn(Panic::InDrop), ()); // first duplicate key, dropped during append + left.insert(c.spawn(Panic::Never), ()); + right.insert(b.spawn(Panic::Never), ()); + right.insert(c.spawn(Panic::Never), ()); catch_unwind(move || left.append(&mut right)).unwrap_err(); - - assert_eq!(DROPS.load(SeqCst), 4); // Rust issue #47949 ate one little piggy + assert_eq!(a.dropped(), 1); + assert_eq!(b.dropped(), 1); // should be 2 were it not for Rust issue #47949 + assert_eq!(c.dropped(), 2); } #[test] @@ -2048,51 +2082,42 @@ fn test_split_off_large_random_sorted() { #[test] fn test_into_iter_drop_leak_height_0() { - static DROPS: AtomicUsize = AtomicUsize::new(0); - - struct D; - - impl Drop for D { - fn drop(&mut self) { - if DROPS.fetch_add(1, SeqCst) == 3 { - panic!("panic in `drop`"); - } - } - } - + let a = CrashTestDummy::new(0); + let b = CrashTestDummy::new(1); + let c = CrashTestDummy::new(2); + let d = CrashTestDummy::new(3); + let e = CrashTestDummy::new(4); let mut map = BTreeMap::new(); - map.insert("a", D); - map.insert("b", D); - map.insert("c", D); - map.insert("d", D); - map.insert("e", D); + map.insert("a", a.spawn(Panic::Never)); + map.insert("b", b.spawn(Panic::Never)); + map.insert("c", c.spawn(Panic::Never)); + map.insert("d", d.spawn(Panic::InDrop)); + map.insert("e", e.spawn(Panic::Never)); catch_unwind(move || drop(map.into_iter())).unwrap_err(); - assert_eq!(DROPS.load(SeqCst), 5); + assert_eq!(a.dropped(), 1); + assert_eq!(b.dropped(), 1); + assert_eq!(c.dropped(), 1); + assert_eq!(d.dropped(), 1); + assert_eq!(e.dropped(), 1); } #[test] fn test_into_iter_drop_leak_height_1() { let size = MIN_INSERTS_HEIGHT_1; - static DROPS: AtomicUsize = AtomicUsize::new(0); - static PANIC_POINT: AtomicUsize = AtomicUsize::new(0); - - struct D; - impl Drop for D { - fn drop(&mut self) { - if DROPS.fetch_add(1, SeqCst) == PANIC_POINT.load(SeqCst) { - panic!("panic in `drop`"); - } - } - } - for panic_point in vec![0, 1, size - 2, size - 1] { - DROPS.store(0, SeqCst); - PANIC_POINT.store(panic_point, SeqCst); - let map: BTreeMap<_, _> = (0..size).map(|i| (i, D)).collect(); + let dummies: Vec<_> = (0..size).map(|i| CrashTestDummy::new(i)).collect(); + let map: BTreeMap<_, _> = (0..size) + .map(|i| { + let panic = if i == panic_point { Panic::InDrop } else { Panic::Never }; + (dummies[i].spawn(Panic::Never), dummies[i].spawn(panic)) + }) + .collect(); catch_unwind(move || drop(map.into_iter())).unwrap_err(); - assert_eq!(DROPS.load(SeqCst), size); + for i in 0..size { + assert_eq!(dummies[i].dropped(), 2); + } } } diff --git a/library/alloc/src/collections/btree/set/tests.rs b/library/alloc/src/collections/btree/set/tests.rs index 9c6fb44af43..4cb6e3d6619 100644 --- a/library/alloc/src/collections/btree/set/tests.rs +++ b/library/alloc/src/collections/btree/set/tests.rs @@ -1,10 +1,10 @@ +use super::super::testing::crash_test::{CrashTestDummy, Panic}; use super::super::testing::rng::DeterministicRng; use super::*; use crate::vec::Vec; use std::cmp::Ordering; use std::iter::FromIterator; use std::panic::{catch_unwind, AssertUnwindSafe}; -use std::sync::atomic::{AtomicU32, Ordering::SeqCst}; #[test] fn test_clone_eq() { @@ -349,70 +349,45 @@ fn test_drain_filter() { #[test] fn test_drain_filter_drop_panic_leak() { - static PREDS: AtomicU32 = AtomicU32::new(0); - static DROPS: AtomicU32 = AtomicU32::new(0); - - #[derive(PartialEq, Eq, PartialOrd, Ord)] - struct D(i32); - impl Drop for D { - fn drop(&mut self) { - if DROPS.fetch_add(1, SeqCst) == 1 { - panic!("panic in `drop`"); - } - } - } - + let a = CrashTestDummy::new(0); + let b = CrashTestDummy::new(1); + let c = CrashTestDummy::new(2); let mut set = BTreeSet::new(); - set.insert(D(0)); - set.insert(D(4)); - set.insert(D(8)); + set.insert(a.spawn(Panic::Never)); + set.insert(b.spawn(Panic::InDrop)); + set.insert(c.spawn(Panic::Never)); - catch_unwind(move || { - drop(set.drain_filter(|d| { - PREDS.fetch_add(1u32 << d.0, SeqCst); - true - })) - }) - .ok(); + catch_unwind(move || drop(set.drain_filter(|dummy| dummy.query(true)))).ok(); - assert_eq!(PREDS.load(SeqCst), 0x011); - assert_eq!(DROPS.load(SeqCst), 3); + assert_eq!(a.queried(), 1); + assert_eq!(b.queried(), 1); + assert_eq!(c.queried(), 0); + assert_eq!(a.dropped(), 1); + assert_eq!(b.dropped(), 1); + assert_eq!(c.dropped(), 1); } #[test] fn test_drain_filter_pred_panic_leak() { - static PREDS: AtomicU32 = AtomicU32::new(0); - static DROPS: AtomicU32 = AtomicU32::new(0); - - #[derive(PartialEq, Eq, PartialOrd, Ord)] - struct D(i32); - impl Drop for D { - fn drop(&mut self) { - DROPS.fetch_add(1, SeqCst); - } - } - + let a = CrashTestDummy::new(0); + let b = CrashTestDummy::new(1); + let c = CrashTestDummy::new(2); let mut set = BTreeSet::new(); - set.insert(D(0)); - set.insert(D(4)); - set.insert(D(8)); + set.insert(a.spawn(Panic::Never)); + set.insert(b.spawn(Panic::InQuery)); + set.insert(c.spawn(Panic::InQuery)); - catch_unwind(AssertUnwindSafe(|| { - drop(set.drain_filter(|d| { - PREDS.fetch_add(1u32 << d.0, SeqCst); - match d.0 { - 0 => true, - _ => panic!(), - } - })) - })) - .ok(); + catch_unwind(AssertUnwindSafe(|| drop(set.drain_filter(|dummy| dummy.query(true))))).ok(); - assert_eq!(PREDS.load(SeqCst), 0x011); - assert_eq!(DROPS.load(SeqCst), 1); + assert_eq!(a.queried(), 1); + assert_eq!(b.queried(), 1); + assert_eq!(c.queried(), 0); + assert_eq!(a.dropped(), 1); + assert_eq!(b.dropped(), 0); + assert_eq!(c.dropped(), 0); assert_eq!(set.len(), 2); - assert_eq!(set.first().unwrap().0, 4); - assert_eq!(set.last().unwrap().0, 8); + assert_eq!(set.first().unwrap().id(), 1); + assert_eq!(set.last().unwrap().id(), 2); } #[test] diff --git a/library/alloc/src/collections/btree/testing/crash_test.rs b/library/alloc/src/collections/btree/testing/crash_test.rs new file mode 100644 index 00000000000..b2527b95f5b --- /dev/null +++ b/library/alloc/src/collections/btree/testing/crash_test.rs @@ -0,0 +1,119 @@ +use crate::fmt::Debug; +use std::cmp::Ordering; +use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; + +/// A blueprint for crash test dummy instances that monitor particular events. +/// Some instances may be configured to panic at some point. +/// Events are `clone`, `drop` or some anonymous `query`. +/// +/// Crash test dummies are identified and ordered by an id, so they can be used +/// as keys in a BTreeMap. The implementation intentionally uses does not rely +/// on anything defined in the crate, apart from the `Debug` trait. +#[derive(Debug)] +pub struct CrashTestDummy { + id: usize, + cloned: AtomicUsize, + dropped: AtomicUsize, + queried: AtomicUsize, +} + +impl CrashTestDummy { + /// Creates a crash test dummy design. The `id` determines order and equality of instances. + pub fn new(id: usize) -> CrashTestDummy { + CrashTestDummy { + id, + cloned: AtomicUsize::new(0), + dropped: AtomicUsize::new(0), + queried: AtomicUsize::new(0), + } + } + + /// Creates an instance of a crash test dummy that records what events it experiences + /// and optionally panics. + pub fn spawn(&self, panic: Panic) -> Instance<'_> { + Instance { origin: self, panic } + } + + /// Returns how many times instances of the dummy have been cloned. + pub fn cloned(&self) -> usize { + self.cloned.load(SeqCst) + } + + /// Returns how many times instances of the dummy have been dropped. + pub fn dropped(&self) -> usize { + self.dropped.load(SeqCst) + } + + /// Returns how many times instances of the dummy have had their `query` member invoked. + pub fn queried(&self) -> usize { + self.queried.load(SeqCst) + } +} + +#[derive(Debug)] +pub struct Instance<'a> { + origin: &'a CrashTestDummy, + panic: Panic, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum Panic { + Never, + InClone, + InDrop, + InQuery, +} + +impl Instance<'_> { + pub fn id(&self) -> usize { + self.origin.id + } + + /// Some anonymous query, the result of which is already given. + pub fn query(&self, result: R) -> R { + self.origin.queried.fetch_add(1, SeqCst); + if self.panic == Panic::InQuery { + panic!("panic in `query`"); + } + result + } +} + +impl Clone for Instance<'_> { + fn clone(&self) -> Self { + self.origin.cloned.fetch_add(1, SeqCst); + if self.panic == Panic::InClone { + panic!("panic in `clone`"); + } + Self { origin: self.origin, panic: Panic::Never } + } +} + +impl Drop for Instance<'_> { + fn drop(&mut self) { + self.origin.dropped.fetch_add(1, SeqCst); + if self.panic == Panic::InDrop { + panic!("panic in `drop`"); + } + } +} + +impl PartialOrd for Instance<'_> { + fn partial_cmp(&self, other: &Self) -> Option { + self.id().partial_cmp(&other.id()) + } +} + +impl Ord for Instance<'_> { + fn cmp(&self, other: &Self) -> Ordering { + self.id().cmp(&other.id()) + } +} + +impl PartialEq for Instance<'_> { + fn eq(&self, other: &Self) -> bool { + self.id().eq(&other.id()) + } +} + +impl Eq for Instance<'_> {} diff --git a/library/alloc/src/collections/btree/testing/mod.rs b/library/alloc/src/collections/btree/testing/mod.rs index 03880e7014e..7a094f8a595 100644 --- a/library/alloc/src/collections/btree/testing/mod.rs +++ b/library/alloc/src/collections/btree/testing/mod.rs @@ -1,2 +1,3 @@ +pub mod crash_test; pub mod ord_chaos; pub mod rng;