use aok::{OK, Void};
use log::info;
use wrecord::{
ADDRESS_MASK, Error, HEADER_SIZE, MAX_FILLER_BYTES, RecordHeader, RecordMut, RecordRef,
TOMBSTONE_BIT, encode_to_slice, record_size, try_encode_to_vec,
};
#[ctor::ctor(unsafe)]
fn _log_init() {
log_init::init();
}
#[test]
fn test_roundtrip_encode_decode() -> Void {
info!("开始测试: 编解码往返一致性");
let key = b"user:10001:profile";
let val = b"{\"name\":\"Alice\",\"age\":30,\"active\":true}";
let prev_addr = 0x0000_1234_5678_9abc_u64;
let encoded = try_encode_to_vec(prev_addr, key, val, false)?;
assert_eq!(encoded.len(), record_size(key.len(), val.len()));
let rec_ref = RecordRef::from_slice(&encoded)?;
assert_eq!(rec_ref.key(), key);
assert_eq!(rec_ref.value(), val);
assert_eq!(rec_ref.prev_address(), prev_addr);
assert!(!rec_ref.is_tombstone());
assert_eq!(rec_ref.total_size(), encoded.len());
let empty_encoded = try_encode_to_vec(0, b"", b"", false)?;
assert_eq!(empty_encoded.len(), HEADER_SIZE);
let empty_ref = RecordRef::from_slice(&empty_encoded)?;
assert_eq!(empty_ref.key(), b"");
assert_eq!(empty_ref.value(), b"");
assert_eq!(empty_ref.prev_address(), 0);
assert!(!empty_ref.is_tombstone());
let max_addr = ADDRESS_MASK;
let max_addr_encoded = try_encode_to_vec(max_addr, b"k", b"v", false)?;
let max_addr_ref = RecordRef::from_slice(&max_addr_encoded)?;
assert_eq!(max_addr_ref.prev_address(), max_addr);
let mut large_buf = vec![0u8; 1024];
let written = encode_to_slice(&mut large_buf, prev_addr, key, val, false)?;
assert_eq!(written, record_size(key.len(), val.len()));
let slice_ref = RecordRef::from_slice(&large_buf)?;
assert_eq!(slice_ref.key(), key);
assert_eq!(slice_ref.value(), val);
info!("编解码往返一致性测试通过");
OK
}
#[test]
fn test_tombstone_flag() -> Void {
info!("开始测试: 墓碑标记设置与检测");
let key = b"deleted_key";
let val = b"";
let prev_addr = 0x0000_aabb_ccdd_eeff_u64;
let encoded = try_encode_to_vec(prev_addr, key, val, true)?;
let rec_ref = RecordRef::from_slice(&encoded)?;
assert!(rec_ref.is_tombstone());
assert_eq!(rec_ref.prev_address(), prev_addr);
let raw_header = RecordHeader::from_slice(&encoded[..HEADER_SIZE])?;
assert_eq!(raw_header.prev_address, prev_addr | TOMBSTONE_BIT);
let mut buf = encoded.clone();
let mut rec_mut = RecordMut::from_slice_mut(&mut buf)?;
assert!(rec_mut.is_tombstone());
rec_mut.set_tombstone(false);
assert!(!rec_mut.is_tombstone());
assert_eq!(rec_mut.prev_address(), prev_addr);
rec_mut.set_tombstone(true);
assert!(rec_mut.is_tombstone());
assert_eq!(rec_mut.prev_address(), prev_addr);
let check_ref = RecordRef::from_slice(&buf)?;
assert!(check_ref.is_tombstone());
assert_eq!(check_ref.prev_address(), prev_addr);
info!("墓碑标记设置与检测测试通过");
OK
}
#[test]
fn test_record_ref_zero_copy() -> Void {
info!("开始测试: 零拷贝借用 RecordRef");
let key = b"my_benchmark_key_12345";
let val = b"my_benchmark_val_67890";
let prev_addr = 0x42;
let encoded = try_encode_to_vec(prev_addr, key, val, false)?;
let rec_ref = RecordRef::from_slice(&encoded)?;
let expected_key_ptr = unsafe { encoded.as_ptr().add(HEADER_SIZE) };
let expected_val_ptr = unsafe { encoded.as_ptr().add(HEADER_SIZE + key.len()) };
assert_eq!(rec_ref.key().as_ptr(), expected_key_ptr);
assert_eq!(rec_ref.value().as_ptr(), expected_val_ptr);
assert_eq!(rec_ref.key().len(), key.len());
assert_eq!(rec_ref.value().len(), val.len());
info!("零拷贝借用指针精确匹配测试通过");
OK
}
#[test]
fn test_record_mut_in_place_update() -> Void {
info!("开始测试: 原位值更新与防御拦截");
let key = b"counter_key";
let initial_val = b"0000000010"; let prev_addr = 0x0000_0001_0000_0000_u64;
let mut buf = try_encode_to_vec(prev_addr, key, initial_val, false)?;
let mut rec_mut = RecordMut::from_slice_mut(&mut buf)?;
assert_eq!(rec_mut.key(), key);
assert_eq!(rec_mut.value(), initial_val);
let updated_val = b"0000000020"; rec_mut.update_value_in_place(updated_val)?;
assert_eq!(rec_mut.value(), updated_val);
let short_val = b"0020";
let err_short = rec_mut.update_value_in_place(short_val);
assert_eq!(
err_short,
Err(Error::ValueLengthMismatch {
expected: 10,
actual: 4,
})
);
let long_val = b"00000000000000000020";
let err_long = rec_mut.update_value_in_place(long_val);
assert_eq!(
err_long,
Err(Error::ValueLengthMismatch {
expected: 10,
actual: 20,
})
);
assert_eq!(rec_mut.value(), updated_val);
let new_prev_addr = 0x0000_0002_0000_0000_u64;
rec_mut.set_prev_address(new_prev_addr)?;
assert_eq!(rec_mut.prev_address(), new_prev_addr);
let invalid_addr = 1u64 << 48;
let err_addr = rec_mut.set_prev_address(invalid_addr);
assert_eq!(err_addr, Err(Error::AddressOverflow(invalid_addr)));
let view = rec_mut.as_ref();
assert_eq!(view.key(), key);
assert_eq!(view.value(), updated_val);
assert_eq!(view.prev_address(), new_prev_addr);
info!("原位值更新与防御拦截测试通过");
OK
}
#[test]
fn test_buffer_too_short_and_bounds_check() -> Void {
info!("开始测试: 缓冲区截断与越界防御");
let tiny_buf = [0u8; 15];
assert_eq!(
RecordHeader::from_slice(&tiny_buf),
Err(Error::BufferTooShort {
expected: 16,
actual: 15,
})
);
assert_eq!(
RecordRef::from_slice(&tiny_buf),
Err(Error::BufferTooShort {
expected: 16,
actual: 15,
})
);
let mut tiny_mut_buf = [0u8; 10];
assert_eq!(
RecordMut::from_slice_mut(&mut tiny_mut_buf),
Err(Error::BufferTooShort {
expected: 16,
actual: 10,
})
);
let key = b"test_key";
let val = b"test_val_12345";
let full_buf = try_encode_to_vec(1, key, val, false)?;
let total_len = full_buf.len();
let truncated_buf = &full_buf[..total_len - 1];
assert_eq!(
RecordRef::from_slice(truncated_buf),
Err(Error::BufferTooShort {
expected: total_len,
actual: total_len - 1,
})
);
let mut small_dst = vec![0u8; total_len - 1];
assert_eq!(
encode_to_slice(&mut small_dst, 1, key, val, false),
Err(Error::BufferTooShort {
expected: total_len,
actual: total_len - 1,
})
);
let overflow_addr = 1u64 << 48;
assert_eq!(
try_encode_to_vec(overflow_addr, key, val, false),
Err(Error::AddressOverflow(overflow_addr))
);
let mut valid_dst = vec![0u8; total_len];
assert_eq!(
encode_to_slice(&mut valid_dst, overflow_addr, key, val, false),
Err(Error::AddressOverflow(overflow_addr))
);
assert_eq!(
RecordHeader::new(overflow_addr, 1, 1, false),
Err(Error::AddressOverflow(overflow_addr))
);
info!("缓冲区截断与越界防御测试通过");
OK
}
#[test]
fn test_tombstone_flip_and_can_update_in_place() -> Void {
info!("开始测试: RecordHeader/RecordMut 翻转墓碑与原位更新判断");
let mut header = RecordHeader::new(0x1234, 10, 20, false)?;
assert!(!header.is_tombstone());
assert!(header.can_update_in_place(20));
assert!(!header.can_update_in_place(19));
assert!(!header.can_update_in_place(21));
assert!(header.flip_tombstone());
assert!(header.is_tombstone());
assert!(!header.can_update_in_place(20));
assert!(!header.flip_tombstone());
assert!(!header.is_tombstone());
assert!(header.can_update_in_place(20));
let mut buf = try_encode_to_vec(0x5678, b"test_key", b"1234567890", false)?;
{
let mut rec_mut = RecordMut::from_slice_mut(&mut buf)?;
assert!(!rec_mut.is_tombstone());
assert!(rec_mut.can_update_in_place(10));
assert!(!rec_mut.can_update_in_place(5));
assert!(rec_mut.flip_tombstone());
assert!(rec_mut.is_tombstone());
assert_eq!(rec_mut.prev_address(), 0x5678);
assert!(!rec_mut.can_update_in_place(10));
}
let ref_check = RecordRef::from_slice(&buf)?;
assert!(ref_check.is_tombstone());
assert!(!ref_check.can_update_in_place(10));
{
let mut rec_mut = RecordMut::from_slice_mut(&mut buf)?;
assert!(!rec_mut.flip_tombstone());
assert!(!rec_mut.is_tombstone());
assert!(rec_mut.can_update_in_place(10));
}
let ref_check2 = RecordRef::from_slice(&buf)?;
assert!(!ref_check2.is_tombstone());
assert!(ref_check2.can_update_in_place(10));
info!("RecordHeader/RecordMut 翻转墓碑与原位更新判断测试通过");
OK
}
#[test]
fn test_filler_words_field_setter() -> Void {
info!("开始测试: FillerWords 词级设置与字节级松弛折算");
let mut hdr = RecordHeader::new(0x10, 8, 16, false)?;
assert_eq!(hdr.filler_bytes(), 0);
hdr.set_filler_words(4);
assert_eq!(hdr.filler_words(), 4);
assert_eq!(hdr.filler_bytes(), 32);
assert_eq!(hdr.address(), 0x10);
hdr.set_filler_bytes(31);
assert_eq!(hdr.filler_words(), 3);
assert_eq!(hdr.filler_rem(), 7);
assert_eq!(hdr.filler_bytes(), 31);
hdr.set_filler_words(5);
assert_eq!(hdr.filler_words(), 5);
assert_eq!(hdr.filler_rem(), 7);
assert_eq!(hdr.filler_bytes(), 47);
assert_eq!(hdr.address(), 0x10);
hdr.set_filler_bytes(MAX_FILLER_BYTES + 128);
assert_eq!(hdr.filler_words(), 255);
assert_eq!(hdr.filler_rem(), 7);
assert_eq!(hdr.filler_bytes(), MAX_FILLER_BYTES);
OK
}
#[test]
fn test_record_header_bitcode() -> Void {
info!("开始测试: RecordHeader bitcode 序列化往返");
let header = RecordHeader::new(0x0000_1234_5678_9ABC, 42, 1024, true)?;
let encoded = header.encode_bitcode();
assert!(!encoded.is_empty());
let decoded = RecordHeader::decode_bitcode(&encoded)?;
assert_eq!(header, decoded);
assert_eq!(decoded.address(), 0x0000_1234_5678_9ABC);
assert_eq!(decoded.key_len(), 42);
assert_eq!(decoded.val_len(), 1024);
assert!(decoded.is_tombstone());
let bad_data = [0xFFu8; 3];
assert!(RecordHeader::decode_bitcode(&bad_data).is_err());
info!("RecordHeader bitcode 序列化往返测试通过");
OK
}
#[test]
fn test_record_mut_dynamic_slack_and_filler_words() -> Void {
info!("开始测试: FillerWords 动态松弛全生命周期原位覆写与容量自洽");
let key = b"session:user:1001";
let initial_val = b"status=active;score=987654;role=admin;meta=verified_2026"; let prev_addr = 0x0000_1234_5678_0000_u64;
let mut buf = try_encode_to_vec(prev_addr, key, initial_val, false)?;
let initial_physical_size = buf.len();
{
let mut rec_mut = RecordMut::from_slice_mut(&mut buf)?;
assert_eq!(rec_mut.val_len(), 56);
assert_eq!(rec_mut.filler_words(), 0);
assert_eq!(rec_mut.val_capacity(), 56);
assert_eq!(rec_mut.physical_size(), initial_physical_size);
let short_val = b"status=idle;score=100000"; assert!(rec_mut.can_update_with_slack(short_val.len()));
rec_mut.update_value_with_slack(short_val)?;
assert_eq!(rec_mut.val_len(), 24);
assert_eq!(rec_mut.filler_words(), 4); assert_eq!(rec_mut.filler_rem(), 0);
assert_eq!(rec_mut.filler_bytes(), 32);
assert_eq!(rec_mut.val_capacity(), 56); assert_eq!(rec_mut.physical_size(), initial_physical_size); assert_eq!(rec_mut.value(), short_val);
let rec_ref = rec_mut.as_ref();
assert_eq!(rec_ref.value(), short_val);
assert_eq!(rec_ref.val_len(), 24);
assert_eq!(rec_ref.filler_words(), 4);
assert_eq!(rec_ref.filler_rem(), 0);
assert_eq!(rec_ref.physical_size(), initial_physical_size);
let non_align_val = b"status=idle;score=100000_"; assert!(rec_mut.can_update_with_slack(non_align_val.len()));
rec_mut.update_value_with_slack(non_align_val)?;
assert_eq!(rec_mut.val_len(), 25);
assert_eq!(rec_mut.filler_words(), 3); assert_eq!(rec_mut.filler_rem(), 7); assert_eq!(rec_mut.filler_bytes(), 31);
assert_eq!(rec_mut.val_capacity(), 56);
assert_eq!(rec_mut.physical_size(), initial_physical_size); assert_eq!(rec_mut.value(), non_align_val);
let medium_val = b"status=active;score=20000;role=moderator"; assert!(rec_mut.can_update_with_slack(medium_val.len()));
rec_mut.update_value_with_slack(medium_val)?;
assert_eq!(rec_mut.val_len(), 40);
assert_eq!(rec_mut.filler_words(), 2); assert_eq!(rec_mut.filler_rem(), 0);
assert_eq!(rec_mut.filler_bytes(), 16);
assert_eq!(rec_mut.val_capacity(), 56);
assert_eq!(rec_mut.physical_size(), initial_physical_size);
assert_eq!(rec_mut.value(), medium_val);
rec_mut.set_tombstone(true);
assert!(rec_mut.is_tombstone());
assert!(!rec_mut.can_update_with_slack(24)); rec_mut.revivify_with_slack(short_val)?;
assert!(!rec_mut.is_tombstone());
assert_eq!(rec_mut.val_len(), 24);
assert_eq!(rec_mut.filler_bytes(), 32);
assert_eq!(rec_mut.val_capacity(), 56);
assert_eq!(rec_mut.physical_size(), initial_physical_size);
assert_eq!(rec_mut.value(), short_val);
rec_mut.update_value_with_slack(initial_val)?;
assert_eq!(rec_mut.val_len(), 56);
assert_eq!(rec_mut.filler_words(), 0);
assert_eq!(rec_mut.filler_rem(), 0);
assert_eq!(rec_mut.val_capacity(), 56);
assert_eq!(rec_mut.value(), initial_val);
let overflow_val = b"status=active;score=987654;role=admin;meta=verified_2026_exceed_cap"; assert!(!rec_mut.can_update_with_slack(overflow_val.len()));
let err = rec_mut.update_value_with_slack(overflow_val);
assert_eq!(
err,
Err(Error::ValueLengthMismatch {
expected: 56,
actual: 67,
})
);
}
let final_ref = RecordRef::from_slice(&buf)?;
assert_eq!(final_ref.value(), initial_val);
assert_eq!(final_ref.val_len(), 56);
assert_eq!(final_ref.filler_words(), 0);
assert_eq!(final_ref.physical_size(), initial_physical_size);
info!("FillerWords 动态松弛全生命周期原位覆写与容量自洽测试通过");
OK
}