use aatxe_core::report::{format_ns, STICKY_MARKER};
use aatxe_core::types::{
AffectedScope, BenchRun, CompareReport, CompareSide, CompareSummary, Language, NeutralReason,
Verdict,
};
use aatxe_core::{render_markdown, types::BenchDiff};
fn run(name: &str) -> BenchRun {
BenchRun {
name: name.to_string(),
file: format!("{}.rs", name),
iterations: 50,
batch_size: 1,
elapsed_ns: 5000.0,
samples: (0..50).map(|i| 100.0 + i as f64).collect(),
mean: 124.5,
median: 124.5,
trimmed_mean: 124.5,
stddev: 14.5,
cv: 0.116,
mad: 12.0,
iqr: 24.0,
min: 100.0,
max: 149.0,
p50: 124.5,
p95: 146.0,
p99: 148.0,
metrics: Vec::new(),
tags: Vec::new(),
}
}
fn mk_cmp(diffs: Vec<BenchDiff>) -> CompareReport {
let mut summary = CompareSummary::default();
for d in &diffs {
match d.verdict {
Verdict::Regression => summary.regressions += 1,
Verdict::Improvement => summary.improvements += 1,
Verdict::Neutral => summary.neutrals += 1,
Verdict::New => summary.new += 1,
Verdict::Removed => summary.removed += 1,
Verdict::OutOfScope => summary.out_of_scope += 1,
}
}
CompareReport {
base: CompareSide {
r#ref: "abcdef0123".to_string(),
service: "svc".to_string(),
},
head: CompareSide {
r#ref: "fedcba9876".to_string(),
service: "svc".to_string(),
},
language: Language::Rust,
threshold_pct: 0.05,
alpha: 0.05,
noisy_cv_threshold: 0.25,
diffs,
summary,
affected_scope: None,
}
}
#[test]
fn starts_with_sticky_marker() {
let cmp = mk_cmp(vec![]);
let md = render_markdown(&cmp);
let first_line = md.lines().next().unwrap();
assert_eq!(first_line, STICKY_MARKER);
}
#[test]
fn no_diffs_renders_clean_headline() {
let cmp = mk_cmp(vec![]);
let md = render_markdown(&cmp);
assert!(md.contains("Performance · no significant changes"));
assert!(md.contains("Methodology"));
}
#[test]
fn regression_count_in_headline() {
let diff = BenchDiff {
name: "a".into(),
base: Some(run("a")),
head: Some(run("a")),
delta_pct: Some(0.30),
mean_delta_pct: Some(0.30),
p_value: Some(1e-6),
p_value_welch: Some(1e-6),
max_cv: Some(0.1),
verdict: Verdict::Regression,
neutral_reason: None,
};
let cmp = mk_cmp(vec![diff]);
let md = render_markdown(&cmp);
assert!(md.contains("Performance · 1 regression"));
assert!(md.contains("Significant changes"));
assert!(md.contains("🔴 Regression"));
assert!(md.contains("`a`"));
}
#[test]
fn out_of_scope_renders_under_dedicated_section() {
let diff = BenchDiff {
name: "skipped-bench".into(),
base: Some(run("skipped-bench")),
head: None,
delta_pct: None,
mean_delta_pct: None,
p_value: None,
p_value_welch: None,
max_cv: None,
verdict: Verdict::OutOfScope,
neutral_reason: None,
};
let cmp = mk_cmp(vec![diff]);
let md = render_markdown(&cmp);
assert!(md.contains("Out of scope"));
assert!(md.contains("counted as regressions"));
assert!(md.contains("skipped-bench"));
}
#[test]
fn noisy_neutral_is_called_out() {
let diff = BenchDiff {
name: "a".into(),
base: Some(run("a")),
head: Some(run("a")),
delta_pct: Some(0.04),
mean_delta_pct: Some(0.04),
p_value: Some(0.4),
p_value_welch: Some(0.4),
max_cv: Some(0.5),
verdict: Verdict::Neutral,
neutral_reason: Some(NeutralReason::TooNoisy),
};
let cmp = mk_cmp(vec![diff]);
let md = render_markdown(&cmp);
assert!(
md.contains("noise-gated"),
"missing 'noise-gated' callout: {md}"
);
assert!(md.contains("🟡 Noisy"));
}
#[test]
fn format_ns_picks_units() {
assert_eq!(format_ns(500.0), "500ns");
assert_eq!(format_ns(1_500.0), "1.50µs");
assert_eq!(format_ns(2_500_000.0), "2.50ms");
assert_eq!(format_ns(3_000_000_000.0), "3.00s");
}
#[test]
fn language_label_appears_in_header() {
let cmp = mk_cmp(vec![]);
let md = render_markdown(&cmp);
assert!(md.contains("(Rust)"), "language label missing: {md}");
}
#[test]
fn improvement_only_run_gets_its_own_headline() {
let diff = BenchDiff {
name: "fast".into(),
base: Some(run("fast")),
head: Some(run("fast")),
delta_pct: Some(-0.30),
mean_delta_pct: Some(-0.30),
p_value: Some(1e-6),
p_value_welch: Some(1e-6),
max_cv: Some(0.1),
verdict: Verdict::Improvement,
neutral_reason: None,
};
let cmp = mk_cmp(vec![diff]);
let md = render_markdown(&cmp);
assert!(md.contains("1 improvement"));
assert!(md.contains("🟢 Improvement"));
assert!(!md.contains("🔴 Regression"));
assert!(!md.contains("Performance · 1 regression"));
}
#[test]
fn pipe_character_in_bench_name_is_escaped() {
let mut b = run("legacy");
b.name = "parser | edge case".into();
let diff = BenchDiff {
name: b.name.clone(),
base: Some(b.clone()),
head: Some(b),
delta_pct: Some(0.30),
mean_delta_pct: Some(0.30),
p_value: Some(1e-6),
p_value_welch: Some(1e-6),
max_cv: Some(0.1),
verdict: Verdict::Regression,
neutral_reason: None,
};
let cmp = mk_cmp(vec![diff]);
let md = render_markdown(&cmp);
assert!(md.contains("parser \\| edge case"));
let table_line = md
.lines()
.find(|l| l.contains("Regression"))
.expect("regression row");
assert!(
!table_line.contains("parser | edge case"),
"row contains an un-escaped pipe: {table_line}"
);
}
#[test]
fn affected_scope_header_is_rendered() {
let mut cmp = mk_cmp(vec![]);
cmp.affected_scope = Some(AffectedScope {
base: "origin/master".into(),
changed_files: vec!["src/a.ts".into(), "src/b.ts".into()],
bench_files: vec!["a.bench.ts".into()],
skipped_bench_files: vec!["b.bench.ts".into(), "c.bench.ts".into()],
});
let md = render_markdown(&cmp);
assert!(md.contains("Affected-scope run vs `origin/master`"));
assert!(md.contains("ran 1 of 3 bench file(s)"));
assert!(md.contains("2 file(s) changed"));
assert!(md.contains("2 bench file(s) skipped"));
}
#[test]
fn inventory_section_renders_only_new_when_no_removed() {
let diff = BenchDiff {
name: "fresh".into(),
base: None,
head: Some(run("fresh")),
delta_pct: None,
mean_delta_pct: None,
p_value: None,
p_value_welch: None,
max_cv: None,
verdict: Verdict::New,
neutral_reason: None,
};
let cmp = mk_cmp(vec![diff]);
let md = render_markdown(&cmp);
assert!(md.contains("**New (1):**"));
assert!(
!md.contains("**Removed"),
"should not render an empty Removed section"
);
}
#[test]
fn inventory_section_renders_only_removed_when_no_new() {
let diff = BenchDiff {
name: "ghost".into(),
base: Some(run("ghost")),
head: None,
delta_pct: None,
mean_delta_pct: None,
p_value: None,
p_value_welch: None,
max_cv: None,
verdict: Verdict::Removed,
neutral_reason: None,
};
let cmp = mk_cmp(vec![diff]);
let md = render_markdown(&cmp);
assert!(md.contains("**Removed (1):**"));
assert!(
!md.contains("**New"),
"should not render an empty New section"
);
}
#[test]
fn very_long_bench_name_does_not_break_table() {
let long = "a-really-very-extremely-quite-rather-long-bench-name-".repeat(8);
let mut b = run("x");
b.name = long.clone();
let diff = BenchDiff {
name: long.clone(),
base: Some(b.clone()),
head: Some(b),
delta_pct: Some(0.30),
mean_delta_pct: Some(0.30),
p_value: Some(1e-6),
p_value_welch: Some(1e-6),
max_cv: Some(0.1),
verdict: Verdict::Regression,
neutral_reason: None,
};
let cmp = mk_cmp(vec![diff]);
let md = render_markdown(&cmp);
let row = md
.lines()
.find(|l| l.contains("Regression"))
.expect("regression row");
assert_eq!(row.matches('|').count(), 9, "row: {row}");
assert!(row.contains(&long));
}
#[test]
fn noisy_callout_uses_plural_form_when_multiple() {
let mk_neutral = |name: &str| BenchDiff {
name: name.into(),
base: Some(run(name)),
head: Some(run(name)),
delta_pct: Some(0.04),
mean_delta_pct: Some(0.04),
p_value: Some(0.4),
p_value_welch: Some(0.4),
max_cv: Some(0.5),
verdict: Verdict::Neutral,
neutral_reason: Some(NeutralReason::TooNoisy),
};
let cmp = mk_cmp(vec![mk_neutral("a"), mk_neutral("b")]);
let md = render_markdown(&cmp);
assert!(md.contains("2 benches had CV"), "missing plural form: {md}");
}
#[test]
fn format_ns_handles_non_finite() {
assert_eq!(format_ns(f64::NAN), "—");
assert_eq!(format_ns(f64::INFINITY), "—");
}