#![cfg(test)]
use crate::DropTracker;
use crate::State::Alive;
use crate::State::Dropped;
use std::collections::HashSet;
use std::mem::ManuallyDrop;
use std::panic::UnwindSafe;
use std::panic;
#[test]
fn state() {
let mut tracker = DropTracker::new();
let item = tracker.track(123);
assert_eq!(tracker.state(&123), Alive);
assert!(tracker.state(&123).is_alive());
assert!(!tracker.state(&123).is_dropped());
drop(item);
assert_eq!(tracker.state(&123), Dropped);
assert!(!tracker.state(&123).is_alive());
assert!(tracker.state(&123).is_dropped());
}
#[test]
fn iterators() {
let mut tracker = DropTracker::new();
assert_eq!(tracker.tracked().copied().collect::<HashSet<_>>(),
HashSet::from([]));
assert_eq!(tracker.alive().copied().collect::<HashSet<_>>(),
HashSet::from([]));
assert_eq!(tracker.dropped().copied().collect::<HashSet<_>>(),
HashSet::from([]));
let item1 = tracker.track(1);
let item2 = tracker.track(2);
let item3 = tracker.track(3);
let item4 = tracker.track(4);
let item5 = tracker.track(5);
assert_eq!(tracker.tracked().copied().collect::<HashSet<_>>(),
HashSet::from([1, 2, 3, 4, 5]));
assert_eq!(tracker.alive().copied().collect::<HashSet<_>>(),
HashSet::from([1, 2, 3, 4, 5]));
assert_eq!(tracker.dropped().copied().collect::<HashSet<_>>(),
HashSet::from([]));
drop(item1);
drop(item2);
assert_eq!(tracker.tracked().copied().collect::<HashSet<_>>(),
HashSet::from([1, 2, 3, 4, 5]));
assert_eq!(tracker.alive().copied().collect::<HashSet<_>>(),
HashSet::from([3, 4, 5]));
assert_eq!(tracker.dropped().copied().collect::<HashSet<_>>(),
HashSet::from([1, 2]));
drop(item3);
drop(item4);
assert_eq!(tracker.tracked().copied().collect::<HashSet<_>>(),
HashSet::from([1, 2, 3, 4, 5]));
assert_eq!(tracker.alive().copied().collect::<HashSet<_>>(),
HashSet::from([5]));
assert_eq!(tracker.dropped().copied().collect::<HashSet<_>>(),
HashSet::from([1, 2, 3, 4]));
drop(item5);
assert_eq!(tracker.tracked().copied().collect::<HashSet<_>>(),
HashSet::from([1, 2, 3, 4, 5]));
assert_eq!(tracker.alive().copied().collect::<HashSet<_>>(),
HashSet::from([]));
assert_eq!(tracker.dropped().copied().collect::<HashSet<_>>(),
HashSet::from([1, 2, 3, 4, 5]));
}
#[test]
fn forget_dropped() {
let mut tracker = DropTracker::new();
tracker.forget_dropped();
assert_eq!(tracker.tracked().copied().collect::<HashSet<_>>(),
HashSet::from([]));
assert_eq!(tracker.alive().copied().collect::<HashSet<_>>(),
HashSet::from([]));
assert_eq!(tracker.dropped().copied().collect::<HashSet<_>>(),
HashSet::from([]));
let item1 = tracker.track(1);
let item2 = tracker.track(2);
let item3 = tracker.track(3);
let item4 = tracker.track(4);
let item5 = tracker.track(5);
tracker.forget_dropped();
assert_eq!(tracker.tracked().copied().collect::<HashSet<_>>(),
HashSet::from([1, 2, 3, 4, 5]));
assert_eq!(tracker.alive().copied().collect::<HashSet<_>>(),
HashSet::from([1, 2, 3, 4, 5]));
assert_eq!(tracker.dropped().copied().collect::<HashSet<_>>(),
HashSet::from([]));
drop(item1);
drop(item2);
tracker.forget_dropped();
assert_eq!(tracker.tracked().copied().collect::<HashSet<_>>(),
HashSet::from([3, 4, 5]));
assert_eq!(tracker.alive().copied().collect::<HashSet<_>>(),
HashSet::from([3, 4, 5]));
assert_eq!(tracker.dropped().copied().collect::<HashSet<_>>(),
HashSet::from([]));
drop(item3);
drop(item4);
tracker.forget_dropped();
assert_eq!(tracker.tracked().copied().collect::<HashSet<_>>(),
HashSet::from([5]));
assert_eq!(tracker.alive().copied().collect::<HashSet<_>>(),
HashSet::from([5]));
assert_eq!(tracker.dropped().copied().collect::<HashSet<_>>(),
HashSet::from([]));
drop(item5);
tracker.forget_dropped();
assert_eq!(tracker.tracked().copied().collect::<HashSet<_>>(),
HashSet::from([]));
assert_eq!(tracker.alive().copied().collect::<HashSet<_>>(),
HashSet::from([]));
assert_eq!(tracker.dropped().copied().collect::<HashSet<_>>(),
HashSet::from([]));
}
fn catch_panic_error<F: FnOnce() + UnwindSafe>(f: F) -> String {
let err = panic::catch_unwind(f)
.expect_err("expected a panic");
if let Some(s) = err.downcast_ref::<&str>() {
s.to_string()
} else if let Some(s) = err.downcast_ref::<String>() {
s.clone()
} else {
panic!("expected the panic payload to be a string");
}
}
#[test]
fn state_errors() {
let mut tracker = DropTracker::new();
let item = tracker.track(());
let state = tracker.state(&());
let err = state.dropped()
.expect_err("item is expected to be alive");
assert_eq!(err.to_string(), "item is alive");
let panic_err = catch_panic_error(move || state.dropped().expect("foo"));
assert_eq!(panic_err, "foo: AliveError");
drop(item);
let state = tracker.state(&());
let err = state.alive()
.expect_err("item is expected to be dropped");
assert_eq!(err.to_string(), "item is dropped");
let panic_err = catch_panic_error(move || state.alive().expect("foo"));
assert_eq!(panic_err, "foo: DroppedError");
}
#[test]
fn all_alive() {
let mut tracker = DropTracker::new();
let item1 = tracker.track(1);
let item2 = tracker.track(2);
let item3 = tracker.track(3);
let item4 = tracker.track(4);
drop(item3);
drop(item4);
let res = tracker.all_alive([&1, &2]);
assert_eq!(res, Ok(()));
let err = tracker.all_alive([&1, &2, &3, &4, &5, &6])
.expect_err("not all items are expected to be alive");
assert_eq!(err.dropped, [&3, &4]);
assert_eq!(err.untracked, [&5, &6]);
assert_eq!(err.to_string(), "not all items are alive: dropped: [3, 4], not tracked: [5, 6]");
let res = tracker.all_alive([&1, &2, &3, &4, &5, &6]);
let panic_err = catch_panic_error(move || res.expect("foo"));
assert_eq!(panic_err, "foo: NotAllAliveError { dropped: [3, 4], untracked: [5, 6] }");
drop(item1);
drop(item2);
}
#[test]
fn all_dropped() {
let mut tracker = DropTracker::new();
let item1 = tracker.track(1);
let item2 = tracker.track(2);
let item3 = tracker.track(3);
let item4 = tracker.track(4);
drop(item3);
drop(item4);
let res = tracker.all_dropped([&3, &4]);
assert_eq!(res, Ok(()));
let err = tracker.all_dropped([&1, &2, &3, &4, &5, &6])
.expect_err("not all items are expected to be dropped");
assert_eq!(err.alive, [&1, &2]);
assert_eq!(err.untracked, [&5, &6]);
assert_eq!(err.to_string(), "not all items are dropped: alive: [1, 2], not tracked: [5, 6]");
let res = tracker.all_dropped([&1, &2, &3, &4, &5, &6]);
let panic_err = catch_panic_error(move || res.expect("foo"));
assert_eq!(panic_err, "foo: NotAllDroppedError { alive: [1, 2], untracked: [5, 6] }");
drop(item1);
drop(item2);
}
#[test]
fn double_drop() {
let mut tracker = DropTracker::new();
let mut item = ManuallyDrop::new(tracker.track(()));
tracker.state(&()).alive().expect("item should be alive");
unsafe { ManuallyDrop::drop(&mut item); }
tracker.state(&()).dropped().expect("item should be dropped");
let panic_err = catch_panic_error(panic::AssertUnwindSafe(
|| unsafe { ManuallyDrop::drop(&mut item) }
));
assert_eq!(panic_err, "item dropped twice");
}
#[test]
fn assertions() {
let mut tracker = DropTracker::new();
tracker.assert_all_alive([0u32; 0]);
tracker.assert_all_dropped([0u32; 0]);
tracker.assert_fully_alive();
tracker.assert_fully_dropped();
let panic_err = catch_panic_error(|| tracker.assert_alive(&1));
assert_eq!(panic_err, "item is not tracked");
let panic_err = catch_panic_error(|| tracker.assert_dropped(&1));
assert_eq!(panic_err, "item is not tracked");
let panic_err = catch_panic_error(|| tracker.assert_all_alive([1]));
assert_eq!(panic_err, "not all items are alive: not tracked: [1]");
let panic_err = catch_panic_error(|| tracker.assert_all_dropped([1]));
assert_eq!(panic_err, "not all items are dropped: not tracked: [1]");
let item = tracker.track(1);
tracker.assert_alive(&1);
tracker.assert_all_alive([1]);
tracker.assert_fully_alive();
let panic_err = catch_panic_error(|| tracker.assert_dropped(&1));
assert_eq!(panic_err, "item is alive");
let panic_err = catch_panic_error(|| tracker.assert_all_dropped([1]));
assert_eq!(panic_err, "not all items are dropped: alive: [1]");
let panic_err = catch_panic_error(|| tracker.assert_fully_dropped());
assert_eq!(panic_err, "item is alive: 1");
drop(item);
tracker.assert_dropped(&1);
tracker.assert_all_dropped([1]);
tracker.assert_fully_dropped();
let panic_err = catch_panic_error(|| tracker.assert_alive(&1));
assert_eq!(panic_err, "item is dropped");
let panic_err = catch_panic_error(|| tracker.assert_all_alive([1]));
assert_eq!(panic_err, "not all items are alive: dropped: [1]");
let panic_err = catch_panic_error(|| tracker.assert_fully_alive());
assert_eq!(panic_err, "item is dropped: 1");
}
#[test]
fn primitive_eq() {
assert_eq!(DropTracker::new().track(123i8), 123i8);
assert_eq!(DropTracker::new().track(123i16), 123i16);
assert_eq!(DropTracker::new().track(123i32), 123i32);
assert_eq!(DropTracker::new().track(123i64), 123i64);
assert_eq!(DropTracker::new().track(123i128), 123i128);
assert_eq!(DropTracker::new().track(123u8), 123u8);
assert_eq!(DropTracker::new().track(123u16), 123u16);
assert_eq!(DropTracker::new().track(123u32), 123u32);
assert_eq!(DropTracker::new().track(123u64), 123u64);
assert_eq!(DropTracker::new().track(123u128), 123u128);
assert_eq!(DropTracker::new().track_with_value('a', 123f32), 123f32);
assert_eq!(DropTracker::new().track_with_value('b', 123f64), 123f64);
assert_eq!(DropTracker::new().track('x'), 'x');
assert_eq!(DropTracker::new().track(true), true);
assert_eq!(DropTracker::new().track(false), false);
assert_eq!(DropTracker::new().track(()), ());
assert_eq!(DropTracker::new().track("abc"), "abc");
assert_eq!(DropTracker::new().track("abc".to_owned()), "abc");
assert_eq!(DropTracker::new().track([1, 2, 3]), [1, 2, 3][..]);
assert_eq!(DropTracker::new().track(vec![1, 2, 3]), [1, 2, 3][..]);
}
#[test]
fn primitive_ne() {
assert_ne!(DropTracker::new().track(123i8), 100i8);
assert_ne!(DropTracker::new().track(123i16), 100i16);
assert_ne!(DropTracker::new().track(123i32), 100i32);
assert_ne!(DropTracker::new().track(123i64), 100i64);
assert_ne!(DropTracker::new().track(123i128), 100i128);
assert_ne!(DropTracker::new().track(123u8), 100u8);
assert_ne!(DropTracker::new().track(123u16), 100u16);
assert_ne!(DropTracker::new().track(123u32), 100u32);
assert_ne!(DropTracker::new().track(123u64), 100u64);
assert_ne!(DropTracker::new().track(123u128), 100u128);
assert_ne!(DropTracker::new().track_with_value('a', 123f32), 100f32);
assert_ne!(DropTracker::new().track_with_value('b', 123f64), 100f64);
assert_ne!(DropTracker::new().track('x'), 'y');
assert_ne!(DropTracker::new().track(true), false);
assert_ne!(DropTracker::new().track(false), true);
assert_ne!(DropTracker::new().track("abc"), "def");
assert_ne!(DropTracker::new().track("abc".to_owned()), "def");
assert_ne!(DropTracker::new().track([1, 2, 3]), [4, 5, 6][..]);
assert_ne!(DropTracker::new().track(vec![1, 2, 3]), [4, 5, 6][..]);
}
#[test]
fn primitive_lt() {
assert!(DropTracker::new().track(123i8) < 127i8);
assert!(DropTracker::new().track(123i16) < 200i16);
assert!(DropTracker::new().track(123i32) < 200i32);
assert!(DropTracker::new().track(123i64) < 200i64);
assert!(DropTracker::new().track(123i128) < 200i128);
assert!(DropTracker::new().track(123u8) < 200u8);
assert!(DropTracker::new().track(123u16) < 200u16);
assert!(DropTracker::new().track(123u32) < 200u32);
assert!(DropTracker::new().track(123u64) < 200u64);
assert!(DropTracker::new().track(123u128) < 200u128);
assert!(DropTracker::new().track_with_value('a', 123f32) < 200f32);
assert!(DropTracker::new().track_with_value('b', 123f64) < 200f64);
assert!(DropTracker::new().track('x') < 'y');
assert!(DropTracker::new().track(false) < true);
}
#[test]
fn primitive_gt() {
assert!(DropTracker::new().track(123i8) > 100i8);
assert!(DropTracker::new().track(123i16) > 100i16);
assert!(DropTracker::new().track(123i32) > 100i32);
assert!(DropTracker::new().track(123i64) > 100i64);
assert!(DropTracker::new().track(123i128) > 100i128);
assert!(DropTracker::new().track(123u8) > 100u8);
assert!(DropTracker::new().track(123u16) > 100u16);
assert!(DropTracker::new().track(123u32) > 100u32);
assert!(DropTracker::new().track(123u64) > 100u64);
assert!(DropTracker::new().track(123u128) > 100u128);
assert!(DropTracker::new().track_with_value('a', 123f32) > 100f32);
assert!(DropTracker::new().track_with_value('b', 123f64) > 100f64);
assert!(DropTracker::new().track('x') > 'w');
assert!(DropTracker::new().track(true) > false);
}