use std::rc::{Rc, Weak};
use dendron::HotNode;
const MIN_DROP_DEPTH: usize = 140_000;
#[allow(dead_code)]
fn should_cause_stack_overflow_due_to_large_min_drop_depth() {
enum SimplifiedNode {
Leaf(Rc<()>),
Node(Box<SimplifiedNode>, Rc<()>),
}
let (counter, node_data) = create_counter(());
let mut head = SimplifiedNode::Leaf(node_data.clone());
for _ in 1..MIN_DROP_DEPTH {
head = SimplifiedNode::Node(Box::new(head), node_data.clone());
}
drop(node_data);
assert_eq!(counter.strong_count(), MIN_DROP_DEPTH);
drop(head);
assert_eq!(counter.strong_count(), 0);
panic!("this test should crash by stack overflow, but did not");
}
#[must_use]
fn create_counter<T>(v: T) -> (Weak<T>, Rc<T>) {
let rc = Rc::new(v);
let weak = Rc::downgrade(&rc);
(weak, rc)
}
#[test]
fn drop_single_node_tree() {
let (counter, root_data) = create_counter(());
let root = HotNode::new_tree(root_data);
assert_eq!(counter.strong_count(), 1, "only the root node exists");
assert!(root.is_root());
drop(root);
assert_eq!(counter.strong_count(), 0, "the tree should not leak");
}
#[test]
fn drop_nested_node_tree() {
let (counter, node_data) = create_counter(());
let root = HotNode::new_tree(node_data.clone());
let child0 = root.create_as_last_child(node_data.clone());
let child1 = root.create_as_last_child(node_data.clone());
let child0_0 = child0.create_as_last_child(node_data);
assert_eq!(counter.strong_count(), 4, "there are four nodes");
drop(root);
assert_eq!(
counter.strong_count(),
4,
"no nodes should be destructed since other nodes in the tree are still alive"
);
drop(child0);
assert_eq!(
counter.strong_count(),
4,
"no nodes should be destructed since other nodes in the tree are still alive"
);
drop(child1);
assert_eq!(
counter.strong_count(),
4,
"no nodes should be destructed since `child0_0` in the same tree is still alive"
);
drop(child0_0);
assert_eq!(
counter.strong_count(),
0,
"now the user cannot refer any nodes in the tree, so all nodes are released"
);
}
#[test]
fn drop_detached_tree() {
let (counter, node_data) = create_counter(());
let root = HotNode::new_tree(node_data.clone());
let child0 = root.create_as_last_child(node_data.clone());
let child1 = root.create_as_last_child(node_data.clone());
let child0_0 = child0.create_as_last_child(node_data.clone());
let child0_1 = child0.create_as_last_child(node_data.clone());
let child1_0 = child1.create_as_last_child(node_data);
assert_eq!(counter.strong_count(), 6, "there are six nodes");
assert!(HotNode::ptr_eq(&root.root(), &root));
assert!(HotNode::ptr_eq(&child0.root(), &root));
assert!(HotNode::ptr_eq(&child1.root(), &root));
assert!(HotNode::ptr_eq(&child0_0.root(), &root));
assert!(HotNode::ptr_eq(&child0_1.root(), &root));
assert!(HotNode::ptr_eq(&child1_0.root(), &root));
assert!(root.is_root());
assert!(!child0.is_root());
assert!(!child1.is_root());
assert!(!child0_0.is_root());
assert!(!child0_1.is_root());
assert!(!child1_0.is_root());
child0.detach_subtree();
assert_eq!(counter.strong_count(), 6, "there are still six nodes");
assert!(HotNode::ptr_eq(&root.root(), &root));
assert!(HotNode::ptr_eq(&child1.root(), &root));
assert!(HotNode::ptr_eq(&child1_0.root(), &root));
assert!(HotNode::ptr_eq(&child0.root(), &child0));
assert!(HotNode::ptr_eq(&child0_0.root(), &child0));
assert!(HotNode::ptr_eq(&child0_1.root(), &child0));
assert!(root.is_root());
assert!(!child1.is_root());
assert!(!child1_0.is_root());
assert!(child0.is_root(), "child0 is now the root of a new tree");
assert!(!child0_0.is_root());
assert!(!child0_1.is_root());
drop(root);
assert_eq!(counter.strong_count(), 6, "there are still six nodes");
assert!(!child1.is_root());
assert!(!child1_0.is_root());
drop(child1);
assert_eq!(counter.strong_count(), 6, "there are still six nodes");
assert!(!child1_0.is_root());
drop(child1_0);
assert_eq!(
counter.strong_count(),
3,
"`root`, `child1`, and `child1_0` are released"
);
drop(child0);
assert_eq!(counter.strong_count(), 3, "there are still three nodes");
assert!(!child0_0.is_root());
assert!(!child0_1.is_root());
drop(child0_1);
assert_eq!(counter.strong_count(), 3, "there are still three nodes");
assert!(!child0_0.is_root());
drop(child0_0);
assert_eq!(counter.strong_count(), 0, "all nodes are now unreachable");
}
#[test]
fn drop_very_deep_tree() {
let (counter, node_data) = create_counter(());
let root = HotNode::new_tree(node_data.clone());
{
let mut current = root.clone();
for _ in 1..MIN_DROP_DEPTH {
current = current.create_as_last_child(node_data.clone());
}
drop(node_data);
}
assert_eq!(
counter.strong_count(),
MIN_DROP_DEPTH,
"there should be {MIN_DROP_DEPTH} nodes"
);
drop(root);
assert_eq!(
counter.strong_count(),
0,
"the entire tree is now dropped without causing stack overflow"
);
}
#[test]
fn drop_very_wide_tree() {
let (counter, node_data) = create_counter(());
let root = HotNode::new_tree(node_data.clone());
for _ in 0..MIN_DROP_DEPTH {
root.create_as_last_child(node_data.clone());
}
drop(node_data);
assert_eq!(
counter.strong_count(),
MIN_DROP_DEPTH + 1,
"there should be a root and {MIN_DROP_DEPTH} children"
);
drop(root);
assert_eq!(
counter.strong_count(),
0,
"the entire tree is now dropped without causing stack overflow"
);
}