use super::{
FrameContentSize, FrameSizeError, find_frame_compressed_size, frame_decompressed_bound,
frame_header_size, read_frame_content_size, read_frame_header_info,
};
use crate::decoding::errors::{FrameDescriptorError, ReadFrameHeaderError};
use crate::encoding::{CompressionLevel, compress_slice_to_vec};
use alloc::vec;
use alloc::vec::Vec;
fn frame(content: &[u8]) -> Vec<u8> {
compress_slice_to_vec(content, CompressionLevel::Default)
}
fn no_fcs_frame() -> Vec<u8> {
vec![
0x28, 0xB5, 0x2F, 0xFD, 0x00, 0x00, 0x19, 0x00, 0x00, 0xAA, 0xBB, 0xCC, ]
}
fn no_fcs_checksum_frame() -> Vec<u8> {
vec![
0x28, 0xB5, 0x2F, 0xFD, 0x04, 0x00, 0x19, 0x00, 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0xAD, 0xBE, 0xEF, ]
}
fn skippable_frame(payload: &[u8]) -> Vec<u8> {
let mut f = vec![0x50, 0x2A, 0x4D, 0x18];
f.extend_from_slice(&(payload.len() as u32).to_le_bytes());
f.extend_from_slice(payload);
f
}
#[test]
fn read_frame_content_size_reports_declared_size() {
let f = frame(&[42u8; 100]);
assert_eq!(
read_frame_content_size(&f).unwrap(),
FrameContentSize::Known(100)
);
}
#[test]
fn read_frame_content_size_reports_unknown_without_fcs() {
assert_eq!(
read_frame_content_size(&no_fcs_frame()).unwrap(),
FrameContentSize::Unknown
);
}
#[test]
fn read_frame_content_size_errors_on_garbage() {
assert!(read_frame_content_size(&[0xAB; 16]).is_err());
}
#[test]
fn find_frame_compressed_size_spans_one_frame_then_the_next() {
let first = frame(&[5u8; 256]);
assert_eq!(find_frame_compressed_size(&first).unwrap(), first.len());
let mut two = first.clone();
two.extend_from_slice(&frame(&[9u8; 50]));
assert_eq!(find_frame_compressed_size(&two).unwrap(), first.len());
}
#[test]
fn find_frame_compressed_size_measures_skippable_frame() {
let skip = skippable_frame(&[1, 2, 3, 4]);
assert_eq!(find_frame_compressed_size(&skip).unwrap(), skip.len());
}
#[test]
fn find_frame_compressed_size_rejects_truncation() {
let f = frame(&[7u8; 512]);
let err = find_frame_compressed_size(&f[..f.len() - 4]).unwrap_err();
assert!(matches!(err, FrameSizeError::Truncated));
}
#[test]
fn frame_header_size_matches_first_block_offset() {
let f = frame(&[3u8; 2048]);
let hdr = frame_header_size(&f).unwrap();
assert!((5..=18).contains(&hdr));
assert!(frame_header_size(&[0u8; 2]).is_err());
}
#[test]
fn read_frame_header_info_fills_declared_fields() {
let f = frame(&[7u8; 512]);
let info = read_frame_header_info(&f, false).unwrap();
assert_eq!(info.content_size, FrameContentSize::Known(512));
assert!(info.window_size >= 512);
assert_eq!(info.dictionary_id, None);
}
#[test]
fn read_frame_header_info_derives_window_without_fcs() {
let info = read_frame_header_info(&no_fcs_frame(), false).unwrap();
assert_eq!(info.content_size, FrameContentSize::Unknown);
assert_eq!(info.window_size, 1024);
}
#[test]
fn frame_decompressed_bound_returns_declared_size() {
let f = frame(&[4u8; 4096]);
assert_eq!(frame_decompressed_bound(&f).unwrap(), 4096);
}
#[test]
fn frame_decompressed_bound_uses_block_bound_without_fcs() {
assert_eq!(frame_decompressed_bound(&no_fcs_frame()).unwrap(), 1024);
}
#[test]
fn frame_decompressed_bound_accepts_present_checksum_trailer() {
assert_eq!(
frame_decompressed_bound(&no_fcs_checksum_frame()).unwrap(),
1024
);
}
#[test]
fn frame_decompressed_bound_rejects_missing_checksum_trailer() {
let mut f = no_fcs_checksum_frame();
f.truncate(f.len() - 4); assert!(matches!(
frame_decompressed_bound(&f).unwrap_err(),
FrameSizeError::Truncated
));
}
#[test]
fn size_helpers_reject_oversized_block_header() {
let block_size = 2000usize;
let raw = ((block_size as u32) << 3) | 1; let mut f = vec![
0x28,
0xB5,
0x2F,
0xFD, 0x00, 0x00, (raw & 0xFF) as u8,
((raw >> 8) & 0xFF) as u8,
((raw >> 16) & 0xFF) as u8,
];
f.resize(f.len() + block_size, 0xAB);
assert!(matches!(
find_frame_compressed_size(&f).unwrap_err(),
FrameSizeError::OversizedBlock
));
assert!(matches!(
frame_decompressed_bound(&f).unwrap_err(),
FrameSizeError::OversizedBlock
));
}
#[test]
fn frame_decompressed_bound_handles_skippable_frame() {
assert_eq!(
frame_decompressed_bound(&skippable_frame(&[0u8; 8])).unwrap(),
0
);
let mut short = skippable_frame(&[0u8; 8]);
short.truncate(short.len() - 2);
assert!(matches!(
frame_decompressed_bound(&short).unwrap_err(),
FrameSizeError::Truncated
));
}
#[test]
fn frame_decompressed_bound_errors_on_garbage_header() {
assert!(frame_decompressed_bound(&[0xAB; 16]).is_err());
}
fn no_fcs_frame_with_descriptor_bits(bits: u8) -> Vec<u8> {
let mut f = no_fcs_frame();
f[4] |= bits;
f
}
fn is_reserved_bit_error(err: &ReadFrameHeaderError) -> bool {
matches!(
err,
ReadFrameHeaderError::InvalidFrameDescriptor(FrameDescriptorError::ReservedBitSet)
)
}
#[test]
fn header_parsers_reject_the_reserved_descriptor_bit() {
use crate::decoding::frame::{read_frame_header_from_slice, read_frame_header_with_format};
let f = no_fcs_frame_with_descriptor_bits(0x08);
for (bytes, magicless) in [(&f[..], false), (&f[4..], true)] {
let err = read_frame_header_with_format(bytes, magicless)
.err()
.expect("the reserved bit must be refused");
assert!(
is_reserved_bit_error(&err),
"magicless={magicless}: {err:?}"
);
let mut input = bytes;
let err = read_frame_header_from_slice(&mut input, magicless)
.err()
.expect("the reserved bit must be refused");
assert!(
is_reserved_bit_error(&err),
"magicless={magicless}: {err:?}"
);
let err = read_frame_header_info(bytes, magicless).unwrap_err();
assert!(
is_reserved_bit_error(&err),
"magicless={magicless}: {err:?}"
);
}
assert!(is_reserved_bit_error(
&read_frame_content_size(&f).unwrap_err()
));
assert_eq!(
alloc::format!("{}", FrameDescriptorError::ReservedBitSet),
"Reserved_bit of the Frame_Header_Descriptor is set; it must be zero"
);
for err in [
find_frame_compressed_size(&f).unwrap_err(),
frame_decompressed_bound(&f).unwrap_err(),
] {
assert!(
matches!(&err, FrameSizeError::Header(e) if is_reserved_bit_error(e)),
"{err:?}"
);
}
}
#[test]
fn frame_header_size_measures_a_header_with_the_reserved_bit() {
assert_eq!(
frame_header_size(&no_fcs_frame_with_descriptor_bits(0x08)).unwrap(),
6
);
}
#[test]
fn frame_header_size_answers_from_the_five_byte_prefix() {
let full = no_fcs_frame();
assert_eq!(frame_header_size(&full[..5]).unwrap(), 6);
let reserved = no_fcs_frame_with_descriptor_bits(0x08);
assert_eq!(frame_header_size(&reserved[..5]).unwrap(), 6);
let wide = [0x28, 0xB5, 0x2F, 0xFD, 0x63];
assert_eq!(frame_header_size(&wide).unwrap(), 4 + 1 + 4 + 2);
assert!(frame_header_size(&full[..4]).is_err());
assert!(matches!(
frame_header_size(&[0xAB; 5]).unwrap_err(),
ReadFrameHeaderError::BadMagicNumber(_)
));
}
#[test]
fn the_unused_descriptor_bit_is_not_interpreted() {
let f = no_fcs_frame_with_descriptor_bits(0x10);
let info = read_frame_header_info(&f, false).unwrap();
assert_eq!(info.window_size, 1024);
assert_eq!(find_frame_compressed_size(&f).unwrap(), f.len());
let mut out = [0u8; 3];
let written = crate::decoding::FrameDecoder::new()
.decode_all(&f, &mut out)
.unwrap();
assert_eq!(&out[..written], &[0xAA, 0xBB, 0xCC]);
}