- **Fix a bunch of low hanging style lints like unnecessary-return** - **Fix single worktree violation** - **And the rest** Release Notes: - N/A
171 lines
4.3 KiB
Rust
171 lines
4.3 KiB
Rust
use serde::{Deserialize, Serialize};
|
|
use std::fmt::Write;
|
|
use std::fmt::{self};
|
|
|
|
#[derive(Default, Debug, Serialize, Deserialize, Clone)]
|
|
pub struct AssertionsReport {
|
|
pub ran: Vec<RanAssertion>,
|
|
pub max: Option<usize>,
|
|
}
|
|
|
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
pub struct RanAssertion {
|
|
pub id: String,
|
|
pub result: Result<RanAssertionResult, String>,
|
|
}
|
|
|
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
pub struct RanAssertionResult {
|
|
pub analysis: Option<String>,
|
|
pub passed: bool,
|
|
}
|
|
|
|
impl AssertionsReport {
|
|
pub fn new(max: Option<usize>) -> Self {
|
|
AssertionsReport {
|
|
ran: Vec::new(),
|
|
max,
|
|
}
|
|
}
|
|
|
|
pub fn error(msg: String) -> Self {
|
|
let assert = RanAssertion {
|
|
id: "no-unhandled-errors".into(),
|
|
result: Err(msg),
|
|
};
|
|
AssertionsReport {
|
|
ran: vec![assert],
|
|
max: Some(1),
|
|
}
|
|
}
|
|
|
|
pub fn is_empty(&self) -> bool {
|
|
self.ran.is_empty()
|
|
}
|
|
|
|
pub fn total_count(&self) -> usize {
|
|
self.run_count().max(self.max.unwrap_or(0))
|
|
}
|
|
|
|
pub fn run_count(&self) -> usize {
|
|
self.ran.len()
|
|
}
|
|
|
|
pub fn passed_count(&self) -> usize {
|
|
self.ran
|
|
.iter()
|
|
.filter(|a| a.result.as_ref().is_ok_and(|result| result.passed))
|
|
.count()
|
|
}
|
|
|
|
pub fn passed_percentage(&self) -> f32 {
|
|
if self.total_count() == 0 {
|
|
0.0
|
|
} else {
|
|
(self.passed_count() as f32 / self.total_count() as f32) * 100.0
|
|
}
|
|
}
|
|
}
|
|
|
|
const ROUND_WIDTH: usize = "Round".len();
|
|
const ASSERTIONS_WIDTH: usize = 42;
|
|
const RESULTS_WIDTH: usize = 8;
|
|
|
|
pub fn print_table_header() {
|
|
println!(
|
|
"┌─{}─┬─{}─┬─{}─┐",
|
|
"─".repeat(ROUND_WIDTH),
|
|
"─".repeat(ASSERTIONS_WIDTH),
|
|
"─".repeat(RESULTS_WIDTH)
|
|
);
|
|
|
|
println!(
|
|
"│ {:^ROUND_WIDTH$} │ {:^ASSERTIONS_WIDTH$} │ {:^RESULTS_WIDTH$} │",
|
|
"Round", "Assertion", "Result"
|
|
);
|
|
|
|
println!(
|
|
"├─{}─┼─{}─┼─{}─┤",
|
|
"─".repeat(ROUND_WIDTH),
|
|
"─".repeat(ASSERTIONS_WIDTH),
|
|
"─".repeat(RESULTS_WIDTH)
|
|
)
|
|
}
|
|
|
|
pub fn display_error_row(f: &mut String, round: usize, error: String) -> fmt::Result {
|
|
let last_two_columns = ASSERTIONS_WIDTH + RESULTS_WIDTH;
|
|
writeln!(
|
|
f,
|
|
"│ {:^ROUND_WIDTH$} │ {:<last_two_columns$} |",
|
|
round,
|
|
truncate(&error, last_two_columns)
|
|
)
|
|
}
|
|
|
|
pub fn display_table_row(f: &mut String, round: usize, assertion: &RanAssertion) -> fmt::Result {
|
|
let result = match &assertion.result {
|
|
Ok(result) if result.passed => "\x1b[32m✔︎ Passed\x1b[0m",
|
|
Ok(_) => "\x1b[31m✗ Failed\x1b[0m",
|
|
Err(_) => "\x1b[31m💥 Judge Error\x1b[0m",
|
|
};
|
|
|
|
writeln!(
|
|
f,
|
|
"│ {:^ROUND_WIDTH$} │ {:<ASSERTIONS_WIDTH$} │ {:>RESULTS_WIDTH$} │",
|
|
round,
|
|
truncate(&assertion.id, ASSERTIONS_WIDTH),
|
|
result
|
|
)
|
|
}
|
|
|
|
pub fn print_table_round_summary<'a>(
|
|
round: &str,
|
|
reports: impl Iterator<Item = &'a AssertionsReport>,
|
|
) {
|
|
let mut passed = 0;
|
|
let mut total = 0;
|
|
for report in reports {
|
|
passed += report.passed_count();
|
|
total += report.total_count();
|
|
}
|
|
|
|
println!(
|
|
"│ {:^ROUND_WIDTH$} │ {:<ASSERTIONS_WIDTH$} │ {:>RESULTS_WIDTH$} │",
|
|
round,
|
|
"total",
|
|
format!("{}%", (passed as f32 / total as f32 * 100.0).floor())
|
|
)
|
|
}
|
|
|
|
pub fn print_table_footer() {
|
|
println!(
|
|
"└─{}─┴─{}─┴─{}─┘",
|
|
"─".repeat(ROUND_WIDTH),
|
|
"─".repeat(ASSERTIONS_WIDTH),
|
|
"─".repeat(RESULTS_WIDTH)
|
|
)
|
|
}
|
|
|
|
pub fn print_table_divider() {
|
|
println!(
|
|
"├─{}─┼─{}─┼─{}─┤",
|
|
"─".repeat(ROUND_WIDTH),
|
|
"─".repeat(ASSERTIONS_WIDTH),
|
|
"─".repeat(RESULTS_WIDTH)
|
|
)
|
|
}
|
|
|
|
fn truncate(assertion: &str, max_width: usize) -> String {
|
|
let is_verbose = std::env::var("VERBOSE").is_ok_and(|v| !v.is_empty());
|
|
|
|
if assertion.len() <= max_width || is_verbose {
|
|
assertion.to_string()
|
|
} else {
|
|
let mut end_ix = max_width - 1;
|
|
while !assertion.is_char_boundary(end_ix) {
|
|
end_ix -= 1;
|
|
}
|
|
format!("{}…", &assertion[..end_ix])
|
|
}
|
|
}
|