#![forbid(unsafe_code)] mod test_utils; use crate::test_utils::FakeReadWriter; use fixed_buffer::{deframe_line, escape_ascii, FixedBuf, MalformedInputError, NoWritableSpace}; use once_cell::sync::Lazy; use std::sync::Mutex; static STATIC_FIXED_BUF: Lazy>> = Lazy::new(|| Mutex::new(FixedBuf::new())); fn deframe_line_reject_xs( data: &[u8], ) -> Result<(usize, Option>), 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(); // Larger sizes will overflow the stack. } #[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); 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(); // Empty assert_eq!(None, buf.deframe(deframe_line_reject_xs).unwrap()); // Incomplete buf.write_bytes("abc").unwrap(); assert_eq!(None, buf.deframe(deframe_line_reject_xs).unwrap()); assert_eq!("abc", buf.escape_ascii()); // Complete buf.write_bytes("\n").unwrap(); assert_eq!(Some(0..3), buf.deframe(deframe_line_reject_xs).unwrap()); assert_eq!("", buf.escape_ascii()); // Error 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(); // Appends existing data. 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())); // EOF, doesn't fill buffer. assert_eq!( 3, buf.copy_once_from(&mut std::io::Cursor::new(b"123")) .unwrap() ); assert_eq!("123", escape_ascii(buf.read_all())); // EOF, fills buffer. assert_eq!( 4, buf.copy_once_from(&mut std::io::Cursor::new(b"1234")) .unwrap() ); assert_eq!("1234", escape_ascii(buf.read_all())); // Fills buffer. assert_eq!( 4, buf.copy_once_from(&mut std::io::Cursor::new(b"12345")) .unwrap() ); assert_eq!("1234", escape_ascii(buf.read_all())); // Buffer already full 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())); // Reads only once. 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_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:?}") ); }