#[cfg(test)]
mod test1 {
use vu64::{
self, check_result_with_length, decode, decode_with_length, decoded_len, encode,
encoded_len, Error, Vu64, MAX_BYTES,
};
#[test]
fn test_memory_layout() {
use std::mem::{align_of, size_of};
let expected_size = 1 + MAX_BYTES;
assert!(
size_of::<Vu64>() <= expected_size + 7, "Size of Vu64 should be around {}, but was {}",
expected_size,
size_of::<Vu64>()
);
assert_eq!(align_of::<Vu64>(), 1, "Alignment of Vu64 should be 1");
assert_eq!(size_of::<Error>(), 1, "Size of Error enum should be 1 byte");
assert_eq!(
align_of::<Error>(),
1,
"Alignment of Error enum should be 1"
);
}
#[test]
fn test_decode_truncated() {
let enc_max = vu64::encode(u64::MAX);
let bytes = enc_max.as_ref();
assert_eq!(bytes.len(), 9);
for i in 1..bytes.len() {
let slice = &bytes[..i];
let err = vu64::decode(slice).unwrap_err();
assert_eq!(err, Error::Truncated, "Failed for slice of length {}", i);
}
let val = vu64::MAX_LEN4;
let enc_val = vu64::encode(val);
let bytes_val = enc_val.as_ref();
assert_eq!(bytes_val.len(), 4);
for i in 1..bytes_val.len() {
let slice = &bytes_val[..i];
let err = vu64::decode(slice).unwrap_err();
assert_eq!(
err,
Error::Truncated,
"Failed for slice of length {} on a 4-byte value",
i
);
}
}
#[test]
fn test_redundant_encodings() {
let redundant_2_byte = &[0x81, 0x00]; assert_eq!(vu64::decode(redundant_2_byte), Err(Error::RedundantEncode));
let redundant_3_byte = &[0xC0, 0x80, 0x00]; assert_eq!(vu64::decode(redundant_3_byte), Err(Error::RedundantEncode));
}
#[test]
fn test_from_u64_for_vu64() {
let val: u64 = 12345;
let vu64_val: Vu64 = val.into();
let decoded = vu64::decode(vu64_val.as_ref()).unwrap();
assert_eq!(decoded, val);
let zero: u64 = 0;
let vu64_zero: Vu64 = zero.into();
let decoded_zero = vu64::decode(vu64_zero.as_ref()).unwrap();
assert_eq!(decoded_zero, zero);
let max: u64 = u64::MAX;
let vu64_max: Vu64 = max.into();
let decoded_max = vu64::decode(vu64_max.as_ref()).unwrap();
assert_eq!(decoded_max, max);
}
#[test]
fn test_decode_with_length_function() {
let value = 123456;
let encoded = encode(value);
let slice = encoded.as_ref();
let len = encoded_len(value);
assert_eq!(decode_with_length(len, slice).unwrap(), value);
let result = decode_with_length(len, &slice[..len as usize - 1]);
assert_eq!(result, Err(Error::Truncated));
}
#[test]
fn test_check_result_with_length_function() {
assert_eq!(check_result_with_length(1, 100).unwrap(), 100);
let val = 1 << 7;
assert_eq!(check_result_with_length(2, val).unwrap(), val);
let val = (1 << 7) - 1;
assert_eq!(check_result_with_length(2, val), Err(Error::RedundantEncode));
let val = u64::MAX;
assert_eq!(check_result_with_length(9, val).unwrap(), val);
let val = (1 << 56) - 1;
assert_eq!(check_result_with_length(9, val), Err(Error::RedundantEncode));
}
#[test]
fn test_vu64_struct_impls() {
let value = 9876543210;
let vu64: Vu64 = value.into();
let encoded_ref = vu64.as_ref();
let decoded_from_ref = decode(encoded_ref).unwrap();
assert_eq!(decoded_from_ref, value);
let debug_str = format!("{:?}", vu64);
assert_eq!(debug_str, format!("V64({})", value));
let cloned_vu64 = vu64;
assert_eq!(vu64.as_ref(), cloned_vu64.as_ref());
let another_vu64: Vu64 = value.into();
assert_eq!(vu64, another_vu64);
let different_value: u64 = 123;
let different_vu64: Vu64 = different_value.into();
assert_ne!(vu64, different_vu64);
}
#[test]
fn test_decoded_len_exhaustive() {
for i in 0..=0x7F {
assert_eq!(decoded_len(i), 1);
}
for i in 0x80..=0xBF {
assert_eq!(decoded_len(i), 2);
}
for i in 0xC0..=0xDF {
assert_eq!(decoded_len(i), 3);
}
for i in 0xE0..=0xEF {
assert_eq!(decoded_len(i), 4);
}
for i in 0xF0..=0xF7 {
assert_eq!(decoded_len(i), 5);
}
for i in 0xF8..=0xFB {
assert_eq!(decoded_len(i), 6);
}
for i in 0xFC..=0xFD {
assert_eq!(decoded_len(i), 7);
}
assert_eq!(decoded_len(0xFE), 8);
assert_eq!(decoded_len(0xFF), 9);
}
#[test]
fn test_encoded_len_boundaries() {
assert_eq!(encoded_len(0), 1);
assert_eq!(encoded_len(vu64::MAX_LEN1), 1);
assert_eq!(encoded_len(vu64::MAX_LEN1 + 1), 2);
assert_eq!(encoded_len(vu64::MAX_LEN2), 2);
assert_eq!(encoded_len(vu64::MAX_LEN2 + 1), 3);
assert_eq!(encoded_len(vu64::MAX_LEN3), 3);
assert_eq!(encoded_len(vu64::MAX_LEN3 + 1), 4);
assert_eq!(encoded_len(vu64::MAX_LEN4), 4);
assert_eq!(encoded_len(vu64::MAX_LEN4 + 1), 5);
assert_eq!(encoded_len(vu64::MAX_LEN5), 5);
assert_eq!(encoded_len(vu64::MAX_LEN5 + 1), 6);
assert_eq!(encoded_len(vu64::MAX_LEN6), 6);
assert_eq!(encoded_len(vu64::MAX_LEN6 + 1), 7);
assert_eq!(encoded_len(vu64::MAX_LEN7), 7);
assert_eq!(encoded_len(vu64::MAX_LEN7 + 1), 8);
assert_eq!(encoded_len(vu64::MAX_LEN8), 8);
assert_eq!(encoded_len(vu64::MAX_LEN8 + 1), 9);
assert_eq!(encoded_len(u64::MAX), 9);
}
fn calculate_encoded_len(value: u64) -> u8 {
if value <= 0x7F {
1
} else if value <= 0x3FFF {
2
} else if value <= 0x1FFFFF {
3
} else if value <= 0xFFFFFFF {
4
} else if value <= 0x7FFFFFFFF {
5
} else if value <= 0x3FFFFFFFFFF {
6
} else if value <= 0x1FFFFFFFFFFFF {
7
} else if value <= 0xFFFFFFFFFFFFFF {
8
} else {
9
}
}
#[test]
fn test_encoded_len_table_correctness() {
let boundaries = [
0,
1,
0x7F,
0x80,
0x3FFF,
0x4000,
0x1FFFFF,
0x200000,
0xFFFFFFF,
0x10000000,
0x7FFFFFFFF,
0x800000000,
0x3FFFFFFFFFF,
0x40000000000,
0x1FFFFFFFFFFFF,
0x2000000000000,
0xFFFFFFFFFFFFFF,
0x100000000000000,
u64::MAX,
];
for &val in &boundaries {
assert_eq!(
encoded_len(val),
calculate_encoded_len(val),
"Failed for value: {:#x}",
val
);
}
for i in 0..=64 {
let value = if i == 64 { 0 } else { u64::MAX >> i };
let expected_len = calculate_encoded_len(value);
assert_eq!(
encoded_len(value),
expected_len,
"Failed for leading zero count: {}",
i
);
}
}
#[test]
fn test_error_enum_impls() {
use std::error::Error as _;
let err = Error::Truncated;
assert_eq!(format!("{}", err), "truncated vu64 value");
assert!(err.source().is_none());
let err = Error::RedundantEncode;
assert_eq!(format!("{}", err), "redundant encoded vu64 value");
assert!(err.source().is_none());
}
#[test]
fn test_vu64_try_from_slice() {
use std::convert::TryFrom;
let val: u64 = 123456789;
let encoded = vu64::encode(val);
let slice = encoded.as_ref();
let vu64_res = Vu64::try_from(slice);
assert!(vu64_res.is_ok());
let vu64_val = vu64_res.unwrap();
assert_eq!(vu64_val.as_ref(), slice);
assert_eq!(vu64::decode(vu64_val.as_ref()).unwrap(), val);
let truncated_slice = &slice[..slice.len() - 1];
let truncated_res = Vu64::try_from(truncated_slice);
assert!(truncated_res.is_err());
assert_eq!(truncated_res.unwrap_err(), Error::Truncated);
let redundant_slice: &[u8] = &[0x81, 0x00]; let redundant_res = Vu64::try_from(redundant_slice);
assert!(redundant_res.is_err());
assert_eq!(redundant_res.unwrap_err(), Error::RedundantEncode);
let empty_slice: &[u8] = &[];
let empty_res = Vu64::try_from(empty_slice);
assert!(empty_res.is_err());
assert_eq!(empty_res.unwrap_err(), Error::Truncated);
}
}