use std::path::Path;
use std::process::Command;
const FIXTURES: &[(&str, &str, &str)] = &[
(
"dump_0_fj-kmeans.hprof",
"dump_0_fj-kmeans_ours.md",
"dump_0_fj-kmeans_mdgraphs.md",
),
(
"dump_1_mnemonics.hprof",
"dump_1_mnemonics_ours.md",
"dump_1_mnemonics_mdgraphs.md",
),
(
"dump_2_scala-doku.hprof",
"dump_2_scala-doku_ours.md",
"dump_2_scala-doku_mdgraphs.md",
),
(
"dump_3_par-mnemonics.hprof",
"dump_3_par-mnemonics_ours.md",
"dump_3_par-mnemonics_mdgraphs.md",
),
(
"dump_4_philosophers.hprof",
"dump_4_philosophers_ours.md",
"dump_4_philosophers_mdgraphs.md",
),
(
"dump_6_dec-tree.hprof",
"dump_6_dec-tree_ours.md",
"dump_6_dec-tree_mdgraphs.md",
),
(
"dump_7_gauss-mix.hprof",
"dump_7_gauss-mix_ours.md",
"dump_7_gauss-mix_mdgraphs.md",
),
(
"dump_8_log-regression.hprof",
"dump_8_log-regression_ours.md",
"dump_8_log-regression_mdgraphs.md",
),
];
fn strip_views_line(s: &str) -> String {
s.lines()
.filter(|l| !l.contains("Generated by hprof-analyzer views"))
.collect::<Vec<_>>()
.join("\n")
}
#[test]
fn parity_all_fixtures() {
let dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures");
let regen = std::env::var("REGEN_FIXTURES").is_ok();
let mut failures = Vec::new();
let mut ran = 0usize;
let mut regenned = 0usize;
for (hprof, baseline_md, baseline_graphs) in FIXTURES {
let hprof_path = dir.join(hprof);
let present = std::fs::metadata(&hprof_path)
.map(|m| m.len() >= 1024)
.unwrap_or(false);
if !present {
eprintln!(
"skipping parity for {hprof}: dump missing at {}",
dir.display()
);
continue;
}
ran += 1;
let out = Command::new(env!("CARGO_BIN_EXE_hprof-analyzer"))
.arg(&hprof_path)
.output()
.unwrap_or_else(|e| panic!("failed to run analyzer on {hprof}: {e}"));
assert!(
out.status.success(),
"{hprof} (md) exited non-zero: {}",
String::from_utf8_lossy(&out.stderr)
);
let got = strip_views_line(&String::from_utf8_lossy(&out.stdout));
if regen {
std::fs::write(dir.join(baseline_md), got.as_bytes()).unwrap();
regenned += 1;
} else {
let want = strip_views_line(&std::fs::read_to_string(dir.join(baseline_md)).unwrap());
if got != want {
failures.push(format!("{hprof} (md)"));
}
}
let out = Command::new(env!("CARGO_BIN_EXE_hprof-analyzer"))
.arg(&hprof_path)
.args(["--format", "md-graphs"])
.output()
.unwrap_or_else(|e| panic!("failed to run analyzer on {hprof} (md-graphs): {e}"));
assert!(
out.status.success(),
"{hprof} (md-graphs) exited non-zero: {}",
String::from_utf8_lossy(&out.stderr)
);
let got = strip_views_line(&String::from_utf8_lossy(&out.stdout));
if regen {
std::fs::write(dir.join(baseline_graphs), got.as_bytes()).unwrap();
} else {
let want =
strip_views_line(&std::fs::read_to_string(dir.join(baseline_graphs)).unwrap());
if got != want {
failures.push(format!("{hprof} (md-graphs)"));
}
}
}
if regen {
eprintln!(
"parity: regenerated {regenned} of {ran} present fixtures ({} total)",
FIXTURES.len()
);
} else {
assert!(
failures.is_empty(),
"parity mismatch for: {failures:?}\n\nRegenerate with: REGEN_FIXTURES=1 cargo test --release parity"
);
eprintln!("parity: ran {ran} of {} fixtures", FIXTURES.len());
}
}