OLD | NEW |
1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 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 "chrome/browser/autocomplete/search_provider.h" | 5 #include "chrome/browser/autocomplete/search_provider.h" |
6 | 6 |
7 #include "base/metrics/field_trial.h" | 7 #include "base/metrics/field_trial.h" |
8 #include "base/prefs/pref_service.h" | 8 #include "base/prefs/pref_service.h" |
9 #include "base/run_loop.h" | 9 #include "base/run_loop.h" |
10 #include "base/strings/string_util.h" | 10 #include "base/strings/string_util.h" |
11 #include "base/strings/utf_string_conversions.h" | 11 #include "base/strings/utf_string_conversions.h" |
12 #include "base/time.h" | 12 #include "base/time.h" |
13 #include "build/build_config.h" | 13 #include "build/build_config.h" |
14 #include "chrome/browser/autocomplete/autocomplete_classifier_factory.h" | 14 #include "chrome/browser/autocomplete/autocomplete_classifier_factory.h" |
15 #include "chrome/browser/autocomplete/autocomplete_controller.h" | 15 #include "chrome/browser/autocomplete/autocomplete_controller.h" |
16 #include "chrome/browser/autocomplete/autocomplete_input.h" | 16 #include "chrome/browser/autocomplete/autocomplete_input.h" |
17 #include "chrome/browser/autocomplete/autocomplete_match.h" | 17 #include "chrome/browser/autocomplete/autocomplete_match.h" |
18 #include "chrome/browser/autocomplete/autocomplete_provider.h" | 18 #include "chrome/browser/autocomplete/autocomplete_provider.h" |
19 #include "chrome/browser/autocomplete/autocomplete_provider_listener.h" | 19 #include "chrome/browser/autocomplete/autocomplete_provider_listener.h" |
20 #include "chrome/browser/autocomplete/history_url_provider.h" | 20 #include "chrome/browser/autocomplete/history_url_provider.h" |
21 #include "chrome/browser/history/history_service.h" | 21 #include "chrome/browser/history/history_service.h" |
22 #include "chrome/browser/history/history_service_factory.h" | 22 #include "chrome/browser/history/history_service_factory.h" |
23 #include "chrome/browser/omnibox/omnibox_field_trial.h" | 23 #include "chrome/browser/omnibox/omnibox_field_trial.h" |
24 #include "chrome/browser/search/search.h" | 24 #include "chrome/browser/search/search.h" |
25 #include "chrome/browser/search_engines/template_url.h" | 25 #include "chrome/browser/search_engines/template_url.h" |
26 #include "chrome/browser/search_engines/template_url_service.h" | 26 #include "chrome/browser/search_engines/template_url_service.h" |
27 #include "chrome/browser/search_engines/template_url_service_factory.h" | 27 #include "chrome/browser/search_engines/template_url_service_factory.h" |
28 #include "chrome/common/instant_types.h" | |
29 #include "chrome/common/metrics/entropy_provider.h" | 28 #include "chrome/common/metrics/entropy_provider.h" |
30 #include "chrome/common/pref_names.h" | 29 #include "chrome/common/pref_names.h" |
31 #include "chrome/test/base/testing_browser_process.h" | 30 #include "chrome/test/base/testing_browser_process.h" |
32 #include "chrome/test/base/testing_profile.h" | 31 #include "chrome/test/base/testing_profile.h" |
33 #include "content/public/test/test_browser_thread.h" | 32 #include "content/public/test/test_browser_thread.h" |
34 #include "net/url_request/test_url_fetcher_factory.h" | 33 #include "net/url_request/test_url_fetcher_factory.h" |
35 #include "net/url_request/url_request_status.h" | 34 #include "net/url_request/url_request_status.h" |
36 #include "testing/gtest/include/gtest/gtest.h" | 35 #include "testing/gtest/include/gtest/gtest.h" |
37 | 36 |
38 using content::BrowserThread; | 37 using content::BrowserThread; |
(...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
279 // URLFetchers runs. | 278 // URLFetchers runs. |
280 message_loop_.RunUntilIdle(); | 279 message_loop_.RunUntilIdle(); |
281 } | 280 } |
282 | 281 |
283 void SearchProviderTest::QueryForInputAndSetWYTMatch( | 282 void SearchProviderTest::QueryForInputAndSetWYTMatch( |
284 const string16& text, | 283 const string16& text, |
285 AutocompleteMatch* wyt_match) { | 284 AutocompleteMatch* wyt_match) { |
286 QueryForInput(text, false, false); | 285 QueryForInput(text, false, false); |
287 profile_.BlockUntilHistoryProcessesPendingRequests(); | 286 profile_.BlockUntilHistoryProcessesPendingRequests(); |
288 ASSERT_NO_FATAL_FAILURE(FinishDefaultSuggestQuery()); | 287 ASSERT_NO_FATAL_FAILURE(FinishDefaultSuggestQuery()); |
289 EXPECT_NE(chrome::IsInstantExtendedAPIEnabled(), provider_->done()); | |
290 if (!wyt_match) | 288 if (!wyt_match) |
291 return; | 289 return; |
292 ASSERT_GE(provider_->matches().size(), 1u); | 290 ASSERT_GE(provider_->matches().size(), 1u); |
293 EXPECT_TRUE(FindMatchWithDestination(GURL( | 291 EXPECT_TRUE(FindMatchWithDestination(GURL( |
294 default_t_url_->url_ref().ReplaceSearchTerms( | 292 default_t_url_->url_ref().ReplaceSearchTerms( |
295 TemplateURLRef::SearchTermsArgs(text))), | 293 TemplateURLRef::SearchTermsArgs(text))), |
296 wyt_match)); | 294 wyt_match)); |
297 } | 295 } |
298 | 296 |
299 void SearchProviderTest::TearDown() { | 297 void SearchProviderTest::TearDown() { |
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
503 for (size_t i = 0; i < arraysize(inputs); ++i) { | 501 for (size_t i = 0; i < arraysize(inputs); ++i) { |
504 QueryForInput(ASCIIToUTF16(inputs[i]), false, false); | 502 QueryForInput(ASCIIToUTF16(inputs[i]), false, false); |
505 // Make sure the default providers suggest service was not queried. | 503 // Make sure the default providers suggest service was not queried. |
506 ASSERT_TRUE(test_factory_.GetFetcherByID( | 504 ASSERT_TRUE(test_factory_.GetFetcherByID( |
507 SearchProvider::kDefaultProviderURLFetcherID) == NULL); | 505 SearchProvider::kDefaultProviderURLFetcherID) == NULL); |
508 // Run till the history results complete. | 506 // Run till the history results complete. |
509 RunTillProviderDone(); | 507 RunTillProviderDone(); |
510 } | 508 } |
511 } | 509 } |
512 | 510 |
513 // Make sure FinalizeInstantQuery works. | |
514 TEST_F(SearchProviderTest, FinalizeInstantQuery) { | |
515 chrome::EnableInstantExtendedAPIForTesting(); | |
516 | |
517 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("foo"), | |
518 NULL)); | |
519 | |
520 // Tell the provider Instant is done. | |
521 provider_->FinalizeInstantQuery(ASCIIToUTF16("foo"), | |
522 InstantSuggestion(ASCIIToUTF16("bar"), | |
523 INSTANT_COMPLETE_NOW, | |
524 INSTANT_SUGGESTION_SEARCH, | |
525 string16(), | |
526 kNoMatchIndex)); | |
527 | |
528 // The provider should now be done. | |
529 EXPECT_TRUE(provider_->done()); | |
530 | |
531 // There should be two matches, one for what you typed, the other for | |
532 // 'foobar'. | |
533 EXPECT_EQ(2u, provider_->matches().size()); | |
534 GURL instant_url(default_t_url_->url_ref().ReplaceSearchTerms( | |
535 TemplateURLRef::SearchTermsArgs(ASCIIToUTF16("foobar")))); | |
536 AutocompleteMatch instant_match; | |
537 EXPECT_TRUE(FindMatchWithDestination(instant_url, &instant_match)); | |
538 | |
539 // And the 'foobar' match should not have a description, it'll be set later. | |
540 EXPECT_TRUE(instant_match.description.empty()); | |
541 | |
542 // Make sure the what you typed match has no description. | |
543 AutocompleteMatch wyt_match; | |
544 EXPECT_TRUE(FindMatchWithDestination( | |
545 GURL(default_t_url_->url_ref().ReplaceSearchTerms( | |
546 TemplateURLRef::SearchTermsArgs(ASCIIToUTF16("foo")))), | |
547 &wyt_match)); | |
548 EXPECT_TRUE(wyt_match.description.empty()); | |
549 | |
550 // Instant search suggestions should be ranked above verbatim matches. | |
551 EXPECT_GT(instant_match.relevance, wyt_match.relevance); | |
552 } | |
553 | |
554 // Make sure FinalizeInstantQuery works with URL suggestions. | |
555 TEST_F(SearchProviderTest, FinalizeInstantURL) { | |
556 chrome::EnableInstantExtendedAPIForTesting(); | |
557 | |
558 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("ex"), | |
559 NULL)); | |
560 | |
561 // Tell the provider Instant is done. | |
562 provider_->FinalizeInstantQuery(ASCIIToUTF16("ex"), | |
563 InstantSuggestion( | |
564 ASCIIToUTF16("http://example.com/"), | |
565 INSTANT_COMPLETE_NOW, | |
566 INSTANT_SUGGESTION_URL, | |
567 string16(), | |
568 kNoMatchIndex)); | |
569 | |
570 // The provider should now be done. | |
571 EXPECT_TRUE(provider_->done()); | |
572 | |
573 // There should be two matches, one for what you typed, the other for | |
574 // "http://example.com/". | |
575 EXPECT_EQ(2u, provider_->matches().size()); | |
576 GURL instant_url("http://example.com"); | |
577 AutocompleteMatch instant_match; | |
578 EXPECT_TRUE(FindMatchWithDestination(instant_url, &instant_match)); | |
579 | |
580 // The Instant match should not have a description, it'll be set later. | |
581 EXPECT_TRUE(instant_match.description.empty()); | |
582 | |
583 // Make sure the what you typed match has no description. | |
584 AutocompleteMatch wyt_match; | |
585 EXPECT_TRUE(FindMatchWithDestination( | |
586 GURL(default_t_url_->url_ref().ReplaceSearchTerms( | |
587 TemplateURLRef::SearchTermsArgs(ASCIIToUTF16("ex")))), | |
588 &wyt_match)); | |
589 EXPECT_TRUE(wyt_match.description.empty()); | |
590 | |
591 // The Instant URL should be more relevant. | |
592 EXPECT_GT(instant_match.relevance, wyt_match.relevance); | |
593 } | |
594 | |
595 // An Instant URL suggestion should behave the same way whether the input text | |
596 // is classified as UNKNOWN or as an URL. Otherwise if the user types | |
597 // "example.co" url-what-you-typed will displace the Instant suggestion for | |
598 // "example.com". | |
599 TEST_F(SearchProviderTest, FinalizeInstantURLWithURLText) { | |
600 chrome::EnableInstantExtendedAPIForTesting(); | |
601 | |
602 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch( | |
603 ASCIIToUTF16("example.co"), NULL)); | |
604 | |
605 // Tell the provider Instant is done. | |
606 provider_->FinalizeInstantQuery(ASCIIToUTF16("example.co"), | |
607 InstantSuggestion( | |
608 ASCIIToUTF16("http://example.com/"), | |
609 INSTANT_COMPLETE_NOW, | |
610 INSTANT_SUGGESTION_URL, | |
611 string16(), | |
612 kNoMatchIndex)); | |
613 | |
614 // The provider should now be done. | |
615 EXPECT_TRUE(provider_->done()); | |
616 | |
617 // There should be two matches, one for what you typed, the other for | |
618 // "http://example.com/". | |
619 EXPECT_EQ(2u, provider_->matches().size()); | |
620 GURL instant_url("http://example.com"); | |
621 AutocompleteMatch instant_match; | |
622 EXPECT_TRUE(FindMatchWithDestination(instant_url, &instant_match)); | |
623 | |
624 // The Instant match should not have a description, it'll be set later. | |
625 EXPECT_TRUE(instant_match.description.empty()); | |
626 | |
627 // The Instant URL should be more relevant than a URL_WHAT_YOU_TYPED match. | |
628 EXPECT_GT(instant_match.relevance, | |
629 HistoryURLProvider::kScoreForWhatYouTypedResult); | |
630 } | |
631 | |
632 // Make sure that if FinalizeInstantQuery is invoked before suggest results | |
633 // return, the suggest text from FinalizeInstantQuery is remembered. | |
634 TEST_F(SearchProviderTest, RememberInstantQuery) { | |
635 chrome::EnableInstantExtendedAPIForTesting(); | |
636 | |
637 QueryForInput(ASCIIToUTF16("foo"), false, false); | |
638 | |
639 // Finalize the Instant query immediately. | |
640 provider_->FinalizeInstantQuery(ASCIIToUTF16("foo"), | |
641 InstantSuggestion(ASCIIToUTF16("bar"), | |
642 INSTANT_COMPLETE_NOW, | |
643 INSTANT_SUGGESTION_SEARCH, | |
644 string16(), | |
645 kNoMatchIndex)); | |
646 | |
647 // There should be two matches, one for what you typed, the other for | |
648 // 'foobar'. | |
649 EXPECT_EQ(2u, provider_->matches().size()); | |
650 GURL instant_url(default_t_url_->url_ref().ReplaceSearchTerms( | |
651 TemplateURLRef::SearchTermsArgs(ASCIIToUTF16("foobar")))); | |
652 AutocompleteMatch instant_match; | |
653 EXPECT_TRUE(FindMatchWithDestination(instant_url, &instant_match)); | |
654 | |
655 // Wait until history and the suggest query complete. | |
656 profile_.BlockUntilHistoryProcessesPendingRequests(); | |
657 ASSERT_NO_FATAL_FAILURE(FinishDefaultSuggestQuery()); | |
658 | |
659 // Provider should be done. | |
660 EXPECT_TRUE(provider_->done()); | |
661 | |
662 // There should be two matches, one for what you typed, the other for | |
663 // 'foobar'. | |
664 EXPECT_EQ(2u, provider_->matches().size()); | |
665 EXPECT_TRUE(FindMatchWithDestination(instant_url, &instant_match)); | |
666 | |
667 // And the 'foobar' match should not have a description, it'll be set later. | |
668 EXPECT_TRUE(instant_match.description.empty()); | |
669 } | |
670 | |
671 // Make sure that if trailing whitespace is added to the text supplied to | |
672 // AutocompleteInput the default suggest text is cleared. | |
673 TEST_F(SearchProviderTest, DifferingText) { | |
674 chrome::EnableInstantExtendedAPIForTesting(); | |
675 | |
676 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("foo"), | |
677 NULL)); | |
678 | |
679 // Finalize the Instant query immediately. | |
680 provider_->FinalizeInstantQuery(ASCIIToUTF16("foo"), | |
681 InstantSuggestion(ASCIIToUTF16("bar"), | |
682 INSTANT_COMPLETE_NOW, | |
683 INSTANT_SUGGESTION_SEARCH, | |
684 string16(), | |
685 kNoMatchIndex)); | |
686 | |
687 // Query with the same input text, but trailing whitespace. | |
688 AutocompleteMatch instant_match; | |
689 ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("foo "), | |
690 &instant_match)); | |
691 | |
692 // There should only one match, for what you typed. | |
693 EXPECT_EQ(1u, provider_->matches().size()); | |
694 EXPECT_FALSE(instant_match.destination_url.is_empty()); | |
695 } | |
696 | |
697 TEST_F(SearchProviderTest, DontAutocompleteURLLikeTerms) { | 511 TEST_F(SearchProviderTest, DontAutocompleteURLLikeTerms) { |
698 AutocompleteClassifierFactory::GetInstance()->SetTestingFactoryAndUse( | 512 AutocompleteClassifierFactory::GetInstance()->SetTestingFactoryAndUse( |
699 &profile_, &AutocompleteClassifierFactory::BuildInstanceFor); | 513 &profile_, &AutocompleteClassifierFactory::BuildInstanceFor); |
700 GURL url = AddSearchToHistory(default_t_url_, | 514 GURL url = AddSearchToHistory(default_t_url_, |
701 ASCIIToUTF16("docs.google.com"), 1); | 515 ASCIIToUTF16("docs.google.com"), 1); |
702 | 516 |
703 // Add the term as a url. | 517 // Add the term as a url. |
704 HistoryServiceFactory::GetForProfile(&profile_, Profile::EXPLICIT_ACCESS)-> | 518 HistoryServiceFactory::GetForProfile(&profile_, Profile::EXPLICIT_ACCESS)-> |
705 AddPageWithDetails(GURL("http://docs.google.com"), string16(), 1, 1, | 519 AddPageWithDetails(GURL("http://docs.google.com"), string16(), 1, 1, |
706 base::Time::Now(), false, history::SOURCE_BROWSED); | 520 base::Time::Now(), false, history::SOURCE_BROWSED); |
(...skipping 944 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1651 } | 1465 } |
1652 // Ensure that no expected matches are missing. | 1466 // Ensure that no expected matches are missing. |
1653 for (; j < ARRAYSIZE_UNSAFE(cases[i].matches); ++j) | 1467 for (; j < ARRAYSIZE_UNSAFE(cases[i].matches); ++j) |
1654 EXPECT_EQ(kNotApplicable, cases[i].matches[j].contents) << | 1468 EXPECT_EQ(kNotApplicable, cases[i].matches[j].contents) << |
1655 "Case # " << i << " " << description; | 1469 "Case # " << i << " " << description; |
1656 } | 1470 } |
1657 } | 1471 } |
1658 | 1472 |
1659 TEST_F(SearchProviderTest, LocalAndRemoteRelevances) { | 1473 TEST_F(SearchProviderTest, LocalAndRemoteRelevances) { |
1660 // Enable Instant Extended in order to allow an increased number of | 1474 // Enable Instant Extended in order to allow an increased number of |
1661 // suggestions. Unfortunately this requires us to call FinalizeInstantQuery() | 1475 // suggestions. |
1662 // every time. | |
1663 chrome::EnableInstantExtendedAPIForTesting(); | 1476 chrome::EnableInstantExtendedAPIForTesting(); |
1664 | 1477 |
1665 // We hardcode the string "term1" below, so ensure that the search term that | 1478 // We hardcode the string "term1" below, so ensure that the search term that |
1666 // got added to history already is that string. | 1479 // got added to history already is that string. |
1667 ASSERT_EQ(ASCIIToUTF16("term1"), term1_); | 1480 ASSERT_EQ(ASCIIToUTF16("term1"), term1_); |
1668 string16 term = term1_.substr(0, term1_.length() - 1); | 1481 string16 term = term1_.substr(0, term1_.length() - 1); |
1669 | 1482 |
1670 AddSearchToHistory(default_t_url_, term + ASCIIToUTF16("2"), 2); | 1483 AddSearchToHistory(default_t_url_, term + ASCIIToUTF16("2"), 2); |
1671 profile_.BlockUntilHistoryProcessesPendingRequests(); | 1484 profile_.BlockUntilHistoryProcessesPendingRequests(); |
1672 | 1485 |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1730 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"NAVIGATION\"," | 1543 "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"NAVIGATION\"," |
1731 "\"NAVIGATION\"]," | 1544 "\"NAVIGATION\"]," |
1732 // A verbatim query for URL-like input scores 850, so the navigation | 1545 // A verbatim query for URL-like input scores 850, so the navigation |
1733 // scores here should bracket it. | 1546 // scores here should bracket it. |
1734 "\"google:suggestrelevance\":[9999, 9998, 900, 800]}]", | 1547 "\"google:suggestrelevance\":[9999, 9998, 900, 800]}]", |
1735 { "a.com/1", "a.com", "a.com/2", "a1", kNotApplicable, kNotApplicable } }, | 1548 { "a.com/1", "a.com", "a.com/2", "a1", kNotApplicable, kNotApplicable } }, |
1736 }; | 1549 }; |
1737 | 1550 |
1738 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) { | 1551 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) { |
1739 QueryForInput(cases[i].input, false, false); | 1552 QueryForInput(cases[i].input, false, false); |
1740 provider_->FinalizeInstantQuery(string16(), InstantSuggestion()); | |
1741 net::TestURLFetcher* fetcher = WaitUntilURLFetcherIsReady( | 1553 net::TestURLFetcher* fetcher = WaitUntilURLFetcherIsReady( |
1742 SearchProvider::kDefaultProviderURLFetcherID); | 1554 SearchProvider::kDefaultProviderURLFetcherID); |
1743 ASSERT_TRUE(fetcher); | 1555 ASSERT_TRUE(fetcher); |
1744 fetcher->set_response_code(200); | 1556 fetcher->set_response_code(200); |
1745 fetcher->SetResponseString(cases[i].json); | 1557 fetcher->SetResponseString(cases[i].json); |
1746 fetcher->delegate()->OnURLFetchComplete(fetcher); | 1558 fetcher->delegate()->OnURLFetchComplete(fetcher); |
1747 RunTillProviderDone(); | 1559 RunTillProviderDone(); |
1748 | 1560 |
1749 const std::string description = "for input with json=" + cases[i].json; | 1561 const std::string description = "for input with json=" + cases[i].json; |
1750 const ACMatches& matches = provider_->matches(); | 1562 const ACMatches& matches = provider_->matches(); |
(...skipping 520 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2271 } else { | 2083 } else { |
2272 ASSERT_NE(sug_end, sug_it) << "Failed to find " << suggestion; | 2084 ASSERT_NE(sug_end, sug_it) << "Failed to find " << suggestion; |
2273 EXPECT_EQ(ASCIIToUTF16(suggestion), sug_it->suggestion()); | 2085 EXPECT_EQ(ASCIIToUTF16(suggestion), sug_it->suggestion()); |
2274 ++sug_it; | 2086 ++sug_it; |
2275 } | 2087 } |
2276 } | 2088 } |
2277 EXPECT_EQ(sug_end, sug_it); | 2089 EXPECT_EQ(sug_end, sug_it); |
2278 EXPECT_EQ(nav_end, nav_it); | 2090 EXPECT_EQ(nav_end, nav_it); |
2279 } | 2091 } |
2280 } | 2092 } |
OLD | NEW |