use fastrace::Span;
use ssb::{Bench, BenchReport};
fn phase1(n: u64) -> u64 {
let _s = Span::enter_with_local_parent("phase1");
(0..n).fold(0u64, |acc, x| acc.wrapping_add(x))
}
fn phase2(x: u64) -> u64 {
let _s = Span::enter_with_local_parent("phase2");
x.wrapping_mul(31)
}
fn compute(n: u64) -> u64 {
phase2(phase1(n))
}
#[test]
fn report_contains_expected_spans() {
let report = Bench::new("compute")
.no_auto_save()
.iterations(20)
.warmup(5)
.run(|| compute(1_000));
assert!(report.spans.contains_key("compute"), "missing total span");
assert!(report.spans.contains_key("phase1"), "missing phase1 span");
assert!(report.spans.contains_key("phase2"), "missing phase2 span");
let total_count = report.spans["compute"].count;
assert!(
total_count >= 20,
"expected at least 20 iterations, got {total_count}"
);
assert_eq!(report.spans["phase1"].count, total_count);
assert_eq!(report.spans["phase2"].count, total_count);
let total_mean = report.spans["compute"].mean_ns;
let phases_mean = report.spans["phase1"].mean_ns + report.spans["phase2"].mean_ns;
assert!(
total_mean >= phases_mean,
"total ({total_mean:.0} ns) < sum of phases ({phases_mean:.0} ns)"
);
}
#[test]
fn stats_are_ordered() {
let report = Bench::new("compute")
.no_auto_save()
.iterations(50)
.warmup(5)
.run(|| compute(500));
for (name, s) in &report.spans {
assert!(s.min_ns <= s.mean_ns as u64, "{name}: min > mean");
assert!(s.mean_ns <= s.max_ns as f64, "{name}: mean > max");
assert!(s.p95_ns <= s.max_ns as f64, "{name}: p95 > max");
}
}
#[test]
fn save_and_load_roundtrip() {
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("report.json");
let original = Bench::new("compute")
.no_auto_save()
.iterations(10)
.warmup(2)
.run(|| compute(100));
original.save(&path).unwrap();
let loaded = BenchReport::load(&path).unwrap();
assert_eq!(original.name, loaded.name);
assert_eq!(original.iterations, loaded.iterations);
assert_eq!(original.spans.len(), loaded.spans.len());
for (k, orig_stats) in &original.spans {
let loaded_stats = &loaded.spans[k];
assert_eq!(orig_stats.count, loaded_stats.count);
assert!((orig_stats.mean_ns - loaded_stats.mean_ns).abs() < 1.0);
}
}
#[test]
fn comparison_smoke_test() {
let baseline = Bench::new("compute")
.no_auto_save()
.iterations(10)
.warmup(2)
.run(|| compute(100));
let current = Bench::new("compute")
.no_auto_save()
.iterations(10)
.warmup(2)
.run(|| compute(100));
current.compare(&baseline).print();
}