use crate::benchmark::BenchmarkRunner;
use super::BenchmarkArgs;
use anyhow::Result;
use colored::*;
pub fn run(args: &BenchmarkArgs) -> Result<()> {
eprintln!("{}", "⚡ Forge Guard — Benchmark".bold());
eprintln!(" Iterations: {}", args.iterations);
eprintln!(" Warmup: {}", args.warmup);
let mut runner = BenchmarkRunner::new(args.iterations, args.warmup);
let results = match &args.module {
Some(module) => vec![runner.benchmark_module(module)?],
None => runner.benchmark_all()?,
};
println!(
"\n{}",
"═══════════════════════════════════════".bright_blue()
);
println!(
"{}",
" BENCHMARK RESULTS "
.bright_blue()
.bold()
);
println!(
"{}",
"═══════════════════════════════════════".bright_blue()
);
for result in &results {
println!("\n 📊 {}:", result.name.bold());
println!(" Avg: {:.2}ms", result.avg_ms);
println!(" Min: {:.2}ms", result.min_ms);
println!(" Max: {:.2}ms", result.max_ms);
println!(" Median: {:.2}ms", result.median_ms);
println!(" P99: {:.2}ms", result.p99_ms);
println!(" Samples: {}", result.samples);
}
if let Some(save_path) = &args.save {
let json = serde_json::to_string_pretty(&results)?;
std::fs::write(save_path, json)?;
println!(
"\n{} Results saved to {}",
"💾".green(),
save_path.display()
);
}
if let Some(baseline_path) = &args.compare {
let baseline_content = std::fs::read_to_string(baseline_path)?;
let baseline: Vec<crate::benchmark::BenchmarkResult> =
serde_json::from_str(&baseline_content)?;
println!("\n{}", "── Comparison with Baseline ──".bold());
for result in &results {
if let Some(baseline) = baseline.iter().find(|b| b.name == result.name) {
let diff = result.avg_ms - baseline.avg_ms;
let pct = (diff / baseline.avg_ms) * 100.0;
if diff > 0.0 {
println!(
" {} {}: +{:.1}ms ({:+.1}%)",
"🔴".red(),
result.name,
diff,
pct
);
} else {
println!(
" {} {}: {:.1}ms ({:+.1}%)",
"🟢".green(),
result.name,
diff,
pct
);
}
}
}
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_benchmark_arg_defaults() {
let args = BenchmarkArgs {
shared: super::super::SharedFlags {
chain: "ethereum".into(),
project: std::path::PathBuf::from("."),
json: false,
markdown: false,
html: false,
strict: false,
offline: false,
production: false,
report: false,
parallelism: 4,
},
iterations: 10,
compare: None,
save: None,
module: None,
warmup: 3,
};
assert_eq!(args.iterations, 10);
assert_eq!(args.warmup, 3);
assert!(args.save.is_none());
assert!(args.compare.is_none());
assert!(args.module.is_none());
}
#[test]
fn test_benchmark_module_specified() {
let args = BenchmarkArgs {
shared: super::super::SharedFlags::default(),
iterations: 50,
compare: None,
save: Some(std::path::PathBuf::from("results.json")),
module: Some("pattern_matching".into()),
warmup: 5,
};
assert_eq!(args.iterations, 50);
assert_eq!(args.warmup, 5);
assert_eq!(args.module.as_deref(), Some("pattern_matching"));
assert!(args.save.is_some());
}
#[test]
fn test_benchmark_module_unknown_returns_error() {
let mut runner = crate::benchmark::BenchmarkRunner::new(3, 1);
let result = runner.benchmark_module("nonexistent_module");
assert!(result.is_err());
let err = result.unwrap_err();
assert!(err.to_string().contains("Unknown benchmark module"));
}
}