mirror of
https://github.com/solaeus/nucleo.git
synced 2024-11-10 01:27:10 +00:00
79 lines
2.6 KiB
Rust
79 lines
2.6 KiB
Rust
|
#![no_main]
|
||
|
|
||
|
use fzf_oxide::{chars, Matcher, MatcherConfig, Utf32Str};
|
||
|
use libfuzzer_sys::arbitrary::Arbitrary;
|
||
|
use libfuzzer_sys::fuzz_target;
|
||
|
|
||
|
#[derive(Arbitrary, Debug)]
|
||
|
pub struct Input<'a> {
|
||
|
haystack: &'a str,
|
||
|
needle: &'a str,
|
||
|
ignore_case: bool,
|
||
|
normalize: bool,
|
||
|
}
|
||
|
|
||
|
fuzz_target!(|data: Input<'_>| {
|
||
|
let mut data = data;
|
||
|
let mut config = MatcherConfig::DEFAULT;
|
||
|
config.ignore_case = data.ignore_case;
|
||
|
config.normalize = data.normalize;
|
||
|
let mut matcher = Matcher::new(config);
|
||
|
let mut indices_optimal = Vec::new();
|
||
|
let mut indices_greedy = Vec::new();
|
||
|
let mut needle_buf = Vec::new();
|
||
|
let mut haystack_buf = Vec::new();
|
||
|
let normalize = |mut c: char| {
|
||
|
if config.normalize {
|
||
|
c = chars::normalize(c);
|
||
|
}
|
||
|
if config.ignore_case {
|
||
|
c = chars::to_lower_case(c);
|
||
|
}
|
||
|
c
|
||
|
};
|
||
|
let needle: String = data.needle.chars().map(normalize).collect();
|
||
|
let needle_chars: Vec<_> = needle.chars().collect();
|
||
|
let needle = Utf32Str::new(&needle, &mut needle_buf);
|
||
|
let haystack = Utf32Str::new(data.haystack, &mut haystack_buf);
|
||
|
|
||
|
let greedy_score = matcher.fuzzy_indices_greedy(haystack, needle, &mut indices_greedy);
|
||
|
if greedy_score.is_some() {
|
||
|
let match_chars: Vec<_> = indices_greedy
|
||
|
.iter()
|
||
|
.map(|&i| normalize(haystack.get(i)))
|
||
|
.collect();
|
||
|
assert_eq!(
|
||
|
match_chars, needle_chars,
|
||
|
"failed match, found {indices_greedy:?} {match_chars:?} (greedy)"
|
||
|
);
|
||
|
}
|
||
|
let optimal_score = matcher.fuzzy_indices(haystack, needle, &mut indices_optimal);
|
||
|
if optimal_score.is_some() {
|
||
|
let match_chars: Vec<_> = indices_optimal
|
||
|
.iter()
|
||
|
.map(|&i| normalize(haystack.get(i)))
|
||
|
.collect();
|
||
|
assert_eq!(
|
||
|
match_chars, needle_chars,
|
||
|
"failed match, found {indices_optimal:?} {match_chars:?}"
|
||
|
);
|
||
|
}
|
||
|
match (greedy_score, optimal_score) {
|
||
|
(None, Some(score)) => unreachable!("optimal matched {score} but greedy did not match"),
|
||
|
(Some(score), None) => unreachable!("greedy matched {score} but optimal did not match"),
|
||
|
(Some(greedy), Some(optimal)) => {
|
||
|
assert!(
|
||
|
greedy <= optimal,
|
||
|
"optimal score must be atleast the same as greedy score {greedy} {optimal}"
|
||
|
);
|
||
|
if indices_greedy == indices_optimal {
|
||
|
assert_eq!(
|
||
|
greedy, optimal,
|
||
|
"if matching same char greedy and optimal score should be identical"
|
||
|
)
|
||
|
}
|
||
|
}
|
||
|
(None, None) => (),
|
||
|
}
|
||
|
});
|