use mumu::parser::interpreter::Interpreter;
use mumu::parser::types::Value;
use super::helper::{
runner_list_bridge, HRULE, HRULE_PLAIN, copy_to_clipboard
};
use super::run_single::{run_single_file_with_report, run_single_file_verbose, FileReport};
use std::fmt::Write as FmtWrite;
pub fn runner_all_bridge(interp: &mut Interpreter, args: Vec<Value>) -> Result<Value, String> {
let (opts, cb) = match args.len() {
1 => (None, args[0].clone()),
2 => (Some(args[0].clone()), args[1].clone()),
n => return Err(format!("test:all => expected 1 or 2 args, got {}", n)),
};
let mut colorize = true;
let mut errors_only = false;
if let Some(Value::KeyedArray(ref map)) = opts {
if let Some(Value::Bool(b)) = map.get("colorize") {
colorize = *b;
}
if let Some(Value::Bool(b)) = map.get("errors_only") {
errors_only = *b;
}
}
let Value::StrArray(mut files) = runner_list_bridge(interp, vec![])? else {
unreachable!("runner_list_bridge did not return a StrArray");
};
files.sort();
let mut results: Vec<(bool, String, String, FileReport)> = Vec::new();
for fname in &files {
let (pass, output, report) = run_single_file_with_report(interp, fname, &cb, colorize)?;
results.push((pass, fname.clone(), output, report));
}
results.sort_by(|a, b| match (a.0, b.0) {
(true, false) => std::cmp::Ordering::Less,
(false, true) => std::cmp::Ordering::Greater,
_ => a.1.cmp(&b.1),
});
let last_fail_idx = results.iter().rposition(|(pass, _, _, _)| !*pass);
if let Some(idx) = last_fail_idx {
let last_fail_fname = &results[idx].1;
match run_single_file_verbose(last_fail_fname) {
Ok(clip_data) => copy_to_clipboard(&clip_data),
Err(e) => eprintln!("Error running verbose mode for '{}': {}", last_fail_fname, e),
}
}
for (i, (pass, _fname, mut output, report)) in results.into_iter().enumerate() {
if errors_only && pass {
continue;
}
if errors_only {
let mut suite_out = String::new();
if colorize {
writeln!(suite_out, "{HRULE}").unwrap();
writeln!(suite_out, "\x1b[1;31m{}\x1b[0m", report.suite).unwrap();
} else {
writeln!(suite_out, "{HRULE_PLAIN}").unwrap();
writeln!(suite_out, "{}", report.suite).unwrap();
}
writeln!(suite_out).unwrap();
let mut had_failing = false;
for t in &report.tests {
if t.passed { continue; }
had_failing = true;
if colorize {
writeln!(suite_out, "\x1b[31m✖ {}\x1b[0m ({} µs)", t.name, t.time_us).unwrap();
writeln!(suite_out).unwrap();
for line in t.output.lines() {
writeln!(suite_out, " {}", line).unwrap();
}
writeln!(suite_out).unwrap();
} else {
writeln!(suite_out, "✖ {} ({} µs)", t.name, t.time_us).unwrap();
writeln!(suite_out).unwrap();
for line in t.output.lines() {
writeln!(suite_out, " {}", line).unwrap();
}
writeln!(suite_out).unwrap();
}
}
if had_failing {
if colorize {
writeln!(suite_out).unwrap();
writeln!(suite_out, "\x1b[1;31mFAILED\x1b[0m").unwrap();
writeln!(suite_out).unwrap();
} else {
writeln!(suite_out).unwrap();
writeln!(suite_out, "FAILED").unwrap();
writeln!(suite_out).unwrap();
}
if let Some(idx) = last_fail_idx {
if i == idx {
if colorize {
let needle = "\n\x1b[1;31mFAILED\x1b[0m\n\n";
let replacement = "\n\x1b[1;31mFAILED\x1b[0m\n\x1b[1;31mDEBUG IN CLIPBOARD\x1b[0m\n\n";
suite_out = suite_out.replacen(needle, replacement, 1);
} else {
let needle = "\nFAILED\n\n";
let replacement = "\nFAILED\nDEBUG IN CLIPBOARD\n\n";
suite_out = suite_out.replacen(needle, replacement, 1);
}
}
}
print!("{}", suite_out);
}
continue;
}
if let Some(idx) = last_fail_idx {
if !pass && i == idx && colorize {
let needle = "\n\x1b[1;31mFAILED\x1b[0m\n\n";
let replacement = "\n\x1b[1;31mFAILED\x1b[0m\n\x1b[1;31mDEBUG IN CLIPBOARD\x1b[0m\n\n";
output = output.replacen(needle, replacement, 1);
} else if !pass && i == idx && !colorize {
let needle = "\nFAILED\n\n";
let replacement = "\nFAILED\nDEBUG IN CLIPBOARD\n\n";
output = output.replacen(needle, replacement, 1);
}
}
print!("{}", output);
}
Ok(Value::Bool(true))
}