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) { |
72 AutocompleteInput input(keyword_cases[i].input, string16::npos, string16(), | 78 AutocompleteInput input(keyword_cases[i].input, string16::npos, string16(), |
73 GURL(), AutocompleteInput::INVALID_SPEC, true, | 79 GURL(), AutocompleteInput::INVALID_SPEC, true, |
74 false, true, AutocompleteInput::ALL_MATCHES); | 80 false, true, AutocompleteInput::ALL_MATCHES); |
75 kw_provider_->Start(input, false); | 81 kw_provider_->Start(input, false); |
76 EXPECT_TRUE(kw_provider_->done()); | 82 EXPECT_TRUE(kw_provider_->done()); |
77 matches = kw_provider_->matches(); | 83 matches = kw_provider_->matches(); |
78 EXPECT_EQ(keyword_cases[i].num_results, matches.size()) << | 84 const string16 description = |
Peter Kasting
2013/08/06 22:56:16
Nit: Maybe instead of manually adding "<< descript
Mark P
2013/08/07 00:44:31
Done.
| |
79 ASCIIToUTF16("Input was: ") + keyword_cases[i].input; | 85 ASCIIToUTF16("Input was: ") + keyword_cases[i].input; |
86 EXPECT_EQ(keyword_cases[i].num_results, matches.size()) << description; | |
80 if (matches.size() == keyword_cases[i].num_results) { | 87 if (matches.size() == keyword_cases[i].num_results) { |
81 for (size_t j = 0; j < keyword_cases[i].num_results; ++j) { | 88 for (size_t j = 0; j < matches.size(); ++j) { |
82 EXPECT_EQ(keyword_cases[i].output[j], matches[j].*member); | 89 EXPECT_EQ(keyword_cases[i].output[j].member, matches[j].*member) << |
90 description; | |
91 EXPECT_EQ(keyword_cases[i].output[j].allowed_to_be_default_match, | |
92 matches[j].allowed_to_be_default_match) << description; | |
83 } | 93 } |
84 } | 94 } |
85 } | 95 } |
86 } | 96 } |
87 | 97 |
88 TEST_F(KeywordProviderTest, Edit) { | 98 TEST_F(KeywordProviderTest, Edit) { |
89 test_data<string16> edit_cases[] = { | 99 const MatchType<string16> kEmptyMatch = { string16(), false }; |
100 TestData<string16> edit_cases[] = { | |
90 // Searching for a nonexistent prefix should give nothing. | 101 // Searching for a nonexistent prefix should give nothing. |
91 {ASCIIToUTF16("Not Found"), 0, {}}, | 102 { ASCIIToUTF16("Not Found"), 0, |
92 {ASCIIToUTF16("aaaaaNot Found"), 0, {}}, | 103 { kEmptyMatch, kEmptyMatch, kEmptyMatch } }, |
104 { ASCIIToUTF16("aaaaaNot Found"), 0, | |
105 { kEmptyMatch, kEmptyMatch, kEmptyMatch } }, | |
93 | 106 |
94 // Check that tokenization only collapses whitespace between first tokens, | 107 // Check that tokenization only collapses whitespace between first tokens, |
95 // no-query-input cases have a space appended, and action is not escaped. | 108 // no-query-input cases have a space appended, and action is not escaped. |
96 {ASCIIToUTF16("z"), 1, {ASCIIToUTF16("z ")}}, | 109 { ASCIIToUTF16("z"), 1, |
97 {ASCIIToUTF16("z \t"), 1, {ASCIIToUTF16("z ")}}, | 110 { { ASCIIToUTF16("z "), true }, kEmptyMatch, kEmptyMatch } }, |
111 { ASCIIToUTF16("z \t"), 1, | |
112 { { ASCIIToUTF16("z "), true }, kEmptyMatch, kEmptyMatch } }, | |
98 | 113 |
99 // Check that exact, substituting keywords with a verbatim search term | 114 // Check that exact, substituting keywords with a verbatim search term |
100 // don't generate a result. (These are handled by SearchProvider.) | 115 // don't generate a result. (These are handled by SearchProvider.) |
101 {ASCIIToUTF16("z foo"), 0, {}}, | 116 { ASCIIToUTF16("z foo"), 0, |
102 {ASCIIToUTF16("z a b c++"), 0, {}}, | 117 { kEmptyMatch, kEmptyMatch, kEmptyMatch } }, |
118 { ASCIIToUTF16("z a b c++"), 0, | |
119 { kEmptyMatch, kEmptyMatch, kEmptyMatch } }, | |
103 | 120 |
104 // Matches should be limited to three, and sorted in quality order, not | 121 // Matches should be limited to three, and sorted in quality order, not |
105 // alphabetical. | 122 // alphabetical. |
106 {ASCIIToUTF16("aaa"), 2, {ASCIIToUTF16("aaaa "), | 123 { ASCIIToUTF16("aaa"), 2, |
107 ASCIIToUTF16("aaaaa ")}}, | 124 { { ASCIIToUTF16("aaaa "), false }, |
108 {ASCIIToUTF16("a 1 2 3"), 3, {ASCIIToUTF16("aa 1 2 3"), | 125 { ASCIIToUTF16("aaaaa "), false }, |
109 ASCIIToUTF16("ab 1 2 3"), | 126 kEmptyMatch } }, |
110 ASCIIToUTF16("aaaa 1 2 3")}}, | 127 { ASCIIToUTF16("a 1 2 3"), 3, |
111 {ASCIIToUTF16("www.a"), 3, {ASCIIToUTF16("aa "), | 128 { { ASCIIToUTF16("aa 1 2 3"), false }, |
112 ASCIIToUTF16("ab "), | 129 { ASCIIToUTF16("ab 1 2 3"), false }, |
113 ASCIIToUTF16("aaaa ")}}, | 130 { ASCIIToUTF16("aaaa 1 2 3"), false } } }, |
131 { ASCIIToUTF16("www.a"), 3, | |
132 { { ASCIIToUTF16("aa "), false }, | |
133 { ASCIIToUTF16("ab "), false }, | |
134 { ASCIIToUTF16("aaaa "), false } } }, | |
114 // Exact matches should prevent returning inexact matches. Also, the | 135 // Exact matches should prevent returning inexact matches. Also, the |
115 // verbatim query for this keyword match should not be returned. (It's | 136 // verbatim query for this keyword match should not be returned. (It's |
116 // returned by SearchProvider.) | 137 // returned by SearchProvider.) |
117 {ASCIIToUTF16("aaaa foo"), 0, {}}, | 138 { ASCIIToUTF16("aaaa foo"), 0, |
118 {ASCIIToUTF16("www.aaaa foo"), 0, {}}, | 139 { kEmptyMatch, kEmptyMatch, kEmptyMatch } }, |
140 { ASCIIToUTF16("www.aaaa foo"), 0, | |
141 { kEmptyMatch, kEmptyMatch, kEmptyMatch } }, | |
119 | 142 |
120 // Clean up keyword input properly. "http" and "https" are the only | 143 // Clean up keyword input properly. "http" and "https" are the only |
121 // allowed schemes. | 144 // allowed schemes. |
122 {ASCIIToUTF16("www"), 1, {ASCIIToUTF16("www ")}}, | 145 { ASCIIToUTF16("www"), 1, |
123 {ASCIIToUTF16("www."), 0, {}}, | 146 { { ASCIIToUTF16("www "), true }, kEmptyMatch, kEmptyMatch }}, |
124 {ASCIIToUTF16("www.w w"), 2, {ASCIIToUTF16("www w"), | 147 { ASCIIToUTF16("www."), 0, |
125 ASCIIToUTF16("weasel w")}}, | 148 { kEmptyMatch, kEmptyMatch, kEmptyMatch } }, |
126 {ASCIIToUTF16("http://www"), 1, {ASCIIToUTF16("www ")}}, | 149 { ASCIIToUTF16("www.w w"), 2, |
127 {ASCIIToUTF16("http://www."), 0, {}}, | 150 { { ASCIIToUTF16("www w"), false }, |
128 {ASCIIToUTF16("ftp: blah"), 0, {}}, | 151 { ASCIIToUTF16("weasel w"), false }, |
129 {ASCIIToUTF16("mailto:z"), 0, {}}, | 152 kEmptyMatch } }, |
130 {ASCIIToUTF16("ftp://z"), 0, {}}, | 153 { ASCIIToUTF16("http://www"), 1, |
131 {ASCIIToUTF16("https://z"), 1, {ASCIIToUTF16("z ")}}, | 154 { { ASCIIToUTF16("www "), true }, kEmptyMatch, kEmptyMatch } }, |
155 { ASCIIToUTF16("http://www."), 0, | |
156 { kEmptyMatch, kEmptyMatch, kEmptyMatch } }, | |
157 { ASCIIToUTF16("ftp: blah"), 0, | |
158 { kEmptyMatch, kEmptyMatch, kEmptyMatch } }, | |
159 { ASCIIToUTF16("mailto:z"), 0, | |
160 { kEmptyMatch, kEmptyMatch, kEmptyMatch } }, | |
161 { ASCIIToUTF16("ftp://z"), 0, | |
162 { kEmptyMatch, kEmptyMatch, kEmptyMatch } }, | |
163 { ASCIIToUTF16("https://z"), 1, | |
164 { { ASCIIToUTF16("z "), true }, kEmptyMatch, kEmptyMatch } }, | |
132 }; | 165 }; |
133 | 166 |
134 RunTest<string16>(edit_cases, arraysize(edit_cases), | 167 RunTest<string16>(edit_cases, arraysize(edit_cases), |
135 &AutocompleteMatch::fill_into_edit); | 168 &AutocompleteMatch::fill_into_edit); |
136 } | 169 } |
137 | 170 |
138 TEST_F(KeywordProviderTest, URL) { | 171 TEST_F(KeywordProviderTest, URL) { |
139 test_data<GURL> url_cases[] = { | 172 TestData<GURL> url_cases[] = { |
140 // No query input -> empty destination URL. | 173 // No query input -> empty destination URL. |
141 {ASCIIToUTF16("z"), 1, {GURL()}}, | 174 {ASCIIToUTF16("z"), 1, {{GURL(), true}}}, |
142 {ASCIIToUTF16("z \t"), 1, {GURL()}}, | 175 {ASCIIToUTF16("z \t"), 1, {{GURL(), true}}}, |
143 | 176 |
144 // Check that tokenization only collapses whitespace between first tokens | 177 // Check that tokenization only collapses whitespace between first tokens |
145 // and query input, but not rest of URL, is escaped. | 178 // and query input, but not rest of URL, is escaped. |
146 {ASCIIToUTF16("w bar +baz"), 2, {GURL(" +%2B?=bar+%2Bbazfoo "), | 179 {ASCIIToUTF16("w bar +baz"), 2, {{GURL(" +%2B?=bar+%2Bbazfoo "), false}, |
147 GURL("bar+%2Bbaz=z")}}, | 180 {GURL("bar+%2Bbaz=z"), false}}}, |
148 | 181 |
149 // Substitution should work with various locations of the "%s". | 182 // Substitution should work with various locations of the "%s". |
150 {ASCIIToUTF16("aaa 1a2b"), 2, {GURL("http://aaaa/?aaaa=1&b=1a2b&c"), | 183 {ASCIIToUTF16("aaa 1a2b"), 2, |
151 GURL("1a2b")}}, | 184 {{GURL("http://aaaa/?aaaa=1&b=1a2b&c"), false}, |
152 {ASCIIToUTF16("a 1 2 3"), 3, {GURL("aa.com?foo=1+2+3"), | 185 {GURL("1a2b"), false}}}, |
153 GURL("bogus URL 1+2+3"), | 186 {ASCIIToUTF16("a 1 2 3"), 3, |
154 GURL("http://aaaa/?aaaa=1&b=1+2+3&c")}}, | 187 {{GURL("aa.com?foo=1+2+3"), false}, |
155 {ASCIIToUTF16("www.w w"), 2, {GURL(" +%2B?=wfoo "), | 188 {GURL("bogus URL 1+2+3"), false}, |
156 GURL("weaselwweasel")}}, | 189 {GURL("http://aaaa/?aaaa=1&b=1+2+3&c"), false}}}, |
190 {ASCIIToUTF16("www.w w"), 2, {{GURL(" +%2B?=wfoo "), false}, | |
191 {GURL("weaselwweasel"), false}}}, | |
157 }; | 192 }; |
158 | 193 |
159 RunTest<GURL>(url_cases, arraysize(url_cases), | 194 RunTest<GURL>(url_cases, arraysize(url_cases), |
160 &AutocompleteMatch::destination_url); | 195 &AutocompleteMatch::destination_url); |
161 } | 196 } |
162 | 197 |
163 TEST_F(KeywordProviderTest, Contents) { | 198 TEST_F(KeywordProviderTest, Contents) { |
164 test_data<string16> contents_cases[] = { | 199 TestData<string16> contents_cases[] = { |
165 // No query input -> substitute "<enter query>" into contents. | 200 // No query input -> substitute "<enter query>" into contents. |
166 {ASCIIToUTF16("z"), 1, | 201 {ASCIIToUTF16("z"), 1, |
167 {ASCIIToUTF16("Search z for <enter query>")}}, | 202 {{ASCIIToUTF16("Search z for <enter query>"), true}}}, |
168 {ASCIIToUTF16("z \t"), 1, | 203 {ASCIIToUTF16("z \t"), 1, |
169 {ASCIIToUTF16("Search z for <enter query>")}}, | 204 {{ASCIIToUTF16("Search z for <enter query>"), true}}}, |
170 | 205 |
171 // Exact keyword matches with remaining text should return nothing. | 206 // Exact keyword matches with remaining text should return nothing. |
172 {ASCIIToUTF16("www.www www"), 0, {}}, | 207 {ASCIIToUTF16("www.www www"), 0, {}}, |
173 {ASCIIToUTF16("z a b c++"), 0, {}}, | 208 {ASCIIToUTF16("z a b c++"), 0, {}}, |
174 | 209 |
175 // Exact keyword matches with remaining text when the keyword is an | 210 // Exact keyword matches with remaining text when the keyword is an |
176 // extension keyword should return something. This is tested in | 211 // extension keyword should return something. This is tested in |
177 // chrome/browser/extensions/api/omnibox/omnibox_apitest.cc's | 212 // chrome/browser/extensions/api/omnibox/omnibox_apitest.cc's |
178 // in OmniboxApiTest's Basic test. | 213 // in OmniboxApiTest's Basic test. |
179 | 214 |
180 // Substitution should work with various locations of the "%s". | 215 // Substitution should work with various locations of the "%s". |
181 {ASCIIToUTF16("aaa"), 2, | 216 {ASCIIToUTF16("aaa"), 2, |
182 {ASCIIToUTF16("Search aaaa for <enter query>"), | 217 {{ASCIIToUTF16("Search aaaa for <enter query>"), false}, |
183 ASCIIToUTF16("Search aaaaa for <enter query>")}}, | 218 {ASCIIToUTF16("Search aaaaa for <enter query>"), false}}}, |
184 {ASCIIToUTF16("www.w w"), 2, | 219 {ASCIIToUTF16("www.w w"), 2, |
185 {ASCIIToUTF16("Search www for w"), | 220 {{ASCIIToUTF16("Search www for w"), false}, |
186 ASCIIToUTF16("Search weasel for w")}}, | 221 {ASCIIToUTF16("Search weasel for w"), false}}}, |
187 // Also, check that tokenization only collapses whitespace between first | 222 // Also, check that tokenization only collapses whitespace between first |
188 // tokens and contents are not escaped or unescaped. | 223 // tokens and contents are not escaped or unescaped. |
189 {ASCIIToUTF16("a 1 2+ 3"), 3, | 224 {ASCIIToUTF16("a 1 2+ 3"), 3, |
190 {ASCIIToUTF16("Search aa for 1 2+ 3"), | 225 {{ASCIIToUTF16("Search aa for 1 2+ 3"), false}, |
191 ASCIIToUTF16("Search ab for 1 2+ 3"), | 226 {ASCIIToUTF16("Search ab for 1 2+ 3"), false}, |
192 ASCIIToUTF16("Search aaaa for 1 2+ 3")}}, | 227 {ASCIIToUTF16("Search aaaa for 1 2+ 3"), false}}}, |
193 }; | 228 }; |
194 | 229 |
195 RunTest<string16>(contents_cases, arraysize(contents_cases), | 230 RunTest<string16>(contents_cases, arraysize(contents_cases), |
196 &AutocompleteMatch::contents); | 231 &AutocompleteMatch::contents); |
197 } | 232 } |
198 | 233 |
199 TEST_F(KeywordProviderTest, AddKeyword) { | 234 TEST_F(KeywordProviderTest, AddKeyword) { |
200 TemplateURLData data; | 235 TemplateURLData data; |
201 data.short_name = ASCIIToUTF16("Test"); | 236 data.short_name = ASCIIToUTF16("Test"); |
202 string16 keyword(ASCIIToUTF16("foo")); | 237 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()); | 314 EXPECT_EQ(cases[i].updated_cursor_position, input.cursor_position()); |
280 } | 315 } |
281 } | 316 } |
282 | 317 |
283 // If extra query params are specified on the command line, they should be | 318 // If extra query params are specified on the command line, they should be |
284 // reflected (only) in the default search provider's destination URL. | 319 // reflected (only) in the default search provider's destination URL. |
285 TEST_F(KeywordProviderTest, ExtraQueryParams) { | 320 TEST_F(KeywordProviderTest, ExtraQueryParams) { |
286 CommandLine::ForCurrentProcess()->AppendSwitchASCII( | 321 CommandLine::ForCurrentProcess()->AppendSwitchASCII( |
287 switches::kExtraSearchQueryParams, "a=b"); | 322 switches::kExtraSearchQueryParams, "a=b"); |
288 | 323 |
289 test_data<GURL> url_cases[] = { | 324 TestData<GURL> url_cases[] = { |
290 {ASCIIToUTF16("a 1 2 3"), 3, {GURL("aa.com?a=b&foo=1+2+3"), | 325 {ASCIIToUTF16("a 1 2 3"), 3, |
291 GURL("bogus URL 1+2+3"), | 326 {{GURL("aa.com?a=b&foo=1+2+3"), false}, |
292 GURL("http://aaaa/?aaaa=1&b=1+2+3&c")}}, | 327 {GURL("bogus URL 1+2+3"), false}, |
328 {GURL("http://aaaa/?aaaa=1&b=1+2+3&c"), false}}}, | |
293 }; | 329 }; |
294 | 330 |
295 RunTest<GURL>(url_cases, arraysize(url_cases), | 331 RunTest<GURL>(url_cases, arraysize(url_cases), |
296 &AutocompleteMatch::destination_url); | 332 &AutocompleteMatch::destination_url); |
297 } | 333 } |
OLD | NEW |