Prevent ANSI colors & styles to appear in JSON output.

This commit is contained in:
KtorZ 2024-11-13 12:52:12 +01:00
parent d24a71ee04
commit fafb89d838
No known key found for this signature in database
GPG Key ID: 33173CB6F77F4277
3 changed files with 72 additions and 54 deletions

View File

@ -1201,28 +1201,50 @@ impl TryFrom<TypedExpr> for Assertion<TypedExpr> {
} }
} }
pub struct AssertionStyleOptions<'a> {
red: Box<dyn Fn(String) -> String + 'a>,
bold: Box<dyn Fn(String) -> String + 'a>,
}
impl<'a> AssertionStyleOptions<'a> {
pub fn new(stream: Option<&'a Stream>) -> Self {
match stream {
Some(stream) => Self {
red: Box::new(|s| {
s.if_supports_color(stream.to_owned(), |s| s.red())
.to_string()
}),
bold: Box::new(|s| {
s.if_supports_color(stream.to_owned(), |s| s.bold())
.to_string()
}),
},
None => Self {
red: Box::new(|s| s),
bold: Box::new(|s| s),
},
}
}
}
impl Assertion<UntypedExpr> { impl Assertion<UntypedExpr> {
#[allow(clippy::just_underscores_and_digits)] #[allow(clippy::just_underscores_and_digits)]
pub fn to_string(&self, stream: Stream, expect_failure: bool) -> String { pub fn to_string(&self, expect_failure: bool, style: &AssertionStyleOptions) -> String {
let red = |s: &str| { let red = |s: &str| style.red.as_ref()(s.to_string());
format!("× {s}") let x = |s: &str| style.red.as_ref()(style.bold.as_ref()(format!("× {s}")));
.if_supports_color(stream, |s| s.red())
.if_supports_color(stream, |s| s.bold())
.to_string()
};
// head did not map to a constant // head did not map to a constant
if self.head.is_err() { if self.head.is_err() {
return red("program failed"); return x("program failed");
} }
// any value in tail did not map to a constant // any value in tail did not map to a constant
if self.tail.is_err() { if self.tail.is_err() {
return red("program failed"); return x("program failed");
} }
fn fmt_side(side: &UntypedExpr, stream: Stream) -> String { fn fmt_side(side: &UntypedExpr, red: &dyn Fn(&str) -> String) -> String {
let __ = "".if_supports_color(stream, |s| s.red()); let __ = red("");
Formatter::new() Formatter::new()
.expr(side, false) .expr(side, false)
@ -1233,20 +1255,17 @@ impl Assertion<UntypedExpr> {
.join("\n") .join("\n")
} }
let left = fmt_side(self.head.as_ref().unwrap(), stream); let left = fmt_side(self.head.as_ref().unwrap(), &red);
let tail = self.tail.as_ref().unwrap(); let tail = self.tail.as_ref().unwrap();
let right = fmt_side(tail.first(), stream); let right = fmt_side(tail.first(), &red);
format!( format!(
"{}{}{}", "{}{}{}",
red("expected"), x("expected"),
if expect_failure && self.bin_op == BinOp::Or { if expect_failure && self.bin_op == BinOp::Or {
" neither\n" x(" neither\n")
.if_supports_color(stream, |s| s.red())
.if_supports_color(stream, |s| s.bold())
.to_string()
} else { } else {
"\n".to_string() "\n".to_string()
}, },
@ -1254,34 +1273,34 @@ impl Assertion<UntypedExpr> {
match self.bin_op { match self.bin_op {
BinOp::And => [ BinOp::And => [
left, left,
red("and"), x("and"),
[ [
tail.mapped_ref(|s| fmt_side(s, stream)) tail.mapped_ref(|s| fmt_side(s, &red))
.join(format!("\n{}\n", red("and")).as_str()), .join(format!("\n{}\n", x("and")).as_str()),
if tail.len() > 1 { if tail.len() > 1 {
red("to not all be true") x("to not all be true")
} else { } else {
red("to not both be true") x("to not both be true")
}, },
] ]
.join("\n"), .join("\n"),
], ],
BinOp::Or => [ BinOp::Or => [
left, left,
red("nor"), x("nor"),
[ [
tail.mapped_ref(|s| fmt_side(s, stream)) tail.mapped_ref(|s| fmt_side(s, &red))
.join(format!("\n{}\n", red("nor")).as_str()), .join(format!("\n{}\n", x("nor")).as_str()),
red("to be true"), x("to be true"),
] ]
.join("\n"), .join("\n"),
], ],
BinOp::Eq => [left, red("to not equal"), right], BinOp::Eq => [left, x("to not equal"), right],
BinOp::NotEq => [left, red("to not be different"), right], BinOp::NotEq => [left, x("to not be different"), right],
BinOp::LtInt => [left, red("to not be lower than"), right], BinOp::LtInt => [left, x("to not be lower than"), right],
BinOp::LtEqInt => [left, red("to not be lower than or equal to"), right], BinOp::LtEqInt => [left, x("to not be lower than or equal to"), right],
BinOp::GtInt => [left, red("to not be greater than"), right], BinOp::GtInt => [left, x("to not be greater than"), right],
BinOp::GtEqInt => [left, red("to not be greater than or equal to"), right], BinOp::GtEqInt => [left, x("to not be greater than or equal to"), right],
_ => unreachable!("unexpected non-boolean binary operator in assertion?"), _ => unreachable!("unexpected non-boolean binary operator in assertion?"),
} }
.join("\n") .join("\n")
@ -1289,34 +1308,34 @@ impl Assertion<UntypedExpr> {
match self.bin_op { match self.bin_op {
BinOp::And => [ BinOp::And => [
left, left,
red("and"), x("and"),
[ [
tail.mapped_ref(|s| fmt_side(s, stream)) tail.mapped_ref(|s| fmt_side(s, &red))
.join(format!("\n{}\n", red("and")).as_str()), .join(format!("\n{}\n", x("and")).as_str()),
if tail.len() > 1 { if tail.len() > 1 {
red("to all be true") x("to all be true")
} else { } else {
red("to both be true") x("to both be true")
}, },
] ]
.join("\n"), .join("\n"),
], ],
BinOp::Or => [ BinOp::Or => [
left, left,
red("or"), x("or"),
[ [
tail.mapped_ref(|s| fmt_side(s, stream)) tail.mapped_ref(|s| fmt_side(s, &red))
.join(format!("\n{}\n", red("or")).as_str()), .join(format!("\n{}\n", x("or")).as_str()),
red("to be true"), x("to be true"),
] ]
.join("\n"), .join("\n"),
], ],
BinOp::Eq => [left, red("to equal"), right], BinOp::Eq => [left, x("to equal"), right],
BinOp::NotEq => [left, red("to not equal"), right], BinOp::NotEq => [left, x("to not equal"), right],
BinOp::LtInt => [left, red("to be lower than"), right], BinOp::LtInt => [left, x("to be lower than"), right],
BinOp::LtEqInt => [left, red("to be lower than or equal to"), right], BinOp::LtEqInt => [left, x("to be lower than or equal to"), right],
BinOp::GtInt => [left, red("to be greater than"), right], BinOp::GtInt => [left, x("to be greater than"), right],
BinOp::GtEqInt => [left, red("to be greater than or equal to"), right], BinOp::GtEqInt => [left, x("to be greater than or equal to"), right],
_ => unreachable!("unexpected non-boolean binary operator in assertion?"), _ => unreachable!("unexpected non-boolean binary operator in assertion?"),
} }
.join("\n") .join("\n")

View File

@ -3,9 +3,8 @@ use aiken_lang::{
ast::OnTestFailure, ast::OnTestFailure,
expr::UntypedExpr, expr::UntypedExpr,
format::Formatter, format::Formatter,
test_framework::{PropertyTestResult, TestResult, UnitTestResult}, test_framework::{AssertionStyleOptions, PropertyTestResult, TestResult, UnitTestResult},
}; };
use owo_colors::Stream::Stderr;
use serde_json::json; use serde_json::json;
#[derive(Debug, Default, Clone, Copy)] #[derive(Debug, Default, Clone, Copy)]
@ -53,7 +52,7 @@ fn fmt_test_json(result: &TestResult<UntypedExpr, UntypedExpr>) -> serde_json::V
if !result.is_success() { if !result.is_success() {
if let Some(assertion) = assertion { if let Some(assertion) = assertion {
test["assertion"] = json!({ test["assertion"] = json!({
"message": assertion.to_string(Stderr, false), "message": assertion.to_string(false, &AssertionStyleOptions::new(None)),
"expected_to_fail": matches!(unit_test.on_test_failure, OnTestFailure::SucceedEventually | OnTestFailure::SucceedImmediately), "expected_to_fail": matches!(unit_test.on_test_failure, OnTestFailure::SucceedEventually | OnTestFailure::SucceedImmediately),
}); });
} }

View File

@ -4,7 +4,7 @@ use aiken_lang::{
ast::OnTestFailure, ast::OnTestFailure,
expr::UntypedExpr, expr::UntypedExpr,
format::Formatter, format::Formatter,
test_framework::{PropertyTestResult, TestResult, UnitTestResult}, test_framework::{AssertionStyleOptions, PropertyTestResult, TestResult, UnitTestResult},
}; };
use owo_colors::{OwoColorize, Stream::Stderr}; use owo_colors::{OwoColorize, Stream::Stderr};
use uplc::machine::cost_model::ExBudget; use uplc::machine::cost_model::ExBudget;
@ -288,12 +288,12 @@ fn fmt_test(
test = format!( test = format!(
"{test}\n{}", "{test}\n{}",
assertion.to_string( assertion.to_string(
Stderr,
match unit_test.on_test_failure { match unit_test.on_test_failure {
OnTestFailure::FailImmediately => false, OnTestFailure::FailImmediately => false,
OnTestFailure::SucceedEventually | OnTestFailure::SucceedImmediately => OnTestFailure::SucceedEventually | OnTestFailure::SucceedImmediately =>
true, true,
} },
&AssertionStyleOptions::new(Some(&Stderr))
), ),
); );
} }