Home | History | Annotate | Download | only in search
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "ui/app_list/search/tokenized_string_match.h"
      6 
      7 #include <string>
      8 
      9 #include "base/basictypes.h"
     10 #include "base/strings/utf_string_conversions.h"
     11 #include "testing/gtest/include/gtest/gtest.h"
     12 
     13 namespace app_list {
     14 namespace test {
     15 
     16 // Returns a string of |text| marked the hits in |match| using block bracket.
     17 // e.g. text= "Text", hits = [{0,1}], returns "[T]ext".
     18 std::string MatchHit(const base::string16& text,
     19                      const TokenizedStringMatch& match) {
     20   base::string16 marked = text;
     21 
     22   const TokenizedStringMatch::Hits& hits = match.hits();
     23   for (TokenizedStringMatch::Hits::const_reverse_iterator it = hits.rbegin();
     24        it != hits.rend(); ++it) {
     25     const gfx::Range& hit = *it;
     26     marked.insert(hit.end(), 1, ']');
     27     marked.insert(hit.start(), 1, '[');
     28   }
     29 
     30   return base::UTF16ToUTF8(marked);
     31 }
     32 
     33 TEST(TokenizedStringMatchTest, NotMatch) {
     34   struct {
     35     const char* text;
     36     const char* query;
     37   } kTestCases[] = {
     38     { "", "" },
     39     { "", "query" },
     40     { "text", "" },
     41     { "!", "!@#$%^&*()<<<**>>>" },
     42     { "abd", "abcd"},
     43     { "cd", "abcd"},
     44   };
     45 
     46   TokenizedStringMatch match;
     47   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestCases); ++i) {
     48     const base::string16 text(base::UTF8ToUTF16(kTestCases[i].text));
     49     EXPECT_FALSE(match.Calculate(base::UTF8ToUTF16(kTestCases[i].query), text))
     50         << "Test case " << i
     51         << " : text=" << kTestCases[i].text
     52         << ", query=" << kTestCases[i].query;
     53   }
     54 }
     55 
     56 TEST(TokenizedStringMatchTest, Match) {
     57   struct {
     58     const char* text;
     59     const char* query;
     60     const char* expect;
     61   } kTestCases[] = {
     62     { "ScratchPad", "pad", "Scratch[Pad]" },
     63     { "ScratchPad", "sp", "[S]cratch[P]ad" },
     64     { "Chess2", "che", "[Che]ss2" },
     65     { "Chess2", "c2", "[C]hess[2]" },
     66     { "Cut the rope", "cut ro", "[Cut] the [ro]pe" },
     67     { "Cut the rope", "cr", "[C]ut the [r]ope" },
     68     { "John Doe", "jdoe", "[J]ohn [Doe]" },
     69     { "John Doe", "johnd", "[John D]oe" },
     70     { "Secure Shell", "she", "Secure [She]ll" },
     71     { "Simple Secure Shell", "sish", "[Si]mple Secure [Sh]ell" },
     72     { "Netflix", "flix", "Net[flix]" },
     73   };
     74 
     75   TokenizedStringMatch match;
     76   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestCases); ++i) {
     77     const base::string16 text(base::UTF8ToUTF16(kTestCases[i].text));
     78     EXPECT_TRUE(match.Calculate(base::UTF8ToUTF16(kTestCases[i].query), text));
     79     EXPECT_EQ(kTestCases[i].expect, MatchHit(text, match));
     80   }
     81 }
     82 
     83 TEST(TokenizedStringMatchTest, Relevance) {
     84   struct {
     85     const char* text;
     86     const char* query_low;
     87     const char* query_high;
     88   } kTestCases[] = {
     89     // More matched chars are better.
     90     { "Google Chrome", "g", "go" },
     91     { "Google Chrome", "go", "goo" },
     92     { "Google Chrome", "goo", "goog" },
     93     { "Google Chrome", "c", "ch" },
     94     { "Google Chrome", "ch", "chr" },
     95     // Acronym match is better than something in the middle.
     96     { "Google Chrome", "ch", "gc" },
     97     // Prefix match is better than middle match and acronym match.
     98     { "Google Chrome", "ch", "go" },
     99     { "Google Chrome", "gc", "go" },
    100     // Substring match has the lowest score.
    101     { "Google Chrome", "oo", "gc" },
    102     { "Google Chrome", "oo", "go" },
    103     { "Google Chrome", "oo", "ch" },
    104   };
    105 
    106   TokenizedStringMatch match_low;
    107   TokenizedStringMatch match_high;
    108   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestCases); ++i) {
    109     const base::string16 text(base::UTF8ToUTF16(kTestCases[i].text));
    110     EXPECT_TRUE(
    111         match_low.Calculate(base::UTF8ToUTF16(kTestCases[i].query_low), text));
    112     EXPECT_TRUE(match_high.Calculate(
    113         base::UTF8ToUTF16(kTestCases[i].query_high), text));
    114     EXPECT_LT(match_low.relevance(), match_high.relevance())
    115         << "Test case " << i
    116         << " : text=" << kTestCases[i].text
    117         << ", query_low=" << kTestCases[i].query_low
    118         << ", query_high=" << kTestCases[i].query_high;
    119   }
    120 }
    121 
    122 }  // namespace test
    123 }  // namespace app_list
    124