use sbom_diff::Differ;
use sbom_model::{Component, ComponentId, Sbom};
use std::collections::BTreeSet;
use std::time::Instant;
fn make_sboms(n: usize) -> (Sbom, Sbom) {
let mut old = Sbom::default();
let mut new = Sbom::default();
for i in 0..n {
let name = format!("pkg-{i}");
let version = "1.0.0".to_string();
let ecosystem = "cargo".to_string();
let mut old_comp = Component::new(name.clone(), Some(version.clone()));
old_comp.ecosystem = Some(ecosystem.clone());
let old_id = old_comp.id.clone();
old.components.insert(old_id.clone(), old_comp);
let purl = format!("pkg:cargo/{name}@{version}");
let new_id = ComponentId::new(Some(&purl), &[]);
let mut new_comp = Component::new(name.clone(), Some(version.clone()));
new_comp.ecosystem = Some(ecosystem);
new_comp.purl = Some(purl);
new_comp.id = new_id.clone();
new.components.insert(new_id.clone(), new_comp);
let dep_name = format!("pkg-{}", (i + 1) % n);
let dep_version = "1.0.0".to_string();
let old_dep_id = Component::new(dep_name.clone(), Some(dep_version.clone())).id;
let new_dep_purl = format!("pkg:cargo/{dep_name}@{dep_version}");
let new_dep_id = ComponentId::new(Some(&new_dep_purl), &[]);
old.dependencies
.entry(old_id)
.or_insert_with(BTreeSet::new)
.insert(old_dep_id);
new.dependencies
.entry(new_id)
.or_insert_with(BTreeSet::new)
.insert(new_dep_id);
}
(old, new)
}
fn bench_diff(label: &str, n: usize, warmup: usize, iters: usize) {
let (old, new) = make_sboms(n);
for _ in 0..warmup {
let _ = Differ::diff(&old, &new, None);
}
let mut times = Vec::with_capacity(iters);
for _ in 0..iters {
let start = Instant::now();
let _ = Differ::diff(&old, &new, None);
times.push(start.elapsed());
}
times.sort();
let median = times[times.len() / 2];
let min = times[0];
let max = times[times.len() - 1];
let mean: f64 = times.iter().map(|t| t.as_secs_f64()).sum::<f64>() / iters as f64;
println!(
"{label} (n={n}): median={:.3}ms mean={:.3}ms min={:.3}ms max={:.3}ms ({iters} iters)",
median.as_secs_f64() * 1000.0,
mean * 1000.0,
min.as_secs_f64() * 1000.0,
max.as_secs_f64() * 1000.0,
);
}
#[test]
#[ignore]
fn benchmark_edge_diff_scaling() {
println!();
for &n in &[500, 1000, 2000, 5000, 10000] {
bench_diff("edge_diff", n, 1, 5);
}
}