use core::ops::{Bound, RangeBounds};
use super::*;
fn check(value: u64, encoded: &[u8]) {
let a = encode_u64_varint(value);
assert_eq!(a.as_ref(), encoded);
assert_eq!(a.len(), encoded.len());
assert_eq!(a.len(), encoded_u64_varint_len(value).get());
let (read, decoded) = decode_u64_varint(&a).unwrap();
assert_eq!(decoded, value);
assert_eq!(read.get(), encoded.len());
assert_eq!(a.len(), encoded_u64_varint_len(value).get());
}
#[test]
fn roundtrip_u64() {
check(2u64.pow(0) - 1, &[0x00]);
check(2u64.pow(0), &[0x01]);
check(2u64.pow(7) - 1, &[0x7F]);
check(2u64.pow(7), &[0x80, 0x01]);
check(300u64, &[0xAC, 0x02]);
check(2u64.pow(14) - 1, &[0xFF, 0x7F]);
check(2u64.pow(14), &[0x80, 0x80, 0x01]);
check(2u64.pow(21) - 1, &[0xFF, 0xFF, 0x7F]);
check(2u64.pow(21), &[0x80, 0x80, 0x80, 0x01]);
check(2u64.pow(28) - 1, &[0xFF, 0xFF, 0xFF, 0x7F]);
check(2u64.pow(28), &[0x80, 0x80, 0x80, 0x80, 0x01]);
check(2u64.pow(35) - 1, &[0xFF, 0xFF, 0xFF, 0xFF, 0x7F]);
check(2u64.pow(35), &[0x80, 0x80, 0x80, 0x80, 0x80, 0x01]);
check(2u64.pow(42) - 1, &[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F]);
check(2u64.pow(42), &[0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x01]);
check(
2u64.pow(49) - 1,
&[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F],
);
check(
2u64.pow(49),
&[0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x01],
);
check(
2u64.pow(56) - 1,
&[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F],
);
check(
2u64.pow(56),
&[0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x01],
);
check(
2u64.pow(63) - 1,
&[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F],
);
check(
2u64.pow(63),
&[0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x01],
);
check(
u64::MAX,
&[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01],
);
}
#[test]
fn test_large_number_encode_decode() {
let original = 30000u64;
let encoded = encode_u64_varint(original);
let (bytes_read, decoded) = decode_u64_varint(&encoded).unwrap();
assert_eq!(original, decoded);
assert_eq!(bytes_read.get(), encoded.len());
}
#[test]
fn test_decode_overflow_error() {
let buffer = [0x80u8; 11]; match decode_u64_varint(&buffer) {
Err(ConstDecodeError::Overflow) => (),
_ => panic!("Expected Overflow error"),
}
let buffer = [0x80u8; 6]; match decode_u32_varint(&buffer) {
Err(ConstDecodeError::Overflow) => (),
_ => panic!("Expected Overflow error"),
}
let buffer = [0x80u8; 4]; match decode_u16_varint(&buffer) {
Err(ConstDecodeError::Overflow) => (),
_ => panic!("Expected Overflow error"),
}
}
fn test_zigzag_encode_decode<T>(value: T)
where
T: Copy
+ PartialEq
+ core::fmt::Debug
+ core::ops::Shl<Output = T>
+ core::ops::Shr<Output = T>
+ Into<i64>
+ core::convert::TryInto<usize>
+ core::convert::TryFrom<usize>,
{
let encoded = encode_i64_varint(value.into());
let bytes_written = encoded.len();
let decode_result = decode_i64_varint(&encoded);
assert!(decode_result.is_ok(), "Decoding failed");
let (decoded_bytes, decoded_value) = decode_result.unwrap();
assert_eq!(
decoded_bytes.get(),
bytes_written,
"Incorrect number of bytes decoded"
);
assert_eq!(
decoded_value,
value.into(),
"Decoded value does not match original"
);
}
#[test]
fn test_zigzag_encode_decode_i8() {
let values = [-1, 0, 1, -100, 100, i8::MIN, i8::MAX];
for &value in &values {
test_zigzag_encode_decode(value);
}
}
#[test]
fn test_zigzag_encode_decode_i16() {
let values = [-1, 0, 1, -100, 100, i16::MIN, i16::MAX];
for &value in &values {
test_zigzag_encode_decode(value);
}
}
#[test]
fn test_zigzag_encode_decode_i32() {
let values = [-1, 0, 1, -10000, 10000, i32::MIN, i32::MAX];
for &value in &values {
test_zigzag_encode_decode(value);
}
}
#[test]
fn test_zigzag_encode_decode_i64() {
let values = [-1, 0, 1, -1000000000, 1000000000, i64::MIN, i64::MAX];
for &value in &values {
test_zigzag_encode_decode(value);
}
}
#[test]
fn test_encode_error_update() {
let ent = ConstEncodeError::insufficient_space(NON_ZERO_USIZE_ONE, 0)
.update(NonZeroUsize::new(4).unwrap(), 0);
let exp = ConstEncodeError::insufficient_space(NonZeroUsize::new(4).unwrap(), 0);
assert_eq!(ent, exp);
let ent = ConstEncodeError::other("test").update(NonZeroUsize::new(4).unwrap(), 0);
assert!(matches!(ent, ConstEncodeError::Other(_)));
}
#[test]
#[should_panic]
fn test_consume_varint_empty() {
consume_varint(&[]);
}
#[test]
#[should_panic]
fn test_consume_varint_bad() {
consume_varint(&[0x80, 0x80, 0x80, 0x80]);
}
#[test]
fn test_consume_varint_checked_empty() {
let result = consume_varint_checked(&[]);
assert!(result.is_none());
}
#[test]
fn test_consume_varint_checked_bad1() {
let result = consume_varint_checked(&[0x80, 0x80, 0x80, 0x80]);
assert!(result.is_none());
}
#[test]
fn test_consume_varint_checked_bad2() {
let result = consume_varint_checked(&[0x80]);
assert!(result.is_none());
}
#[test]
fn test_try_consume_varint_empty() {
let result = try_consume_varint(&[]);
assert!(result.is_err());
}
#[test]
fn test_try_consume_varint_bad1() {
let result = try_consume_varint(&[0x80, 0x80, 0x80, 0x80]);
assert!(result.is_err());
}
#[test]
fn test_try_consume_varint_bad2() {
let result = try_consume_varint(&[0x80]);
assert!(result.is_err());
}
#[allow(clippy::clone_on_copy)]
#[test]
fn test_map_decoder_clone_and_copy() {
let original = MapDecoder::<u64, u64>::new(&[]);
let cloned = original.clone();
let copied = original;
assert_eq!(cloned.position(), original.position());
assert_eq!(copied.position(), original.position());
}
#[allow(clippy::clone_on_copy)]
#[test]
fn test_seq_decoder_clone_and_copy() {
let original = SequenceDecoder::<u64>::new(&[]);
let cloned = original.clone();
let copied = original;
assert_eq!(cloned.position(), original.position());
assert_eq!(copied.position(), original.position());
}
#[derive(Debug)]
struct AdversarialDecodeLength;
impl Varint for AdversarialDecodeLength {
const MIN_ENCODED_LEN: NonZeroUsize = NON_ZERO_USIZE_ONE;
const MAX_ENCODED_LEN: NonZeroUsize = NON_ZERO_USIZE_ONE;
fn encoded_len(&self) -> NonZeroUsize {
NON_ZERO_USIZE_ONE
}
fn encode(&self, _: &mut [u8]) -> Result<NonZeroUsize, EncodeError> {
Err(EncodeError::other("encoding is not used by this test type"))
}
fn decode(buf: &[u8]) -> Result<(NonZeroUsize, Self), DecodeError> {
let consumed = if matches!(buf.first(), Some(0)) {
NON_ZERO_USIZE_ONE
} else {
NonZeroUsize::new(usize::MAX).unwrap()
};
Ok((consumed, Self))
}
}
#[derive(Debug, PartialEq, Eq)]
struct ItemCount(usize);
impl<T> core::iter::FromIterator<T> for ItemCount {
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
Self(iter.into_iter().count())
}
}
#[test]
fn sequence_decoder_rejects_wrapping_consumed_length() {
let buf = [0, 1];
let mut decoder = sequence_decoder::<AdversarialDecodeLength>(&buf);
let (consumed, _) = decoder.next().unwrap().unwrap();
assert_eq!(consumed, NON_ZERO_USIZE_ONE);
assert_eq!(decoder.position(), 1);
assert!(matches!(decoder.next(), Some(Err(DecodeError::Other(_)))));
assert_eq!(decoder.position(), buf.len());
assert!(decoder.next().is_none());
}
#[test]
fn decode_sequence_rejects_invalid_consumed_length() {
assert!(matches!(
decode_sequence::<AdversarialDecodeLength, ItemCount>(&[0, 1]),
Err(DecodeError::Other(_))
));
assert!(matches!(
decode_sequence::<AdversarialDecodeLength, ItemCount>(&[1]),
Err(DecodeError::Other(_))
));
}
#[test]
fn map_decoder_rejects_wrapping_consumed_length() {
let buf = [0];
let mut decoder = map_decoder::<AdversarialDecodeLength, AdversarialDecodeLength>(&buf);
assert!(matches!(decoder.next(), Some(Err(DecodeError::Other(_)))));
assert_eq!(decoder.position(), buf.len());
assert!(decoder.next().is_none());
}
#[test]
fn map_decoder_rejects_out_of_bounds_key_length() {
let buf = [1];
let mut decoder = map_decoder::<AdversarialDecodeLength, AdversarialDecodeLength>(&buf);
assert!(matches!(decoder.next(), Some(Err(DecodeError::Other(_)))));
assert_eq!(decoder.position(), buf.len());
assert!(decoder.next().is_none());
}
#[test]
fn decode_map_rejects_invalid_consumed_lengths() {
assert!(matches!(
decode_map::<AdversarialDecodeLength, AdversarialDecodeLength, ItemCount>(&[0]),
Err(DecodeError::Other(_))
));
assert!(matches!(
decode_map::<AdversarialDecodeLength, AdversarialDecodeLength, ItemCount>(&[1]),
Err(DecodeError::Other(_))
));
}
#[allow(dead_code)]
#[test]
fn test_default_varint_range() {
struct Wrap(u64);
impl Varint for Wrap {
const MIN_ENCODED_LEN: NonZeroUsize = u64::MIN_ENCODED_LEN;
const MAX_ENCODED_LEN: NonZeroUsize = u64::MAX_ENCODED_LEN;
fn encoded_len(&self) -> NonZeroUsize {
todo!()
}
fn encode(&self, _: &mut [u8]) -> Result<NonZeroUsize, EncodeError> {
todo!()
}
fn decode(_: &[u8]) -> Result<(NonZeroUsize, Self), DecodeError>
where
Self: Sized,
{
todo!()
}
}
let range = Wrap::ENCODED_LEN_RANGE;
assert_eq!(range.start_bound(), Bound::Included(&u64::MIN_ENCODED_LEN));
assert_eq!(range.end_bound(), Bound::Included(&u64::MAX_ENCODED_LEN));
}
#[test]
fn encode_u8_sequence_to_empty_buffer_and_nonempty_sequence_errors() {
let err = encode_u8_sequence_to(&[1u8, 2u8], &mut []).unwrap_err();
assert!(matches!(err, ConstEncodeError::InsufficientSpace(_)));
}
#[test]
fn encode_u8_sequence_to_one_byte_too_short_errors() {
let err = encode_u8_sequence_to(&[1u8, 2u8], &mut [0u8; 1]).unwrap_err();
match err {
ConstEncodeError::InsufficientSpace(iss) => {
assert_eq!(iss.requested().get(), 2);
assert_eq!(iss.available(), 1);
}
other => panic!("expected InsufficientSpace, got {other:?}"),
}
}
#[test]
fn encode_u8_sequence_to_exact_fit_roundtrips() {
let seq = [1u8, 2u8, 200u8];
let total = encoded_u8_sequence_len(&seq);
assert_eq!(total, 4);
let mut buf = [0u8; 4];
let written = encode_u8_sequence_to(&seq, &mut buf).unwrap();
assert_eq!(written, total);
let mut offset = 0;
for &expected in &seq {
let (read, value) = decode_u8_varint(&buf[offset..written]).unwrap();
assert_eq!(value, expected);
offset += read.get();
}
assert_eq!(offset, written);
}
#[test]
fn encode_u8_sequence_to_oversized_buffer_ok() {
let seq = [1u8, 2u8, 200u8];
let total = encoded_u8_sequence_len(&seq);
let mut buf = [0xFFu8; 16];
let written = encode_u8_sequence_to(&seq, &mut buf).unwrap();
assert_eq!(written, total);
let mut offset = 0;
for &expected in &seq {
let (read, value) = decode_u8_varint(&buf[offset..written]).unwrap();
assert_eq!(value, expected);
offset += read.get();
}
assert_eq!(offset, written);
}
#[test]
fn encode_u8_sequence_to_empty_sequence_ok() {
let seq: [u8; 0] = [];
assert_eq!(encode_u8_sequence_to(&seq, &mut []).unwrap(), 0);
assert_eq!(encode_u8_sequence_to(&seq, &mut [0xFFu8; 4]).unwrap(), 0);
}
#[test]
fn encode_u16_sequence_to_empty_buffer_and_nonempty_sequence_errors() {
let err = encode_u16_sequence_to(&[1u16, 2u16], &mut []).unwrap_err();
assert!(matches!(err, ConstEncodeError::InsufficientSpace(_)));
}
#[test]
fn encode_u16_sequence_to_one_byte_too_short_errors() {
let err = encode_u16_sequence_to(&[300u16, 300u16], &mut [0u8; 2]).unwrap_err();
match err {
ConstEncodeError::InsufficientSpace(iss) => {
assert_eq!(iss.requested().get(), 4);
assert_eq!(iss.available(), 2);
}
other => panic!("expected InsufficientSpace, got {other:?}"),
}
}
#[test]
fn encode_u16_sequence_to_exact_fit_roundtrips() {
let seq = [1u16, 2u16, 300u16];
let total = encoded_u16_sequence_len(&seq);
assert_eq!(total, 4);
let mut buf = [0u8; 4];
let written = encode_u16_sequence_to(&seq, &mut buf).unwrap();
assert_eq!(written, total);
let mut offset = 0;
for &expected in &seq {
let (read, value) = decode_u16_varint(&buf[offset..written]).unwrap();
assert_eq!(value, expected);
offset += read.get();
}
assert_eq!(offset, written);
}
#[test]
fn encode_u16_sequence_to_oversized_buffer_ok() {
let seq = [1u16, 2u16, 300u16];
let total = encoded_u16_sequence_len(&seq);
let mut buf = [0xFFu8; 16];
let written = encode_u16_sequence_to(&seq, &mut buf).unwrap();
assert_eq!(written, total);
let mut offset = 0;
for &expected in &seq {
let (read, value) = decode_u16_varint(&buf[offset..written]).unwrap();
assert_eq!(value, expected);
offset += read.get();
}
assert_eq!(offset, written);
}
#[test]
fn encode_u16_sequence_to_empty_sequence_ok() {
let seq: [u16; 0] = [];
assert_eq!(encode_u16_sequence_to(&seq, &mut []).unwrap(), 0);
assert_eq!(encode_u16_sequence_to(&seq, &mut [0xFFu8; 4]).unwrap(), 0);
}
#[test]
fn encode_i16_sequence_to_empty_buffer_and_nonempty_sequence_errors() {
let err = encode_i16_sequence_to(&[1i16, 2i16], &mut []).unwrap_err();
assert!(matches!(err, ConstEncodeError::InsufficientSpace(_)));
}
#[test]
fn encode_i16_sequence_to_one_byte_too_short_errors() {
let err = encode_i16_sequence_to(&[1i16, 2i16], &mut [0u8; 1]).unwrap_err();
match err {
ConstEncodeError::InsufficientSpace(iss) => {
assert_eq!(iss.requested().get(), 2);
assert_eq!(iss.available(), 1);
}
other => panic!("expected InsufficientSpace, got {other:?}"),
}
}
#[test]
fn encode_i16_sequence_to_exact_fit_roundtrips() {
let seq = [1i16, -2i16, 1000i16];
let total = encoded_i16_sequence_len(&seq);
assert_eq!(total, 4);
let mut buf = [0u8; 4];
let written = encode_i16_sequence_to(&seq, &mut buf).unwrap();
assert_eq!(written, total);
let mut offset = 0;
for &expected in &seq {
let (read, value) = decode_i16_varint(&buf[offset..written]).unwrap();
assert_eq!(value, expected);
offset += read.get();
}
assert_eq!(offset, written);
}
#[test]
fn encode_i16_sequence_to_oversized_buffer_ok() {
let seq = [1i16, -2i16, 1000i16];
let total = encoded_i16_sequence_len(&seq);
let mut buf = [0xFFu8; 16];
let written = encode_i16_sequence_to(&seq, &mut buf).unwrap();
assert_eq!(written, total);
let mut offset = 0;
for &expected in &seq {
let (read, value) = decode_i16_varint(&buf[offset..written]).unwrap();
assert_eq!(value, expected);
offset += read.get();
}
assert_eq!(offset, written);
}
#[test]
fn encode_i16_sequence_to_empty_sequence_ok() {
let seq: [i16; 0] = [];
assert_eq!(encode_i16_sequence_to(&seq, &mut []).unwrap(), 0);
assert_eq!(encode_i16_sequence_to(&seq, &mut [0xFFu8; 4]).unwrap(), 0);
}