use super::{MAX_IDLE_PER_WORKER, acquire, checked_out, clear, idle};
fn with_empty_pool(body: impl FnOnce()) {
clear();
assert_eq!((checked_out(), idle()), (0, 0));
body();
clear();
}
#[test]
fn test_the_next_file_reuses_the_same_arena_memory() {
with_empty_pool(|| {
let first_address = {
let arena = acquire();
arena.alloc_str("file N").as_ptr() as usize
};
assert_eq!(idle(), 1);
let arena = acquire();
assert_eq!(arena.allocated_bytes(), 0);
assert_eq!(arena.alloc_str("file M").as_ptr() as usize, first_address);
});
}
#[test]
fn test_checked_out_tracks_guard_scope() {
with_empty_pool(|| {
let outer = acquire();
assert_eq!(checked_out(), 1);
{
let inner = acquire();
assert_eq!(checked_out(), 2);
assert_ne!(inner.stamp(), outer.stamp());
}
assert_eq!(checked_out(), 1);
drop(outer);
assert_eq!((checked_out(), idle()), (0, 2));
});
}
#[test]
#[cfg(debug_assertions)]
#[should_panic(expected = "arena-backed value outlived its compile")]
fn test_recycling_a_guard_makes_its_stamps_stale() {
clear();
let stamp = {
let arena = acquire();
let _ = arena.alloc_str("file N");
arena.stamp()
};
let arena = acquire();
arena.assert_stamp_current(stamp);
}
#[test]
fn test_a_live_guard_keeps_its_stamp_current() {
with_empty_pool(|| {
let arena = acquire();
let stamp = arena.stamp();
let _ = arena.alloc_str("still the same compile");
arena.assert_stamp_current(stamp);
assert_eq!(arena.stamp(), stamp);
});
}
#[test]
fn test_idle_arenas_are_bounded() {
with_empty_pool(|| {
let guards: std::vec::Vec<_> = (0..MAX_IDLE_PER_WORKER + 3).map(|_| acquire()).collect();
assert_eq!(checked_out(), MAX_IDLE_PER_WORKER + 3);
drop(guards);
assert_eq!((checked_out(), idle()), (0, MAX_IDLE_PER_WORKER));
});
}
#[test]
fn test_pools_are_per_worker() {
with_empty_pool(|| {
let outer = acquire();
let _ = outer.alloc_str("owned by this worker");
let observed = std::thread::spawn(|| {
let idle_at_start = idle();
let arena = acquire();
let _ = arena.alloc_str("owned by the other worker");
let checked_out_inside = checked_out();
drop(arena);
(idle_at_start, checked_out_inside, idle(), checked_out())
})
.join()
.expect("the worker thread runs to completion");
assert_eq!(observed, (0, 1, 1, 0));
assert_eq!((checked_out(), idle()), (1, 0));
});
}
#[test]
fn test_parked_values_drop_when_the_guard_returns() {
use std::sync::atomic::{AtomicUsize, Ordering};
static DROPS: AtomicUsize = AtomicUsize::new(0);
struct Parked;
impl Drop for Parked {
fn drop(&mut self) {
DROPS.fetch_add(1, Ordering::Relaxed);
}
}
with_empty_pool(|| {
let before = DROPS.load(Ordering::Relaxed);
for _ in 0..8 {
let arena = acquire();
let parked: &Parked = arena.alloc_owned(Parked);
let _ = std::hint::black_box(parked);
}
assert_eq!(DROPS.load(Ordering::Relaxed), before + 8);
});
}