Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / ui / app_list / search / tokenized_string_match_unittest.cc
blobe412a8a856337686c5020c1378879a3c67285232
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.
5 #include "ui/app_list/search/tokenized_string_match.h"
7 #include <string>
9 #include "base/basictypes.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "testing/gtest/include/gtest/gtest.h"
13 namespace app_list {
14 namespace test {
16 // Returns a string of |text| marked the hits in |match| using block bracket.
17 // e.g. text= "Text", match.hits = [{0,1}], returns "[T]ext".
18 std::string MatchHit(const base::string16& text,
19 const TokenizedStringMatch& match) {
20 base::string16 marked = text;
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, '[');
30 return base::UTF16ToUTF8(marked);
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"},
46 TokenizedStringMatch match;
47 for (size_t i = 0; i < arraysize(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;
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]" },
75 TokenizedStringMatch match;
76 for (size_t i = 0; i < arraysize(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));
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" },
106 TokenizedStringMatch match_low;
107 TokenizedStringMatch match_high;
108 for (size_t i = 0; i < arraysize(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;
122 // More specialized tests of the absolute relevance scores. (These tests are
123 // minimal, because they are so brittle. Changing the scoring algorithm will
124 // require updating this test.)
125 TEST(TokenizedStringMatchTest, AbsoluteRelevance) {
126 const double kEpsilon = 0.006;
127 struct {
128 const char* text;
129 const char* query;
130 double expected_score;
131 } kTestCases[] = {
132 // The first few chars should increase the score extremely high. After
133 // that, they should count less.
134 // NOTE: 0.87 is a magic number, as it is the Omnibox score for a "pretty
135 // good" match. We want a 3-letter prefix match to be slightly above 0.87.
136 {"Google Chrome", "g", 0.5},
137 {"Google Chrome", "go", 0.75},
138 {"Google Chrome", "goo", 0.88},
139 {"Google Chrome", "goog", 0.94},
142 TokenizedStringMatch match;
143 for (size_t i = 0; i < arraysize(kTestCases); ++i) {
144 const base::string16 text(base::UTF8ToUTF16(kTestCases[i].text));
145 EXPECT_TRUE(match.Calculate(base::UTF8ToUTF16(kTestCases[i].query), text));
146 EXPECT_NEAR(match.relevance(), kTestCases[i].expected_score, kEpsilon)
147 << "Test case " << i << " : text=" << kTestCases[i].text
148 << ", query=" << kTestCases[i].query
149 << ", expected_score=" << kTestCases[i].expected_score;
153 } // namespace test
154 } // namespace app_list