use proptest::prelude::*;
use vexil_runtime::{BitReader, BitWriter};
proptest! {
#[test]
fn roundtrip_u64(val in any::<u64>()) {
let mut w = BitWriter::new();
w.write_u64(val);
let bytes = w.finish();
let mut r = BitReader::new(&bytes);
prop_assert_eq!(r.read_u64().unwrap(), val);
}
#[test]
fn roundtrip_u32(val in any::<u32>()) {
let mut w = BitWriter::new();
w.write_u32(val);
let bytes = w.finish();
let mut r = BitReader::new(&bytes);
prop_assert_eq!(r.read_u32().unwrap(), val);
}
#[test]
fn roundtrip_u16(val in any::<u16>()) {
let mut w = BitWriter::new();
w.write_u16(val);
let bytes = w.finish();
let mut r = BitReader::new(&bytes);
prop_assert_eq!(r.read_u16().unwrap(), val);
}
#[test]
fn roundtrip_u8(val in any::<u8>()) {
let mut w = BitWriter::new();
w.write_u8(val);
let bytes = w.finish();
let mut r = BitReader::new(&bytes);
prop_assert_eq!(r.read_u8().unwrap(), val);
}
#[test]
fn roundtrip_i64(val in any::<i64>()) {
let mut w = BitWriter::new();
w.write_i64(val);
let bytes = w.finish();
let mut r = BitReader::new(&bytes);
prop_assert_eq!(r.read_i64().unwrap(), val);
}
#[test]
fn roundtrip_i32(val in any::<i32>()) {
let mut w = BitWriter::new();
w.write_i32(val);
let bytes = w.finish();
let mut r = BitReader::new(&bytes);
prop_assert_eq!(r.read_i32().unwrap(), val);
}
#[test]
fn roundtrip_f32(val in any::<f32>()) {
let mut w = BitWriter::new();
w.write_f32(val);
let bytes = w.finish();
let mut r = BitReader::new(&bytes);
let decoded = r.read_f32().unwrap();
prop_assert_eq!(val.to_bits(), decoded.to_bits());
}
#[test]
fn roundtrip_f64(val in any::<f64>()) {
let mut w = BitWriter::new();
w.write_f64(val);
let bytes = w.finish();
let mut r = BitReader::new(&bytes);
let decoded = r.read_f64().unwrap();
prop_assert_eq!(val.to_bits(), decoded.to_bits());
}
#[test]
fn roundtrip_bool(val in any::<bool>()) {
let mut w = BitWriter::new();
w.write_bool(val);
w.flush_to_byte_boundary();
let bytes = w.finish();
let mut r = BitReader::new(&bytes);
prop_assert_eq!(r.read_bool().unwrap(), val);
}
#[test]
fn roundtrip_sub_byte(bits in 1u8..=8, val in any::<u64>()) {
let mask = if bits == 64 { u64::MAX } else { (1u64 << bits) - 1 };
let masked_val = val & mask;
let mut w = BitWriter::new();
w.write_bits(masked_val, bits);
w.flush_to_byte_boundary();
let bytes = w.finish();
let mut r = BitReader::new(&bytes);
prop_assert_eq!(r.read_bits(bits).unwrap(), masked_val);
}
#[test]
fn roundtrip_packed_fields(
a in 0u8..=7u8,
b in 0u8..=31u8,
c in 0u8..=15u8,
) {
let mut w = BitWriter::new();
w.write_bits(a as u64, 3);
w.write_bits(b as u64, 5);
w.write_bits(c as u64, 4);
w.flush_to_byte_boundary();
let bytes = w.finish();
let mut r = BitReader::new(&bytes);
prop_assert_eq!(r.read_bits(3).unwrap(), a as u64);
prop_assert_eq!(r.read_bits(5).unwrap(), b as u64);
prop_assert_eq!(r.read_bits(4).unwrap(), c as u64);
}
#[test]
fn roundtrip_string(val in "[ -~]{0,1024}") {
let mut w = BitWriter::new();
w.write_string(&val);
let bytes = w.finish();
let mut r = BitReader::new(&bytes);
prop_assert_eq!(r.read_string().unwrap(), val);
}
#[test]
fn roundtrip_string_ref(val in "[ -~]{0,1024}") {
let mut w = BitWriter::new();
w.write_string(&val);
let bytes = w.finish();
let mut r = BitReader::new(&bytes);
prop_assert_eq!(r.read_string_ref().unwrap(), val);
}
#[test]
fn roundtrip_bytes(val in prop::collection::vec(any::<u8>(), 0..=1024)) {
let mut w = BitWriter::new();
w.write_bytes(&val);
let bytes = w.finish();
let mut r = BitReader::new(&bytes);
prop_assert_eq!(r.read_bytes().unwrap(), val);
}
#[test]
fn roundtrip_leb128(val in 0u64..(1u64 << 35)) {
let mut w = BitWriter::new();
w.write_leb128(val);
let bytes = w.finish();
let mut r = BitReader::new(&bytes);
prop_assert_eq!(r.read_leb128(10).unwrap(), val);
}
#[test]
fn writer_reset_reuse(val in any::<u32>()) {
let mut w = BitWriter::with_capacity(64);
w.write_u32(val);
let bytes1 = w.finish();
let mut w = BitWriter::with_capacity(64);
w.write_u32(val + 1);
w.reset();
w.write_u32(val);
let bytes2 = w.finish();
prop_assert_eq!(bytes1, bytes2);
}
}