| // Copyright 2022 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chromeos/ash/components/string_matching/prefix_matcher.h" |
| |
| #include "chromeos/ash/components/string_matching/tokenized_string.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace ash::string_matching { |
| |
| namespace { |
| |
| using prefix_matcher_constants::kIsFrontOfTokenCharScore; |
| using prefix_matcher_constants::kIsPrefixCharScore; |
| using prefix_matcher_constants::kIsWeakHitCharScore; |
| using prefix_matcher_constants::kNoMatchScore; |
| |
| constexpr double kAbsError = 1e-5; |
| |
| } // namespace |
| |
| class PrefixMatcherTest : public testing::Test {}; |
| |
| // Note on expected score calculations: |
| // |
| // When a query successfully matches to a text, each letter of the query |
| // contributes some amount towards a final total. The expected score in |
| // each test is then the sum over all of the contributions of the individual |
| // query letters. This is described in more detail in prefix_matcher.cc. |
| // |
| // When a query does not successfully match to a text, the overall expected |
| // score is `kNoMatchScore`. |
| |
| TEST_F(PrefixMatcherTest, ExactMatch) { |
| TokenizedString query(u"abc def"); |
| TokenizedString text(u"abc def"); |
| |
| PrefixMatcher pm(query, text); |
| pm.Match(); |
| double expected_score = kIsPrefixCharScore * 6; |
| EXPECT_NEAR(pm.relevance(), expected_score, kAbsError); |
| } |
| |
| TEST_F(PrefixMatcherTest, ExactPrefixMatch) { |
| TokenizedString query(u"abc def"); |
| TokenizedString text(u"abc defgh ijklm"); |
| |
| PrefixMatcher pm(query, text); |
| pm.Match(); |
| double expected_score = kIsPrefixCharScore * 6; |
| EXPECT_NEAR(pm.relevance(), expected_score, kAbsError); |
| } |
| |
| TEST_F(PrefixMatcherTest, ExactPrefixMatchFirstToken) { |
| TokenizedString query(u"ab"); |
| TokenizedString text(u"abc def"); |
| |
| PrefixMatcher pm(query, text); |
| pm.Match(); |
| double expected_score = kIsPrefixCharScore * 2; |
| EXPECT_NEAR(pm.relevance(), expected_score, kAbsError); |
| } |
| |
| TEST_F(PrefixMatcherTest, ExactPrefixMatchNonFirstToken) { |
| TokenizedString query(u"de"); |
| TokenizedString text(u"abc def"); |
| |
| PrefixMatcher pm(query, text); |
| pm.Match(); |
| double expected_score = kIsFrontOfTokenCharScore + kIsWeakHitCharScore; |
| EXPECT_NEAR(pm.relevance(), expected_score, kAbsError); |
| } |
| |
| TEST_F(PrefixMatcherTest, AcronymMatchFirstTokenMatchConsideredNonMatch) { |
| TokenizedString query(u"abc"); |
| TokenizedString text(u"axx bxx cxx dxx exx"); |
| |
| PrefixMatcher pm(query, text); |
| pm.Match(); |
| double expected_score = kNoMatchScore; |
| EXPECT_NEAR(pm.relevance(), expected_score, kAbsError); |
| } |
| |
| TEST_F(PrefixMatcherTest, AcronymMatchNonFirstTokenMatchConsideredNonMatch) { |
| TokenizedString query(u"bcd"); |
| TokenizedString text(u"axx bxx cxx dxx exx"); |
| |
| PrefixMatcher pm(query, text); |
| pm.Match(); |
| double expected_score = kNoMatchScore; |
| EXPECT_NEAR(pm.relevance(), expected_score, kAbsError); |
| } |
| |
| TEST_F(PrefixMatcherTest, AcronymMatchNonConsecutiveConsideredNonMatch) { |
| TokenizedString query(u"acd"); |
| TokenizedString text(u"axx bxx cxx dxx exx"); |
| |
| PrefixMatcher pm(query, text); |
| pm.Match(); |
| double expected_score = kNoMatchScore; |
| EXPECT_NEAR(pm.relevance(), expected_score, kAbsError); |
| } |
| |
| TEST_F(PrefixMatcherTest, MixedAcronymAndPrefixMatchingConsideredNonMatch) { |
| TokenizedString query(u"adefg"); |
| TokenizedString text(u"abc def ghi"); |
| |
| PrefixMatcher pm(query, text); |
| pm.Match(); |
| |
| double expected_score = kNoMatchScore; |
| EXPECT_NEAR(pm.relevance(), expected_score, kAbsError); |
| } |
| |
| TEST_F(PrefixMatcherTest, FinalPartialTokenConsideredMatch) { |
| TokenizedString query(u"abc de"); |
| TokenizedString text(u"abc def"); |
| |
| PrefixMatcher pm(query, text); |
| pm.Match(); |
| double expected_score = kIsPrefixCharScore * 5; |
| EXPECT_NEAR(pm.relevance(), expected_score, kAbsError); |
| } |
| |
| TEST_F(PrefixMatcherTest, NonFinalPartialTokenConsideredNonMatch) { |
| TokenizedString query(u"abce"); |
| TokenizedString text(u"a bcd e"); |
| |
| PrefixMatcher pm(query, text); |
| pm.Match(); |
| double expected_score = kNoMatchScore; |
| EXPECT_NEAR(pm.relevance(), expected_score, kAbsError); |
| } |
| |
| TEST_F(PrefixMatcherTest, ExactPrefixMatchDiscrete) { |
| TokenizedString query(u"abc ghi"); |
| TokenizedString text(u"abc def ghi"); |
| |
| PrefixMatcher pm(query, text); |
| pm.Match(); |
| double expected_score = kIsPrefixCharScore * 3 + kIsFrontOfTokenCharScore + |
| kIsWeakHitCharScore * 2; |
| EXPECT_NEAR(pm.relevance(), expected_score, kAbsError); |
| } |
| |
| TEST_F(PrefixMatcherTest, ExactPrefixMatchDiscreteNonFirstToken) { |
| TokenizedString query(u"abc ghi"); |
| TokenizedString text(u"jkl abc def ghi"); |
| |
| PrefixMatcher pm(query, text); |
| pm.Match(); |
| double expected_score = |
| kIsFrontOfTokenCharScore * 2 + kIsWeakHitCharScore * 4; |
| EXPECT_NEAR(pm.relevance(), expected_score, kAbsError); |
| } |
| |
| TEST_F(PrefixMatcherTest, ExactPrefixMatchOrderVariation) { |
| TokenizedString query(u"ghi abc"); |
| TokenizedString text(u"abc ghi"); |
| |
| PrefixMatcher pm(query, text); |
| pm.Match(); |
| double expected_score = |
| kIsFrontOfTokenCharScore * 2 + kIsWeakHitCharScore * 4; |
| EXPECT_NEAR(pm.relevance(), expected_score, kAbsError); |
| } |
| |
| TEST_F(PrefixMatcherTest, ExactPrefixMatchOrderVariationNonFirstToken) { |
| TokenizedString query(u"ghi abc"); |
| TokenizedString text(u"jkl abc ghi"); |
| |
| PrefixMatcher pm(query, text); |
| pm.Match(); |
| double expected_score = |
| kIsFrontOfTokenCharScore * 2 + kIsWeakHitCharScore * 4; |
| EXPECT_NEAR(pm.relevance(), expected_score, kAbsError); |
| } |
| |
| TEST_F(PrefixMatcherTest, ExactPrefixMatchOrderVariationAndDiscrete) { |
| TokenizedString query(u"ghi abc"); |
| TokenizedString text(u"jkl abc def ghi"); |
| |
| PrefixMatcher pm(query, text); |
| pm.Match(); |
| double expected_score = |
| kIsFrontOfTokenCharScore * 2 + kIsWeakHitCharScore * 4; |
| EXPECT_NEAR(pm.relevance(), expected_score, kAbsError); |
| } |
| |
| TEST_F(PrefixMatcherTest, SentencePrefixMatch) { |
| TokenizedString query(u"abcd"); |
| TokenizedString text(u"a bcd e"); |
| |
| PrefixMatcher pm(query, text); |
| pm.Match(); |
| double expected_score = kIsPrefixCharScore * 4; |
| EXPECT_NEAR(pm.relevance(), expected_score, kAbsError); |
| } |
| |
| TEST_F(PrefixMatcherTest, SentencePrefixMatchNotInFront) { |
| TokenizedString query(u"abcd"); |
| TokenizedString text(u"fgh a bcd e"); |
| |
| PrefixMatcher pm(query, text); |
| pm.Match(); |
| double expected_score = (kIsFrontOfTokenCharScore + kIsWeakHitCharScore) * 2; |
| EXPECT_NEAR(pm.relevance(), expected_score, kAbsError); |
| } |
| |
| TEST_F(PrefixMatcherTest, CaseSentencePrefixMatchPreferred) { |
| TokenizedString query(u"abc def"); |
| TokenizedString text(u"abcdef abc def"); |
| |
| PrefixMatcher pm(query, text); |
| pm.Match(); |
| double expected_score = kIsPrefixCharScore * 6; |
| EXPECT_NEAR(pm.relevance(), expected_score, kAbsError); |
| } |
| |
| TEST_F(PrefixMatcherTest, CaseTokenPrefixMatchPreferred) { |
| TokenizedString query(u"abc def"); |
| TokenizedString text(u"def abc abcdef"); |
| |
| PrefixMatcher pm(query, text); |
| pm.Match(); |
| double expected_score = |
| kIsFrontOfTokenCharScore * 2 + kIsWeakHitCharScore * 4; |
| EXPECT_NEAR(pm.relevance(), expected_score, kAbsError); |
| } |
| |
| TEST_F(PrefixMatcherTest, LastQueryTokenCanBeMatchedAtMostOnce) { |
| TokenizedString query(u"about c"); |
| TokenizedString text(u"Chrome Canvas"); |
| |
| PrefixMatcher pm(query, text); |
| pm.Match(); |
| double expected_score = 0; |
| EXPECT_NEAR(pm.relevance(), expected_score, kAbsError); |
| } |
| |
| } // namespace ash::string_matching |