Fix and improve test outputs for prop tests.
This commit is contained in:
parent
7a2537432a
commit
fbda31d980
|
@ -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(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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> {
|
||||||
|
|
|
@ -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(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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())
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in New Issue