| // Copyright 2020 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/ui/commander/fuzzy_finder.h" |
| |
| #include "base/i18n/case_conversion.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace commander { |
| TEST(CommanderFuzzyFinder, NonmatchIsZero) { |
| std::vector<gfx::Range> ranges; |
| EXPECT_EQ(0, FuzzyFind(base::ASCIIToUTF16("orange"), |
| base::ASCIIToUTF16("orangutan"), &ranges)); |
| EXPECT_TRUE(ranges.empty()); |
| EXPECT_EQ(0, FuzzyFind(base::ASCIIToUTF16("elephant"), |
| base::ASCIIToUTF16("orangutan"), &ranges)); |
| EXPECT_TRUE(ranges.empty()); |
| } |
| |
| TEST(CommanderFuzzyFinder, ExactMatchIsOne) { |
| std::vector<gfx::Range> ranges; |
| EXPECT_EQ(1, FuzzyFind(base::ASCIIToUTF16("orange"), |
| base::ASCIIToUTF16("orange"), &ranges)); |
| EXPECT_EQ(ranges, std::vector<gfx::Range>({{0, 6}})); |
| } |
| |
| // This ensures coverage for a fast path. Successful match is |
| // tested in ExactMatchIsOne() above. |
| TEST(CommanderFuzzyFinder, NeedleHaystackSameLength) { |
| std::vector<gfx::Range> ranges; |
| EXPECT_EQ(0, FuzzyFind(base::ASCIIToUTF16("ranges"), |
| base::ASCIIToUTF16("orange"), &ranges)); |
| EXPECT_TRUE(ranges.empty()); |
| } |
| |
| // This ensures coverage for a fast path (just making sure the path has |
| // coverage rather than ensuring the path is taken). |
| TEST(CommanderFuzzyFinder, SingleCharNeedle) { |
| std::vector<gfx::Range> ranges; |
| |
| double prefix_score = |
| FuzzyFind(base::ASCIIToUTF16("o"), base::ASCIIToUTF16("orange"), &ranges); |
| EXPECT_EQ(ranges, std::vector<gfx::Range>({{0, 1}})); |
| double internal_score = |
| FuzzyFind(base::ASCIIToUTF16("o"), base::ASCIIToUTF16("phone"), &ranges); |
| EXPECT_EQ(ranges, std::vector<gfx::Range>({{2, 3}})); |
| double boundary_score = FuzzyFind( |
| base::ASCIIToUTF16("o"), base::ASCIIToUTF16("phone operator"), &ranges); |
| EXPECT_EQ(ranges, std::vector<gfx::Range>({{6, 7}})); |
| |
| // Expected ordering: |
| // - Prefix should rank highest. |
| // - Word boundary matches that are not the prefix should rank next |
| // highest, even if there's an internal match earlier in the haystack. |
| // - Internal matches should rank lowest. |
| EXPECT_GT(prefix_score, boundary_score); |
| EXPECT_GT(boundary_score, internal_score); |
| |
| // ...and non-matches should have score = 0. |
| EXPECT_EQ(0, FuzzyFind(base::ASCIIToUTF16("o"), |
| base::ASCIIToUTF16("aquarium"), &ranges)); |
| EXPECT_TRUE(ranges.empty()); |
| } |
| |
| TEST(CommanderFuzzyFinder, CaseInsensitive) { |
| std::vector<gfx::Range> ranges; |
| EXPECT_EQ(1, FuzzyFind(base::ASCIIToUTF16("orange"), |
| base::ASCIIToUTF16("Orange"), &ranges)); |
| EXPECT_EQ(ranges, std::vector<gfx::Range>({{0, 6}})); |
| } |
| |
| TEST(CommanderFuzzyFinder, PrefixRanksHigherThanInternal) { |
| std::vector<gfx::Range> ranges; |
| |
| double prefix_rank = FuzzyFind(base::ASCIIToUTF16("orange"), |
| base::ASCIIToUTF16("Orange juice"), &ranges); |
| double non_prefix_rank = |
| FuzzyFind(base::ASCIIToUTF16("orange"), |
| base::ASCIIToUTF16("William of Orange"), &ranges); |
| |
| EXPECT_GT(prefix_rank, 0); |
| EXPECT_GT(non_prefix_rank, 0); |
| EXPECT_LT(prefix_rank, 1); |
| EXPECT_LT(non_prefix_rank, 1); |
| EXPECT_GT(prefix_rank, non_prefix_rank); |
| } |
| |
| TEST(CommanderFuzzyFinder, NeedleLongerThanHaystack) { |
| std::vector<gfx::Range> ranges; |
| EXPECT_EQ(0, FuzzyFind(base::ASCIIToUTF16("orange juice"), |
| base::ASCIIToUTF16("orange"), &ranges)); |
| EXPECT_TRUE(ranges.empty()); |
| } |
| |
| TEST(CommanderFuzzyFinder, Noncontiguous) { |
| std::vector<gfx::Range> ranges; |
| EXPECT_GT(FuzzyFind(base::ASCIIToUTF16("tuot"), |
| base::UTF8ToUTF16("Tlön, Uqbar, Orbis Tertius"), &ranges), |
| 0); |
| EXPECT_EQ(ranges, |
| std::vector<gfx::Range>({{0, 1}, {6, 7}, {13, 14}, {19, 20}})); |
| } |
| } // namespace commander |