use crate::Wrc;
use std::cell::Cell;
struct Canary<'a>(&'a Cell<usize>);
impl<'a> Drop for Canary<'a> {
fn drop(&mut self) {
let drop_count = self.0.get();
self.0.set(drop_count + 1);
}
}
#[test]
fn initializes_with_default_weight() {
let wrc = Wrc::new(5);
assert_eq!(wrc.local_weight(), 1 << 16);
assert_eq!(Wrc::total_weight(&wrc), 1 << 16);
}
#[test]
fn clone_splits_weight() {
let wrc0 = Wrc::new(5);
assert_eq!(wrc0.local_weight(), 1 << 16);
let wrc1 = wrc0.clone();
assert_eq!(
wrc0.local_weight() + wrc1.local_weight(),
Wrc::total_weight(&wrc0)
);
}
#[allow(clippy::redundant_clone)]
#[test]
fn more_weight_is_allocated_with_weight_exhausted() {
let wrc0 = Wrc::new(5);
let wrc1 = wrc0
.clone()
.clone()
.clone()
.clone()
.clone()
.clone()
.clone()
.clone()
.clone()
.clone()
.clone()
.clone()
.clone()
.clone()
.clone()
.clone();
assert_eq!(wrc1.local_weight(), 1);
assert_eq!(Wrc::total_weight(&wrc0), (1 << 15) + 1);
let wrc2 = wrc1.clone();
assert_eq!(wrc1.local_weight(), 1);
assert_eq!(wrc2.local_weight(), 1 << 16);
assert_eq!(Wrc::total_weight(&wrc0), (1 << 15) + 1 + (1 << 16));
}
#[test]
fn dropping_refs_drops_weight_from_inner() {
let wrc0 = Wrc::new(5);
let wrc1 = wrc0.clone();
let wrc2 = wrc1.clone();
let wrc3 = wrc2.clone();
assert_eq!(wrc0.local_weight(), 1 << 15);
assert_eq!(wrc1.local_weight(), 1 << 14);
assert_eq!(wrc2.local_weight(), 1 << 13);
assert_eq!(wrc3.local_weight(), 1 << 13);
assert_eq!(Wrc::total_weight(&wrc0), 1 << 16);
drop(wrc3);
assert_eq!(Wrc::total_weight(&wrc0), (1 << 16) - (1 << 13));
drop(wrc2);
assert_eq!(Wrc::total_weight(&wrc0), (1 << 16) - (1 << 14));
drop(wrc1);
assert_eq!(Wrc::total_weight(&wrc0), 1 << 15);
}
#[test]
fn dropping_all_refs_drops_the_inner() {
let drop_count = Cell::new(0);
let wrc0 = Wrc::new(Canary(&drop_count));
let wrc1 = wrc0.clone();
assert_eq!(drop_count.get(), 0);
drop(wrc0);
assert_eq!(drop_count.get(), 0);
drop(wrc1);
assert_eq!(drop_count.get(), 1);
}
#[test]
fn get_mut_succeeds_when_unique() {
let mut wrc = Wrc::new(5);
{
let mutref = Wrc::get_mut(&mut wrc).unwrap();
*mutref = 13;
}
assert_eq!(*wrc, 13);
}
#[test]
fn get_mut_fails_when_not_unique() {
let mut wrc = Wrc::new(5);
let _wrc2 = wrc.clone();
assert!(Wrc::get_mut(&mut wrc).is_none());
}
#[test]
fn get_mut_fails_when_weak_exists() {
let mut wrc = Wrc::new(5);
let _weak = Wrc::downgrade(&wrc);
assert!(Wrc::get_mut(&mut wrc).is_none());
}
#[test]
fn weak_upgrade_succeeds_while_strong_exists() {
let wrc = Wrc::new(5);
let weak = Wrc::downgrade(&wrc);
assert_eq!(*weak.upgrade().unwrap(), 5);
}
#[test]
fn weak_upgrade_fails_after_strong_dropped() {
let wrc = Wrc::new(5);
let weak = Wrc::downgrade(&wrc);
drop(wrc);
assert!(weak.upgrade().is_none());
}
#[test]
fn weak_does_not_prevent_data_drop() {
let drop_count = Cell::new(0);
let wrc = Wrc::new(Canary(&drop_count));
let weak = Wrc::downgrade(&wrc);
assert_eq!(drop_count.get(), 0);
drop(wrc);
assert_eq!(drop_count.get(), 1);
assert!(weak.upgrade().is_none());
}
#[test]
fn weak_clone_works() {
let wrc = Wrc::new(5);
let weak1 = Wrc::downgrade(&wrc);
let weak2 = weak1.clone();
assert_eq!(*weak1.upgrade().unwrap(), 5);
assert_eq!(*weak2.upgrade().unwrap(), 5);
}
#[test]
fn multiple_weak_refs_can_exist() {
let drop_count = Cell::new(0);
let wrc = Wrc::new(Canary(&drop_count));
let weak1 = Wrc::downgrade(&wrc);
let weak2 = Wrc::downgrade(&wrc);
let weak3 = weak1.clone();
drop(wrc);
assert_eq!(drop_count.get(), 1);
assert!(weak1.upgrade().is_none());
assert!(weak2.upgrade().is_none());
assert!(weak3.upgrade().is_none());
}