Add code for structured printing of test results.

This commit is contained in:
Tom Alexander 2023-10-14 14:30:24 -04:00
parent 3d68e1fd00
commit dde4bc7920
Signed by: talexander
GPG Key ID: D3A179C9A53C0EDE

View File

@ -6,7 +6,6 @@ use std::path::PathBuf;
use futures::future::BoxFuture; use futures::future::BoxFuture;
use futures::future::FutureExt; use futures::future::FutureExt;
use organic::compare::run_anonymous_compare;
use organic::compare::run_compare_on_file; use organic::compare::run_compare_on_file;
use tokio::sync::Semaphore; use tokio::sync::Semaphore;
use tokio::task::JoinError; use tokio::task::JoinError;
@ -53,7 +52,7 @@ async fn main_body() -> Result<(), Box<dyn std::error::Error>> {
let running_tests: Vec<_> = layer.map(|c| tokio::spawn(c.run_test())).collect(); let running_tests: Vec<_> = layer.map(|c| tokio::spawn(c.run_test())).collect();
for test in running_tests.into_iter() { for test in running_tests.into_iter() {
let test_result = test.await??; let test_result = test.await??;
println!("{:?}", test_result); test_result.print();
} }
Ok(()) Ok(())
@ -187,3 +186,148 @@ impl TestLayer {
}) })
} }
} }
impl TestResult {
pub fn print(&self) {
self.print_indented(0);
}
fn print_indented(&self, indentation: usize) {
match self {
TestResult::ResultLayer(result) => result.print_indented(indentation),
TestResult::SingleFileResult(result) => result.print_indented(indentation),
}
}
fn has_bad_children(&self) -> bool {
match self {
TestResult::ResultLayer(result) => result.has_bad_children(),
TestResult::SingleFileResult(result) => result.has_bad_children(),
}
}
fn is_immediately_bad(&self) -> bool {
match self {
TestResult::ResultLayer(result) => result.is_immediately_bad(),
TestResult::SingleFileResult(result) => result.is_immediately_bad(),
}
}
pub(crate) fn foreground_color(red: u8, green: u8, blue: u8) -> String {
if TestResult::should_use_color() {
format!(
"\x1b[38;2;{red};{green};{blue}m",
red = red,
green = green,
blue = blue
)
} else {
String::new()
}
}
#[allow(dead_code)]
pub(crate) fn background_color(red: u8, green: u8, blue: u8) -> String {
if TestResult::should_use_color() {
format!(
"\x1b[48;2;{red};{green};{blue}m",
red = red,
green = green,
blue = blue
)
} else {
String::new()
}
}
pub(crate) fn reset_color() -> &'static str {
if TestResult::should_use_color() {
"\x1b[0m"
} else {
""
}
}
fn should_use_color() -> bool {
!std::env::var("NO_COLOR").is_ok_and(|val| !val.is_empty())
}
}
impl SingleFileResult {
fn print_indented(&self, indentation: usize) {
match self.status {
TestStatus::Pass => {
println!(
"{indentation}{color}PASS{reset} {name}",
indentation = " ".repeat(indentation),
color = TestResult::foreground_color(0, 255, 0),
reset = TestResult::reset_color(),
name = self.name
);
}
TestStatus::Fail => {
println!(
"{indentation}{color}FAIL{reset} {name}",
indentation = " ".repeat(indentation),
color = TestResult::foreground_color(255, 0, 0),
reset = TestResult::reset_color(),
name = self.name
);
}
}
}
fn has_bad_children(&self) -> bool {
false
}
fn is_immediately_bad(&self) -> bool {
match self.status {
TestStatus::Pass => false,
TestStatus::Fail => true,
}
}
}
impl ResultLayer {
fn print_indented(&self, indentation: usize) {
if self.is_immediately_bad() {
println!(
"{indentation}{color}FAIL{reset} {name}",
indentation = " ".repeat(indentation),
color = TestResult::foreground_color(255, 0, 0),
reset = TestResult::reset_color(),
name = self.name
);
} else if self.has_bad_children() {
println!(
"{indentation}{color}BADCHILD{reset} {name}",
indentation = " ".repeat(indentation),
color = TestResult::foreground_color(255, 255, 0),
reset = TestResult::reset_color(),
name = self.name
);
} else {
println!(
"{indentation}{color}PASS{reset} {name}",
indentation = " ".repeat(indentation),
color = TestResult::foreground_color(0, 255, 0),
reset = TestResult::reset_color(),
name = self.name
);
}
self.children
.iter()
.for_each(|result| result.print_indented(indentation + 1));
}
fn has_bad_children(&self) -> bool {
self.children
.iter()
.any(|result| result.is_immediately_bad() || result.has_bad_children())
}
fn is_immediately_bad(&self) -> bool {
false
}
}