Rewrite run_n_times to not be recursive but mutates arguments.

We reach a stack-overflow for n > 2000 otherwise. Mutation works well here and is a valid use-case.
This commit is contained in:
KtorZ 2024-03-14 14:18:38 +01:00
parent 1d72838f83
commit 038c5b2d34
No known key found for this signature in database
GPG Key ID: 33173CB6F77F4277
1 changed files with 17 additions and 25 deletions

View File

@ -226,11 +226,12 @@ impl PropertyTest {
/// may stops earlier on failure; in which case a 'counterexample' is returned. /// may stops earlier on failure; in which case a 'counterexample' is returned.
pub fn run<U>(self, seed: u32, n: usize) -> TestResult<U, PlutusData> { pub fn run<U>(self, seed: u32, n: usize) -> TestResult<U, PlutusData> {
let mut labels = BTreeMap::new(); let mut labels = BTreeMap::new();
let mut remaining = n;
let (traces, counterexample, iterations) = let (traces, counterexample, iterations) =
match self.run_n_times(n, Prng::from_seed(seed), None, &mut labels) { match self.run_n_times(&mut remaining, Prng::from_seed(seed), &mut labels) {
Ok(None) => (Vec::new(), Ok(None), n), Ok(None) => (Vec::new(), Ok(None), n),
Ok(Some((remaining, counterexample))) => ( Ok(Some(counterexample)) => (
self.eval(&counterexample.value) self.eval(&counterexample.value)
.logs() .logs()
.into_iter() .into_iter()
@ -260,24 +261,19 @@ impl PropertyTest {
fn run_n_times<'a>( fn run_n_times<'a>(
&'a self, &'a self,
remaining: usize, remaining: &mut usize,
prng: Prng, initial_prng: Prng,
counterexample: Option<(usize, Counterexample<'a>)>,
labels: &mut BTreeMap<String, usize>, labels: &mut BTreeMap<String, usize>,
) -> Result<Option<(usize, Counterexample<'a>)>, FuzzerError> { ) -> Result<Option<Counterexample<'a>>, FuzzerError> {
// We short-circuit failures in case we have any. The counterexample is already simplified let mut prng = initial_prng;
// at this point. let mut counterexample = None;
if remaining > 0 && counterexample.is_none() {
let (next_prng, counterexample) = self.run_once(prng, labels)?; while *remaining > 0 && counterexample.is_none() {
self.run_n_times( (prng, counterexample) = self.run_once(prng, labels)?;
remaining - 1, *remaining -= 1;
next_prng,
counterexample.map(|c| (remaining, c)),
labels,
)
} else {
Ok(counterexample)
} }
Ok(counterexample)
} }
fn run_once( fn run_once(
@ -1418,13 +1414,9 @@ mod test {
impl PropertyTest { impl PropertyTest {
fn expect_failure(&self) -> Counterexample { fn expect_failure(&self) -> Counterexample {
let mut labels = BTreeMap::new(); let mut labels = BTreeMap::new();
match self.run_n_times( let mut remaining = PropertyTest::DEFAULT_MAX_SUCCESS;
PropertyTest::DEFAULT_MAX_SUCCESS, match self.run_n_times(&mut remaining, Prng::from_seed(42), &mut labels) {
Prng::from_seed(42), Ok(Some(counterexample)) => counterexample,
None,
&mut labels,
) {
Ok(Some((_, counterexample))) => counterexample,
_ => panic!("expected property to fail but it didn't."), _ => panic!("expected property to fail but it didn't."),
} }
} }