use proptest::prelude::*;
use spdr::DecodeError;
const FIXTURE: &[u8] = include_bytes!("fixtures/teamgroup-ud5-6000_0104eef6.spd");
fn run_all_decoders(data: &[u8]) {
let _ = spdr::decode_identity_and_base(data);
let _ = spdr::verify_base_crc(data);
let _ = spdr::crc16(data);
let _ = spdr::decode_timings(data);
let _ = spdr::decode_module_specific(data);
let _ = spdr::decode_manufacturing(data);
let _ = spdr::decode_xmp(data);
let _ = spdr::decode_expo(data);
let _ = spdr::decode_vendor_profiles(data);
}
proptest! {
#[test]
fn arbitrary_bytes_panics_no_decoder(
data in proptest::collection::vec(any::<u8>(), 0..=2048),
) {
run_all_decoders(&data);
spdr::lint(&data, &mut |_| {});
}
#[test]
fn single_byte_mutation_panics_no_decoder(
index in 0usize..FIXTURE.len(),
value in any::<u8>(),
) {
let mut img = FIXTURE.to_vec();
img[index] = value;
run_all_decoders(&img);
spdr::lint(&img, &mut |_| {});
}
}
#[test]
fn every_truncation_returns_ok_or_truncated() {
for len in 0..=FIXTURE.len() {
let truncated = &FIXTURE[..len];
assert_ok_or_truncated(
spdr::decode_identity_and_base(truncated),
len,
"identity and base",
);
assert_ok_or_truncated(spdr::verify_base_crc(truncated), len, "base CRC");
let _ = spdr::crc16(truncated);
assert_ok_or_truncated(spdr::decode_timings(truncated), len, "timings");
assert_ok_or_truncated(
spdr::decode_module_specific(truncated),
len,
"module-specific",
);
assert_ok_or_truncated(spdr::decode_manufacturing(truncated), len, "manufacturing");
assert_ok_or_truncated(spdr::decode_xmp(truncated), len, "XMP");
assert_ok_or_truncated(spdr::decode_expo(truncated), len, "EXPO");
}
}
fn assert_ok_or_truncated<T: std::fmt::Debug>(
result: Result<T, DecodeError>,
len: usize,
decoder: &str,
) {
assert!(
matches!(result, Ok(_) | Err(DecodeError::Truncated { .. })),
"{decoder} at truncation length {len} returned {result:?}, expected Ok or Truncated",
);
}