Fix and improve test outputs for prop tests.

This commit is contained in:
KtorZ 2024-03-03 21:00:51 +01:00
parent 7a2537432a
commit fbda31d980
No known key found for this signature in database
GPG Key ID: 33173CB6F77F4277
4 changed files with 103 additions and 80 deletions

View File

@ -125,6 +125,12 @@ pub enum Error {
impl Error { impl Error {
pub fn report(&self) { pub fn report(&self) {
if let Error::TestFailure { verbose, .. } = self {
if !verbose {
return;
}
}
println!("{self:?}") println!("{self:?}")
} }
@ -320,25 +326,33 @@ impl Diagnostic for Error {
Error::Parse { error, .. } => error.kind.help(), Error::Parse { error, .. } => error.kind.help(),
Error::Type { error, .. } => error.help(), Error::Type { error, .. } => error.help(),
Error::StandardIo(_) => None, Error::StandardIo(_) => None,
Error::MissingManifest { .. } => Some(Box::new("Try running `aiken new <REPOSITORY/PROJECT>` to initialise a project with an example manifest.")), Error::MissingManifest { .. } => Some(Box::new(
"Try running `aiken new <REPOSITORY/PROJECT>` to initialise a project with an example manifest.",
)),
Error::TomlLoading { .. } => None, Error::TomlLoading { .. } => None,
Error::Format { .. } => None, Error::Format { .. } => None,
Error::TestFailure { assertion, .. } => match assertion { Error::TestFailure { assertion, .. } => match assertion {
None => None, None => None,
Some(hint) => Some(Box::new(hint.to_string())) Some(hint) => Some(Box::new(hint.to_string())),
}, },
Error::Http(_) => None, Error::Http(_) => None,
Error::ZipExtract(_) => None, Error::ZipExtract(_) => None,
Error::JoinError(_) => None, Error::JoinError(_) => None,
Error::UnknownPackageVersion{..} => Some(Box::new("Perhaps, double-check the package repository and version?")), Error::UnknownPackageVersion { .. } => Some(Box::new(
Error::UnableToResolvePackage{..} => Some(Box::new("The network is unavailable and the package isn't in the local cache either. Try connecting to the Internet so I can look it up?")), "Perhaps, double-check the package repository and version?",
)),
Error::UnableToResolvePackage { .. } => Some(Box::new(
"The network is unavailable and the package isn't in the local cache either. Try connecting to the Internet so I can look it up?",
)),
Error::Json(error) => Some(Box::new(format!("{error}"))), Error::Json(error) => Some(Box::new(format!("{error}"))),
Error::MalformedStakeAddress { error } => Some(Box::new(format!("A stake address must be provided either as a base16-encoded string, or as a bech32-encoded string with the 'stake' or 'stake_test' prefix.{hint}", hint = match error { Error::MalformedStakeAddress { error } => Some(Box::new(format!(
"A stake address must be provided either as a base16-encoded string, or as a bech32-encoded string with the 'stake' or 'stake_test' prefix.{hint}",
hint = match error {
Some(error) => format!("\n\nHere's the error I encountered: {error}"), Some(error) => format!("\n\nHere's the error I encountered: {error}"),
None => String::new(), None => String::new(),
}))), }
Error::NoValidatorNotFound { known_validators } => { ))),
Some(Box::new(format!( Error::NoValidatorNotFound { known_validators } => Some(Box::new(format!(
"Here's a list of all validators I've found in your project. Please double-check this list against the options that you've provided:\n\n{}", "Here's a list of all validators I've found in your project. Please double-check this list against the options that you've provided:\n\n{}",
known_validators known_validators
.iter() .iter()
@ -348,10 +362,8 @@ impl Diagnostic for Error {
)) ))
.collect::<Vec<String>>() .collect::<Vec<String>>()
.join("\n") .join("\n")
))) ))),
}, Error::MoreThanOneValidatorFound { known_validators } => Some(Box::new(format!(
Error::MoreThanOneValidatorFound { known_validators } => {
Some(Box::new(format!(
"Here's a list of all validators I've found in your project. Select one of them using the appropriate options:\n\n{}", "Here's a list of all validators I've found in your project. Select one of them using the appropriate options:\n\n{}",
known_validators known_validators
.iter() .iter()
@ -361,8 +373,7 @@ impl Diagnostic for Error {
)) ))
.collect::<Vec<String>>() .collect::<Vec<String>>()
.join("\n") .join("\n")
))) ))),
},
Error::Module(e) => e.help(), Error::Module(e) => e.help(),
} }
} }

