OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "components/omnibox/browser/history_quick_provider.h" | |
6 | |
7 #include <stddef.h> | |
8 | |
9 #include <algorithm> | |
10 #include <functional> | |
11 #include <set> | |
12 #include <string> | |
13 #include <vector> | |
14 | |
15 #include "base/format_macros.h" | |
16 #include "base/macros.h" | |
17 #include "base/memory/scoped_ptr.h" | |
18 #include "base/message_loop/message_loop.h" | |
19 #include "base/prefs/pref_service.h" | |
20 #include "base/strings/stringprintf.h" | |
21 #include "base/strings/utf_string_conversions.h" | |
22 #include "chrome/browser/autocomplete/chrome_autocomplete_provider_client.h" | |
23 #include "chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.h" | |
24 #include "chrome/browser/autocomplete/in_memory_url_index_factory.h" | |
25 #include "chrome/browser/bookmarks/bookmark_model_factory.h" | |
26 #include "chrome/browser/history/history_service_factory.h" | |
27 #include "chrome/browser/search_engines/chrome_template_url_service_client.h" | |
28 #include "chrome/browser/search_engines/template_url_service_factory.h" | |
29 #include "chrome/test/base/testing_browser_process.h" | |
30 #include "chrome/test/base/testing_profile.h" | |
31 #include "components/bookmarks/test/bookmark_test_helpers.h" | |
32 #include "components/history/core/browser/history_backend.h" | |
33 #include "components/history/core/browser/history_database.h" | |
34 #include "components/history/core/browser/history_service.h" | |
35 #include "components/history/core/browser/history_service_observer.h" | |
36 #include "components/history/core/browser/url_database.h" | |
37 #include "components/metrics/proto/omnibox_event.pb.h" | |
38 #include "components/omnibox/browser/autocomplete_match.h" | |
39 #include "components/omnibox/browser/autocomplete_result.h" | |
40 #include "components/omnibox/browser/history_url_provider.h" | |
41 #include "components/omnibox/browser/in_memory_url_index.h" | |
42 #include "components/omnibox/browser/url_index_private_data.h" | |
43 #include "components/search_engines/search_terms_data.h" | |
44 #include "components/search_engines/template_url.h" | |
45 #include "components/search_engines/template_url_service.h" | |
46 #include "content/public/test/test_browser_thread.h" | |
47 #include "content/public/test/test_utils.h" | |
48 #include "sql/transaction.h" | |
49 #include "testing/gtest/include/gtest/gtest.h" | |
50 | |
51 using base::ASCIIToUTF16; | |
52 using base::Time; | |
53 using base::TimeDelta; | |
54 | |
55 using content::BrowserThread; | |
56 | |
57 namespace { | |
58 | |
59 struct TestURLInfo { | |
60 std::string url; | |
61 std::string title; | |
62 int visit_count; | |
63 int typed_count; | |
64 int days_from_now; | |
65 } quick_test_db[] = { | |
66 {"http://www.google.com/", "Google", 3, 3, 0}, | |
67 {"http://slashdot.org/favorite_page.html", "Favorite page", 200, 100, 0}, | |
68 {"http://kerneltrap.org/not_very_popular.html", "Less popular", 4, 0, 0}, | |
69 {"http://freshmeat.net/unpopular.html", "Unpopular", 1, 1, 0}, | |
70 {"http://news.google.com/?ned=us&topic=n", "Google News - U.S.", 2, 2, 0}, | |
71 {"http://news.google.com/", "Google News", 1, 1, 0}, | |
72 {"http://foo.com/", "Dir", 200, 100, 0}, | |
73 {"http://foo.com/dir/", "Dir", 2, 1, 10}, | |
74 {"http://foo.com/dir/another/", "Dir", 10, 5, 0}, | |
75 {"http://foo.com/dir/another/again/", "Dir", 5, 1, 0}, | |
76 {"http://foo.com/dir/another/again/myfile.html", "File", 3, 1, 0}, | |
77 {"http://visitedest.com/y/a", "VA", 10, 1, 20}, | |
78 {"http://visitedest.com/y/b", "VB", 9, 1, 20}, | |
79 {"http://visitedest.com/x/c", "VC", 8, 1, 20}, | |
80 {"http://visitedest.com/x/d", "VD", 7, 1, 20}, | |
81 {"http://visitedest.com/y/e", "VE", 6, 1, 20}, | |
82 {"http://typeredest.com/y/a", "TA", 5, 5, 0}, | |
83 {"http://typeredest.com/y/b", "TB", 5, 4, 0}, | |
84 {"http://typeredest.com/x/c", "TC", 5, 3, 0}, | |
85 {"http://typeredest.com/x/d", "TD", 5, 2, 0}, | |
86 {"http://typeredest.com/y/e", "TE", 5, 1, 0}, | |
87 {"http://daysagoest.com/y/a", "DA", 1, 1, 0}, | |
88 {"http://daysagoest.com/y/b", "DB", 1, 1, 1}, | |
89 {"http://daysagoest.com/x/c", "DC", 1, 1, 2}, | |
90 {"http://daysagoest.com/x/d", "DD", 1, 1, 3}, | |
91 {"http://daysagoest.com/y/e", "DE", 1, 1, 4}, | |
92 {"http://abcdefghixyzjklmnopqrstuvw.com/a", "", 3, 1, 0}, | |
93 {"http://spaces.com/path%20with%20spaces/foo.html", "Spaces", 2, 2, 0}, | |
94 {"http://abcdefghijklxyzmnopqrstuvw.com/a", "", 3, 1, 0}, | |
95 {"http://abcdefxyzghijklmnopqrstuvw.com/a", "", 3, 1, 0}, | |
96 {"http://abcxyzdefghijklmnopqrstuvw.com/a", "", 3, 1, 0}, | |
97 {"http://xyzabcdefghijklmnopqrstuvw.com/a", "", 3, 1, 0}, | |
98 {"http://cda.com/Dogs%20Cats%20Gorillas%20Sea%20Slugs%20and%20Mice", | |
99 "Dogs & Cats & Mice & Other Animals", 1, 1, 0}, | |
100 {"https://monkeytrap.org/", "", 3, 1, 0}, | |
101 {"http://popularsitewithpathonly.com/moo", | |
102 "popularsitewithpathonly.com/moo", 50, 50, 0}, | |
103 {"http://popularsitewithroot.com/", "popularsitewithroot.com", 50, 50, 0}, | |
104 {"http://testsearch.com/?q=thequery", "Test Search Engine", 10, 10, 0}, | |
105 {"http://testsearch.com/", "Test Search Engine", 9, 9, 0}, | |
106 {"http://anotherengine.com/?q=thequery", "Another Search Engine", 8, 8, 0}, | |
107 // The encoded stuff between /wiki/ and the # is 第二次世界大戦 | |
108 {"http://ja.wikipedia.org/wiki/%E7%AC%AC%E4%BA%8C%E6%AC%A1%E4%B8%96%E7%95" | |
109 "%8C%E5%A4%A7%E6%88%A6#.E3.83.B4.E3.82.A7.E3.83.AB.E3.82.B5.E3.82.A4.E3." | |
110 "83.A6.E4.BD.93.E5.88.B6", "Title Unimportant", 2, 2, 0} | |
111 }; | |
112 | |
113 // Waits for OnURLsDeletedNotification and when run quits the supplied run loop. | |
114 class WaitForURLsDeletedObserver : public history::HistoryServiceObserver { | |
115 public: | |
116 explicit WaitForURLsDeletedObserver(base::RunLoop* runner); | |
117 ~WaitForURLsDeletedObserver() override; | |
118 | |
119 private: | |
120 // history::HistoryServiceObserver: | |
121 void OnURLsDeleted(history::HistoryService* service, | |
122 bool all_history, | |
123 bool expired, | |
124 const history::URLRows& deleted_rows, | |
125 const std::set<GURL>& favicon_urls) override; | |
126 | |
127 // Weak. Owned by our owner. | |
128 base::RunLoop* runner_; | |
129 | |
130 DISALLOW_COPY_AND_ASSIGN(WaitForURLsDeletedObserver); | |
131 }; | |
132 | |
133 WaitForURLsDeletedObserver::WaitForURLsDeletedObserver(base::RunLoop* runner) | |
134 : runner_(runner) { | |
135 } | |
136 | |
137 WaitForURLsDeletedObserver::~WaitForURLsDeletedObserver() { | |
138 } | |
139 | |
140 void WaitForURLsDeletedObserver::OnURLsDeleted( | |
141 history::HistoryService* service, | |
142 bool all_history, | |
143 bool expired, | |
144 const history::URLRows& deleted_rows, | |
145 const std::set<GURL>& favicon_urls) { | |
146 runner_->Quit(); | |
147 } | |
148 | |
149 void WaitForURLsDeletedNotification(history::HistoryService* history_service) { | |
150 base::RunLoop runner; | |
151 WaitForURLsDeletedObserver observer(&runner); | |
152 ScopedObserver<history::HistoryService, history::HistoryServiceObserver> | |
153 scoped_observer(&observer); | |
154 scoped_observer.Add(history_service); | |
155 runner.Run(); | |
156 } | |
157 | |
158 // Post history_backend->GetURL() to the history thread and stop the originating | |
159 // thread's message loop when done. | |
160 class GetURLTask : public history::HistoryDBTask { | |
161 public: | |
162 GetURLTask(const GURL& url, bool* result_storage) | |
163 : result_storage_(result_storage), | |
164 url_(url) { | |
165 } | |
166 | |
167 bool RunOnDBThread(history::HistoryBackend* backend, | |
168 history::HistoryDatabase* db) override { | |
169 *result_storage_ = backend->GetURL(url_, NULL); | |
170 return true; | |
171 } | |
172 | |
173 void DoneRunOnMainThread() override { | |
174 base::MessageLoop::current()->QuitWhenIdle(); | |
175 } | |
176 | |
177 private: | |
178 ~GetURLTask() override {} | |
179 | |
180 bool* result_storage_; | |
181 const GURL url_; | |
182 | |
183 DISALLOW_COPY_AND_ASSIGN(GetURLTask); | |
184 }; | |
185 | |
186 } // namespace | |
187 | |
188 class HistoryQuickProviderTest : public testing::Test { | |
189 public: | |
190 HistoryQuickProviderTest() | |
191 : ui_thread_(BrowserThread::UI, &message_loop_), | |
192 file_thread_(BrowserThread::FILE, &message_loop_) {} | |
193 | |
194 protected: | |
195 class SetShouldContain : public std::unary_function<const std::string&, | |
196 std::set<std::string> > { | |
197 public: | |
198 explicit SetShouldContain(const ACMatches& matched_urls); | |
199 | |
200 void operator()(const std::string& expected); | |
201 | |
202 std::set<std::string> LeftOvers() const { return matches_; } | |
203 | |
204 private: | |
205 std::set<std::string> matches_; | |
206 }; | |
207 | |
208 static scoped_ptr<KeyedService> CreateTemplateURLService( | |
209 content::BrowserContext* context) { | |
210 Profile* profile = static_cast<Profile*>(context); | |
211 return make_scoped_ptr(new TemplateURLService( | |
212 profile->GetPrefs(), make_scoped_ptr(new SearchTermsData), NULL, | |
213 scoped_ptr<TemplateURLServiceClient>(new ChromeTemplateURLServiceClient( | |
214 HistoryServiceFactory::GetForProfile( | |
215 profile, ServiceAccessType::EXPLICIT_ACCESS))), | |
216 NULL, NULL, base::Closure())); | |
217 } | |
218 | |
219 void SetUp() override; | |
220 void TearDown() override; | |
221 | |
222 virtual void GetTestData(size_t* data_count, TestURLInfo** test_data); | |
223 | |
224 // Fills test data into the history system. | |
225 void FillData(); | |
226 | |
227 // Runs an autocomplete query on |text| and checks to see that the returned | |
228 // results' destination URLs match those provided. |expected_urls| does not | |
229 // need to be in sorted order. | |
230 void RunTest(const base::string16 text, | |
231 bool prevent_inline_autocomplete, | |
232 std::vector<std::string> expected_urls, | |
233 bool can_inline_top_result, | |
234 base::string16 expected_fill_into_edit, | |
235 base::string16 autocompletion); | |
236 | |
237 // As above, simply with a cursor position specified. | |
238 void RunTestWithCursor(const base::string16 text, | |
239 const size_t cursor_position, | |
240 bool prevent_inline_autocomplete, | |
241 std::vector<std::string> expected_urls, | |
242 bool can_inline_top_result, | |
243 base::string16 expected_fill_into_edit, | |
244 base::string16 autocompletion); | |
245 | |
246 // TODO(shess): From history_service.h in reference to history_backend: | |
247 // > This class has most of the implementation and runs on the 'thread_'. | |
248 // > You MUST communicate with this class ONLY through the thread_'s | |
249 // > message_loop(). | |
250 // Direct use of this object in tests is almost certainly not thread-safe. | |
251 history::HistoryBackend* history_backend() { | |
252 return history_service_->history_backend_.get(); | |
253 } | |
254 | |
255 // Call history_backend()->GetURL(url, NULL) on the history thread, returning | |
256 // the result. | |
257 bool GetURLProxy(const GURL& url); | |
258 | |
259 base::MessageLoopForUI message_loop_; | |
260 content::TestBrowserThread ui_thread_; | |
261 content::TestBrowserThread file_thread_; | |
262 | |
263 scoped_ptr<TestingProfile> profile_; | |
264 scoped_ptr<ChromeAutocompleteProviderClient> client_; | |
265 history::HistoryService* history_service_; | |
266 | |
267 ACMatches ac_matches_; // The resulting matches after running RunTest. | |
268 | |
269 scoped_refptr<HistoryQuickProvider> provider_; | |
270 }; | |
271 | |
272 void HistoryQuickProviderTest::SetUp() { | |
273 profile_.reset(new TestingProfile()); | |
274 client_.reset(new ChromeAutocompleteProviderClient(profile_.get())); | |
275 ASSERT_TRUE(profile_->CreateHistoryService(true, false)); | |
276 profile_->CreateBookmarkModel(true); | |
277 bookmarks::test::WaitForBookmarkModelToLoad( | |
278 BookmarkModelFactory::GetForProfile(profile_.get())); | |
279 profile_->BlockUntilHistoryIndexIsRefreshed(); | |
280 // History index refresh creates rebuilt tasks to run on history thread. | |
281 // Block here to make sure that all of them are complete. | |
282 profile_->BlockUntilHistoryProcessesPendingRequests(); | |
283 history_service_ = HistoryServiceFactory::GetForProfile( | |
284 profile_.get(), ServiceAccessType::EXPLICIT_ACCESS); | |
285 EXPECT_TRUE(history_service_); | |
286 provider_ = new HistoryQuickProvider(client_.get()); | |
287 TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse( | |
288 profile_.get(), &HistoryQuickProviderTest::CreateTemplateURLService); | |
289 FillData(); | |
290 InMemoryURLIndex* index = | |
291 InMemoryURLIndexFactory::GetForProfile(profile_.get()); | |
292 EXPECT_TRUE(index); | |
293 index->RebuildFromHistory(history_backend()->db()); | |
294 } | |
295 | |
296 void HistoryQuickProviderTest::TearDown() { | |
297 provider_ = NULL; | |
298 // History index rebuild task is created from main thread during SetUp, | |
299 // performed on DB thread and must be deleted on main thread. | |
300 // Run main loop to process delete task, to prevent leaks. | |
301 base::MessageLoop::current()->RunUntilIdle(); | |
302 } | |
303 | |
304 void HistoryQuickProviderTest::GetTestData(size_t* data_count, | |
305 TestURLInfo** test_data) { | |
306 DCHECK(data_count); | |
307 DCHECK(test_data); | |
308 *data_count = arraysize(quick_test_db); | |
309 *test_data = &quick_test_db[0]; | |
310 } | |
311 | |
312 void HistoryQuickProviderTest::FillData() { | |
313 sql::Connection& db(history_backend()->db()->GetDB()); | |
314 ASSERT_TRUE(db.is_open()); | |
315 | |
316 size_t data_count = 0; | |
317 TestURLInfo* test_data = NULL; | |
318 GetTestData(&data_count, &test_data); | |
319 size_t visit_id = 1; | |
320 for (size_t i = 0; i < data_count; ++i) { | |
321 const TestURLInfo& cur(test_data[i]); | |
322 Time visit_time = Time::Now() - TimeDelta::FromDays(cur.days_from_now); | |
323 sql::Transaction transaction(&db); | |
324 | |
325 // Add URL. | |
326 transaction.Begin(); | |
327 std::string sql_cmd_line = base::StringPrintf( | |
328 "INSERT INTO \"urls\" VALUES(%" PRIuS ", \'%s\', \'%s\', %d, %d, %" | |
329 PRId64 ", 0, 0)", | |
330 i + 1, cur.url.c_str(), cur.title.c_str(), cur.visit_count, | |
331 cur.typed_count, visit_time.ToInternalValue()); | |
332 sql::Statement sql_stmt(db.GetUniqueStatement(sql_cmd_line.c_str())); | |
333 EXPECT_TRUE(sql_stmt.Run()); | |
334 transaction.Commit(); | |
335 | |
336 // Add visits. | |
337 for (int j = 0; j < cur.visit_count; ++j) { | |
338 // Assume earlier visits are at one-day intervals. | |
339 visit_time -= TimeDelta::FromDays(1); | |
340 transaction.Begin(); | |
341 // Mark the most recent |cur.typed_count| visits as typed. | |
342 std::string sql_cmd_line = base::StringPrintf( | |
343 "INSERT INTO \"visits\" VALUES(%" PRIuS ", %" PRIuS ", %" PRId64 | |
344 ", 0, %d, 0, 1)", | |
345 visit_id++, i + 1, visit_time.ToInternalValue(), | |
346 (j < cur.typed_count) ? ui::PAGE_TRANSITION_TYPED : | |
347 ui::PAGE_TRANSITION_LINK); | |
348 | |
349 sql::Statement sql_stmt(db.GetUniqueStatement(sql_cmd_line.c_str())); | |
350 EXPECT_TRUE(sql_stmt.Run()); | |
351 transaction.Commit(); | |
352 } | |
353 } | |
354 } | |
355 | |
356 HistoryQuickProviderTest::SetShouldContain::SetShouldContain( | |
357 const ACMatches& matched_urls) { | |
358 for (ACMatches::const_iterator iter = matched_urls.begin(); | |
359 iter != matched_urls.end(); ++iter) | |
360 matches_.insert(iter->destination_url.spec()); | |
361 } | |
362 | |
363 void HistoryQuickProviderTest::SetShouldContain::operator()( | |
364 const std::string& expected) { | |
365 EXPECT_EQ(1U, matches_.erase(expected)) | |
366 << "Results did not contain '" << expected << "' but should have."; | |
367 } | |
368 | |
369 void HistoryQuickProviderTest::RunTest( | |
370 const base::string16 text, | |
371 bool prevent_inline_autocomplete, | |
372 std::vector<std::string> expected_urls, | |
373 bool can_inline_top_result, | |
374 base::string16 expected_fill_into_edit, | |
375 base::string16 expected_autocompletion) { | |
376 RunTestWithCursor(text, base::string16::npos, prevent_inline_autocomplete, | |
377 expected_urls, can_inline_top_result, | |
378 expected_fill_into_edit, expected_autocompletion); | |
379 } | |
380 | |
381 void HistoryQuickProviderTest::RunTestWithCursor( | |
382 const base::string16 text, | |
383 const size_t cursor_position, | |
384 bool prevent_inline_autocomplete, | |
385 std::vector<std::string> expected_urls, | |
386 bool can_inline_top_result, | |
387 base::string16 expected_fill_into_edit, | |
388 base::string16 expected_autocompletion) { | |
389 SCOPED_TRACE(text); // Minimal hint to query being run. | |
390 base::MessageLoop::current()->RunUntilIdle(); | |
391 AutocompleteInput input(text, cursor_position, std::string(), GURL(), | |
392 metrics::OmniboxEventProto::INVALID_SPEC, | |
393 prevent_inline_autocomplete, false, true, true, false, | |
394 ChromeAutocompleteSchemeClassifier(profile_.get())); | |
395 provider_->Start(input, false); | |
396 EXPECT_TRUE(provider_->done()); | |
397 | |
398 ac_matches_ = provider_->matches(); | |
399 | |
400 // We should have gotten back at most AutocompleteProvider::kMaxMatches. | |
401 EXPECT_LE(ac_matches_.size(), AutocompleteProvider::kMaxMatches); | |
402 | |
403 // If the number of expected and actual matches aren't equal then we need | |
404 // test no further, but let's do anyway so that we know which URLs failed. | |
405 EXPECT_EQ(expected_urls.size(), ac_matches_.size()); | |
406 | |
407 // Verify that all expected URLs were found and that all found URLs | |
408 // were expected. | |
409 std::set<std::string> leftovers = | |
410 for_each(expected_urls.begin(), expected_urls.end(), | |
411 SetShouldContain(ac_matches_)).LeftOvers(); | |
412 EXPECT_EQ(0U, leftovers.size()) << "There were " << leftovers.size() | |
413 << " unexpected results, one of which was: '" | |
414 << *(leftovers.begin()) << "'."; | |
415 | |
416 if (expected_urls.empty()) | |
417 return; | |
418 | |
419 // Verify that we got the results in the order expected. | |
420 int best_score = ac_matches_.begin()->relevance + 1; | |
421 int i = 0; | |
422 std::vector<std::string>::const_iterator expected = expected_urls.begin(); | |
423 for (ACMatches::const_iterator actual = ac_matches_.begin(); | |
424 actual != ac_matches_.end() && expected != expected_urls.end(); | |
425 ++actual, ++expected, ++i) { | |
426 EXPECT_EQ(*expected, actual->destination_url.spec()) | |
427 << "For result #" << i << " we got '" << actual->destination_url.spec() | |
428 << "' but expected '" << *expected << "'."; | |
429 EXPECT_LT(actual->relevance, best_score) | |
430 << "At result #" << i << " (url=" << actual->destination_url.spec() | |
431 << "), we noticed scores are not monotonically decreasing."; | |
432 best_score = actual->relevance; | |
433 } | |
434 | |
435 EXPECT_EQ(can_inline_top_result, ac_matches_[0].allowed_to_be_default_match); | |
436 if (can_inline_top_result) | |
437 EXPECT_EQ(expected_autocompletion, ac_matches_[0].inline_autocompletion); | |
438 EXPECT_EQ(expected_fill_into_edit, ac_matches_[0].fill_into_edit); | |
439 } | |
440 | |
441 bool HistoryQuickProviderTest::GetURLProxy(const GURL& url) { | |
442 base::CancelableTaskTracker task_tracker; | |
443 bool result = false; | |
444 history_service_->ScheduleDBTask( | |
445 scoped_ptr<history::HistoryDBTask>(new GetURLTask(url, &result)), | |
446 &task_tracker); | |
447 // Run the message loop until GetURLTask::DoneRunOnMainThread stops it. If | |
448 // the test hangs, DoneRunOnMainThread isn't being invoked correctly. | |
449 base::MessageLoop::current()->Run(); | |
450 return result; | |
451 } | |
452 | |
453 TEST_F(HistoryQuickProviderTest, SimpleSingleMatch) { | |
454 std::vector<std::string> expected_urls; | |
455 expected_urls.push_back("http://slashdot.org/favorite_page.html"); | |
456 RunTest(ASCIIToUTF16("slashdot"), false, expected_urls, true, | |
457 ASCIIToUTF16("slashdot.org/favorite_page.html"), | |
458 ASCIIToUTF16(".org/favorite_page.html")); | |
459 } | |
460 | |
461 TEST_F(HistoryQuickProviderTest, SingleMatchWithCursor) { | |
462 std::vector<std::string> expected_urls; | |
463 expected_urls.push_back("http://slashdot.org/favorite_page.html"); | |
464 // With cursor after "slash", we should retrieve the desired result but it | |
465 // should not be allowed to be the default match. | |
466 RunTestWithCursor(ASCIIToUTF16("slashfavorite_page.html"), 5, false, | |
467 expected_urls, false, | |
468 ASCIIToUTF16("slashdot.org/favorite_page.html"), | |
469 base::string16()); | |
470 } | |
471 | |
472 TEST_F(HistoryQuickProviderTest, WordBoundariesWithPunctuationMatch) { | |
473 std::vector<std::string> expected_urls; | |
474 expected_urls.push_back("http://popularsitewithpathonly.com/moo"); | |
475 RunTest(ASCIIToUTF16("/moo"), false, expected_urls, false, | |
476 ASCIIToUTF16("popularsitewithpathonly.com/moo"), base::string16()); | |
477 } | |
478 | |
479 TEST_F(HistoryQuickProviderTest, MultiTermTitleMatch) { | |
480 std::vector<std::string> expected_urls; | |
481 expected_urls.push_back( | |
482 "http://cda.com/Dogs%20Cats%20Gorillas%20Sea%20Slugs%20and%20Mice"); | |
483 RunTest(ASCIIToUTF16("mice other animals"), false, expected_urls, false, | |
484 ASCIIToUTF16("cda.com/Dogs Cats Gorillas Sea Slugs and Mice"), | |
485 base::string16()); | |
486 } | |
487 | |
488 TEST_F(HistoryQuickProviderTest, NonWordLastCharacterMatch) { | |
489 std::string expected_url("http://slashdot.org/favorite_page.html"); | |
490 std::vector<std::string> expected_urls; | |
491 expected_urls.push_back(expected_url); | |
492 RunTest(ASCIIToUTF16("slashdot.org/"), false, expected_urls, true, | |
493 ASCIIToUTF16("slashdot.org/favorite_page.html"), | |
494 ASCIIToUTF16("favorite_page.html")); | |
495 } | |
496 | |
497 TEST_F(HistoryQuickProviderTest, MultiMatch) { | |
498 std::vector<std::string> expected_urls; | |
499 // Scores high because of typed_count. | |
500 expected_urls.push_back("http://foo.com/"); | |
501 // Scores high because of visit count. | |
502 expected_urls.push_back("http://foo.com/dir/another/"); | |
503 // Scores high because of high visit count. | |
504 expected_urls.push_back("http://foo.com/dir/another/again/"); | |
505 RunTest(ASCIIToUTF16("foo"), false, expected_urls, true, | |
506 ASCIIToUTF16("foo.com"), ASCIIToUTF16(".com")); | |
507 } | |
508 | |
509 TEST_F(HistoryQuickProviderTest, StartRelativeMatch) { | |
510 std::vector<std::string> expected_urls; | |
511 expected_urls.push_back("http://xyzabcdefghijklmnopqrstuvw.com/a"); | |
512 RunTest(ASCIIToUTF16("xyza"), false, expected_urls, true, | |
513 ASCIIToUTF16("xyzabcdefghijklmnopqrstuvw.com/a"), | |
514 ASCIIToUTF16("bcdefghijklmnopqrstuvw.com/a")); | |
515 } | |
516 | |
517 TEST_F(HistoryQuickProviderTest, EncodingMatch) { | |
518 std::vector<std::string> expected_urls; | |
519 expected_urls.push_back("http://spaces.com/path%20with%20spaces/foo.html"); | |
520 RunTest(ASCIIToUTF16("path with spaces"), false, expected_urls, false, | |
521 ASCIIToUTF16("spaces.com/path with spaces/foo.html"), | |
522 base::string16()); | |
523 } | |
524 | |
525 TEST_F(HistoryQuickProviderTest, ContentsClass) { | |
526 std::vector<std::string> expected_urls; | |
527 expected_urls.push_back( | |
528 "http://ja.wikipedia.org/wiki/%E7%AC%AC%E4%BA%8C%E6%AC%A1%E4%B8%96%E7" | |
529 "%95%8C%E5%A4%A7%E6%88%A6#.E3.83.B4.E3.82.A7.E3.83.AB.E3.82.B5.E3.82." | |
530 "A4.E3.83.A6.E4.BD.93.E5.88.B6"); | |
531 RunTest(base::UTF8ToUTF16("第二 e3"), false, expected_urls, false, | |
532 base::UTF8ToUTF16("ja.wikipedia.org/wiki/第二次世界大戦#.E3.83.B4.E3." | |
533 "82.A7.E3.83.AB.E3.82.B5.E3.82.A4.E3.83.A6.E4.BD." | |
534 "93.E5.88.B6"), | |
535 base::string16()); | |
536 #ifndef NDEBUG | |
537 ac_matches_[0].Validate(); | |
538 #endif | |
539 // Verify that contents_class divides the string in the right places. | |
540 // [22, 24) is the "第二". All the other pairs are the "e3". | |
541 ACMatchClassifications contents_class(ac_matches_[0].contents_class); | |
542 size_t expected_offsets[] = { 0, 22, 24, 31, 33, 40, 42, 49, 51, 58, 60, 67, | |
543 69, 76, 78 }; | |
544 // ScoredHistoryMatch may not highlight all the occurrences of these terms | |
545 // because it only highlights terms at word breaks, and it only stores word | |
546 // breaks up to some specified number of characters (50 at the time of this | |
547 // comment). This test is written flexibly so it still will pass if we | |
548 // increase that number in the future. Regardless, we require the first | |
549 // five offsets to be correct--in this example these cover at least one | |
550 // occurrence of each term. | |
551 EXPECT_LE(contents_class.size(), arraysize(expected_offsets)); | |
552 EXPECT_GE(contents_class.size(), 5u); | |
553 for (size_t i = 0; i < contents_class.size(); ++i) | |
554 EXPECT_EQ(expected_offsets[i], contents_class[i].offset); | |
555 } | |
556 | |
557 TEST_F(HistoryQuickProviderTest, VisitCountMatches) { | |
558 std::vector<std::string> expected_urls; | |
559 expected_urls.push_back("http://visitedest.com/y/a"); | |
560 expected_urls.push_back("http://visitedest.com/y/b"); | |
561 expected_urls.push_back("http://visitedest.com/x/c"); | |
562 RunTest(ASCIIToUTF16("visitedest"), false, expected_urls, true, | |
563 ASCIIToUTF16("visitedest.com/y/a"), | |
564 ASCIIToUTF16(".com/y/a")); | |
565 } | |
566 | |
567 TEST_F(HistoryQuickProviderTest, TypedCountMatches) { | |
568 std::vector<std::string> expected_urls; | |
569 expected_urls.push_back("http://typeredest.com/y/a"); | |
570 expected_urls.push_back("http://typeredest.com/y/b"); | |
571 expected_urls.push_back("http://typeredest.com/x/c"); | |
572 RunTest(ASCIIToUTF16("typeredest"), false, expected_urls, true, | |
573 ASCIIToUTF16("typeredest.com/y/a"), | |
574 ASCIIToUTF16(".com/y/a")); | |
575 } | |
576 | |
577 TEST_F(HistoryQuickProviderTest, DaysAgoMatches) { | |
578 std::vector<std::string> expected_urls; | |
579 expected_urls.push_back("http://daysagoest.com/y/a"); | |
580 expected_urls.push_back("http://daysagoest.com/y/b"); | |
581 expected_urls.push_back("http://daysagoest.com/x/c"); | |
582 RunTest(ASCIIToUTF16("daysagoest"), false, expected_urls, true, | |
583 ASCIIToUTF16("daysagoest.com/y/a"), | |
584 ASCIIToUTF16(".com/y/a")); | |
585 } | |
586 | |
587 TEST_F(HistoryQuickProviderTest, EncodingLimitMatch) { | |
588 std::vector<std::string> expected_urls; | |
589 std::string url( | |
590 "http://cda.com/Dogs%20Cats%20Gorillas%20Sea%20Slugs%20and%20Mice"); | |
591 // First check that a mid-word match yield no results. | |
592 RunTest(ASCIIToUTF16("ice"), false, expected_urls, false, | |
593 ASCIIToUTF16("cda.com/Dogs Cats Gorillas Sea Slugs and Mice"), | |
594 base::string16()); | |
595 // Then check that we get results when the match is at a word start | |
596 // that is present because of an encoded separate (%20 = space). | |
597 expected_urls.push_back(url); | |
598 RunTest(ASCIIToUTF16("Mice"), false, expected_urls, false, | |
599 ASCIIToUTF16("cda.com/Dogs Cats Gorillas Sea Slugs and Mice"), | |
600 base::string16()); | |
601 // Verify that the matches' ACMatchClassifications offsets are in range. | |
602 ACMatchClassifications content(ac_matches_[0].contents_class); | |
603 // The max offset accounts for 6 occurrences of '%20' plus the 'http://'. | |
604 const size_t max_offset = url.length() - ((6 * 2) + 7); | |
605 for (ACMatchClassifications::const_iterator citer = content.begin(); | |
606 citer != content.end(); ++citer) | |
607 EXPECT_LT(citer->offset, max_offset); | |
608 ACMatchClassifications description(ac_matches_[0].description_class); | |
609 std::string page_title("Dogs & Cats & Mice & Other Animals"); | |
610 for (ACMatchClassifications::const_iterator diter = description.begin(); | |
611 diter != description.end(); ++diter) | |
612 EXPECT_LT(diter->offset, page_title.length()); | |
613 } | |
614 | |
615 TEST_F(HistoryQuickProviderTest, Spans) { | |
616 // Test SpansFromTermMatch | |
617 TermMatches matches_a; | |
618 // Simulates matches: '.xx.xxx..xx...xxxxx..' which will test no match at | |
619 // either beginning or end as well as adjacent matches. | |
620 matches_a.push_back(TermMatch(1, 1, 2)); | |
621 matches_a.push_back(TermMatch(2, 4, 3)); | |
622 matches_a.push_back(TermMatch(3, 9, 1)); | |
623 matches_a.push_back(TermMatch(3, 10, 1)); | |
624 matches_a.push_back(TermMatch(4, 14, 5)); | |
625 ACMatchClassifications spans_a = | |
626 HistoryQuickProvider::SpansFromTermMatch(matches_a, 20, false); | |
627 // ACMatch spans should be: 'NM-NM---N-M-N--M----N-' | |
628 ASSERT_EQ(9U, spans_a.size()); | |
629 EXPECT_EQ(0U, spans_a[0].offset); | |
630 EXPECT_EQ(ACMatchClassification::NONE, spans_a[0].style); | |
631 EXPECT_EQ(1U, spans_a[1].offset); | |
632 EXPECT_EQ(ACMatchClassification::MATCH, spans_a[1].style); | |
633 EXPECT_EQ(3U, spans_a[2].offset); | |
634 EXPECT_EQ(ACMatchClassification::NONE, spans_a[2].style); | |
635 EXPECT_EQ(4U, spans_a[3].offset); | |
636 EXPECT_EQ(ACMatchClassification::MATCH, spans_a[3].style); | |
637 EXPECT_EQ(7U, spans_a[4].offset); | |
638 EXPECT_EQ(ACMatchClassification::NONE, spans_a[4].style); | |
639 EXPECT_EQ(9U, spans_a[5].offset); | |
640 EXPECT_EQ(ACMatchClassification::MATCH, spans_a[5].style); | |
641 EXPECT_EQ(11U, spans_a[6].offset); | |
642 EXPECT_EQ(ACMatchClassification::NONE, spans_a[6].style); | |
643 EXPECT_EQ(14U, spans_a[7].offset); | |
644 EXPECT_EQ(ACMatchClassification::MATCH, spans_a[7].style); | |
645 EXPECT_EQ(19U, spans_a[8].offset); | |
646 EXPECT_EQ(ACMatchClassification::NONE, spans_a[8].style); | |
647 // Simulates matches: 'xx.xx' which will test matches at both beginning and | |
648 // end. | |
649 TermMatches matches_b; | |
650 matches_b.push_back(TermMatch(1, 0, 2)); | |
651 matches_b.push_back(TermMatch(2, 3, 2)); | |
652 ACMatchClassifications spans_b = | |
653 HistoryQuickProvider::SpansFromTermMatch(matches_b, 5, true); | |
654 // ACMatch spans should be: 'M-NM-' | |
655 ASSERT_EQ(3U, spans_b.size()); | |
656 EXPECT_EQ(0U, spans_b[0].offset); | |
657 EXPECT_EQ(ACMatchClassification::MATCH | ACMatchClassification::URL, | |
658 spans_b[0].style); | |
659 EXPECT_EQ(2U, spans_b[1].offset); | |
660 EXPECT_EQ(ACMatchClassification::URL, spans_b[1].style); | |
661 EXPECT_EQ(3U, spans_b[2].offset); | |
662 EXPECT_EQ(ACMatchClassification::MATCH | ACMatchClassification::URL, | |
663 spans_b[2].style); | |
664 } | |
665 | |
666 TEST_F(HistoryQuickProviderTest, DeleteMatch) { | |
667 GURL test_url("http://slashdot.org/favorite_page.html"); | |
668 std::vector<std::string> expected_urls; | |
669 expected_urls.push_back(test_url.spec()); | |
670 // Fill up ac_matches_; we don't really care about the test yet. | |
671 RunTest(ASCIIToUTF16("slashdot"), false, expected_urls, true, | |
672 ASCIIToUTF16("slashdot.org/favorite_page.html"), | |
673 ASCIIToUTF16(".org/favorite_page.html")); | |
674 EXPECT_EQ(1U, ac_matches_.size()); | |
675 EXPECT_TRUE(GetURLProxy(test_url)); | |
676 provider_->DeleteMatch(ac_matches_[0]); | |
677 | |
678 // Check that the underlying URL is deleted from the history DB (this implies | |
679 // that all visits are gone as well). Also verify that a deletion notification | |
680 // is sent, in response to which the secondary data stores (InMemoryDatabase, | |
681 // InMemoryURLIndex) will drop any data they might have pertaining to the URL. | |
682 // To ensure that the deletion has been propagated everywhere before we start | |
683 // verifying post-deletion states, first wait until we see the notification. | |
684 WaitForURLsDeletedNotification(history_service_); | |
685 EXPECT_FALSE(GetURLProxy(test_url)); | |
686 | |
687 // Just to be on the safe side, explicitly verify that we have deleted enough | |
688 // data so that we will not be serving the same result again. | |
689 expected_urls.clear(); | |
690 RunTest(ASCIIToUTF16("slashdot"), false, expected_urls, true, | |
691 ASCIIToUTF16("NONE EXPECTED"), base::string16()); | |
692 } | |
693 | |
694 TEST_F(HistoryQuickProviderTest, PreventBeatingURLWhatYouTypedMatch) { | |
695 std::vector<std::string> expected_urls; | |
696 | |
697 expected_urls.clear(); | |
698 expected_urls.push_back("http://popularsitewithroot.com/"); | |
699 // If the user enters a hostname (no path) that they have visited | |
700 // before, we should make sure that all HistoryQuickProvider results | |
701 // have scores less than what HistoryURLProvider will assign the | |
702 // URL-what-you-typed match. | |
703 RunTest(ASCIIToUTF16("popularsitewithroot.com"), false, expected_urls, true, | |
704 ASCIIToUTF16("popularsitewithroot.com"), base::string16()); | |
705 EXPECT_LT(ac_matches_[0].relevance, | |
706 HistoryURLProvider::kScoreForBestInlineableResult); | |
707 | |
708 // Check that if the user didn't quite enter the full hostname, this | |
709 // hostname would've normally scored above the URL-what-you-typed match. | |
710 RunTest(ASCIIToUTF16("popularsitewithroot.c"), false, expected_urls, true, | |
711 ASCIIToUTF16("popularsitewithroot.com"), | |
712 ASCIIToUTF16("om")); | |
713 EXPECT_GE(ac_matches_[0].relevance, | |
714 HistoryURLProvider::kScoreForWhatYouTypedResult); | |
715 | |
716 expected_urls.clear(); | |
717 expected_urls.push_back("http://popularsitewithpathonly.com/moo"); | |
718 // If the user enters a hostname of a host that they have visited | |
719 // but never visited the root page of, we should make sure that all | |
720 // HistoryQuickProvider results have scores less than what the | |
721 // HistoryURLProvider will assign the URL-what-you-typed match. | |
722 RunTest(ASCIIToUTF16("popularsitewithpathonly.com"), false, expected_urls, | |
723 true, | |
724 ASCIIToUTF16("popularsitewithpathonly.com/moo"), | |
725 ASCIIToUTF16("/moo")); | |
726 EXPECT_LT(ac_matches_[0].relevance, | |
727 HistoryURLProvider::kScoreForUnvisitedIntranetResult); | |
728 | |
729 // Verify the same thing happens if the user adds a / to end of the | |
730 // hostname. | |
731 RunTest(ASCIIToUTF16("popularsitewithpathonly.com/"), false, expected_urls, | |
732 true, ASCIIToUTF16("popularsitewithpathonly.com/moo"), | |
733 ASCIIToUTF16("moo")); | |
734 EXPECT_LT(ac_matches_[0].relevance, | |
735 HistoryURLProvider::kScoreForUnvisitedIntranetResult); | |
736 | |
737 // Check that if the user didn't quite enter the full hostname, this | |
738 // page would've normally scored above the URL-what-you-typed match. | |
739 RunTest(ASCIIToUTF16("popularsitewithpathonly.co"), false, expected_urls, | |
740 true, ASCIIToUTF16("popularsitewithpathonly.com/moo"), | |
741 ASCIIToUTF16("m/moo")); | |
742 EXPECT_GE(ac_matches_[0].relevance, | |
743 HistoryURLProvider::kScoreForWhatYouTypedResult); | |
744 | |
745 // If the user enters a hostname + path that they have not visited | |
746 // before (but visited other things on the host), we can allow | |
747 // inline autocompletions. | |
748 RunTest(ASCIIToUTF16("popularsitewithpathonly.com/mo"), false, expected_urls, | |
749 true, | |
750 ASCIIToUTF16("popularsitewithpathonly.com/moo"), | |
751 ASCIIToUTF16("o")); | |
752 EXPECT_GE(ac_matches_[0].relevance, | |
753 HistoryURLProvider::kScoreForWhatYouTypedResult); | |
754 | |
755 // If the user enters a hostname + path that they have visited | |
756 // before, we should make sure that all HistoryQuickProvider results | |
757 // have scores less than what the HistoryURLProvider will assign | |
758 // the URL-what-you-typed match. | |
759 RunTest(ASCIIToUTF16("popularsitewithpathonly.com/moo"), false, | |
760 expected_urls, true, | |
761 ASCIIToUTF16("popularsitewithpathonly.com/moo"), base::string16()); | |
762 EXPECT_LT(ac_matches_[0].relevance, | |
763 HistoryURLProvider::kScoreForBestInlineableResult); | |
764 } | |
765 | |
766 TEST_F(HistoryQuickProviderTest, PreventInlineAutocomplete) { | |
767 std::vector<std::string> expected_urls; | |
768 expected_urls.push_back("http://popularsitewithroot.com/"); | |
769 | |
770 // Check that the desired URL is normally allowed to be the default match | |
771 // against input that is a prefex of the URL. | |
772 RunTest(ASCIIToUTF16("popularsitewithr"), false, expected_urls, true, | |
773 ASCIIToUTF16("popularsitewithroot.com"), | |
774 ASCIIToUTF16("oot.com")); | |
775 | |
776 // Check that it's not allowed to be the default match if | |
777 // prevent_inline_autocomplete is true. | |
778 RunTest(ASCIIToUTF16("popularsitewithr"), true, expected_urls, false, | |
779 ASCIIToUTF16("popularsitewithroot.com"), | |
780 ASCIIToUTF16("oot.com")); | |
781 | |
782 // But the exact hostname can still match even if prevent inline autocomplete | |
783 // is true. i.e., there's no autocompletion necessary; this is effectively | |
784 // URL-what-you-typed. | |
785 RunTest(ASCIIToUTF16("popularsitewithroot.com"), true, expected_urls, true, | |
786 ASCIIToUTF16("popularsitewithroot.com"), base::string16()); | |
787 | |
788 // The above still holds even with an extra trailing slash. | |
789 RunTest(ASCIIToUTF16("popularsitewithroot.com/"), true, expected_urls, true, | |
790 ASCIIToUTF16("popularsitewithroot.com"), base::string16()); | |
791 } | |
792 | |
793 TEST_F(HistoryQuickProviderTest, CullSearchResults) { | |
794 // Set up a default search engine. | |
795 TemplateURLData data; | |
796 data.SetShortName(ASCIIToUTF16("TestEngine")); | |
797 data.SetKeyword(ASCIIToUTF16("TestEngine")); | |
798 data.SetURL("http://testsearch.com/?q={searchTerms}"); | |
799 TemplateURLService* template_url_service = | |
800 TemplateURLServiceFactory::GetForProfile(profile_.get()); | |
801 TemplateURL* template_url = new TemplateURL(data); | |
802 template_url_service->Add(template_url); | |
803 template_url_service->SetUserSelectedDefaultSearchProvider(template_url); | |
804 template_url_service->Load(); | |
805 | |
806 // A search results page should not be returned when typing a query. | |
807 std::vector<std::string> expected_urls; | |
808 RunTest(ASCIIToUTF16("thequery"), false, expected_urls, false, | |
809 ASCIIToUTF16("anotherengine.com/?q=thequery"), base::string16()); | |
810 | |
811 // A search results page should not be returned when typing the engine URL. | |
812 expected_urls.clear(); | |
813 expected_urls.push_back("http://testsearch.com/"); | |
814 RunTest(ASCIIToUTF16("testsearch"), false, expected_urls, true, | |
815 ASCIIToUTF16("testsearch.com"), | |
816 ASCIIToUTF16(".com")); | |
817 } | |
818 | |
819 TEST_F(HistoryQuickProviderTest, DoesNotProvideMatchesOnFocus) { | |
820 AutocompleteInput input( | |
821 ASCIIToUTF16("popularsite"), base::string16::npos, std::string(), GURL(), | |
822 metrics::OmniboxEventProto::INVALID_SPEC, false, false, true, true, true, | |
823 ChromeAutocompleteSchemeClassifier(profile_.get())); | |
824 provider_->Start(input, false); | |
825 EXPECT_TRUE(provider_->matches().empty()); | |
826 } | |
827 | |
828 // HQPOrderingTest ------------------------------------------------------------- | |
829 | |
830 TestURLInfo ordering_test_db[] = { | |
831 {"http://www.teamliquid.net/tlpd/korean/games/21648_bisu_vs_iris", "", 6, 3, | |
832 256}, | |
833 {"http://www.amazon.com/", "amazon.com: online shopping for electronics, " | |
834 "apparel, computers, books, dvds & more", 20, 20, 10}, | |
835 {"http://www.teamliquid.net/forum/viewmessage.php?topic_id=52045&" | |
836 "currentpage=83", "google images", 6, 6, 0}, | |
837 {"http://www.tempurpedic.com/", "tempur-pedic", 7, 7, 0}, | |
838 {"http://www.teamfortress.com/", "", 5, 5, 6}, | |
839 {"http://www.rottentomatoes.com/", "", 3, 3, 7}, | |
840 {"http://music.google.com/music/listen?u=0#start_pl", "", 3, 3, 9}, | |
841 {"https://www.emigrantdirect.com/", "high interest savings account, high " | |
842 "yield savings - emigrantdirect", 5, 5, 3}, | |
843 {"http://store.steampowered.com/", "", 6, 6, 1}, | |
844 {"http://techmeme.com/", "techmeme", 111, 110, 4}, | |
845 {"http://www.teamliquid.net/tlpd", "team liquid progaming database", 15, 15, | |
846 2}, | |
847 {"http://store.steampowered.com/", "the steam summer camp sale", 6, 6, 1}, | |
848 {"http://www.teamliquid.net/tlpd/korean/players", "tlpd - bw korean - player " | |
849 "index", 25, 7, 219}, | |
850 {"http://slashdot.org/", "slashdot: news for nerds, stuff that matters", 3, 3, | |
851 6}, | |
852 {"http://translate.google.com/", "google translate", 3, 3, 0}, | |
853 {"http://arstechnica.com/", "ars technica", 3, 3, 3}, | |
854 {"http://www.rottentomatoes.com/", "movies | movie trailers | reviews - " | |
855 "rotten tomatoes", 3, 3, 7}, | |
856 {"http://www.teamliquid.net/", "team liquid - starcraft 2 and brood war pro " | |
857 "gaming news", 26, 25, 3}, | |
858 {"http://metaleater.com/", "metaleater", 4, 3, 8}, | |
859 {"http://half.com/", "half.com: textbooks , books , music , movies , games , " | |
860 "video games", 4, 4, 6}, | |
861 {"http://teamliquid.net/", "team liquid - starcraft 2 and brood war pro " | |
862 "gaming news", 8, 5, 9}, | |
863 }; | |
864 | |
865 class HQPOrderingTest : public HistoryQuickProviderTest { | |
866 protected: | |
867 void GetTestData(size_t* data_count, TestURLInfo** test_data) override; | |
868 }; | |
869 | |
870 void HQPOrderingTest::GetTestData(size_t* data_count, TestURLInfo** test_data) { | |
871 DCHECK(data_count); | |
872 DCHECK(test_data); | |
873 *data_count = arraysize(ordering_test_db); | |
874 *test_data = &ordering_test_db[0]; | |
875 } | |
876 | |
877 TEST_F(HQPOrderingTest, TEMatch) { | |
878 std::vector<std::string> expected_urls; | |
879 expected_urls.push_back("http://techmeme.com/"); | |
880 expected_urls.push_back("http://www.teamliquid.net/"); | |
881 expected_urls.push_back("http://www.teamliquid.net/tlpd"); | |
882 RunTest(ASCIIToUTF16("te"), false, expected_urls, true, | |
883 ASCIIToUTF16("techmeme.com"), | |
884 ASCIIToUTF16("chmeme.com")); | |
885 } | |
886 | |
887 TEST_F(HQPOrderingTest, TEAMatch) { | |
888 std::vector<std::string> expected_urls; | |
889 expected_urls.push_back("http://www.teamliquid.net/"); | |
890 expected_urls.push_back("http://www.teamliquid.net/tlpd"); | |
891 expected_urls.push_back("http://www.teamliquid.net/tlpd/korean/players"); | |
892 RunTest(ASCIIToUTF16("tea"), false, expected_urls, true, | |
893 ASCIIToUTF16("www.teamliquid.net"), | |
894 ASCIIToUTF16("mliquid.net")); | |
895 } | |
OLD | NEW |