From dde4bc79203cfb375d46ac5ebadd64aa4edc6b8d Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sat, 14 Oct 2023 14:30:24 -0400 Subject: [PATCH] Add code for structured printing of test results. --- src/bin_foreign_document_test.rs | 148 ++++++++++++++++++++++++++++++- 1 file changed, 146 insertions(+), 2 deletions(-) diff --git a/src/bin_foreign_document_test.rs b/src/bin_foreign_document_test.rs index c4d809b8..f6018b9d 100644 --- a/src/bin_foreign_document_test.rs +++ b/src/bin_foreign_document_test.rs @@ -6,7 +6,6 @@ use std::path::PathBuf; use futures::future::BoxFuture; use futures::future::FutureExt; -use organic::compare::run_anonymous_compare; use organic::compare::run_compare_on_file; use tokio::sync::Semaphore; use tokio::task::JoinError; @@ -53,7 +52,7 @@ async fn main_body() -> Result<(), Box> { let running_tests: Vec<_> = layer.map(|c| tokio::spawn(c.run_test())).collect(); for test in running_tests.into_iter() { let test_result = test.await??; - println!("{:?}", test_result); + test_result.print(); } 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 + } +}