aboutsummaryrefslogtreecommitdiffstats
path: root/matcher/src/tests.rs
diff options
context:
space:
mode:
Diffstat (limited to 'matcher/src/tests.rs')
-rw-r--r--matcher/src/tests.rs771
1 files changed, 0 insertions, 771 deletions
diff --git a/matcher/src/tests.rs b/matcher/src/tests.rs
deleted file mode 100644
index 32a02403..00000000
--- a/matcher/src/tests.rs
+++ /dev/null
@@ -1,771 +0,0 @@
-use crate::chars::Char;
-use crate::pattern::{CaseMatching, Normalization, Pattern};
-use crate::score::{
- BONUS_BOUNDARY, BONUS_CAMEL123, BONUS_CONSECUTIVE, BONUS_FIRST_CHAR_MULTIPLIER, BONUS_NON_WORD,
- MAX_PREFIX_BONUS, PENALTY_GAP_EXTENSION, PENALTY_GAP_START, SCORE_MATCH,
-};
-use crate::utf32_str::Utf32Str;
-use crate::{Config, Matcher};
-
-use Algorithm::*;
-
-#[derive(Debug)]
-enum Algorithm {
- FuzzyOptimal,
- FuzzyGreedy,
- Substring,
- Prefix,
- Postfix,
- Exact,
-}
-
-fn assert_matches(
- algorithm: &[Algorithm],
- normalize: bool,
- case_sensitive: bool,
- path: bool,
- prefer_prefix: bool,
- cases: &[(&str, &str, &[u32], u16)],
-) {
- let mut config = Config {
- normalize,
- ignore_case: !case_sensitive,
- prefer_prefix,
- ..Config::DEFAULT
- };
- if path {
- config.set_match_paths();
- }
- let mut matcher = Matcher::new(config);
- let mut matched_indices = Vec::new();
- let mut needle_buf = Vec::new();
- let mut haystack_buf = Vec::new();
- for &(haystack, needle, indices, mut score) in cases {
- let needle = if !case_sensitive {
- needle.to_lowercase()
- } else {
- needle.to_owned()
- };
- let needle = Utf32Str::new(&needle, &mut needle_buf);
- let haystack = Utf32Str::new(haystack, &mut haystack_buf);
- score += needle.len() as u16 * SCORE_MATCH;
- for algo in algorithm {
- println!("xx {matched_indices:?} {algo:?}");
- matched_indices.clear();
- let res = match algo {
- FuzzyOptimal => matcher.fuzzy_indices(haystack, needle, &mut matched_indices),
- FuzzyGreedy => matcher.fuzzy_indices_greedy(haystack, needle, &mut matched_indices),
- Substring => matcher.substring_indices(haystack, needle, &mut matched_indices),
- Prefix => matcher.prefix_indices(haystack, needle, &mut matched_indices),
- Postfix => matcher.postfix_indices(haystack, needle, &mut matched_indices),
- Exact => matcher.exact_indices(haystack, needle, &mut matched_indices),
- };
- println!("{matched_indices:?}");
- let match_chars: Vec<_> = matched_indices
- .iter()
- .map(|&i| haystack.get(i).normalize(&matcher.config))
- .collect();
- let needle_chars: Vec<_> = needle.chars().collect();
-
- assert_eq!(
- res,
- Some(score),
- "{needle:?} did not match {haystack:?}: matched {match_chars:?} {matched_indices:?} {algo:?}"
- );
- assert_eq!(
- matched_indices, indices,
- "{needle:?} match {haystack:?} {algo:?}"
- );
- assert_eq!(
- match_chars, needle_chars,
- "{needle:?} match {haystack:?} indices are incorrect {matched_indices:?} {algo:?}"
- );
- }
- }
-}
-
-fn assert_not_matches_with(
- normalize: bool,
- case_sensitive: bool,
- algorithm: &[Algorithm],
- cases: &[(&str, &str)],
-) {
- let config = Config {
- normalize,
- ignore_case: !case_sensitive,
- ..Config::DEFAULT
- };
- let mut matcher = Matcher::new(config);
- let mut needle_buf = Vec::new();
- let mut haystack_buf = Vec::new();
- for &(haystack, needle) in cases {
- let needle = if !case_sensitive {
- needle.to_lowercase()
- } else {
- needle.to_owned()
- };
- let needle = Utf32Str::new(&needle, &mut needle_buf);
- let haystack = Utf32Str::new(haystack, &mut haystack_buf);
-
- for algo in algorithm {
- let res = match algo {
- FuzzyOptimal => matcher.fuzzy_match(haystack, needle),
- FuzzyGreedy => matcher.fuzzy_match_greedy(haystack, needle),
- Substring => matcher.substring_match(haystack, needle),
- Prefix => matcher.prefix_match(haystack, needle),
- Postfix => matcher.postfix_match(haystack, needle),
- Exact => matcher.exact_match(haystack, needle),
- };
- assert_eq!(
- res, None,
- "{needle:?} should not match {haystack:?} {algo:?}"
- );
- }
- }
-}
-
-pub fn assert_not_matches(normalize: bool, case_sensitive: bool, cases: &[(&str, &str)]) {
- assert_not_matches_with(
- normalize,
- case_sensitive,
- &[FuzzyOptimal, FuzzyGreedy, Substring, Prefix, Postfix, Exact],
- cases,
- )
-}
-
-const BONUS_BOUNDARY_WHITE: u16 = Config::DEFAULT.bonus_boundary_white;
-const BONUS_BOUNDARY_DELIMITER: u16 = Config::DEFAULT.bonus_boundary_delimiter;
-
-#[test]
-fn test_fuzzy() {
- assert_matches(
- &[FuzzyGreedy, FuzzyOptimal],
- false,
- false,
- false,
- false,
- &[
- (
- "fooBarbaz1",
- "obr",
- &[2, 3, 5],
- BONUS_CAMEL123 - PENALTY_GAP_START,
- ),
- (
- "/usr/share/doc/at/ChangeLog",
- "changelog",
- &[18, 19, 20, 21, 22, 23, 24, 25, 26],
- (BONUS_FIRST_CHAR_MULTIPLIER + 8) * BONUS_BOUNDARY_DELIMITER,
- ),
- (
- "fooBarbaz1",
- "br",
- &[3, 5],
- BONUS_CAMEL123 * BONUS_FIRST_CHAR_MULTIPLIER - PENALTY_GAP_START,
- ),
- (
- "foo bar baz",
- "fbb",
- &[0, 4, 8],
- BONUS_BOUNDARY_WHITE * BONUS_FIRST_CHAR_MULTIPLIER + BONUS_BOUNDARY_WHITE * 2
- - 2 * PENALTY_GAP_START
- - 4 * PENALTY_GAP_EXTENSION,
- ),
- (
- "/AutomatorDocument.icns",
- "rdoc",
- &[9, 10, 11, 12],
- BONUS_CAMEL123 + 2 * BONUS_CONSECUTIVE,
- ),
- (
- "/man1/zshcompctl.1",
- "zshc",
- &[6, 7, 8, 9],
- BONUS_BOUNDARY_DELIMITER * (BONUS_FIRST_CHAR_MULTIPLIER + 3),
- ),
- (
- "/.oh-my-zsh/cache",
- "zshc",
- &[8, 9, 10, 12],
- BONUS_BOUNDARY * (BONUS_FIRST_CHAR_MULTIPLIER + 2) - PENALTY_GAP_START
- + BONUS_BOUNDARY_DELIMITER,
- ),
- (
- "ab0123 456",
- "12356",
- &[3, 4, 5, 8, 9],
- BONUS_CONSECUTIVE * 3 - PENALTY_GAP_START - PENALTY_GAP_EXTENSION,
- ),
- (
- "abc123 456",
- "12356",
- &[3, 4, 5, 8, 9],
- BONUS_CAMEL123 * (BONUS_FIRST_CHAR_MULTIPLIER + 2)
- - PENALTY_GAP_START
- - PENALTY_GAP_EXTENSION
- + BONUS_CONSECUTIVE,
- ),
- (
- "foo/bar/baz",
- "fbb",
- &[0, 4, 8],
- BONUS_BOUNDARY_WHITE * BONUS_FIRST_CHAR_MULTIPLIER + BONUS_BOUNDARY_DELIMITER * 2
- - 2 * PENALTY_GAP_START
- - 4 * PENALTY_GAP_EXTENSION,
- ),
- (
- "fooBarBaz",
- "fbb",
- &[0, 3, 6],
- BONUS_BOUNDARY_WHITE * BONUS_FIRST_CHAR_MULTIPLIER + BONUS_CAMEL123 * 2
- - 2 * PENALTY_GAP_START
- - 2 * PENALTY_GAP_EXTENSION,
- ),
- (
- "foo barbaz",
- "fbb",
- &[0, 4, 7],
- BONUS_BOUNDARY_WHITE * BONUS_FIRST_CHAR_MULTIPLIER + BONUS_BOUNDARY_WHITE
- - PENALTY_GAP_START * 2
- - PENALTY_GAP_EXTENSION * 3,
- ),
- (
- "fooBar Baz",
- "foob",
- &[0, 1, 2, 3],
- BONUS_BOUNDARY_WHITE * (BONUS_FIRST_CHAR_MULTIPLIER + 3),
- ),
- (
- "xFoo-Bar Baz",
- "foo-b",
- &[1, 2, 3, 4, 5],
- BONUS_CAMEL123 * (BONUS_FIRST_CHAR_MULTIPLIER + 2) + 2 * BONUS_NON_WORD,
- ),
- ],
- );
-}
-
-#[test]
-fn empty_needle() {
- assert_matches(
- &[Substring, Prefix, Postfix, FuzzyGreedy, FuzzyOptimal, Exact],
- false,
- false,
- false,
- false,
- &[("foo bar baz", "", &[], 0)],
- );
-}
-
-#[test]
-fn test_substring() {
- assert_matches(
- &[Substring, Prefix],
- false,
- false,
- false,
- false,
- &[
- (
- "foo bar baz",
- "foo",
- &[0, 1, 2],
- BONUS_BOUNDARY_WHITE * (BONUS_FIRST_CHAR_MULTIPLIER + 2),
- ),
- (
- " foo bar baz",
- "FOO",
- &[1, 2, 3],
- BONUS_BOUNDARY_WHITE * (BONUS_FIRST_CHAR_MULTIPLIER + 2),
- ),
- (
- " foo bar baz",
- " FOO",
- &[0, 1, 2, 3],
- BONUS_BOUNDARY_WHITE * (BONUS_FIRST_CHAR_MULTIPLIER + 3),
- ),
- ],
- );
- assert_matches(
- &[Substring, Postfix],
- false,
- false,
- false,
- false,
- &[
- (
- "foo bar baz",
- "baz",
- &[8, 9, 10],
- BONUS_BOUNDARY_WHITE * (BONUS_FIRST_CHAR_MULTIPLIER + 2),
- ),
- (
- "foo bar baz ",
- "baz",
- &[8, 9, 10],
- BONUS_BOUNDARY_WHITE * (BONUS_FIRST_CHAR_MULTIPLIER + 2),
- ),
- (
- "foo bar baz ",
- "baz ",
- &[8, 9, 10, 11],
- BONUS_BOUNDARY_WHITE * (BONUS_FIRST_CHAR_MULTIPLIER + 3),
- ),
- ],
- );
- assert_matches(
- &[Substring, Prefix, Postfix, Exact, FuzzyGreedy, FuzzyOptimal],
- false,
- false,
- false,
- false,
- &[
- (
- "foo",
- "foo",
- &[0, 1, 2],
- BONUS_BOUNDARY_WHITE * (BONUS_FIRST_CHAR_MULTIPLIER + 2),
- ),
- (
- " foo",
- "foo",
- &[1, 2, 3],
- BONUS_BOUNDARY_WHITE * (BONUS_FIRST_CHAR_MULTIPLIER + 2),
- ),
- (
- " foo",
- " foo",
- &[0, 1, 2, 3],
- BONUS_BOUNDARY_WHITE * (BONUS_FIRST_CHAR_MULTIPLIER + 3),
- ),
- ],
- );
- assert_matches(
- &[Substring],
- false,
- false,
- false,
- false,
- &[
- (
- "fooBarbaz1",
- "oba",
- &[2, 3, 4],
- BONUS_CAMEL123 + BONUS_CONSECUTIVE,
- ),
- (
- "/AutomatorDocument.icns",
- "rdoc",
- &[9, 10, 11, 12],
- BONUS_CAMEL123 + 2 * BONUS_CONSECUTIVE,
- ),
- (
- "/man1/zshcompctl.1",
- "zshc",
- &[6, 7, 8, 9],
- BONUS_BOUNDARY_DELIMITER * (BONUS_FIRST_CHAR_MULTIPLIER + 3),
- ),
- (
- "/.oh-my-zsh/cache",
- "zsh/c",
- &[8, 9, 10, 11, 12],
- BONUS_BOUNDARY * (BONUS_FIRST_CHAR_MULTIPLIER + 2)
- + BONUS_NON_WORD
- + BONUS_BOUNDARY_DELIMITER,
- ),
- ],
- );
- assert_not_matches_with(
- true,
- false,
- &[Prefix, Substring, Postfix, Exact],
- &[(
- "At the Road’s End - Seeming - SOL: A Self-Banishment Ritual",
- "adi",
- )],
- )
-}
-
-#[test]
-fn test_substring_case_sensitive() {
- assert_matches(
- &[Substring, Prefix],
- false,
- true,
- false,
- false,
- &[
- (
- "Foo bar baz",
- "Foo",
- &[0, 1, 2],
- BONUS_BOUNDARY_WHITE * (BONUS_FIRST_CHAR_MULTIPLIER + 2),
- ),
- (
- "Fȫô bar baz",
- "Fȫô",
- &[0, 1, 2],
- BONUS_BOUNDARY_WHITE * (BONUS_FIRST_CHAR_MULTIPLIER + 2),
- ),
- (
- "Foo ฿ar baz",
- "Foo",
- &[0, 1, 2],
- BONUS_BOUNDARY_WHITE * (BONUS_FIRST_CHAR_MULTIPLIER + 2),
- ),
- ],
- );
- assert_not_matches_with(false, true, &[Substring, Prefix], &[("foo bar baz", "Foo")]);
-}
-
-#[test]
-fn test_fuzzy_case_sensitive() {
- assert_matches(
- &[FuzzyGreedy, FuzzyOptimal],
- false,
- true,
- false,
- false,
- &[
- (
- "fooBarbaz1",
- "oBr",
- &[2, 3, 5],
- BONUS_CAMEL123 - PENALTY_GAP_START,
- ),
- (
- "Foo/Bar/Baz",
- "FBB",
- &[0, 4, 8],
- BONUS_BOUNDARY_WHITE * BONUS_FIRST_CHAR_MULTIPLIER + BONUS_BOUNDARY_DELIMITER * 2
- - 2 * PENALTY_GAP_START
- - 4 * PENALTY_GAP_EXTENSION,
- ),
- (
- "FooBarBaz",
- "FBB",
- &[0, 3, 6],
- BONUS_BOUNDARY_WHITE * BONUS_FIRST_CHAR_MULTIPLIER + BONUS_CAMEL123 * 2
- - 2 * PENALTY_GAP_START
- - 2 * PENALTY_GAP_EXTENSION,
- ),
- (
- "FooBar Baz",
- "FooB",
- &[0, 1, 2, 3],
- BONUS_BOUNDARY_WHITE * (BONUS_FIRST_CHAR_MULTIPLIER + 3),
- ),
- ("foo-bar", "o-ba", &[2, 3, 4, 5], BONUS_NON_WORD * 3),
- ],
- );
-}
-
-#[test]
-fn test_normalize() {
- assert_matches(
- &[FuzzyGreedy, FuzzyOptimal],
- true,
- false,
- false,
- false,
- &[
- (
- "Só Danço Samba",
- "So",
- &[0, 1],
- BONUS_BOUNDARY_WHITE * (BONUS_FIRST_CHAR_MULTIPLIER + 1),
- ),
- (
- "Só Danço Samba",
- "sodc",
- &[0, 1, 3, 6],
- BONUS_BOUNDARY_WHITE * (BONUS_FIRST_CHAR_MULTIPLIER + 1) - PENALTY_GAP_START
- + BONUS_BOUNDARY_WHITE
- - PENALTY_GAP_START
- - PENALTY_GAP_EXTENSION,
- ),
- (
- "Danço",
- "danco",
- &[0, 1, 2, 3, 4],
- BONUS_BOUNDARY_WHITE * (BONUS_FIRST_CHAR_MULTIPLIER + 4),
- ),
- (
- "DanÇo",
- "danco",
- &[0, 1, 2, 3, 4],
- BONUS_BOUNDARY_WHITE * (BONUS_FIRST_CHAR_MULTIPLIER + 4),
- ),
- (
- "xÇando",
- "cando",
- &[1, 2, 3, 4, 5],
- BONUS_CAMEL123 * (BONUS_FIRST_CHAR_MULTIPLIER + 4),
- ),
- ("ۂ(GCGɴCG", "n", &[5], 0),
- ],
- )
-}
-
-#[test]
-fn test_unicode() {
- assert_matches(
- &[FuzzyGreedy, FuzzyOptimal, Substring],
- true,
- false,
- false,
- false,
- &[
- (
- "你好世界",
- "你好",
- &[0, 1],
- BONUS_BOUNDARY_WHITE * (BONUS_FIRST_CHAR_MULTIPLIER + 1),
- ),
- (
- " 你好世界",
- "你好",
- &[1, 2],
- BONUS_BOUNDARY_WHITE * (BONUS_FIRST_CHAR_MULTIPLIER + 1),
- ),
- ],
- );
- assert_matches(
- &[FuzzyGreedy, FuzzyOptimal],
- true,
- false,
- false,
- false,
- &[(
- "你好世界",
- "你世",
- &[0, 2],
- BONUS_BOUNDARY_WHITE * BONUS_FIRST_CHAR_MULTIPLIER - PENALTY_GAP_START,
- )],
- );
- assert_not_matches(
- false,
- false,
- &[("Flibbertigibbet / イタズラっ子たち", "lying")],
- );
-}
-
-#[test]
-fn test_long_str() {
- assert_matches(
- &[FuzzyGreedy, FuzzyOptimal],
- false,
- false,
- false,
- false,
- &[(
- &"x".repeat(u16::MAX as usize + 1),
- "xx",
- &[0, 1],
- BONUS_BOUNDARY_WHITE * (BONUS_FIRST_CHAR_MULTIPLIER + 1),
- )],
- );
-}
-
-#[test]
-fn test_casing() {
- assert_matches(
- &[FuzzyGreedy, FuzzyOptimal],
- false,
- false,
- false,
- false,
- &[
- // these two have the same score
- (
- "fooBar",
- "foobar",
- &[0, 1, 2, 3, 4, 5],
- BONUS_BOUNDARY_WHITE * (BONUS_FIRST_CHAR_MULTIPLIER + 5),
- ),
- (
- "foobar",
- "foobar",
- &[0, 1, 2, 3, 4, 5],
- BONUS_BOUNDARY_WHITE * (BONUS_FIRST_CHAR_MULTIPLIER + 5),
- ),
- // these two have the same score (slightly lower than the other two: 60 instead of 70)
- (
- "foo-bar",
- "foobar",
- &[0, 1, 2, 4, 5, 6],
- BONUS_BOUNDARY_WHITE * (BONUS_FIRST_CHAR_MULTIPLIER + 2) - PENALTY_GAP_START
- + BONUS_BOUNDARY * 3,
- ),
- (
- "foo_bar",
- "foobar",
- &[0, 1, 2, 4, 5, 6],
- BONUS_BOUNDARY_WHITE * (BONUS_FIRST_CHAR_MULTIPLIER + 2) - PENALTY_GAP_START
- + BONUS_BOUNDARY * 3,
- ),
- ],
- )
-}
-
-#[test]
-fn test_optimal() {
- assert_matches(
- &[FuzzyOptimal],
- false,
- false,
- false,
- false,
- &[
- (
- "axxx xx ",
- "xx",
- &[5, 6],
- BONUS_BOUNDARY_WHITE * (BONUS_FIRST_CHAR_MULTIPLIER + 1),
- ),
- (
- "SS!H",
- "S!",
- &[0, 2],
- BONUS_BOUNDARY_WHITE * BONUS_FIRST_CHAR_MULTIPLIER - PENALTY_GAP_START
- + BONUS_NON_WORD,
- ),
- // this case is a cool example of why our algorithm is more than fzf
- // we handle this corretly detect that it's better to match
- // the second f instead of the third yielding a higher score
- // (despite using the same scoring function!)
- (
- "xf.foo",
- "xfoo",
- &[0, 3, 4, 5],
- BONUS_BOUNDARY_WHITE * BONUS_FIRST_CHAR_MULTIPLIER
- - PENALTY_GAP_START
- - PENALTY_GAP_EXTENSION
- + BONUS_BOUNDARY * 3,
- ),
- (
- "xf fo",
- "xfo",
- &[0, 3, 4],
- BONUS_BOUNDARY_WHITE * (BONUS_FIRST_CHAR_MULTIPLIER + 2)
- - PENALTY_GAP_START
- - PENALTY_GAP_EXTENSION,
- ),
- ],
- );
-}
-
-#[test]
-fn test_reject() {
- assert_not_matches(
- true,
- false,
- &[
- ("你好界", "abc"),
- ("你好界", "a"),
- ("你好世界", "富"),
- ("Só Danço Samba", "sox"),
- ("fooBarbaz", "fooBarbazz"),
- ("fooBarbaz", "c"),
- ],
- );
- assert_not_matches(
- true,
- true,
- &[
- ("你好界", "abc"),
- ("abc", "你"),
- ("abc", "A"),
- ("abc", "d"),
- ("你好世界", "富"),
- ("Só Danço Samba", "sox"),
- ("fooBarbaz", "oBZ"),
- ("Foo Bar Baz", "fbb"),
- ("fooBarbaz", "fooBarbazz"),
- ],
- );
- assert_not_matches(
- false,
- true,
- &[
- ("Só Danço Samba", "sod"),
- ("Só Danço Samba", "soc"),
- ("Só Danç", "So"),
- ],
- );
- assert_not_matches(false, false, &[("ۂۂfoۂۂ", "foo")]);
-}
-
-#[test]
-fn test_prefer_prefix() {
- assert_matches(
- &[FuzzyOptimal, FuzzyGreedy],
- false,
- false,
- false,
- true,
- &[
- (
- "Moby Dick",
- "md",
- &[0, 5],
- BONUS_BOUNDARY_WHITE * (BONUS_FIRST_CHAR_MULTIPLIER + 1) + MAX_PREFIX_BONUS
- - PENALTY_GAP_START
- - 3 * PENALTY_GAP_EXTENSION,
- ),
- (
- "Though I cannot tell why it was exactly that those stage managers, the Fates, put me down for this shabby part of a whaling voyage",
- "md",
- &[82, 85],
- BONUS_BOUNDARY_WHITE * (BONUS_FIRST_CHAR_MULTIPLIER + 1)
- - PENALTY_GAP_START
- - PENALTY_GAP_EXTENSION,
- ),
- ],
- );
-}
-
-#[test]
-fn test_single_char_needle() {
- assert_matches(
- &[FuzzyOptimal],
- false,
- false,
- false,
- false,
- &[(
- "foO",
- "o",
- &[2],
- BONUS_FIRST_CHAR_MULTIPLIER * BONUS_CAMEL123,
- )],
- );
- assert_matches(
- &[FuzzyOptimal],
- false,
- false,
- false,
- false,
- &[(
- "föÖ",
- "ö",
- &[2],
- BONUS_FIRST_CHAR_MULTIPLIER * BONUS_CAMEL123,
- )],
- );
-}
-
-#[test]
-fn umlaut() {
- let paths = ["be", "bë"];
- let mut matcher = Matcher::new(Config::DEFAULT);
- let matches = Pattern::parse("ë", CaseMatching::Ignore, Normalization::Smart)
- .match_list(paths, &mut matcher);
- assert_eq!(matches.len(), 1);
- let matches = Pattern::parse("e", CaseMatching::Ignore, Normalization::Never)
- .match_list(paths, &mut matcher);
- assert_eq!(matches.len(), 1);
- let matches = Pattern::parse("e", CaseMatching::Ignore, Normalization::Smart)
- .match_list(paths, &mut matcher);
- assert_eq!(matches.len(), 2);
-}