fuzz/tests/seeds.rs
//! **Every fuzz target takes its committed seeds without a panic, on plain stable cargo**
//! (lane OSSF-NEXT). The nightly fuzz run on the dwarves forge starts from the same
//! corpus; this test is the per-push floor under it, and it keeps the corpus current:
//! the synthetic seeds (`holger_fuzz::seeds::synthetic`) must be committed byte for byte
//! (`HOLGER_FUZZ_WRITE_SEEDS=1 cargo test` writes them).
use std::collections::BTreeSet;
use std::path::PathBuf;
fn fuzz_dir() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
}
#[test]
fn every_target_is_a_bin_of_the_cargo_fuzz_layout() {
let manifest = std::fs::read_to_string(fuzz_dir().join("Cargo.toml")).unwrap();
assert!(
manifest.contains("cargo-fuzz = true"),
"the cargo-fuzz layout marks its package"
);
let bins: BTreeSet<String> = manifest
.split("\n[[bin]]\n")
.skip(1)
.filter_map(|b| {
b.lines()
.find_map(|l| l.trim().strip_prefix("name = \""))
.map(|n| n.trim_end_matches('"').to_owned())
})
.collect();
let targets: BTreeSet<String> = holger_fuzz::TARGETS.iter().map(|t| t.to_string()).collect();
assert_eq!(bins, targets, "one [[bin]] per target");
for t in holger_fuzz::TARGETS {
let src = std::fs::read_to_string(fuzz_dir().join(format!("fuzz_targets/{t}.rs"))).unwrap();
assert!(
src.contains("fuzz_target!") && src.contains(&format!("holger_fuzz::run(\"{t}\"")),
"{t}.rs runs its own entry"
);
}
}
#[test]
fn the_synthetic_seeds_are_committed() {
let write = std::env::var("HOLGER_FUZZ_WRITE_SEEDS").as_deref() == Ok("1");
let mut stale = Vec::new();
for (target, name, bytes) in holger_fuzz::seeds::synthetic() {
assert!(holger_fuzz::TARGETS.contains(&target), "{target}");
let p = fuzz_dir().join("corpus").join(target).join(&name);
if write {
std::fs::create_dir_all(p.parent().unwrap()).unwrap();
std::fs::write(&p, &bytes).unwrap();
} else if std::fs::read(&p).ok().as_deref() != Some(&bytes[..]) {
stale.push(p.display().to_string());
}
}
assert!(
stale.is_empty(),
"seeds not committed (HOLGER_FUZZ_WRITE_SEEDS=1 cargo test writes them):\n {}",
stale.join("\n ")
);
}
#[test]
fn every_committed_seed_runs_through_its_target() {
for t in holger_fuzz::TARGETS {
let dir = fuzz_dir().join("corpus").join(t);
let mut seen = 0;
let mut files: Vec<PathBuf> = std::fs::read_dir(&dir)
.unwrap_or_else(|e| panic!("{}: {e}", dir.display()))
.map(|e| e.unwrap().path())
.collect();
files.sort();
for f in files {
holger_fuzz::run(t, &std::fs::read(&f).unwrap());
seen += 1;
}
assert!(seen > 0, "{t} has seeds in {}", dir.display());
}
}
/// The edges every target must survive: nothing, one byte, a lot of one byte.
#[test]
fn every_target_survives_the_degenerate_inputs() {
for t in holger_fuzz::TARGETS {
for input in [&b""[..], b"\0", b"\xff", &[0u8; 4096], &[b'{'; 1024]] {
holger_fuzz::run(t, input);
}
}
}