#include "build/build_config.h"
#include "chrome/browser/autocomplete/autocomplete_classifier_factory.h"
#include "chrome/browser/autocomplete/autocomplete_controller.h"
-#include "chrome/browser/autocomplete/autocomplete_input.h"
-#include "chrome/browser/autocomplete/autocomplete_match.h"
-#include "chrome/browser/autocomplete/autocomplete_provider.h"
-#include "chrome/browser/autocomplete/autocomplete_provider_listener.h"
+#include "chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.h"
#include "chrome/browser/autocomplete/history_url_provider.h"
#include "chrome/browser/history/history_service.h"
#include "chrome/browser/history/history_service_factory.h"
-#include "chrome/browser/omnibox/omnibox_field_trial.h"
-#include "chrome/browser/search/search.h"
-#include "chrome/browser/search_engines/template_url.h"
-#include "chrome/browser/search_engines/template_url_service.h"
#include "chrome/browser/search_engines/template_url_service_factory.h"
+#include "chrome/browser/signin/signin_manager_factory.h"
+#include "chrome/browser/sync/profile_sync_service.h"
+#include "chrome/browser/sync/profile_sync_service_factory.h"
#include "chrome/common/chrome_switches.h"
-#include "chrome/common/metrics/variations/variations_util.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile.h"
+#include "components/google/core/browser/google_switches.h"
+#include "components/metrics/proto/omnibox_event.pb.h"
+#include "components/omnibox/autocomplete_input.h"
+#include "components/omnibox/autocomplete_match.h"
+#include "components/omnibox/autocomplete_provider.h"
+#include "components/omnibox/autocomplete_provider_listener.h"
+#include "components/omnibox/omnibox_field_trial.h"
+#include "components/omnibox/omnibox_switches.h"
+#include "components/search_engines/search_engine_type.h"
+#include "components/search_engines/search_engines_switches.h"
+#include "components/search_engines/search_terms_data.h"
+#include "components/search_engines/template_url.h"
+#include "components/search_engines/template_url_service.h"
+#include "components/signin/core/browser/signin_manager.h"
+#include "components/sync_driver/pref_names.h"
#include "components/variations/entropy_provider.h"
+#include "components/variations/variations_associated_data.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "net/url_request/test_url_fetcher_factory.h"
#include "net/url_request/url_request_status.h"
#include "testing/gtest/include/gtest/gtest.h"
+using base::ASCIIToUTF16;
+
+namespace {
+
+// Returns the first match in |matches| with |allowed_to_be_default_match|
+// set to true.
+ACMatches::const_iterator FindDefaultMatch(const ACMatches& matches) {
+ ACMatches::const_iterator it = matches.begin();
+ while ((it != matches.end()) && !it->allowed_to_be_default_match)
+ ++it;
+ return it;
+}
+
+class SuggestionDeletionHandler;
+class SearchProviderForTest : public SearchProvider {
+ public:
+ SearchProviderForTest(AutocompleteProviderListener* listener,
+ TemplateURLService* template_url_service,
+ Profile* profile);
+ bool is_success() { return is_success_; };
+
+ protected:
+ virtual ~SearchProviderForTest();
+
+ private:
+ virtual void RecordDeletionResult(bool success) OVERRIDE;
+ bool is_success_;
+ DISALLOW_COPY_AND_ASSIGN(SearchProviderForTest);
+};
+
+SearchProviderForTest::SearchProviderForTest(
+ AutocompleteProviderListener* listener,
+ TemplateURLService* template_url_service,
+ Profile* profile)
+ : SearchProvider(listener, template_url_service, profile),
+ is_success_(false) {
+}
+
+SearchProviderForTest::~SearchProviderForTest() {
+}
+
+void SearchProviderForTest::RecordDeletionResult(bool success) {
+ is_success_ = success;
+}
+
+} // namespace
+
// SearchProviderTest ---------------------------------------------------------
// The following environment is configured for these tests:
public AutocompleteProviderListener {
public:
struct ResultInfo {
- ResultInfo() : result_type(AutocompleteMatchType::NUM_TYPES) {
+ ResultInfo() : result_type(AutocompleteMatchType::NUM_TYPES),
+ allowed_to_be_default_match(false) {
}
ResultInfo(GURL gurl,
AutocompleteMatch::Type result_type,
- string16 fill_into_edit)
+ bool allowed_to_be_default_match,
+ base::string16 fill_into_edit)
: gurl(gurl),
result_type(result_type),
+ allowed_to_be_default_match(allowed_to_be_default_match),
fill_into_edit(fill_into_edit) {
}
const GURL gurl;
const AutocompleteMatch::Type result_type;
- const string16 fill_into_edit;
+ const bool allowed_to_be_default_match;
+ const base::string16 fill_into_edit;
};
struct TestData {
- const string16 input;
+ const base::string16 input;
const size_t num_results;
const ResultInfo output[3];
};
// Adds a search for |term|, using the engine |t_url| to the history, and
// returns the URL for that search.
- GURL AddSearchToHistory(TemplateURL* t_url, string16 term, int visit_count);
+ GURL AddSearchToHistory(TemplateURL* t_url, base::string16 term, int visit_count);
// Looks for a match in |provider_| with |contents| equal to |contents|.
// Sets |match| to it if found. Returns whether |match| was set.
- bool FindMatchWithContents(const string16& contents,
+ bool FindMatchWithContents(const base::string16& contents,
AutocompleteMatch* match);
// Looks for a match in |provider_| with destination |url|. Sets |match| to
void RunTillProviderDone();
// Invokes Start on provider_, then runs all pending tasks.
- void QueryForInput(const string16& text,
+ void QueryForInput(const base::string16& text,
bool prevent_inline_autocomplete,
bool prefer_keyword);
// Calls QueryForInput(), finishes any suggest query, then if |wyt_match| is
// non-NULL, sets it to the "what you typed" entry for |text|.
- void QueryForInputAndSetWYTMatch(const string16& text,
+ void QueryForInputAndSetWYTMatch(const base::string16& text,
AutocompleteMatch* wyt_match);
// Notifies the URLFetcher for the suggest query corresponding to the default
// Be sure and wrap calls to this in ASSERT_NO_FATAL_FAILURE.
void FinishDefaultSuggestQuery();
+ // Runs SearchProvider on |input|, for which the suggest server replies
+ // with |json|, and expects that the resulting matches' contents equals
+ // that in |matches|. An empty entry in |matches| means no match should
+ // be returned in that position. Reports any errors with a message that
+ // includes |error_description|.
+ void ForcedQueryTestHelper(const std::string& input,
+ const std::string& json,
+ const std::string matches[3],
+ const std::string& error_description);
+
void ResetFieldTrialList();
+ // Create a field trial, with ZeroSuggest activation based on |enabled|.
+ base::FieldTrial* CreateZeroSuggestFieldTrial(bool enabled);
+
void ClearAllResults();
// See description above class for details of these fields.
TemplateURL* default_t_url_;
- const string16 term1_;
+ const base::string16 term1_;
GURL term1_url_;
TemplateURL* keyword_t_url_;
- const string16 keyword_term_;
+ const base::string16 keyword_term_;
GURL keyword_url_;
content::TestBrowserThreadBundle thread_bundle_;
TestingProfile profile_;
// The provider.
- scoped_refptr<SearchProvider> provider_;
+ scoped_refptr<SearchProviderForTest> provider_;
// If non-NULL, OnProviderUpdate quits the current |run_loop_|.
base::RunLoop* run_loop_;
data.suggestions_url = "http://defaultturl2/{searchTerms}";
data.instant_url = "http://does/not/exist?strk=1";
data.search_terms_replacement_key = "strk";
- default_t_url_ = new TemplateURL(&profile_, data);
+ default_t_url_ = new TemplateURL(data);
turl_model->Add(default_t_url_);
- turl_model->SetDefaultSearchProvider(default_t_url_);
+ turl_model->SetUserSelectedDefaultSearchProvider(default_t_url_);
TemplateURLID default_provider_id = default_t_url_->id();
ASSERT_NE(0, default_provider_id);
data.SetKeyword(ASCIIToUTF16("k"));
data.SetURL("http://keyword/{searchTerms}");
data.suggestions_url = "http://suggest_keyword/{searchTerms}";
- keyword_t_url_ = new TemplateURL(&profile_, data);
+ keyword_t_url_ = new TemplateURL(data);
turl_model->Add(keyword_t_url_);
ASSERT_NE(0, keyword_t_url_->id());
// requests to ensure the InMemoryDatabase is the state we expect it.
profile_.BlockUntilHistoryProcessesPendingRequests();
- provider_ = new SearchProvider(this, &profile_);
+ provider_ = new SearchProviderForTest(this, turl_model, &profile_);
provider_->kMinimumTimeBetweenSuggestQueriesMs = 0;
}
bool prefer_keyword) {
ACMatches matches;
for (int i = 0; i < num_cases; ++i) {
- AutocompleteInput input(cases[i].input, string16::npos, string16(), GURL(),
- AutocompleteInput::INVALID_SPEC, false,
- prefer_keyword, true,
- AutocompleteInput::ALL_MATCHES);
+ AutocompleteInput input(cases[i].input, base::string16::npos,
+ base::string16(), GURL(),
+ metrics::OmniboxEventProto::INVALID_SPEC, false,
+ prefer_keyword, true, true,
+ ChromeAutocompleteSchemeClassifier(&profile_));
provider_->Start(input, false);
matches = provider_->matches();
- string16 diagnostic_details = ASCIIToUTF16("Input was: ") + cases[i].input +
+ base::string16 diagnostic_details =
+ ASCIIToUTF16("Input was: ") +
+ cases[i].input +
ASCIIToUTF16("; prefer_keyword was: ") +
(prefer_keyword ? ASCIIToUTF16("true") : ASCIIToUTF16("false"));
EXPECT_EQ(cases[i].num_results, matches.size()) << diagnostic_details;
EXPECT_EQ(cases[i].output[j].result_type, matches[j].type) <<
diagnostic_details;
EXPECT_EQ(cases[i].output[j].fill_into_edit,
- matches[j].fill_into_edit) <<
- diagnostic_details;
- // All callers that use this helper function at the moment produce
- // matches that are always allowed to be the default match.
- EXPECT_TRUE(matches[j].allowed_to_be_default_match);
+ matches[j].fill_into_edit) << diagnostic_details;
+ EXPECT_EQ(cases[i].output[j].allowed_to_be_default_match,
+ matches[j].allowed_to_be_default_match) << diagnostic_details;
}
}
}
run_loop.Run();
}
-void SearchProviderTest::QueryForInput(const string16& text,
+void SearchProviderTest::QueryForInput(const base::string16& text,
bool prevent_inline_autocomplete,
bool prefer_keyword) {
// Start a query.
- AutocompleteInput input(text, string16::npos, string16(), GURL(),
- AutocompleteInput::INVALID_SPEC,
+ AutocompleteInput input(text, base::string16::npos, base::string16(), GURL(),
+ metrics::OmniboxEventProto::INVALID_SPEC,
prevent_inline_autocomplete, prefer_keyword, true,
- AutocompleteInput::ALL_MATCHES);
+ true, ChromeAutocompleteSchemeClassifier(&profile_));
provider_->Start(input, false);
// RunUntilIdle so that the task scheduled by SearchProvider to create the
}
void SearchProviderTest::QueryForInputAndSetWYTMatch(
- const string16& text,
+ const base::string16& text,
AutocompleteMatch* wyt_match) {
QueryForInput(text, false, false);
profile_.BlockUntilHistoryProcessesPendingRequests();
if (!wyt_match)
return;
ASSERT_GE(provider_->matches().size(), 1u);
- EXPECT_TRUE(FindMatchWithDestination(GURL(
- default_t_url_->url_ref().ReplaceSearchTerms(
- TemplateURLRef::SearchTermsArgs(text))),
+ EXPECT_TRUE(FindMatchWithDestination(
+ GURL(default_t_url_->url_ref().ReplaceSearchTerms(
+ TemplateURLRef::SearchTermsArgs(base::CollapseWhitespace(
+ text, false)),
+ TemplateURLServiceFactory::GetForProfile(
+ &profile_)->search_terms_data())),
wyt_match));
}
GURL SearchProviderTest::AddSearchToHistory(TemplateURL* t_url,
- string16 term,
+ base::string16 term,
int visit_count) {
HistoryService* history =
HistoryServiceFactory::GetForProfile(&profile_,
Profile::EXPLICIT_ACCESS);
GURL search(t_url->url_ref().ReplaceSearchTerms(
- TemplateURLRef::SearchTermsArgs(term)));
+ TemplateURLRef::SearchTermsArgs(term),
+ TemplateURLServiceFactory::GetForProfile(
+ &profile_)->search_terms_data()));
static base::Time last_added_time;
last_added_time = std::max(base::Time::Now(),
last_added_time + base::TimeDelta::FromMicroseconds(1));
- history->AddPageWithDetails(search, string16(), visit_count, visit_count,
+ history->AddPageWithDetails(search, base::string16(), visit_count, visit_count,
last_added_time, false, history::SOURCE_BROWSED);
history->SetKeywordSearchTermsForURL(search, t_url->id(), term);
return search;
}
-bool SearchProviderTest::FindMatchWithContents(const string16& contents,
+bool SearchProviderTest::FindMatchWithContents(const base::string16& contents,
AutocompleteMatch* match) {
for (ACMatches::const_iterator i = provider_->matches().begin();
i != provider_->matches().end(); ++i) {
default_fetcher->delegate()->OnURLFetchComplete(default_fetcher);
}
+void SearchProviderTest::ForcedQueryTestHelper(
+ const std::string& input,
+ const std::string& json,
+ const std::string expected_matches[3],
+ const std::string& error_description) {
+ QueryForInput(ASCIIToUTF16(input), false, false);
+ net::TestURLFetcher* fetcher = test_factory_.GetFetcherByID(
+ SearchProvider::kDefaultProviderURLFetcherID);
+ ASSERT_TRUE(fetcher);
+ fetcher->set_response_code(200);
+ fetcher->SetResponseString(json);
+ fetcher->delegate()->OnURLFetchComplete(fetcher);
+ RunTillProviderDone();
+
+ const ACMatches& matches = provider_->matches();
+ ASSERT_LE(matches.size(), 3u);
+ size_t i = 0;
+ // Ensure that the returned matches equal the expectations.
+ for (; i < matches.size(); ++i) {
+ EXPECT_EQ(ASCIIToUTF16(expected_matches[i]), matches[i].contents) <<
+ error_description;
+ }
+ // Ensure that no expected matches are missing.
+ for (; i < 3u; ++i) {
+ EXPECT_EQ(std::string(), expected_matches[i]) <<
+ "Case #" << i << ": " << error_description;
+ }
+}
+
void SearchProviderTest::ResetFieldTrialList() {
// Destroy the existing FieldTrialList before creating a new one to avoid
// a DCHECK.
field_trial_list_.reset();
field_trial_list_.reset(new base::FieldTrialList(
new metrics::SHA1EntropyProvider("foo")));
- chrome_variations::testing::ClearAllVariationParams();
+ variations::testing::ClearAllVariationParams();
base::FieldTrial* trial = base::FieldTrialList::CreateFieldTrial(
"AutocompleteDynamicTrial_0", "DefaultGroup");
trial->group();
}
+base::FieldTrial* SearchProviderTest::CreateZeroSuggestFieldTrial(
+ bool enabled) {
+ std::map<std::string, std::string> params;
+ params[std::string(OmniboxFieldTrial::kZeroSuggestRule)] = enabled ?
+ "true" : "false";
+ variations::AssociateVariationParams(
+ OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A", params);
+ return base::FieldTrialList::CreateFieldTrial(
+ OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A");
+}
+
void SearchProviderTest::ClearAllResults() {
provider_->ClearAllResults();
}
// Make sure we query history for the default provider and a URLFetcher is
// created for the default provider suggest results.
TEST_F(SearchProviderTest, QueryDefaultProvider) {
- string16 term = term1_.substr(0, term1_.length() - 1);
+ base::string16 term = term1_.substr(0, term1_.length() - 1);
QueryForInput(term, false, false);
// Make sure the default providers suggest service was queried.
// And the URL matches what we expected.
GURL expected_url(default_t_url_->suggestions_url_ref().ReplaceSearchTerms(
- TemplateURLRef::SearchTermsArgs(term)));
+ TemplateURLRef::SearchTermsArgs(term),
+ TemplateURLServiceFactory::GetForProfile(
+ &profile_)->search_terms_data()));
ASSERT_TRUE(fetcher->GetOriginalURL() == expected_url);
// Tell the SearchProvider the suggest query is done.
AutocompleteMatch wyt_match;
EXPECT_TRUE(FindMatchWithDestination(
GURL(default_t_url_->url_ref().ReplaceSearchTerms(
- TemplateURLRef::SearchTermsArgs(term))), &wyt_match));
+ TemplateURLRef::SearchTermsArgs(term),
+ TemplateURLServiceFactory::GetForProfile(
+ &profile_)->search_terms_data())),
+ &wyt_match));
EXPECT_TRUE(wyt_match.description.empty());
// The match for term1 should be more relevant than the what you typed match.
}
TEST_F(SearchProviderTest, HonorPreventInlineAutocomplete) {
- string16 term = term1_.substr(0, term1_.length() - 1);
+ base::string16 term = term1_.substr(0, term1_.length() - 1);
QueryForInput(term, true, false);
ASSERT_FALSE(provider_->matches().empty());
// Issues a query that matches the registered keyword and makes sure history
// is queried as well as URLFetchers getting created.
TEST_F(SearchProviderTest, QueryKeywordProvider) {
- string16 term = keyword_term_.substr(0, keyword_term_.length() - 1);
+ base::string16 term = keyword_term_.substr(0, keyword_term_.length() - 1);
QueryForInput(keyword_t_url_->keyword() + ASCIIToUTF16(" ") + term,
false,
false);
// And the URL matches what we expected.
GURL expected_url(keyword_t_url_->suggestions_url_ref().ReplaceSearchTerms(
- TemplateURLRef::SearchTermsArgs(term)));
+ TemplateURLRef::SearchTermsArgs(term),
+ TemplateURLServiceFactory::GetForProfile(
+ &profile_)->search_terms_data()));
ASSERT_TRUE(keyword_fetcher->GetOriginalURL() == expected_url);
// Tell the SearchProvider the keyword suggest query is done.
EXPECT_FALSE(match.keyword.empty());
// The fill into edit should contain the keyword.
- EXPECT_EQ(keyword_t_url_->keyword() + char16(' ') + keyword_term_,
+ EXPECT_EQ(keyword_t_url_->keyword() + base::char16(' ') + keyword_term_,
match.fill_into_edit);
}
// Add the term as a url.
HistoryServiceFactory::GetForProfile(&profile_, Profile::EXPLICIT_ACCESS)->
- AddPageWithDetails(GURL("http://docs.google.com"), string16(), 1, 1,
+ AddPageWithDetails(GURL("http://docs.google.com"), base::string16(), 1, 1,
base::Time::Now(), false, history::SOURCE_BROWSED);
profile_.BlockUntilHistoryProcessesPendingRequests();
EXPECT_TRUE(term_match.allowed_to_be_default_match);
}
+TEST_F(SearchProviderTest, DontGiveNavsuggestionsInForcedQueryMode) {
+ const std::string kEmptyMatch;
+ struct {
+ const std::string json;
+ const std::string matches_in_default_mode[3];
+ const std::string matches_in_forced_query_mode[3];
+ } cases[] = {
+ // Without suggested relevance scores.
+ { "[\"a\",[\"http://a1.com\", \"a2\"],[],[],"
+ "{\"google:suggesttype\":[\"NAVIGATION\", \"QUERY\"]}]",
+ { "a", "a1.com", "a2" },
+ { "a", "a2", kEmptyMatch } },
+
+ // With suggested relevance scores in a situation where navsuggest would
+ // go second.
+ { "[\"a\",[\"http://a1.com\", \"a2\"],[],[],"
+ "{\"google:suggesttype\":[\"NAVIGATION\", \"QUERY\"],"
+ "\"google:suggestrelevance\":[1250, 1200]}]",
+ { "a", "a1.com", "a2" },
+ { "a", "a2", kEmptyMatch } },
+
+ // With suggested relevance scores in a situation where navsuggest
+ // would go first.
+ { "[\"a\",[\"http://a1.com\", \"a2\"],[],[],"
+ "{\"google:suggesttype\":[\"NAVIGATION\", \"QUERY\"],"
+ "\"google:suggestrelevance\":[1350, 1250]}]",
+ { "a1.com", "a", "a2" },
+ { "a", "a2", kEmptyMatch } },
+
+ // With suggested relevance scores in a situation where navsuggest
+ // would go first only because verbatim has been demoted.
+ { "[\"a\",[\"http://a1.com\", \"a2\"],[],[],"
+ "{\"google:suggesttype\":[\"NAVIGATION\", \"QUERY\"],"
+ "\"google:suggestrelevance\":[1450, 1400],"
+ "\"google:verbatimrelevance\":1350}]",
+ { "a1.com", "a2", "a" },
+ { "a2", "a", kEmptyMatch } },
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
+ ForcedQueryTestHelper("a", cases[i].json, cases[i].matches_in_default_mode,
+ "regular input with json=" + cases[i].json);
+ ForcedQueryTestHelper("?a", cases[i].json,
+ cases[i].matches_in_forced_query_mode,
+ "forced query input with json=" + cases[i].json);
+ }
+}
+
// A multiword search with one visit should not autocomplete until multiple
// words are typed.
TEST_F(SearchProviderTest, DontAutocompleteUntilMultipleWordsTyped) {
EXPECT_TRUE(wyt_match.allowed_to_be_default_match);
}
-// Autocompletion should work at a word boundary after a space.
+// Autocompletion should work at a word boundary after a space, and should
+// offer a suggestion for the trimmed search query.
TEST_F(SearchProviderTest, AutocompleteAfterSpace) {
- GURL term_url(AddSearchToHistory(default_t_url_, ASCIIToUTF16("two searches"),
- 2));
+ AddSearchToHistory(default_t_url_, ASCIIToUTF16("two searches "), 2);
+ GURL suggested_url(default_t_url_->url_ref().ReplaceSearchTerms(
+ TemplateURLRef::SearchTermsArgs(ASCIIToUTF16("two searches")),
+ TemplateURLServiceFactory::GetForProfile(
+ &profile_)->search_terms_data()));
profile_.BlockUntilHistoryProcessesPendingRequests();
AutocompleteMatch wyt_match;
&wyt_match));
ASSERT_EQ(2u, provider_->matches().size());
AutocompleteMatch term_match;
- EXPECT_TRUE(FindMatchWithDestination(term_url, &term_match));
+ EXPECT_TRUE(FindMatchWithDestination(suggested_url, &term_match));
EXPECT_GT(term_match.relevance, wyt_match.relevance);
EXPECT_TRUE(term_match.allowed_to_be_default_match);
+ EXPECT_EQ(ASCIIToUTF16("searches"), term_match.inline_autocompletion);
+ EXPECT_EQ(ASCIIToUTF16("two searches"), term_match.fill_into_edit);
EXPECT_TRUE(wyt_match.allowed_to_be_default_match);
}
}
// An autocompleted multiword search should not be replaced by a different
-// autocompletion while the user is still typing a valid prefix.
+// autocompletion while the user is still typing a valid prefix unless the
+// user has typed the prefix as a query before.
TEST_F(SearchProviderTest, DontReplacePreviousAutocompletion) {
GURL term_url_a(AddSearchToHistory(default_t_url_,
- ASCIIToUTF16("four searches aaa"), 2));
+ ASCIIToUTF16("four searches aaa"), 3));
GURL term_url_b(AddSearchToHistory(default_t_url_,
ASCIIToUTF16("four searches bbb"), 1));
+ GURL term_url_c(AddSearchToHistory(default_t_url_,
+ ASCIIToUTF16("four searches"), 1));
profile_.BlockUntilHistoryProcessesPendingRequests();
AutocompleteMatch wyt_match;
ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("fo"),
&wyt_match));
- ASSERT_EQ(3u, provider_->matches().size());
+ ASSERT_EQ(4u, provider_->matches().size());
AutocompleteMatch term_match_a;
EXPECT_TRUE(FindMatchWithDestination(term_url_a, &term_match_a));
AutocompleteMatch term_match_b;
EXPECT_TRUE(FindMatchWithDestination(term_url_b, &term_match_b));
+ AutocompleteMatch term_match_c;
+ EXPECT_TRUE(FindMatchWithDestination(term_url_c, &term_match_c));
EXPECT_GT(term_match_a.relevance, wyt_match.relevance);
+ // We don't care about the relative order of b and c.
EXPECT_GT(wyt_match.relevance, term_match_b.relevance);
+ EXPECT_GT(wyt_match.relevance, term_match_c.relevance);
EXPECT_TRUE(term_match_a.allowed_to_be_default_match);
EXPECT_TRUE(term_match_b.allowed_to_be_default_match);
+ EXPECT_TRUE(term_match_c.allowed_to_be_default_match);
EXPECT_TRUE(wyt_match.allowed_to_be_default_match);
ASSERT_NO_FATAL_FAILURE(QueryForInputAndSetWYTMatch(ASCIIToUTF16("four se"),
&wyt_match));
- ASSERT_EQ(3u, provider_->matches().size());
+ ASSERT_EQ(4u, provider_->matches().size());
EXPECT_TRUE(FindMatchWithDestination(term_url_a, &term_match_a));
EXPECT_TRUE(FindMatchWithDestination(term_url_b, &term_match_b));
+ EXPECT_TRUE(FindMatchWithDestination(term_url_c, &term_match_c));
EXPECT_GT(term_match_a.relevance, wyt_match.relevance);
EXPECT_GT(wyt_match.relevance, term_match_b.relevance);
+ EXPECT_GT(wyt_match.relevance, term_match_c.relevance);
+ EXPECT_TRUE(term_match_a.allowed_to_be_default_match);
+ EXPECT_TRUE(term_match_b.allowed_to_be_default_match);
+ EXPECT_TRUE(term_match_c.allowed_to_be_default_match);
+ EXPECT_TRUE(wyt_match.allowed_to_be_default_match);
+
+ // For the exact previously-issued query, the what-you-typed match should win.
+ ASSERT_NO_FATAL_FAILURE(
+ QueryForInputAndSetWYTMatch(ASCIIToUTF16("four searches"), &wyt_match));
+ ASSERT_EQ(3u, provider_->matches().size());
+ EXPECT_TRUE(FindMatchWithDestination(term_url_a, &term_match_a));
+ EXPECT_TRUE(FindMatchWithDestination(term_url_b, &term_match_b));
+ EXPECT_GT(wyt_match.relevance, term_match_a.relevance);
+ EXPECT_GT(wyt_match.relevance, term_match_b.relevance);
EXPECT_TRUE(term_match_a.allowed_to_be_default_match);
EXPECT_TRUE(term_match_b.allowed_to_be_default_match);
EXPECT_TRUE(wyt_match.allowed_to_be_default_match);
AddSearchToHistory(keyword_t_url_, ASCIIToUTF16("term2"), 1);
profile_.BlockUntilHistoryProcessesPendingRequests();
- AutocompleteController controller(&profile_, NULL,
- AutocompleteProvider::TYPE_SEARCH);
+ AutocompleteController controller(&profile_,
+ TemplateURLServiceFactory::GetForProfile(&profile_),
+ NULL, AutocompleteProvider::TYPE_SEARCH);
controller.Start(AutocompleteInput(
- ASCIIToUTF16("k t"), string16::npos, string16(), GURL(),
- AutocompleteInput::INVALID_SPEC, false, false, true,
- AutocompleteInput::ALL_MATCHES));
+ ASCIIToUTF16("k t"), base::string16::npos, base::string16(), GURL(),
+ metrics::OmniboxEventProto::INVALID_SPEC, false, false, true, true,
+ ChromeAutocompleteSchemeClassifier(&profile_)));
const AutocompleteResult& result = controller.result();
// There should be three matches, one for the keyword history, one for
EXPECT_GT(result.match_at(1).relevance, result.match_at(2).relevance);
EXPECT_TRUE(result.match_at(0).allowed_to_be_default_match);
EXPECT_TRUE(result.match_at(1).allowed_to_be_default_match);
- EXPECT_TRUE(result.match_at(2).allowed_to_be_default_match);
+ EXPECT_FALSE(result.match_at(2).allowed_to_be_default_match);
// The two keyword results should come with the keyword we expect.
EXPECT_EQ(ASCIIToUTF16("k"), result.match_at(0).keyword);
{ ASCIIToUTF16("k foo"), 2,
{ ResultInfo(GURL("http://keyword/foo"),
AutocompleteMatchType::SEARCH_OTHER_ENGINE,
+ true,
ASCIIToUTF16("k foo")),
ResultInfo(GURL("http://defaultturl/k%20foo"),
AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
+ false,
ASCIIToUTF16("k foo") ) } },
// Make sure extra whitespace after the keyword doesn't change the
- // keyword verbatim query.
+ // keyword verbatim query. Also verify that interior consecutive
+ // whitespace gets trimmed.
{ ASCIIToUTF16("k foo"), 2,
{ ResultInfo(GURL("http://keyword/foo"),
AutocompleteMatchType::SEARCH_OTHER_ENGINE,
+ true,
ASCIIToUTF16("k foo")),
- ResultInfo(GURL("http://defaultturl/k%20%20%20foo"),
+ ResultInfo(GURL("http://defaultturl/k%20foo"),
AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
- ASCIIToUTF16("k foo")) } },
+ false,
+ ASCIIToUTF16("k foo")) } },
// Leading whitespace should be stripped before SearchProvider gets the
// input; hence there are no tests here about how it handles those inputs.
- // But whitespace elsewhere in the query string should matter to both
- // matches.
+ // Verify that interior consecutive whitespace gets trimmed in either case.
{ ASCIIToUTF16("k foo bar"), 2,
- { ResultInfo(GURL("http://keyword/foo%20%20bar"),
+ { ResultInfo(GURL("http://keyword/foo%20bar"),
AutocompleteMatchType::SEARCH_OTHER_ENGINE,
- ASCIIToUTF16("k foo bar")),
- ResultInfo(GURL("http://defaultturl/k%20%20foo%20%20bar"),
+ true,
+ ASCIIToUTF16("k foo bar")),
+ ResultInfo(GURL("http://defaultturl/k%20foo%20bar"),
AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
- ASCIIToUTF16("k foo bar")) } },
- // Note in the above test case we don't test trailing whitespace because
- // SearchProvider still doesn't handle this well. See related bugs:
- // 102690, 99239, 164635.
+ false,
+ ASCIIToUTF16("k foo bar")) } },
+
+ // Verify that trailing whitespace gets trimmed.
+ { ASCIIToUTF16("k foo bar "), 2,
+ { ResultInfo(GURL("http://keyword/foo%20bar"),
+ AutocompleteMatchType::SEARCH_OTHER_ENGINE,
+ true,
+ ASCIIToUTF16("k foo bar")),
+ ResultInfo(GURL("http://defaultturl/k%20foo%20bar"),
+ AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
+ false,
+ ASCIIToUTF16("k foo bar")) } },
// Keywords can be prefixed by certain things that should get ignored
// when constructing the keyword match.
{ ASCIIToUTF16("www.k foo"), 2,
{ ResultInfo(GURL("http://keyword/foo"),
AutocompleteMatchType::SEARCH_OTHER_ENGINE,
+ true,
ASCIIToUTF16("k foo")),
ResultInfo(GURL("http://defaultturl/www.k%20foo"),
AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
+ false,
ASCIIToUTF16("www.k foo")) } },
{ ASCIIToUTF16("http://k foo"), 2,
{ ResultInfo(GURL("http://keyword/foo"),
AutocompleteMatchType::SEARCH_OTHER_ENGINE,
+ true,
ASCIIToUTF16("k foo")),
ResultInfo(GURL("http://defaultturl/http%3A//k%20foo"),
AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
+ false,
ASCIIToUTF16("http://k foo")) } },
{ ASCIIToUTF16("http://www.k foo"), 2,
{ ResultInfo(GURL("http://keyword/foo"),
AutocompleteMatchType::SEARCH_OTHER_ENGINE,
+ true,
ASCIIToUTF16("k foo")),
ResultInfo(GURL("http://defaultturl/http%3A//www.k%20foo"),
AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
+ false,
ASCIIToUTF16("http://www.k foo")) } },
// A keyword with no remaining input shouldn't get a keyword
{ ASCIIToUTF16("k"), 1,
{ ResultInfo(GURL("http://defaultturl/k"),
AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
+ true,
ASCIIToUTF16("k")) } },
+ // Ditto. Trailing whitespace shouldn't make a difference.
{ ASCIIToUTF16("k "), 1,
- { ResultInfo(GURL("http://defaultturl/k%20"),
+ { ResultInfo(GURL("http://defaultturl/k"),
AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
- ASCIIToUTF16("k ")) } }
+ true,
+ ASCIIToUTF16("k")) } }
// The fact that verbatim queries to keyword are handled by KeywordProvider
// not SearchProvider is tested in
data.short_name = ASCIIToUTF16("default");
data.SetKeyword(data.short_name);
data.SetURL("{google:baseURL}{searchTerms}");
- default_t_url_ = new TemplateURL(&profile_, data);
+ default_t_url_ = new TemplateURL(data);
turl_model->Add(default_t_url_);
- turl_model->SetDefaultSearchProvider(default_t_url_);
+ turl_model->SetUserSelectedDefaultSearchProvider(default_t_url_);
CommandLine::ForCurrentProcess()->AppendSwitchASCII(switches::kGoogleBaseURL,
"http://www.bar.com/");
{ ASCIIToUTF16("k a"), 2,
{ ResultInfo(GURL("http://keyword/a"),
AutocompleteMatchType::SEARCH_OTHER_ENGINE,
+ true,
ASCIIToUTF16("k a")),
ResultInfo(GURL("http://www.bar.com/k%20a?a=b"),
AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
+ false,
ASCIIToUTF16("k a")) } },
};
EXPECT_TRUE(match_a3.allowed_to_be_default_match);
}
+// Verifies that the default provider abandons suggested relevance scores
+// when in keyword mode. This should happen regardless of whether the
+// keyword provider returns suggested relevance scores.
+TEST_F(SearchProviderTest, DefaultProviderNoSuggestRelevanceInKeywordMode) {
+ struct {
+ const std::string default_provider_json;
+ const std::string keyword_provider_json;
+ const std::string matches[5];
+ } cases[] = {
+ // First, try an input where the keyword provider does not deliver
+ // suggested relevance scores.
+ { "[\"k a\",[\"k adefault-query\", \"adefault.com\"],[],[],"
+ "{\"google:verbatimrelevance\":9700,"
+ "\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
+ "\"google:suggestrelevance\":[9900, 9800]}]",
+ "[\"a\",[\"akeyword-query\"],[],[],{\"google:suggesttype\":[\"QUERY\"]}]",
+ { "a", "akeyword-query", "k a", "adefault.com", "k adefault-query" } },
+
+ // Now try with keyword provider suggested relevance scores.
+ { "[\"k a\",[\"k adefault-query\", \"adefault.com\"],[],[],"
+ "{\"google:verbatimrelevance\":9700,"
+ "\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
+ "\"google:suggestrelevance\":[9900, 9800]}]",
+ "[\"a\",[\"akeyword-query\"],[],[],{\"google:suggesttype\":[\"QUERY\"],"
+ "\"google:verbatimrelevance\":9500,"
+ "\"google:suggestrelevance\":[9600]}]",
+ { "akeyword-query", "a", "k a", "adefault.com", "k adefault-query" } }
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
+ QueryForInput(ASCIIToUTF16("k a"), false, true);
+ net::TestURLFetcher* default_fetcher =
+ test_factory_.GetFetcherByID(
+ SearchProvider::kDefaultProviderURLFetcherID);
+ ASSERT_TRUE(default_fetcher);
+ default_fetcher->set_response_code(200);
+ default_fetcher->SetResponseString(cases[i].default_provider_json);
+ default_fetcher->delegate()->OnURLFetchComplete(default_fetcher);
+ net::TestURLFetcher* keyword_fetcher =
+ test_factory_.GetFetcherByID(
+ SearchProvider::kKeywordProviderURLFetcherID);
+ ASSERT_TRUE(keyword_fetcher);
+ keyword_fetcher->set_response_code(200);
+ keyword_fetcher->SetResponseString(cases[i].keyword_provider_json);
+ keyword_fetcher->delegate()->OnURLFetchComplete(keyword_fetcher);
+ RunTillProviderDone();
+
+ const std::string description = "for input with default_provider_json=" +
+ cases[i].default_provider_json + " and keyword_provider_json=" +
+ cases[i].keyword_provider_json;
+ const ACMatches& matches = provider_->matches();
+ ASSERT_LE(matches.size(), ARRAYSIZE_UNSAFE(cases[i].matches));
+ size_t j = 0;
+ // Ensure that the returned matches equal the expectations.
+ for (; j < matches.size(); ++j) {
+ EXPECT_EQ(ASCIIToUTF16(cases[i].matches[j]), matches[j].contents) <<
+ description;
+ }
+ // Ensure that no expected matches are missing.
+ for (; j < ARRAYSIZE_UNSAFE(cases[i].matches); ++j)
+ EXPECT_EQ(std::string(), cases[i].matches[j]) << description;
+ }
+}
+
// Verifies that suggest results with relevance scores are added
// properly when using the default fetcher. When adding a new test
// case to this test, please consider adding it to the tests in
const DefaultFetcherMatch kEmptyMatch = { kNotApplicable, false };
struct {
const std::string json;
- const DefaultFetcherMatch matches[4];
+ const DefaultFetcherMatch matches[6];
const std::string inline_autocompletion;
} cases[] = {
// Ensure that suggestrelevance scores reorder matches.
{ "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]",
- { { "a", true }, { "c", false }, { "b", false }, kEmptyMatch },
+ { { "a", true }, { "c", false }, { "b", false }, kEmptyMatch, kEmptyMatch,
+ kEmptyMatch },
std::string() },
{ "[\"a\",[\"http://b.com\", \"http://c.com\"],[],[],"
"{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
"\"google:suggestrelevance\":[1, 2]}]",
- { { "a", true }, { "c.com", false }, { "b.com", false }, kEmptyMatch },
+ { { "a", true }, { "c.com", false }, { "b.com", false }, kEmptyMatch,
+ kEmptyMatch, kEmptyMatch },
std::string() },
// Without suggested relevance scores, we should only allow one
// navsuggest result to be be displayed.
{ "[\"a\",[\"http://b.com\", \"http://c.com\"],[],[],"
"{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"]}]",
- { { "a", true }, { "b.com", false }, kEmptyMatch, kEmptyMatch },
+ { { "a", true }, { "b.com", false }, kEmptyMatch, kEmptyMatch,
+ kEmptyMatch, kEmptyMatch },
std::string() },
// Ensure that verbatimrelevance scores reorder or suppress verbatim.
// Negative values will have no effect; the calculated value will be used.
{ "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9999,"
"\"google:suggestrelevance\":[9998]}]",
- { { "a", true}, { "a1", true }, kEmptyMatch, kEmptyMatch },
+ { { "a", true}, { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
+ kEmptyMatch },
std::string() },
{ "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9998,"
"\"google:suggestrelevance\":[9999]}]",
- { { "a1", true }, { "a", true }, kEmptyMatch, kEmptyMatch },
+ { { "a1", true }, { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
+ kEmptyMatch },
"1" },
{ "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0,"
"\"google:suggestrelevance\":[9999]}]",
- { { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch },
+ { { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch,
+ kEmptyMatch },
"1" },
{ "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":-1,"
"\"google:suggestrelevance\":[9999]}]",
- { { "a1", true }, { "a", true }, kEmptyMatch, kEmptyMatch },
+ { { "a1", true }, { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
+ kEmptyMatch },
"1" },
{ "[\"a\",[\"http://a.com\"],[],[],"
"{\"google:suggesttype\":[\"NAVIGATION\"],"
"\"google:verbatimrelevance\":9999,"
"\"google:suggestrelevance\":[9998]}]",
- { { "a", true }, { "a.com", true }, kEmptyMatch, kEmptyMatch },
+ { { "a", true }, { "a.com", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
+ kEmptyMatch },
std::string() },
{ "[\"a\",[\"http://a.com\"],[],[],"
"{\"google:suggesttype\":[\"NAVIGATION\"],"
"\"google:verbatimrelevance\":9998,"
"\"google:suggestrelevance\":[9999]}]",
- { { "a.com", true }, { "a", true }, kEmptyMatch, kEmptyMatch },
+ { { "a.com", true }, { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
+ kEmptyMatch },
".com" },
{ "[\"a\",[\"http://a.com\"],[],[],"
"{\"google:suggesttype\":[\"NAVIGATION\"],"
"\"google:verbatimrelevance\":0,"
"\"google:suggestrelevance\":[9999]}]",
- { { "a.com", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch },
+ { { "a.com", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch,
+ kEmptyMatch },
".com" },
{ "[\"a\",[\"http://a.com\"],[],[],"
"{\"google:suggesttype\":[\"NAVIGATION\"],"
"\"google:verbatimrelevance\":-1,"
"\"google:suggestrelevance\":[9999]}]",
- { { "a.com", true }, { "a", true }, kEmptyMatch, kEmptyMatch },
+ { { "a.com", true }, { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
+ kEmptyMatch },
".com" },
// Ensure that both types of relevance scores reorder matches together.
{ "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[9999, 9997],"
"\"google:verbatimrelevance\":9998}]",
- { { "a1", true }, { "a", true }, { "a2", true }, kEmptyMatch },
+ { { "a1", true }, { "a", true }, { "a2", true }, kEmptyMatch, kEmptyMatch,
+ kEmptyMatch },
"1" },
- // Ensure that only inlinable matches may be ranked as the highest result.
- // Ignore all suggested relevance scores if this constraint is violated.
+ // Allow non-inlineable matches to be the highest-scoring match but,
+ // if the result set lacks a single inlineable result, abandon suggested
+ // relevance scores entirely.
{ "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999]}]",
- { { "a", true }, { "b", false }, kEmptyMatch, kEmptyMatch },
+ { { "b", false }, { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
+ kEmptyMatch },
std::string() },
{ "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999],"
"\"google:verbatimrelevance\":0}]",
- { { "a", true }, { "b", false }, kEmptyMatch, kEmptyMatch },
+ { { "a", true }, { "b", false }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
+ kEmptyMatch },
std::string() },
{ "[\"a\",[\"http://b.com\"],[],[],"
"{\"google:suggesttype\":[\"NAVIGATION\"],"
"\"google:suggestrelevance\":[9999]}]",
- { { "a", true }, { "b.com", false }, kEmptyMatch, kEmptyMatch },
+ { { "b.com", false }, { "a", true }, kEmptyMatch, kEmptyMatch,
+ kEmptyMatch, kEmptyMatch },
std::string() },
{ "[\"a\",[\"http://b.com\"],[],[],"
"{\"google:suggesttype\":[\"NAVIGATION\"],"
"\"google:suggestrelevance\":[9999],"
"\"google:verbatimrelevance\":0}]",
- { { "a", true }, { "b.com", false }, kEmptyMatch, kEmptyMatch },
- std::string() },
- { "[\"a\",[\"https://a/\"],[],[],"
- "{\"google:suggesttype\":[\"NAVIGATION\"],"
- "\"google:suggestrelevance\":[9999]}]",
- { { "https://a", true }, { "a", true }, kEmptyMatch, kEmptyMatch },
+ { { "a", true }, { "b.com", false }, kEmptyMatch, kEmptyMatch,
+ kEmptyMatch, kEmptyMatch },
std::string() },
- // Ensure that the top result is ranked as highly as calculated verbatim.
- // Ignore the suggested verbatim relevance if this constraint is violated.
+ // Allow low-scoring matches.
{ "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0}]",
- { { "a", true }, { "a1", true }, kEmptyMatch, kEmptyMatch },
- std::string() },
+ { { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch,
+ kEmptyMatch },
+ "1" },
{ "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":1}]",
- { { "a", true }, { "a1", true }, kEmptyMatch, kEmptyMatch },
- std::string() },
+ { { "a1", true }, { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
+ kEmptyMatch },
+ "1" },
{ "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[1],"
"\"google:verbatimrelevance\":0}]",
- { { "a", true }, { "a1", true }, kEmptyMatch, kEmptyMatch },
- std::string() },
+ { { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch,
+ kEmptyMatch },
+ "1" },
{ "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 2],"
"\"google:verbatimrelevance\":0}]",
- { { "a", true }, { "a2", true }, { "a1", true }, kEmptyMatch },
- std::string() },
+ { { "a2", true }, { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
+ kEmptyMatch },
+ "2" },
{ "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 3],"
"\"google:verbatimrelevance\":2}]",
- { { "a", true }, { "a2", true }, { "a1", true }, kEmptyMatch },
- std::string() },
+ { { "a2", true }, { "a", true }, { "a1", true }, kEmptyMatch, kEmptyMatch,
+ kEmptyMatch },
+ "2" },
{ "[\"a\",[\"http://a.com\"],[],[],"
"{\"google:suggesttype\":[\"NAVIGATION\"],"
"\"google:suggestrelevance\":[1],"
"\"google:verbatimrelevance\":0}]",
- { { "a", true }, { "a.com", true }, kEmptyMatch, kEmptyMatch },
- std::string() },
+ { { "a.com", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch,
+ kEmptyMatch },
+ ".com" },
{ "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
"{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
"\"google:suggestrelevance\":[1, 2],"
"\"google:verbatimrelevance\":0}]",
- { { "a", true }, { "a2.com", true }, { "a1.com", true }, kEmptyMatch },
- std::string() },
+ { { "a2.com", true }, { "a1.com", true }, kEmptyMatch, kEmptyMatch,
+ kEmptyMatch, kEmptyMatch },
+ "2.com" },
// Ensure that all suggestions are considered, regardless of order.
{ "[\"a\",[\"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"],[],[],"
"{\"google:suggestrelevance\":[1, 2, 3, 4, 5, 6, 7]}]",
- { { "a", true }, { "h", false }, { "g", false }, { "f", false } },
+ { { "a", true }, { "h", false }, { "g", false }, { "f", false },
+ { "e", false }, { "d", false } },
std::string() },
{ "[\"a\",[\"http://b.com\", \"http://c.com\", \"http://d.com\","
"\"http://e.com\", \"http://f.com\", \"http://g.com\","
"\"NAVIGATION\"],"
"\"google:suggestrelevance\":[1, 2, 3, 4, 5, 6, 7]}]",
{ { "a", true }, { "h.com", false }, { "g.com", false },
- { "f.com", false } },
+ { "f.com", false }, { "e.com", false }, { "d.com", false } },
std::string() },
// Ensure that incorrectly sized suggestion relevance lists are ignored.
{ "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1]}]",
- { { "a", true }, { "a1", true }, { "a2", true }, kEmptyMatch },
+ { { "a", true }, { "a1", true }, { "a2", true }, kEmptyMatch, kEmptyMatch,
+ kEmptyMatch },
std::string() },
{ "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[9999, 1]}]",
- { { "a", true }, { "a1", true }, kEmptyMatch, kEmptyMatch },
+ { { "a", true }, { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
+ kEmptyMatch },
std::string() },
{ "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
"{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
"\"google:suggestrelevance\":[1]}]",
- { { "a", true }, { "a1.com", true }, kEmptyMatch, kEmptyMatch },
+ { { "a", true }, { "a1.com", true }, kEmptyMatch, kEmptyMatch,
+ kEmptyMatch, kEmptyMatch },
std::string() },
{ "[\"a\",[\"http://a1.com\"],[],[],"
"{\"google:suggesttype\":[\"NAVIGATION\"],"
"\"google:suggestrelevance\":[9999, 1]}]",
- { { "a", true }, { "a1.com", true }, kEmptyMatch, kEmptyMatch },
+ { { "a", true }, { "a1.com", true }, kEmptyMatch, kEmptyMatch,
+ kEmptyMatch, kEmptyMatch },
std::string() },
// Ensure that all 'verbatim' results are merged with their maximum score.
{ "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
"{\"google:suggestrelevance\":[9998, 9997, 9999]}]",
- { { "a2", true }, { "a", true }, { "a1", true }, kEmptyMatch },
+ { { "a2", true }, { "a", true }, { "a1", true }, kEmptyMatch, kEmptyMatch,
+ kEmptyMatch },
"2" },
{ "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
"{\"google:suggestrelevance\":[9998, 9997, 9999],"
"\"google:verbatimrelevance\":0}]",
- { { "a2", true }, { "a", true }, { "a1", true }, kEmptyMatch },
+ { { "a2", true }, { "a", true }, { "a1", true }, kEmptyMatch, kEmptyMatch,
+ kEmptyMatch },
"2" },
// Ensure that verbatim is always generated without other suggestions.
// TODO(msw): Ensure verbatimrelevance is respected (except suppression).
{ "[\"a\",[],[],[],{\"google:verbatimrelevance\":1}]",
- { { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch },
+ { { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch,
+ kEmptyMatch },
std::string() },
{ "[\"a\",[],[],[],{\"google:verbatimrelevance\":0}]",
- { { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch },
+ { { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch,
+ kEmptyMatch },
std::string() },
};
const std::string description = "for input with json=" + cases[i].json;
const ACMatches& matches = provider_->matches();
- // The top match must inline and score as highly as calculated verbatim.
ASSERT_FALSE(matches.empty());
+ // Find the first match that's allowed to be the default match and check
+ // its inline_autocompletion.
+ ACMatches::const_iterator it = FindDefaultMatch(matches);
+ ASSERT_NE(matches.end(), it);
EXPECT_EQ(ASCIIToUTF16(cases[i].inline_autocompletion),
- matches[0].inline_autocompletion) << description;
- EXPECT_GE(matches[0].relevance, 1300) << description;
+ it->inline_autocompletion) << description;
+ ASSERT_LE(matches.size(), ARRAYSIZE_UNSAFE(cases[i].matches));
size_t j = 0;
// Ensure that the returned matches equal the expectations.
for (; j < matches.size(); ++j) {
}
}
-// This test is like DefaultFetcherSuggestRelevance above except it enables
-// the field trial that causes the omnibox to be willing to reorder matches
-// to guarantee the top result is a legal default match. This field trial
-// causes SearchProvider to allow some constraints to be violated that it
-// wouldn't normally because the omnibox will fix the problems later.
-TEST_F(SearchProviderTest, DefaultFetcherSuggestRelevanceWithReorder) {
- struct DefaultFetcherMatch {
+// Verifies that suggest results with relevance scores are added
+// properly when using the keyword fetcher. This is similar to the
+// test DefaultFetcherSuggestRelevance above but this uses inputs that
+// trigger keyword suggestions (i.e., "k a" rather than "a") and has
+// different expectations (because now the results are a mix of
+// keyword suggestions and default provider suggestions). When a new
+// test is added to this TEST_F, please consider if it would be
+// appropriate to add to DefaultFetcherSuggestRelevance as well.
+TEST_F(SearchProviderTest, KeywordFetcherSuggestRelevance) {
+ struct KeywordFetcherMatch {
std::string contents;
+ bool from_keyword;
bool allowed_to_be_default_match;
};
- const DefaultFetcherMatch kEmptyMatch = { kNotApplicable, false };
+ const KeywordFetcherMatch kEmptyMatch = { kNotApplicable, false, false };
struct {
const std::string json;
- const DefaultFetcherMatch matches[4];
+ const KeywordFetcherMatch matches[6];
const std::string inline_autocompletion;
} cases[] = {
- // Ensure that suggestrelevance scores reorder matches.
+ // Ensure that suggest relevance scores reorder matches and that
+ // the keyword verbatim (lacking a suggested verbatim score) beats
+ // the default provider verbatim.
{ "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]",
- { { "a", true }, { "c", false }, { "b", false }, kEmptyMatch },
+ { { "a", true, true },
+ { "k a", false, false },
+ { "c", true, false },
+ { "b", true, false },
+ kEmptyMatch, kEmptyMatch },
std::string() },
- { "[\"a\",[\"http://b.com\", \"http://c.com\"],[],[],"
- "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
- "\"google:suggestrelevance\":[1, 2]}]",
- { { "a", true }, { "c.com", false }, { "b.com", false }, kEmptyMatch },
+ // Again, check that relevance scores reorder matches, just this
+ // time with navigation matches. This also checks that with
+ // suggested relevance scores we allow multiple navsuggest results.
+ // Note that navsuggest results that come from a keyword provider
+ // are marked as not a keyword result. (They don't go to a
+ // keyword search engine.)
+ { "[\"a\",[\"http://b.com\", \"http://c.com\", \"d\"],[],[],"
+ "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
+ "\"google:suggestrelevance\":[1301, 1302, 1303]}]",
+ { { "a", true, true },
+ { "d", true, false },
+ { "c.com", false, false },
+ { "b.com", false, false },
+ { "k a", false, false },
+ kEmptyMatch },
std::string() },
// Without suggested relevance scores, we should only allow one
// navsuggest result to be be displayed.
{ "[\"a\",[\"http://b.com\", \"http://c.com\"],[],[],"
"{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"]}]",
- { { "a", true }, { "b.com", false }, kEmptyMatch, kEmptyMatch },
+ { { "a", true, true },
+ { "b.com", false, false },
+ { "k a", false, false },
+ kEmptyMatch, kEmptyMatch, kEmptyMatch },
std::string() },
// Ensure that verbatimrelevance scores reorder or suppress verbatim.
// Negative values will have no effect; the calculated value will be used.
{ "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9999,"
"\"google:suggestrelevance\":[9998]}]",
- { { "a", true}, { "a1", true }, kEmptyMatch, kEmptyMatch },
+ { { "a", true, true },
+ { "a1", true, true },
+ { "k a", false, false },
+ kEmptyMatch, kEmptyMatch, kEmptyMatch },
std::string() },
{ "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9998,"
"\"google:suggestrelevance\":[9999]}]",
- { { "a1", true }, { "a", true }, kEmptyMatch, kEmptyMatch },
+ { { "a1", true, true },
+ { "a", true, true },
+ { "k a", false, false },
+ kEmptyMatch, kEmptyMatch, kEmptyMatch },
"1" },
{ "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0,"
"\"google:suggestrelevance\":[9999]}]",
- { { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch },
+ { { "a1", true, true },
+ { "k a", false, false },
+ kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
"1" },
{ "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":-1,"
"\"google:suggestrelevance\":[9999]}]",
- { { "a1", true }, { "a", true }, kEmptyMatch, kEmptyMatch },
+ { { "a1", true, true },
+ { "a", true, true },
+ { "k a", false, false },
+ kEmptyMatch, kEmptyMatch, kEmptyMatch },
"1" },
{ "[\"a\",[\"http://a.com\"],[],[],"
"{\"google:suggesttype\":[\"NAVIGATION\"],"
"\"google:verbatimrelevance\":9999,"
"\"google:suggestrelevance\":[9998]}]",
- { { "a", true }, { "a.com", true }, kEmptyMatch, kEmptyMatch },
+ { { "a", true, true },
+ { "a.com", false, false },
+ { "k a", false, false },
+ kEmptyMatch, kEmptyMatch, kEmptyMatch },
std::string() },
- { "[\"a\",[\"http://a.com\"],[],[],"
- "{\"google:suggesttype\":[\"NAVIGATION\"],"
- "\"google:verbatimrelevance\":9998,"
- "\"google:suggestrelevance\":[9999]}]",
- { { "a.com", true }, { "a", true }, kEmptyMatch, kEmptyMatch },
- ".com" },
- { "[\"a\",[\"http://a.com\"],[],[],"
- "{\"google:suggesttype\":[\"NAVIGATION\"],"
- "\"google:verbatimrelevance\":0,"
- "\"google:suggestrelevance\":[9999]}]",
- { { "a.com", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch },
- ".com" },
- { "[\"a\",[\"http://a.com\"],[],[],"
- "{\"google:suggesttype\":[\"NAVIGATION\"],"
- "\"google:verbatimrelevance\":-1,"
- "\"google:suggestrelevance\":[9999]}]",
- { { "a.com", true }, { "a", true }, kEmptyMatch, kEmptyMatch },
- ".com" },
// Ensure that both types of relevance scores reorder matches together.
{ "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[9999, 9997],"
"\"google:verbatimrelevance\":9998}]",
- { { "a1", true }, { "a", true }, { "a2", true }, kEmptyMatch },
+ { { "a1", true, true },
+ { "a", true, true },
+ { "a2", true, true },
+ { "k a", false, false },
+ kEmptyMatch, kEmptyMatch },
"1" },
- // Allow non-inlineable matches to be the highest-scoring match but,
- // if the result set lacks a single inlineable result, abandon suggested
- // relevance scores entirely.
+ // Check that non-inlinable matches may be ranked as the highest result
+ // if there is at least one inlineable match.
{ "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999]}]",
- { { "b", false }, { "a", true }, kEmptyMatch, kEmptyMatch },
- std::string() },
- { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999],"
- "\"google:verbatimrelevance\":0}]",
- { { "a", true }, { "b", false }, kEmptyMatch, kEmptyMatch },
+ { { "b", true, false },
+ { "a", true, true },
+ { "k a", false, false },
+ kEmptyMatch, kEmptyMatch, kEmptyMatch },
std::string() },
{ "[\"a\",[\"http://b.com\"],[],[],"
"{\"google:suggesttype\":[\"NAVIGATION\"],"
"\"google:suggestrelevance\":[9999]}]",
- { { "b.com", false }, { "a", true }, kEmptyMatch, kEmptyMatch },
+ { { "b.com", false, false },
+ { "a", true, true },
+ { "k a", false, false },
+ kEmptyMatch, kEmptyMatch, kEmptyMatch },
+ std::string() },
+ // On the other hand, if there is no inlineable match, restore
+ // the keyword verbatim score.
+ { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999],"
+ "\"google:verbatimrelevance\":0}]",
+ { { "b", true, false },
+ { "a", true, true },
+ { "k a", false, false },
+ kEmptyMatch, kEmptyMatch, kEmptyMatch },
std::string() },
{ "[\"a\",[\"http://b.com\"],[],[],"
"{\"google:suggesttype\":[\"NAVIGATION\"],"
"\"google:suggestrelevance\":[9999],"
"\"google:verbatimrelevance\":0}]",
- { { "a", true }, { "b.com", false }, kEmptyMatch, kEmptyMatch },
+ { { "b.com", false, false },
+ { "a", true, true },
+ { "k a", false, false },
+ kEmptyMatch, kEmptyMatch, kEmptyMatch },
std::string() },
- // Allow low-scoring matches.
+ // The top result does not have to score as highly as calculated
+ // verbatim. i.e., there are no minimum score restrictions in
+ // this provider.
{ "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0}]",
- { { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch },
+ { { "a1", true, true },
+ { "k a", false, false },
+ kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
"1" },
{ "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":1}]",
- { { "a1", true }, { "a", true }, kEmptyMatch, kEmptyMatch },
+ { { "a1", true, true },
+ { "k a", false, false },
+ { "a", true, true },
+ kEmptyMatch, kEmptyMatch, kEmptyMatch },
"1" },
{ "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[1],"
"\"google:verbatimrelevance\":0}]",
- { { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch },
+ { { "k a", false, false },
+ { "a1", true, true },
+ kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
"1" },
{ "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 2],"
"\"google:verbatimrelevance\":0}]",
- { { "a2", true }, { "a1", true }, kEmptyMatch, kEmptyMatch },
+ {
+ { "k a", false, false },
+ { "a2", true, true },
+ { "a1", true, true },
+ kEmptyMatch, kEmptyMatch, kEmptyMatch },
"2" },
{ "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 3],"
"\"google:verbatimrelevance\":2}]",
- { { "a2", true }, { "a", true }, { "a1", true }, kEmptyMatch },
+ { { "k a", false, false },
+ { "a2", true, true },
+ { "a", true, true },
+ { "a1", true, true },
+ kEmptyMatch, kEmptyMatch },
"2" },
- { "[\"a\",[\"http://a.com\"],[],[],"
- "{\"google:suggesttype\":[\"NAVIGATION\"],"
- "\"google:suggestrelevance\":[1],"
- "\"google:verbatimrelevance\":0}]",
- { { "a.com", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch },
- ".com" },
- { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
- "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
- "\"google:suggestrelevance\":[1, 2],"
- "\"google:verbatimrelevance\":0}]",
- { { "a2.com", true }, { "a1.com", true }, kEmptyMatch, kEmptyMatch },
- "2.com" },
-
- // Ensure that all suggestions are considered, regardless of order.
- { "[\"a\",[\"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"],[],[],"
- "{\"google:suggestrelevance\":[1, 2, 3, 4, 5, 6, 7]}]",
- { { "a", true }, { "h", false }, { "g", false }, { "f", false } },
- std::string() },
- { "[\"a\",[\"http://b.com\", \"http://c.com\", \"http://d.com\","
- "\"http://e.com\", \"http://f.com\", \"http://g.com\","
- "\"http://h.com\"],[],[],"
- "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\","
- "\"NAVIGATION\", \"NAVIGATION\","
- "\"NAVIGATION\", \"NAVIGATION\","
- "\"NAVIGATION\"],"
- "\"google:suggestrelevance\":[1, 2, 3, 4, 5, 6, 7]}]",
- { { "a", true }, { "h.com", false }, { "g.com", false },
- { "f.com", false } },
- std::string() },
-
- // Ensure that incorrectly sized suggestion relevance lists are ignored.
- { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1]}]",
- { { "a", true }, { "a1", true }, { "a2", true }, kEmptyMatch },
- std::string() },
- { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[9999, 1]}]",
- { { "a", true }, { "a1", true }, kEmptyMatch, kEmptyMatch },
- std::string() },
- { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
- "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
- "\"google:suggestrelevance\":[1]}]",
- { { "a", true }, { "a1.com", true }, kEmptyMatch, kEmptyMatch },
- std::string() },
- { "[\"a\",[\"http://a1.com\"],[],[],"
- "{\"google:suggesttype\":[\"NAVIGATION\"],"
- "\"google:suggestrelevance\":[9999, 1]}]",
- { { "a", true }, { "a1.com", true }, kEmptyMatch, kEmptyMatch },
- std::string() },
-
- // Ensure that all 'verbatim' results are merged with their maximum score.
- { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
- "{\"google:suggestrelevance\":[9998, 9997, 9999]}]",
- { { "a2", true }, { "a", true }, { "a1", true }, kEmptyMatch },
- "2" },
- { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
- "{\"google:suggestrelevance\":[9998, 9997, 9999],"
- "\"google:verbatimrelevance\":0}]",
- { { "a2", true }, { "a", true }, { "a1", true }, kEmptyMatch },
- "2" },
-
- // Ensure that verbatim is always generated without other suggestions.
- // TODO(msw): Ensure verbatimrelevance is respected (except suppression).
- { "[\"a\",[],[],[],{\"google:verbatimrelevance\":1}]",
- { { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch },
- std::string() },
- { "[\"a\",[],[],[],{\"google:verbatimrelevance\":0}]",
- { { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch },
- std::string() },
- };
-
- std::map<std::string, std::string> params;
- params[std::string(OmniboxFieldTrial::kReorderForLegalDefaultMatchRule) +
- ":*:*"] = OmniboxFieldTrial::kReorderForLegalDefaultMatchRuleEnabled;
- ASSERT_TRUE(chrome_variations::AssociateVariationParams(
- OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A", params));
- base::FieldTrialList::CreateFieldTrial(
- OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A");
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
- QueryForInput(ASCIIToUTF16("a"), false, false);
- net::TestURLFetcher* fetcher =
- test_factory_.GetFetcherByID(
- SearchProvider::kDefaultProviderURLFetcherID);
- ASSERT_TRUE(fetcher);
- fetcher->set_response_code(200);
- fetcher->SetResponseString(cases[i].json);
- fetcher->delegate()->OnURLFetchComplete(fetcher);
- RunTillProviderDone();
-
- const std::string description = "for input with json=" + cases[i].json;
- const ACMatches& matches = provider_->matches();
- // The top match must inline and score as highly as calculated verbatim.
- ASSERT_FALSE(matches.empty());
- EXPECT_EQ(ASCIIToUTF16(cases[i].inline_autocompletion),
- matches[0].inline_autocompletion) << description;
-
- size_t j = 0;
- // Ensure that the returned matches equal the expectations.
- for (; j < matches.size(); ++j) {
- EXPECT_EQ(ASCIIToUTF16(cases[i].matches[j].contents),
- matches[j].contents) << description;
- EXPECT_EQ(cases[i].matches[j].allowed_to_be_default_match,
- matches[j].allowed_to_be_default_match) << description;
- }
- // Ensure that no expected matches are missing.
- for (; j < ARRAYSIZE_UNSAFE(cases[i].matches); ++j)
- EXPECT_EQ(kNotApplicable, cases[i].matches[j].contents) <<
- "Case # " << i << " " << description;
- }
-}
-
-// Verifies that suggest results with relevance scores are added
-// properly when using the keyword fetcher. This is similar to the
-// test DefaultFetcherSuggestRelevance above but this uses inputs that
-// trigger keyword suggestions (i.e., "k a" rather than "a") and has
-// different expectations (because now the results are a mix of
-// keyword suggestions and default provider suggestions). When a new
-// test is added to this TEST_F, please consider if it would be
-// appropriate to add to DefaultFetcherSuggestRelevance as well.
-TEST_F(SearchProviderTest, KeywordFetcherSuggestRelevance) {
- struct KeywordFetcherMatch {
- std::string contents;
- bool from_keyword;
- bool allowed_to_be_default_match;
- };
- const KeywordFetcherMatch kEmptyMatch = { kNotApplicable, false, false };
- struct {
- const std::string json;
- const KeywordFetcherMatch matches[5];
- const std::string inline_autocompletion;
- } cases[] = {
- // Ensure that suggest relevance scores reorder matches and that
- // the keyword verbatim (lacking a suggested verbatim score) beats
- // the default provider verbatim.
- { "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]",
- { { "a", true, true },
- { "k a", false, true },
- { "c", true, false },
- { "b", true, false },
- kEmptyMatch },
- std::string() },
- // Again, check that relevance scores reorder matches, just this
- // time with navigation matches. This also checks that with
- // suggested relevance scores we allow multiple navsuggest results.
- // It's odd that navsuggest results that come from a keyword
- // provider are marked as not a keyword result. I think this
- // comes from them not going to a keyword search engine).
- // TODO(mpearson): Investigate the implications (if any) of
- // tagging these results appropriately. If so, do it because it
- // makes more sense.
- { "[\"a\",[\"http://b.com\", \"http://c.com\", \"d\"],[],[],"
- "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
- "\"google:suggestrelevance\":[1301, 1302, 1303]}]",
- { { "a", true, true },
- { "d", true, false },
- { "c.com", false, false },
- { "b.com", false, false },
- { "k a", false, true }, },
- std::string() },
-
- // Without suggested relevance scores, we should only allow one
- // navsuggest result to be be displayed.
- { "[\"a\",[\"http://b.com\", \"http://c.com\"],[],[],"
- "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"]}]",
- { { "a", true, true },
- { "b.com", false, false },
- { "k a", false, true },
- kEmptyMatch, kEmptyMatch },
- std::string() },
-
- // Ensure that verbatimrelevance scores reorder or suppress verbatim.
- // Negative values will have no effect; the calculated value will be used.
- { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9999,"
- "\"google:suggestrelevance\":[9998]}]",
- { { "a", true, true },
- { "a1", true, true },
- { "k a", false, true },
- kEmptyMatch, kEmptyMatch },
- std::string() },
- { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9998,"
- "\"google:suggestrelevance\":[9999]}]",
- { { "a1", true, true },
- { "a", true, true },
- { "k a", false, true },
- kEmptyMatch, kEmptyMatch },
- "1" },
- { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0,"
- "\"google:suggestrelevance\":[9999]}]",
- { { "a1", true, true },
- { "k a", false, true },
- kEmptyMatch, kEmptyMatch, kEmptyMatch },
- "1" },
- { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":-1,"
- "\"google:suggestrelevance\":[9999]}]",
- { { "a1", true, true },
- { "a", true, true },
- { "k a", false, true },
- kEmptyMatch, kEmptyMatch },
- "1" },
- { "[\"a\",[\"http://a.com\"],[],[],"
- "{\"google:suggesttype\":[\"NAVIGATION\"],"
- "\"google:verbatimrelevance\":9999,"
- "\"google:suggestrelevance\":[9998]}]",
- { { "a", true, true },
- { "a.com", false, true },
- { "k a", false, true },
- kEmptyMatch, kEmptyMatch },
- std::string() },
-
- // Ensure that both types of relevance scores reorder matches together.
- { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[9999, 9997],"
- "\"google:verbatimrelevance\":9998}]",
- { { "a1", true, true },
- { "a", true, true },
- { "a2", true, true },
- { "k a", false, true },
- kEmptyMatch },
- "1" },
-
- // Ensure that only inlinable matches may be ranked as the highest result.
- // Ignore all suggested relevance scores if this constraint is violated.
- { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999]}]",
- { { "a", true, true },
- { "b", true, false },
- { "k a", false, true },
- kEmptyMatch, kEmptyMatch },
- std::string() },
- { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999],"
- "\"google:verbatimrelevance\":0}]",
- { { "a", true, true },
- { "b", true, false },
- { "k a", false, true },
- kEmptyMatch, kEmptyMatch },
- std::string() },
- { "[\"a\",[\"http://b.com\"],[],[],"
- "{\"google:suggesttype\":[\"NAVIGATION\"],"
- "\"google:suggestrelevance\":[9999]}]",
- { { "a", true, true },
- { "b.com", false, false },
- { "k a", false, true },
- kEmptyMatch, kEmptyMatch },
- std::string() },
- { "[\"a\",[\"http://b.com\"],[],[],"
- "{\"google:suggesttype\":[\"NAVIGATION\"],"
- "\"google:suggestrelevance\":[9999],"
- "\"google:verbatimrelevance\":0}]",
- { { "a", true, true },
- { "b.com", false, false },
- { "k a", false, true },
- kEmptyMatch, kEmptyMatch },
- std::string() },
-
- // Ensure that the top result is ranked as highly as calculated verbatim.
- // Ignore the suggested verbatim relevance if this constraint is violated.
- // Note that keyword suggestions by default (not in suggested relevance
- // mode) score more highly than the default verbatim.
- { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0}]",
- { { "a", true, true },
- { "a1", true, true },
- { "k a", false, true },
- kEmptyMatch, kEmptyMatch },
- std::string() },
- { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":1}]",
- { { "a", true, true },
- { "a1", true, true },
- { "k a", false, true },
- kEmptyMatch, kEmptyMatch},
- std::string() },
- // Continuing the same category of tests, but make sure we keep the
- // suggested relevance scores even as we discard the verbatim relevance
- // scores.
- { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[1],"
- "\"google:verbatimrelevance\":0}]",
- { { "a", true, true },
- { "k a", false, true },
- { "a1", true, true },
- kEmptyMatch, kEmptyMatch},
- std::string() },
- { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 2],"
- "\"google:verbatimrelevance\":0}]",
- { { "a", true, true },
- { "k a", false, true },
- { "a2", true, true },
- { "a1", true, true },
- kEmptyMatch },
- std::string() },
- { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 3],"
- "\"google:verbatimrelevance\":2}]",
- { { "a", true, true },
- { "k a", false, true },
- { "a2", true, true },
- { "a1", true, true },
- kEmptyMatch },
- std::string() },
// Ensure that all suggestions are considered, regardless of order.
{ "[\"a\",[\"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\"],[],[],"
"{\"google:suggestrelevance\":[1, 2, 3, 4, 5, 6, 7]}]",
{ { "a", true, true },
- { "k a", false, true },
+ { "k a", false, false },
{ "h", true, false },
{ "g", true, false },
- { "f", true, false } },
+ { "f", true, false },
+ { "e", true, false } },
std::string() },
{ "[\"a\",[\"http://b.com\", \"http://c.com\", \"http://d.com\","
"\"http://e.com\", \"http://f.com\", \"http://g.com\","
"\"NAVIGATION\"],"
"\"google:suggestrelevance\":[1, 2, 3, 4, 5, 6, 7]}]",
{ { "a", true, true },
- { "k a", false, true },
+ { "k a", false, false },
{ "h.com", false, false },
{ "g.com", false, false },
- { "f.com", false, false } },
+ { "f.com", false, false },
+ { "e.com", false, false } },
std::string() },
// Ensure that incorrectly sized suggestion relevance lists are ignored.
{ { "a", true, true },
{ "a1", true, true },
{ "a2", true, true },
- { "k a", false, true },
- kEmptyMatch },
+ { "k a", false, false },
+ kEmptyMatch, kEmptyMatch },
std::string() },
{ "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[9999, 1]}]",
{ { "a", true, true },
{ "a1", true, true },
- { "k a", false, true },
- kEmptyMatch, kEmptyMatch},
+ { "k a", false, false },
+ kEmptyMatch, kEmptyMatch, kEmptyMatch },
std::string() },
- // In this case, ignored the suggested relevance scores means we keep
+ // In this case, ignoring the suggested relevance scores means we keep
// only one navsuggest result.
{ "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
"{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
"\"google:suggestrelevance\":[1]}]",
{ { "a", true, true },
- { "a1.com", false, true },
- { "k a", false, true },
- kEmptyMatch, kEmptyMatch},
+ { "a1.com", false, false },
+ { "k a", false, false },
+ kEmptyMatch, kEmptyMatch, kEmptyMatch },
std::string() },
{ "[\"a\",[\"http://a1.com\"],[],[],"
"{\"google:suggesttype\":[\"NAVIGATION\"],"
"\"google:suggestrelevance\":[9999, 1]}]",
{ { "a", true, true },
- { "a1.com", false, true },
- { "k a", false, true },
- kEmptyMatch, kEmptyMatch},
+ { "a1.com", false, false },
+ { "k a", false, false },
+ kEmptyMatch, kEmptyMatch, kEmptyMatch },
std::string() },
// Ensure that all 'verbatim' results are merged with their maximum score.
{ { "a2", true, true },
{ "a", true, true },
{ "a1", true, true },
- { "k a", false, true },
- kEmptyMatch },
+ { "k a", false, false },
+ kEmptyMatch, kEmptyMatch },
"2" },
{ "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
"{\"google:suggestrelevance\":[9998, 9997, 9999],"
{ { "a2", true, true },
{ "a", true, true },
{ "a1", true, true },
- { "k a", false, true },
- kEmptyMatch },
+ { "k a", false, false },
+ kEmptyMatch, kEmptyMatch },
"2" },
// Ensure that verbatim is always generated without other suggestions.
// TODO(mpearson): Ensure the value of verbatimrelevance is respected
// (except when suggested relevances are ignored).
{ "[\"a\",[],[],[],{\"google:verbatimrelevance\":1}]",
- { { "a", true, true },
- { "k a", false, true },
- kEmptyMatch, kEmptyMatch, kEmptyMatch},
+ { { "k a", false, false },
+ { "a", true, true },
+ kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
std::string() },
{ "[\"a\",[],[],[],{\"google:verbatimrelevance\":0}]",
{ { "a", true, true },
- { "k a", false, true },
- kEmptyMatch, kEmptyMatch, kEmptyMatch},
+ { "k a", false, false },
+ kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
std::string() },
- // Check that navsuggestions will be demoted below queries.
- // (Navsuggestions are not allowed to appear first.) In the process,
- // make sure the navsuggestions still remain in the same order.
- // First, check the situation where navsuggest scores more than verbatim
- // and there are no query suggestions.
+ // In reorder mode, navsuggestions will not need to be demoted (because
+ // they are marked as not allowed to be default match and will be
+ // reordered as necessary).
{ "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
"{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
"\"google:verbatimrelevance\":9990,"
"\"google:suggestrelevance\":[9998, 9999]}]",
- { { "a", true, true },
- { "a2.com", false, true },
- { "a1.com", false, true },
- { "k a", false, true },
- kEmptyMatch },
+ { { "a2.com", false, false },
+ { "a1.com", false, false },
+ { "a", true, true },
+ { "k a", false, false },
+ kEmptyMatch, kEmptyMatch },
std::string() },
{ "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
"{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
"\"google:verbatimrelevance\":9990,"
"\"google:suggestrelevance\":[9999, 9998]}]",
- { { "a", true, true },
- { "a1.com", false, true },
- { "a2.com", false, true },
- { "k a", false, true },
- kEmptyMatch },
+ { { "a1.com", false, false },
+ { "a2.com", false, false },
+ { "a", true, true },
+ { "k a", false, false },
+ kEmptyMatch, kEmptyMatch },
std::string() },
{ "[\"a\",[\"https://a/\"],[],[],"
"{\"google:suggesttype\":[\"NAVIGATION\"],"
"\"google:suggestrelevance\":[9999]}]",
- { { "a", true, true },
- { "https://a", false, true },
- { "k a", false, true },
- kEmptyMatch,
- kEmptyMatch },
+ { { "https://a", false, false },
+ { "a", true, true },
+ { "k a", false, false },
+ kEmptyMatch, kEmptyMatch, kEmptyMatch },
std::string() },
// Check when navsuggest scores more than verbatim and there is query
// suggestion but it scores lower.
"{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
"\"google:verbatimrelevance\":9990,"
"\"google:suggestrelevance\":[9998, 9999, 1300]}]",
- { { "a", true, true },
- { "a2.com", false, true },
- { "a1.com", false, true },
+ { { "a2.com", false, false },
+ { "a1.com", false, false },
+ { "a", true, true },
{ "a3", true, true },
- { "k a", false, true } },
+ { "k a", false, false },
+ kEmptyMatch },
std::string() },
{ "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
"{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
"\"google:verbatimrelevance\":9990,"
"\"google:suggestrelevance\":[9999, 9998, 1300]}]",
- { { "a", true, true },
- { "a1.com", false, true },
- { "a2.com", false, true },
+ { { "a1.com", false, false },
+ { "a2.com", false, false },
+ { "a", true, true },
{ "a3", true, true },
- { "k a", false, true } },
+ { "k a", false, false },
+ kEmptyMatch },
std::string() },
// Check when navsuggest scores more than a query suggestion. There is
// a verbatim but it scores lower.
"{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
"\"google:verbatimrelevance\":9990,"
"\"google:suggestrelevance\":[9998, 9999, 9997]}]",
- { { "a3", true, true },
- { "a2.com", false, true },
- { "a1.com", false, true },
+ { { "a2.com", false, false },
+ { "a1.com", false, false },
+ { "a3", true, true },
{ "a", true, true },
- { "k a", false, true } },
+ { "k a", false, false },
+ kEmptyMatch },
"3" },
{ "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
"{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
"\"google:verbatimrelevance\":9990,"
"\"google:suggestrelevance\":[9999, 9998, 9997]}]",
- { { "a3", true, true },
- { "a1.com", false, true },
- { "a2.com", false, true },
+ { { "a1.com", false, false },
+ { "a2.com", false, false },
+ { "a3", true, true },
{ "a", true, true },
- { "k a", false, true } },
+ { "k a", false, false },
+ kEmptyMatch },
"3" },
{ "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
"{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
"\"google:verbatimrelevance\":0,"
"\"google:suggestrelevance\":[9998, 9999, 9997]}]",
- { { "a3", true, true },
- { "a2.com", false, true },
- { "a1.com", false, true },
- { "k a", false, true },
- kEmptyMatch },
+ { { "a2.com", false, false },
+ { "a1.com", false, false },
+ { "a3", true, true },
+ { "k a", false, false },
+ kEmptyMatch, kEmptyMatch },
"3" },
{ "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
"{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
"\"google:verbatimrelevance\":0,"
"\"google:suggestrelevance\":[9999, 9998, 9997]}]",
- { { "a3", true, true },
- { "a1.com", false, true },
- { "a2.com", false, true },
- { "k a", false, true },
- kEmptyMatch },
+ { { "a1.com", false, false },
+ { "a2.com", false, false },
+ { "a3", true, true },
+ { "k a", false, false },
+ kEmptyMatch, kEmptyMatch },
"3" },
// Check when there is neither verbatim nor a query suggestion that,
// because we can't demote navsuggestions below a query suggestion,
- // we abandon suggested relevance scores entirely. One consequence is
- // that this means we restore the keyword verbatim match. Note
- // that in this case of abandoning suggested relevance scores, we still
- // keep the navsuggestions in the same order, but we revert to only allowing
- // one navigation to appear because the scores are completely local.
+ // we restore the keyword verbatim score.
{ "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
"{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
"\"google:verbatimrelevance\":0,"
"\"google:suggestrelevance\":[9998, 9999]}]",
- { { "a", true, true },
- { "a2.com", false, true },
- { "k a", false, true },
- kEmptyMatch, kEmptyMatch},
+ { { "a2.com", false, false },
+ { "a1.com", false, false },
+ { "a", true, true },
+ { "k a", false, false },
+ kEmptyMatch, kEmptyMatch },
std::string() },
{ "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
"{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
"\"google:verbatimrelevance\":0,"
"\"google:suggestrelevance\":[9999, 9998]}]",
- { { "a", true, true },
- { "a1.com", false, true },
- { "k a", false, true },
- kEmptyMatch, kEmptyMatch},
+ { { "a1.com", false, false },
+ { "a2.com", false, false },
+ { "a", true, true },
+ { "k a", false, false },
+ kEmptyMatch, kEmptyMatch },
std::string() },
// More checks that everything works when it's not necessary to demote.
{ "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
"\"google:verbatimrelevance\":9990,"
"\"google:suggestrelevance\":[9997, 9998, 9999]}]",
{ { "a3", true, true },
- { "a2.com", false, true },
- { "a1.com", false, true },
+ { "a2.com", false, false },
+ { "a1.com", false, false },
{ "a", true, true },
- { "k a", false, true } },
+ { "k a", false, false },
+ kEmptyMatch },
"3" },
{ "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
"{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
"\"google:verbatimrelevance\":9990,"
"\"google:suggestrelevance\":[9998, 9997, 9999]}]",
{ { "a3", true, true },
- { "a1.com", false, true },
- { "a2.com", false, true },
+ { "a1.com", false, false },
+ { "a2.com", false, false },
{ "a", true, true },
- { "k a", false, true } },
+ { "k a", false, false },
+ kEmptyMatch },
"3" },
};
const std::string description = "for input with json=" + cases[i].json;
const ACMatches& matches = provider_->matches();
- // The top match must inline and score as highly as calculated verbatim.
ASSERT_FALSE(matches.empty());
+ // Find the first match that's allowed to be the default match and check
+ // its inline_autocompletion.
+ ACMatches::const_iterator it = FindDefaultMatch(matches);
+ ASSERT_NE(matches.end(), it);
EXPECT_EQ(ASCIIToUTF16(cases[i].inline_autocompletion),
- matches[0].inline_autocompletion) << description;
- EXPECT_GE(matches[0].relevance, 1300) << description;
+ it->inline_autocompletion) << description;
+ ASSERT_LE(matches.size(), ARRAYSIZE_UNSAFE(cases[i].matches));
size_t j = 0;
// Ensure that the returned matches equal the expectations.
for (; j < matches.size(); ++j) {
}
TEST_F(SearchProviderTest, LocalAndRemoteRelevances) {
- // Enable Instant Extended in order to allow an increased number of
- // suggestions.
- chrome::EnableInstantExtendedAPIForTesting();
-
// We hardcode the string "term1" below, so ensure that the search term that
// got added to history already is that string.
ASSERT_EQ(ASCIIToUTF16("term1"), term1_);
- string16 term = term1_.substr(0, term1_.length() - 1);
+ base::string16 term = term1_.substr(0, term1_.length() - 1);
AddSearchToHistory(default_t_url_, term + ASCIIToUTF16("2"), 2);
profile_.BlockUntilHistoryProcessesPendingRequests();
struct {
- const string16 input;
+ const base::string16 input;
const std::string json;
const std::string matches[6];
} cases[] = {
"{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\", \"QUERY\"],"
"\"google:verbatimrelevance\":1450,"
"\"google:suggestrelevance\":[1430, 1410, 1390, 1370]}]",
- { "term", "a1", "a2", "term2", "a3", "a4" } },
- // When the input looks like a URL, we disallow having a query as the
- // highest-ranking result. If the query was provided by a suggestion, we
- // reset the suggest scores to enforce this (see
- // SearchProvider::UpdateMatches()). Even if we reset the suggest scores,
- // however, we should still allow navsuggestions to be treated as
- // server-provided.
- { ASCIIToUTF16("a.com"),
- "[\"a.com\",[\"a1\", \"a2\", \"a.com/1\", \"a.com/2\"],[],[],"
- "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"NAVIGATION\","
- "\"NAVIGATION\"],"
- // A verbatim query for URL-like input scores 850, so the navigation
- // scores here should bracket it.
- "\"google:suggestrelevance\":[9999, 9998, 900, 800]}]",
- { "a.com/1", "a.com", "a.com/2", "a1", kNotApplicable, kNotApplicable } },
+ { "term", "a1", "a2", "term2", "a3", "a4" } }
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
const ACMatches& matches = provider_->matches();
// Ensure no extra matches are present.
- ASSERT_LE(matches.size(), 6U);
+ ASSERT_LE(matches.size(), ARRAYSIZE_UNSAFE(cases[i].matches));
size_t j = 0;
// Ensure that the returned matches equal the expectations.
const std::string json;
const DefaultFetcherUrlInputMatch output[4];
} cases[] = {
- // Ensure topmost NAVIGATION matches are allowed for URL input.
+ // Ensure NAVIGATION matches are allowed to be listed first for URL
+ // input regardless of whether the match is inlineable. Note that
+ // non-inlineable matches should not be allowed to be the default match.
+ { "a.com", "[\"a.com\",[\"http://b.com/\"],[],[],"
+ "{\"google:suggesttype\":[\"NAVIGATION\"],"
+ "\"google:suggestrelevance\":[9999]}]",
+ { { "b.com", AutocompleteMatchType::NAVSUGGEST, false },
+ { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
+ kEmptyMatch, kEmptyMatch } },
+ { "a.com", "[\"a.com\",[\"https://b.com\"],[],[],"
+ "{\"google:suggesttype\":[\"NAVIGATION\"],"
+ "\"google:suggestrelevance\":[9999]}]",
+ { { "https://b.com", AutocompleteMatchType::NAVSUGGEST, false },
+ { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
+ kEmptyMatch, kEmptyMatch } },
{ "a.com", "[\"a.com\",[\"http://a.com/a\"],[],[],"
"{\"google:suggesttype\":[\"NAVIGATION\"],"
"\"google:suggestrelevance\":[9999]}]",
{ "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
kEmptyMatch, kEmptyMatch } },
- // Ensure topmost SUGGEST matches are not allowed for URL input.
- // SearchProvider disregards search and verbatim suggested relevances.
+ // Ensure topmost inlineable SUGGEST matches are NOT allowed for URL
+ // input. SearchProvider disregards search and verbatim suggested
+ // relevances.
{ "a.com", "[\"a.com\",[\"a.com info\"],[],[],"
"{\"google:suggestrelevance\":[9999]}]",
{ { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
{ "a.com info", AutocompleteMatchType::SEARCH_SUGGEST, true },
kEmptyMatch, kEmptyMatch } },
- { "a.com", "[\"a.com\",[\"a.com/a\"],[],[],"
+ { "a.com", "[\"a.com\",[\"a.com info\"],[],[],"
"{\"google:suggestrelevance\":[9999]}]",
- { { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
- { "a.com/a", AutocompleteMatchType::SEARCH_SUGGEST, true },
+ { { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
+ { "a.com info", AutocompleteMatchType::SEARCH_SUGGEST, true },
kEmptyMatch, kEmptyMatch } },
// Ensure the fallback mechanism allows inlinable NAVIGATION matches.
- { "a.com", "[\"a.com\",[\"a.com/a\", \"http://a.com/b\"],[],[],"
+ { "a.com", "[\"a.com\",[\"a.com info\", \"http://a.com/b\"],[],[],"
"{\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
"\"google:suggestrelevance\":[9999, 9998]}]",
- { { "a.com/b", AutocompleteMatchType::NAVSUGGEST, true },
- { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
- { "a.com/a", AutocompleteMatchType::SEARCH_SUGGEST, true },
+ { { "a.com/b", AutocompleteMatchType::NAVSUGGEST, true },
+ { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
+ { "a.com info", AutocompleteMatchType::SEARCH_SUGGEST, true },
kEmptyMatch } },
- { "a.com", "[\"a.com\",[\"a.com/a\", \"http://a.com/b\"],[],[],"
+ { "a.com", "[\"a.com\",[\"a.com info\", \"http://a.com/b\"],[],[],"
"{\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
"\"google:suggestrelevance\":[9998, 9997],"
"\"google:verbatimrelevance\":9999}]",
- { { "a.com/b", AutocompleteMatchType::NAVSUGGEST, true },
- { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
- { "a.com/a", AutocompleteMatchType::SEARCH_SUGGEST, true },
+ { { "a.com/b", AutocompleteMatchType::NAVSUGGEST, true },
+ { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
+ { "a.com info", AutocompleteMatchType::SEARCH_SUGGEST, true },
kEmptyMatch } },
- // Ensure the fallback mechanism disallows non-inlinable NAVIGATION matches.
- { "a.com", "[\"a.com\",[\"a.com/a\", \"http://abc.com\"],[],[],"
- "{\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
- "\"google:suggestrelevance\":[9999, 9998]}]",
- { { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
- { "abc.com", AutocompleteMatchType::NAVSUGGEST, false },
- { "a.com/a", AutocompleteMatchType::SEARCH_SUGGEST, true },
- kEmptyMatch } },
- { "a.com", "[\"a.com\",[\"a.com/a\", \"http://abc.com\"],[],[],"
- "{\"google:suggesttype\":[\"QUERY\", \"NAVIGATION\"],"
- "\"google:suggestrelevance\":[9998, 9997],"
- "\"google:verbatimrelevance\":9999}]",
- { { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
- { "abc.com", AutocompleteMatchType::NAVSUGGEST, false },
- { "a.com/a", AutocompleteMatchType::SEARCH_SUGGEST, true },
- kEmptyMatch } },
+ // Ensure topmost non-inlineable SUGGEST matches are allowed for URL
+ // input assuming the top inlineable match is not a query (i.e., is a
+ // NAVSUGGEST).
+ { "a.com", "[\"a.com\",[\"info\"],[],[],"
+ "{\"google:suggestrelevance\":[9999]}]",
+ { { "info", AutocompleteMatchType::SEARCH_SUGGEST, false },
+ { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
+ kEmptyMatch, kEmptyMatch } },
+ { "a.com", "[\"a.com\",[\"info\"],[],[],"
+ "{\"google:suggestrelevance\":[9999]}]",
+ { { "info", AutocompleteMatchType::SEARCH_SUGGEST, false },
+ { "a.com", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
+ kEmptyMatch, kEmptyMatch } },
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
size_t j = 0;
const ACMatches& matches = provider_->matches();
+ ASSERT_LE(matches.size(), ARRAYSIZE_UNSAFE(cases[i].output));
// Ensure that the returned matches equal the expectations.
for (; j < matches.size(); ++j) {
EXPECT_EQ(ASCIIToUTF16(cases[i].output[j].match_contents),
// Some cases do not trim "http://" to match from the start of the scheme.
const std::string fill_into_edit;
const std::string inline_autocompletion;
- const bool allowed_to_be_default_match;
+ const bool allowed_to_be_default_match_in_regular_mode;
+ const bool allowed_to_be_default_match_in_prevent_inline_mode;
} cases[] = {
// Do not inline matches that do not contain the input; trim http as needed.
- { "x", "http://www.abc.com",
- "www.abc.com", std::string(), false },
- { "https:", "http://www.abc.com",
- "www.abc.com", std::string(), false },
- { "abc.com/", "http://www.abc.com",
- "www.abc.com", std::string(), false },
+ { "x", "http://www.abc.com",
+ "www.abc.com", std::string(), false, false },
+ { "https:", "http://www.abc.com",
+ "www.abc.com", std::string(), false, false },
{ "http://www.abc.com/a", "http://www.abc.com",
- "http://www.abc.com", std::string(), false },
- { "http://www.abc.com", "https://www.abc.com",
- "https://www.abc.com", std::string(), false },
- { "http://abc.com", "ftp://abc.com",
- "ftp://abc.com", std::string(), false },
- { "https://www.abc.com", "http://www.abc.com",
- "www.abc.com", std::string(), false },
- { "ftp://abc.com", "http://abc.com",
- "abc.com", std::string(), false },
+ "http://www.abc.com", std::string(), false,
+ false },
// Do not inline matches with invalid input prefixes; trim http as needed.
- { "ttp", "http://www.abc.com",
- "www.abc.com", std::string(), false },
- { "://w", "http://www.abc.com",
- "www.abc.com", std::string(), false },
- { "ww.", "http://www.abc.com",
- "www.abc.com", std::string(), false },
- { ".ab", "http://www.abc.com",
- "www.abc.com", std::string(), false },
- { "bc", "http://www.abc.com",
- "www.abc.com", std::string(), false },
- { ".com", "http://www.abc.com",
- "www.abc.com", std::string(), false },
+ { "ttp", "http://www.abc.com",
+ "www.abc.com", std::string(), false, false },
+ { "://w", "http://www.abc.com",
+ "www.abc.com", std::string(), false, false },
+ { "ww.", "http://www.abc.com",
+ "www.abc.com", std::string(), false, false },
+ { ".ab", "http://www.abc.com",
+ "www.abc.com", std::string(), false, false },
+ { "bc", "http://www.abc.com",
+ "www.abc.com", std::string(), false, false },
+ { ".com", "http://www.abc.com",
+ "www.abc.com", std::string(), false, false },
// Do not inline matches that omit input domain labels; trim http as needed.
- { "www.a", "http://a.com",
- "a.com", std::string(), false },
- { "http://www.a", "http://a.com",
- "http://a.com", std::string(), false },
- { "www.a", "ftp://a.com",
- "ftp://a.com", std::string(), false },
- { "ftp://www.a", "ftp://a.com",
- "ftp://a.com", std::string(), false },
+ { "www.a", "http://a.com",
+ "a.com", std::string(), false, false },
+ { "http://www.a", "http://a.com",
+ "http://a.com", std::string(), false, false },
+ { "www.a", "ftp://a.com",
+ "ftp://a.com", std::string(), false, false },
+ { "ftp://www.a", "ftp://a.com",
+ "ftp://a.com", std::string(), false, false },
// Input matching but with nothing to inline will not yield an offset, but
// will be allowed to be default.
- { "abc.com", "http://www.abc.com",
- "www.abc.com", std::string(), true },
- { "http://www.abc.com", "http://www.abc.com",
- "http://www.abc.com", std::string(), true },
+ { "abc.com", "http://www.abc.com",
+ "www.abc.com", std::string(), true, true },
+ { "abc.com/", "http://www.abc.com",
+ "www.abc.com", std::string(), true, true },
+ { "http://www.abc.com", "http://www.abc.com",
+ "http://www.abc.com", std::string(), true, true },
+ { "http://www.abc.com/", "http://www.abc.com",
+ "http://www.abc.com", std::string(), true, true },
+
+ // Inputs with trailing whitespace should inline when possible.
+ { "abc.com ", "http://www.abc.com",
+ "www.abc.com", std::string(), true, true },
+ { "abc.com/ ", "http://www.abc.com",
+ "www.abc.com", std::string(), true, true },
+ { "abc.com ", "http://www.abc.com/bar",
+ "www.abc.com/bar", "/bar", false, false },
+
+ // A suggestion that's equivalent to what the input gets fixed up to
+ // should be inlined.
+ { "abc.com:", "http://abc.com/",
+ "abc.com", "", true, true },
+ { "abc.com:", "http://www.abc.com",
+ "www.abc.com", "", true, true },
// Inline matches when the input is a leading substring of the scheme.
- { "h", "http://www.abc.com",
- "http://www.abc.com", "ttp://www.abc.com", true },
- { "http", "http://www.abc.com",
- "http://www.abc.com", "://www.abc.com", true },
+ { "h", "http://www.abc.com",
+ "http://www.abc.com", "ttp://www.abc.com", true, false },
+ { "http", "http://www.abc.com",
+ "http://www.abc.com", "://www.abc.com", true, false },
// Inline matches when the input is a leading substring of the full URL.
- { "http:", "http://www.abc.com",
- "http://www.abc.com", "//www.abc.com", true },
- { "http://w", "http://www.abc.com",
- "http://www.abc.com", "ww.abc.com", true },
- { "http://www.", "http://www.abc.com",
- "http://www.abc.com", "abc.com", true },
- { "http://www.ab", "http://www.abc.com",
- "http://www.abc.com", "c.com", true },
+ { "http:", "http://www.abc.com",
+ "http://www.abc.com", "//www.abc.com", true, false },
+ { "http://w", "http://www.abc.com",
+ "http://www.abc.com", "ww.abc.com", true, false },
+ { "http://www.", "http://www.abc.com",
+ "http://www.abc.com", "abc.com", true, false },
+ { "http://www.ab", "http://www.abc.com",
+ "http://www.abc.com", "c.com", true, false },
{ "http://www.abc.com/p", "http://www.abc.com/path/file.htm?q=x#foo",
"http://www.abc.com/path/file.htm?q=x#foo",
"ath/file.htm?q=x#foo",
- true },
+ true, false },
{ "http://abc.com/p", "http://abc.com/path/file.htm?q=x#foo",
"http://abc.com/path/file.htm?q=x#foo",
- "ath/file.htm?q=x#foo", true},
+ "ath/file.htm?q=x#foo",
+ true, false},
// Inline matches with valid URLPrefixes; only trim "http://".
{ "w", "http://www.abc.com",
- "www.abc.com", "ww.abc.com", true },
+ "www.abc.com", "ww.abc.com", true, false },
{ "www.a", "http://www.abc.com",
- "www.abc.com", "bc.com", true },
+ "www.abc.com", "bc.com", true, false },
{ "abc", "http://www.abc.com",
- "www.abc.com", ".com", true },
+ "www.abc.com", ".com", true, false },
{ "abc.c", "http://www.abc.com",
- "www.abc.com", "om", true },
+ "www.abc.com", "om", true, false },
{ "abc.com/p", "http://www.abc.com/path/file.htm?q=x#foo",
"www.abc.com/path/file.htm?q=x#foo",
- "ath/file.htm?q=x#foo", true },
+ "ath/file.htm?q=x#foo",
+ true, false },
{ "abc.com/p", "http://abc.com/path/file.htm?q=x#foo",
"abc.com/path/file.htm?q=x#foo",
- "ath/file.htm?q=x#foo", true },
+ "ath/file.htm?q=x#foo",
+ true, false },
// Inline matches using the maximal URLPrefix components.
{ "h", "http://help.com",
- "help.com", "elp.com", true },
+ "help.com", "elp.com", true, false },
{ "http", "http://http.com",
- "http.com", ".com", true },
+ "http.com", ".com", true, false },
{ "h", "http://www.help.com",
- "www.help.com", "elp.com", true },
+ "www.help.com", "elp.com", true, false },
{ "http", "http://www.http.com",
- "www.http.com", ".com", true },
+ "www.http.com", ".com", true, false },
{ "w", "http://www.www.com",
- "www.www.com", "ww.com", true },
+ "www.www.com", "ww.com", true, false },
// Test similar behavior for the ftp and https schemes.
- { "ftp://www.ab", "ftp://www.abc.com/path/file.htm?q=x#foo",
- "ftp://www.abc.com/path/file.htm?q=x#foo",
- "c.com/path/file.htm?q=x#foo", true },
- { "www.ab", "ftp://www.abc.com/path/file.htm?q=x#foo",
- "ftp://www.abc.com/path/file.htm?q=x#foo",
- "c.com/path/file.htm?q=x#foo", true },
- { "ab", "ftp://www.abc.com/path/file.htm?q=x#foo",
- "ftp://www.abc.com/path/file.htm?q=x#foo",
- "c.com/path/file.htm?q=x#foo", true },
- { "ab", "ftp://abc.com/path/file.htm?q=x#foo",
- "ftp://abc.com/path/file.htm?q=x#foo",
- "c.com/path/file.htm?q=x#foo", true },
+ { "ftp://www.ab", "ftp://www.abc.com/path/file.htm?q=x#foo",
+ "ftp://www.abc.com/path/file.htm?q=x#foo",
+ "c.com/path/file.htm?q=x#foo", true, false },
+ { "www.ab", "ftp://www.abc.com/path/file.htm?q=x#foo",
+ "ftp://www.abc.com/path/file.htm?q=x#foo",
+ "c.com/path/file.htm?q=x#foo", true, false },
+ { "ab", "ftp://www.abc.com/path/file.htm?q=x#foo",
+ "ftp://www.abc.com/path/file.htm?q=x#foo",
+ "c.com/path/file.htm?q=x#foo", true, false },
+ { "ab", "ftp://abc.com/path/file.htm?q=x#foo",
+ "ftp://abc.com/path/file.htm?q=x#foo",
+ "c.com/path/file.htm?q=x#foo", true, false },
{ "https://www.ab", "https://www.abc.com/path/file.htm?q=x#foo",
"https://www.abc.com/path/file.htm?q=x#foo",
- "c.com/path/file.htm?q=x#foo", true },
- { "www.ab", "https://www.abc.com/path/file.htm?q=x#foo",
- "https://www.abc.com/path/file.htm?q=x#foo",
- "c.com/path/file.htm?q=x#foo", true },
- { "ab", "https://www.abc.com/path/file.htm?q=x#foo",
- "https://www.abc.com/path/file.htm?q=x#foo",
- "c.com/path/file.htm?q=x#foo", true },
- { "ab", "https://abc.com/path/file.htm?q=x#foo",
- "https://abc.com/path/file.htm?q=x#foo",
- "c.com/path/file.htm?q=x#foo", true },
+ "c.com/path/file.htm?q=x#foo",
+ true, false },
+ { "www.ab", "https://www.abc.com/path/file.htm?q=x#foo",
+ "https://www.abc.com/path/file.htm?q=x#foo",
+ "c.com/path/file.htm?q=x#foo", true, false },
+ { "ab", "https://www.abc.com/path/file.htm?q=x#foo",
+ "https://www.abc.com/path/file.htm?q=x#foo",
+ "c.com/path/file.htm?q=x#foo", true, false },
+ { "ab", "https://abc.com/path/file.htm?q=x#foo",
+ "https://abc.com/path/file.htm?q=x#foo",
+ "c.com/path/file.htm?q=x#foo", true, false },
// Forced query input should inline and retain the "?" prefix.
{ "?http://www.ab", "http://www.abc.com",
- "?http://www.abc.com", "c.com", true },
+ "?http://www.abc.com", "c.com", true, false },
{ "?www.ab", "http://www.abc.com",
- "?www.abc.com", "c.com", true },
+ "?www.abc.com", "c.com", true, false },
{ "?ab", "http://www.abc.com",
- "?www.abc.com", "c.com", true },
+ "?www.abc.com", "c.com", true, false },
+ { "?abc.com", "http://www.abc.com",
+ "?www.abc.com", "", true, true },
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
+ // First test regular mode.
QueryForInput(ASCIIToUTF16(cases[i].input), false, false);
AutocompleteMatch match(
- provider_->NavigationToMatch(SearchProvider::NavigationResult(
- *provider_.get(), GURL(cases[i].url), string16(), false, 0,
- false)));
+ provider_->NavigationToMatch(SearchSuggestionParser::NavigationResult(
+ ChromeAutocompleteSchemeClassifier(&profile_), GURL(cases[i].url),
+ AutocompleteMatchType::NAVSUGGEST, base::string16(), std::string(),
+ false, 0, false, ASCIIToUTF16(cases[i].input), std::string())));
EXPECT_EQ(ASCIIToUTF16(cases[i].inline_autocompletion),
match.inline_autocompletion);
EXPECT_EQ(ASCIIToUTF16(cases[i].fill_into_edit), match.fill_into_edit);
- EXPECT_EQ(cases[i].allowed_to_be_default_match,
+ EXPECT_EQ(cases[i].allowed_to_be_default_match_in_regular_mode,
match.allowed_to_be_default_match);
+
+ // Then test prevent-inline-autocomplete mode.
+ QueryForInput(ASCIIToUTF16(cases[i].input), true, false);
+ AutocompleteMatch match_prevent_inline(
+ provider_->NavigationToMatch(SearchSuggestionParser::NavigationResult(
+ ChromeAutocompleteSchemeClassifier(&profile_), GURL(cases[i].url),
+ AutocompleteMatchType::NAVSUGGEST, base::string16(), std::string(),
+ false, 0, false, ASCIIToUTF16(cases[i].input), std::string())));
+ EXPECT_EQ(ASCIIToUTF16(cases[i].inline_autocompletion),
+ match_prevent_inline.inline_autocompletion);
+ EXPECT_EQ(ASCIIToUTF16(cases[i].fill_into_edit),
+ match_prevent_inline.fill_into_edit);
+ EXPECT_EQ(cases[i].allowed_to_be_default_match_in_prevent_inline_mode,
+ match_prevent_inline.allowed_to_be_default_match);
}
}
// Verifies that "http://" is not trimmed for input that is a leading substring.
TEST_F(SearchProviderTest, NavigationInlineSchemeSubstring) {
- const string16 input(ASCIIToUTF16("ht"));
- const string16 url(ASCIIToUTF16("http://a.com"));
- const SearchProvider::NavigationResult result(
- *provider_.get(), GURL(url), string16(), false, 0, false);
+ const base::string16 input(ASCIIToUTF16("ht"));
+ const base::string16 url(ASCIIToUTF16("http://a.com"));
+ const SearchSuggestionParser::NavigationResult result(
+ ChromeAutocompleteSchemeClassifier(&profile_), GURL(url),
+ AutocompleteMatchType::NAVSUGGEST,
+ base::string16(), std::string(), false, 0, false, input, std::string());
// Check the offset and strings when inline autocompletion is allowed.
QueryForInput(input, false, false);
EXPECT_TRUE(match_inline.allowed_to_be_default_match);
EXPECT_EQ(url, match_inline.contents);
- // Check the same offset and strings when inline autocompletion is prevented.
+ // Check the same strings when inline autocompletion is prevented.
QueryForInput(input, true, false);
AutocompleteMatch match_prevent(provider_->NavigationToMatch(result));
EXPECT_EQ(url, match_prevent.fill_into_edit);
- EXPECT_TRUE(match_prevent.inline_autocompletion.empty());
EXPECT_FALSE(match_prevent.allowed_to_be_default_match);
EXPECT_EQ(url, match_prevent.contents);
}
TEST_F(SearchProviderTest, NavigationInlineDomainClassify) {
QueryForInput(ASCIIToUTF16("w"), false, false);
AutocompleteMatch match(
- provider_->NavigationToMatch(SearchProvider::NavigationResult(
- *provider_.get(), GURL("http://www.wow.com"), string16(), false, 0,
- false)));
+ provider_->NavigationToMatch(SearchSuggestionParser::NavigationResult(
+ ChromeAutocompleteSchemeClassifier(&profile_),
+ GURL("http://www.wow.com"),
+ AutocompleteMatchType::NAVSUGGEST, base::string16(), std::string(),
+ false, 0, false, ASCIIToUTF16("w"), std::string())));
EXPECT_EQ(ASCIIToUTF16("ow.com"), match.inline_autocompletion);
EXPECT_TRUE(match.allowed_to_be_default_match);
EXPECT_EQ(ASCIIToUTF16("www.wow.com"), match.fill_into_edit);
match.contents_class[2].style);
}
-TEST_F(SearchProviderTest, RemoveStaleResultsTest) {
- // TODO(mpearson): Consider expanding this test to explicitly cover
- // testing staleness for keyword results.
- struct {
- const std::string omnibox_input;
- const int verbatim_relevance;
- // These cached suggestions should already be sorted.
- // The particular number 5 as the length of the array is
- // unimportant; it's merely enough cached results to fully test
- // the functioning of RemoveAllStaleResults().
- struct {
- const std::string suggestion;
- const bool is_navigation_result;
- const int relevance;
- // |expect_match| is true if this result should survive
- // RemoveAllStaleResults() filtering against |omnibox_input| below.
- const bool expect_match;
- } results[5];
- } cases[] = {
- // Simple case: multiple query suggestions and no navsuggestions.
- // All query suggestions score less than search-what-you-typed and
- // thus none should be filtered because none will appear first.
- { "x", 1300,
- { { "food", false, 1299, true },
- { "foobar", false, 1298, true },
- { "crazy", false, 1297, true },
- { "friend", false, 1296, true },
- { kNotApplicable, false, 0, false } } },
-
- // Similarly simple cases, but the query suggestion appears first.
- { "f", 1200,
- { { "food", false, 1299, true },
- { "foobar", false, 1298, true },
- { "crazy", false, 1297, true },
- { "friend", false, 1296, true },
- { kNotApplicable, false, 0, false } } },
- { "c", 1200,
- { { "food", false, 1299, false },
- { "foobar", false, 1298, false },
- { "crazy", false, 1297, true },
- { "friend", false, 1296, true },
- { kNotApplicable, false, 0, false } } },
- { "x", 1200,
- { { "food", false, 1299, false },
- { "foobar", false, 1298, false },
- { "crazy", false, 1297, false },
- { "friend", false, 1296, false },
- { kNotApplicable, false, 0, false } } },
-
- // The same sort of cases, just using a mix of queries and navsuggestions.
- { "x", 1300,
- { { "http://food.com/", true, 1299, true },
- { "foobar", false, 1298, true },
- { "http://crazy.com/", true, 1297, true },
- { "friend", false, 1296, true },
- { "http://friend.com/", true, 1295, true } } },
- { "f", 1200,
- { { "http://food.com/", true, 1299, true },
- { "foobar", false, 1298, true },
- { "http://crazy.com/", true, 1297, true },
- { "friend", false, 1296, true },
- { "http://friend.com/", true, 1295, true } } },
- { "c", 1200,
- { { "http://food.com/", true, 1299, false },
- { "foobar", false, 1298, false },
- { "http://crazy.com/", true, 1297, true },
- { "friend", false, 1296, true },
- { "http://friend.com/", true, 1295, true } } },
- { "x", 1200,
- { { "http://food.com/", true, 1299, false },
- { "foobar", false, 1298, false },
- { "http://crazy.com/", true, 1297, false },
- { "friend", false, 1296, false },
- { "http://friend.com/", true, 1295, false } } },
-
- // Run the three tests immediately above again, just with verbatim
- // suppressed. Note that in the last case, all results are filtered.
- // Because verbatim is also suppressed, SearchProvider will realize
- // in UpdateMatches() that it needs to restore verbatim to fulfill
- // its constraints. This restoration does not happen in
- // RemoveAllStaleResults() and hence is not tested here. This restoration
- // is tested in the DefaultFetcherSuggestRelevance test.
- { "f", 0,
- { { "http://food.com/", true, 1299, true },
- { "foobar", false, 1298, true },
- { "http://crazy.com/", true, 1297, true },
- { "friend", false, 1296, true },
- { "http://friend.com/", true, 1295, true } } },
- { "c", 0,
- { { "http://food.com/", true, 1299, false },
- { "foobar", false, 1298, false },
- { "http://crazy.com/", true, 1297, true },
- { "friend", false, 1296, true },
- { "http://friend.com/", true, 1295, true } } },
- { "x", 0,
- { { "http://food.com/", true, 1299, false },
- { "foobar", false, 1298, false },
- { "http://crazy.com/", true, 1297, false },
- { "friend", false, 1296, false },
- { "http://friend.com/", true, 1295, false } } },
-
- // The same sort of tests again, just with verbatim with a score
- // that would place it in between other suggestions.
- { "f", 1290,
- { { "http://food.com/", true, 1299, true },
- { "foobar", false, 1288, true },
- { "http://crazy.com/", true, 1277, true },
- { "friend", false, 1266, true },
- { "http://friend.com/", true, 1255, true } } },
- { "c", 1290,
- { { "http://food.com/", true, 1299, false },
- { "foobar", false, 1288, true },
- { "http://crazy.com/", true, 1277, true },
- { "friend", false, 1266, true },
- { "http://friend.com/", true, 1255, true } } },
- { "c", 1270,
- { { "http://food.com/", true, 1299, false },
- { "foobar", false, 1288, false },
- { "http://crazy.com/", true, 1277, true },
- { "friend", false, 1266, true },
- { "http://friend.com/", true, 1255, true } } },
- { "x", 1280,
- { { "http://food.com/", true, 1299, false },
- { "foobar", false, 1288, false },
- { "http://crazy.com/", true, 1277, true },
- { "friend", false, 1266, true },
- { "http://friend.com/", true, 1255, true } } },
- };
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
- // Initialize cached results for this test case.
- provider_->default_results_.verbatim_relevance =
- cases[i].verbatim_relevance;
- provider_->default_results_.navigation_results.clear();
- provider_->default_results_.suggest_results.clear();
- for (size_t j = 0; j < ARRAYSIZE_UNSAFE(cases[i].results); ++j) {
- const std::string& suggestion = cases[i].results[j].suggestion;
- if (suggestion == kNotApplicable)
- break;
- if (cases[i].results[j].is_navigation_result) {
- provider_->default_results_.navigation_results.push_back(
- SearchProvider::NavigationResult(
- *provider_.get(), GURL(suggestion), string16(), false,
- cases[i].results[j].relevance, false));
- } else {
- provider_->default_results_.suggest_results.push_back(
- SearchProvider::SuggestResult(ASCIIToUTF16(suggestion), string16(),
- string16(), std::string(), false,
- cases[i].results[j].relevance,
- false, false));
- }
- }
-
- provider_->input_ = AutocompleteInput(
- ASCIIToUTF16(cases[i].omnibox_input), string16::npos, string16(),
- GURL(), AutocompleteInput::INVALID_SPEC, false, false, true,
- AutocompleteInput::ALL_MATCHES);
- provider_->RemoveAllStaleResults();
-
- // Check cached results.
- SearchProvider::SuggestResults::const_iterator sug_it =
- provider_->default_results_.suggest_results.begin();
- const SearchProvider::SuggestResults::const_iterator sug_end =
- provider_->default_results_.suggest_results.end();
- SearchProvider::NavigationResults::const_iterator nav_it =
- provider_->default_results_.navigation_results.begin();
- const SearchProvider::NavigationResults::const_iterator nav_end =
- provider_->default_results_.navigation_results.end();
- for (size_t j = 0; j < ARRAYSIZE_UNSAFE(cases[i].results); ++j) {
- const std::string& suggestion = cases[i].results[j].suggestion;
- if (suggestion == kNotApplicable)
- continue;
- if (!cases[i].results[j].expect_match)
- continue;
- if (cases[i].results[j].is_navigation_result) {
- ASSERT_NE(nav_end, nav_it) << "Failed to find " << suggestion;
- EXPECT_EQ(suggestion, nav_it->url().spec());
- ++nav_it;
- } else {
- ASSERT_NE(sug_end, sug_it) << "Failed to find " << suggestion;
- EXPECT_EQ(ASCIIToUTF16(suggestion), sug_it->suggestion());
- ++sug_it;
- }
- }
- EXPECT_EQ(sug_end, sug_it);
- EXPECT_EQ(nav_end, nav_it);
- }
-}
-
#if !defined(OS_WIN)
// Verify entity suggestion parsing.
TEST_F(SearchProviderTest, ParseEntitySuggestion) {
struct Match {
std::string contents;
+ std::string description;
std::string query_params;
std::string fill_into_edit;
AutocompleteMatchType::Type type;
- size_t classification_offsets[3];
- int classification_styles[3];
};
- const size_t invalid_offset = 10;
- const int invalid_style = -1;
const Match kEmptyMatch = {
- kNotApplicable, kNotApplicable, kNotApplicable,
- AutocompleteMatchType::NUM_TYPES,
- { invalid_offset, invalid_offset, invalid_offset },
- { invalid_style, invalid_style, invalid_style } };
+ kNotApplicable, kNotApplicable, kNotApplicable, kNotApplicable,
+ AutocompleteMatchType::NUM_TYPES};
struct {
const std::string input_text;
} cases[] = {
// A query and an entity suggestion with different search terms.
{ "x",
- "[\"x\",[\"xy\", \"xy\"],[\"\",\"\"],[],"
+ "[\"x\",[\"xy\", \"yy\"],[\"\",\"\"],[],"
" {\"google:suggestdetail\":[{},"
- " {\"a\":\"A\",\"dq\":\"yy\",\"q\":\"p=v\"}],"
+ " {\"a\":\"A\",\"t\":\"xy\",\"q\":\"p=v\"}],"
"\"google:suggesttype\":[\"QUERY\",\"ENTITY\"]}]",
- { { "x", "", "x", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
- { 0, invalid_offset, invalid_offset },
- { ACMatchClassification::NONE, invalid_style, invalid_style } },
- { "xy", "", "xy", AutocompleteMatchType::SEARCH_SUGGEST,
- { 0, 1, invalid_offset },
- { ACMatchClassification::NONE, ACMatchClassification::MATCH,
- invalid_style } },
- { "xy - A", "p=v", "yy", AutocompleteMatchType::SEARCH_SUGGEST,
- { 0, 1, 2 },
- { ACMatchClassification::NONE, ACMatchClassification::MATCH,
- ACMatchClassification::DIM } },
+ { { "x", "", "", "x", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED },
+ { "xy", "", "", "xy", AutocompleteMatchType::SEARCH_SUGGEST },
+ { "xy", "A", "p=v", "yy",
+ AutocompleteMatchType::SEARCH_SUGGEST_ENTITY },
kEmptyMatch,
kEmptyMatch
},
{ "x",
"[\"x\",[\"xy\", \"xy\"],[\"\",\"\"],[],"
" {\"google:suggestdetail\":[{},"
- " {\"a\":\"A\",\"dq\":\"xy\",\"q\":\"p=v\"}],"
+ " {\"a\":\"A\",\"t\":\"xy\",\"q\":\"p=v\"}],"
"\"google:suggesttype\":[\"QUERY\",\"ENTITY\"]}]",
- { { "x", "", "x", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
- { 0, invalid_offset, invalid_offset },
- { ACMatchClassification::NONE, invalid_style, invalid_style } },
- { "xy", "", "xy", AutocompleteMatchType::SEARCH_SUGGEST,
- { 0, 1, invalid_offset },
- { ACMatchClassification::NONE, ACMatchClassification::MATCH,
- invalid_style } },
- { "xy - A", "p=v", "xy", AutocompleteMatchType::SEARCH_SUGGEST,
- { 0, 1, 2 },
- { ACMatchClassification::NONE, ACMatchClassification::MATCH,
- ACMatchClassification::DIM } },
+ { { "x", "", "", "x", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED },
+ { "xy", "", "", "xy", AutocompleteMatchType::SEARCH_SUGGEST },
+ { "xy", "A", "p=v", "xy",
+ AutocompleteMatchType::SEARCH_SUGGEST_ENTITY },
kEmptyMatch,
kEmptyMatch
},
SCOPED_TRACE("for input with json = " + cases[i].response_json);
+ ASSERT_LE(matches.size(), ARRAYSIZE_UNSAFE(cases[i].matches));
size_t j = 0;
// Ensure that the returned matches equal the expectations.
for (; j < matches.size(); ++j) {
const Match& match = cases[i].matches[j];
SCOPED_TRACE(" and match index: " + base::IntToString(j));
EXPECT_EQ(match.contents,
- UTF16ToUTF8(matches[j].contents));
+ base::UTF16ToUTF8(matches[j].contents));
+ EXPECT_EQ(match.description,
+ base::UTF16ToUTF8(matches[j].description));
EXPECT_EQ(match.query_params,
matches[j].search_terms_args->suggest_query_params);
EXPECT_EQ(match.fill_into_edit,
- UTF16ToUTF8(matches[j].fill_into_edit));
+ base::UTF16ToUTF8(matches[j].fill_into_edit));
EXPECT_EQ(match.type, matches[j].type);
-
- size_t k = 0;
- for (; k < matches[j].contents_class.size(); k++) {
- SCOPED_TRACE(" and contents class: " + base::IntToString(k));
- EXPECT_EQ(match.classification_offsets[k],
- matches[j].contents_class[k].offset);
- EXPECT_EQ(match.classification_styles[k],
- matches[j].contents_class[k].style);
- }
- for (; k < ARRAYSIZE_UNSAFE(match.classification_offsets); k++) {
- SCOPED_TRACE(" and contents class: " + base::IntToString(k));
- EXPECT_EQ(match.classification_offsets[k], invalid_offset);
- EXPECT_EQ(match.classification_styles[k], invalid_style);
- }
}
// Ensure that no expected matches are missing.
for (; j < ARRAYSIZE_UNSAFE(cases[i].matches); ++j) {
SCOPED_TRACE(" and match index: " + base::IntToString(j));
EXPECT_EQ(cases[i].matches[j].contents, kNotApplicable);
+ EXPECT_EQ(cases[i].matches[j].description, kNotApplicable);
EXPECT_EQ(cases[i].matches[j].query_params, kNotApplicable);
EXPECT_EQ(cases[i].matches[j].fill_into_edit, kNotApplicable);
EXPECT_EQ(cases[i].matches[j].type, AutocompleteMatchType::NUM_TYPES);
}
#endif // !defined(OS_WIN)
-TEST_F(SearchProviderTest, SearchHistorySuppressesEntitySuggestion) {
- struct Match {
- std::string contents;
- std::string query_params;
- std::string fill_into_edit;
- AutocompleteMatchType::Type type;
- };
- const Match kEmptyMatch = { kNotApplicable, kNotApplicable, kNotApplicable,
- AutocompleteMatchType::NUM_TYPES};
-
- struct {
- const std::string input_text;
- const std::string history_search_term;
- const std::string response_json;
- const Match matches[5];
- } cases[] = {
- // Search history suppresses both query and entity suggestions.
- { "x", "xy",
- "[\"x\",[\"xy\", \"xy\"],[\"\",\"\"],[],"
- " {\"google:suggestdetail\":[{},"
- " {\"a\":\"A\",\"dq\":\"xy\",\"q\":\"p=v\"}],"
- "\"google:suggesttype\":[\"QUERY\",\"ENTITY\"]}]",
- {
- {"xy", "", "xy", AutocompleteMatchType::SEARCH_HISTORY},
- {"x", "", "x", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED},
- {"xy - A", "p=v", "xy", AutocompleteMatchType::SEARCH_SUGGEST},
- kEmptyMatch,
- kEmptyMatch,
- },
- },
- // Search history suppresses only query suggestion.
- { "x", "xyy",
- "[\"x\",[\"xy\", \"xy\"],[\"\",\"\"],[],"
- " {\"google:suggestdetail\":[{},"
- " {\"a\":\"A\",\"dq\":\"xyy\",\"q\":\"p=v\"}],"
- "\"google:suggesttype\":[\"QUERY\",\"ENTITY\"]}]",
- {
- {"xyy", "", "xyy", AutocompleteMatchType::SEARCH_HISTORY},
- {"xy", "", "xy", AutocompleteMatchType::SEARCH_HISTORY},
- {"x", "", "x", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED},
- {"xy - A", "p=v", "xyy", AutocompleteMatchType::SEARCH_SUGGEST},
- kEmptyMatch,
- },
- }
- };
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
- GURL term_url(AddSearchToHistory(
- default_t_url_, ASCIIToUTF16(cases[i].history_search_term), 10));
- profile_.BlockUntilHistoryProcessesPendingRequests();
- QueryForInput(ASCIIToUTF16(cases[i].input_text), false, false);
-
- // Set up a default fetcher with provided results.
- net::TestURLFetcher* fetcher =
- test_factory_.GetFetcherByID(
- SearchProvider::kDefaultProviderURLFetcherID);
- ASSERT_TRUE(fetcher);
- fetcher->set_response_code(200);
- fetcher->SetResponseString(cases[i].response_json);
- fetcher->delegate()->OnURLFetchComplete(fetcher);
-
- RunTillProviderDone();
-
- const ACMatches& matches = provider_->matches();
- ASSERT_FALSE(matches.empty());
- SCOPED_TRACE("for case: " + base::IntToString(i));
-
- size_t j = 0;
- // Ensure that the returned matches equal the expectations.
- for (; j < matches.size(); ++j) {
- SCOPED_TRACE(" and match index: " + base::IntToString(j));
- EXPECT_EQ(cases[i].matches[j].contents,
- UTF16ToUTF8(matches[j].contents));
- EXPECT_EQ(cases[i].matches[j].query_params,
- matches[j].search_terms_args->suggest_query_params);
- EXPECT_EQ(cases[i].matches[j].fill_into_edit,
- UTF16ToUTF8(matches[j].fill_into_edit));
- EXPECT_EQ(cases[i].matches[j].type, matches[j].type);
- }
- // Ensure that no expected matches are missing.
- for (; j < ARRAYSIZE_UNSAFE(cases[i].matches); ++j) {
- SCOPED_TRACE(" and match index: " + base::IntToString(j));
- EXPECT_EQ(cases[i].matches[j].contents, kNotApplicable);
- EXPECT_EQ(cases[i].matches[j].query_params, kNotApplicable);
- EXPECT_EQ(cases[i].matches[j].fill_into_edit, kNotApplicable);
- EXPECT_EQ(cases[i].matches[j].type, AutocompleteMatchType::NUM_TYPES);
- }
- }
-}
// A basic test that verifies the prefetch metadata parsing logic.
TEST_F(SearchProviderTest, PrefetchMetadataParsing) {
ASSERT_FALSE(matches.empty());
EXPECT_GE(matches[0].relevance, 1300);
+ ASSERT_LE(matches.size(), ARRAYSIZE_UNSAFE(cases[i].matches));
// Ensure that the returned matches equal the expectations.
for (size_t j = 0; j < matches.size(); ++j) {
SCOPED_TRACE(description);
- EXPECT_EQ(cases[i].matches[j].contents, UTF16ToUTF8(matches[j].contents));
+ EXPECT_EQ(cases[i].matches[j].contents,
+ base::UTF16ToUTF8(matches[j].contents));
EXPECT_EQ(cases[i].matches[j].allowed_to_be_prefetched,
SearchProvider::ShouldPrefetch(matches[j]));
EXPECT_EQ(cases[i].matches[j].type, matches[j].type);
}
}
+TEST_F(SearchProviderTest, XSSIGuardedJSONParsing_InvalidResponse) {
+ ClearAllResults();
+
+ std::string input_str("abc");
+ QueryForInput(ASCIIToUTF16(input_str), false, false);
+
+ // Set up a default fetcher with provided results.
+ net::TestURLFetcher* fetcher =
+ test_factory_.GetFetcherByID(
+ SearchProvider::kDefaultProviderURLFetcherID);
+ ASSERT_TRUE(fetcher);
+ fetcher->set_response_code(200);
+ fetcher->SetResponseString("this is a bad non-json response");
+ fetcher->delegate()->OnURLFetchComplete(fetcher);
+
+ RunTillProviderDone();
+
+ const ACMatches& matches = provider_->matches();
+
+ // Should have exactly one "search what you typed" match
+ ASSERT_TRUE(matches.size() == 1);
+ EXPECT_EQ(input_str, base::UTF16ToUTF8(matches[0].contents));
+ EXPECT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
+ matches[0].type);
+}
+
// A basic test that verifies that the XSSI guarded JSON response is parsed
// correctly.
-TEST_F(SearchProviderTest, XSSIGuardedJSONParsing) {
+TEST_F(SearchProviderTest, XSSIGuardedJSONParsing_ValidResponses) {
struct Match {
std::string contents;
AutocompleteMatchType::Type type;
};
- const Match kEmptyMatch = { kNotApplicable,
- AutocompleteMatchType::NUM_TYPES};
+ const Match kEmptyMatch = {
+ kNotApplicable, AutocompleteMatchType::NUM_TYPES
+ };
struct {
const std::string input_text;
EXPECT_GE(matches[0].relevance, 1300);
SCOPED_TRACE("for case: " + base::IntToString(i));
+ ASSERT_LE(matches.size(), ARRAYSIZE_UNSAFE(cases[i].matches));
size_t j = 0;
// Ensure that the returned matches equal the expectations.
for (; j < matches.size(); ++j) {
SCOPED_TRACE("and match: " + base::IntToString(j));
- EXPECT_EQ(cases[i].matches[j].contents, UTF16ToUTF8(matches[j].contents));
+ EXPECT_EQ(cases[i].matches[j].contents,
+ base::UTF16ToUTF8(matches[j].contents));
EXPECT_EQ(cases[i].matches[j].type, matches[j].type);
}
for (; j < ARRAYSIZE_UNSAFE(cases[i].matches); ++j) {
}
}
+// Test that deletion url gets set on an AutocompleteMatch when available for a
+// personalized query or a personalized URL.
+TEST_F(SearchProviderTest, ParseDeletionUrl) {
+ struct Match {
+ std::string contents;
+ std::string deletion_url;
+ AutocompleteMatchType::Type type;
+ };
+
+ const Match kEmptyMatch = {
+ kNotApplicable, "", AutocompleteMatchType::NUM_TYPES
+ };
+
+ const char* url[] = {
+ "http://defaultturl/complete/deleteitems"
+ "?delq=ab&client=chrome&deltok=xsrf124",
+ "http://defaultturl/complete/deleteitems"
+ "?delq=www.amazon.com&client=chrome&deltok=xsrf123",
+ };
+
+ struct {
+ const std::string input_text;
+ const std::string response_json;
+ const Match matches[5];
+ } cases[] = {
+ // A deletion URL on a personalized query should be reflected in the
+ // resulting AutocompleteMatch.
+ { "a",
+ "[\"a\",[\"ab\", \"ac\",\"www.amazon.com\"],[],[],"
+ "{\"google:suggesttype\":[\"PERSONALIZED_QUERY\",\"QUERY\","
+ "\"PERSONALIZED_NAVIGATION\"],"
+ "\"google:suggestrelevance\":[3, 2, 1],"
+ "\"google:suggestdetail\":[{\"du\":"
+ "\"/complete/deleteitems?delq=ab&client=chrome"
+ "&deltok=xsrf124\"}, {}, {\"du\":"
+ "\"/complete/deleteitems?delq=www.amazon.com&"
+ "client=chrome&deltok=xsrf123\"}]}]",
+ { { "a", "", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED },
+ { "ab", url[0], AutocompleteMatchType::SEARCH_SUGGEST },
+ { "ac", "", AutocompleteMatchType::SEARCH_SUGGEST },
+ { "www.amazon.com", url[1],
+ AutocompleteMatchType::NAVSUGGEST_PERSONALIZED },
+ kEmptyMatch,
+ },
+ },
+ // Personalized queries or a personalized URL without deletion URLs
+ // shouldn't cause errors.
+ { "a",
+ "[\"a\",[\"ab\", \"ac\"],[],[],"
+ "{\"google:suggesttype\":[\"PERSONALIZED_QUERY\",\"QUERY\","
+ "\"PERSONALIZED_NAVIGATION\"],"
+ "\"google:suggestrelevance\":[1, 2],"
+ "\"google:suggestdetail\":[{}, {}]}]",
+ { { "a", "", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED },
+ { "ac", "", AutocompleteMatchType::SEARCH_SUGGEST },
+ { "ab", "", AutocompleteMatchType::SEARCH_SUGGEST },
+ { "www.amazon.com", "",
+ AutocompleteMatchType::NAVSUGGEST_PERSONALIZED },
+ kEmptyMatch,
+ },
+ },
+ // Personalized queries or a personalized URL without
+ // google:suggestdetail shouldn't cause errors.
+ { "a",
+ "[\"a\",[\"ab\", \"ac\"],[],[],"
+ "{\"google:suggesttype\":[\"PERSONALIZED_QUERY\",\"QUERY\","
+ "\"PERSONALIZED_NAVIGATION\"],"
+ "\"google:suggestrelevance\":[1, 2]}]",
+ { { "a", "", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED },
+ { "ac", "", AutocompleteMatchType::SEARCH_SUGGEST },
+ { "ab", "", AutocompleteMatchType::SEARCH_SUGGEST },
+ { "www.amazon.com", "",
+ AutocompleteMatchType::NAVSUGGEST_PERSONALIZED },
+ kEmptyMatch,
+ },
+ },
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
+ QueryForInput(ASCIIToUTF16(cases[i].input_text), false, false);
+
+ net::TestURLFetcher* fetcher = test_factory_.GetFetcherByID(
+ SearchProvider::kDefaultProviderURLFetcherID);
+ ASSERT_TRUE(fetcher);
+ fetcher->set_response_code(200);
+ fetcher->SetResponseString(cases[i].response_json);
+ fetcher->delegate()->OnURLFetchComplete(fetcher);
+
+ RunTillProviderDone();
+
+ const ACMatches& matches = provider_->matches();
+ ASSERT_FALSE(matches.empty());
+
+ SCOPED_TRACE("for input with json = " + cases[i].response_json);
+
+ for (size_t j = 0; j < matches.size(); ++j) {
+ const Match& match = cases[i].matches[j];
+ SCOPED_TRACE(" and match index: " + base::IntToString(j));
+ EXPECT_EQ(match.contents, base::UTF16ToUTF8(matches[j].contents));
+ EXPECT_EQ(match.deletion_url, matches[j].GetAdditionalInfo(
+ "deletion_url"));
+ }
+ }
+}
TEST_F(SearchProviderTest, ReflectsBookmarkBarState) {
profile_.GetPrefs()->SetBoolean(prefs::kShowBookmarkBar, false);
- string16 term = term1_.substr(0, term1_.length() - 1);
+ base::string16 term = term1_.substr(0, term1_.length() - 1);
QueryForInput(term, true, false);
ASSERT_FALSE(provider_->matches().empty());
EXPECT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
ASSERT_TRUE(provider_->matches()[0].search_terms_args != NULL);
EXPECT_TRUE(provider_->matches()[0].search_terms_args->bookmark_bar_pinned);
}
+
+TEST_F(SearchProviderTest, CanSendURL) {
+ TemplateURLData template_url_data;
+ template_url_data.short_name = ASCIIToUTF16("t");
+ template_url_data.SetURL("http://www.google.com/{searchTerms}");
+ template_url_data.suggestions_url = "http://www.google.com/{searchTerms}";
+ template_url_data.instant_url = "http://does/not/exist?strk=1";
+ template_url_data.search_terms_replacement_key = "strk";
+ template_url_data.id = SEARCH_ENGINE_GOOGLE;
+ TemplateURL google_template_url(template_url_data);
+
+ // Create field trial.
+ CreateZeroSuggestFieldTrial(true);
+
+ // Not signed in.
+ EXPECT_FALSE(SearchProvider::CanSendURL(
+ GURL("http://www.google.com/search"),
+ GURL("https://www.google.com/complete/search"), &google_template_url,
+ metrics::OmniboxEventProto::OTHER, SearchTermsData(), &profile_));
+ SigninManagerBase* signin = SigninManagerFactory::GetForProfile(&profile_);
+ signin->SetAuthenticatedUsername("test");
+
+ // All conditions should be met.
+ EXPECT_TRUE(SearchProvider::CanSendURL(
+ GURL("http://www.google.com/search"),
+ GURL("https://www.google.com/complete/search"), &google_template_url,
+ metrics::OmniboxEventProto::OTHER, SearchTermsData(), &profile_));
+
+ // Not in field trial.
+ ResetFieldTrialList();
+ CreateZeroSuggestFieldTrial(false);
+ EXPECT_FALSE(SearchProvider::CanSendURL(
+ GURL("http://www.google.com/search"),
+ GURL("https://www.google.com/complete/search"), &google_template_url,
+ metrics::OmniboxEventProto::OTHER, SearchTermsData(), &profile_));
+ ResetFieldTrialList();
+ CreateZeroSuggestFieldTrial(true);
+
+ // Invalid page URL.
+ EXPECT_FALSE(SearchProvider::CanSendURL(
+ GURL("badpageurl"),
+ GURL("https://www.google.com/complete/search"), &google_template_url,
+ metrics::OmniboxEventProto::OTHER, SearchTermsData(), &profile_));
+
+ // Invalid page classification.
+ EXPECT_FALSE(SearchProvider::CanSendURL(
+ GURL("http://www.google.com/search"),
+ GURL("https://www.google.com/complete/search"), &google_template_url,
+ metrics::OmniboxEventProto::INSTANT_NTP_WITH_FAKEBOX_AS_STARTING_FOCUS,
+ SearchTermsData(), &profile_));
+
+ // Invalid page classification.
+ EXPECT_FALSE(SearchProvider::CanSendURL(
+ GURL("http://www.google.com/search"),
+ GURL("https://www.google.com/complete/search"), &google_template_url,
+ metrics::OmniboxEventProto::INSTANT_NTP_WITH_OMNIBOX_AS_STARTING_FOCUS,
+ SearchTermsData(), &profile_));
+
+ // HTTPS page URL on same domain as provider.
+ EXPECT_TRUE(SearchProvider::CanSendURL(
+ GURL("https://www.google.com/search"),
+ GURL("https://www.google.com/complete/search"),
+ &google_template_url, metrics::OmniboxEventProto::OTHER,
+ SearchTermsData(), &profile_));
+
+ // Non-HTTP[S] page URL on same domain as provider.
+ EXPECT_FALSE(SearchProvider::CanSendURL(
+ GURL("ftp://www.google.com/search"),
+ GURL("https://www.google.com/complete/search"), &google_template_url,
+ metrics::OmniboxEventProto::OTHER, SearchTermsData(), &profile_));
+
+ // Non-HTTP page URL on different domain.
+ EXPECT_FALSE(SearchProvider::CanSendURL(
+ GURL("https://www.notgoogle.com/search"),
+ GURL("https://www.google.com/complete/search"), &google_template_url,
+ metrics::OmniboxEventProto::OTHER, SearchTermsData(), &profile_));
+
+ // Non-HTTPS provider.
+ EXPECT_FALSE(SearchProvider::CanSendURL(
+ GURL("http://www.google.com/search"),
+ GURL("http://www.google.com/complete/search"), &google_template_url,
+ metrics::OmniboxEventProto::OTHER, SearchTermsData(), &profile_));
+
+ // Suggest disabled.
+ profile_.GetPrefs()->SetBoolean(prefs::kSearchSuggestEnabled, false);
+ EXPECT_FALSE(SearchProvider::CanSendURL(
+ GURL("http://www.google.com/search"),
+ GURL("https://www.google.com/complete/search"), &google_template_url,
+ metrics::OmniboxEventProto::OTHER, SearchTermsData(), &profile_));
+ profile_.GetPrefs()->SetBoolean(prefs::kSearchSuggestEnabled, true);
+
+ // Incognito.
+ EXPECT_FALSE(SearchProvider::CanSendURL(
+ GURL("http://www.google.com/search"),
+ GURL("https://www.google.com/complete/search"), &google_template_url,
+ metrics::OmniboxEventProto::OTHER, SearchTermsData(),
+ profile_.GetOffTheRecordProfile()));
+
+ // Tab sync not enabled.
+ profile_.GetPrefs()->SetBoolean(sync_driver::prefs::kSyncKeepEverythingSynced,
+ false);
+ profile_.GetPrefs()->SetBoolean(sync_driver::prefs::kSyncTabs, false);
+ EXPECT_FALSE(SearchProvider::CanSendURL(
+ GURL("http://www.google.com/search"),
+ GURL("https://www.google.com/complete/search"), &google_template_url,
+ metrics::OmniboxEventProto::OTHER, SearchTermsData(), &profile_));
+ profile_.GetPrefs()->SetBoolean(sync_driver::prefs::kSyncTabs, true);
+
+ // Tab sync is encrypted.
+ ProfileSyncService* service =
+ ProfileSyncServiceFactory::GetInstance()->GetForProfile(&profile_);
+ syncer::ModelTypeSet encrypted_types = service->GetEncryptedDataTypes();
+ encrypted_types.Put(syncer::SESSIONS);
+ service->OnEncryptedTypesChanged(encrypted_types, false);
+ EXPECT_FALSE(SearchProvider::CanSendURL(
+ GURL("http://www.google.com/search"),
+ GURL("https://www.google.com/complete/search"), &google_template_url,
+ metrics::OmniboxEventProto::OTHER, SearchTermsData(), &profile_));
+ encrypted_types.Remove(syncer::SESSIONS);
+ service->OnEncryptedTypesChanged(encrypted_types, false);
+
+ // Check that there were no side effects from previous tests.
+ EXPECT_TRUE(SearchProvider::CanSendURL(
+ GURL("http://www.google.com/search"),
+ GURL("https://www.google.com/complete/search"), &google_template_url,
+ metrics::OmniboxEventProto::OTHER, SearchTermsData(), &profile_));
+}
+
+TEST_F(SearchProviderTest, TestDeleteMatch) {
+ AutocompleteMatch match(provider_, 0, true,
+ AutocompleteMatchType::SEARCH_SUGGEST);
+ match.RecordAdditionalInfo(
+ SearchProvider::kDeletionUrlKey,
+ "https://www.google.com/complete/deleteitem?q=foo");
+
+ // Test a successful deletion request.
+ provider_->matches_.push_back(match);
+ provider_->DeleteMatch(match);
+ EXPECT_FALSE(provider_->deletion_handlers_.empty());
+ EXPECT_TRUE(provider_->matches_.empty());
+ // Set up a default fetcher with provided results.
+ net::TestURLFetcher* fetcher = test_factory_.GetFetcherByID(
+ SearchProvider::kDeletionURLFetcherID);
+ ASSERT_TRUE(fetcher);
+ fetcher->set_response_code(200);
+ fetcher->delegate()->OnURLFetchComplete(fetcher);
+ EXPECT_TRUE(provider_->deletion_handlers_.empty());
+ EXPECT_TRUE(provider_->is_success());
+
+ // Test a failing deletion request.
+ provider_->matches_.push_back(match);
+ provider_->DeleteMatch(match);
+ EXPECT_FALSE(provider_->deletion_handlers_.empty());
+ // Set up a default fetcher with provided results.
+ fetcher = test_factory_.GetFetcherByID(
+ SearchProvider::kDeletionURLFetcherID);
+ ASSERT_TRUE(fetcher);
+ fetcher->set_response_code(500);
+ fetcher->delegate()->OnURLFetchComplete(fetcher);
+ EXPECT_TRUE(provider_->deletion_handlers_.empty());
+ EXPECT_FALSE(provider_->is_success());
+}
+
+TEST_F(SearchProviderTest, TestDeleteHistoryQueryMatch) {
+ GURL term_url(
+ AddSearchToHistory(default_t_url_, ASCIIToUTF16("flash games"), 1));
+ profile_.BlockUntilHistoryProcessesPendingRequests();
+
+ AutocompleteMatch games;
+ QueryForInput(ASCIIToUTF16("fla"), false, false);
+ profile_.BlockUntilHistoryProcessesPendingRequests();
+ ASSERT_NO_FATAL_FAILURE(FinishDefaultSuggestQuery());
+ ASSERT_TRUE(FindMatchWithContents(ASCIIToUTF16("flash games"), &games));
+
+ size_t matches_before = provider_->matches().size();
+ provider_->DeleteMatch(games);
+ EXPECT_EQ(matches_before - 1, provider_->matches().size());
+
+ // Process history deletions.
+ profile_.BlockUntilHistoryProcessesPendingRequests();
+
+ // Check that the match is gone.
+ QueryForInput(ASCIIToUTF16("fla"), false, false);
+ profile_.BlockUntilHistoryProcessesPendingRequests();
+ ASSERT_NO_FATAL_FAILURE(FinishDefaultSuggestQuery());
+ EXPECT_FALSE(FindMatchWithContents(ASCIIToUTF16("flash games"), &games));
+}
+
+// Verifies that duplicates are preserved in AddMatchToMap().
+TEST_F(SearchProviderTest, CheckDuplicateMatchesSaved) {
+ AddSearchToHistory(default_t_url_, ASCIIToUTF16("a"), 1);
+ AddSearchToHistory(default_t_url_, ASCIIToUTF16("alpha"), 1);
+ AddSearchToHistory(default_t_url_, ASCIIToUTF16("avid"), 1);
+
+ profile_.BlockUntilHistoryProcessesPendingRequests();
+ QueryForInput(ASCIIToUTF16("a"), false, false);
+
+ // Make sure the default provider's suggest service was queried.
+ net::TestURLFetcher* fetcher = test_factory_.GetFetcherByID(
+ SearchProvider::kDefaultProviderURLFetcherID);
+ ASSERT_TRUE(fetcher);
+
+ // Tell the SearchProvider the suggest query is done.
+ fetcher->set_response_code(200);
+ fetcher->SetResponseString(
+ "[\"a\",[\"a\", \"alpha\", \"avid\", \"apricot\"],[],[],"
+ "{\"google:suggestrelevance\":[1450, 1200, 1150, 1100],"
+ "\"google:verbatimrelevance\":1350}]");
+ fetcher->delegate()->OnURLFetchComplete(fetcher);
+ fetcher = NULL;
+
+ // Run till the history results complete.
+ RunTillProviderDone();
+
+ AutocompleteMatch verbatim, match_alpha, match_apricot, match_avid;
+ EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("a"), &verbatim));
+ EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("alpha"), &match_alpha));
+ EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("apricot"), &match_apricot));
+ EXPECT_TRUE(FindMatchWithContents(ASCIIToUTF16("avid"), &match_avid));
+
+ // Verbatim match duplicates are added such that each one has a higher
+ // relevance than the previous one.
+ EXPECT_EQ(2U, verbatim.duplicate_matches.size());
+
+ // Other match duplicates are added in descending relevance order.
+ EXPECT_EQ(1U, match_alpha.duplicate_matches.size());
+ EXPECT_EQ(1U, match_avid.duplicate_matches.size());
+
+ EXPECT_EQ(0U, match_apricot.duplicate_matches.size());
+}
+
+TEST_F(SearchProviderTest, SuggestQueryUsesToken) {
+ CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableAnswersInSuggest);
+
+ TemplateURLService* turl_model =
+ TemplateURLServiceFactory::GetForProfile(&profile_);
+
+ TemplateURLData data;
+ data.short_name = ASCIIToUTF16("default");
+ data.SetKeyword(data.short_name);
+ data.SetURL("http://example/{searchTerms}{google:sessionToken}");
+ data.suggestions_url =
+ "http://suggest/?q={searchTerms}&{google:sessionToken}";
+ default_t_url_ = new TemplateURL(data);
+ turl_model->Add(default_t_url_);
+ turl_model->SetUserSelectedDefaultSearchProvider(default_t_url_);
+
+ base::string16 term = term1_.substr(0, term1_.length() - 1);
+ QueryForInput(term, false, false);
+
+ // Make sure the default provider's suggest service was queried.
+ net::TestURLFetcher* fetcher = test_factory_.GetFetcherByID(
+ SearchProvider::kDefaultProviderURLFetcherID);
+ ASSERT_TRUE(fetcher);
+
+ // And the URL matches what we expected.
+ TemplateURLRef::SearchTermsArgs search_terms_args(term);
+ search_terms_args.session_token = provider_->current_token_;
+ GURL expected_url(default_t_url_->suggestions_url_ref().ReplaceSearchTerms(
+ search_terms_args, turl_model->search_terms_data()));
+ EXPECT_EQ(fetcher->GetOriginalURL().spec(), expected_url.spec());
+
+ // Complete running the fetcher to clean up.
+ fetcher->set_response_code(200);
+ fetcher->delegate()->OnURLFetchComplete(fetcher);
+ RunTillProviderDone();
+}
+
+TEST_F(SearchProviderTest, SessionToken) {
+ // Subsequent calls always get the same token.
+ std::string token = provider_->GetSessionToken();
+ std::string token2 = provider_->GetSessionToken();
+ EXPECT_EQ(token, token2);
+ EXPECT_FALSE(token.empty());
+
+ // Calls do not regenerate a token.
+ provider_->current_token_ = "PRE-EXISTING TOKEN";
+ token = provider_->GetSessionToken();
+ EXPECT_EQ(token, "PRE-EXISTING TOKEN");
+
+ // ... unless the token has expired.
+ provider_->current_token_.clear();
+ const base::TimeDelta kSmallDelta = base::TimeDelta::FromMilliseconds(1);
+ provider_->token_expiration_time_ = base::TimeTicks::Now() - kSmallDelta;
+ token = provider_->GetSessionToken();
+ EXPECT_FALSE(token.empty());
+ EXPECT_EQ(token, provider_->current_token_);
+
+ // The expiration time is always updated.
+ provider_->GetSessionToken();
+ base::TimeTicks expiration_time_1 = provider_->token_expiration_time_;
+ base::PlatformThread::Sleep(kSmallDelta);
+ provider_->GetSessionToken();
+ base::TimeTicks expiration_time_2 = provider_->token_expiration_time_;
+ EXPECT_GT(expiration_time_2, expiration_time_1);
+ EXPECT_GE(expiration_time_2, expiration_time_1 + kSmallDelta);
+}
+
+TEST_F(SearchProviderTest, AnswersCache) {
+ // Initial condition: empty cache.
+ ASSERT_TRUE(provider_->last_answer_seen_.full_query_text.empty());
+
+ AutocompleteResult result;
+ ACMatches matches;
+ AutocompleteMatch match1;
+ match1.answer_contents = base::ASCIIToUTF16("m1");
+ match1.answer_type = base::ASCIIToUTF16("2334");
+ match1.fill_into_edit = base::ASCIIToUTF16("weather los angeles");
+
+ AutocompleteMatch non_answer_match1;
+ non_answer_match1.fill_into_edit = base::ASCIIToUTF16("weather laguna beach");
+
+ // Test that an answer in the first slot populates the cache.
+ matches.push_back(match1);
+ matches.push_back(non_answer_match1);
+ result.AppendMatches(matches);
+ provider_->RegisterDisplayedAnswers(result);
+ EXPECT_EQ(base::ASCIIToUTF16("weather los angeles"),
+ provider_->last_answer_seen_.full_query_text);
+ EXPECT_EQ(base::ASCIIToUTF16("2334"),
+ provider_->last_answer_seen_.query_type);
+
+ // Test that DoAnswersQuery retrieves data from cache.
+ AutocompleteInput input(base::ASCIIToUTF16("weather l"),
+ base::string16::npos, base::string16(), GURL(),
+ metrics::OmniboxEventProto::INVALID_SPEC, false,
+ false, true, true,
+ ChromeAutocompleteSchemeClassifier(&profile_));
+ provider_->DoAnswersQuery(input);
+ EXPECT_EQ(base::ASCIIToUTF16("weather los angeles"),
+ provider_->prefetch_data_.full_query_text);
+ EXPECT_EQ(base::ASCIIToUTF16("2334"), provider_->prefetch_data_.query_type);
+
+ // Mismatching input will return empty prefetch data.
+ AutocompleteInput input2(base::ASCIIToUTF16("weather n"),
+ base::string16::npos, base::string16(), GURL(),
+ metrics::OmniboxEventProto::INVALID_SPEC, false,
+ false, true, true,
+ ChromeAutocompleteSchemeClassifier(&profile_));
+ provider_->DoAnswersQuery(input2);
+ EXPECT_TRUE(provider_->prefetch_data_.full_query_text.empty());
+ EXPECT_TRUE(provider_->prefetch_data_.query_type.empty());
+}