Accept an optional --seed parameter for check, otherwise default to random.
Also, show the seed on failure.
This commit is contained in:
parent
a7b9d4bb22
commit
7a2537432a
|
@ -67,6 +67,7 @@ dependencies = [
|
|||
"ordinal",
|
||||
"owo-colors",
|
||||
"pallas",
|
||||
"rand",
|
||||
"regex",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use std::{collections::HashMap, path::PathBuf};
|
||||
|
||||
use aiken_lang::{ast::Tracing, line_numbers::LineNumbers};
|
||||
use aiken_project::{config::Config, error::Error as ProjectError, module::CheckedModule, Project};
|
||||
use std::{collections::HashMap, path::PathBuf};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SourceInfo {
|
||||
|
@ -30,9 +29,9 @@ impl LspProject {
|
|||
pub fn compile(&mut self) -> Result<(), Vec<ProjectError>> {
|
||||
let checkpoint = self.project.checkpoint();
|
||||
|
||||
let result = self
|
||||
.project
|
||||
.check(true, None, false, false, Tracing::silent());
|
||||
let result =
|
||||
self.project
|
||||
.check(true, None, false, false, u32::default(), Tracing::silent());
|
||||
|
||||
self.project.restore(checkpoint);
|
||||
|
||||
|
|
|
@ -226,6 +226,7 @@ where
|
|||
match_tests: Option<Vec<String>>,
|
||||
verbose: bool,
|
||||
exact_match: bool,
|
||||
seed: u32,
|
||||
tracing: Tracing,
|
||||
) -> Result<(), Vec<Error>> {
|
||||
let options = Options {
|
||||
|
@ -237,6 +238,7 @@ where
|
|||
match_tests,
|
||||
verbose,
|
||||
exact_match,
|
||||
seed,
|
||||
}
|
||||
},
|
||||
};
|
||||
|
@ -322,6 +324,7 @@ where
|
|||
match_tests,
|
||||
verbose,
|
||||
exact_match,
|
||||
seed,
|
||||
} => {
|
||||
let tests =
|
||||
self.collect_tests(verbose, match_tests, exact_match, options.tracing)?;
|
||||
|
@ -330,7 +333,7 @@ where
|
|||
self.event_listener.handle_event(Event::RunningTests);
|
||||
}
|
||||
|
||||
let tests = self.run_tests(tests);
|
||||
let tests = self.run_tests(tests, seed);
|
||||
|
||||
let errors: Vec<Error> = tests
|
||||
.iter()
|
||||
|
@ -786,7 +789,7 @@ where
|
|||
Ok(tests)
|
||||
}
|
||||
|
||||
fn run_tests(&self, tests: Vec<Test>) -> Vec<TestResult<UntypedExpr>> {
|
||||
fn run_tests(&self, tests: Vec<Test>, seed: u32) -> Vec<TestResult<UntypedExpr>> {
|
||||
use rayon::prelude::*;
|
||||
|
||||
let data_types = utils::indexmap::as_ref_values(&self.data_types);
|
||||
|
@ -797,7 +800,7 @@ where
|
|||
Test::UnitTest(unit_test) => unit_test.run(),
|
||||
// TODO: Get the seed from the command-line, defaulting to a random one when not
|
||||
// provided.
|
||||
Test::PropertyTest(property_test) => property_test.run(42),
|
||||
Test::PropertyTest(property_test) => property_test.run(seed),
|
||||
})
|
||||
.collect::<Vec<TestResult<PlutusData>>>()
|
||||
.into_iter()
|
||||
|
|
|
@ -10,6 +10,7 @@ pub enum CodeGenMode {
|
|||
match_tests: Option<Vec<String>>,
|
||||
verbose: bool,
|
||||
exact_match: bool,
|
||||
seed: u32,
|
||||
},
|
||||
Build(bool),
|
||||
NoOp,
|
||||
|
|
|
@ -267,8 +267,6 @@ impl PropertyTest {
|
|||
} = next_prng
|
||||
{
|
||||
if result.failed(self.can_error) {
|
||||
println!("{:#?}", result.result());
|
||||
|
||||
let mut counterexample = Counterexample {
|
||||
value,
|
||||
choices: next_prng.choices(),
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{telemetry::Terminal, Project};
|
||||
use crate::{telemetry::Terminal, Error, Project};
|
||||
use miette::{Diagnostic, IntoDiagnostic};
|
||||
use notify::{Event, RecursiveMode, Watcher};
|
||||
use owo_colors::{OwoColorize, Stream::Stderr};
|
||||
|
@ -75,7 +75,12 @@ pub fn default_filter(evt: &Event) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn with_project<A>(directory: Option<&Path>, deny: bool, mut action: A) -> miette::Result<()>
|
||||
pub fn with_project<A>(
|
||||
directory: Option<&Path>,
|
||||
seed: u32,
|
||||
deny: bool,
|
||||
mut action: A,
|
||||
) -> miette::Result<()>
|
||||
where
|
||||
A: FnMut(&mut Project<Terminal>) -> Result<(), Vec<crate::error::Error>>,
|
||||
{
|
||||
|
@ -116,17 +121,24 @@ where
|
|||
}
|
||||
);
|
||||
|
||||
if errs.iter().any(|e| matches!(e, Error::TestFailure { .. })) {
|
||||
eprintln!(
|
||||
" ━━━━━━\n ╰─▶ use {} {} to replay",
|
||||
"--seed".if_supports_color(Stderr, |s| s.bold()),
|
||||
format!("{seed}").if_supports_color(Stderr, |s| s.bold())
|
||||
);
|
||||
}
|
||||
return Err(ExitFailure::into_report());
|
||||
} else {
|
||||
eprintln!(
|
||||
"{}",
|
||||
Summary {
|
||||
error_count: 0,
|
||||
warning_count
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
eprintln!(
|
||||
"{}",
|
||||
Summary {
|
||||
error_count: 0,
|
||||
warning_count
|
||||
}
|
||||
);
|
||||
|
||||
if warning_count > 0 && deny {
|
||||
Err(ExitFailure::into_report())
|
||||
} else {
|
||||
|
@ -148,6 +160,7 @@ where
|
|||
pub fn watch_project<F, A>(
|
||||
directory: Option<&Path>,
|
||||
filter: F,
|
||||
seed: u32,
|
||||
debounce: u32,
|
||||
mut action: A,
|
||||
) -> miette::Result<()>
|
||||
|
@ -219,7 +232,7 @@ where
|
|||
.if_supports_color(Stderr, |s| s.bold())
|
||||
.if_supports_color(Stderr, |s| s.purple()),
|
||||
);
|
||||
with_project(directory, false, &mut action).unwrap_or(())
|
||||
with_project(directory, seed, false, &mut action).unwrap_or(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,3 +38,4 @@ clap_complete = "4.3.2"
|
|||
inquire = "0.6.2"
|
||||
num-bigint = "0.4.3"
|
||||
ordinal = "0.3.2"
|
||||
rand = "0.8.5"
|
||||
|
|
|
@ -39,7 +39,7 @@ pub fn exec(
|
|||
mainnet,
|
||||
}: Args,
|
||||
) -> miette::Result<()> {
|
||||
with_project(directory.as_deref(), false, |p| {
|
||||
with_project(directory.as_deref(), u32::default(), false, |p| {
|
||||
if rebuild {
|
||||
p.build(false, Tracing::silent())?;
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ pub fn exec(
|
|||
validator,
|
||||
}: Args,
|
||||
) -> miette::Result<()> {
|
||||
with_project(None, false, |p| {
|
||||
with_project(None, u32::default(), false, |p| {
|
||||
let title = module.as_ref().map(|m| {
|
||||
format!(
|
||||
"{m}{}",
|
||||
|
|
|
@ -29,7 +29,7 @@ pub fn exec(
|
|||
rebuild,
|
||||
}: Args,
|
||||
) -> miette::Result<()> {
|
||||
with_project(directory.as_deref(), false, |p| {
|
||||
with_project(directory.as_deref(), u32::default(), false, |p| {
|
||||
if rebuild {
|
||||
p.build(false, Tracing::silent())?;
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ pub fn exec(
|
|||
rebuild,
|
||||
}: Args,
|
||||
) -> miette::Result<()> {
|
||||
with_project(directory.as_deref(), false, |p| {
|
||||
with_project(directory.as_deref(), u32::default(), false, |p| {
|
||||
if rebuild {
|
||||
p.build(false, Tracing::silent())?;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use aiken_lang::ast::{TraceLevel, Tracing};
|
||||
use aiken_project::watch::{self, watch_project, with_project};
|
||||
use clap::builder::MapValueParser;
|
||||
use clap::builder::{PossibleValuesParser, TypedValueParser};
|
||||
use clap::builder::{MapValueParser, PossibleValuesParser, TypedValueParser};
|
||||
use std::{path::PathBuf, process};
|
||||
|
||||
#[derive(clap::Args)]
|
||||
|
@ -52,17 +51,23 @@ pub fn exec(
|
|||
}: Args,
|
||||
) -> miette::Result<()> {
|
||||
let result = if watch {
|
||||
watch_project(directory.as_deref(), watch::default_filter, 500, |p| {
|
||||
p.build(
|
||||
uplc,
|
||||
match filter_traces {
|
||||
Some(filter_traces) => filter_traces(trace_level),
|
||||
None => Tracing::All(trace_level),
|
||||
},
|
||||
)
|
||||
})
|
||||
watch_project(
|
||||
directory.as_deref(),
|
||||
watch::default_filter,
|
||||
u32::default(),
|
||||
500,
|
||||
|p| {
|
||||
p.build(
|
||||
uplc,
|
||||
match filter_traces {
|
||||
Some(filter_traces) => filter_traces(trace_level),
|
||||
None => Tracing::All(trace_level),
|
||||
},
|
||||
)
|
||||
},
|
||||
)
|
||||
} else {
|
||||
with_project(directory.as_deref(), deny, |p| {
|
||||
with_project(directory.as_deref(), u32::default(), deny, |p| {
|
||||
p.build(
|
||||
uplc,
|
||||
match filter_traces {
|
||||
|
@ -77,8 +82,8 @@ pub fn exec(
|
|||
}
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub fn filter_traces_parser(
|
||||
) -> MapValueParser<PossibleValuesParser, fn(String) -> fn(TraceLevel) -> Tracing> {
|
||||
pub fn filter_traces_parser()
|
||||
-> MapValueParser<PossibleValuesParser, fn(String) -> fn(TraceLevel) -> Tracing> {
|
||||
PossibleValuesParser::new(["user-defined", "compiler-generated", "all"]).map(
|
||||
|s: String| match s.as_str() {
|
||||
"user-defined" => Tracing::UserDefined,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use super::build::{filter_traces_parser, trace_level_parser};
|
||||
use aiken_lang::ast::{TraceLevel, Tracing};
|
||||
use aiken_project::watch::{self, watch_project, with_project};
|
||||
use rand::prelude::*;
|
||||
use std::{path::PathBuf, process};
|
||||
|
||||
#[derive(clap::Args)]
|
||||
|
@ -25,6 +26,10 @@ pub struct Args {
|
|||
#[clap(long)]
|
||||
watch: bool,
|
||||
|
||||
/// An initial seed to initialize the pseudo-random generator for property-tests.
|
||||
#[clap(long)]
|
||||
seed: Option<u32>,
|
||||
|
||||
/// 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 test with `-m "aiken/list.{map}"` or `-m "aiken/option.{flatten_1}"`
|
||||
|
@ -66,28 +71,41 @@ pub fn exec(
|
|||
watch,
|
||||
filter_traces,
|
||||
trace_level,
|
||||
seed,
|
||||
}: Args,
|
||||
) -> miette::Result<()> {
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
let seed = seed.unwrap_or_else(|| rng.gen());
|
||||
|
||||
let result = if watch {
|
||||
watch_project(directory.as_deref(), watch::default_filter, 500, |p| {
|
||||
p.check(
|
||||
skip_tests,
|
||||
match_tests.clone(),
|
||||
debug,
|
||||
exact_match,
|
||||
match filter_traces {
|
||||
Some(filter_traces) => filter_traces(trace_level),
|
||||
None => Tracing::All(trace_level),
|
||||
},
|
||||
)
|
||||
})
|
||||
watch_project(
|
||||
directory.as_deref(),
|
||||
watch::default_filter,
|
||||
seed,
|
||||
500,
|
||||
|p| {
|
||||
p.check(
|
||||
skip_tests,
|
||||
match_tests.clone(),
|
||||
debug,
|
||||
exact_match,
|
||||
seed,
|
||||
match filter_traces {
|
||||
Some(filter_traces) => filter_traces(trace_level),
|
||||
None => Tracing::All(trace_level),
|
||||
},
|
||||
)
|
||||
},
|
||||
)
|
||||
} else {
|
||||
with_project(directory.as_deref(), deny, |p| {
|
||||
with_project(directory.as_deref(), seed, deny, |p| {
|
||||
p.check(
|
||||
skip_tests,
|
||||
match_tests.clone(),
|
||||
debug,
|
||||
exact_match,
|
||||
seed,
|
||||
match filter_traces {
|
||||
Some(filter_traces) => filter_traces(trace_level),
|
||||
None => Tracing::All(trace_level),
|
||||
|
|
|
@ -29,11 +29,17 @@ pub fn exec(
|
|||
}: Args,
|
||||
) -> miette::Result<()> {
|
||||
let result = if watch {
|
||||
watch_project(directory.as_deref(), watch::default_filter, 500, |p| {
|
||||
watch_project(
|
||||
directory.as_deref(),
|
||||
watch::default_filter,
|
||||
u32::default(),
|
||||
500,
|
||||
|p| p.docs(destination.clone()),
|
||||
)
|
||||
} else {
|
||||
with_project(directory.as_deref(), u32::default(), deny, |p| {
|
||||
p.docs(destination.clone())
|
||||
})
|
||||
} else {
|
||||
with_project(directory.as_deref(), deny, |p| p.docs(destination.clone()))
|
||||
};
|
||||
|
||||
result.map_err(|_| process::exit(1))
|
||||
|
|
Loading…
Reference in New Issue