use super::*;
use ruc::*;
use std::{fs, mem::size_of};
#[test]
fn test_insert() {
let mut hdr = MapxRaw::new();
let max = 100;
(0..max)
.map(|i: u64| (to_bytes(i), to_bytes(max + i)))
.for_each(|(key, value)| {
assert!(hdr.get(key).is_none());
hdr.entry(&key).or_insert(&value);
assert!(hdr.contains_key(key));
assert_eq!(&pnk!(hdr.get(key))[..], &value[..]);
hdr.remove(key);
assert!(hdr.get(key).is_none());
hdr.insert(key, value);
assert!(hdr.contains_key(key));
});
hdr.clear();
(0..max).map(|i: u64| to_bytes(i)).for_each(|key| {
assert!(hdr.get(key).is_none());
});
}
#[test]
fn test_iter() {
let mut hdr = MapxRaw::new();
let max = 100;
(0..max)
.map(|i: u64| (to_bytes(i), to_bytes(i)))
.for_each(|(key, value)| {
hdr.insert(key, value);
});
hdr.iter_mut().for_each(|(_k, mut v)| {
*v = to_bytes(to_u64(&v) + 1).to_vec();
});
for (idx, (_key, value)) in hdr.iter().enumerate() {
assert_eq!(idx as u64 + 1, to_u64(&value));
}
}
#[test]
fn test_first_last() {
let mut hdr = MapxRaw::new();
let max = 100;
(0..max)
.map(|i: u64| (to_bytes(i), to_bytes(i)))
.for_each(|(key, value)| {
hdr.insert(key, value);
});
let (_, value) = pnk!(hdr.iter().next());
let val = to_u64(&value);
assert_eq!(0, val);
let (_, value) = pnk!(hdr.iter().next_back());
let val = to_u64(&value);
assert_eq!(max - 1, val);
}
#[test]
fn test_batch() {
let mut hdr = MapxRaw::new();
let max = 100u64;
{
let mut batch = hdr.batch_entry();
for i in 0..max {
let key = to_bytes(i);
let value = to_bytes(max + i);
batch.insert(&key, &value);
}
batch.commit().unwrap();
}
for i in 0..max {
let key = to_bytes(i);
let value = to_bytes(max + i);
assert_eq!(&pnk!(hdr.get(key))[..], &value[..]);
}
{
let mut batch = hdr.batch_entry();
for i in 0..max {
let key = to_bytes(i);
batch.remove(&key);
}
batch.commit().unwrap();
}
for i in 0..max {
let key = to_bytes(i);
assert!(hdr.get(key).is_none());
}
}
#[test]
fn test_batch_wiped() {
let mut hdr = MapxRaw::new();
let max = 100u64;
for i in 0..max {
hdr.insert(to_bytes(i), to_bytes(i));
}
{
let mut batch = hdr.batch_entry_wiped();
batch.insert(&to_bytes(7), &to_bytes(70));
batch.insert(&to_bytes(max + 1), &to_bytes(71));
batch.commit().unwrap();
}
assert_eq!(hdr.iter().count(), 2);
assert_eq!(&pnk!(hdr.get(to_bytes(7)))[..], &to_bytes(70)[..]);
assert_eq!(&pnk!(hdr.get(to_bytes(max + 1)))[..], &to_bytes(71)[..]);
for i in (0..max).filter(|&i| i != 7) {
assert!(hdr.get(to_bytes(i)).is_none());
}
hdr.batch_entry_wiped().commit().unwrap();
assert_eq!(hdr.iter().count(), 0);
hdr.insert(to_bytes(1), to_bytes(2));
assert_eq!(&pnk!(hdr.get(to_bytes(1)))[..], &to_bytes(2)[..]);
}
#[test]
fn test_clear_large() {
let mut hdr = MapxRaw::new();
let max = 5000u64;
for i in 0..max {
hdr.insert(to_bytes(i), to_bytes(i));
}
hdr.clear();
assert_eq!(hdr.iter().count(), 0);
assert!(hdr.get(to_bytes(0)).is_none());
assert!(hdr.get(to_bytes(max - 1)).is_none());
hdr.insert(to_bytes(3), to_bytes(4));
assert_eq!(hdr.iter().count(), 1);
assert_eq!(&pnk!(hdr.get(to_bytes(3)))[..], &to_bytes(4)[..]);
}
fn to_u64(bytes: &[u8]) -> u64 {
u64::from_be_bytes(<[u8; size_of::<u64>()]>::try_from(bytes).unwrap())
}
fn to_bytes(i: u64) -> [u8; size_of::<u64>()] {
i.to_be_bytes()
}
#[test]
fn test_save_and_from_meta() {
let mut hdr = MapxRaw::new();
hdr.insert([1], [10]);
hdr.insert([2], [20]);
let id = pnk!(hdr.save_meta());
assert_eq!(id, hdr.instance_id());
let restored = pnk!(MapxRaw::from_meta(id));
assert_eq!(restored.get([1]), Some(vec![10]));
assert_eq!(restored.get([2]), Some(vec![20]));
assert!(restored.is_the_same_instance(&hdr));
}
#[test]
fn test_from_meta_rejects_legacy_prefix_metadata() {
let mut hdr = MapxRaw::new();
hdr.insert([1], [10]);
let id = hdr.instance_id();
fs::write(crate::common::vsdb_meta_path(id.map_id), hdr.as_bytes()).unwrap();
assert!(MapxRaw::from_meta(id).is_err());
let id = pnk!(hdr.save_meta());
let restored = pnk!(MapxRaw::from_meta(id));
assert_eq!(restored.get([1]), Some(vec![10]));
assert!(restored.is_the_same_instance(&hdr));
}
#[test]
fn test_from_meta_nonexistent() {
assert!(MapxRaw::from_meta(u64::MAX).is_err());
}
#[test]
fn test_serde_roundtrip() {
let mut hdr = MapxRaw::new();
for i in 0u64..50 {
hdr.insert(i.to_be_bytes(), (i * 10).to_be_bytes());
}
let bytes = postcard::to_allocvec(&hdr).unwrap();
let restored: MapxRaw = postcard::from_bytes(&bytes).unwrap();
assert!(restored.is_the_same_instance(&hdr));
for i in 0u64..50 {
assert_eq!(
&restored.get(i.to_be_bytes()).unwrap()[..],
&(i * 10).to_be_bytes()
);
}
}
#[test]
fn test_serde_size() {
let hdr = MapxRaw::new();
let bytes = postcard::to_allocvec(&hdr).unwrap();
assert!(bytes.len() <= 20, "expected ≤20 bytes, got {}", bytes.len());
}
#[test]
fn test_serde_rejects_raw_prefix_bytes() {
let hdr = MapxRaw::new();
assert!(postcard::from_bytes::<MapxRaw>(hdr.as_bytes()).is_err());
}
#[test]
fn test_serde_rejects_legacy_prefix_payload() {
let hdr = MapxRaw::new();
let legacy_payload = postcard::to_allocvec(hdr.as_bytes().as_slice()).unwrap();
assert!(postcard::from_bytes::<MapxRaw>(&legacy_payload).is_err());
}
#[test]
fn test_serde_rejects_allocator_future_prefix() {
let mut meta = Vec::new();
meta.extend_from_slice(b"VSMAPX01");
meta.extend_from_slice(&u64::MAX.to_le_bytes());
let payload = postcard::to_allocvec(meta.as_slice()).unwrap();
assert!(postcard::from_bytes::<MapxRaw>(&payload).is_err());
}
#[test]
fn test_serde_reserves_recovered_future_prefix() {
let hdr = MapxRaw::new();
let future = hdr.instance_id().map_id + 1;
let mut meta = Vec::new();
meta.extend_from_slice(b"VSMAPX01");
meta.extend_from_slice(&future.to_le_bytes());
let payload = postcard::to_allocvec(meta.as_slice()).unwrap();
let mut recovered: MapxRaw = postcard::from_bytes(&payload).unwrap();
recovered.insert(b"k", b"recovered");
let mut next = MapxRaw::new();
next.insert(b"k", b"next");
assert_ne!(next.instance_id().map_id, future);
assert_eq!(&recovered.get(b"k").unwrap()[..], b"recovered");
assert_eq!(&next.get(b"k").unwrap()[..], b"next");
}
#[test]
fn test_meta_restore_then_mutate() {
let mut hdr = MapxRaw::new();
hdr.insert(b"k1", b"v1");
let id = pnk!(hdr.save_meta());
let mut restored = pnk!(MapxRaw::from_meta(id));
restored.insert(b"k2", b"v2");
restored.remove(b"k1");
assert!(restored.get(b"k1").is_none());
assert_eq!(&restored.get(b"k2").unwrap()[..], b"v2");
assert!(hdr.get(b"k1").is_none());
assert_eq!(&hdr.get(b"k2").unwrap()[..], b"v2");
}
#[test]
fn test_prefix_isolation_between_instances() {
let mut a = MapxRaw::new();
let mut b = MapxRaw::new();
assert!(!a.is_the_same_instance(&b));
for i in 0u64..100 {
a.insert(to_bytes(i), to_bytes(i));
b.insert(to_bytes(i), to_bytes(i + 1000));
}
for i in 0u64..100 {
assert_eq!(to_u64(&pnk!(a.get(to_bytes(i)))), i);
assert_eq!(to_u64(&pnk!(b.get(to_bytes(i)))), i + 1000);
}
a.insert(to_bytes(500), to_bytes(500));
assert!(b.get(to_bytes(500)).is_none());
a.remove(to_bytes(0));
assert!(a.get(to_bytes(0)).is_none());
assert_eq!(to_u64(&pnk!(b.get(to_bytes(0)))), 1000);
assert_eq!(a.iter().count(), 100); assert_eq!(b.iter().count(), 100);
for (_, v) in b.iter() {
assert!(to_u64(&v) >= 1000);
}
b.clear();
assert!(b.iter().next().is_none());
assert_eq!(a.iter().count(), 100);
assert_eq!(to_u64(&pnk!(a.get(to_bytes(1)))), 1);
}