diff --git a/fuzz/.gitignore b/fuzz/.gitignore new file mode 100644 index 0000000..a092511 --- /dev/null +++ b/fuzz/.gitignore @@ -0,0 +1,3 @@ +target +corpus +artifacts diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml new file mode 100644 index 0000000..3824e13 --- /dev/null +++ b/fuzz/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "norm-fuzz" +version = "0.0.0" +authors = ["Automatically generated"] +publish = false +edition = "2021" + +[package.metadata] +cargo-fuzz = true + +[dependencies] +norm = { path = "..", features = ["fzf-v1", "fzf-v2"] } +libfuzzer-sys = { version = "0.4", features = ["arbitrary-derive"] } + +# Prevent this from interfering with workspaces +[workspace] +members = ["."] + +[[bin]] +name = "fzf" +path = "fuzz_targets/fzf.rs" +test = false +doc = false diff --git a/fuzz/fuzz_targets/fzf.rs b/fuzz/fuzz_targets/fzf.rs new file mode 100644 index 0000000..666fbf1 --- /dev/null +++ b/fuzz/fuzz_targets/fzf.rs @@ -0,0 +1,67 @@ +#![no_main] + +use libfuzzer_sys::arbitrary::{self, Arbitrary}; +use libfuzzer_sys::fuzz_target; +use norm::fzf::{FzfParser, FzfScheme, FzfV1, FzfV2}; +use norm::{CaseSensitivity, Metric}; + +#[derive(Arbitrary, Copy, Clone, Debug)] +struct Query<'a>(&'a str); + +#[derive(Arbitrary, Clone, Debug)] +struct Candidate<'a>(&'a str); + +fn with_opts(mut fun: F) +where + F: FnMut(CaseSensitivity, bool, FzfScheme), +{ + for case_sensitivity in [ + CaseSensitivity::Sensitive, + CaseSensitivity::Insensitive, + CaseSensitivity::Smart, + ] { + for normalization in [true, false] { + for scheme in + [FzfScheme::Default, FzfScheme::Path, FzfScheme::History] + { + fun(case_sensitivity, normalization, scheme) + } + } + } +} + +fuzz_target!(|data: (Query, Candidate)| { + let (Query(query), Candidate(candidate)) = data; + + let mut parser = FzfParser::new(); + + let query = parser.parse(query); + + let mut fzf_v1 = FzfV1::new(); + + let mut fzf_v2 = FzfV2::new(); + + with_opts(|case_sensitivity, normalization, scheme| { + fzf_v1 = core::mem::take(&mut fzf_v1) + .with_case_sensitivity(case_sensitivity) + .with_normalization(normalization) + .with_scoring_scheme(scheme); + + if let Some(mach) = fzf_v1.distance(query, candidate) { + for range in mach.matched_ranges() { + let _s = &candidate[range.clone()]; + } + } + + fzf_v2 = core::mem::take(&mut fzf_v2) + .with_case_sensitivity(case_sensitivity) + .with_normalization(normalization) + .with_scoring_scheme(scheme); + + if let Some(mach) = fzf_v2.distance(query, candidate) { + for range in mach.matched_ranges() { + let _s = &candidate[range.clone()]; + } + } + }); +});