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 {
pub fn report(&self) {
if let Error::TestFailure { verbose, .. } = self {
if !verbose {
return;
}
}
println!("{self:?}")
}
@ -320,49 +326,54 @@ impl Diagnostic for Error {
Error::Parse { error, .. } => error.kind.help(),
Error::Type { error, .. } => error.help(),
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::Format { .. } => None,
Error::TestFailure { assertion, .. } => match assertion {
Error::TestFailure { assertion, .. } => match assertion {
None => None,
Some(hint) => Some(Box::new(hint.to_string()))
Some(hint) => Some(Box::new(hint.to_string())),
},
Error::Http(_) => None,
Error::ZipExtract(_) => None,
Error::JoinError(_) => None,
Error::UnknownPackageVersion{..} => Some(Box::new("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::UnknownPackageVersion { .. } => Some(Box::new(
"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::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}"),
None => String::new(),
}))),
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{}",
known_validators
.iter()
.map(|title| format!(
"→ {title}",
title = title.if_supports_color(Stdout, |s| s.purple())
))
.collect::<Vec<String>>()
.join("\n")
)))
},
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{}",
known_validators
.iter()
.map(|title| format!(
"→ {title}",
title = title.if_supports_color(Stdout, |s| s.purple())
))
.collect::<Vec<String>>()
.join("\n")
)))
},
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}"),
None => String::new(),
}
))),
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{}",
known_validators
.iter()
.map(|title| format!(
"→ {title}",
title = title.if_supports_color(Stdout, |s| s.purple())
))
.collect::<Vec<String>>()
.join("\n")
))),
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{}",
known_validators
.iter()
.map(|title| format!(
"→ {title}",
title = title.if_supports_color(Stdout, |s| s.purple())
))
.collect::<Vec<String>>()
.join("\n")
))),
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 {
s.lines().fold(zero, |max, l| {
let n = ansi_len(l);
if n > max {
n
} else {
max
}
if n > max { n } else { max }
})
}
@ -73,19 +69,27 @@ pub fn open_box(
let top = format!(
"{} {}",
border_style("┍━"),
border_style(if footer.is_empty() {
"┝━"
} else {
"┍━"
}),
pad_right(format!("{title} "), i - 1, &border_style("")),
);
let bottom = format!(
"{} {}",
pad_right(
border_style(""),
if j < k { 0 } else { j + 1 - k },
&border_style("")
),
footer
);
let bottom = if footer.is_empty() {
border_style("")
} else {
format!(
"{} {}",
pad_right(
border_style(""),
if j < k { 0 } else { j + 1 - k },
&border_style("")
),
footer
)
};
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 {
if styled {
apply_style(s)
} else {
s
}
if styled { apply_style(s) } else { s }
}
pub fn multiline(max_len: usize, s: String) -> Vec<String> {

View File

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