use haem_frames::frame;
use std::io::{self, Cursor, Read};
use std::num::NonZeroU32;
#[test]
fn tagged_frame_is_big_endian_and_counts_the_tag() -> io::Result<()> {
let mut bytes = Vec::new();
frame::write(&mut bytes, 4, b"{}", NonZeroU32::MAX)?;
assert_eq!(bytes, b"\0\0\0\x03\x04{}");
assert_eq!(
frame::read(&mut Cursor::new(bytes), NonZeroU32::MAX)?,
Some(b"\x04{}".to_vec())
);
Ok(())
}
#[test]
fn cut_and_oversized_frames_never_adopt_their_tail() -> io::Result<()> {
let limit = NonZeroU32::MIN;
let mut oversized = Cursor::new(b"\0\0\0\x02ab".to_vec());
assert!(frame::read(&mut oversized, limit).is_err());
assert_eq!(oversized.position(), 4);
let mut tail = Vec::new();
oversized.read_to_end(&mut tail)?;
assert_eq!(tail, b"ab");
Ok(())
}
#[test]
fn clean_eof_differs_from_a_cut_header_or_payload() -> io::Result<()> {
assert_eq!(frame::read(&mut Cursor::new([]), NonZeroU32::MAX)?, None);
for bytes in [
b"\0".as_slice(),
b"\0\0\0\x02a".as_slice(),
b"\0\0\0\0".as_slice(),
] {
assert!(frame::read(&mut Cursor::new(bytes), NonZeroU32::MAX).is_err());
}
Ok(())
}
#[test]
fn rejected_write_emits_no_header() {
let mut output = Vec::new();
assert!(frame::write(&mut output, 4, b"{}", NonZeroU32::MIN).is_err());
assert!(output.is_empty());
}
#[test]
fn an_oversized_header_is_a_typed_fault_found_before_the_body() -> Result<(), String> {
let limit = NonZeroU32::MIN.saturating_add(9);
let mut input = Cursor::new(b"\0\0\0\x0bbody never read".to_vec());
let error = frame::read(&mut input, limit)
.err()
.ok_or("an oversized frame was read")?;
assert_eq!(
frame::Fault::of(&error),
Some(frame::Fault::TooLarge {
length: 11,
limit: 10
})
);
assert_eq!(input.position(), 4, "the reader went past the header");
Ok(())
}
#[test]
fn an_empty_or_cut_frame_is_a_malformed_fault_not_too_large() {
for (bytes, fault) in [
(b"\0\0\0\0".as_slice(), frame::Fault::Empty),
(b"\0".as_slice(), frame::Fault::Cut),
(b"\0\0\0\x02a".as_slice(), frame::Fault::Cut),
] {
let read = frame::read(&mut Cursor::new(bytes), NonZeroU32::MAX);
assert_eq!(read.err().as_ref().and_then(frame::Fault::of), Some(fault));
}
}