View File

@ -10,11 +10,7 @@ pub fn ansi_len(s: &str) -> usize {
pub fn len_longest_line(zero: usize, s: &str) -> usize { pub fn len_longest_line(zero: usize, s: &str) -> usize {
s.lines().fold(zero, |max, l| { s.lines().fold(zero, |max, l| {
let n = ansi_len(l); let n = ansi_len(l);
if n > max { if n > max { n } else { max }
n
} else {
max
}
}) })
} }
@ -73,11 +69,18 @@ pub fn open_box(
let top = format!( let top = format!(
"{} {}", "{} {}",
border_style("┍━"), border_style(if footer.is_empty() {
"┝━"
} else {
"┍━"
}),
pad_right(format!("{title} "), i - 1, &border_style("")), pad_right(format!("{title} "), i - 1, &border_style("")),
); );
let bottom = format!( let bottom = if footer.is_empty() {
border_style("")
} else {
format!(
"{} {}", "{} {}",
pad_right( pad_right(
border_style(""), border_style(""),
@ -85,7 +88,8 @@ pub fn open_box(
&border_style("") &border_style("")
), ),
footer footer
); )
};
format!("{top}\n{content}\n{bottom}") format!("{top}\n{content}\n{bottom}")
} }
@ -120,11 +124,7 @@ pub fn pad_right(mut text: String, n: usize, delimiter: &str) -> String {
} }
pub fn style_if(styled: bool, s: String, apply_style: fn(String) -> String) -> String { pub fn style_if(styled: bool, s: String, apply_style: fn(String) -> String) -> String {
if styled { if styled { apply_style(s) } else { s }
apply_style(s)
} else {
s
}
} }
pub fn multiline(max_len: usize, s: String) -> Vec<String> { pub fn multiline(max_len: usize, s: String) -> Vec<String> {

View File

@ -1,5 +1,7 @@
use crate::pretty; use crate::{
use crate::test_framework::{PropertyTestResult, TestResult, UnitTestResult}; pretty,
test_framework::{PropertyTestResult, TestResult, UnitTestResult},
};
use aiken_lang::{expr::UntypedExpr, format::Formatter}; use aiken_lang::{expr::UntypedExpr, format::Formatter};
use owo_colors::{OwoColorize, Stream::Stderr}; use owo_colors::{OwoColorize, Stream::Stderr};
use std::{collections::BTreeMap, fmt::Display, path::PathBuf}; use std::{collections::BTreeMap, fmt::Display, path::PathBuf};
@ -169,7 +171,7 @@ impl EventListener for Terminal {
); );
} }
Event::FinishedTests { tests } => { Event::FinishedTests { tests } => {
let (max_mem, max_cpu) = find_max_execution_units(&tests); let (max_mem, max_cpu, max_iter) = find_max_execution_units(&tests);
for (module, results) in &group_by_module(&tests) { for (module, results) in &group_by_module(&tests) {
let title = module let title = module
@ -179,7 +181,7 @@ impl EventListener for Terminal {
let tests = results let tests = results
.iter() .iter()
.map(|r| fmt_test(r, max_mem, max_cpu, true)) .map(|r| fmt_test(r, max_mem, max_cpu, max_iter, true))
.collect::<Vec<String>>() .collect::<Vec<String>>()
.join("\n"); .join("\n");
@ -254,6 +256,7 @@ fn fmt_test(
result: &TestResult<UntypedExpr>, result: &TestResult<UntypedExpr>,
max_mem: usize, max_mem: usize,
max_cpu: usize, max_cpu: usize,
max_iter: usize,
styled: bool, styled: bool,
) -> String { ) -> String {
// Status // Status
@ -292,10 +295,10 @@ fn fmt_test(
test = pretty::pad_right( test = pretty::pad_right(
format!( format!(
"{test} [after {} test{}]", "{test} [after {} test{}]",
pretty::pad_left(iterations.to_string(), 3, " "), pretty::pad_left(iterations.to_string(), max_iter, " "),
if *iterations > 1 { "s" } else { "" } if *iterations > 1 { "s" } else { "" }
), ),
14 + max_mem + max_cpu, 18 + max_mem + max_cpu + max_iter,
" ", " ",
); );
} }
@ -317,7 +320,7 @@ fn fmt_test(
{ {
test = format!( test = format!(
"{test}\n{}", "{test}\n{}",
pretty::boxed_with( pretty::open_box(
&pretty::style_if(styled, "counterexample".to_string(), |s| s &pretty::style_if(styled, "counterexample".to_string(), |s| s
.if_supports_color(Stderr, |s| s.red()) .if_supports_color(Stderr, |s| s.red())
.if_supports_color(Stderr, |s| s.bold()) .if_supports_color(Stderr, |s| s.bold())
@ -325,6 +328,7 @@ fn fmt_test(
&Formatter::new() &Formatter::new()
.expr(counterexample, false) .expr(counterexample, false)
.to_pretty_string(70), .to_pretty_string(70),
"",
|s| s.red().to_string() |s| s.red().to_string()
) )
) )
@ -392,23 +396,29 @@ fn group_by_module<T>(results: &Vec<TestResult<T>>) -> BTreeMap<String, Vec<&Tes
modules modules
} }
fn find_max_execution_units<T>(xs: &[TestResult<T>]) -> (usize, usize) { fn find_max_execution_units<T>(xs: &[TestResult<T>]) -> (usize, usize, usize) {
let (max_mem, max_cpu) = xs let (max_mem, max_cpu, max_iter) =
.iter() xs.iter()
.fold((0, 0), |(max_mem, max_cpu), test| match test { .fold((0, 0, 0), |(max_mem, max_cpu, max_iter), test| match test {
TestResult::PropertyTestResult(..) => (max_mem, max_cpu), TestResult::PropertyTestResult(PropertyTestResult { iterations, .. }) => {
(max_mem, max_cpu, std::cmp::max(max_iter, *iterations))
}
TestResult::UnitTestResult(UnitTestResult { spent_budget, .. }) => { TestResult::UnitTestResult(UnitTestResult { spent_budget, .. }) => {
if spent_budget.mem >= max_mem && spent_budget.cpu >= max_cpu { if spent_budget.mem >= max_mem && spent_budget.cpu >= max_cpu {
(spent_budget.mem, spent_budget.cpu) (spent_budget.mem, spent_budget.cpu, max_iter)
} else if spent_budget.mem > max_mem { } else if spent_budget.mem > max_mem {
(spent_budget.mem, max_cpu) (spent_budget.mem, max_cpu, max_iter)
} else if spent_budget.cpu > max_cpu { } else if spent_budget.cpu > max_cpu {
(max_mem, spent_budget.cpu) (max_mem, spent_budget.cpu, max_iter)
} else { } else {
(max_mem, max_cpu) (max_mem, max_cpu, max_iter)
} }
} }
}); });
(max_mem.to_string().len(), max_cpu.to_string().len()) (
max_mem.to_string().len(),
max_cpu.to_string().len(),
max_iter.to_string().len(),
)
} }

View File

@ -123,7 +123,9 @@ where
if errs.iter().any(|e| matches!(e, Error::TestFailure { .. })) { if errs.iter().any(|e| matches!(e, Error::TestFailure { .. })) {
eprintln!( eprintln!(
" ━━━━━━\n ╰─▶ use {} {} to replay", " {}══╤══\n{} ╰─▶ use {} {} to replay",
if errs.len() > 1 { "" } else { "" },
if errs.len() > 1 { " " } else { "" },
"--seed".if_supports_color(Stderr, |s| s.bold()), "--seed".if_supports_color(Stderr, |s| s.bold()),
format!("{seed}").if_supports_color(Stderr, |s| s.bold()) format!("{seed}").if_supports_color(Stderr, |s| s.bold())
); );