Only reify unit tests assertions on failure.
This commit is contained in:
parent
0d599f7e2d
commit
8e558d893f
|
@ -38,7 +38,7 @@ use aiken_lang::{
|
|||
expr::UntypedExpr,
|
||||
gen_uplc::CodeGenerator,
|
||||
line_numbers::LineNumbers,
|
||||
tipo::TypeInfo,
|
||||
tipo::{Type, TypeInfo},
|
||||
IdGenerator,
|
||||
};
|
||||
use indexmap::IndexMap;
|
||||
|
@ -55,11 +55,12 @@ use std::{
|
|||
fs::{self, File},
|
||||
io::BufReader,
|
||||
path::{Path, PathBuf},
|
||||
rc::Rc,
|
||||
};
|
||||
use telemetry::EventListener;
|
||||
use test_framework::{Test, TestResult};
|
||||
use uplc::{
|
||||
ast::{Name, Program},
|
||||
ast::{Constant, Name, Program},
|
||||
PlutusData,
|
||||
};
|
||||
|
||||
|
@ -834,7 +835,7 @@ where
|
|||
Ok(tests)
|
||||
}
|
||||
|
||||
fn run_tests(&self, tests: Vec<Test>, seed: u32) -> Vec<TestResult<UntypedExpr>> {
|
||||
fn run_tests(&self, tests: Vec<Test>, seed: u32) -> Vec<TestResult<UntypedExpr, UntypedExpr>> {
|
||||
use rayon::prelude::*;
|
||||
|
||||
let data_types = utils::indexmap::as_ref_values(&self.data_types);
|
||||
|
@ -845,7 +846,7 @@ where
|
|||
Test::UnitTest(unit_test) => unit_test.run(),
|
||||
Test::PropertyTest(property_test) => property_test.run(seed),
|
||||
})
|
||||
.collect::<Vec<TestResult<PlutusData>>>()
|
||||
.collect::<Vec<TestResult<(Constant, Rc<Type>), PlutusData>>>()
|
||||
.into_iter()
|
||||
.map(|test| test.reify(&data_types))
|
||||
.collect()
|
||||
|
|
|
@ -38,7 +38,7 @@ pub enum Event {
|
|||
RunningTests,
|
||||
FinishedTests {
|
||||
seed: u32,
|
||||
tests: Vec<TestResult<UntypedExpr>>,
|
||||
tests: Vec<TestResult<UntypedExpr, UntypedExpr>>,
|
||||
},
|
||||
WaitingForBuildDirLock,
|
||||
ResolvingPackages {
|
||||
|
@ -266,7 +266,7 @@ impl EventListener for Terminal {
|
|||
}
|
||||
|
||||
fn fmt_test(
|
||||
result: &TestResult<UntypedExpr>,
|
||||
result: &TestResult<UntypedExpr, UntypedExpr>,
|
||||
max_mem: usize,
|
||||
max_cpu: usize,
|
||||
max_iter: usize,
|
||||
|
@ -324,16 +324,16 @@ fn fmt_test(
|
|||
// Annotations
|
||||
match result {
|
||||
TestResult::UnitTestResult(UnitTestResult {
|
||||
test: unit_test, ..
|
||||
assertion: Some(assertion),
|
||||
test: unit_test,
|
||||
..
|
||||
}) if !result.is_success() => {
|
||||
if let Some(ref assertion) = unit_test.assertion {
|
||||
test = format!(
|
||||
"{test}\n{}{new_line}",
|
||||
assertion.to_string(Stderr, unit_test.can_error),
|
||||
new_line = if result.logs().is_empty() { "\n" } else { "" },
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
|
@ -396,7 +396,7 @@ fn fmt_test(
|
|||
test
|
||||
}
|
||||
|
||||
fn fmt_test_summary<T>(tests: &[&TestResult<T>], styled: bool) -> String {
|
||||
fn fmt_test_summary<T>(tests: &[&TestResult<T, T>], styled: bool) -> String {
|
||||
let (n_passed, n_failed) = tests.iter().fold((0, 0), |(n_passed, n_failed), result| {
|
||||
if result.is_success() {
|
||||
(n_passed + 1, n_failed)
|
||||
|
@ -420,16 +420,16 @@ fn fmt_test_summary<T>(tests: &[&TestResult<T>], styled: bool) -> String {
|
|||
)
|
||||
}
|
||||
|
||||
fn group_by_module<T>(results: &Vec<TestResult<T>>) -> BTreeMap<String, Vec<&TestResult<T>>> {
|
||||
fn group_by_module<T>(results: &Vec<TestResult<T, T>>) -> BTreeMap<String, Vec<&TestResult<T, T>>> {
|
||||
let mut modules = BTreeMap::new();
|
||||
for r in results {
|
||||
let xs: &mut Vec<&TestResult<_>> = modules.entry(r.module().to_string()).or_default();
|
||||
let xs: &mut Vec<&TestResult<_, _>> = modules.entry(r.module().to_string()).or_default();
|
||||
xs.push(r);
|
||||
}
|
||||
modules
|
||||
}
|
||||
|
||||
fn find_max_execution_units<T>(xs: &[TestResult<T>]) -> (usize, usize, usize) {
|
||||
fn find_max_execution_units<T>(xs: &[TestResult<T, T>]) -> (usize, usize, usize) {
|
||||
let (max_mem, max_cpu, max_iter) =
|
||||
xs.iter()
|
||||
.fold((0, 0, 0), |(max_mem, max_cpu, max_iter), test| match test {
|
||||
|
|
|
@ -49,8 +49,6 @@ impl Test {
|
|||
module_name: String,
|
||||
input_path: PathBuf,
|
||||
) -> Test {
|
||||
let data_types = generator.data_types().clone();
|
||||
|
||||
let program = generator.generate_raw(&test.body, &[], &module_name);
|
||||
|
||||
let assertion = match test.body.try_into() {
|
||||
|
@ -65,10 +63,7 @@ impl Test {
|
|||
.expect("failed to convert assertion operaand to NamedDeBruijn")
|
||||
.eval(ExBudget::max())
|
||||
.unwrap_constant()
|
||||
.map(|cst| {
|
||||
UntypedExpr::reify_constant(&data_types, cst, &side.tipo())
|
||||
.expect("failed to reify assertion operand?")
|
||||
})
|
||||
.map(|cst| (cst, side.tipo()))
|
||||
};
|
||||
|
||||
Some(Assertion {
|
||||
|
@ -165,13 +160,13 @@ pub struct UnitTest {
|
|||
pub name: String,
|
||||
pub can_error: bool,
|
||||
pub program: Program<Name>,
|
||||
pub assertion: Option<Assertion<UntypedExpr>>,
|
||||
pub assertion: Option<Assertion<(Constant, Rc<Type>)>>,
|
||||
}
|
||||
|
||||
unsafe impl Send for UnitTest {}
|
||||
|
||||
impl UnitTest {
|
||||
pub fn run<T>(self) -> TestResult<T> {
|
||||
pub fn run<T>(self) -> TestResult<(Constant, Rc<Type>), T> {
|
||||
let mut eval_result = Program::<NamedDeBruijn>::try_from(self.program.clone())
|
||||
.unwrap()
|
||||
.eval(ExBudget::max());
|
||||
|
@ -184,6 +179,7 @@ impl UnitTest {
|
|||
spent_budget: eval_result.cost(),
|
||||
logs: eval_result.logs(),
|
||||
output: eval_result.result().ok(),
|
||||
assertion: self.assertion,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -219,7 +215,7 @@ impl PropertyTest {
|
|||
|
||||
/// Run a property test from a given seed. The property is run at most MAX_TEST_RUN times. It
|
||||
/// may stops earlier on failure; in which case a 'counterexample' is returned.
|
||||
pub fn run(self, seed: u32) -> TestResult<PlutusData> {
|
||||
pub fn run<U>(self, seed: u32) -> TestResult<U, PlutusData> {
|
||||
let n = PropertyTest::MAX_TEST_RUN;
|
||||
|
||||
let (counterexample, iterations) = match self.run_n_times(n, Prng::from_seed(seed), None) {
|
||||
|
@ -679,20 +675,20 @@ impl<'a> Counterexample<'a> {
|
|||
// ----------------------------------------------------------------------------
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum TestResult<T> {
|
||||
UnitTestResult(UnitTestResult),
|
||||
pub enum TestResult<U, T> {
|
||||
UnitTestResult(UnitTestResult<U>),
|
||||
PropertyTestResult(PropertyTestResult<T>),
|
||||
}
|
||||
|
||||
unsafe impl<T> Send for TestResult<T> {}
|
||||
unsafe impl<U, T> Send for TestResult<U, T> {}
|
||||
|
||||
impl TestResult<PlutusData> {
|
||||
impl TestResult<(Constant, Rc<Type>), PlutusData> {
|
||||
pub fn reify(
|
||||
self,
|
||||
data_types: &IndexMap<&DataTypeKey, &TypedDataType>,
|
||||
) -> TestResult<UntypedExpr> {
|
||||
) -> TestResult<UntypedExpr, UntypedExpr> {
|
||||
match self {
|
||||
TestResult::UnitTestResult(test) => TestResult::UnitTestResult(test),
|
||||
TestResult::UnitTestResult(test) => TestResult::UnitTestResult(test.reify(data_types)),
|
||||
TestResult::PropertyTestResult(test) => {
|
||||
TestResult::PropertyTestResult(test.reify(data_types))
|
||||
}
|
||||
|
@ -700,7 +696,7 @@ impl TestResult<PlutusData> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> TestResult<T> {
|
||||
impl<U, T> TestResult<U, T> {
|
||||
pub fn is_success(&self) -> bool {
|
||||
match self {
|
||||
TestResult::UnitTestResult(UnitTestResult { success, .. }) => *success,
|
||||
|
@ -766,15 +762,52 @@ impl<T> TestResult<T> {
|
|||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct UnitTestResult {
|
||||
pub struct UnitTestResult<T> {
|
||||
pub success: bool,
|
||||
pub spent_budget: ExBudget,
|
||||
pub output: Option<Term<NamedDeBruijn>>,
|
||||
pub logs: Vec<String>,
|
||||
pub test: UnitTest,
|
||||
pub assertion: Option<Assertion<T>>,
|
||||
}
|
||||
|
||||
unsafe impl Send for UnitTestResult {}
|
||||
unsafe impl<T> Send for UnitTestResult<T> {}
|
||||
|
||||
impl UnitTestResult<(Constant, Rc<Type>)> {
|
||||
pub fn reify(
|
||||
self,
|
||||
data_types: &IndexMap<&DataTypeKey, &TypedDataType>,
|
||||
) -> UnitTestResult<UntypedExpr> {
|
||||
UnitTestResult {
|
||||
success: self.success,
|
||||
spent_budget: self.spent_budget,
|
||||
output: self.output,
|
||||
logs: self.logs,
|
||||
test: self.test,
|
||||
assertion: self.assertion.and_then(|assertion| {
|
||||
// No need to spend time/cpu on reifying assertions for successful
|
||||
// tests since they aren't shown.
|
||||
if self.success {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(Assertion {
|
||||
bin_op: assertion.bin_op,
|
||||
head: assertion.head.map(|(cst, tipo)| {
|
||||
UntypedExpr::reify_constant(data_types, cst, &tipo)
|
||||
.expect("failed to reify assertion operand?")
|
||||
}),
|
||||
tail: assertion.tail.map(|xs| {
|
||||
xs.mapped(|(cst, tipo)| {
|
||||
UntypedExpr::reify_constant(data_types, cst, &tipo)
|
||||
.expect("failed to reify assertion operand?")
|
||||
})
|
||||
}),
|
||||
})
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PropertyTestResult<T> {
|
||||
|
@ -791,17 +824,10 @@ impl PropertyTestResult<PlutusData> {
|
|||
data_types: &IndexMap<&DataTypeKey, &TypedDataType>,
|
||||
) -> PropertyTestResult<UntypedExpr> {
|
||||
PropertyTestResult {
|
||||
counterexample: match self.counterexample {
|
||||
None => None,
|
||||
Some(counterexample) => Some(
|
||||
UntypedExpr::reify_data(
|
||||
data_types,
|
||||
counterexample,
|
||||
&self.test.fuzzer.type_info,
|
||||
)
|
||||
.expect("Failed to reify counterexample?"),
|
||||
),
|
||||
},
|
||||
counterexample: self.counterexample.map(|counterexample| {
|
||||
UntypedExpr::reify_data(data_types, counterexample, &self.test.fuzzer.type_info)
|
||||
.expect("Failed to reify counterexample?")
|
||||
}),
|
||||
iterations: self.iterations,
|
||||
test: self.test,
|
||||
}
|
||||
|
@ -1266,7 +1292,7 @@ mod test {
|
|||
}
|
||||
"#});
|
||||
|
||||
assert!(prop.run(42).is_success());
|
||||
assert!(prop.run::<()>(42).is_success());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
Loading…
Reference in New Issue