use super::*;
#[test]
fn phase_display_options_rel_threshold_override_branch_takes_precedence() {
let opts = PhaseDisplayOptions {
phase_threshold: Some(25.0), ..PhaseDisplayOptions::default()
};
let mut policy = ComparisonPolicy::default();
policy
.per_metric_percent
.insert("max_dsq_depth".into(), 99.0);
let resolved = opts.rel_threshold(&policy, "max_dsq_depth", 0.50);
assert_eq!(
resolved, 0.25,
"--phase-threshold 25 → 0.25 fraction regardless of policy override"
);
}
#[test]
fn phase_display_options_rel_threshold_falls_through_to_policy_when_unset() {
let opts = PhaseDisplayOptions::default(); let mut policy = ComparisonPolicy::default();
policy
.per_metric_percent
.insert("max_dsq_depth".into(), 30.0); let resolved = opts.rel_threshold(&policy, "max_dsq_depth", 0.50);
assert_eq!(
resolved, 0.30,
"absent --phase-threshold → policy.rel_threshold = 30% / 100 = 0.30"
);
}
#[test]
fn phase_display_options_rel_threshold_falls_through_to_registry_default() {
let opts = PhaseDisplayOptions::default();
let policy = ComparisonPolicy::default(); let resolved = opts.rel_threshold(&policy, "max_dsq_depth", 0.50);
assert_eq!(
resolved, 0.50,
"no flag, no policy → registry default_rel = 0.50"
);
}
#[test]
fn matches_phase_default_opts_pass_all_steps() {
let opts = PhaseDisplayOptions::default();
for step in [0u16, 1, 2, 7, 65535] {
assert!(
opts.matches_phase(step),
"default opts must match step_index = {step}"
);
}
}
#[test]
fn matches_phase_steps_only_suppresses_only_baseline() {
let opts = PhaseDisplayOptions {
steps_only: true,
..PhaseDisplayOptions::default()
};
assert!(
!opts.matches_phase(0),
"--steps-only: step_index = 0 (BASELINE) must be suppressed"
);
for step in [1u16, 2, 3, 7, 65535] {
assert!(
opts.matches_phase(step),
"--steps-only: step_index = {step} must NOT be suppressed"
);
}
}
#[test]
fn matches_phase_phase_filter_keeps_only_target_step() {
let opts = PhaseDisplayOptions {
phase: Some(2),
..PhaseDisplayOptions::default()
};
assert!(opts.matches_phase(2), "--phase 2 must keep step_index = 2");
for step in [0u16, 1, 3, 7, 65535] {
assert!(
!opts.matches_phase(step),
"--phase 2: step_index = {step} must be suppressed"
);
}
}
#[test]
fn matches_phase_phase_zero_keeps_only_baseline() {
let opts = PhaseDisplayOptions {
phase: Some(0),
..PhaseDisplayOptions::default()
};
assert!(opts.matches_phase(0), "--phase 0 must keep step_index = 0");
for step in [1u16, 2, 7, 65535] {
assert!(
!opts.matches_phase(step),
"--phase 0: step_index = {step} must be suppressed"
);
}
}
#[test]
fn format_average_header_exact_string() {
let out = format_average_header(5, 3, "kernel-6.14", "kernel-6.15");
assert_eq!(
out,
"averaged across 5 runs (kernel-6.14) and 3 runs (kernel-6.15)",
);
}
#[test]
fn format_average_header_zero_contributor_sides_render_verbatim() {
assert_eq!(
format_average_header(0, 0, "a", "b"),
"averaged across 0 runs (a) and 0 runs (b)",
);
}
fn group(
scenario: &str,
topology: &str,
work_type: &str,
passes_observed: u32,
total_observed: u32,
) -> AveragedGroup {
let mut row = make_row(scenario, topology, true, 0.0);
row.work_type = work_type.into();
AveragedGroup {
row,
passes_observed,
skips_observed: 0,
inconclusives_observed: 0,
failures_observed: 0,
total_observed,
}
}
fn group_with_breakdown(
scenario: &str,
topology: &str,
work_type: &str,
passes: u32,
skips: u32,
incs: u32,
fails: u32,
) -> AveragedGroup {
let mut row = make_row(scenario, topology, true, 0.0);
row.work_type = work_type.into();
AveragedGroup {
row,
passes_observed: passes,
skips_observed: skips,
inconclusives_observed: incs,
failures_observed: fails,
total_observed: passes + skips + incs + fails,
}
}
#[test]
fn format_per_group_pass_counts_renders_skip_inc_fail_breakdown() {
let g_a = group_with_breakdown("scn", "topo", "wt", 1, 1, 1, 1);
let g_b = group_with_breakdown("scn", "topo", "wt", 4, 0, 0, 0);
let out = format_per_group_pass_counts(&[g_a], &[g_b], "A", "B");
assert!(
out.contains("A=1/4 (1 skip, 1 inc, 1 fail)"),
"non-zero buckets must surface in the per-group breakdown for A: {out}"
);
assert!(
out.contains("B=4/4"),
"all-pass side must stay terse (no breakdown suffix): {out}"
);
assert!(
!out.contains("B=4/4 ("),
"B has zero non-pass buckets — must NOT append empty breakdown: {out}"
);
}
#[test]
fn format_per_group_pass_counts_empty_returns_empty_string() {
let out = format_per_group_pass_counts(&[], &[], "a", "b");
assert!(
out.is_empty(),
"empty input must yield empty output, got: {out:?}",
);
}
#[test]
fn format_per_group_pass_counts_renders_every_group_with_n_over_m() {
let avg_a = vec![
group("alpha", "tiny-1llc", "SpinWait", 5, 5),
group("beta", "tiny-1llc", "SpinWait", 3, 5),
];
let avg_b = vec![
group("alpha", "tiny-1llc", "SpinWait", 4, 5),
group("beta", "tiny-1llc", "SpinWait", 5, 5),
];
let out = format_per_group_pass_counts(&avg_a, &avg_b, "a", "b");
assert!(
out.contains("per-group pass counts"),
"header line must appear, got: {out:?}",
);
assert!(
out.contains("alpha/tiny-1llc/SpinWait: a=5/5 b=4/5"),
"alpha group line missing; got: {out:?}",
);
assert!(
out.contains("beta/tiny-1llc/SpinWait: a=3/5 b=5/5"),
"beta group line missing; got: {out:?}",
);
assert!(
out.ends_with('\n'),
"block must end with newline, got: {out:?}",
);
}
#[test]
fn format_per_group_pass_counts_one_side_missing_renders_dash() {
let avg_a = vec![group("only_a", "tiny-1llc", "SpinWait", 5, 5)];
let avg_b = vec![group("only_b", "tiny-1llc", "SpinWait", 3, 5)];
let out = format_per_group_pass_counts(&avg_a, &avg_b, "a", "b");
assert!(
out.contains("only_a/tiny-1llc/SpinWait: a=5/5 b=-"),
"A-only group must render b=-; got: {out:?}",
);
assert!(
out.contains("only_b/tiny-1llc/SpinWait: a=- b=3/5"),
"B-only group must render a=-; got: {out:?}",
);
}
#[test]
fn compare_partition_as_str_maps_each_variant_to_its_letter() {
assert_eq!(ComparePartition::A.as_str(), "A");
assert_eq!(ComparePartition::B.as_str(), "B");
}