#![allow(clippy::drop_non_drop)]
use ferntree::Tree;
use std::sync::Arc;
use std::thread;
fn force_epoch_advancement() {
for _ in 0..10 {
let _guard = crossbeam_epoch::pin();
std::thread::yield_now();
}
}
#[test]
fn no_leak_after_insert_remove_all() {
let tree: Tree<i32, i32> = Tree::new();
for i in 0..1000 {
tree.insert(i, i);
}
for i in 0..1000 {
tree.remove(&i);
}
assert!(tree.is_empty());
drop(tree);
force_epoch_advancement();
}
#[test]
fn no_leak_after_clear() {
let tree: Tree<i32, i32> = Tree::new();
for i in 0..1000 {
tree.insert(i, i);
}
assert!(tree.height() > 1);
tree.clear();
assert!(tree.is_empty());
assert_eq!(tree.height(), 1);
drop(tree);
force_epoch_advancement();
}
#[test]
fn no_leak_repeated_updates() {
let tree: Tree<i32, String> = Tree::new();
for i in 0..1000 {
tree.insert(1, format!("value_{}", i));
}
assert_eq!(tree.len(), 1);
drop(tree);
force_epoch_advancement();
}
#[test]
fn no_leak_after_splits() {
let tree: Tree<i32, i32> = Tree::new();
for i in 0..5000 {
tree.insert(i, i);
}
assert!(tree.height() >= 3);
drop(tree);
force_epoch_advancement();
}
#[test]
fn no_leak_after_merges() {
let tree: Tree<i32, i32> = Tree::new();
for i in 0..1000 {
tree.insert(i, i);
}
for i in (0..1000).step_by(2) {
tree.remove(&i);
}
drop(tree);
force_epoch_advancement();
}
#[test]
fn no_leak_concurrent_inserts() {
let tree = Arc::new(Tree::<i32, i32>::new());
let handles: Vec<_> = (0..4)
.map(|t| {
let tree = Arc::clone(&tree);
thread::spawn(move || {
for i in 0..250 {
let key = t * 250 + i;
tree.insert(key, key);
}
})
})
.collect();
for h in handles {
h.join().unwrap();
}
assert_eq!(tree.len(), 1000);
drop(tree);
force_epoch_advancement();
}
#[test]
fn no_leak_concurrent_insert_remove() {
let tree = Arc::new(Tree::<i32, i32>::new());
let handles: Vec<_> = (0..4)
.map(|t| {
let tree = Arc::clone(&tree);
thread::spawn(move || {
for i in 0..250 {
let key = t * 250 + i;
tree.insert(key, key);
}
for i in 0..250 {
let key = t * 250 + i;
tree.remove(&key);
}
})
})
.collect();
for h in handles {
h.join().unwrap();
}
assert!(tree.is_empty());
drop(tree);
force_epoch_advancement();
}
#[test]
fn no_leak_concurrent_updates() {
let tree = Arc::new(Tree::<i32, i32>::new());
for i in 0..100 {
tree.insert(i, 0);
}
let handles: Vec<_> = (0..4)
.map(|t| {
let tree = Arc::clone(&tree);
thread::spawn(move || {
for iter in 0..100 {
for key in 0..100 {
tree.insert(key, t * 100 + iter);
}
}
})
})
.collect();
for h in handles {
h.join().unwrap();
}
assert_eq!(tree.len(), 100);
drop(tree);
force_epoch_advancement();
}
#[test]
fn no_leak_iterator_early_drop() {
let tree: Tree<i32, i32> = Tree::new();
for i in 0..100 {
tree.insert(i, i);
}
{
let mut iter = tree.raw_iter();
iter.seek_to_first();
for _ in 0..50 {
let _ = iter.next();
}
}
assert_eq!(tree.len(), 100);
drop(tree);
force_epoch_advancement();
}
#[test]
fn no_leak_multiple_iterators() {
let tree: Tree<i32, i32> = Tree::new();
for i in 0..100 {
tree.insert(i, i);
}
for _ in 0..10 {
let mut iter = tree.raw_iter();
iter.seek_to_first();
while iter.next().is_some() {}
}
drop(tree);
force_epoch_advancement();
}
#[test]
fn no_leak_mutable_iterator() {
let tree: Tree<i32, i32> = Tree::new();
for i in 0..100 {
tree.insert(i, i);
}
{
let mut iter = tree.raw_iter_mut();
iter.seek_to_first();
while let Some((_, v)) = iter.next() {
*v *= 2;
}
}
drop(tree);
force_epoch_advancement();
}
#[test]
fn no_leak_empty_tree() {
let tree: Tree<i32, i32> = Tree::new();
drop(tree);
force_epoch_advancement();
}
#[test]
fn no_leak_single_element() {
let tree: Tree<i32, i32> = Tree::new();
tree.insert(1, 1);
drop(tree);
force_epoch_advancement();
}
#[test]
fn no_leak_large_values() {
let tree: Tree<i32, Vec<u8>> = Tree::new();
for i in 0..100 {
tree.insert(i, vec![0u8; 1024]);
}
drop(tree);
force_epoch_advancement();
}
#[test]
fn no_leak_string_tree() {
let tree: Tree<String, String> = Tree::new();
for i in 0..100 {
tree.insert(format!("key_{}", i), format!("value_{}", i));
}
for i in 0..100 {
tree.remove(&format!("key_{}", i));
}
drop(tree);
force_epoch_advancement();
}
#[test]
fn no_leak_pop_first() {
let tree: Tree<i32, i32> = Tree::new();
for i in 0..100 {
tree.insert(i, i);
}
while tree.pop_first().is_some() {}
assert!(tree.is_empty());
drop(tree);
force_epoch_advancement();
}
#[test]
fn no_leak_pop_last() {
let tree: Tree<i32, i32> = Tree::new();
for i in 0..100 {
tree.insert(i, i);
}
while tree.pop_last().is_some() {}
assert!(tree.is_empty());
drop(tree);
force_epoch_advancement();
}
#[test]
fn no_leak_stress_small_ops() {
let tree: Tree<i32, i32> = Tree::new();
for round in 0..10 {
for i in 0..100 {
tree.insert(round * 100 + i, i);
}
for i in (0..100).step_by(2) {
tree.remove(&(round * 100 + i));
}
}
drop(tree);
force_epoch_advancement();
}
#[test]
fn no_leak_stress_rebuild() {
for _ in 0..5 {
let tree: Tree<i32, i32> = Tree::new();
for i in 0..500 {
tree.insert(i, i);
}
for i in 0..500 {
tree.remove(&i);
}
drop(tree);
}
force_epoch_advancement();
}