Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/monetize

fuzz/tests/seeds.rs

//! **The committed seeds stay valid**, on a plain stable `cargo test` (no libFuzzer, no
//! instrumentation): `cargo test --manifest-path fuzz/Cargo.toml --no-default-features`.
//!
//! Every file in `corpus/<target>/` is run through the target's entry function (a panic
//! fails the test), and every `ok-*` seed must be ACCEPTED: a seed that no longer verifies or
//! parses starts the fuzzer at the shallow end, which is a silent loss of coverage.
//!
//! `write_seeds` (ignored) regenerates the seeds from the throwaway keys in `src/lib.rs`:
//! `cargo test ... -- --ignored write_seeds`.

use std::path::{Path, PathBuf};

type Entry = fn(&[u8]) -> bool;

const TARGETS: &[(&str, Entry)] = &[
    ("pay_callback", monetize_fuzz::pay_callback),
    ("feed_config", monetize_fuzz::feed_config),
    ("signed_facts", monetize_fuzz::signed_facts),
    ("fleet_door", monetize_fuzz::fleet_door),
    ("fleet_orders", monetize_fuzz::fleet_orders),
];

fn corpus(target: &str) -> PathBuf {
    Path::new(env!("CARGO_MANIFEST_DIR"))
        .join("corpus")
        .join(target)
}

#[test]
fn every_target_has_a_bin_and_accepted_seeds() {
    let manifest =
        std::fs::read_to_string(Path::new(env!("CARGO_MANIFEST_DIR")).join("Cargo.toml")).unwrap();
    let mut wrong = Vec::new();
    for (target, entry) in TARGETS {
        if !manifest.contains(&format!("path = \"fuzz_targets/{target}.rs\"")) {
            wrong.push(format!("{target}: no [[bin]] in fuzz/Cargo.toml"));
        }
        let Ok(dir) = std::fs::read_dir(corpus(target)) else {
            wrong.push(format!("{target}: no corpus/{target}/"));
            continue;
        };
        let mut ok_seeds = 0;
        for file in dir.flatten() {
            let name = file.file_name().to_string_lossy().to_string();
            let bytes = std::fs::read(file.path()).unwrap();
            let accepted = entry(&bytes);
            if name.starts_with("ok-") {
                ok_seeds += 1;
                if !accepted {
                    wrong.push(format!("{target}: seed {name} is not accepted"));
                }
            } else if name.starts_with("refused-") && accepted {
                wrong.push(format!(
                    "{target}: seed {name} is accepted, but it is a refusal"
                ));
            }
        }
        if ok_seeds == 0 {
            wrong.push(format!(
                "{target}: no ok-* seed, so nothing proves the parser's deep end is reached"
            ));
        }
    }
    assert!(
        wrong.is_empty(),
        "the fuzz corpus is not what the targets need:\n  {}",
        wrong.join("\n  ")
    );
}

/// The committed seeds are the ones `src/lib.rs` makes: a seed edited by hand, or a key or
/// a wire format that moved without the seeds, fails here by name.
#[test]
fn the_committed_seeds_are_the_generated_ones() {
    let mut wrong = Vec::new();
    for (target, name, bytes) in monetize_fuzz::seeds() {
        match std::fs::read(corpus(target).join(&name)) {
            Ok(on_disk) if on_disk == bytes => {}
            Ok(_) => wrong.push(format!(
                "{target}/{name}: differs from seeds() (run write_seeds)"
            )),
            Err(_) => wrong.push(format!("{target}/{name}: missing (run write_seeds)")),
        }
    }
    assert!(wrong.is_empty(), "{}", wrong.join("\n"));
}

#[test]
#[ignore]
fn write_seeds() {
    for (target, name, bytes) in monetize_fuzz::seeds() {
        std::fs::create_dir_all(corpus(target)).unwrap();
        std::fs::write(corpus(target).join(name), bytes).unwrap();
    }
}