#![forbid(unsafe_code)]
mod test_utils;
use crate::test_utils::FakeReadWriter;
use fixed_buffer::{deframe_line, escape_ascii, FixedBuf, MalformedInputError, NoWritableSpace};
use std::sync::{LazyLock, Mutex};
static STATIC_FIXED_BUF: LazyLock<Mutex<FixedBuf<131_072>>> =
LazyLock::new(|| Mutex::new(FixedBuf::new()));
fn deframe_line_reject_xs(
data: &[u8],
) -> Result<(usize, Option<core::ops::Range<usize>>), MalformedInputError> {
if data.contains(&b'x') || data.contains(&b'X') {
return Err(MalformedInputError::new("err1".to_string()));
}
deframe_line(data)
}
#[test]
fn test_no_writable_space_error() {
let e = NoWritableSpace {};
let io_error: std::io::Error = e.into();
assert_eq!(std::io::ErrorKind::InvalidData, io_error.kind());
assert_eq!("no writable space in buffer", &io_error.to_string());
let string: String = e.into();
assert_eq!("no writable space in buffer", &string);
}
#[test]
fn test_malformed_input_error() {
let e = MalformedInputError("err1".to_string());
let io_error: std::io::Error = e.clone().into();
assert_eq!(std::io::ErrorKind::InvalidData, io_error.kind());
assert_eq!("malformed input: err1", &io_error.to_string());
let string: String = e.into();
assert_eq!("malformed input: err1", &string);
}
#[test]
fn test_static_fixed_buf() {
let mut buf = STATIC_FIXED_BUF.lock().unwrap();
assert_eq!(0, buf.len());
buf.write_bytes("abc").unwrap();
assert_eq!("abc", buf.escape_ascii());
}
#[test]
fn test_new() {
let buf: FixedBuf<1> = FixedBuf::new();
assert_eq!("", buf.escape_ascii());
let _: FixedBuf<42> = FixedBuf::new();
let _: FixedBuf<262_144> = FixedBuf::new();
}
#[test]
fn test_from_array() {
let mut buf = FixedBuf::from(*b"aaaaaaaa");
assert_eq!("aaaaaaaa", buf.escape_ascii());
buf.try_read_byte().unwrap();
buf.shift();
buf.write_bytes("b").unwrap();
assert_eq!("aaaaaaab", buf.escape_ascii());
}
#[test]
fn test_from_array_ref() {
let mut buf = FixedBuf::from(b"aaaaaaaa");
assert_eq!("aaaaaaaa", buf.escape_ascii());
buf.try_read_byte().unwrap();
buf.shift();
buf.write_bytes("b").unwrap();
assert_eq!("aaaaaaab", buf.escape_ascii());
}
#[test]
fn test_into_inner() {
let mut buf: FixedBuf<8> = FixedBuf::new();
buf.write_bytes("abc").unwrap();
let mem = buf.into_inner();
assert_eq!(&[97_u8, 98, 99, 0, 0, 0, 0, 0], &mem);
}
#[test]
fn test_len() {
let mut buf: FixedBuf<16> = FixedBuf::new();
assert_eq!(0, buf.len());
buf.write_bytes("abc").unwrap();
assert_eq!(3, buf.len());
buf.try_read_exact(2).unwrap();
assert_eq!(1, buf.len());
buf.shift();
assert_eq!(1, buf.len());
buf.read_all();
assert_eq!(0, buf.len());
}
#[test]
fn test_is_empty() {
let mut buf: FixedBuf<16> = FixedBuf::new();
assert!(buf.is_empty());
buf.write_bytes("abc").unwrap();
assert!(!buf.is_empty());
buf.read_all();
assert!(buf.is_empty());
}
#[test]
fn test_clear() {
let mut buf: FixedBuf<16> = FixedBuf::new();
buf.write_bytes("abc").unwrap();
assert_eq!(3, buf.len());
buf.clear();
assert!(buf.is_empty());
}
#[test]
fn test_write_bytes() {
let mut buf: FixedBuf<4> = FixedBuf::new();
assert_eq!(Ok(0), buf.write_bytes(b""));
assert_eq!(Ok(1), buf.write_bytes(b"a"));
assert_eq!(Ok(2), buf.write_bytes("bc"));
assert_eq!("abc", buf.escape_ascii());
assert_eq!(Ok(1), buf.write_bytes(b"de"));
assert_eq!("abcd", buf.escape_ascii());
assert_eq!(Err(NoWritableSpace {}), buf.write_bytes("e"));
assert_eq!("abcd", buf.escape_ascii());
buf.try_read_byte().unwrap();
buf.shift();
assert_eq!(Ok(1), buf.write_bytes("e"));
assert_eq!(Err(NoWritableSpace {}), buf.write_bytes(b"f"));
assert_eq!("bcde", buf.escape_ascii());
}
#[test]
fn test_writable_and_wrote() {
let mut buf: FixedBuf<16> = FixedBuf::new();
assert_eq!(16, buf.writable().len());
buf.writable()[0] = b'a';
buf.wrote(1);
buf.wrote(0);
assert_eq!("a", buf.escape_ascii());
let many_bs = "b".repeat(15);
assert_eq!(many_bs.len(), buf.writable().len());
buf.writable().copy_from_slice(many_bs.as_bytes());
buf.wrote(many_bs.len());
assert_eq!("a".to_string() + &many_bs, buf.escape_ascii());
assert!(buf.writable().is_empty());
}
#[test]
#[should_panic(expected = "write would overflow")]
fn test_wrote_too_much() {
let mut buf: FixedBuf<16> = FixedBuf::new();
buf.wrote(17);
}
#[test]
fn test_shift_empty() {
let mut buf: FixedBuf<4> = FixedBuf::new();
buf.shift();
buf.write_bytes("abcd").unwrap();
assert_eq!("abcd", buf.escape_ascii());
}
#[test]
fn test_shift_half_full() {
let mut buf: FixedBuf<6> = FixedBuf::new();
buf.write_bytes("abcd").unwrap();
buf.shift();
buf.try_read_exact(2).unwrap();
buf.write_bytes("ef").unwrap();
assert_eq!(NoWritableSpace {}, buf.write_bytes("gh").unwrap_err());
buf.shift();
buf.write_bytes("gh").unwrap();
assert_eq!("cdefgh", buf.escape_ascii());
}
#[test]
fn test_shift_full() {
let mut buf: FixedBuf<4> = FixedBuf::new();
buf.write_bytes("abcd").unwrap();
buf.shift();
buf.try_read_exact(2).unwrap();
assert_eq!(NoWritableSpace {}, buf.write_bytes("e").unwrap_err());
buf.shift();
buf.write_bytes("e").unwrap();
buf.write_bytes("f").unwrap();
assert_eq!(NoWritableSpace {}, buf.write_bytes("g").unwrap_err());
assert_eq!("cdef", buf.escape_ascii());
}
#[test]
fn test_shift_read_all() {
let mut buf: FixedBuf<4> = FixedBuf::new();
buf.write_bytes("abcd").unwrap();
buf.try_read_exact(4).unwrap();
buf.shift();
buf.write_bytes("efgh").unwrap();
assert_eq!("efgh", buf.escape_ascii());
}
#[test]
fn test_deframe() {
let mut buf: FixedBuf<8> = FixedBuf::new();
assert_eq!(None, buf.deframe(deframe_line_reject_xs).unwrap());
buf.write_bytes("abc").unwrap();
assert_eq!(None, buf.deframe(deframe_line_reject_xs).unwrap());
assert_eq!("abc", buf.escape_ascii());
buf.write_bytes("\n").unwrap();
assert_eq!(Some(0..3), buf.deframe(deframe_line_reject_xs).unwrap());
assert_eq!("", buf.escape_ascii());
buf.write_bytes("x").unwrap();
assert_eq!(
std::io::ErrorKind::InvalidData,
buf.deframe(deframe_line_reject_xs).unwrap_err().kind()
);
}
#[test]
fn test_read_frame_empty_to_eof() {
let mut buf: FixedBuf<8> = FixedBuf::new();
let mut reader = std::io::Cursor::new(b"");
assert_eq!(
None,
buf.read_frame(&mut reader, deframe_line_reject_xs).unwrap()
);
assert_eq!("", buf.escape_ascii());
}
#[test]
fn test_read_frame_empty_to_incomplete() {
let mut buf: FixedBuf<8> = FixedBuf::new();
let mut reader = std::io::Cursor::new(b"abc");
assert_eq!(
std::io::ErrorKind::UnexpectedEof,
buf.read_frame(&mut reader, deframe_line_reject_xs)
.unwrap_err()
.kind()
);
assert_eq!("abc", buf.escape_ascii());
}
#[test]
fn test_read_frame_empty_to_complete() {
let mut buf: FixedBuf<8> = FixedBuf::new();
let mut reader = std::io::Cursor::new(b"abc\n");
assert_eq!(
"abc",
escape_ascii(
buf.read_frame(&mut reader, deframe_line_reject_xs)
.unwrap()
.unwrap()
)
);
assert_eq!("", buf.escape_ascii());
}
#[test]
fn test_read_frame_empty_to_complete_with_leftover() {
let mut buf: FixedBuf<8> = FixedBuf::new();
let mut reader = std::io::Cursor::new(b"abc\nde");
assert_eq!(
"abc",
escape_ascii(
buf.read_frame(&mut reader, deframe_line_reject_xs)
.unwrap()
.unwrap()
)
);
assert_eq!("de", buf.escape_ascii());
}
#[test]
fn test_read_frame_empty_to_invalid() {
let mut buf: FixedBuf<8> = FixedBuf::new();
let mut reader = std::io::Cursor::new(b"x");
assert_eq!(
std::io::ErrorKind::InvalidData,
buf.read_frame(&mut reader, deframe_line_reject_xs)
.unwrap_err()
.kind()
);
assert_eq!("x", buf.escape_ascii());
}
#[test]
fn test_read_frame_incomplete_to_eof() {
let mut buf: FixedBuf<8> = FixedBuf::new();
buf.write_bytes("a").unwrap();
let mut reader = std::io::Cursor::new(b"");
assert_eq!(
std::io::ErrorKind::UnexpectedEof,
buf.read_frame(&mut reader, deframe_line_reject_xs)
.unwrap_err()
.kind()
);
assert_eq!("a", buf.escape_ascii());
}
#[test]
fn test_read_frame_incomplete_to_incomplete() {
let mut buf: FixedBuf<8> = FixedBuf::new();
buf.write_bytes("a").unwrap();
let mut reader = std::io::Cursor::new(b"bc");
assert_eq!(
std::io::ErrorKind::UnexpectedEof,
buf.read_frame(&mut reader, deframe_line_reject_xs)
.unwrap_err()
.kind()
);
assert_eq!("abc", buf.escape_ascii());
}
#[test]
fn test_read_frame_incomplete_to_complete() {
let mut buf: FixedBuf<8> = FixedBuf::new();
buf.write_bytes("a").unwrap();
let mut reader = std::io::Cursor::new(b"bc\n");
assert_eq!(
"abc",
escape_ascii(
buf.read_frame(&mut reader, deframe_line_reject_xs)
.unwrap()
.unwrap()
)
);
assert_eq!("", buf.escape_ascii());
}
#[test]
fn test_read_frame_incomplete_to_complete_with_leftover() {
let mut buf: FixedBuf<8> = FixedBuf::new();
buf.write_bytes("a").unwrap();
let mut reader = std::io::Cursor::new(b"bc\nde");
assert_eq!(
"abc",
escape_ascii(
buf.read_frame(&mut reader, deframe_line_reject_xs)
.unwrap()
.unwrap()
)
);
assert_eq!("de", buf.escape_ascii());
}
#[test]
fn test_read_frame_complete_doesnt_read() {
let mut buf: FixedBuf<8> = FixedBuf::new();
buf.write_bytes("abc\n").unwrap();
assert_eq!(
"abc",
escape_ascii(
buf.read_frame(&mut FakeReadWriter::empty(), deframe_line_reject_xs)
.unwrap()
.unwrap()
)
);
assert_eq!("", buf.escape_ascii());
}
#[test]
fn test_read_frame_complete_leaves_leftovers() {
let mut buf: FixedBuf<8> = FixedBuf::new();
buf.write_bytes("abc\nde").unwrap();
assert_eq!(
"abc",
escape_ascii(
buf.read_frame(&mut FakeReadWriter::empty(), deframe_line_reject_xs)
.unwrap()
.unwrap()
)
);
assert_eq!("de", buf.escape_ascii());
}
#[test]
fn test_read_frame_invalid_doesnt_read() {
let mut buf: FixedBuf<8> = FixedBuf::new();
buf.write_bytes("x").unwrap();
assert_eq!(
std::io::ErrorKind::InvalidData,
buf.read_frame(&mut FakeReadWriter::empty(), deframe_line_reject_xs)
.unwrap_err()
.kind()
);
assert_eq!("x", buf.escape_ascii());
}
#[test]
fn test_read_frame_buffer_full() {
let mut buf: FixedBuf<8> = FixedBuf::new();
buf.write_bytes("abcdefgh").unwrap();
let mut reader = std::io::Cursor::new(b"bc\nde");
assert_eq!(
std::io::ErrorKind::InvalidData,
buf.read_frame(&mut reader, deframe_line_reject_xs)
.unwrap_err()
.kind()
);
assert_eq!("abcdefgh", buf.escape_ascii());
}
#[test]
fn test_readable() {
let mut buf: FixedBuf<16> = FixedBuf::new();
assert_eq!("", escape_ascii(buf.readable()));
buf.write_bytes("abc").unwrap();
assert_eq!("abc", escape_ascii(buf.readable()));
buf.try_read_exact(2).unwrap();
assert_eq!("c", escape_ascii(buf.readable()));
buf.try_read_exact(1).unwrap();
assert_eq!("", escape_ascii(buf.readable()));
buf.write_bytes("d").unwrap();
assert_eq!("d", escape_ascii(buf.readable()));
buf.shift();
assert_eq!("d", escape_ascii(buf.readable()));
}
#[test]
fn test_try_read_exact() {
let mut buf: FixedBuf<16> = FixedBuf::new();
buf.write_bytes("abc").unwrap();
assert_eq!(Some("a".as_bytes()), buf.try_read_exact(1));
assert_eq!("bc", buf.escape_ascii());
assert_eq!(None, buf.try_read_exact(3));
assert_eq!("bc", buf.escape_ascii());
assert_eq!(Some("bc".as_bytes()), buf.try_read_exact(2));
assert_eq!("", buf.escape_ascii());
assert_eq!(None, buf.try_read_exact(1));
assert_eq!("", buf.escape_ascii());
buf.write_bytes("d").unwrap();
buf.shift();
buf.write_bytes("e").unwrap();
assert_eq!(Some("d".as_bytes()), buf.try_read_exact(1));
assert_eq!("e", buf.escape_ascii());
}
#[test]
fn test_read_all() {
let mut buf: FixedBuf<16> = FixedBuf::new();
assert_eq!("", escape_ascii(buf.read_all()));
buf.write_bytes("abc").unwrap();
assert_eq!("abc", escape_ascii(buf.read_all()));
buf.write_bytes("def").unwrap();
assert_eq!("def", escape_ascii(buf.read_all()));
assert_eq!("", escape_ascii(buf.read_all()));
}
#[test]
fn test_read_and_copy_bytes() {
let mut buf: FixedBuf<16> = FixedBuf::new();
buf.write_bytes("abc").unwrap();
let mut one = [0_u8; 1];
assert_eq!(1, buf.read_and_copy_bytes(&mut one));
assert_eq!(b"a", &one);
assert_eq!("bc", buf.escape_ascii());
let mut four = [0_u8; 4];
assert_eq!(2, buf.read_and_copy_bytes(&mut four));
assert_eq!(&[b'b', b'c', 0, 0], &four);
assert_eq!("", buf.escape_ascii());
buf.write_bytes("d").unwrap();
buf.shift();
buf.write_bytes("e").unwrap();
assert_eq!(1, buf.read_and_copy_bytes(&mut one));
assert_eq!(b"d", &one);
assert_eq!("e", buf.escape_ascii());
}
#[test]
fn test_read_and_copy_exact() {
let mut buf: FixedBuf<16> = FixedBuf::new();
buf.write_bytes("abc").unwrap();
let mut one = [0_u8; 1];
buf.read_and_copy_exact(&mut one).unwrap();
assert_eq!(b"a", &one);
assert_eq!("bc", buf.escape_ascii());
let mut three = [0_u8; 3];
assert_eq!(None, buf.read_and_copy_exact(&mut three));
assert_eq!(&[0, 0, 0], &three);
assert_eq!("bc", buf.escape_ascii());
buf.write_bytes("d").unwrap();
buf.shift();
buf.write_bytes("e").unwrap();
buf.read_and_copy_exact(&mut three).unwrap();
assert_eq!(b"bcd", &three);
assert_eq!("e", buf.escape_ascii());
}
#[test]
fn test_copy_once_from() {
let mut buf: FixedBuf<4> = FixedBuf::new();
buf.write_bytes("a").unwrap();
assert_eq!(
2,
buf.copy_once_from(&mut std::io::Cursor::new(b"12"))
.unwrap()
);
assert_eq!("a12", escape_ascii(buf.read_all()));
assert_eq!(
3,
buf.copy_once_from(&mut std::io::Cursor::new(b"123"))
.unwrap()
);
assert_eq!("123", escape_ascii(buf.read_all()));
assert_eq!(
4,
buf.copy_once_from(&mut std::io::Cursor::new(b"1234"))
.unwrap()
);
assert_eq!("1234", escape_ascii(buf.read_all()));
assert_eq!(
4,
buf.copy_once_from(&mut std::io::Cursor::new(b"12345"))
.unwrap()
);
assert_eq!("1234", escape_ascii(buf.read_all()));
buf.write_bytes("abcd").unwrap();
assert_eq!(
std::io::ErrorKind::InvalidData,
buf.copy_once_from(&mut std::io::Cursor::new(b"1"))
.unwrap_err()
.kind()
);
assert_eq!("abcd", escape_ascii(buf.read_all()));
assert_eq!(
2,
buf.copy_once_from(&mut FakeReadWriter::new(vec![Ok(2)]))
.unwrap()
);
assert_eq!("ab", escape_ascii(buf.read_all()));
}
#[test]
fn test_escape_ascii() {
assert_eq!("", FixedBuf::from([]).escape_ascii());
assert_eq!("abc", FixedBuf::from(*b"abc").escape_ascii());
assert_eq!("\\r\\n", FixedBuf::from(*b"\r\n").escape_ascii());
let mut buf: FixedBuf<4> = FixedBuf::new();
buf.write_bytes("€").unwrap();
assert_eq!("\\xe2\\x82\\xac", buf.escape_ascii());
assert_eq!("\\x01", FixedBuf::from([1]).escape_ascii());
let buf = FixedBuf::from(*b"abc");
assert_eq!("abc", buf.escape_ascii());
assert_eq!(b"abc", buf.readable());
}
#[test]
fn test_std_io_write() {
let mut buf: FixedBuf<16> = FixedBuf::new();
std::io::Write::write(&mut buf, b"abc").unwrap();
assert_eq!("abc", buf.escape_ascii());
std::io::Write::write(&mut buf, b"def").unwrap();
assert_eq!("abcdef", buf.escape_ascii());
buf.try_read_exact(1).unwrap();
std::io::Write::write(&mut buf, b"g").unwrap();
assert_eq!("bcdefg", buf.escape_ascii());
std::io::Write::write(&mut buf, "h".repeat(8).as_bytes()).unwrap();
std::io::Write::write(&mut buf, b"i").unwrap();
assert_eq!(
std::io::ErrorKind::InvalidData,
std::io::Write::write(&mut buf, b"def").unwrap_err().kind()
);
}
#[test]
fn test_std_io_flush() {
let mut buf: FixedBuf<16> = FixedBuf::new();
std::io::Write::write(&mut buf, b"abc").unwrap();
std::io::Write::flush(&mut buf).unwrap();
assert_eq!("abc", buf.escape_ascii());
}
#[test]
fn test_std_io_read() {
let mut buf: FixedBuf<16> = FixedBuf::new();
let mut data = [b'.'; 16];
assert_eq!(0, std::io::Read::read(&mut buf, &mut data).unwrap());
assert_eq!("..........", escape_ascii(&data[..10]));
buf.write_bytes("abc").unwrap();
assert_eq!(3, std::io::Read::read(&mut buf, &mut data).unwrap());
assert_eq!("abc.......", escape_ascii(&data[..10]));
assert_eq!(0, std::io::Read::read(&mut buf, &mut data).unwrap());
let many_bs = "b".repeat(16);
buf.write_bytes(&many_bs).unwrap();
assert_eq!(16, std::io::Read::read(&mut buf, &mut data).unwrap());
assert_eq!(many_bs, escape_ascii(&data[..]));
assert_eq!(0, std::io::Read::read(&mut buf, &mut data).unwrap());
}
#[test]
fn test_default() {
let _: FixedBuf<8> = FixedBuf::default();
let _: FixedBuf<16> = FixedBuf::default();
let mut buf: FixedBuf<32> = FixedBuf::default();
buf.write_bytes("abc").unwrap();
assert_eq!("abc", buf.escape_ascii());
}
#[test]
fn test_debug() {
let mut buf: FixedBuf<8> = FixedBuf::new();
buf.write_bytes("abc").unwrap();
buf.try_read_exact(1).unwrap();
assert_eq!(
"FixedBuf<8>{5 writable, 2 readable: \"bc\"}",
format!("{buf:?}")
);
}