codeq/
testing.rs

1//! Test utilities for codec implementations.
2
3use std::any::type_name;
4use std::fmt::Debug;
5use std::io;
6use std::mem::size_of;
7
8use crate::codec::Codec;
9use crate::FixedSize;
10
11/// Comprehensively tests a codec implementation with both valid and corrupted data.
12///
13/// This function performs several checks:
14/// 1. Encodes the value and verifies it matches the expected bytes
15/// 2. Decodes the encoded bytes and verifies it matches the original value
16/// 3. Tests error handling by corrupting each byte and ensuring decode fails
17///
18/// # Arguments
19/// * `encoded_bytes` - The expected encoded representation
20/// * `v` - The value to test encoding/decoding
21///
22/// # Returns
23/// `Ok(())` if all tests pass, `io::Error` if any encoding/decoding operation fails
24pub fn test_codec<D: Codec + PartialEq + Debug>(
25    encoded_bytes: &[u8],
26    v: &D,
27) -> Result<(), io::Error> {
28    // convert `correct` to string if possible
29    let correct_str = String::from_utf8_lossy(encoded_bytes);
30    println!("correct data: {}", correct_str);
31
32    let mes = format!("Type: {} encoded data: {:?}", type_name::<D>(), correct_str);
33
34    // Test encoding
35    {
36        let mut b = Vec::new();
37        let n = v.encode(&mut b)?;
38        assert_eq!(n, b.len(), "output len, {}", &mes);
39        assert_eq!(b, encoded_bytes, "output data, {}", &mes);
40    }
41
42    // Assert the input is correct
43
44    {
45        let b = encoded_bytes.to_vec();
46        let decoded = D::decode(&mut b.as_slice())?;
47        assert_eq!(v, &decoded, "decode, {}", &mes);
48    }
49
50    // Assert corrupted data returns error
51    for i in 0..encoded_bytes.len() {
52        let mut corrupted = encoded_bytes.to_vec();
53        corrupted[i] = corrupted[i].wrapping_add(1);
54
55        let res = D::decode(&mut corrupted.as_slice());
56        assert!(
57            res.is_err(),
58            "change {}-th byte for type {}; the correct encoded data is: {}",
59            i,
60            type_name::<D>(),
61            correct_str
62        );
63    }
64
65    Ok(())
66}
67
68/// Tests integer codec implementations for fixed-size types.
69///
70/// Verifies that:
71/// 1. The encoded size matches the type's size in memory
72/// 2. The value can be encoded and decoded correctly
73/// 3. The encoded length matches the expected size
74///
75/// # Arguments
76/// * `v` - The integer value to test
77///
78/// # Returns
79/// `Ok(())` if all tests pass, or an error if any check fails
80pub fn test_int_coded<T: Codec + FixedSize + PartialEq + Debug>(v: T) -> anyhow::Result<()> {
81    let size = size_of::<T>();
82
83    assert_eq!(T::encoded_size(), size);
84
85    let mut buf = Vec::new();
86    let n = v.encode(&mut buf)?;
87    assert_eq!(n, buf.len());
88
89    let b = T::decode(&mut buf.as_slice())?;
90    assert_eq!(v, b);
91
92    Ok(())
93}