Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / autocomplete / search_provider_unittest.cc
index 7df13f4..2cb68a4 100644 (file)
 #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/search_engine_type.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.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 "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,
+      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,
+    Profile* profile)
+    : SearchProvider(listener, profile), is_success_(false) {
+}
+
+SearchProviderForTest::~SearchProviderForTest() {
+}
+
+void SearchProviderForTest::RecordDeletionResult(bool success) {
+  is_success_ = success;
+}
+
+} // namespace
+
 // SearchProviderTest ---------------------------------------------------------
 
 // The following environment is configured for these tests:
@@ -56,23 +105,27 @@ class SearchProviderTest : public testing::Test,
                            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];
   };
@@ -101,11 +154,11 @@ class SearchProviderTest : public testing::Test,
 
   // 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
@@ -121,13 +174,13 @@ class SearchProviderTest : public testing::Test,
   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
@@ -135,16 +188,26 @@ class SearchProviderTest : public testing::Test,
   // 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();
 
   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_;
@@ -156,7 +219,7 @@ class SearchProviderTest : public testing::Test,
   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_;
@@ -214,7 +277,7 @@ void SearchProviderTest::SetUp() {
   // requests to ensure the InMemoryDatabase is the state we expect it.
   profile_.BlockUntilHistoryProcessesPendingRequests();
 
-  provider_ = new SearchProvider(this, &profile_);
+  provider_ = new SearchProviderForTest(this, &profile_);
   provider_->kMinimumTimeBetweenSuggestQueriesMs = 0;
 }
 
