OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/command_line.h" | 5 #include "base/command_line.h" |
6 #include "base/message_loop/message_loop.h" | 6 #include "base/message_loop/message_loop.h" |
7 #include "base/strings/utf_string_conversions.h" | 7 #include "base/strings/utf_string_conversions.h" |
8 #include "chrome/browser/autocomplete/autocomplete_match.h" | 8 #include "chrome/browser/autocomplete/autocomplete_match.h" |
9 #include "chrome/browser/autocomplete/keyword_provider.h" | 9 #include "chrome/browser/autocomplete/keyword_provider.h" |
10 #include "chrome/browser/search_engines/template_url.h" | 10 #include "chrome/browser/search_engines/template_url.h" |
11 #include "chrome/browser/search_engines/template_url_service.h" | 11 #include "chrome/browser/search_engines/template_url_service.h" |
12 #include "chrome/common/chrome_switches.h" | 12 #include "chrome/common/chrome_switches.h" |
13 #include "chrome/test/base/testing_browser_process.h" | 13 #include "chrome/test/base/testing_browser_process.h" |
14 #include "testing/gtest/include/gtest/gtest.h" | 14 #include "testing/gtest/include/gtest/gtest.h" |
15 #include "url/gurl.h" | 15 #include "url/gurl.h" |
16 | 16 |
17 class KeywordProviderTest : public testing::Test { | 17 class KeywordProviderTest : public testing::Test { |
18 protected: | 18 protected: |
19 template<class ResultType> | 19 template<class ResultType> |
20 struct test_data { | 20 struct MatchType { |
| 21 const ResultType member; |
| 22 bool allowed_to_be_default_match; |
| 23 }; |
| 24 |
| 25 template<class ResultType> |
| 26 struct TestData { |
21 const string16 input; | 27 const string16 input; |
22 const size_t num_results; | 28 const size_t num_results; |
23 const ResultType output[3]; | 29 const MatchType<ResultType> output[3]; |
24 }; | 30 }; |
25 | 31 |
26 KeywordProviderTest() : kw_provider_(NULL) { } | 32 KeywordProviderTest() : kw_provider_(NULL) { } |
27 virtual ~KeywordProviderTest() { } | 33 virtual ~KeywordProviderTest() { } |
28 | 34 |
29 virtual void SetUp(); | 35 virtual void SetUp(); |
30 virtual void TearDown(); | 36 virtual void TearDown(); |
31 | 37 |
32 template<class ResultType> | 38 template<class ResultType> |
33 void RunTest(test_data<ResultType>* keyword_cases, | 39 void RunTest(TestData<ResultType>* keyword_cases, |
34 int num_cases, | 40 int num_cases, |
35 ResultType AutocompleteMatch::* member); | 41 ResultType AutocompleteMatch::* member); |
36 | 42 |
37 protected: | 43 protected: |
38 static const TemplateURLService::Initializer kTestData[]; | 44 static const TemplateURLService::Initializer kTestData[]; |
39 | 45 |
40 scoped_refptr<KeywordProvider> kw_provider_; | 46 scoped_refptr<KeywordProvider> kw_provider_; |
41 scoped_ptr<TemplateURLService> model_; | 47 scoped_ptr<TemplateURLService> model_; |
42 }; | 48 }; |
43 | 49 |
(...skipping 13 matching lines...) Expand all Loading... |
57 kw_provider_ = new KeywordProvider(NULL, model_.get()); | 63 kw_provider_ = new KeywordProvider(NULL, model_.get()); |
58 } | 64 } |
59 | 65 |
60 void KeywordProviderTest::TearDown() { | 66 void KeywordProviderTest::TearDown() { |
61 model_.reset(); | 67 model_.reset(); |
62 kw_provider_ = NULL; | 68 kw_provider_ = NULL; |
63 } | 69 } |
64 | 70 |
65 template<class ResultType> | 71 template<class ResultType> |
66 void KeywordProviderTest::RunTest( | 72 void KeywordProviderTest::RunTest( |
67 test_data<ResultType>* keyword_cases, | 73 TestData<ResultType>* keyword_cases, |
68 int num_cases, | 74 int num_cases, |
69 ResultType AutocompleteMatch::* member) { | 75 ResultType AutocompleteMatch::* member) { |
70 ACMatches matches; | 76 ACMatches matches; |
71 for (int i = 0; i < num_cases; ++i) { | 77 for (int i = 0; i < num_cases; ++i) { |
| 78 SCOPED_TRACE(keyword_cases[i].input); |
72 AutocompleteInput input(keyword_cases[i].input, string16::npos, string16(), | 79 AutocompleteInput input(keyword_cases[i].input, string16::npos, string16(), |
73 GURL(), AutocompleteInput::INVALID_SPEC, true, | 80 GURL(), AutocompleteInput::INVALID_SPEC, true, |
74 false, true, AutocompleteInput::ALL_MATCHES); | 81 false, true, AutocompleteInput::ALL_MATCHES); |
75 kw_provider_->Start(input, false); | 82 kw_provider_->Start(input, false); |
76 EXPECT_TRUE(kw_provider_->done()); | 83 EXPECT_TRUE(kw_provider_->done()); |
77 matches = kw_provider_->matches(); | 84 matches = kw_provider_->matches(); |
78 EXPECT_EQ(keyword_cases[i].num_results, matches.size()) << | 85 ASSERT_EQ(keyword_cases[i].num_results, matches.size()); |
79 ASCIIToUTF16("Input was: ") + keyword_cases[i].input; | 86 for (size_t j = 0; j < matches.size(); ++j) { |
80 if (matches.size() == keyword_cases[i].num_results) { | 87 EXPECT_EQ(keyword_cases[i].output[j].member, matches[j].*member); |
81 for (size_t j = 0; j < keyword_cases[i].num_results; ++j) { | 88 EXPECT_EQ(keyword_cases[i].output[j].allowed_to_be_default_match, |
82 EXPECT_EQ(keyword_cases[i].output[j], matches[j].*member); | 89 matches[j].allowed_to_be_default_match); |
83 } | |
84 } | 90 } |
85 } | 91 } |
86 } | 92 } |
87 | 93 |
88 TEST_F(KeywordProviderTest, Edit) { | 94 TEST_F(KeywordProviderTest, Edit) { |
89 test_data<string16> edit_cases[] = { | 95 const MatchType<string16> kEmptyMatch = { string16(), false }; |
| 96 TestData<string16> edit_cases[] = { |
90 // Searching for a nonexistent prefix should give nothing. | 97 // Searching for a nonexistent prefix should give nothing. |
91 {ASCIIToUTF16("Not Found"), 0, {}}, | 98 { ASCIIToUTF16("Not Found"), 0, |
92 {ASCIIToUTF16("aaaaaNot Found"), 0, {}}, | 99 { kEmptyMatch, kEmptyMatch, kEmptyMatch } }, |
| 100 { ASCIIToUTF16("aaaaaNot Found"), 0, |
| 101 { kEmptyMatch, kEmptyMatch, kEmptyMatch } }, |
93 | 102 |
94 // Check that tokenization only collapses whitespace between first tokens, | 103 // Check that tokenization only collapses whitespace between first tokens, |
95 // no-query-input cases have a space appended, and action is not escaped. | 104 // no-query-input cases have a space appended, and action is not escaped. |
96 {ASCIIToUTF16("z"), 1, {ASCIIToUTF16("z ")}}, | 105 { ASCIIToUTF16("z"), 1, |
97 {ASCIIToUTF16("z \t"), 1, {ASCIIToUTF16("z ")}}, | 106 { { ASCIIToUTF16("z "), true }, kEmptyMatch, kEmptyMatch } }, |
| 107 { ASCIIToUTF16("z \t"), 1, |
| 108 { { ASCIIToUTF16("z "), true }, kEmptyMatch, kEmptyMatch } }, |
98 | 109 |
99 // Check that exact, substituting keywords with a verbatim search term | 110 // Check that exact, substituting keywords with a verbatim search term |
100 // don't generate a result. (These are handled by SearchProvider.) | 111 // don't generate a result. (These are handled by SearchProvider.) |
101 {ASCIIToUTF16("z foo"), 0, {}}, | 112 { ASCIIToUTF16("z foo"), 0, |
102 {ASCIIToUTF16("z a b c++"), 0, {}}, | 113 { kEmptyMatch, kEmptyMatch, kEmptyMatch } }, |
| 114 { ASCIIToUTF16("z a b c++"), 0, |
| 115 { kEmptyMatch, kEmptyMatch, kEmptyMatch } }, |
103 | 116 |
104 // Matches should be limited to three, and sorted in quality order, not | 117 // Matches should be limited to three, and sorted in quality order, not |
105 // alphabetical. | 118 // alphabetical. |
106 {ASCIIToUTF16("aaa"), 2, {ASCIIToUTF16("aaaa "), | 119 { ASCIIToUTF16("aaa"), 2, |
107 ASCIIToUTF16("aaaaa ")}}, | 120 { { ASCIIToUTF16("aaaa "), false }, |
108 {ASCIIToUTF16("a 1 2 3"), 3, {ASCIIToUTF16("aa 1 2 3"), | 121 { ASCIIToUTF16("aaaaa "), false }, |
109 ASCIIToUTF16("ab 1 2 3"), | 122 kEmptyMatch } }, |
110 ASCIIToUTF16("aaaa 1 2 3")}}, | 123 { ASCIIToUTF16("a 1 2 3"), 3, |
111 {ASCIIToUTF16("www.a"), 3, {ASCIIToUTF16("aa "), | 124 { { ASCIIToUTF16("aa 1 2 3"), false }, |
112 ASCIIToUTF16("ab "), | 125 { ASCIIToUTF16("ab 1 2 3"), false }, |
113 ASCIIToUTF16("aaaa ")}}, | 126 { ASCIIToUTF16("aaaa 1 2 3"), false } } }, |
| 127 { ASCIIToUTF16("www.a"), 3, |
| 128 { { ASCIIToUTF16("aa "), false }, |
| 129 { ASCIIToUTF16("ab "), false }, |
| 130 { ASCIIToUTF16("aaaa "), false } } }, |
114 // Exact matches should prevent returning inexact matches. Also, the | 131 // Exact matches should prevent returning inexact matches. Also, the |
115 // verbatim query for this keyword match should not be returned. (It's | 132 // verbatim query for this keyword match should not be returned. (It's |
116 // returned by SearchProvider.) | 133 // returned by SearchProvider.) |
117 {ASCIIToUTF16("aaaa foo"), 0, {}}, | 134 { ASCIIToUTF16("aaaa foo"), 0, |
118 {ASCIIToUTF16("www.aaaa foo"), 0, {}}, | 135 { kEmptyMatch, kEmptyMatch, kEmptyMatch } }, |
| 136 { ASCIIToUTF16("www.aaaa foo"), 0, |
| 137 { kEmptyMatch, kEmptyMatch, kEmptyMatch } }, |
119 | 138 |
120 // Clean up keyword input properly. "http" and "https" are the only | 139 // Clean up keyword input properly. "http" and "https" are the only |
121 // allowed schemes. | 140 // allowed schemes. |
122 {ASCIIToUTF16("www"), 1, {ASCIIToUTF16("www ")}}, | 141 { ASCIIToUTF16("www"), 1, |
123 {ASCIIToUTF16("www."), 0, {}}, | 142 { { ASCIIToUTF16("www "), true }, kEmptyMatch, kEmptyMatch }}, |
124 {ASCIIToUTF16("www.w w"), 2, {ASCIIToUTF16("www w"), | 143 { ASCIIToUTF16("www."), 0, |
125 ASCIIToUTF16("weasel w")}}, | 144 { kEmptyMatch, kEmptyMatch, kEmptyMatch } }, |
126 {ASCIIToUTF16("http://www"), 1, {ASCIIToUTF16("www ")}}, | 145 { ASCIIToUTF16("www.w w"), 2, |
127 {ASCIIToUTF16("http://www."), 0, {}}, | 146 { { ASCIIToUTF16("www w"), false }, |
128 {ASCIIToUTF16("ftp: blah"), 0, {}}, | 147 { ASCIIToUTF16("weasel w"), false }, |
129 {ASCIIToUTF16("mailto:z"), 0, {}}, | 148 kEmptyMatch } }, |
130 {ASCIIToUTF16("ftp://z"), 0, {}}, | 149 { ASCIIToUTF16("http://www"), 1, |
131 {ASCIIToUTF16("https://z"), 1, {ASCIIToUTF16("z ")}}, | 150 { { ASCIIToUTF16("www "), true }, kEmptyMatch, kEmptyMatch } }, |
| 151 { ASCIIToUTF16("http://www."), 0, |
| 152 { kEmptyMatch, kEmptyMatch, kEmptyMatch } }, |
| 153 { ASCIIToUTF16("ftp: blah"), 0, |
| 154 { kEmptyMatch, kEmptyMatch, kEmptyMatch } }, |
| 155 { ASCIIToUTF16("mailto:z"), 0, |
| 156 { kEmptyMatch, kEmptyMatch, kEmptyMatch } }, |
| 157 { ASCIIToUTF16("ftp://z"), 0, |
| 158 { kEmptyMatch, kEmptyMatch, kEmptyMatch } }, |
| 159 { ASCIIToUTF16("https://z"), 1, |
| 160 { { ASCIIToUTF16("z "), true }, kEmptyMatch, kEmptyMatch } }, |
132 }; | 161 }; |
133 | 162 |
134 RunTest<string16>(edit_cases, arraysize(edit_cases), | 163 RunTest<string16>(edit_cases, arraysize(edit_cases), |
135 &AutocompleteMatch::fill_into_edit); | 164 &AutocompleteMatch::fill_into_edit); |
136 } | 165 } |
137 | 166 |
138 TEST_F(KeywordProviderTest, URL) { | 167 TEST_F(KeywordProviderTest, URL) { |
139 test_data<GURL> url_cases[] = { | 168 const MatchType<GURL> kEmptyMatch = { GURL(), false }; |
| 169 TestData<GURL> url_cases[] = { |
140 // No query input -> empty destination URL. | 170 // No query input -> empty destination URL. |
141 {ASCIIToUTF16("z"), 1, {GURL()}}, | 171 { ASCIIToUTF16("z"), 1, |
142 {ASCIIToUTF16("z \t"), 1, {GURL()}}, | 172 { { GURL(), true }, kEmptyMatch, kEmptyMatch } }, |
| 173 { ASCIIToUTF16("z \t"), 1, |
| 174 { { GURL(), true }, kEmptyMatch, kEmptyMatch } }, |
143 | 175 |
144 // Check that tokenization only collapses whitespace between first tokens | 176 // Check that tokenization only collapses whitespace between first tokens |
145 // and query input, but not rest of URL, is escaped. | 177 // and query input, but not rest of URL, is escaped. |
146 {ASCIIToUTF16("w bar +baz"), 2, {GURL(" +%2B?=bar+%2Bbazfoo "), | 178 { ASCIIToUTF16("w bar +baz"), 2, |
147 GURL("bar+%2Bbaz=z")}}, | 179 { { GURL(" +%2B?=bar+%2Bbazfoo "), false }, |
| 180 { GURL("bar+%2Bbaz=z"), false }, |
| 181 kEmptyMatch } }, |
148 | 182 |
149 // Substitution should work with various locations of the "%s". | 183 // Substitution should work with various locations of the "%s". |
150 {ASCIIToUTF16("aaa 1a2b"), 2, {GURL("http://aaaa/?aaaa=1&b=1a2b&c"), | 184 { ASCIIToUTF16("aaa 1a2b"), 2, |
151 GURL("1a2b")}}, | 185 { { GURL("http://aaaa/?aaaa=1&b=1a2b&c"), false }, |
152 {ASCIIToUTF16("a 1 2 3"), 3, {GURL("aa.com?foo=1+2+3"), | 186 { GURL("1a2b"), false }, |
153 GURL("bogus URL 1+2+3"), | 187 kEmptyMatch } }, |
154 GURL("http://aaaa/?aaaa=1&b=1+2+3&c")}}, | 188 { ASCIIToUTF16("a 1 2 3"), 3, |
155 {ASCIIToUTF16("www.w w"), 2, {GURL(" +%2B?=wfoo "), | 189 { { GURL("aa.com?foo=1+2+3"), false }, |
156 GURL("weaselwweasel")}}, | 190 { GURL("bogus URL 1+2+3"), false }, |
| 191 { GURL("http://aaaa/?aaaa=1&b=1+2+3&c"), false } } }, |
| 192 { ASCIIToUTF16("www.w w"), 2, |
| 193 { { GURL(" +%2B?=wfoo "), false }, |
| 194 { GURL("weaselwweasel"), false }, |
| 195 kEmptyMatch } }, |
157 }; | 196 }; |
158 | 197 |
159 RunTest<GURL>(url_cases, arraysize(url_cases), | 198 RunTest<GURL>(url_cases, arraysize(url_cases), |
160 &AutocompleteMatch::destination_url); | 199 &AutocompleteMatch::destination_url); |
161 } | 200 } |
162 | 201 |
163 TEST_F(KeywordProviderTest, Contents) { | 202 TEST_F(KeywordProviderTest, Contents) { |
164 test_data<string16> contents_cases[] = { | 203 const MatchType<string16> kEmptyMatch = { string16(), false }; |
| 204 TestData<string16> contents_cases[] = { |
165 // No query input -> substitute "<enter query>" into contents. | 205 // No query input -> substitute "<enter query>" into contents. |
166 {ASCIIToUTF16("z"), 1, | 206 { ASCIIToUTF16("z"), 1, |
167 {ASCIIToUTF16("Search z for <enter query>")}}, | 207 { { ASCIIToUTF16("Search z for <enter query>"), true }, |
168 {ASCIIToUTF16("z \t"), 1, | 208 kEmptyMatch, kEmptyMatch } }, |
169 {ASCIIToUTF16("Search z for <enter query>")}}, | 209 { ASCIIToUTF16("z \t"), 1, |
| 210 { { ASCIIToUTF16("Search z for <enter query>"), true }, |
| 211 kEmptyMatch, kEmptyMatch } }, |
170 | 212 |
171 // Exact keyword matches with remaining text should return nothing. | 213 // Exact keyword matches with remaining text should return nothing. |
172 {ASCIIToUTF16("www.www www"), 0, {}}, | 214 { ASCIIToUTF16("www.www www"), 0, |
173 {ASCIIToUTF16("z a b c++"), 0, {}}, | 215 { kEmptyMatch, kEmptyMatch, kEmptyMatch } }, |
| 216 { ASCIIToUTF16("z a b c++"), 0, |
| 217 { kEmptyMatch, kEmptyMatch, kEmptyMatch } }, |
174 | 218 |
175 // Exact keyword matches with remaining text when the keyword is an | 219 // Exact keyword matches with remaining text when the keyword is an |
176 // extension keyword should return something. This is tested in | 220 // extension keyword should return something. This is tested in |
177 // chrome/browser/extensions/api/omnibox/omnibox_apitest.cc's | 221 // chrome/browser/extensions/api/omnibox/omnibox_apitest.cc's |
178 // in OmniboxApiTest's Basic test. | 222 // in OmniboxApiTest's Basic test. |
179 | 223 |
180 // Substitution should work with various locations of the "%s". | 224 // Substitution should work with various locations of the "%s". |
181 {ASCIIToUTF16("aaa"), 2, | 225 { ASCIIToUTF16("aaa"), 2, |
182 {ASCIIToUTF16("Search aaaa for <enter query>"), | 226 { { ASCIIToUTF16("Search aaaa for <enter query>"), false }, |
183 ASCIIToUTF16("Search aaaaa for <enter query>")}}, | 227 { ASCIIToUTF16("Search aaaaa for <enter query>"), false }, |
184 {ASCIIToUTF16("www.w w"), 2, | 228 kEmptyMatch} }, |
185 {ASCIIToUTF16("Search www for w"), | 229 { ASCIIToUTF16("www.w w"), 2, |
186 ASCIIToUTF16("Search weasel for w")}}, | 230 { { ASCIIToUTF16("Search www for w"), false }, |
| 231 { ASCIIToUTF16("Search weasel for w"), false }, |
| 232 kEmptyMatch } }, |
187 // Also, check that tokenization only collapses whitespace between first | 233 // Also, check that tokenization only collapses whitespace between first |
188 // tokens and contents are not escaped or unescaped. | 234 // tokens and contents are not escaped or unescaped. |
189 {ASCIIToUTF16("a 1 2+ 3"), 3, | 235 { ASCIIToUTF16("a 1 2+ 3"), 3, |
190 {ASCIIToUTF16("Search aa for 1 2+ 3"), | 236 { { ASCIIToUTF16("Search aa for 1 2+ 3"), false }, |
191 ASCIIToUTF16("Search ab for 1 2+ 3"), | 237 { ASCIIToUTF16("Search ab for 1 2+ 3"), false }, |
192 ASCIIToUTF16("Search aaaa for 1 2+ 3")}}, | 238 { ASCIIToUTF16("Search aaaa for 1 2+ 3"), false } } }, |
193 }; | 239 }; |
194 | 240 |
195 RunTest<string16>(contents_cases, arraysize(contents_cases), | 241 RunTest<string16>(contents_cases, arraysize(contents_cases), |
196 &AutocompleteMatch::contents); | 242 &AutocompleteMatch::contents); |
197 } | 243 } |
198 | 244 |
199 TEST_F(KeywordProviderTest, AddKeyword) { | 245 TEST_F(KeywordProviderTest, AddKeyword) { |
200 TemplateURLData data; | 246 TemplateURLData data; |
201 data.short_name = ASCIIToUTF16("Test"); | 247 data.short_name = ASCIIToUTF16("Test"); |
202 string16 keyword(ASCIIToUTF16("foo")); | 248 string16 keyword(ASCIIToUTF16("foo")); |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
279 EXPECT_EQ(cases[i].updated_cursor_position, input.cursor_position()); | 325 EXPECT_EQ(cases[i].updated_cursor_position, input.cursor_position()); |
280 } | 326 } |
281 } | 327 } |
282 | 328 |
283 // If extra query params are specified on the command line, they should be | 329 // If extra query params are specified on the command line, they should be |
284 // reflected (only) in the default search provider's destination URL. | 330 // reflected (only) in the default search provider's destination URL. |
285 TEST_F(KeywordProviderTest, ExtraQueryParams) { | 331 TEST_F(KeywordProviderTest, ExtraQueryParams) { |
286 CommandLine::ForCurrentProcess()->AppendSwitchASCII( | 332 CommandLine::ForCurrentProcess()->AppendSwitchASCII( |
287 switches::kExtraSearchQueryParams, "a=b"); | 333 switches::kExtraSearchQueryParams, "a=b"); |
288 | 334 |
289 test_data<GURL> url_cases[] = { | 335 TestData<GURL> url_cases[] = { |
290 {ASCIIToUTF16("a 1 2 3"), 3, {GURL("aa.com?a=b&foo=1+2+3"), | 336 { ASCIIToUTF16("a 1 2 3"), 3, |
291 GURL("bogus URL 1+2+3"), | 337 { { GURL("aa.com?a=b&foo=1+2+3"), false }, |
292 GURL("http://aaaa/?aaaa=1&b=1+2+3&c")}}, | 338 { GURL("bogus URL 1+2+3"), false }, |
| 339 { GURL("http://aaaa/?aaaa=1&b=1+2+3&c"), false } } }, |
293 }; | 340 }; |
294 | 341 |
295 RunTest<GURL>(url_cases, arraysize(url_cases), | 342 RunTest<GURL>(url_cases, arraysize(url_cases), |
296 &AutocompleteMatch::destination_url); | 343 &AutocompleteMatch::destination_url); |
297 } | 344 } |
OLD | NEW |