diff --git a/codec/src/conformance.rs b/codec/src/conformance.rs index 9856339364..bb73798169 100644 --- a/codec/src/conformance.rs +++ b/codec/src/conformance.rs @@ -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(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.