use moa_idalloc::table::{Id, IdTable};
fn slot_of(id: Id) -> u64 {
id.bits() & 0xFFFF_FFFF
}
fn gen_of(id: Id) -> u64 {
id.bits() >> 32
}
#[test]
fn insert_get_remove() {
let mut t = IdTable::new();
let a = t.insert("a");
let b = t.insert("b");
assert_eq!(t.get(a), Some(&"a"));
assert_eq!(t.get(b), Some(&"b"));
assert_eq!(t.len(), 2);
assert_eq!(t.remove(a), Some("a"));
assert_eq!(t.get(a), None);
assert_eq!(t.len(), 1);
assert!(!t.is_empty());
}
#[test]
fn empty_table_transitions() {
let mut t = IdTable::new();
assert!(t.is_empty());
assert_eq!(t.len(), 0);
let id = t.insert(());
assert!(!t.is_empty());
assert_eq!(t.len(), 1);
t.remove(id);
assert!(t.is_empty());
assert_eq!(t.len(), 0);
}
#[test]
fn default_is_empty() {
let t: IdTable<i32> = IdTable::default();
assert!(t.is_empty());
}
#[test]
fn get_mut_updates_value() {
let mut t = IdTable::new();
let id = t.insert(1);
*t.get_mut(id).unwrap() = 99;
assert_eq!(t.get(id), Some(&99));
}
#[test]
fn double_remove_returns_none() {
let mut t = IdTable::new();
let id = t.insert(1);
assert_eq!(t.remove(id), Some(1));
assert_eq!(t.remove(id), None);
assert!(t.get_mut(id).is_none());
}
#[test]
fn never_issued_id_returns_none() {
let t: IdTable<i32> = IdTable::new();
assert_eq!(t.get(Id::from_bits(0)), None);
assert_eq!(t.get(Id::from_bits(0xDEAD_BEEF_0000_0005)), None);
}
#[test]
fn removing_one_keeps_others() {
let mut t = IdTable::new();
let ids: Vec<Id> = (0..5).map(|i| t.insert(i)).collect();
t.remove(ids[2]);
assert_eq!(t.get(ids[0]), Some(&0));
assert_eq!(t.get(ids[2]), None);
assert_eq!(t.get(ids[4]), Some(&4));
assert_eq!(t.len(), 4);
}
#[test]
fn reuses_freed_slot_before_growing() {
let mut t = IdTable::new();
let a = t.insert(1);
let _b = t.insert(2);
let a_slot = slot_of(a);
t.remove(a);
let c = t.insert(3);
assert_eq!(slot_of(c), a_slot, "应复用 a 的槽位而非新增");
}
#[test]
fn generation_rejects_stale_id() {
let mut t = IdTable::new();
let a = t.insert(10);
assert_eq!(t.remove(a), Some(10));
let b = t.insert(20);
assert_eq!(slot_of(a), slot_of(b), "复用同一槽位");
assert_ne!(a, b, "generation 不同,id 不等");
assert_eq!(t.get(a), None, "旧 id 被拒(ABA 安全)");
assert_eq!(t.remove(a), None);
assert_eq!(t.get(b), Some(&20));
}
#[test]
fn generation_increments_each_reuse() {
let mut t = IdTable::new();
let mut id = t.insert(0);
let slot = slot_of(id);
assert_eq!(gen_of(id), 0);
for expected_gen in 1..=5 {
t.remove(id);
id = t.insert(0);
assert_eq!(slot_of(id), slot, "始终复用同一槽位");
assert_eq!(gen_of(id), expected_gen, "每次复用 generation +1");
}
}
#[test]
fn stale_id_stays_rejected_across_many_reuses() {
let mut t = IdTable::new();
let stale = t.insert(100);
let mut cur = stale;
for _ in 0..8 {
t.remove(cur);
cur = t.insert(200);
}
assert_eq!(t.get(stale), None, "最初的旧 id 经多轮复用仍被拒");
assert_eq!(t.get(cur), Some(&200));
}
#[test]
fn bits_roundtrip() {
let mut t = IdTable::new();
let a = t.insert(42);
let restored = Id::from_bits(a.bits());
assert_eq!(restored, a);
assert_eq!(t.get(restored), Some(&42));
}
#[test]
fn many_insert_remove_cycles_stay_consistent() {
let mut t = IdTable::new();
let mut live: Vec<(Id, usize)> = Vec::new();
for round in 0..500 {
let id = t.insert(round);
live.push((id, round));
if round % 3 == 0 && live.len() > 1 {
let (rid, rval) = live.remove(0);
assert_eq!(t.remove(rid), Some(rval));
}
}
assert_eq!(t.len(), live.len());
for (id, val) in live {
assert_eq!(t.get(id), Some(&val));
}
}