Add --max-success for running more or less prop runs on demand.

This commit is contained in:
KtorZ 2024-03-09 19:17:57 +01:00
parent d581183cc6
commit 22b86a5f82
No known key found for this signature in database
GPG Key ID: 33173CB6F77F4277
6 changed files with 46 additions and 16 deletions

View File

@ -17,6 +17,7 @@
- **aiken**: support outputting mainnet addresses for validators. @rvcas - **aiken**: support outputting mainnet addresses for validators. @rvcas
- **aiken-lang**: added serde to CheckedModule to encode modules as cbor. @rvcas - **aiken-lang**: added serde to CheckedModule to encode modules as cbor. @rvcas
- **aiken-lang**: Strings can contain a nul byte using the escape sequence `\0`. @KtorZ - **aiken-lang**: Strings can contain a nul byte using the escape sequence `\0`. @KtorZ
- **aiken**: The `check` command now accept an extra (optional) option `--max-success` to control the number of property-test iterations to perform. @KtorZ
### Fixed ### Fixed

View File

@ -1,5 +1,8 @@
use aiken_lang::{ast::Tracing, line_numbers::LineNumbers}; use aiken_lang::{ast::Tracing, line_numbers::LineNumbers};
use aiken_project::{config::Config, error::Error as ProjectError, module::CheckedModule, Project}; use aiken_project::{
config::Config, error::Error as ProjectError, module::CheckedModule,
test_framework::PropertyTest, Project,
};
use std::{collections::HashMap, path::PathBuf}; use std::{collections::HashMap, path::PathBuf};
#[derive(Debug)] #[derive(Debug)]
@ -29,9 +32,15 @@ impl LspProject {
pub fn compile(&mut self) -> Result<(), Vec<ProjectError>> { pub fn compile(&mut self) -> Result<(), Vec<ProjectError>> {
let checkpoint = self.project.checkpoint(); let checkpoint = self.project.checkpoint();
let result = let result = self.project.check(
self.project true,
.check(true, None, false, false, u32::default(), Tracing::silent()); None,
false,
false,
u32::default(),
PropertyTest::DEFAULT_MAX_SUCCESS,
Tracing::silent(),
);
self.project.restore(checkpoint); self.project.restore(checkpoint);

View File

@ -223,6 +223,7 @@ where
Ok(()) Ok(())
} }
#[allow(clippy::too_many_arguments)]
pub fn check( pub fn check(
&mut self, &mut self,
skip_tests: bool, skip_tests: bool,
@ -230,6 +231,7 @@ where
verbose: bool, verbose: bool,
exact_match: bool, exact_match: bool,
seed: u32, seed: u32,
property_max_success: usize,
tracing: Tracing, tracing: Tracing,
) -> Result<(), Vec<Error>> { ) -> Result<(), Vec<Error>> {
let options = Options { let options = Options {
@ -242,6 +244,7 @@ where
verbose, verbose,
exact_match, exact_match,
seed, seed,
property_max_success,
} }
}, },
}; };
@ -328,6 +331,7 @@ where
verbose, verbose,
exact_match, exact_match,
seed, seed,
property_max_success,
} => { } => {
let tests = let tests =
self.collect_tests(verbose, match_tests, exact_match, options.tracing)?; self.collect_tests(verbose, match_tests, exact_match, options.tracing)?;
@ -336,7 +340,7 @@ where
self.event_listener.handle_event(Event::RunningTests); self.event_listener.handle_event(Event::RunningTests);
} }
let tests = self.run_tests(tests, seed); let tests = self.run_tests(tests, seed, property_max_success);
self.checks_count = if tests.is_empty() { self.checks_count = if tests.is_empty() {
None None
@ -848,7 +852,12 @@ where
Ok(tests) Ok(tests)
} }
fn run_tests(&self, tests: Vec<Test>, seed: u32) -> Vec<TestResult<UntypedExpr, UntypedExpr>> { fn run_tests(
&self,
tests: Vec<Test>,
seed: u32,
property_max_success: usize,
) -> Vec<TestResult<UntypedExpr, UntypedExpr>> {
use rayon::prelude::*; use rayon::prelude::*;
let data_types = utils::indexmap::as_ref_values(&self.data_types); let data_types = utils::indexmap::as_ref_values(&self.data_types);
@ -857,7 +866,7 @@ where
.into_par_iter() .into_par_iter()
.map(|test| match test { .map(|test| match test {
Test::UnitTest(unit_test) => unit_test.run(), Test::UnitTest(unit_test) => unit_test.run(),
Test::PropertyTest(property_test) => property_test.run(seed), Test::PropertyTest(property_test) => property_test.run(seed, property_max_success),
}) })
.collect::<Vec<TestResult<(Constant, Rc<Type>), PlutusData>>>() .collect::<Vec<TestResult<(Constant, Rc<Type>), PlutusData>>>()
.into_iter() .into_iter()

View File

@ -11,6 +11,7 @@ pub enum CodeGenMode {
verbose: bool, verbose: bool,
exact_match: bool, exact_match: bool,
seed: u32, seed: u32,
property_max_success: usize,
}, },
Build(bool), Build(bool),
NoOp, NoOp,

View File

@ -214,13 +214,11 @@ pub struct Fuzzer<T> {
} }
impl PropertyTest { impl PropertyTest {
const MAX_TEST_RUN: usize = 100; pub const DEFAULT_MAX_SUCCESS: usize = 100;
/// Run a property test from a given seed. The property is run at most MAX_TEST_RUN times. It /// Run a property test from a given seed. The property is run at most DEFAULT_MAX_SUCCESS times. It
/// 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) -> TestResult<U, PlutusData> { pub fn run<U>(self, seed: u32, n: usize) -> TestResult<U, PlutusData> {
let n = PropertyTest::MAX_TEST_RUN;
let mut labels = BTreeMap::new(); let mut labels = BTreeMap::new();
let (counterexample, iterations) = let (counterexample, iterations) =
@ -1378,7 +1376,7 @@ mod test {
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( match self.run_n_times(
PropertyTest::MAX_TEST_RUN, PropertyTest::DEFAULT_MAX_SUCCESS,
Prng::from_seed(42), Prng::from_seed(42),
None, None,
&mut labels, &mut labels,
@ -1397,7 +1395,9 @@ mod test {
} }
"#}); "#});
assert!(prop.run::<()>(42).is_success()); assert!(prop
.run::<()>(42, PropertyTest::DEFAULT_MAX_SUCCESS)
.is_success());
} }
#[test] #[test]
@ -1419,7 +1419,7 @@ mod test {
} }
"#}); "#});
match prop.run::<()>(42) { match prop.run::<()>(42, PropertyTest::DEFAULT_MAX_SUCCESS) {
TestResult::UnitTestResult(..) => unreachable!("property returned unit-test result ?!"), TestResult::UnitTestResult(..) => unreachable!("property returned unit-test result ?!"),
TestResult::PropertyTestResult(result) => { TestResult::PropertyTestResult(result) => {
assert!( assert!(

View File

@ -1,6 +1,9 @@
use super::build::{filter_traces_parser, trace_level_parser}; use super::build::{filter_traces_parser, trace_level_parser};
use aiken_lang::ast::{TraceLevel, Tracing}; use aiken_lang::ast::{TraceLevel, Tracing};
use aiken_project::watch::{self, watch_project, with_project}; use aiken_project::{
test_framework::PropertyTest,
watch::{self, watch_project, with_project},
};
use rand::prelude::*; use rand::prelude::*;
use std::{path::PathBuf, process}; use std::{path::PathBuf, process};
@ -30,6 +33,10 @@ pub struct Args {
#[clap(long)] #[clap(long)]
seed: Option<u32>, seed: Option<u32>,
/// Maximum number of successful test run for considering a property-based test valid.
#[clap(long, default_value_t = PropertyTest::DEFAULT_MAX_SUCCESS)]
max_success: usize,
/// Only run tests if they match any of these strings. /// Only run tests if they match any of these strings.
/// You can match a module with `-m aiken/list` or `-m list`. /// You can match a module with `-m aiken/list` or `-m list`.
/// You can match a test with `-m "aiken/list.{map}"` or `-m "aiken/option.{flatten_1}"` /// You can match a test with `-m "aiken/list.{map}"` or `-m "aiken/option.{flatten_1}"`
@ -72,6 +79,7 @@ pub fn exec(
filter_traces, filter_traces,
trace_level, trace_level,
seed, seed,
max_success,
}: Args, }: Args,
) -> miette::Result<()> { ) -> miette::Result<()> {
let mut rng = rand::thread_rng(); let mut rng = rand::thread_rng();
@ -86,6 +94,7 @@ pub fn exec(
debug, debug,
exact_match, exact_match,
seed, seed,
max_success,
match filter_traces { match filter_traces {
Some(filter_traces) => filter_traces(trace_level), Some(filter_traces) => filter_traces(trace_level),
None => Tracing::All(trace_level), None => Tracing::All(trace_level),
@ -100,6 +109,7 @@ pub fn exec(
debug, debug,
exact_match, exact_match,
seed, seed,
max_success,
match filter_traces { match filter_traces {
Some(filter_traces) => filter_traces(trace_level), Some(filter_traces) => filter_traces(trace_level),
None => Tracing::All(trace_level), None => Tracing::All(trace_level),