Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 31 additions & 13 deletions codec/src/conformance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,29 +11,47 @@ use rand::{Rng, SeedableRng};
use rand_chacha::ChaCha8Rng;
use std::{fmt::Debug, marker::PhantomData};

/// Size of the random buffer used for generating arbitrary values.
///
/// This should be large enough to generate complex nested types.
const ARBITRARY_BUFFER_SIZE: usize = 4096;
/// Initial size of the random buffer used for generating arbitrary values.
const INITIAL_BUFFER_SIZE: usize = 4096;

/// Maximum buffer size to try before giving up (16 MB).
const MAX_BUFFER_SIZE: usize = 16 * 1024 * 1024;

/// Generate a deterministic value of type `T` using the given seed.
///
/// Uses the [`arbitrary`] crate with a seeded ChaCha RNG for reproducible
/// value generation.
/// value generation. If the initial buffer is insufficient, the buffer size
/// is doubled until generation succeeds or the maximum size is reached.
pub fn generate_value<T>(seed: u64) -> T
where
T: for<'a> Arbitrary<'a>,
{
// Create a seeded RNG
let mut rng = ChaCha8Rng::seed_from_u64(seed);
let mut buffer_size = INITIAL_BUFFER_SIZE;
loop {
// Create a seeded RNG
let mut rng = ChaCha8Rng::seed_from_u64(seed);

// Generate random bytes for the Unstructured input
let mut buffer = vec![0u8; ARBITRARY_BUFFER_SIZE];
rng.fill(&mut buffer[..]);
// Generate random bytes for the Unstructured input
let mut buffer = vec![0u8; buffer_size];
rng.fill(&mut buffer[..]);

// Generate the arbitrary value
let mut unstructured = Unstructured::new(&buffer);
T::arbitrary(&mut unstructured).expect("failed to generate arbitrary value")
// Try to generate the arbitrary value
let mut unstructured = Unstructured::new(&buffer);
match T::arbitrary(&mut unstructured) {
Ok(value) => return value,
Err(arbitrary::Error::NotEnoughData) => {
// Give up if we've already tried the maximum size
if buffer_size >= MAX_BUFFER_SIZE {
panic!(
"failed to generate arbitrary value: NotEnoughData with {buffer_size} bytes"
);
}
// Double the buffer size (capped at MAX) and retry
buffer_size = (buffer_size * 2).min(MAX_BUFFER_SIZE);
}
Err(e) => panic!("failed to generate arbitrary value: {e}"),
}
}
}

/// Marker type for codec conformance testing.
Expand Down
Loading