struct Lcg {
state: u64,
}
impl Lcg {
fn new(seed: u64) -> Self {
Lcg { state: seed }
}
#[allow(dead_code)]
fn next_u64(&mut self) -> u64 {
self.state = self.state.wrapping_mul(6364136223846793005).wrapping_add(1);
self.state
}
#[allow(dead_code)]
fn next_u8(&mut self) -> u8 {
self.state = self.state.wrapping_mul(6364136223846793005).wrapping_add(1);
(self.state >> 32) as u8
}
}
#[cfg(test)]
mod test_fuzz {
use super::Lcg;
use vu64::{self, decode, decode2, decode3, encode, signed, Error};
#[test]
fn fuzz_u64_encode_decode() {
let mut rng = Lcg::new(0xdeadbeef);
for _ in 0..100_000 {
let value = rng.next_u64();
let encoded = vu64::encode(value);
let decoded = vu64::decode(encoded.as_ref()).unwrap();
assert_eq!(value, decoded);
}
}
#[test]
fn fuzz_i64_encode_decode() {
let mut rng = Lcg::new(0xbadc0ffee);
for _ in 0..100_000 {
let value = rng.next_u64() as i64;
let encoded = vu64::signed::encode(value);
let decoded = vu64::signed::decode(encoded.as_ref()).unwrap();
assert_eq!(value, decoded);
}
}
#[test]
fn fuzz_decode_with_random_bytes() {
let mut rng = Lcg::new(0x12345678);
let mut bytes = [0u8; 10];
for _ in 0..100_000 {
for a in &mut bytes {
*a = rng.next_u8();
}
let _ = vu64::decode(&bytes);
let _ = signed::decode(&bytes);
}
}
#[test]
fn test_decode_equivalency() {
let mut rng = Lcg::new(0xabcdef1234567890);
for _ in 0..100_000 {
let value = rng.next_u64();
let encoded = encode(value);
let slice = encoded.as_ref();
let r1 = decode(slice).unwrap();
let r2 = decode2(slice[0], &slice[1..]).unwrap();
let mut buf = [0u8; 8];
if slice.len() > 1 {
buf[..slice.len() - 1].copy_from_slice(&slice[1..]);
}
let follow_le = u64::from_le_bytes(buf);
let r3 = decode3(slice[0], follow_le).unwrap();
assert_eq!(value, r1, "decode failed for {}", value);
assert_eq!(value, r2, "decode2 failed for {}", value);
assert_eq!(value, r3, "decode3 failed for {}", value);
}
}
#[test]
fn test_decode2_thoroughly() {
let mut rng = Lcg::new(0xdeadbeefbadc0fee);
for _ in 0..100_000 {
let value = rng.next_u64();
let encoded = encode(value);
let slice = encoded.as_ref();
let result = decode2(slice[0], &slice[1..]);
assert_eq!(result.unwrap(), value);
if slice.len() > 1 {
let result = decode2(slice[0], &slice[1..slice.len() - 1]);
assert_eq!(result, Err(Error::Truncated));
}
}
let redundant_slice = &[0x81, 0x00]; let result = decode2(redundant_slice[0], &redundant_slice[1..]);
assert_eq!(result, Err(Error::RedundantEncode));
}
#[test]
fn test_decode3_thoroughly() {
let mut rng = Lcg::new(0x1234567890abcdef);
for _ in 0..100_000 {
let value = rng.next_u64();
let encoded = encode(value);
let slice = encoded.as_ref();
let mut buf = [0u8; 8];
if slice.len() > 1 {
buf[..slice.len() - 1].copy_from_slice(&slice[1..]);
}
let follow_le = u64::from_le_bytes(buf);
let result = decode3(slice[0], follow_le);
assert_eq!(result.unwrap(), value);
}
let redundant_slice = &[0x81, 0x00]; let mut buf = [0u8; 8];
buf[..1].copy_from_slice(&redundant_slice[1..]);
let follow_le = u64::from_le_bytes(buf);
let result = decode3(redundant_slice[0], follow_le);
assert_eq!(result, Err(Error::RedundantEncode));
}
#[test]
fn test_interoperability() {
let mut rng = Lcg::new(0xf0f0f0f0f0f0f0f0);
for _ in 0..100_000 {
let value = rng.next_u64();
let enc1 = encode(value);
let dec1 = decode2(enc1.as_ref()[0], &enc1.as_ref()[1..]).unwrap();
let enc2 = encode(dec1);
let dec2 = vu64::decode(enc2.as_ref()).unwrap();
assert_eq!(value, dec2);
let enc3 = encode(value);
let mut buf = [0u8; 8];
if enc3.as_ref().len() > 1 {
buf[..enc3.as_ref().len() - 1].copy_from_slice(&enc3.as_ref()[1..]);
}
let follow_le = u64::from_le_bytes(buf);
let dec3 = decode3(enc3.as_ref()[0], follow_le).unwrap();
let enc4 = encode(dec3);
let dec4 = decode2(enc4.as_ref()[0], &enc4.as_ref()[1..]).unwrap();
assert_eq!(value, dec4);
}
}
}