use super::*;
#[test]
fn basic_alloc_and_read() {
let arena = Arena::new();
let off = arena.alloc(4, 4).expect("should succeed");
assert!(off >= 1);
assert_eq!(off & 3, 0);
unsafe {
let bytes = arena.get_bytes_mut(off, 4);
bytes.copy_from_slice(&[1, 2, 3, 4]);
}
let read = unsafe { arena.get_bytes(off, 4) };
assert_eq!(read, &[1, 2, 3, 4]);
}
#[test]
fn alloc_respects_alignment() {
let arena = Arena::new();
let a = arena.alloc(1, 1).expect("ok");
let b = arena.alloc(4, 4).expect("ok");
assert_eq!(b & 3, 0);
assert!(b > a);
}
#[test]
fn alloc_crosses_block_boundary() {
let arena = Arena::new();
let big = BLOCK_SIZE - 64;
let off1 = arena.alloc(big, 1).expect("ok");
assert_eq!(off1 >> BLOCK_SHIFT, 0);
let off2 = arena.alloc(128, 4).expect("ok");
assert_eq!(off2 >> BLOCK_SHIFT, 1);
}
#[test]
fn atomic_u32_round_trip() {
let arena = Arena::new();
let off = arena.alloc(4, 4).expect("ok");
unsafe {
let atom = arena.get_atomic_u32(off);
atom.store(42, Ordering::Relaxed);
assert_eq!(atom.load(Ordering::Relaxed), 42);
}
}
#[test]
fn concurrent_alloc() {
use std::sync::Arc;
let arena = Arc::new(Arena::new());
let handles: Vec<_> = (0..8)
.map(|_| {
let arena = Arc::clone(&arena);
std::thread::spawn(move || {
let mut offsets = Vec::new();
for _ in 0..1000 {
if let Some(off) = arena.alloc(64, 4) {
offsets.push(off);
}
}
offsets
})
})
.collect();
let mut all_offsets: Vec<u32> = Vec::new();
for h in handles {
all_offsets.extend(h.join().expect("thread ok"));
}
all_offsets.sort();
all_offsets.dedup();
assert_eq!(all_offsets.len(), 8000);
}
#[test]
fn alloc_invalid_alignment_returns_none() {
let arena = Arena::new();
assert!(arena.alloc(100, 3).is_none()); assert!(arena.alloc(0, 4).is_none()); assert!(arena.alloc(BLOCK_SIZE, 1).is_none()); assert!(arena.alloc(BLOCK_SIZE + 1, 1).is_none()); }
#[test]
fn default_impl() {
let arena = Arena::default();
let off = arena.alloc(8, 4).expect("should work");
assert!(off > 0);
}
#[test]
fn drop_with_multiple_blocks() {
let arena = Arena::new();
let big = BLOCK_SIZE - 8;
let _ = arena.alloc(big, 1).expect("block 0");
let _ = arena.alloc(64, 4).expect("block 1");
}
#[test]
fn exact_block_fill_does_not_corrupt() {
let arena = Arena::new();
arena.cursor.store(1 << BLOCK_SHIFT, Ordering::Relaxed);
let filler = BLOCK_SIZE - 4;
let f = arena.alloc(filler, 1).expect("filler");
assert_eq!(f >> BLOCK_SHIFT, 1, "filler should be in block 1");
unsafe {
let bytes = arena.get_bytes_mut(f, filler);
bytes[filler as usize - 1] = 0xAB;
}
let boundary = arena.alloc(4, 4).expect("boundary alloc");
assert_eq!(
boundary >> BLOCK_SHIFT,
2,
"exact-fill allocation must advance to the next block"
);
let next = arena.alloc(8, 4).expect("next alloc");
assert_eq!(
next >> BLOCK_SHIFT,
2,
"subsequent allocation must stay in the advanced block"
);
let read_sentinel = unsafe { arena.get_bytes(f, filler) };
assert_eq!(
read_sentinel[filler as usize - 1],
0xAB,
"block 1 data must not be corrupted by subsequent allocations"
);
}