@@ -230,13 +293,16 @@ void SearchProviderTest::RunTest(TestData* cases,
                                  bool prefer_keyword) {
   ACMatches matches;
   for (int i = 0; i < num_cases; ++i) {
-    AutocompleteInput input(cases[i].input, string16::npos, string16(), GURL(),
+    AutocompleteInput input(cases[i].input, base::string16::npos,
+                            base::string16(), GURL(),
                             AutocompleteInput::INVALID_SPEC, false,
                             prefer_keyword, true,
                             AutocompleteInput::ALL_MATCHES);
     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;
@@ -247,11 +313,9 @@ void SearchProviderTest::RunTest(TestData* cases,
         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;
       }
     }
   }
@@ -273,11 +337,11 @@ void SearchProviderTest::RunTillProviderDone() {
   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 input(text, base::string16::npos, base::string16(), GURL(),
                           AutocompleteInput::INVALID_SPEC,
                           prevent_inline_autocomplete, prefer_keyword, true,
                           AutocompleteInput::ALL_MATCHES);
@@ -289,7 +353,7 @@ void SearchProviderTest::QueryForInput(const string16& text,
 }
 
 void SearchProviderTest::QueryForInputAndSetWYTMatch(
-    const string16& text,
+    const base::string16& text,
     AutocompleteMatch* wyt_match) {
   QueryForInput(text, false, false);
   profile_.BlockUntilHistoryProcessesPendingRequests();
@@ -304,7 +368,7 @@ void SearchProviderTest::QueryForInputAndSetWYTMatch(
 }
 
 GURL SearchProviderTest::AddSearchToHistory(TemplateURL* t_url,
-                                            string16 term,
+                                            base::string16 term,
                                             int visit_count) {
   HistoryService* history =
       HistoryServiceFactory::GetForProfile(&profile_,
@@ -314,13 +378,13 @@ GURL SearchProviderTest::AddSearchToHistory(TemplateURL* t_url,
   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) {
@@ -355,6 +419,35 @@ void SearchProviderTest::FinishDefaultSuggestQuery() {
   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.
@@ -376,7 +469,7 @@ void SearchProviderTest::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.
@@ -419,7 +512,7 @@ TEST_F(SearchProviderTest, QueryDefaultProvider) {
 }
 
 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());
@@ -431,7 +524,7 @@ TEST_F(SearchProviderTest, HonorPreventInlineAutocomplete) {
 // 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);
@@ -473,7 +566,7 @@ TEST_F(SearchProviderTest, QueryKeywordProvider) {
   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);
 }
 
@@ -537,7 +630,7 @@ TEST_F(SearchProviderTest, DontAutocompleteURLLikeTerms) {
 
   // 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();
 
@@ -556,6 +649,54 @@ TEST_F(SearchProviderTest, DontAutocompleteURLLikeTerms) {
   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) {
@@ -721,7 +862,7 @@ TEST_F(SearchProviderTest, KeywordOrderingAndDescriptions) {
   AutocompleteController controller(&profile_, NULL,
       AutocompleteProvider::TYPE_SEARCH);
   controller.Start(AutocompleteInput(
-      ASCIIToUTF16("k t"), string16::npos, string16(), GURL(),
+      ASCIIToUTF16("k t"), base::string16::npos, base::string16(), GURL(),
       AutocompleteInput::INVALID_SPEC, false, false, true,
       AutocompleteInput::ALL_MATCHES));
   const AutocompleteResult& result = controller.result();
@@ -739,7 +880,7 @@ TEST_F(SearchProviderTest, KeywordOrderingAndDescriptions) {
   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);
@@ -764,9 +905,11 @@ TEST_F(SearchProviderTest, KeywordVerbatim) {
     { 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
@@ -774,9 +917,11 @@ TEST_F(SearchProviderTest, KeywordVerbatim) {
     { 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"),
                    AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
+                   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.
@@ -786,9 +931,11 @@ TEST_F(SearchProviderTest, KeywordVerbatim) {
     { ASCIIToUTF16("k  foo  bar"), 2,
       { ResultInfo(GURL("http://keyword/foo%20%20bar"),
                    AutocompleteMatchType::SEARCH_OTHER_ENGINE,
+                   true,
                    ASCIIToUTF16("k foo  bar")),
         ResultInfo(GURL("http://defaultturl/k%20%20foo%20%20bar"),
                    AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
+                   false,
                    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:
@@ -799,23 +946,29 @@ TEST_F(SearchProviderTest, KeywordVerbatim) {
     { 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
@@ -823,10 +976,12 @@ TEST_F(SearchProviderTest, KeywordVerbatim) {
     { ASCIIToUTF16("k"), 1,
       { ResultInfo(GURL("http://defaultturl/k"),
                    AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
+                   true,
                    ASCIIToUTF16("k")) } },
     { ASCIIToUTF16("k "), 1,
       { ResultInfo(GURL("http://defaultturl/k%20"),
                    AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED,
+                   true,
                    ASCIIToUTF16("k ")) } }
 
     // The fact that verbatim queries to keyword are handled by KeywordProvider
@@ -864,9 +1019,11 @@ TEST_F(SearchProviderTest, CommandLineOverrides) {
     { 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")) } },
   };
 
@@ -937,6 +1094,70 @@ TEST_F(SearchProviderTest, SuggestRelevance) {
   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
@@ -949,138 +1170,163 @@ TEST_F(SearchProviderTest, DefaultFetcherSuggestRelevance) {
   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.
     { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999]}]",
-      { { "a", true }, { "b", false }, kEmptyMatch, kEmptyMatch },
+      { { "a", true }, { "b", false }, 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 },
+      { { "a", true }, { "b.com", false }, 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 },
+      { { "a", true }, { "b.com", false }, kEmptyMatch, kEmptyMatch,
+        kEmptyMatch, kEmptyMatch },
       std::string() },
     { "[\"a\",[\"https://a/\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\"],"
         "\"google:suggestrelevance\":[9999]}]",
-      { { "https://a", true }, { "a", true }, kEmptyMatch, kEmptyMatch },
+      { { "https://a", true }, { "a", true }, 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.
     { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0}]",
-      { { "a", true }, { "a1", true }, kEmptyMatch, kEmptyMatch },
+      { { "a", true }, { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
+        kEmptyMatch },
       std::string() },
     { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":1}]",
-      { { "a", true }, { "a1", true }, kEmptyMatch, kEmptyMatch },
+      { { "a", true }, { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
+        kEmptyMatch },
       std::string() },
     { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[1],"
                              "\"google:verbatimrelevance\":0}]",
-      { { "a", true }, { "a1", true }, kEmptyMatch, kEmptyMatch },
+      { { "a", true }, { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
+        kEmptyMatch },
       std::string() },
     { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 2],"
                                      "\"google:verbatimrelevance\":0}]",
-      { { "a", true }, { "a2", true }, { "a1", true }, kEmptyMatch },
+      { { "a", true }, { "a2", true }, { "a1", true }, kEmptyMatch, kEmptyMatch,
+        kEmptyMatch },
       std::string() },
     { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 3],"
       "\"google:verbatimrelevance\":2}]",
-      { { "a", true }, { "a2", true }, { "a1", true }, kEmptyMatch },
+      { { "a", true }, { "a2", true }, { "a1", true }, kEmptyMatch, kEmptyMatch,
+        kEmptyMatch },
       std::string() },
     { "[\"a\",[\"http://a.com\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\"],"
         "\"google:suggestrelevance\":[1],"
         "\"google:verbatimrelevance\":0}]",
-      { { "a", true }, { "a.com", true }, kEmptyMatch, kEmptyMatch },
+      { { "a", true }, { "a.com", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
+        kEmptyMatch },
       std::string() },
     { "[\"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 },
+      { { "a", true }, { "a2.com", true }, { "a1.com", true }, kEmptyMatch,
+        kEmptyMatch, 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 }, { "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\","
@@ -1091,48 +1337,64 @@ TEST_F(SearchProviderTest, DefaultFetcherSuggestRelevance) {
                                 "\"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() },
   };
 
+  std::map<std::string, std::string> params;
+  params[std::string(OmniboxFieldTrial::kReorderForLegalDefaultMatchRule) +
+      ":*:*"] = OmniboxFieldTrial::kReorderForLegalDefaultMatchRuleDisabled;
+  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 =
@@ -1152,6 +1414,7 @@ TEST_F(SearchProviderTest, DefaultFetcherSuggestRelevance) {
               matches[0].inline_autocompletion) << description;
     EXPECT_GE(matches[0].relevance, 1300) << 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) {
@@ -1180,133 +1443,157 @@ TEST_F(SearchProviderTest, DefaultFetcherSuggestRelevanceWithReorder) {
   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" },
 
     // 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]}]",
-      { { "b", false }, { "a", true }, 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]}]",
-      { { "b.com", false }, { "a", true }, 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 },
+      { { "a", true }, { "b.com", false }, kEmptyMatch, kEmptyMatch,
+        kEmptyMatch, kEmptyMatch },
       std::string() },
 
     // Allow low-scoring matches.
     { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0}]",
-      { { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch },
+      { { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch,
+        kEmptyMatch },
       "1" },
     { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":1}]",
-      { { "a1", true }, { "a", true }, kEmptyMatch, kEmptyMatch },
+      { { "a1", true }, { "a", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
+        kEmptyMatch },
       "1" },
     { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[1],"
                              "\"google:verbatimrelevance\":0}]",
-      { { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch },
+      { { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch,
+        kEmptyMatch },
       "1" },
     { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 2],"
                                      "\"google:verbatimrelevance\":0}]",
-      { { "a2", true }, { "a1", true }, kEmptyMatch, kEmptyMatch },
+      { { "a2", true }, { "a1", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch,
+        kEmptyMatch },
       "2" },
     { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 3],"
       "\"google:verbatimrelevance\":2}]",
-      { { "a2", true }, { "a", true }, { "a1", true }, kEmptyMatch },
+      { { "a2", true }, { "a", true }, { "a1", true }, kEmptyMatch, kEmptyMatch,
+        kEmptyMatch },
       "2" },
     { "[\"a\",[\"http://a.com\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\"],"
         "\"google:suggestrelevance\":[1],"
         "\"google:verbatimrelevance\":0}]",
-      { { "a.com", true }, kEmptyMatch, kEmptyMatch, kEmptyMatch },
+      { { "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}]",
-      { { "a2.com", true }, { "a1.com", true }, kEmptyMatch, kEmptyMatch },
+      { { "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\","
@@ -1317,56 +1604,56 @@ TEST_F(SearchProviderTest, DefaultFetcherSuggestRelevanceWithReorder) {
                                 "\"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() },
   };
 
-  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 =
@@ -1380,11 +1667,15 @@ TEST_F(SearchProviderTest, DefaultFetcherSuggestRelevanceWithReorder) {
 
     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;
+              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) {
@@ -1417,7 +1708,7 @@ TEST_F(SearchProviderTest, KeywordFetcherSuggestRelevance) {
   const KeywordFetcherMatch kEmptyMatch = { kNotApplicable, false, false };
   struct {
     const std::string json;
-    const KeywordFetcherMatch matches[5];
+    const KeywordFetcherMatch matches[6];
     const std::string inline_autocompletion;
   } cases[] = {
     // Ensure that suggest relevance scores reorder matches and that
@@ -1425,20 +1716,17 @@ TEST_F(SearchProviderTest, KeywordFetcherSuggestRelevance) {
     // the default provider verbatim.
     { "[\"a\",[\"b\", \"c\"],[],[],{\"google:suggestrelevance\":[1, 2]}]",
       { { "a",   true,  true },
-        { "k a", false, true },
+        { "k a", false, false },
         { "c",   true,  false },
         { "b",   true,  false },
-        kEmptyMatch },
+        kEmptyMatch, 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.
+    // 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]}]",
@@ -1446,7 +1734,8 @@ TEST_F(SearchProviderTest, KeywordFetcherSuggestRelevance) {
         { "d",     true,  false },
         { "c.com", false, false },
         { "b.com", false, false },
-        { "k a",   false, true }, },
+        { "k a",   false, false },
+        kEmptyMatch },
       std::string() },
 
     // Without suggested relevance scores, we should only allow one
@@ -1455,8 +1744,8 @@ TEST_F(SearchProviderTest, KeywordFetcherSuggestRelevance) {
        "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"]}]",
       { { "a",     true,  true },
         { "b.com", false, false },
-        { "k a",   false, true },
-        kEmptyMatch, kEmptyMatch },
+        { "k a",   false, false },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch },
       std::string() },
 
     // Ensure that verbatimrelevance scores reorder or suppress verbatim.
@@ -1465,37 +1754,37 @@ TEST_F(SearchProviderTest, KeywordFetcherSuggestRelevance) {
                              "\"google:suggestrelevance\":[9998]}]",
       { { "a",   true,  true },
         { "a1",  true,  true },
-        { "k a", false, true },
-        kEmptyMatch, kEmptyMatch },
+        { "k a", false, false },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch },
       std::string() },
     { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9998,"
                              "\"google:suggestrelevance\":[9999]}]",
       { { "a1",  true,  true },
         { "a",   true,  true },
-        { "k a", false, true },
-        kEmptyMatch, kEmptyMatch },
+        { "k a", false, false },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch },
       "1" },
     { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0,"
                              "\"google:suggestrelevance\":[9999]}]",
       { { "a1",  true,  true },
-        { "k a", false, true },
-        kEmptyMatch, kEmptyMatch, kEmptyMatch },
+        { "k a", false, false },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
       "1" },
     { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":-1,"
                              "\"google:suggestrelevance\":[9999]}]",
       { { "a1",  true,  true },
         { "a",   true,  true },
-        { "k a", false, true },
-        kEmptyMatch, kEmptyMatch },
+        { "k a", false, false },
+        kEmptyMatch, 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 },
+        { "a.com", false, false },
+        { "k a",   false, false },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch },
       std::string() },
 
     // Ensure that both types of relevance scores reorder matches together.
@@ -1504,8 +1793,8 @@ TEST_F(SearchProviderTest, KeywordFetcherSuggestRelevance) {
       { { "a1",  true,  true },
         { "a",   true,  true },
         { "a2",  true,  true },
-        { "k a", false, true },
-        kEmptyMatch },
+        { "k a", false, false },
+        kEmptyMatch, kEmptyMatch },
       "1" },
 
     // Ensure that only inlinable matches may be ranked as the highest result.
@@ -1513,23 +1802,23 @@ TEST_F(SearchProviderTest, KeywordFetcherSuggestRelevance) {
     { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999]}]",
       { { "a",   true,  true },
         { "b",   true,  false },
-        { "k a", false, true },
-        kEmptyMatch, kEmptyMatch },
+        { "k a", false, false },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch },
       std::string() },
     { "[\"a\",[\"b\"],[],[],{\"google:suggestrelevance\":[9999],"
                             "\"google:verbatimrelevance\":0}]",
       { { "a",   true,  true },
         { "b",   true,  false },
-        { "k a", false, true },
-        kEmptyMatch, kEmptyMatch },
+        { "k a", false, false },
+        kEmptyMatch, 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 },
+        { "k a",   false, false },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch },
       std::string() },
     { "[\"a\",[\"http://b.com\"],[],[],"
        "{\"google:suggesttype\":[\"NAVIGATION\"],"
@@ -1537,8 +1826,8 @@ TEST_F(SearchProviderTest, KeywordFetcherSuggestRelevance) {
         "\"google:verbatimrelevance\":0}]",
       { { "a",     true,  true },
         { "b.com", false, false },
-        { "k a",   false, true },
-        kEmptyMatch, kEmptyMatch },
+        { "k a",   false, false },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch },
       std::string() },
 
     // Ensure that the top result is ranked as highly as calculated verbatim.
@@ -1548,14 +1837,14 @@ TEST_F(SearchProviderTest, KeywordFetcherSuggestRelevance) {
     { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0}]",
       { { "a",   true,  true },
         { "a1",  true,  true },
-        { "k a", false, true },
-        kEmptyMatch, kEmptyMatch },
+        { "k a", false, false },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch },
       std::string() },
     { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":1}]",
       { { "a",   true,  true },
         { "a1",  true,  true },
-        { "k a", false, true },
-        kEmptyMatch, kEmptyMatch},
+        { "k a", false, false },
+        kEmptyMatch, 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
@@ -1563,35 +1852,36 @@ TEST_F(SearchProviderTest, KeywordFetcherSuggestRelevance) {
     { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[1],"
                              "\"google:verbatimrelevance\":0}]",
       { { "a",   true,  true },
-        { "k a", false, true },
+        { "k a", false, false },
         { "a1",   true, true },
-        kEmptyMatch, kEmptyMatch},
+        kEmptyMatch, kEmptyMatch, kEmptyMatch },
       std::string() },
     { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 2],"
                                      "\"google:verbatimrelevance\":0}]",
       { { "a",   true,  true },
-        { "k a", false, true },
+        { "k a", false, false },
         { "a2",  true,  true },
         { "a1",  true,  true },
-        kEmptyMatch },
+        kEmptyMatch, kEmptyMatch },
       std::string() },
     { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 3],"
       "\"google:verbatimrelevance\":2}]",
       { { "a",   true,  true },
-        { "k a", false, true },
+        { "k a", false, false },
         { "a2",  true,  true },
         { "a1",  true,  true },
-        kEmptyMatch },
+        kEmptyMatch, 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\","
@@ -1602,10 +1892,11 @@ TEST_F(SearchProviderTest, KeywordFetcherSuggestRelevance) {
                                 "\"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.
@@ -1615,32 +1906,32 @@ TEST_F(SearchProviderTest, KeywordFetcherSuggestRelevance) {
       { { "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.
@@ -1649,8 +1940,8 @@ TEST_F(SearchProviderTest, KeywordFetcherSuggestRelevance) {
       { { "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],"
@@ -1658,8 +1949,8 @@ TEST_F(SearchProviderTest, KeywordFetcherSuggestRelevance) {
       { { "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.
@@ -1667,13 +1958,13 @@ TEST_F(SearchProviderTest, KeywordFetcherSuggestRelevance) {
     // (except when suggested relevances are ignored).
     { "[\"a\",[],[],[],{\"google:verbatimrelevance\":1}]",
       { { "a",   true,  true },
-        { "k a", false, true },
-        kEmptyMatch, kEmptyMatch, kEmptyMatch},
+        { "k a", false, false },
+        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.
@@ -1686,29 +1977,28 @@ TEST_F(SearchProviderTest, KeywordFetcherSuggestRelevance) {
         "\"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 },
+        { "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 },
+        { "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 },
+      { { "a",         true,  true },
+        { "https://a", false, false },
+        { "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.
@@ -1717,20 +2007,22 @@ TEST_F(SearchProviderTest, KeywordFetcherSuggestRelevance) {
         "\"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 },
         { "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 },
         { "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.
@@ -1739,40 +2031,42 @@ TEST_F(SearchProviderTest, KeywordFetcherSuggestRelevance) {
         "\"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 },
         { "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 },
         { "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 },
+        { "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 },
+        { "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,
@@ -1786,18 +2080,18 @@ TEST_F(SearchProviderTest, KeywordFetcherSuggestRelevance) {
         "\"google:verbatimrelevance\":0,"
         "\"google:suggestrelevance\":[9998, 9999]}]",
       { { "a",      true,  true },
-        { "a2.com", false, true },
-        { "k a",    false, true },
-        kEmptyMatch, kEmptyMatch},
+        { "a2.com", false, false },
+        { "k a",    false, false },
+        kEmptyMatch, 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 },
+        { "k a",    false, false },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch },
       std::string() },
     // More checks that everything works when it's not necessary to demote.
     { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
@@ -1805,23 +2099,33 @@ TEST_F(SearchProviderTest, KeywordFetcherSuggestRelevance) {
         "\"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" },
   };
 
+  std::map<std::string, std::string> params;
+  params[std::string(OmniboxFieldTrial::kReorderForLegalDefaultMatchRule) +
+      ":*:*"] = OmniboxFieldTrial::kReorderForLegalDefaultMatchRuleDisabled;
+  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("k a"), false, true);
 
@@ -1853,6 +2157,7 @@ TEST_F(SearchProviderTest, KeywordFetcherSuggestRelevance) {
               matches[0].inline_autocompletion) << description;
     EXPECT_GE(matches[0].relevance, 1300) << 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) {
@@ -1870,48 +2175,512 @@ TEST_F(SearchProviderTest, KeywordFetcherSuggestRelevance) {
   }
 }
 
-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);
-
-  AddSearchToHistory(default_t_url_, term + ASCIIToUTF16("2"), 2);
-  profile_.BlockUntilHistoryProcessesPendingRequests();
-
+// This test is like KeywordFetcherSuggestRelevance 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, KeywordFetcherSuggestRelevanceWithReorder) {
+  struct KeywordFetcherMatch {
+    std::string contents;
+    bool from_keyword;
+    bool allowed_to_be_default_match;
+  };
+  const KeywordFetcherMatch kEmptyMatch = { kNotApplicable, false, false };
   struct {
-    const string16 input;
     const std::string json;
-    const std::string matches[6];
+    const KeywordFetcherMatch matches[6];
+    const std::string inline_autocompletion;
   } cases[] = {
-    // The history results outscore the default verbatim score.  term2 has more
-    // visits so it outscores term1.  The suggestions are still returned since
-    // they're server-scored.
-    { term,
-      "[\"term\",[\"a1\", \"a2\", \"a3\"],[],[],"
-       "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\"],"
-        "\"google:suggestrelevance\":[1, 2, 3]}]",
-      { "term2", "term1", "term", "a3", "a2", "a1" } },
-    // Because we already have three suggestions by the time we see the history
-    // results, they don't get returned.
-    { term,
-      "[\"term\",[\"a1\", \"a2\", \"a3\"],[],[],"
-       "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\"],"
-        "\"google:verbatimrelevance\":1450,"
-        "\"google:suggestrelevance\":[1440, 1430, 1420]}]",
-      { "term", "a1", "a2", "a3", kNotApplicable, kNotApplicable } },
-    // If we only have two suggestions, we have room for a history result.
-    { term,
-      "[\"term\",[\"a1\", \"a2\"],[],[],"
-       "{\"google:suggesttype\":[\"QUERY\", \"QUERY\"],"
-        "\"google:verbatimrelevance\":1450,"
-        "\"google:suggestrelevance\":[1430, 1410]}]",
-      { "term", "a1", "a2", "term2", kNotApplicable, kNotApplicable } },
-    // If we have more than three suggestions, they should all be returned as
+    // 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, false },
+        { "c",   true,  false },
+        { "b",   true,  false },
+        kEmptyMatch, 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.
+    // 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,  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,  true },
+        { "a1",  true,  true },
+        { "k a", false, false },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch },
+      std::string() },
+    { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":9998,"
+                             "\"google:suggestrelevance\":[9999]}]",
+      { { "a1",  true,  true },
+        { "a",   true,  true },
+        { "k a", false, false },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch },
+      "1" },
+    { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":0,"
+                             "\"google:suggestrelevance\":[9999]}]",
+      { { "a1",  true,  true },
+        { "k a", false, false },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
+      "1" },
+    { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":-1,"
+                             "\"google:suggestrelevance\":[9999]}]",
+      { { "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,  true },
+        { "a.com", false, false },
+        { "k a",   false, false },
+        kEmptyMatch, 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, false },
+        kEmptyMatch, kEmptyMatch },
+      "1" },
+
+    // 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",   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, 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}]",
+      { { "b.com", false, false },
+        { "a",     true,  true },
+        { "k a",   false, false },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch },
+      std::string() },
+
+    // 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,  true },
+        { "k a", false, false },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
+      "1" },
+    { "[\"a\",[\"a1\"],[],[],{\"google:verbatimrelevance\":1}]",
+      { { "a1",  true,  true },
+        { "k a", false, false },
+        { "a",   true,  true },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch },
+      "1" },
+    { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[1],"
+                             "\"google:verbatimrelevance\":0}]",
+      { { "k a", false, false },
+        { "a1",   true, true },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
+      "1" },
+    { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 2],"
+                                     "\"google:verbatimrelevance\":0}]",
+      {
+        { "k a", false, false },
+        { "a2",  true,  true },
+        { "a1",  true,  true },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch },
+      "2" },
+    { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1, 3],"
+      "\"google:verbatimrelevance\":2}]",
+      { { "k a", false, false },
+        { "a2",  true,  true },
+        { "a",   true,  true },
+        { "a1",  true,  true },
+        kEmptyMatch, kEmptyMatch },
+      "2" },
+
+    // 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, false },
+        { "h",   true,  false },
+        { "g",   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\","
+              "\"http://h.com\"],[],[],"
+       "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\","
+                                "\"NAVIGATION\", \"NAVIGATION\","
+                                "\"NAVIGATION\", \"NAVIGATION\","
+                                "\"NAVIGATION\"],"
+        "\"google:suggestrelevance\":[1, 2, 3, 4, 5, 6, 7]}]",
+      { { "a",     true,  true },
+        { "k a",   false, false },
+        { "h.com", false, false },
+        { "g.com", false, false },
+        { "f.com", false, false },
+        { "e.com", false, false } },
+      std::string() },
+
+    // Ensure that incorrectly sized suggestion relevance lists are ignored.
+    // Note that keyword suggestions by default (not in suggested relevance
+    // mode) score more highly than the default verbatim.
+    { "[\"a\",[\"a1\", \"a2\"],[],[],{\"google:suggestrelevance\":[1]}]",
+      { { "a",   true,  true },
+        { "a1",  true,  true },
+        { "a2",  true,  true },
+        { "k a", false, false },
+        kEmptyMatch, kEmptyMatch },
+      std::string() },
+    { "[\"a\",[\"a1\"],[],[],{\"google:suggestrelevance\":[9999, 1]}]",
+      { { "a",   true,  true },
+        { "a1",  true,  true },
+        { "k a", false, false },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch },
+      std::string() },
+    // 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, 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, false },
+        { "k a",    false, false },
+        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,  true },
+        { "a",   true,  true },
+        { "a1",  true,  true },
+        { "k a", false, false },
+        kEmptyMatch, kEmptyMatch },
+      "2" },
+    { "[\"a\",[\"a\", \"a1\", \"a2\"],[],[],"
+       "{\"google:suggestrelevance\":[9998, 9997, 9999],"
+        "\"google:verbatimrelevance\":0}]",
+      { { "a2",  true,  true },
+        { "a",   true,  true },
+        { "a1",  true,  true },
+        { "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}]",
+      { { "k a", false, false },
+        { "a",   true,  true },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
+      std::string() },
+    { "[\"a\",[],[],[],{\"google:verbatimrelevance\":0}]",
+      { { "a",   true,  true },
+        { "k a", false, false },
+        kEmptyMatch, kEmptyMatch, kEmptyMatch, kEmptyMatch },
+      std::string() },
+
+    // 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]}]",
+      { { "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]}]",
+      { { "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]}]",
+      { { "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.
+    { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
+       "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
+        "\"google:verbatimrelevance\":9990,"
+        "\"google:suggestrelevance\":[9998, 9999, 1300]}]",
+      { { "a2.com", false, false },
+        { "a1.com", false, false },
+        { "a",      true,  true },
+        { "a3",     true,  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]}]",
+      { { "a1.com", false, false },
+        { "a2.com", false, false },
+        { "a",      true,  true },
+        { "a3",     true,  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.
+    { "[\"a\",[\"http://a1.com\", \"http://a2.com\", \"a3\"],[],[],"
+       "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
+        "\"google:verbatimrelevance\":9990,"
+        "\"google:suggestrelevance\":[9998, 9999, 9997]}]",
+      { { "a2.com", false, false },
+        { "a1.com", false, false },
+        { "a3",     true,  true },
+        { "a",      true,  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]}]",
+      { { "a1.com", false, false },
+        { "a2.com", false, false },
+        { "a3",     true,  true },
+        { "a",      true,  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]}]",
+      { { "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]}]",
+      { { "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 restore the keyword verbatim score.
+    { "[\"a\",[\"http://a1.com\", \"http://a2.com\"],[],[],"
+       "{\"google:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\"],"
+        "\"google:verbatimrelevance\":0,"
+        "\"google:suggestrelevance\":[9998, 9999]}]",
+      { { "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]}]",
+      { { "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:suggesttype\":[\"NAVIGATION\", \"NAVIGATION\", \"QUERY\"],"
+        "\"google:verbatimrelevance\":9990,"
+        "\"google:suggestrelevance\":[9997, 9998, 9999]}]",
+      { { "a3",     true,  true },
+        { "a2.com", false, false },
+        { "a1.com", false, false },
+        { "a",      true,  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, false },
+        { "a2.com", false, false },
+        { "a",      true,  true },
+        { "k a",    false, false },
+        kEmptyMatch },
+      "3" },
+  };
+
+  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
+    QueryForInput(ASCIIToUTF16("k a"), false, true);
+
+    // Set up a default fetcher with no results.
+    net::TestURLFetcher* default_fetcher =
+        test_factory_.GetFetcherByID(
+            SearchProvider::kDefaultProviderURLFetcherID);
+    ASSERT_TRUE(default_fetcher);
+    default_fetcher->set_response_code(200);
+    default_fetcher->delegate()->OnURLFetchComplete(default_fetcher);
+    default_fetcher = NULL;
+
+    // Set up a keyword fetcher with provided results.
+    net::TestURLFetcher* keyword_fetcher =
+        test_factory_.GetFetcherByID(
+            SearchProvider::kKeywordProviderURLFetcherID);
+    ASSERT_TRUE(keyword_fetcher);
+    keyword_fetcher->set_response_code(200);
+    keyword_fetcher->SetResponseString(cases[i].json);
+    keyword_fetcher->delegate()->OnURLFetchComplete(keyword_fetcher);
+    keyword_fetcher = NULL;
+    RunTillProviderDone();
+
+    const std::string description = "for input with json=" + cases[i].json;
+    const ACMatches& matches = provider_->matches();
+    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),
+              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) {
+      EXPECT_EQ(ASCIIToUTF16(cases[i].matches[j].contents),
+                matches[j].contents) << description;
+      EXPECT_EQ(cases[i].matches[j].from_keyword,
+                matches[j].keyword == ASCIIToUTF16("k")) << 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;
+  }
+}
+
+TEST_F(SearchProviderTest, LocalAndRemoteRelevances) {
+  // 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_);
+  base::string16 term = term1_.substr(0, term1_.length() - 1);
+
+  AddSearchToHistory(default_t_url_, term + ASCIIToUTF16("2"), 2);
+  profile_.BlockUntilHistoryProcessesPendingRequests();
+
+  struct {
+    const base::string16 input;
+    const std::string json;
+    const std::string matches[6];
+  } cases[] = {
+    // The history results outscore the default verbatim score.  term2 has more
+    // visits so it outscores term1.  The suggestions are still returned since
+    // they're server-scored.
+    { term,
+      "[\"term\",[\"a1\", \"a2\", \"a3\"],[],[],"
+       "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\"],"
+        "\"google:suggestrelevance\":[1, 2, 3]}]",
+      { "term2", "term1", "term", "a3", "a2", "a1" } },
+    // Because we already have three suggestions by the time we see the history
+    // results, they don't get returned.
+    { term,
+      "[\"term\",[\"a1\", \"a2\", \"a3\"],[],[],"
+       "{\"google:suggesttype\":[\"QUERY\", \"QUERY\", \"QUERY\"],"
+        "\"google:verbatimrelevance\":1450,"
+        "\"google:suggestrelevance\":[1440, 1430, 1420]}]",
+      { "term", "a1", "a2", "a3", kNotApplicable, kNotApplicable } },
+    // If we only have two suggestions, we have room for a history result.
+    { term,
+      "[\"term\",[\"a1\", \"a2\"],[],[],"
+       "{\"google:suggesttype\":[\"QUERY\", \"QUERY\"],"
+        "\"google:verbatimrelevance\":1450,"
+        "\"google:suggestrelevance\":[1430, 1410]}]",
+      { "term", "a1", "a2", "term2", kNotApplicable, kNotApplicable } },
+    // If we have more than three suggestions, they should all be returned as
     // long as we have enough total space for them.
     { term,
       "[\"term\",[\"a1\", \"a2\", \"a3\", \"a4\"],[],[],"
@@ -1931,21 +2700,7 @@ TEST_F(SearchProviderTest, LocalAndRemoteRelevances) {
        "{\"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++) {
@@ -1963,7 +2718,7 @@ TEST_F(SearchProviderTest, LocalAndRemoteRelevances) {
     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.
@@ -2053,6 +2808,140 @@ TEST_F(SearchProviderTest, DefaultProviderSuggestRelevanceScoringUrlInput) {
         kEmptyMatch } },
   };
 
+  std::map<std::string, std::string> params;
+  params[std::string(OmniboxFieldTrial::kReorderForLegalDefaultMatchRule) +
+      ":*:*"] = OmniboxFieldTrial::kReorderForLegalDefaultMatchRuleDisabled;
+  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(cases[i].input), 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();
+
+    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),
+                matches[j].contents);
+      EXPECT_EQ(cases[i].output[j].match_type, matches[j].type);
+      EXPECT_EQ(cases[i].output[j].allowed_to_be_default_match,
+                matches[j].allowed_to_be_default_match);
+    }
+    // Ensure that no expected matches are missing.
+    for (; j < ARRAYSIZE_UNSAFE(cases[i].output); ++j) {
+      EXPECT_EQ(kNotApplicable, cases[i].output[j].match_contents);
+      EXPECT_EQ(AutocompleteMatchType::NUM_TYPES,
+                cases[i].output[j].match_type);
+      EXPECT_FALSE(cases[i].output[j].allowed_to_be_default_match);
+    }
+  }
+}
+
+// This test is like DefaultProviderSuggestRelevanceScoringUrlInput
+// 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,
+    DefaultProviderSuggestRelevanceScoringUrlInputWithReorder) {
+  struct DefaultFetcherUrlInputMatch {
+    const std::string match_contents;
+    AutocompleteMatch::Type match_type;
+    bool allowed_to_be_default_match;
+  };
+  const DefaultFetcherUrlInputMatch kEmptyMatch =
+      { kNotApplicable, AutocompleteMatchType::NUM_TYPES, false };
+  struct {
+    const std::string input;
+    const std::string json;
+    const DefaultFetcherUrlInputMatch output[4];
+  } cases[] = {
+    // 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/a", AutocompleteMatchType::NAVSUGGEST,            true },
+        { "a.com",   AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
+        kEmptyMatch, kEmptyMatch } },
+    { "a.com", "[\"a.com\",[\"https://a.com\"],[],[],"
+                "{\"google:suggesttype\":[\"NAVIGATION\"],"
+                 "\"google:suggestrelevance\":[9999]}]",
+      { { "https://a.com", AutocompleteMatchType::NAVSUGGEST,            true },
+        { "a.com",         AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, true },
+        kEmptyMatch, kEmptyMatch } },
+
+    // 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 info\"],[],[],"
+                "{\"google:suggestrelevance\":[9999]}]",
+      { { "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 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 info", AutocompleteMatchType::SEARCH_SUGGEST,        true },
+        kEmptyMatch } },
+    { "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 info", 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++) {
     QueryForInput(ASCIIToUTF16(cases[i].input), false, false);
     net::TestURLFetcher* fetcher =
@@ -2066,6 +2955,7 @@ TEST_F(SearchProviderTest, DefaultProviderSuggestRelevanceScoringUrlInput) {
 
     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),
@@ -2135,163 +3025,192 @@ TEST_F(SearchProviderTest, NavigationInline) {
     // 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",  std::string(), false,
+                                                                    false },
     { "http://www.abc.com",   "https://www.abc.com",
-                              "https://www.abc.com", std::string(), false },
+                              "https://www.abc.com", std::string(), false,
+                                                                    false },
     { "http://abc.com",       "ftp://abc.com",
-                              "ftp://abc.com",       std::string(), false },
+                              "ftp://abc.com",       std::string(), false,
+                                                                    false },
     { "https://www.abc.com",  "http://www.abc.com",
-                                     "www.abc.com",  std::string(), false },
+                                     "www.abc.com",  std::string(), false,
+                                                                    false },
     { "ftp://abc.com",        "http://abc.com",
-                                     "abc.com",      std::string(), false },
+                                     "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 },
 
     // 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_.get(), GURL(cases[i].url), base::string16(), 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(SearchProvider::NavigationResult(
+            *provider_.get(), GURL(cases[i].url), base::string16(), 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 base::string16 input(ASCIIToUTF16("ht"));
+  const base::string16 url(ASCIIToUTF16("http://a.com"));
   const SearchProvider::NavigationResult result(
-      *provider_.get(), GURL(url), string16(), false, 0, false);
+      *provider_.get(), GURL(url), base::string16(), false, 0, false,
+      input, std::string());
 
   // Check the offset and strings when inline autocompletion is allowed.
   QueryForInput(input, false, false);
@@ -2301,11 +3220,10 @@ TEST_F(SearchProviderTest, NavigationInlineSchemeSubstring) {
   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);
 }
@@ -2315,8 +3233,8 @@ 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_.get(), GURL("http://www.wow.com"), base::string16(), 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);
@@ -2465,6 +3383,14 @@ TEST_F(SearchProviderTest, RemoveStaleResultsTest) {
         { "http://friend.com/", true,  1255, true  } } },
   };
 
+  std::map<std::string, std::string> params;
+  params[std::string(OmniboxFieldTrial::kReorderForLegalDefaultMatchRule) +
+      ":*:*"] = OmniboxFieldTrial::kReorderForLegalDefaultMatchRuleDisabled;
+  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++) {
     // Initialize cached results for this test case.
     provider_->default_results_.verbatim_relevance =
@@ -2478,21 +3404,23 @@ TEST_F(SearchProviderTest, RemoveStaleResultsTest) {
       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));
+                *provider_.get(), GURL(suggestion), base::string16(), false,
+                cases[i].results[j].relevance, false,
+                ASCIIToUTF16(cases[i].omnibox_input), std::string()));
       } else {
         provider_->default_results_.suggest_results.push_back(
-            SearchProvider::SuggestResult(ASCIIToUTF16(suggestion), string16(),
-                                          string16(), std::string(), false,
-                                          cases[i].results[j].relevance,
-                                          false, false));
+            SearchProvider::SuggestResult(
+                ASCIIToUTF16(suggestion), AutocompleteMatchType::SEARCH_SUGGEST,
+                ASCIIToUTF16(suggestion), base::string16(), std::string(),
+                std::string(), false, cases[i].results[j].relevance, false,
+                false, ASCIIToUTF16(cases[i].omnibox_input)));
       }
     }
 
     provider_->input_ = AutocompleteInput(
-        ASCIIToUTF16(cases[i].omnibox_input), string16::npos, string16(),
-        GURL(), AutocompleteInput::INVALID_SPEC, false, false, true,
-        AutocompleteInput::ALL_MATCHES);
+        ASCIIToUTF16(cases[i].omnibox_input), base::string16::npos,
+        base::string16(), GURL(), AutocompleteInput::INVALID_SPEC, false, false,
+        true, AutocompleteInput::ALL_MATCHES);
     provider_->RemoveAllStaleResults();
 
     // Check cached results.
@@ -2530,19 +3458,14 @@ TEST_F(SearchProviderTest, RemoveStaleResultsTest) {
 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;
@@ -2551,21 +3474,14 @@ TEST_F(SearchProviderTest, ParseEntitySuggestion) {
   } 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
       },
@@ -2574,19 +3490,12 @@ TEST_F(SearchProviderTest, ParseEntitySuggestion) {
     { "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
       },
@@ -2611,37 +3520,27 @@ TEST_F(SearchProviderTest, ParseEntitySuggestion) {
 
     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);
@@ -2650,95 +3549,6 @@ TEST_F(SearchProviderTest, ParseEntitySuggestion) {
 }
 #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) {
@@ -2861,10 +3671,12 @@ 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);
@@ -2874,15 +3686,42 @@ TEST_F(SearchProviderTest, PrefetchMetadataParsing) {
   }
 }
 
+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;
@@ -2945,11 +3784,13 @@ TEST_F(SearchProviderTest, XSSIGuardedJSONParsing) {
     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) {
@@ -2960,10 +3801,86 @@ TEST_F(SearchProviderTest, XSSIGuardedJSONParsing) {
   }
 }
 
+// Test that deletion url gets set on an AutocompleteMatch when available for a
+// personalized query.
+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[] = "https://www.google.com/complete/deleteitems"
+       "?delq=ab&client=chrome&deltok=xsrf123";
+
+   struct {
+       const std::string input_text;
+       const std::string response_json;
+       const Match matches[4];
+     } cases[] = {
+       // A deletion URL on a personalized query should be reflected in the
+       // resulting AutocompleteMatch.
+       { "a",
+         "[\"a\",[\"ab\", \"ac\"],[],[],"
+         "{\"google:suggesttype\":[\"PERSONALIZED_QUERY\",\"QUERY\"],"
+         "\"google:suggestrelevance\":[1, 2],"
+         "\"google:suggestdetail\":[{\"du\":"
+         "\"https://www.google.com/complete/deleteitems?delq=ab&client=chrome"
+         "&deltok=xsrf123\"}, {}]}]",
+         { { "a", "", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED },
+           { "ac", "", AutocompleteMatchType::SEARCH_SUGGEST },
+           { "ab", url, AutocompleteMatchType::SEARCH_SUGGEST },
+           kEmptyMatch,
+         },
+       },
+       // Personalized queries without deletion URLs shouldn't cause errors.
+       { "a",
+         "[\"a\",[\"ab\", \"ac\"],[],[],"
+         "{\"google:suggesttype\":[\"PERSONALIZED_QUERY\",\"QUERY\"],"
+         "\"google:suggestrelevance\":[1, 2],"
+         "\"google:suggestdetail\":[{}, {}]}]",
+         { { "a", "", AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED },
+           { "ac", "", AutocompleteMatchType::SEARCH_SUGGEST },
+           { "ab", "", AutocompleteMatchType::SEARCH_SUGGEST },
+           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,
@@ -2980,3 +3897,164 @@ TEST_F(SearchProviderTest, ReflectsBookmarkBarState) {
   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(&profile_, template_url_data);
+
+  // Create field trial.
+  base::FieldTrial* field_trial = base::FieldTrialList::CreateFieldTrial(
+      "AutocompleteDynamicTrial_2", "EnableZeroSuggest");
+  field_trial->group();
+
+  // Not signed in.
+  EXPECT_FALSE(SearchProvider::CanSendURL(
+      GURL("http://www.google.com/search"),
+      GURL("https://www.google.com/complete/search"), &google_template_url,
+      AutocompleteInput::OTHER, &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,
+      AutocompleteInput::OTHER, &profile_));
+
+  // Not in field trial.
+  ResetFieldTrialList();
+  EXPECT_FALSE(SearchProvider::CanSendURL(
+      GURL("http://www.google.com/search"),
+      GURL("https://www.google.com/complete/search"), &google_template_url,
+      AutocompleteInput::OTHER, &profile_));
+  field_trial = base::FieldTrialList::CreateFieldTrial(
+      "AutocompleteDynamicTrial_2", "EnableZeroSuggest");
+  field_trial->group();
+
+  // Invalid page URL.
+  EXPECT_FALSE(SearchProvider::CanSendURL(
+      GURL("badpageurl"),
+      GURL("https://www.google.com/complete/search"), &google_template_url,
+      AutocompleteInput::OTHER, &profile_));
+
+  // Invalid page classification.
+  EXPECT_FALSE(SearchProvider::CanSendURL(
+      GURL("http://www.google.com/search"),
+      GURL("https://www.google.com/complete/search"), &google_template_url,
+      AutocompleteInput::INSTANT_NTP_WITH_FAKEBOX_AS_STARTING_FOCUS,
+      &profile_));
+
+  // Invalid page classification.
+  EXPECT_FALSE(SearchProvider::CanSendURL(
+      GURL("http://www.google.com/search"),
+      GURL("https://www.google.com/complete/search"), &google_template_url,
+      AutocompleteInput::INSTANT_NTP_WITH_OMNIBOX_AS_STARTING_FOCUS,
+      &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, AutocompleteInput::OTHER, &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,
+      AutocompleteInput::OTHER, &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,
+      AutocompleteInput::OTHER, &profile_));
+
+  // Non-HTTPS provider.
+  EXPECT_FALSE(SearchProvider::CanSendURL(
+      GURL("http://www.google.com/search"),
+      GURL("http://www.google.com/complete/search"), &google_template_url,
+      AutocompleteInput::OTHER, &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,
+      AutocompleteInput::OTHER, &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,
+      AutocompleteInput::OTHER, profile_.GetOffTheRecordProfile()));
+
+  // Tab sync not enabled.
+  profile_.GetPrefs()->SetBoolean(prefs::kSyncKeepEverythingSynced, false);
+  profile_.GetPrefs()->SetBoolean(prefs::kSyncTabs, false);
+  EXPECT_FALSE(SearchProvider::CanSendURL(
+      GURL("http://www.google.com/search"),
+      GURL("https://www.google.com/complete/search"), &google_template_url,
+      AutocompleteInput::OTHER, &profile_));
+  profile_.GetPrefs()->SetBoolean(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,
+      AutocompleteInput::OTHER, &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,
+      AutocompleteInput::OTHER, &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());
+}