#![allow(clippy::std_instead_of_core, reason = "tests use std")]
#![allow(clippy::unwrap_used, reason = "test code")]
use multitude::vec::Vec as ArenaVec;
use multitude::{Arena, ArenaBuilder};
#[cfg(feature = "stats")]
#[test]
fn stats_alloc_slice_fill_with_records_bytes_equals_size_times_len() {
let arena = Arena::new();
let baseline = arena.stats().total_bytes_allocated;
let _: &mut [u32] = arena.alloc_slice_fill_with::<u32, _>(7, |i| u32::try_from(i).expect("test bench length fits in u32"));
let delta = arena.stats().total_bytes_allocated - baseline;
assert_eq!(delta, 4 * 7, "fill_with must record size * len bytes");
}
#[cfg(feature = "stats")]
#[test]
fn stats_alloc_slice_fill_with_drop_records_bytes_equals_size_times_len() {
#[derive(Clone)]
struct D(#[expect(dead_code, reason = "field gives the type a non-zero size")] u32);
#[expect(clippy::empty_drop, reason = "intentional: forces needs_drop::<D>() = true")]
impl Drop for D {
fn drop(&mut self) {}
}
let arena = Arena::new();
let baseline = arena.stats().total_bytes_allocated;
let _: &mut [D] = arena.alloc_slice_fill_with::<D, _>(5, |i| D(u32::try_from(i).expect("test bench length fits in u32")));
let delta = arena.stats().total_bytes_allocated - baseline;
assert_eq!(delta, core::mem::size_of::<D>() as u64 * 5);
}
#[cfg(feature = "stats")]
#[test]
fn stats_alloc_slice_fill_iter_records_bytes_equals_size_times_len() {
let arena = Arena::new();
let baseline = arena.stats().total_bytes_allocated;
let _: &mut [u32] = arena.alloc_slice_fill_iter::<u32, _>(0..9_u32);
let delta = arena.stats().total_bytes_allocated - baseline;
assert_eq!(delta, 4 * 9, "fill_iter must record size * len bytes");
}
#[cfg(feature = "stats")]
#[test]
fn stats_alloc_slice_fill_iter_drop_records_bytes_equals_size_times_len() {
#[derive(Clone)]
struct D(#[expect(dead_code, reason = "field gives the type a non-zero size")] u32);
#[expect(clippy::empty_drop, reason = "intentional: forces needs_drop::<D>() = true")]
impl Drop for D {
fn drop(&mut self) {}
}
let arena = Arena::new();
let baseline = arena.stats().total_bytes_allocated;
let v: std::vec::Vec<D> = (0..6_u32).map(D).collect();
let _: &mut [D] = arena.alloc_slice_fill_iter::<D, _>(v);
let delta = arena.stats().total_bytes_allocated - baseline;
assert_eq!(delta, core::mem::size_of::<D>() as u64 * 6);
}
#[cfg(feature = "stats")]
#[test]
fn stats_alloc_utf16_records_bytes_equals_units_times_two() {
let arena = Arena::new();
let baseline = arena.stats().total_bytes_allocated;
let s = "hello!"; let _ = arena.alloc_utf16_str_arc_from_str(s);
let delta = arena.stats().total_bytes_allocated - baseline;
assert_eq!(delta, 12, "alloc_utf16 must record code_units * 2 bytes");
}
#[cfg(feature = "stats")]
#[test]
fn chunk_provider_config_returns_custom_max_normal_alloc_local() {
let arena: Arena = ArenaBuilder::new().max_normal_alloc(4 * 1024).build();
let baseline = arena.stats().oversized_local_chunks_allocated;
let _: &mut [u8] = arena.alloc_slice_fill_with::<u8, _>(12 * 1024, |_| 0);
let after = arena.stats().oversized_local_chunks_allocated;
assert!(
after > baseline,
"12 KiB local allocation with 4 KiB max_normal_alloc must route to an oversized chunk; stats: {after} vs baseline {baseline}",
);
}
#[cfg(feature = "stats")]
#[test]
fn chunk_provider_config_returns_custom_max_normal_alloc_shared() {
let arena: Arena = ArenaBuilder::new().max_normal_alloc(4 * 1024).build();
let baseline = arena.stats().oversized_shared_chunks_allocated;
let s: std::string::String = (0..12 * 1024).map(|_| 'a').collect();
let _ = arena.alloc_str_box(&s);
let after = arena.stats().oversized_shared_chunks_allocated;
assert!(
after > baseline,
"12 KiB shared allocation with 4 KiB max_normal_alloc must route to an oversized chunk; stats: {after} vs baseline {baseline}",
);
}
#[cfg(feature = "stats")]
#[test]
fn acquire_local_at_max_normal_alloc_boundary_stays_normal_class() {
let mna = 4 * 1024;
let arena: Arena = ArenaBuilder::new().max_normal_alloc(mna).build();
let baseline = arena.stats().oversized_local_chunks_allocated;
let len = mna - 1;
let _: &mut [u8] = arena.alloc_slice_fill_with::<u8, _>(len, |_| 0);
let after = arena.stats().oversized_local_chunks_allocated;
assert_eq!(
after - baseline,
0,
"min_payload == max_normal_alloc must stay on the normal cache path",
);
}
#[cfg(feature = "stats")]
#[test]
fn acquire_shared_at_max_normal_alloc_boundary_stays_normal_class() {
let mna = 4 * 1024;
let arena: Arena = ArenaBuilder::new().max_normal_alloc(mna).build();
let baseline = arena.stats().oversized_shared_chunks_allocated;
let len: usize = 4088;
debug_assert_eq!(1 + len.div_ceil(core::mem::size_of::<usize>()).max(1), 512);
let s: std::string::String = (0..len).map(|_| 'a').collect();
let _ = arena.alloc_str_box(&s);
let after = arena.stats().oversized_shared_chunks_allocated;
assert_eq!(
after - baseline,
0,
"min_payload == max_normal_alloc must stay on the normal cache path (shared)",
);
}
#[test]
fn vec_shrink_to_fit_at_max_normal_alloc_boundary_reclaims() {
let mna = 4 * 1024;
let arena: Arena = ArenaBuilder::new().max_normal_alloc(mna).build();
let cap = mna - 1;
let mut v: ArenaVec<'_, u8> = ArenaVec::with_capacity_in(cap, &arena);
v.extend_from_slice([7_u8; 16]);
assert_eq!(v.capacity(), cap);
v.shrink_to_fit();
assert_eq!(
v.capacity(),
v.len(),
"shrink_to_fit on a Vec backed by the current normal chunk must reclaim the unused tail",
);
}