use crate::{
parsing::{parse_cargo_test, Stats},
prettify::{make_pretty, TestTree, ICON_NOTATION},
regex::re,
};
use colored::Colorize;
use std::process::{Command, ExitCode, Output};
use termtree::Tree;
pub struct Emit {
output: Output,
no_parse: bool,
}
impl Emit {
pub fn run(self) -> ExitCode {
let Emit { output, no_parse } = self;
let stderr = strip_ansi_escapes::strip(output.stderr);
let stdout = strip_ansi_escapes::strip(output.stdout);
let stderr = String::from_utf8_lossy(&stderr);
let stdout = String::from_utf8_lossy(&stdout);
if no_parse {
println!(
"{phelp}\n{ICON_NOTATION}\n{sep}\n\n{help}",
phelp = "cargo pretty-test help:".blue().bold(),
sep = re().separator,
help = "cargo test help:".blue().bold()
);
eprintln!("{stderr}");
println!("{stdout}");
} else {
let (tree, stats) = parse_cargo_test_output(&stderr, &stdout);
println!("{tree}");
eprintln!("{stats}");
if !stats.ok {
return ExitCode::FAILURE;
}
}
ExitCode::SUCCESS
}
}
pub fn run() -> ExitCode {
cargo_test().run()
}
pub fn cargo_test() -> Emit {
let passin: Vec<_> = std::env::args().collect();
let forward = if passin
.get(..2)
.is_some_and(|v| v[0].ends_with("cargo-pretty-test") && v[1] == "pretty-test")
{
&passin[2..]
} else {
&passin[1..]
};
let no_parse = passin.iter().any(|arg| arg == "--help" || arg == "-h");
let args = forward.iter().filter(|arg| *arg != "--nocapture");
Emit {
output: Command::new("cargo")
.arg("test")
.args(args)
.output()
.expect("`cargo test` failed"),
no_parse,
}
}
pub fn parse_cargo_test_output<'s>(stderr: &'s str, stdout: &'s str) -> (TestTree<'s>, Stats) {
let mut tree = Tree::new("Generated by cargo-pretty-test".bold().to_string().into());
let mut stats = Stats::default();
for (pkg, data) in parse_cargo_test(stderr, stdout).pkgs {
stats += &data.stats;
let root = data.stats.root_string(pkg.unwrap_or("tests")).into();
tree.push(
Tree::new(root).with_leaves(data.inner.into_iter().filter_map(|data| {
let parsed = data.info.parsed;
let detail_without_stats = parsed.detail;
if !detail_without_stats.is_empty() {
eprintln!("{detail_without_stats}\n\n{}\n", re().separator);
}
let root = data.info.stats.subroot_string(data.runner.src.src_path);
make_pretty(root, parsed.tree.into_iter())
})),
);
}
(tree, stats)
}