use super::{
control, count_done_ring_slots, debug, decode_load_miss, encode_load_miss, read_debug_log,
read_debug_log_into, read_metrics_into, slot, try_encode_control, try_encode_empty_debug_log,
try_encode_empty_ring, try_encode_empty_ring_into, try_encode_load_miss,
try_encode_load_miss_into, try_read_debug_log, try_read_debug_log_into, try_read_metrics_into,
try_slot_byte_len, try_slot_word_base, try_slot_word_index, MAX_ENCODED_DEBUG_RECORDS,
MAX_ENCODED_OBSERVABLE_SLOTS, MAX_ENCODED_RING_SLOTS, STATUS_WORD,
};
#[test]
#[allow(clippy::assertions_on_constants)]
fn control_regions_do_not_alias() {
let metrics_end = control::METRICS_BASE + control::METRICS_SLOTS;
assert!(metrics_end <= control::EPOCH);
assert!(control::EPOCH < control::OBSERVABLE_BASE);
}
#[test]
fn count_done_ring_slots_counts_only_done_status_words() {
let mut ring = Vec::new();
try_encode_empty_ring_into(4, &mut ring).unwrap();
for (slot_idx, status) in [slot::DONE, slot::CLAIMED, slot::DONE, slot::EMPTY]
.into_iter()
.enumerate()
{
let word_idx = slot_idx * super::SLOT_WORDS as usize + STATUS_WORD as usize;
let byte_idx = word_idx * 4;
ring[byte_idx..byte_idx + 4].copy_from_slice(&status.to_le_bytes());
}
assert_eq!(count_done_ring_slots(&ring, 4), Some(2));
assert_eq!(count_done_ring_slots(&ring, 0), None);
assert_eq!(count_done_ring_slots(&ring[..8], 4), None);
let mut unaligned = vec![0xAA];
unaligned.extend_from_slice(&ring);
assert_eq!(count_done_ring_slots(&unaligned[1..], 4), Some(2));
}
#[test]
fn allocating_encoders_reject_allocation_cap_before_reserving() {
let control_err = try_encode_control(false, 1, MAX_ENCODED_OBSERVABLE_SLOTS + 1)
.expect_err("observable cap exceeded");
let err_str = control_err.to_string();
assert!(
err_str.contains("observable"),
"control cap error: {}",
err_str
);
let ring_err =
try_encode_empty_ring(MAX_ENCODED_RING_SLOTS + 1).expect_err("ring cap exceeded");
let err_str = ring_err.to_string();
assert!(
err_str.contains("ring") || err_str.contains("slot"),
"ring cap error: {}",
err_str
);
let debug_err =
try_encode_empty_debug_log(MAX_ENCODED_DEBUG_RECORDS + 1).expect_err("debug cap exceeded");
let err_str = debug_err.to_string();
assert!(err_str.contains("debug"), "debug cap error: {}", err_str);
}
#[test]
fn allocating_encoders_preallocate_exact_protocol_capacity() {
let control = try_encode_control(false, 1, 16).unwrap();
assert_eq!(control.capacity(), control.len());
let ring = try_encode_empty_ring(16).unwrap();
assert_eq!(ring.capacity(), ring.len());
let debug_log = try_encode_empty_debug_log(16).unwrap();
assert_eq!(debug_log.capacity(), debug_log.len());
}
#[test]
fn metrics_decode_into_reuses_capacity_without_overreserve() {
let mut control = super::try_encode_control(false, 1, 0).unwrap();
let word_idx = control::METRICS_BASE as usize;
control[word_idx * 4..word_idx * 4 + 4].copy_from_slice(&9_u32.to_le_bytes());
let mut out = Vec::with_capacity(control::METRICS_SLOTS as usize);
let initial_capacity = out.capacity();
read_metrics_into(&control, &mut out);
assert_eq!(out, vec![(0, 9)]);
assert_eq!(out.capacity(), initial_capacity);
try_read_metrics_into(&control, &mut out).unwrap();
assert_eq!(out, vec![(0, 9)]);
assert_eq!(out.capacity(), initial_capacity);
}
#[test]
fn metrics_decode_into_does_not_allocate_for_empty_metrics() {
let control = super::try_encode_control(false, 1, 0).unwrap();
let mut out = Vec::new();
read_metrics_into(&control, &mut out);
assert!(out.is_empty());
assert_eq!(
out.capacity(),
0,
"Fix: empty metrics snapshots must not allocate the full metrics window."
);
try_read_metrics_into(&control, &mut out).unwrap();
assert!(out.is_empty());
assert_eq!(
out.capacity(),
0,
"Fix: strict empty metrics snapshots must not allocate the full metrics window."
);
}
#[test]
fn metrics_decode_into_reserves_only_nonzero_metrics() {
let mut control = super::try_encode_control(false, 1, 0).unwrap();
let word_idx = (control::METRICS_BASE + 7) as usize;
control[word_idx * 4..word_idx * 4 + 4].copy_from_slice(&13_u32.to_le_bytes());
let mut out = Vec::new();
read_metrics_into(&control, &mut out);
assert_eq!(out, vec![(7, 13)]);
assert!(
out.capacity() < control::METRICS_SLOTS as usize,
"Fix: sparse metrics decode must not reserve the entire metrics window."
);
out.clear();
out.shrink_to_fit();
try_read_metrics_into(&control, &mut out).unwrap();
assert_eq!(out, vec![(7, 13)]);
assert!(
out.capacity() < control::METRICS_SLOTS as usize,
"Fix: strict sparse metrics decode must not reserve the entire metrics window."
);
}
#[test]
fn debug_log_decode_into_reuses_capacity_without_overreserve() {
let mut debug_log = super::try_encode_empty_debug_log(2).unwrap();
debug_log[(debug::CURSOR_WORD as usize) * 4..(debug::CURSOR_WORD as usize) * 4 + 4]
.copy_from_slice(&debug::RECORD_WORDS.to_le_bytes());
let record_start = debug::RECORDS_BASE as usize * 4;
for (idx, value) in [7_u32, 1, 2, 3].into_iter().enumerate() {
let byte_idx = record_start + idx * 4;
debug_log[byte_idx..byte_idx + 4].copy_from_slice(&value.to_le_bytes());
}
let mut out = Vec::with_capacity(1);
let initial_capacity = out.capacity();
read_debug_log_into(&debug_log, &mut out);
assert_eq!(out.len(), 1);
assert_eq!(out[0].fmt_id, 7);
assert_eq!(out.capacity(), initial_capacity);
try_read_debug_log_into(&debug_log, &mut out).unwrap();
assert_eq!(out.len(), 1);
assert_eq!(out.capacity(), initial_capacity);
}
#[test]
fn debug_log_owned_decode_does_not_allocate_for_empty_log() {
let debug_log = super::try_encode_empty_debug_log(64).unwrap();
let records = read_debug_log(&debug_log);
assert!(records.is_empty());
assert_eq!(
records.capacity(),
0,
"Fix: empty debug-log decode must not allocate the full record capacity."
);
let records = try_read_debug_log(&debug_log).unwrap();
assert!(records.is_empty());
assert_eq!(
records.capacity(),
0,
"Fix: strict empty debug-log decode must not allocate the full record capacity."
);
}
#[test]
fn encode_load_miss_produces_correct_slot_layout() {
let bytes = encode_load_miss(42, true);
assert_eq!(bytes.len(), 64);
assert_eq!(decode_load_miss(&bytes, 0), Some((42, true)));
}
#[test]
fn try_encode_load_miss_produces_correct_slot_layout_and_reuses_storage() {
let bytes = try_encode_load_miss(42, true).expect("Fix: valid load-miss slot must encode");
assert_eq!(bytes.len(), try_slot_byte_len().unwrap());
assert_eq!(decode_load_miss(&bytes, 0), Some((42, true)));
let mut reused = Vec::with_capacity(128);
let initial_capacity = reused.capacity();
try_encode_load_miss_into(7, false, &mut reused)
.expect("Fix: caller-owned load-miss slot must encode");
assert_eq!(reused.len(), 64);
assert_eq!(reused.capacity(), initial_capacity);
assert_eq!(decode_load_miss(&reused, 0), Some((7, false)));
}
#[test]
fn slot_word_arithmetic_rejects_overflow_without_panic() {
let base_result = std::panic::catch_unwind(|| try_slot_word_base(u32::MAX));
assert!(
base_result.is_ok(),
"fallible slot word-base arithmetic must return an error instead of panicking"
);
let err = base_result.unwrap().unwrap_err().to_string();
assert!(
err.contains("slot word base overflows"),
"Fix: overflow must identify the slot word-base contract, got: {err}"
);
let word_result = std::panic::catch_unwind(|| try_slot_word_index(0, super::SLOT_WORDS));
assert!(
word_result.is_ok(),
"fallible slot-local word arithmetic must return an error instead of panicking"
);
let err = word_result.unwrap().unwrap_err().to_string();
assert!(
err.contains("outside SLOT_WORDS"),
"Fix: out-of-slot word errors must name the slot layout contract, got: {err}"
);
}
#[test]
fn decode_load_miss_returns_none_for_wrong_opcode() {
let mut bytes = encode_load_miss(42, true);
bytes[4..8].copy_from_slice(&0_u32.to_le_bytes());
assert_eq!(decode_load_miss(&bytes, 0), None);
}
#[test]
fn decode_load_miss_returns_none_for_short_buffer() {
assert_eq!(decode_load_miss(&[0u8; 60], 0), None);
}
#[test]
fn decode_load_miss_uses_slot_index_correctly() {
let mut ring = vec![0u8; 128];
let slot0 = encode_load_miss(7, false);
let slot1 = encode_load_miss(99, true);
ring[..64].copy_from_slice(&slot0);
ring[64..128].copy_from_slice(&slot1);
assert_eq!(decode_load_miss(&ring, 0), Some((7, false)));
assert_eq!(decode_load_miss(&ring, 1), Some((99, true)));
assert_eq!(decode_load_miss(&ring, 2), None);
}