Skip to main content

max / docengine

1.7 KB · 45 lines History Blame Raw
1 //! Replay every input the fuzzer has ever found, on stable, in CI.
2 //!
3 //! A crash found by `cargo fuzz` becomes a permanent test by copying one file
4 //! into `fuzz/regressions/`. Nothing else is needed: this walks the directory
5 //! and runs the same `docengine::oracle::check` the fuzz target runs, so the two
6 //! cannot drift into checking different things.
7 //!
8 //! An empty directory is a passing run and says so. That is not the same as no
9 //! coverage -- the soak tier is where the searching happens -- but a silently
10 //! empty replay would look identical to a replay that ran, which is the failure
11 //! this note exists to prevent.
12
13 use std::fs;
14 use std::path::Path;
15
16 #[test]
17 fn every_fuzz_regression_still_passes() {
18 let dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("fuzz/regressions");
19 let Ok(entries) = fs::read_dir(&dir) else {
20 // Not a failure: a checkout without the directory is a checkout with no
21 // regressions yet.
22 println!("no regressions directory at {}", dir.display());
23 return;
24 };
25
26 let mut checked = 0usize;
27 for entry in entries {
28 let path = entry.expect("reading a regression entry").path();
29 if !path.is_file() {
30 continue;
31 }
32 // Lossy on purpose. The corpus is bytes the fuzzer produced, and one
33 // that is not valid UTF-8 is still worth replaying through the same
34 // conversion the target's `&str` input performs.
35 let input =
36 String::from_utf8_lossy(&fs::read(&path).expect("reading a regression")).into_owned();
37 docengine::oracle::check(&input);
38 checked += 1;
39 }
40 println!(
41 "replayed {checked} fuzz regression(s) from {}",
42 dir.display()
43 );
44 }
45