forge_guard/fuzzing/
mod.rs1use crate::core::ForgeGuardError;
4
5pub struct FuzzingConfig {
7 pub runs: u32,
9 pub seed: Option<u64>,
11 pub test_filter: Option<String>,
13 pub contract_filter: Option<String>,
15 pub fail_on_revert: bool,
17}
18
19impl Default for FuzzingConfig {
20 fn default() -> Self {
21 Self {
22 runs: 10_000,
23 seed: None,
24 test_filter: None,
25 contract_filter: None,
26 fail_on_revert: false,
27 }
28 }
29}
30
31pub struct FuzzingAdapter;
33
34impl FuzzingAdapter {
35 pub fn run_forge_fuzz(config: &FuzzingConfig) -> Result<FuzzingReport, ForgeGuardError> {
37 let mut cmd = std::process::Command::new("forge");
38 cmd.arg("test");
39 cmd.arg("--fuzz-runs").arg(config.runs.to_string());
40
41 if let Some(seed) = config.seed {
42 cmd.arg("--fuzz-seed").arg(seed.to_string());
43 }
44
45 if let Some(test) = &config.test_filter {
46 cmd.arg("--match-test").arg(test);
47 }
48
49 if let Some(contract) = &config.contract_filter {
50 cmd.arg("--match-contract").arg(contract);
51 }
52
53 if config.fail_on_revert {
54 cmd.arg("--fail-on-revert");
55 }
56
57 let start = std::time::Instant::now();
58 let output = cmd
59 .output()
60 .map_err(|e| ForgeGuardError::Command(format!("Failed to run fuzz: {}", e)))?;
61
62 let duration = start.elapsed();
63
64 Ok(FuzzingReport {
65 passed: output.status.success(),
66 runs: config.runs,
67 duration_secs: duration.as_secs_f64(),
68 output: String::from_utf8_lossy(&output.stdout).to_string(),
69 errors: if output.status.success() {
70 String::new()
71 } else {
72 String::from_utf8_lossy(&output.stderr).to_string()
73 },
74 })
75 }
76}
77
78#[derive(Debug, Clone)]
80pub struct FuzzingReport {
81 pub passed: bool,
82 pub runs: u32,
83 pub duration_secs: f64,
84 pub output: String,
85 pub errors: String,
86}