use super::*;
fn build_expected_skippable(magic_variant: u8, payload: &[u8]) -> Vec<u8> {
let magic = (SKIPPABLE_MAGIC_START + u32::from(magic_variant)).to_le_bytes();
let size = (payload.len() as u32).to_le_bytes();
let mut out = Vec::with_capacity(payload.len() + SKIPPABLE_HEADER_SIZE);
out.extend_from_slice(&magic);
out.extend_from_slice(&size);
out.extend_from_slice(payload);
out
}
#[test]
fn round_trip_all_sixteen_variants() {
for variant in 0u8..=15 {
let payload = alloc::vec![variant; 32 + variant as usize];
let frame = SkippableFrame::new(variant, payload.clone()).expect("variant in range");
let mut wire = Vec::new();
frame
.encode_into(&mut wire)
.expect("encode into Vec succeeds");
let mut cursor: &[u8] = wire.as_slice();
let decoded = SkippableFrame::decode_from(&mut cursor).expect("round-trip decode");
assert_eq!(decoded.magic_variant(), variant);
assert_eq!(
decoded.magic_number(),
SKIPPABLE_MAGIC_START + u32::from(variant)
);
assert_eq!(decoded.payload(), payload.as_slice());
assert!(
cursor.is_empty(),
"decode_from must consume exactly the frame bytes, no overshoot or undershoot"
);
}
}
#[test]
fn empty_payload_round_trips() {
let frame = SkippableFrame::new(7, Vec::new()).expect("empty payload OK");
assert_eq!(frame.serialized_size(), SKIPPABLE_HEADER_SIZE);
let mut wire = Vec::new();
frame.encode_into(&mut wire).unwrap();
assert_eq!(wire.len(), SKIPPABLE_HEADER_SIZE);
let mut cursor: &[u8] = wire.as_slice();
let decoded = SkippableFrame::decode_from(&mut cursor).unwrap();
assert!(decoded.payload().is_empty());
assert_eq!(decoded.magic_variant(), 7);
}
#[test]
fn large_payload_round_trips() {
let payload = alloc::vec![0xABu8; 1024 * 1024];
let frame = SkippableFrame::new(0, payload.clone()).unwrap();
let mut wire = Vec::new();
frame.encode_into(&mut wire).unwrap();
assert_eq!(wire.len(), payload.len() + SKIPPABLE_HEADER_SIZE);
let mut cursor: &[u8] = wire.as_slice();
let decoded = SkippableFrame::decode_from(&mut cursor).unwrap();
assert_eq!(decoded.payload().len(), payload.len());
assert!(decoded.payload() == payload.as_slice());
}
#[test]
fn new_rejects_variant_sixteen() {
let err = SkippableFrame::new(16, Vec::new()).expect_err("variant 16 out of range");
match err {
SkippableFrameError::InvalidMagicVariant(v) => assert_eq!(v, 16),
other => panic!("expected InvalidMagicVariant(16), got {other:?}"),
}
}
#[test]
fn new_rejects_variant_max() {
let err = SkippableFrame::new(255, Vec::new()).unwrap_err();
match err {
SkippableFrameError::InvalidMagicVariant(v) => assert_eq!(v, 255),
other => panic!("expected InvalidMagicVariant(255), got {other:?}"),
}
}
#[test]
fn write_function_rejects_invalid_variant() {
let mut sink: Vec<u8> = Vec::new();
let err = write_skippable_frame(16, b"x", &mut sink).unwrap_err();
assert!(matches!(err, SkippableFrameError::InvalidMagicVariant(16)));
assert!(
sink.is_empty(),
"no bytes must be written on rejected input"
);
}
#[test]
fn byte_parity_with_spec_layout() {
for &payload_len in &[0usize, 1, 8, 256, 4096] {
let payload: Vec<u8> = (0..payload_len).map(|i| (i % 251) as u8).collect();
for variant in 0u8..=15 {
let expected = build_expected_skippable(variant, &payload);
let mut via_struct = Vec::new();
SkippableFrame::new(variant, payload.clone())
.unwrap()
.encode_into(&mut via_struct)
.unwrap();
assert_eq!(
via_struct, expected,
"struct encode mismatch: variant={variant} len={payload_len}"
);
let mut via_free = Vec::new();
let written = write_skippable_frame(variant, &payload, &mut via_free).unwrap();
assert_eq!(written, expected.len());
assert_eq!(
via_free, expected,
"free-fn encode mismatch: variant={variant} len={payload_len}"
);
}
}
}
#[test]
fn decode_rejects_non_skippable_magic() {
let mut wire = Vec::new();
wire.extend_from_slice(&0xFD2F_B528u32.to_le_bytes());
wire.extend_from_slice(&0u32.to_le_bytes());
let mut cursor: &[u8] = wire.as_slice();
let err = SkippableFrame::decode_from(&mut cursor).unwrap_err();
match err {
DecodeSkippableFrameError::BadMagicNumber(m) => assert_eq!(m, 0xFD2F_B528),
other => panic!("expected BadMagicNumber, got {other:?}"),
}
}
#[test]
fn decode_rejects_magic_above_band() {
let mut wire = Vec::new();
wire.extend_from_slice(&0x184D_2A60u32.to_le_bytes());
wire.extend_from_slice(&0u32.to_le_bytes());
let mut cursor: &[u8] = wire.as_slice();
let err = SkippableFrame::decode_from(&mut cursor).unwrap_err();
assert!(matches!(
err,
DecodeSkippableFrameError::BadMagicNumber(0x184D_2A60)
));
}
#[test]
fn decode_truncated_magic_surfaces_typed_error() {
let wire = [0x50u8, 0x2A, 0x4D];
let mut cursor: &[u8] = &wire;
let err = SkippableFrame::decode_from(&mut cursor).unwrap_err();
assert!(
matches!(err, DecodeSkippableFrameError::Magic(_)),
"expected Magic, got {err:?}"
);
}
#[test]
fn decode_truncated_length_surfaces_typed_error() {
let mut wire = Vec::new();
wire.extend_from_slice(&SKIPPABLE_MAGIC_START.to_le_bytes());
wire.extend_from_slice(&[0u8, 0, 0]);
let mut cursor: &[u8] = wire.as_slice();
let err = SkippableFrame::decode_from(&mut cursor).unwrap_err();
assert!(
matches!(err, DecodeSkippableFrameError::Length(_)),
"expected Length, got {err:?}"
);
}
#[test]
fn decode_truncated_payload_surfaces_typed_error() {
let mut wire = Vec::new();
wire.extend_from_slice(&SKIPPABLE_MAGIC_START.to_le_bytes());
wire.extend_from_slice(&16u32.to_le_bytes());
wire.extend_from_slice(&[0u8; 4]);
let mut cursor: &[u8] = wire.as_slice();
let err = SkippableFrame::decode_from(&mut cursor).unwrap_err();
assert!(
matches!(err, DecodeSkippableFrameError::Payload(_)),
"expected Payload, got {err:?}"
);
}
#[test]
fn serialized_size_matches_encoded_length() {
for payload_len in [0usize, 1, 7, 8, 9, 255, 256, 1023, 1024] {
let payload = alloc::vec![0u8; payload_len];
let frame = SkippableFrame::new(3, payload).unwrap();
let mut wire = Vec::new();
frame.encode_into(&mut wire).unwrap();
assert_eq!(
wire.len(),
frame.serialized_size(),
"serialized_size() must match actual encode length for payload_len={payload_len}"
);
}
}
#[test]
fn decode_huge_length_returns_typed_error_not_oom_abort() {
let huge: u32 = u32::MAX;
let mut wire = Vec::new();
wire.extend_from_slice(&SKIPPABLE_MAGIC_START.to_le_bytes());
wire.extend_from_slice(&huge.to_le_bytes());
let mut cursor: &[u8] = wire.as_slice();
let err = SkippableFrame::decode_from(&mut cursor).unwrap_err();
match err {
DecodeSkippableFrameError::PayloadTooLarge { length } => {
assert_eq!(length, huge);
}
DecodeSkippableFrameError::AllocationFailed { requested } => {
assert_eq!(requested, huge as usize);
}
DecodeSkippableFrameError::Payload(_) => {
}
other => panic!("expected PayloadTooLarge / AllocationFailed / Payload, got {other:?}"),
}
}
#[test]
fn payload_too_large_check_branches_on_pointer_width() {
#[cfg(target_pointer_width = "64")]
{
let result = validate_payload_size(u32::MAX as usize + 1);
assert!(matches!(
result,
Err(SkippableFrameError::PayloadTooLarge(_))
));
let ok = validate_payload_size(u32::MAX as usize);
assert!(ok.is_ok(), "u32::MAX representable on 64-bit");
}
#[cfg(target_pointer_width = "32")]
{
let result = validate_payload_size(u32::MAX as usize);
assert!(
matches!(result, Err(SkippableFrameError::PayloadTooLarge(_))),
"u32::MAX overflows when combined with the 8-byte header on 32-bit"
);
let ok = validate_payload_size((u32::MAX as usize) - SKIPPABLE_HEADER_SIZE);
assert!(ok.is_ok(), "below the header-overflow boundary on 32-bit");
}
}