#![cfg(all(feature = "alloc-core", feature = "alloc-decommit"))]
use core::alloc::Layout;
use sefer_alloc::alloc_core::AllocCore;
#[cfg_attr(miri, ignore)]
#[test]
fn decommit_fires_and_recommit_roundtrips() {
let before = AllocCore::dbg_decommit_count();
let mut ac = AllocCore::new().expect("primordial");
let layout = Layout::from_size_align(256, 8).unwrap();
const N: usize = 60_000;
const ROUNDS: usize = 4;
for round in 0..ROUNDS {
let mut ptrs = Vec::with_capacity(N);
for i in 0..N {
let p = ac.alloc(layout);
assert!(!p.is_null(), "alloc null at i={i} round={round}");
unsafe {
let b = (i & 0xFF) as u8;
core::ptr::write_bytes(p, b, 256);
}
ptrs.push(p);
}
for (i, &p) in ptrs.iter().enumerate() {
let b = (i & 0xFF) as u8;
unsafe {
assert_eq!(p.read(), b, "readback byte0 mismatch i={i} round={round}");
assert_eq!(
p.add(255).read(),
b,
"readback last-byte mismatch i={i} round={round}"
);
}
}
for &p in &ptrs {
ac.dealloc(p, layout);
}
}
let after = AllocCore::dbg_decommit_count();
assert!(
after > before,
"M6 decommit hook never fired across the soak (before={before}, after={after}) — \
live-count zero-crossing or non-current proviso is miswired"
);
}
#[test]
fn live_count_tracks_alloc_free_exactly() {
let mut ac = AllocCore::new().expect("primordial");
let layout = Layout::from_size_align(64, 8).unwrap();
const K: usize = 200;
let mut ptrs = Vec::with_capacity(K);
let mut base_lc: Option<u32> = None;
for _ in 0..K {
let p = ac.alloc(layout);
assert!(!p.is_null());
if base_lc.is_none() {
base_lc = ac.dbg_live_count_for(p);
}
ptrs.push(p);
}
let lc_after_alloc = ac
.dbg_live_count_for(ptrs[0])
.expect("tracked segment live_count");
assert!(lc_after_alloc > 0, "live_count must rise on alloc");
for &p in &ptrs {
ac.dealloc(p, layout);
}
let lc_after_free = ac
.dbg_live_count_for(ptrs[0])
.expect("tracked segment live_count after free");
assert_eq!(
lc_after_free, 0,
"live_count must return to zero once every block of the segment is freed"
);
}