//! `block-buffer` tests. use block_buffer::{ EagerBuffer, LazyBuffer, ReadBuffer, array::{ Array, typenum::{U4, U8, U10, U16, U24}, }, }; use hex_literal::hex; use core::{array, panic::AssertUnwindSafe}; use std::panic::catch_unwind; #[test] fn test_eager_digest() { let mut buf = EagerBuffer::::default(); let inputs = [ &b"01234567"[..], &b"89"[..], &b"abcdefghij"[..], &b"klmnopqrs"[..], &b"tuv"[..], &b"wx"[..], ]; let exp_blocks = [ (0, &[b"0123", b"4567"][..]), (2, &[b"89ab"][..]), (2, &[b"cdef", b"ghij"][..]), (3, &[b"klmn", b"opqr"][..]), (4, &[b"stuv"][..]), ]; let exp_poses = [0, 2, 0, 1, 0, 2]; let mut n = 0; for (i, input) in inputs.iter().enumerate() { buf.digest_blocks(input, |b| { let (j, exp) = exp_blocks[n]; n += 1; assert_eq!(i, j); assert_eq!(b.len(), exp.len()); assert!(b.iter().zip(exp.iter()).all(|v| v.0[..] == v.1[..])); }); assert_eq!(exp_poses[i], buf.get_pos()); } assert_eq!(buf.pad_with_zeros()[..], b"wx\0\0"[..]); assert_eq!(buf.get_pos(), 0); } #[test] fn test_lazy_digest() { let mut buf = LazyBuffer::::default(); let inputs = [ &b"01234567"[..], &b"89"[..], &b"abcdefghij"[..], &b"klmnopqrs"[..], ]; let expected = [ (0, &[b"0123"][..]), (1, &[b"4567"][..]), (2, &[b"89ab"][..]), (2, &[b"cdef"][..]), (3, &[b"ghij"][..]), (3, &[b"klmn", b"opqr"][..]), ]; let exp_poses = [4, 2, 4, 1]; let mut n = 0; for (i, input) in inputs.iter().enumerate() { buf.digest_blocks(input, |b| { let (j, exp) = expected[n]; n += 1; assert_eq!(i, j); assert_eq!(b.len(), exp.len()); assert!(b.iter().zip(exp.iter()).all(|v| v.0[..] == v.1[..])); }); assert_eq!(exp_poses[i], buf.get_pos()); } assert_eq!(buf.pad_with_zeros()[..], b"s\0\0\0"[..]); assert_eq!(buf.get_pos(), 0); } #[test] fn digest_pad_combinations() { let delim = 0x80; let data: [u8; 7] = array::from_fn(|i| u8::try_from(i).unwrap()); let suffix: [u8; 7] = array::from_fn(|i| u8::try_from(i + 0x10).unwrap()); for data_len in 0..data.len() { for suffix_len in 0..suffix.len() { let data = &data[..data_len]; let suffix = &suffix[..suffix_len]; let mut buf = EagerBuffer::::default(); buf.digest_blocks(data, |_| panic!("should not be called")); let mut accum = Vec::with_capacity(2 * buf.size()); buf.digest_pad(delim, suffix, |block| accum.extend_from_slice(block)); assert!(accum.len() <= 2 * buf.size()); assert_eq!(buf.get_pos(), 0); let (res_data, rem) = accum.split_at(data_len); let (res_delim, rem) = rem.split_at(1); let (res_zeros, res_suffix) = rem.split_at(rem.len() - suffix_len); assert_eq!(res_data, data); assert_eq!(res_delim, &[delim]); assert!(res_zeros.iter().all(|&b| b == 0)); assert_eq!(res_suffix, suffix); } } } #[test] fn test_read() { type Buf = ReadBuffer; let mut buf = Buf::default(); let mut n = 0u8; let mut g = |block: &mut Array| { block.iter_mut().for_each(|b| { *b = n; n += 1; }); }; let res = buf.read_cached(0); assert!(res.is_empty()); let res = buf.read_cached(10); assert!(res.is_empty()); buf.write_block(2, &mut g, |buf| assert_eq!(buf, [0, 1])); assert_eq!(buf.remaining(), 2); let res = buf.read_cached(1); assert_eq!(res, [2]); let res = buf.read_cached(10); assert_eq!(res, [3]); assert_eq!(buf.remaining(), 0); buf.write_block(0, |_| unreachable!(), |_| unreachable!()); buf.write_block(3, &mut g, |buf| assert_eq!(buf, [4, 5, 6])); assert_eq!(buf.remaining(), 1); buf.write_block(0, |_| unreachable!(), |_| unreachable!()); assert_eq!(buf.remaining(), 1); let res = buf.read_cached(10); assert_eq!(res, [7]); buf.write_block(1, &mut g, |buf| assert_eq!(buf, [8])); assert_eq!(buf.remaining(), 3); let res = buf.read_cached(10); assert_eq!(res, [9, 10, 11]); assert_eq!(buf.remaining(), 0); } #[test] fn test_eager_paddings() { let mut buf_be = EagerBuffer::::new(&[0x42]); let mut buf_le = buf_be.clone(); let mut out_be = Vec::::new(); let mut out_le = Vec::::new(); let len = 0x0001_0203_0405_0607; buf_be.len64_padding_be(len, |block| out_be.extend(block)); buf_le.len64_padding_le(len, |block| out_le.extend(block)); assert_eq!(out_be, hex!("4280000000000000 0001020304050607")); assert_eq!(out_le, hex!("4280000000000000 0706050403020100")); let mut buf_be = EagerBuffer::::new(&[0x42]); let mut buf_le = buf_be.clone(); let mut out_be = Vec::::new(); let mut out_le = Vec::::new(); buf_be.len64_padding_be(len, |block| out_be.extend(block)); buf_le.len64_padding_le(len, |block| out_le.extend(block)); assert_eq!(out_be, hex!("42800001020304050607")); assert_eq!(out_le, hex!("42800706050403020100")); let mut buf = EagerBuffer::::new(&[0x42]); let mut out = Vec::::new(); let len = 0x0001_0203_0405_0607_0809_0a0b_0c0d_0e0f; buf.len128_padding_be(len, |block| out.extend(block)); assert_eq!( out, hex!( "42800000000000000000000000000000" "000102030405060708090a0b0c0d0e0f" ), ); let mut buf = EagerBuffer::::new(&[0x42]); let mut out = Vec::::new(); let len = 0x0001_0203_0405_0607_0809_0a0b_0c0d_0e0f; buf.len128_padding_be(len, |block| out.extend(block)); assert_eq!( out, hex!("4280000000000000 0001020304050607 08090a0b0c0d0e0f") ); let mut buf = EagerBuffer::::new(&[0x42]); let mut out = Vec::::new(); buf.digest_pad(0xff, &hex!("101112"), |block| out.extend(block)); assert_eq!(out, hex!("42ff000000101112")); let mut buf = EagerBuffer::::new(&[0x42]); let mut out = Vec::::new(); buf.digest_pad(0xff, &hex!("1011"), |block| out.extend(block)); assert_eq!(out, hex!("42ff1011")); } #[test] fn test_try_new() { assert!(EagerBuffer::::try_new(&[0; 3]).is_ok()); assert!(EagerBuffer::::try_new(&[0; 4]).is_err()); assert!(LazyBuffer::::try_new(&[0; 4]).is_ok()); assert!(LazyBuffer::::try_new(&[0; 5]).is_err()); } #[test] fn test_eager_serialize() { type Buf = EagerBuffer; let mut buf1 = Buf::default(); let ser0 = buf1.serialize(); assert_eq!(&ser0[..], &[0, 0, 0, 0]); assert_eq!(Buf::deserialize(&ser0).unwrap().serialize(), ser0); buf1.digest_blocks(&[41, 42], |_| {}); let ser1 = buf1.serialize(); assert_eq!(&ser1[..], &[2, 41, 42, 0]); let mut buf2 = Buf::deserialize(&ser1).unwrap(); assert_eq!(buf1.serialize(), ser1); buf1.digest_blocks(&[43], |_| {}); buf2.digest_blocks(&[43], |_| {}); let ser2 = buf1.serialize(); assert_eq!(&ser2[..], &[3, 41, 42, 43]); assert_eq!(buf1.serialize(), ser2); let mut buf3 = Buf::deserialize(&ser2).unwrap(); assert_eq!(buf3.serialize(), ser2); buf1.digest_blocks(&[44], |_| {}); buf2.digest_blocks(&[44], |_| {}); buf3.digest_blocks(&[44], |_| {}); let ser3 = buf1.serialize(); assert_eq!(&ser3[..], &[0, 0, 0, 0]); assert_eq!(buf2.serialize(), ser3); assert_eq!(buf3.serialize(), ser3); // Invalid position let buf = Array([0, 0, 0, 4]); assert!(Buf::deserialize(&buf).is_err()); let buf = Array([0, 0, 0, 10]); assert!(Buf::deserialize(&buf).is_err()); // "Garbage" bytes are not zeroized let buf = Array([0, 1, 0, 0]); assert!(Buf::deserialize(&buf).is_err()); let buf = Array([1, 0, 1, 0]); assert!(Buf::deserialize(&buf).is_err()); let buf = Array([2, 0, 0, 1]); assert!(Buf::deserialize(&buf).is_err()); } #[test] fn test_lazy_serialize() { type Buf = LazyBuffer; let mut buf1 = Buf::default(); let ser0 = buf1.serialize(); assert_eq!(&ser0[..], &[0, 0, 0, 0, 0]); Buf::deserialize(&ser0).unwrap(); assert_eq!(Buf::deserialize(&ser0).unwrap().serialize(), ser0); buf1.digest_blocks(&[41, 42], |_| {}); let ser1 = buf1.serialize(); assert_eq!(&ser1[..], &[2, 41, 42, 0, 0]); let mut buf2 = Buf::deserialize(&ser1).unwrap(); assert_eq!(buf1.serialize(), ser1); buf1.digest_blocks(&[43], |_| {}); buf2.digest_blocks(&[43], |_| {}); let ser2 = buf1.serialize(); assert_eq!(&ser2[..], &[3, 41, 42, 43, 0]); assert_eq!(buf1.serialize(), ser2); let mut buf3 = Buf::deserialize(&ser2).unwrap(); assert_eq!(buf3.serialize(), ser2); buf1.digest_blocks(&[44], |_| {}); buf2.digest_blocks(&[44], |_| {}); buf3.digest_blocks(&[44], |_| {}); let ser3 = buf1.serialize(); assert_eq!(&ser3[..], &[4, 41, 42, 43, 44]); assert_eq!(buf2.serialize(), ser3); assert_eq!(buf3.serialize(), ser3); buf1.digest_blocks(&[45], |_| {}); buf2.digest_blocks(&[45], |_| {}); buf3.digest_blocks(&[45], |_| {}); let ser4 = buf1.serialize(); assert_eq!(&ser4[..], &[1, 45, 0, 0, 0]); assert_eq!(buf2.serialize(), ser4); assert_eq!(buf3.serialize(), ser4); // Invalid position let buf = Array([10, 0, 0, 0, 0]); assert!(Buf::deserialize(&buf).is_err()); let buf = Array([5, 0, 0, 0, 0]); assert!(Buf::deserialize(&buf).is_err()); // "Garbage" bytes are not zeroized let buf = Array([0, 1, 0, 0, 0]); assert!(Buf::deserialize(&buf).is_err()); let buf = Array([1, 0, 1, 0, 0]); assert!(Buf::deserialize(&buf).is_err()); let buf = Array([2, 0, 0, 1, 0]); assert!(Buf::deserialize(&buf).is_err()); let buf = Array([3, 0, 0, 0, 1]); assert!(Buf::deserialize(&buf).is_err()); } #[test] fn test_read_serialize() { type Buf = ReadBuffer; let mut n = 0u8; let mut g = |block: &mut Array| { block.iter_mut().for_each(|b| { *b = n; n += 1; }); }; let mut buf = Buf::default(); let ser1 = buf.serialize(); assert_eq!(&ser1[..], &[4, 0, 0, 0]); assert_eq!(Buf::deserialize(&ser1).unwrap().serialize(), ser1); let mut buf1 = Buf::deserialize(&ser1).unwrap(); assert_eq!(buf1.serialize(), ser1); assert_eq!(buf1.remaining(), 0); assert_eq!(buf1.read_cached(10), []); buf.write_block(2, &mut g, |buf| assert_eq!(buf, [0, 1])); let ser2 = buf.serialize(); assert_eq!(&ser2[..], &[2, 0, 2, 3]); let mut buf2 = Buf::deserialize(&ser2).unwrap(); assert_eq!(buf2.serialize(), ser2); assert_eq!(buf2.remaining(), 2); assert_eq!(buf2.read_cached(10), [2, 3]); // Invalid position let buf = Array([0, 0, 0, 0]); assert!(Buf::deserialize(&buf).is_err()); let buf = Array([5, 0, 0, 0]); assert!(Buf::deserialize(&buf).is_err()); let buf = Array([10, 0, 0, 0]); assert!(Buf::deserialize(&buf).is_err()); // "Garbage" bytes are not zeroized let buf = Array([2, 1, 0, 0]); assert!(Buf::deserialize(&buf).is_err()); let buf = Array([3, 0, 1, 0]); assert!(Buf::deserialize(&buf).is_err()); let buf = Array([4, 0, 0, 1]); assert!(Buf::deserialize(&buf).is_err()); } #[test] fn eager_buffer_exception_safety() { let mut buf = EagerBuffer::::default(); let res = catch_unwind(AssertUnwindSafe(|| { buf.digest_blocks(b"ab", |_| {}); buf.digest_blocks(b"cd", |_| panic!("compression panic")); })); assert!(res.is_err()); let _ = buf.get_pos(); let mut buf = EagerBuffer::::default(); let res = catch_unwind(AssertUnwindSafe(|| { buf.digest_pad(0x80, &[0xFF; 2], |_| panic!("compression panic")); })); assert!(res.is_err()); let _ = buf.get_pos(); } #[test] fn read_buffer_exception_safety() { let mut buf = ReadBuffer::::default(); let res = catch_unwind(AssertUnwindSafe(|| { buf.write_block( 1, |block| { block[0] = 0xFF; panic!("block generation panic"); }, |_| {}, ); })); assert!(res.is_err()); let _ = buf.get_pos(); let mut buf = ReadBuffer::::default(); let res = catch_unwind(AssertUnwindSafe(|| { buf.write_block( 1, |block| block.0 = [0xFF; 4], |_| panic!("data read panic"), ); })); assert!(res.is_err()); let _ = buf.get_pos(); }