use std::cell::{Cell, RefCell};
use std::collections::HashSet;
#[derive(Default, Debug)]
pub struct TestDrop {
id: Cell<usize>,
drops: RefCell<HashSet<usize>>,
}
impl TestDrop {
pub fn new() -> TestDrop {
TestDrop::default()
}
pub fn new_item(&self) -> (usize, Item) {
let id = self.id.get();
self.id.set(id + 1);
(id,
Item {
id: id,
parent: self,
})
}
pub fn num_tracked_items(&self) -> usize {
self.id.get()
}
pub fn num_dropped_items(&self) -> usize {
self.drops.borrow().len()
}
pub fn assert_drop(&self, id: usize) {
assert!(self.drops.borrow().contains(&id),
"{} should be dropped, but was not",
id);
}
pub fn assert_no_drop(&self, id: usize) {
assert!(!self.drops.borrow().contains(&id),
"{} should not be dropped, but was",
id);
}
fn add_drop(&self, id: usize) {
if !self.drops.borrow_mut().insert(id) {
panic!("{} is already dropped", id)
}
}
}
#[derive(Debug)]
pub struct Item<'a> {
id: usize,
parent: &'a TestDrop,
}
impl<'a> PartialEq for Item<'a> {
fn eq(&self, other: &Self) -> bool {
self.id == other.id && self.parent as *const _ == other.parent as *const _
}
}
impl<'a> Drop for Item<'a> {
fn drop(&mut self) {
self.parent.add_drop(self.id)
}
}
impl<'a> Item<'a> {
pub fn id(&self) -> usize {
self.id
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[should_panic(expected = "0 should be dropped, but was not")]
fn assert_drop() {
let td = TestDrop::new();
let (id, _item) = td.new_item();
td.assert_drop(id);
}
#[test]
#[should_panic(expected = "0 should not be dropped, but was")]
fn assert_no_drop() {
let td = TestDrop::new();
let (id, item) = td.new_item();
drop(item);
td.assert_no_drop(id);
}
#[test]
#[should_panic(expected = "0 is already dropped")]
fn drop_more_than_once() {
let td = TestDrop::new();
let (_, a) = td.new_item();
unsafe { ::std::ptr::read(&a as *const _) };
}
#[test]
fn count() {
let td = TestDrop::new();
assert_eq!(0, td.num_tracked_items());
assert_eq!(0, td.num_dropped_items());
let (_, a) = td.new_item();
let (_, b) = td.new_item();
assert_eq!(2, td.num_tracked_items());
assert_eq!(0, td.num_dropped_items());
drop(a);
assert_eq!(2, td.num_tracked_items());
assert_eq!(1, td.num_dropped_items());
drop(b);
assert_eq!(2, td.num_tracked_items());
assert_eq!(2, td.num_dropped_items());
}
}