history_url_provider_unittest.cc revision c2db58bd994c04d98e4ee2cd7565b71548655fe3
1b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek// Copyright (c) 2012 The Chromium Authors. All rights reserved.
277349cb20bfd7069d081f84c91975bfa8ef60a32Ted Kremenek// Use of this source code is governed by a BSD-style license that can be
377349cb20bfd7069d081f84c91975bfa8ef60a32Ted Kremenek// found in the LICENSE file.
477349cb20bfd7069d081f84c91975bfa8ef60a32Ted Kremenek
577349cb20bfd7069d081f84c91975bfa8ef60a32Ted Kremenek#include "chrome/browser/autocomplete/history_url_provider.h"
677349cb20bfd7069d081f84c91975bfa8ef60a32Ted Kremenek
777349cb20bfd7069d081f84c91975bfa8ef60a32Ted Kremenek#include <algorithm>
877349cb20bfd7069d081f84c91975bfa8ef60a32Ted Kremenek
977349cb20bfd7069d081f84c91975bfa8ef60a32Ted Kremenek#include "base/message_loop/message_loop.h"
10b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek#include "base/path_service.h"
11b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek#include "base/strings/string_util.h"
12b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek#include "base/strings/utf_string_conversions.h"
1377349cb20bfd7069d081f84c91975bfa8ef60a32Ted Kremenek#include "base/time/time.h"
1477349cb20bfd7069d081f84c91975bfa8ef60a32Ted Kremenek#include "chrome/browser/autocomplete/autocomplete_match.h"
1577349cb20bfd7069d081f84c91975bfa8ef60a32Ted Kremenek#include "chrome/browser/autocomplete/autocomplete_provider.h"
1677349cb20bfd7069d081f84c91975bfa8ef60a32Ted Kremenek#include "chrome/browser/autocomplete/autocomplete_provider_listener.h"
17aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek#include "chrome/browser/autocomplete/history_quick_provider.h"
1877349cb20bfd7069d081f84c91975bfa8ef60a32Ted Kremenek#include "chrome/browser/history/history_service.h"
1977349cb20bfd7069d081f84c91975bfa8ef60a32Ted Kremenek#include "chrome/browser/history/history_service_factory.h"
20b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek#include "chrome/browser/search_engines/template_url.h"
2177349cb20bfd7069d081f84c91975bfa8ef60a32Ted Kremenek#include "chrome/browser/search_engines/template_url_service.h"
22b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek#include "chrome/browser/search_engines/template_url_service_factory.h"
23b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek#include "chrome/common/net/url_fixer_upper.h"
24b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek#include "chrome/test/base/testing_browser_process.h"
25e5f4dcb6bd73a10df6eb6c3cfe057c88cb2362ccTed Kremenek#include "chrome/test/base/testing_profile.h"
26b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek#include "content/public/test/test_browser_thread_bundle.h"
27aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek#include "testing/gtest/include/gtest/gtest.h"
28b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek
29b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenekusing base::Time;
30f116bd654bcdb5d7c22656f224deeb7a67f7d0cdTed Kremenekusing base::TimeDelta;
31aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek
32aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenekusing content::TestBrowserThreadBundle;
33aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek
34330dddd19406f9cc227e59e0bb0a36ecdc52915eTed Kremenekstruct TestURLInfo {
3577349cb20bfd7069d081f84c91975bfa8ef60a32Ted Kremenek  const char* url;
36b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  const char* title;
37b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  int visit_count;
38b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  int typed_count;
39b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek} test_db[] = {
40b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  {"http://www.google.com/", "Google", 3, 3},
41b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek
42b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  // High-quality pages should get a host synthesized as a lower-quality match.
43b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  {"http://slashdot.org/favorite_page.html", "Favorite page", 200, 100},
44b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek
45b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  // Less popular pages should have hosts synthesized as higher-quality
46b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  // matches.
47b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  {"http://kerneltrap.org/not_very_popular.html", "Less popular", 4, 0},
48b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek
49b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  // Unpopular pages should not appear in the results at all.
50b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  {"http://freshmeat.net/unpopular.html", "Unpopular", 1, 0},
51aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek
52240f1f00dda1d481276ea872fe8f8851581a7e6bTed Kremenek  // If a host has a match, we should pick it up during host synthesis.
53b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  {"http://news.google.com/?ned=us&topic=n", "Google News - U.S.", 2, 2},
54b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  {"http://news.google.com/", "Google News", 1, 1},
55aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek
56b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  // Matches that are normally not inline-autocompletable should be
57b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  // autocompleted if they are shorter substitutes for longer matches that would
58b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  // have been inline autocompleted.
59b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  {"http://synthesisatest.com/foo/", "Test A", 1, 1},
60b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  {"http://synthesisbtest.com/foo/", "Test B", 1, 1},
61b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  {"http://synthesisbtest.com/foo/bar.html", "Test B Bar", 2, 2},
62b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek
63b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  // Suggested short URLs must be "good enough" and must match user input.
64b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  {"http://foo.com/", "Dir", 5, 5},
65b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  {"http://foo.com/dir/", "Dir", 2, 2},
66affb2159712b2373a18a89ed205c1a309d3aec12Ted Kremenek  {"http://foo.com/dir/another/", "Dir", 5, 1},
674a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenek  {"http://foo.com/dir/another/again/", "Dir", 10, 0},
684a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenek  {"http://foo.com/dir/another/again/myfile.html", "File", 10, 2},
69affb2159712b2373a18a89ed205c1a309d3aec12Ted Kremenek
705e03fcb5420c33207433dd6f800588e256dd9bdbTed Kremenek  // We throw in a lot of extra URLs here to make sure we're testing the
711e80aa49ec689d1937e54fb353d6626e0a58f0dbTed Kremenek  // history database's query, not just the autocomplete provider.
72affb2159712b2373a18a89ed205c1a309d3aec12Ted Kremenek  {"http://startest.com/y/a", "A", 2, 2},
73affb2159712b2373a18a89ed205c1a309d3aec12Ted Kremenek  {"http://startest.com/y/b", "B", 5, 2},
748cc13ea74fea1c04042a2f4087665bc5182e8408Ted Kremenek  {"http://startest.com/x/c", "C", 5, 2},
758cc13ea74fea1c04042a2f4087665bc5182e8408Ted Kremenek  {"http://startest.com/x/d", "D", 5, 5},
76b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  {"http://startest.com/y/e", "E", 4, 2},
774a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenek  {"http://startest.com/y/f", "F", 3, 2},
784a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenek  {"http://startest.com/y/g", "G", 3, 2},
794a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenek  {"http://startest.com/y/h", "H", 3, 2},
80b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  {"http://startest.com/y/i", "I", 3, 2},
814a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenek  {"http://startest.com/y/j", "J", 3, 2},
824a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenek  {"http://startest.com/y/k", "K", 3, 2},
834a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenek  {"http://startest.com/y/l", "L", 3, 2},
849dca062461a6244cf0f733346657fa3eee853f9bTed Kremenek  {"http://startest.com/y/m", "M", 3, 2},
85affb2159712b2373a18a89ed205c1a309d3aec12Ted Kremenek
86affb2159712b2373a18a89ed205c1a309d3aec12Ted Kremenek  // A file: URL is useful for testing that fixup does the right thing w.r.t.
87affb2159712b2373a18a89ed205c1a309d3aec12Ted Kremenek  // the number of trailing slashes on the user's input.
88affb2159712b2373a18a89ed205c1a309d3aec12Ted Kremenek  {"file:///C:/foo.txt", "", 2, 2},
89b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek
9007d83aa220567bef263ef76cfc9b0159320bb640Ted Kremenek  // Results with absurdly high typed_counts so that very generic queries like
91b5339121f63f2754d4f26e8f3a092caf9f7d9290Ted Kremenek  // "http" will give consistent results even if more data is added above.
9207d83aa220567bef263ef76cfc9b0159320bb640Ted Kremenek  {"http://bogussite.com/a", "Bogus A", 10002, 10000},
9307d83aa220567bef263ef76cfc9b0159320bb640Ted Kremenek  {"http://bogussite.com/b", "Bogus B", 10001, 10000},
9407d83aa220567bef263ef76cfc9b0159320bb640Ted Kremenek  {"http://bogussite.com/c", "Bogus C", 10000, 10000},
95b5339121f63f2754d4f26e8f3a092caf9f7d9290Ted Kremenek
9607d83aa220567bef263ef76cfc9b0159320bb640Ted Kremenek  // Domain name with number.
9707d83aa220567bef263ef76cfc9b0159320bb640Ted Kremenek  {"http://www.17173.com/", "Domain with number", 3, 3},
984a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenek
994a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenek  // URLs to test exact-matching behavior.
10007d83aa220567bef263ef76cfc9b0159320bb640Ted Kremenek  {"http://go/", "Intranet URL", 1, 1},
1014d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek  {"http://gooey/", "Intranet URL 2", 5, 5},
1024d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek
1034d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek  // URLs for testing offset adjustment.
1044d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek  {"http://www.\xEA\xB5\x90\xEC\x9C\xA1.kr/", "Korean", 2, 2},
1054d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek  {"http://spaces.com/path%20with%20spaces/foo.html", "Spaces", 2, 2},
1064d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek  {"http://ms/c++%20style%20guide", "Style guide", 2, 2},
1074d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek
1084d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek  // URLs for testing ctrl-enter behavior.
1094d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek  {"http://binky/", "Intranet binky", 2, 2},
110b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  {"http://winky/", "Intranet winky", 2, 2},
1118cc13ea74fea1c04042a2f4087665bc5182e8408Ted Kremenek  {"http://www.winky.com/", "Internet winky", 5, 0},
1128cc13ea74fea1c04042a2f4087665bc5182e8408Ted Kremenek
1138cc13ea74fea1c04042a2f4087665bc5182e8408Ted Kremenek  // URLs used by EmptyVisits.
1148cc13ea74fea1c04042a2f4087665bc5182e8408Ted Kremenek  {"http://pandora.com/", "Pandora", 2, 2},
1155e03fcb5420c33207433dd6f800588e256dd9bdbTed Kremenek  // This entry is explicitly added more recently than
1165e03fcb5420c33207433dd6f800588e256dd9bdbTed Kremenek  // history::kLowQualityMatchAgeLimitInDays.
1175e03fcb5420c33207433dd6f800588e256dd9bdbTed Kremenek  // {"http://p/", "p", 0, 0},
1185e03fcb5420c33207433dd6f800588e256dd9bdbTed Kremenek
1192ded35a576e3899553ea0ccfcbf5cbdb3d8cf664Ted Kremenek  // For intranet based tests.
1202ded35a576e3899553ea0ccfcbf5cbdb3d8cf664Ted Kremenek  {"http://intra/one", "Intranet", 2, 2},
1212ded35a576e3899553ea0ccfcbf5cbdb3d8cf664Ted Kremenek  {"http://intra/two", "Intranet two", 1, 1},
1222ded35a576e3899553ea0ccfcbf5cbdb3d8cf664Ted Kremenek  {"http://intra/three", "Intranet three", 2, 2},
123b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  {"http://moo/bar", "Intranet moo", 1, 1},
124b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  {"http://typedhost/typedpath", "Intranet typed", 1, 1},
125b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  {"http://typedhost/untypedpath", "Intranet untyped", 1, 0},
126b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek
127b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  {"http://x.com/one", "Internet", 2, 2},
128b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  {"http://x.com/two", "Internet two", 1, 1},
129b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  {"http://x.com/three", "Internet three", 2, 2},
130240f1f00dda1d481276ea872fe8f8851581a7e6bTed Kremenek};
131b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek
132b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenekclass HistoryURLProviderTest : public testing::Test,
133b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek                               public AutocompleteProviderListener {
134b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek public:
135b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  struct UrlAndLegalDefault {
136b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek    std::string url;
137b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek    bool allowed_to_be_default_match;
138b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  };
139b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek
140b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  HistoryURLProviderTest()
141b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek      : sort_matches_(false) {
142b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek    HistoryQuickProvider::set_disabled(true);
143b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  }
144b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek
145b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  virtual ~HistoryURLProviderTest() {
146b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek    HistoryQuickProvider::set_disabled(false);
147b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  }
148b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek
149b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  // AutocompleteProviderListener:
150e01c98767dfd7153c3c84637c36659e3bbe16ff7Ted Kremenek  virtual void OnProviderUpdate(bool updated_matches) OVERRIDE;
151e01c98767dfd7153c3c84637c36659e3bbe16ff7Ted Kremenek
152ffe0f43806d4823271c2406c1fccc2373115c36aTed Kremenek protected:
153e01c98767dfd7153c3c84637c36659e3bbe16ff7Ted Kremenek  static BrowserContextKeyedService* CreateTemplateURLService(
154b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek      content::BrowserContext* profile) {
155b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek    return new TemplateURLService(static_cast<Profile*>(profile));
156aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek  }
157b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek
1584a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenek  // testing::Test
1594a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenek  virtual void SetUp() {
160b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek    ASSERT_TRUE(SetUpImpl(false));
161b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  }
1624a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenek  virtual void TearDown();
1634a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenek
1649dca062461a6244cf0f733346657fa3eee853f9bTed Kremenek  // Does the real setup.
1659dca062461a6244cf0f733346657fa3eee853f9bTed Kremenek  bool SetUpImpl(bool no_db) WARN_UNUSED_RESULT;
166b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek
167b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  // Fills test data into the history system.
168b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  void FillData();
169b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek
170b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  // Runs an autocomplete query on |text| and checks to see that the returned
171b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  // results' destination URLs match those provided.  Also allows checking
172b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  // that the input type was identified correctly.
173b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  void RunTest(const string16 text,
1744a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenek               const string16& desired_tld,
1754a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenek               bool prevent_inline_autocomplete,
176b5339121f63f2754d4f26e8f3a092caf9f7d9290Ted Kremenek               const UrlAndLegalDefault* expected_urls,
177b5339121f63f2754d4f26e8f3a092caf9f7d9290Ted Kremenek               size_t num_results,
1784d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek               AutocompleteInput::Type* identified_input_type);
1794d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek
1804d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek  // A version of the above without the final |type| output parameter.
1814d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek  void RunTest(const string16 text,
1824d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek               const string16& desired_tld,
1834d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek               bool prevent_inline_autocomplete,
184d763eb91aab5bdecd11825fadb35d6d8cc905f63Ted Kremenek               const UrlAndLegalDefault* expected_urls,
185d763eb91aab5bdecd11825fadb35d6d8cc905f63Ted Kremenek               size_t num_results) {
186affb2159712b2373a18a89ed205c1a309d3aec12Ted Kremenek    AutocompleteInput::Type type;
187affb2159712b2373a18a89ed205c1a309d3aec12Ted Kremenek    return RunTest(text, desired_tld, prevent_inline_autocomplete,
188affb2159712b2373a18a89ed205c1a309d3aec12Ted Kremenek                   expected_urls, num_results, &type);
1898cc13ea74fea1c04042a2f4087665bc5182e8408Ted Kremenek  }
1908cc13ea74fea1c04042a2f4087665bc5182e8408Ted Kremenek
1918cc13ea74fea1c04042a2f4087665bc5182e8408Ted Kremenek  content::TestBrowserThreadBundle thread_bundle_;
1928cc13ea74fea1c04042a2f4087665bc5182e8408Ted Kremenek  ACMatches matches_;
1938cc13ea74fea1c04042a2f4087665bc5182e8408Ted Kremenek  scoped_ptr<TestingProfile> profile_;
1945e03fcb5420c33207433dd6f800588e256dd9bdbTed Kremenek  HistoryService* history_service_;
1955e03fcb5420c33207433dd6f800588e256dd9bdbTed Kremenek  scoped_refptr<HistoryURLProvider> autocomplete_;
1965e03fcb5420c33207433dd6f800588e256dd9bdbTed Kremenek  // Should the matches be sorted and duplicates removed?
1975e03fcb5420c33207433dd6f800588e256dd9bdbTed Kremenek  bool sort_matches_;
1982ded35a576e3899553ea0ccfcbf5cbdb3d8cf664Ted Kremenek};
1991e80aa49ec689d1937e54fb353d6626e0a58f0dbTed Kremenek
2001e80aa49ec689d1937e54fb353d6626e0a58f0dbTed Kremenekclass HistoryURLProviderTestNoDB : public HistoryURLProviderTest {
2012ded35a576e3899553ea0ccfcbf5cbdb3d8cf664Ted Kremenek protected:
2022ded35a576e3899553ea0ccfcbf5cbdb3d8cf664Ted Kremenek  virtual void SetUp() {
203d87a321a3c3902f7acfc6539b8946a00da6e45ccTed Kremenek    ASSERT_TRUE(SetUpImpl(true));
204d87a321a3c3902f7acfc6539b8946a00da6e45ccTed Kremenek  }
205d87a321a3c3902f7acfc6539b8946a00da6e45ccTed Kremenek};
206d87a321a3c3902f7acfc6539b8946a00da6e45ccTed Kremenek
2074a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenekvoid HistoryURLProviderTest::OnProviderUpdate(bool updated_matches) {
2084a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenek  if (autocomplete_->done())
2094a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenek    base::MessageLoop::current()->Quit();
210d87a321a3c3902f7acfc6539b8946a00da6e45ccTed Kremenek}
211d87a321a3c3902f7acfc6539b8946a00da6e45ccTed Kremenek
2124d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenekbool HistoryURLProviderTest::SetUpImpl(bool no_db) {
2134d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek  profile_.reset(new TestingProfile());
2144d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek  if (!(profile_->CreateHistoryService(true, no_db)))
2154d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek    return false;
2164d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek  if (!no_db) {
2174d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek    profile_->BlockUntilHistoryProcessesPendingRequests();
2184d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek    profile_->BlockUntilHistoryIndexIsRefreshed();
2194d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek  }
2204d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek  history_service_ =
2214d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek      HistoryServiceFactory::GetForProfile(profile_.get(),
2224d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek                                           Profile::EXPLICIT_ACCESS);
2234d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek
2244d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek  autocomplete_ = new HistoryURLProvider(this, profile_.get(), "en-US,en,ko");
2254d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek  TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse(
2264d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek      profile_.get(), &HistoryURLProviderTest::CreateTemplateURLService);
2274d839b4949efe9e2b16eeab679c25b28e31ea742Ted Kremenek  FillData();
228b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  return true;
2298cc13ea74fea1c04042a2f4087665bc5182e8408Ted Kremenek}
2308cc13ea74fea1c04042a2f4087665bc5182e8408Ted Kremenek
2318cc13ea74fea1c04042a2f4087665bc5182e8408Ted Kremenekvoid HistoryURLProviderTest::TearDown() {
2325e03fcb5420c33207433dd6f800588e256dd9bdbTed Kremenek  autocomplete_ = NULL;
2335e03fcb5420c33207433dd6f800588e256dd9bdbTed Kremenek}
2345e03fcb5420c33207433dd6f800588e256dd9bdbTed Kremenek
2355e03fcb5420c33207433dd6f800588e256dd9bdbTed Kremenekvoid HistoryURLProviderTest::FillData() {
2368cc13ea74fea1c04042a2f4087665bc5182e8408Ted Kremenek  // All visits are a long time ago (some tests require this since we do some
2372ded35a576e3899553ea0ccfcbf5cbdb3d8cf664Ted Kremenek  // special logic for things visited very recently). Note that this time must
2382ded35a576e3899553ea0ccfcbf5cbdb3d8cf664Ted Kremenek  // be more recent than the "archived history" threshold for the data to go
2392ded35a576e3899553ea0ccfcbf5cbdb3d8cf664Ted Kremenek  // into the main database.
2402ded35a576e3899553ea0ccfcbf5cbdb3d8cf664Ted Kremenek  //
241b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  // TODO(brettw) It would be nice if we could test this behavior, in which
2426a6719a3a11087b48d9f1a4eb08b3bd43cb05a65Ted Kremenek  // case the time would be specifed in the test_db structure.
243b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  Time visit_time = Time::Now() - TimeDelta::FromDays(80);
244b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek
2456a6719a3a11087b48d9f1a4eb08b3bd43cb05a65Ted Kremenek  for (size_t i = 0; i < arraysize(test_db); ++i) {
2466a6719a3a11087b48d9f1a4eb08b3bd43cb05a65Ted Kremenek    const TestURLInfo& cur = test_db[i];
2476a6719a3a11087b48d9f1a4eb08b3bd43cb05a65Ted Kremenek    const GURL current_url(cur.url);
2486a6719a3a11087b48d9f1a4eb08b3bd43cb05a65Ted Kremenek    history_service_->AddPageWithDetails(current_url, UTF8ToUTF16(cur.title),
2496a6719a3a11087b48d9f1a4eb08b3bd43cb05a65Ted Kremenek                                         cur.visit_count, cur.typed_count,
250b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek                                         visit_time, false,
251b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek                                         history::SOURCE_BROWSED);
252b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  }
253b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek
254b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  history_service_->AddPageWithDetails(
255b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek      GURL("http://p/"), UTF8ToUTF16("p"), 0, 0,
256b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek      Time::Now() -
257b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek      TimeDelta::FromDays(history::kLowQualityMatchAgeLimitInDays - 1),
258b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek      false, history::SOURCE_BROWSED);
259b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek}
26005a2378c708688c8ef498a5cea40ed7f5db15fa5Ted Kremenek
26105a2378c708688c8ef498a5cea40ed7f5db15fa5Ted Kremenekvoid HistoryURLProviderTest::RunTest(
26205a2378c708688c8ef498a5cea40ed7f5db15fa5Ted Kremenek    const string16 text,
263b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek    const string16& desired_tld,
264b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek    bool prevent_inline_autocomplete,
265b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek    const UrlAndLegalDefault* expected_urls,
266b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek    size_t num_results,
267b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek    AutocompleteInput::Type* identified_input_type) {
268aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek  AutocompleteInput input(text, string16::npos, desired_tld, GURL(),
269b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek                          AutocompleteInput::INVALID_SPEC,
270b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek                          prevent_inline_autocomplete, false, true,
271b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek                          AutocompleteInput::ALL_MATCHES);
272aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek  *identified_input_type = input.type();
273b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  autocomplete_->Start(input, false);
274aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek  if (!autocomplete_->done())
275aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek    base::MessageLoop::current()->Run();
276b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek
27705a2378c708688c8ef498a5cea40ed7f5db15fa5Ted Kremenek  matches_ = autocomplete_->matches();
278aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek  if (sort_matches_) {
2795a7b3821c6abed7f58a53a94eac128bd23d23289Ted Kremenek    for (ACMatches::iterator i = matches_.begin(); i != matches_.end(); ++i)
28005a2378c708688c8ef498a5cea40ed7f5db15fa5Ted Kremenek      i->ComputeStrippedDestinationURL(profile_.get());
281b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek    std::sort(matches_.begin(), matches_.end(),
282aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek              &AutocompleteMatch::DestinationSortFunc);
283aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek    matches_.erase(std::unique(matches_.begin(), matches_.end(),
284aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek                               &AutocompleteMatch::DestinationsEqual),
285aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek                   matches_.end());
286aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek    std::sort(matches_.begin(), matches_.end(),
287aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek              &AutocompleteMatch::MoreRelevant);
288aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek  }
289b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  ASSERT_EQ(num_results, matches_.size()) << "Input text: " << text
290aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek                                          << "\nTLD: \"" << desired_tld << "\"";
291b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  for (size_t i = 0; i < num_results; ++i) {
292aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek    EXPECT_EQ(expected_urls[i].url, matches_[i].destination_url.spec());
293aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek    EXPECT_EQ(expected_urls[i].allowed_to_be_default_match,
294b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek              matches_[i].allowed_to_be_default_match);
29505a2378c708688c8ef498a5cea40ed7f5db15fa5Ted Kremenek  }
296aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek}
297aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek
298b387a3f23e423d62c053be86294b703da1d1a222Ted KremenekTEST_F(HistoryURLProviderTest, PromoteShorterURLs) {
299b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  // Test that hosts get synthesized below popular pages.
300aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek  const UrlAndLegalDefault expected_nonsynth[] = {
30105a2378c708688c8ef498a5cea40ed7f5db15fa5Ted Kremenek    { "http://slashdot.org/favorite_page.html", false },
30205a2378c708688c8ef498a5cea40ed7f5db15fa5Ted Kremenek    { "http://slashdot.org/", false }
30377349cb20bfd7069d081f84c91975bfa8ef60a32Ted Kremenek  };
304aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek  RunTest(ASCIIToUTF16("slash"), string16(), true, expected_nonsynth,
305aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek          arraysize(expected_nonsynth));
306b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek
307b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  // Test that hosts get synthesized above less popular pages.
308aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek  const UrlAndLegalDefault expected_synth[] = {
309aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek    { "http://kerneltrap.org/", false },
310b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek    { "http://kerneltrap.org/not_very_popular.html", false }
311b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  };
312aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek  RunTest(ASCIIToUTF16("kernel"), string16(), true, expected_synth,
313240f1f00dda1d481276ea872fe8f8851581a7e6bTed Kremenek          arraysize(expected_synth));
314b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek
315b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  // Test that unpopular pages are ignored completely.
316b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  RunTest(ASCIIToUTF16("fresh"), string16(), true, NULL, 0);
317b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek
318aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek  // Test that if we create or promote shorter suggestions that would not
319aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek  // normally be inline autocompletable, we make them inline autocompletable if
320aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek  // the original suggestion (that we replaced as "top") was inline
321aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek  // autocompletable.
322aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek  const UrlAndLegalDefault expected_synthesisa[] = {
323aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek    { "http://synthesisatest.com/", true },
324aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek    { "http://synthesisatest.com/foo/", true }
325aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek  };
326aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek  RunTest(ASCIIToUTF16("synthesisa"), string16(), false, expected_synthesisa,
327aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek          arraysize(expected_synthesisa));
328b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  EXPECT_LT(matches_.front().relevance, 1200);
329aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek  const UrlAndLegalDefault expected_synthesisb[] = {
330b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek    { "http://synthesisbtest.com/foo/", true },
331b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek    { "http://synthesisbtest.com/foo/bar.html", true }
332aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek  };
333aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek  RunTest(ASCIIToUTF16("synthesisb"), string16(), false, expected_synthesisb,
334aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek          arraysize(expected_synthesisb));
335aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek  EXPECT_GE(matches_.front().relevance, 1410);
336aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek
337b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  // Test that if we have a synthesized host that matches a suggestion, they
338aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek  // get combined into one.
339aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek  const UrlAndLegalDefault expected_combine[] = {
340b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek    { "http://news.google.com/", false },
341aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek    { "http://news.google.com/?ned=us&topic=n", false },
342aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek  };
343b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  ASSERT_NO_FATAL_FAILURE(RunTest(ASCIIToUTF16("news"), string16(), true,
344aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek      expected_combine, arraysize(expected_combine)));
345aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek  // The title should also have gotten set properly on the host for the
346b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  // synthesized one, since it was also in the results.
3475c684c4be01fb98077a9b5e07ca1fdc01d8d97cbTed Kremenek  EXPECT_EQ(ASCIIToUTF16("Google News"), matches_.front().description);
3485c684c4be01fb98077a9b5e07ca1fdc01d8d97cbTed Kremenek
3495c684c4be01fb98077a9b5e07ca1fdc01d8d97cbTed Kremenek  // Test that short URL matching works correctly as the user types more
3505c684c4be01fb98077a9b5e07ca1fdc01d8d97cbTed Kremenek  // (several tests):
351b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  // The entry for foo.com is the best of all five foo.com* entries.
3524a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenek  const UrlAndLegalDefault short_1[] = {
3534a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenek    { "http://foo.com/", false },
3544a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenek    { "http://foo.com/dir/another/again/myfile.html", false },
3559dca062461a6244cf0f733346657fa3eee853f9bTed Kremenek    { "http://foo.com/dir/", false }
356b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  };
357b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  RunTest(ASCIIToUTF16("foo"), string16(), true, short_1, arraysize(short_1));
358b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek
359b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  // When the user types the whole host, make sure we don't get two results for
360b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  // it.
361b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  const UrlAndLegalDefault short_2[] = {
362b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek    { "http://foo.com/", true },
363aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek    { "http://foo.com/dir/another/again/myfile.html", false },
364b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek    { "http://foo.com/dir/", false },
365de43424560f1a744de6214dab6bbee28ad8437f5Ted Kremenek    { "http://foo.com/dir/another/", false }
366de43424560f1a744de6214dab6bbee28ad8437f5Ted Kremenek  };
367aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek  RunTest(ASCIIToUTF16("foo.com"), string16(), true, short_2,
368de43424560f1a744de6214dab6bbee28ad8437f5Ted Kremenek          arraysize(short_2));
369de43424560f1a744de6214dab6bbee28ad8437f5Ted Kremenek  RunTest(ASCIIToUTF16("foo.com/"), string16(), true, short_2,
370b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek          arraysize(short_2));
371aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek
372b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  // The filename is the second best of the foo.com* entries, but there is a
373b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  // shorter URL that's "good enough".  The host doesn't match the user input
374b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  // and so should not appear.
375b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  const UrlAndLegalDefault short_3[] = {
376b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek    { "http://foo.com/d", true },
377b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek    { "http://foo.com/dir/another/", false },
378b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek    { "http://foo.com/dir/another/again/myfile.html", false },
379b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek    { "http://foo.com/dir/", false }
380aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek  };
381b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  RunTest(ASCIIToUTF16("foo.com/d"), string16(), true, short_3,
382b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek          arraysize(short_3));
383b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek
384b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  // We shouldn't promote shorter URLs than the best if they're not good
385b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  // enough.
386aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek  const UrlAndLegalDefault short_4[] = {
387b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek    { "http://foo.com/dir/another/a", true },
388b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek    { "http://foo.com/dir/another/again/myfile.html", false },
389aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek    { "http://foo.com/dir/another/again/", false }
390aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek  };
391aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek  RunTest(ASCIIToUTF16("foo.com/dir/another/a"), string16(), true, short_4,
392b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek          arraysize(short_4));
393b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek
394b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  // Exact matches should always be best no matter how much more another match
395ffe0f43806d4823271c2406c1fccc2373115c36aTed Kremenek  // has been typed.
396ffe0f43806d4823271c2406c1fccc2373115c36aTed Kremenek  const UrlAndLegalDefault short_5a[] = {
397d8e9f0dc737133d4e8342f39389064620f5a7f8fTed Kremenek    { "http://gooey/", true },
3989ef1ec98a8fc17e7560e07641184bc4daee39b46Ted Kremenek    { "http://www.google.com/", true },
3994a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenek    { "http://go/", true }
4009ef1ec98a8fc17e7560e07641184bc4daee39b46Ted Kremenek  };
4019ef1ec98a8fc17e7560e07641184bc4daee39b46Ted Kremenek  const UrlAndLegalDefault short_5b[] = {
4029ef1ec98a8fc17e7560e07641184bc4daee39b46Ted Kremenek    { "http://go/", true },
403240f1f00dda1d481276ea872fe8f8851581a7e6bTed Kremenek    { "http://gooey/", true },
4049ef1ec98a8fc17e7560e07641184bc4daee39b46Ted Kremenek    { "http://www.google.com/", true }
405240f1f00dda1d481276ea872fe8f8851581a7e6bTed Kremenek  };
406b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  RunTest(ASCIIToUTF16("g"), string16(), false, short_5a, arraysize(short_5a));
407b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  RunTest(ASCIIToUTF16("go"), string16(), false, short_5b, arraysize(short_5b));
408aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek}
409240f1f00dda1d481276ea872fe8f8851581a7e6bTed Kremenek
410b387a3f23e423d62c053be86294b703da1d1a222Ted KremenekTEST_F(HistoryURLProviderTest, CullRedirects) {
411b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  // URLs we will be using, plus the visit counts they will initially get
412aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek  // (the redirect set below will also increment the visit counts). We want
413240f1f00dda1d481276ea872fe8f8851581a7e6bTed Kremenek  // the results to be in A,B,C order. Note also that our visit counts are
41490e420321f60860f4c4e7a68ca9f7567824b46ecTed Kremenek  // all high enough so that domain synthesizing won't get triggered.
41510c16657eec144def180ee53d1e0249c9ed2b3b5Ted Kremenek  struct TestCase {
416aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek    const char* url;
417240f1f00dda1d481276ea872fe8f8851581a7e6bTed Kremenek    int count;
418b640b3b5dfccaf259967cb2cb6755c9aa20d4423Ted Kremenek  } test_cases[] = {
41950d0ac299c641bee9024f3fbae2ea0640898a040Ted Kremenek    {"http://redirects/A", 30},
420c3055ab39ac3535ffd581d33e21b72133099a6ebTed Kremenek    {"http://redirects/B", 20},
421240f1f00dda1d481276ea872fe8f8851581a7e6bTed Kremenek    {"http://redirects/C", 10}
422c3055ab39ac3535ffd581d33e21b72133099a6ebTed Kremenek  };
423c3055ab39ac3535ffd581d33e21b72133099a6ebTed Kremenek  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
424aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek    history_service_->AddPageWithDetails(GURL(test_cases[i].url),
425692416c214a3b234236dedcf875735a9cc29e90bTed Kremenek        UTF8ToUTF16("Title"), test_cases[i].count, test_cases[i].count,
4264a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenek        Time::Now(), false, history::SOURCE_BROWSED);
4274a4e524afef40d6f3ddb25d0e407c814e4ca56a8Ted Kremenek  }
428692416c214a3b234236dedcf875735a9cc29e90bTed Kremenek
429aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek  // Create a B->C->A redirect chain, but set the visit counts such that they
430692416c214a3b234236dedcf875735a9cc29e90bTed Kremenek  // will appear in A,B,C order in the results. The autocomplete query will
431aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek  // search for the most recent visit when looking for redirects, so this will
432aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek  // be found even though the previous visits had no redirects.
433aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek  history::RedirectList redirects_to_a;
434240f1f00dda1d481276ea872fe8f8851581a7e6bTed Kremenek  redirects_to_a.push_back(GURL(test_cases[1].url));
435aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek  redirects_to_a.push_back(GURL(test_cases[2].url));
436240f1f00dda1d481276ea872fe8f8851581a7e6bTed Kremenek  redirects_to_a.push_back(GURL(test_cases[0].url));
437aa1c4e5a6b87b62d991c55a0d4522bcd778068d7Ted Kremenek  history_service_->AddPage(GURL(test_cases[0].url), base::Time::Now(),
438692416c214a3b234236dedcf875735a9cc29e90bTed Kremenek      NULL, 0, GURL(), redirects_to_a, content::PAGE_TRANSITION_TYPED,
439240f1f00dda1d481276ea872fe8f8851581a7e6bTed Kremenek      history::SOURCE_BROWSED, true);
44050d0ac299c641bee9024f3fbae2ea0640898a040Ted Kremenek
441de43424560f1a744de6214dab6bbee28ad8437f5Ted Kremenek  // Because all the results are part of a redirect chain with other results,
442330dddd19406f9cc227e59e0bb0a36ecdc52915eTed Kremenek  // all but the first one (A) should be culled. We should get the default
443330dddd19406f9cc227e59e0bb0a36ecdc52915eTed Kremenek  // "what you typed" result, plus this one.
444240f1f00dda1d481276ea872fe8f8851581a7e6bTed Kremenek  const string16 typing(ASCIIToUTF16("http://redirects/"));
445de43424560f1a744de6214dab6bbee28ad8437f5Ted Kremenek  const UrlAndLegalDefault expected_results[] = {
44605a2378c708688c8ef498a5cea40ed7f5db15fa5Ted Kremenek    { UTF16ToUTF8(typing), true },
447aed9b6ac2ed0013133e4d4aebf2fad2ccd27f3e6Ted Kremenek    { test_cases[0].url, false }
448b387a3f23e423d62c053be86294b703da1d1a222Ted Kremenek  };
44972fc3b30d775a6b720dd0dd87aa853226f0625ddChris Lattner  RunTest(typing, string16(), true, expected_results,
45072fc3b30d775a6b720dd0dd87aa853226f0625ddChris Lattner          arraysize(expected_results));
451}
452
453TEST_F(HistoryURLProviderTest, WhatYouTyped) {
454  // Make sure we suggest a What You Typed match at the right times.
455  RunTest(ASCIIToUTF16("wytmatch"), string16(), false, NULL, 0);
456  RunTest(ASCIIToUTF16("wytmatch foo bar"), string16(), false, NULL, 0);
457  RunTest(ASCIIToUTF16("wytmatch+foo+bar"), string16(), false, NULL, 0);
458  RunTest(ASCIIToUTF16("wytmatch+foo+bar.com"), string16(), false, NULL, 0);
459
460  const UrlAndLegalDefault results_1[] = {
461    { "http://www.wytmatch.com/", true }
462  };
463  RunTest(ASCIIToUTF16("wytmatch"), ASCIIToUTF16("com"), false, results_1,
464          arraysize(results_1));
465
466  const UrlAndLegalDefault results_2[] = {
467    { "http://wytmatch%20foo%20bar/", true }
468  };
469  RunTest(ASCIIToUTF16("http://wytmatch foo bar"), string16(), false, results_2,
470          arraysize(results_2));
471
472  const UrlAndLegalDefault results_3[] = {
473    { "https://wytmatch%20foo%20bar/", true }
474  };
475  RunTest(ASCIIToUTF16("https://wytmatch foo bar"), string16(), false,
476          results_3, arraysize(results_3));
477}
478
479TEST_F(HistoryURLProviderTest, Fixup) {
480  // Test for various past crashes we've had.
481  RunTest(ASCIIToUTF16("\\"), string16(), false, NULL, 0);
482  RunTest(ASCIIToUTF16("#"), string16(), false, NULL, 0);
483  RunTest(ASCIIToUTF16("%20"), string16(), false, NULL, 0);
484  const UrlAndLegalDefault fixup_crash[] = {
485    { "http://%EF%BD%A5@s/", true }
486  };
487  RunTest(WideToUTF16(L"\uff65@s"), string16(), false, fixup_crash,
488          arraysize(fixup_crash));
489  RunTest(WideToUTF16(L"\u2015\u2015@ \uff7c"), string16(), false, NULL, 0);
490
491  // Fixing up "file:" should result in an inline autocomplete offset of just
492  // after "file:", not just after "file://".
493  const string16 input_1(ASCIIToUTF16("file:"));
494  const UrlAndLegalDefault fixup_1[] = {
495    { "file:///C:/foo.txt", true }
496  };
497  ASSERT_NO_FATAL_FAILURE(RunTest(input_1, string16(), false, fixup_1,
498                                  arraysize(fixup_1)));
499  EXPECT_EQ(ASCIIToUTF16("///C:/foo.txt"),
500            matches_.front().inline_autocompletion);
501
502  // Fixing up "http:/" should result in an inline autocomplete offset of just
503  // after "http:/", not just after "http:".
504  const string16 input_2(ASCIIToUTF16("http:/"));
505  const UrlAndLegalDefault fixup_2[] = {
506    { "http://bogussite.com/a", true },
507    { "http://bogussite.com/b", true },
508    { "http://bogussite.com/c", true }
509  };
510  ASSERT_NO_FATAL_FAILURE(RunTest(input_2, string16(), false, fixup_2,
511                                  arraysize(fixup_2)));
512  EXPECT_EQ(ASCIIToUTF16("/bogussite.com/a"),
513            matches_.front().inline_autocompletion);
514
515  // Adding a TLD to a small number like "56" should result in "www.56.com"
516  // rather than "0.0.0.56.com".
517  const UrlAndLegalDefault fixup_3[] = {
518    { "http://www.56.com/", true }
519  };
520  RunTest(ASCIIToUTF16("56"), ASCIIToUTF16("com"), true, fixup_3,
521          arraysize(fixup_3));
522
523  // An input looks like a IP address like "127.0.0.1" should result in
524  // "http://127.0.0.1/".
525  const UrlAndLegalDefault fixup_4[] = {
526    { "http://127.0.0.1/", true }
527  };
528  RunTest(ASCIIToUTF16("127.0.0.1"), string16(), false, fixup_4,
529          arraysize(fixup_4));
530
531  // An number "17173" should result in "http://www.17173.com/" in db.
532  const UrlAndLegalDefault fixup_5[] = {
533    { "http://www.17173.com/", true }
534  };
535  RunTest(ASCIIToUTF16("17173"), string16(), false, fixup_5,
536          arraysize(fixup_5));
537}
538
539// Make sure the results for the input 'p' don't change between the first and
540// second passes.
541TEST_F(HistoryURLProviderTest, EmptyVisits) {
542  // Wait for history to create the in memory DB.
543  profile_->BlockUntilHistoryProcessesPendingRequests();
544
545  AutocompleteInput input(ASCIIToUTF16("p"), string16::npos, string16(), GURL(),
546                          AutocompleteInput::INVALID_SPEC, false, false, true,
547                          AutocompleteInput::ALL_MATCHES);
548  autocomplete_->Start(input, false);
549  // HistoryURLProvider shouldn't be done (waiting on async results).
550  EXPECT_FALSE(autocomplete_->done());
551
552  // We should get back an entry for pandora.
553  matches_ = autocomplete_->matches();
554  ASSERT_GT(matches_.size(), 0u);
555  EXPECT_EQ(GURL("http://pandora.com/"), matches_[0].destination_url);
556  int pandora_relevance = matches_[0].relevance;
557
558  // Run the message loop. When |autocomplete_| finishes the loop is quit.
559  base::MessageLoop::current()->Run();
560  EXPECT_TRUE(autocomplete_->done());
561  matches_ = autocomplete_->matches();
562  ASSERT_GT(matches_.size(), 0u);
563  EXPECT_EQ(GURL("http://pandora.com/"), matches_[0].destination_url);
564  EXPECT_EQ(pandora_relevance, matches_[0].relevance);
565}
566
567TEST_F(HistoryURLProviderTestNoDB, NavigateWithoutDB) {
568  // Ensure that we will still produce matches for navigation when there is no
569  // database.
570  UrlAndLegalDefault navigation_1[] = {
571    { "http://test.com/", true }
572  };
573  RunTest(ASCIIToUTF16("test.com"), string16(), false, navigation_1,
574          arraysize(navigation_1));
575
576  UrlAndLegalDefault navigation_2[] = {
577    { "http://slash/", true }
578  };
579  RunTest(ASCIIToUTF16("slash"), string16(), false, navigation_2,
580          arraysize(navigation_2));
581
582  RunTest(ASCIIToUTF16("this is a query"), string16(), false, NULL, 0);
583}
584
585TEST_F(HistoryURLProviderTest, DontAutocompleteOnTrailingWhitespace) {
586  AutocompleteInput input(ASCIIToUTF16("slash "), string16::npos, string16(),
587                          GURL(), AutocompleteInput::INVALID_SPEC, false, false,
588                          true, AutocompleteInput::ALL_MATCHES);
589  autocomplete_->Start(input, false);
590  if (!autocomplete_->done())
591    base::MessageLoop::current()->Run();
592
593  // None of the matches should attempt to autocomplete.
594  matches_ = autocomplete_->matches();
595  for (size_t i = 0; i < matches_.size(); ++i) {
596    EXPECT_TRUE(matches_[i].inline_autocompletion.empty());
597    EXPECT_FALSE(matches_[i].allowed_to_be_default_match);
598  }
599}
600
601TEST_F(HistoryURLProviderTest, TreatEmailsAsSearches) {
602  // Visiting foo.com should not make this string be treated as a navigation.
603  // That means the result should be scored around 1200 ("what you typed")
604  // and not 1400+.
605  const UrlAndLegalDefault expected[] = {
606    { "http://user@foo.com/", true }
607  };
608  ASSERT_NO_FATAL_FAILURE(RunTest(ASCIIToUTF16("user@foo.com"), string16(),
609                                  false, expected, arraysize(expected)));
610  EXPECT_LE(1200, matches_[0].relevance);
611  EXPECT_LT(matches_[0].relevance, 1210);
612}
613
614TEST_F(HistoryURLProviderTest, IntranetURLsWithPaths) {
615  struct TestCase {
616    const char* input;
617    int relevance;
618  } test_cases[] = {
619    { "fooey", 0 },
620    { "fooey/", 1200 },     // 1200 for URL would still navigate by default.
621    { "fooey/a", 1200 },    // 1200 for UNKNOWN would not.
622    { "fooey/a b", 1200 },  // Also UNKNOWN.
623    { "gooey", 1410 },
624    { "gooey/", 1410 },
625    { "gooey/a", 1400 },
626    { "gooey/a b", 1400 },
627  };
628  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
629    SCOPED_TRACE(test_cases[i].input);
630    if (test_cases[i].relevance == 0) {
631      RunTest(ASCIIToUTF16(test_cases[i].input), string16(), false, NULL, 0);
632    } else {
633      const UrlAndLegalDefault output[] = {
634        { URLFixerUpper::FixupURL(test_cases[i].input, std::string()).spec(),
635          true }
636      };
637      ASSERT_NO_FATAL_FAILURE(RunTest(ASCIIToUTF16(test_cases[i].input),
638                              string16(), false, output, arraysize(output)));
639      // Actual relevance should be at least what test_cases expects and
640      // and no more than 10 more.
641      EXPECT_LE(test_cases[i].relevance, matches_[0].relevance);
642      EXPECT_LT(matches_[0].relevance, test_cases[i].relevance + 10);
643    }
644  }
645}
646
647TEST_F(HistoryURLProviderTest, IntranetURLsWithRefs) {
648  struct TestCase {
649    const char* input;
650    int relevance;
651    AutocompleteInput::Type type;
652  } test_cases[] = {
653    { "gooey", 1410, AutocompleteInput::UNKNOWN },
654    { "gooey/", 1410, AutocompleteInput::URL },
655    { "gooey#", 1200, AutocompleteInput::UNKNOWN },
656    { "gooey/#", 1200, AutocompleteInput::URL },
657    { "gooey#foo", 1200, AutocompleteInput::UNKNOWN },
658    { "gooey/#foo", 1200, AutocompleteInput::URL },
659    { "gooey# foo", 1200, AutocompleteInput::UNKNOWN },
660    { "gooey/# foo", 1200, AutocompleteInput::URL },
661  };
662  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
663    SCOPED_TRACE(test_cases[i].input);
664    const UrlAndLegalDefault output[] = {
665      { URLFixerUpper::FixupURL(test_cases[i].input, std::string()).spec(),
666        true }
667    };
668    AutocompleteInput::Type type;
669    ASSERT_NO_FATAL_FAILURE(
670        RunTest(ASCIIToUTF16(test_cases[i].input),
671                string16(), false, output, arraysize(output), &type));
672    // Actual relevance should be at least what test_cases expects and
673    // and no more than 10 more.
674    EXPECT_LE(test_cases[i].relevance, matches_[0].relevance);
675    EXPECT_LT(matches_[0].relevance, test_cases[i].relevance + 10);
676    // Input type should be what we expect.  This is important because
677    // this provider counts on SearchProvider to give queries a relevance
678    // score >1200 for UNKNOWN inputs and <1200 for URL inputs.  (That's
679    // already tested in search_provider_unittest.cc.)  For this test
680    // here to test that the user sees the correct behavior, it needs
681    // to check that the input type was identified correctly.
682    EXPECT_EQ(test_cases[i].type, type);
683  }
684}
685
686// Makes sure autocompletion happens for intranet sites that have been
687// previoulsy visited.
688TEST_F(HistoryURLProviderTest, IntranetURLCompletion) {
689  sort_matches_ = true;
690
691  const UrlAndLegalDefault expected1[] = {
692    { "http://intra/three", true },
693    { "http://intra/two", true }
694  };
695  ASSERT_NO_FATAL_FAILURE(RunTest(ASCIIToUTF16("intra/t"), string16(), false,
696                                  expected1, arraysize(expected1)));
697  EXPECT_LE(1410, matches_[0].relevance);
698  EXPECT_LT(matches_[0].relevance, 1420);
699  EXPECT_EQ(matches_[0].relevance - 1, matches_[1].relevance);
700
701  const UrlAndLegalDefault expected2[] = {
702    { "http://moo/b", true },
703    { "http://moo/bar", true }
704  };
705  ASSERT_NO_FATAL_FAILURE(RunTest(ASCIIToUTF16("moo/b"), string16(), false,
706                                  expected2, arraysize(expected2)));
707  // The url what you typed match should be around 1400, otherwise the
708  // search what you typed match is going to be first.
709  EXPECT_LE(1400, matches_[0].relevance);
710  EXPECT_LT(matches_[0].relevance, 1410);
711
712  const UrlAndLegalDefault expected3[] = {
713    { "http://intra/one", true },
714    { "http://intra/three", true },
715    { "http://intra/two", true }
716  };
717  RunTest(ASCIIToUTF16("intra"), string16(), false, expected3,
718          arraysize(expected3));
719
720  const UrlAndLegalDefault expected4[] = {
721    { "http://intra/one", true },
722    { "http://intra/three", true },
723    { "http://intra/two", true }
724  };
725  RunTest(ASCIIToUTF16("intra/"), string16(), false, expected4,
726          arraysize(expected4));
727
728  const UrlAndLegalDefault expected5[] = {
729    { "http://intra/one", true }
730  };
731  ASSERT_NO_FATAL_FAILURE(RunTest(ASCIIToUTF16("intra/o"), string16(), false,
732                                  expected5, arraysize(expected5)));
733  EXPECT_LE(1410, matches_[0].relevance);
734  EXPECT_LT(matches_[0].relevance, 1420);
735
736  const UrlAndLegalDefault expected6[] = {
737    { "http://intra/x", true }
738  };
739  ASSERT_NO_FATAL_FAILURE(RunTest(ASCIIToUTF16("intra/x"), string16(), false,
740                                  expected6, arraysize(expected6)));
741  EXPECT_LE(1400, matches_[0].relevance);
742  EXPECT_LT(matches_[0].relevance, 1410);
743
744  const UrlAndLegalDefault expected7[] = {
745    { "http://typedhost/untypedpath", true }
746  };
747  ASSERT_NO_FATAL_FAILURE(RunTest(ASCIIToUTF16("typedhost/untypedpath"),
748      string16(), false, expected7, arraysize(expected7)));
749  EXPECT_LE(1400, matches_[0].relevance);
750  EXPECT_LT(matches_[0].relevance, 1410);
751}
752
753TEST_F(HistoryURLProviderTest, CrashDueToFixup) {
754  // This test passes if we don't crash.  The results don't matter.
755  const char* const test_cases[] = {
756    "//c",
757    "\\@st"
758  };
759  for (size_t i = 0; i < arraysize(test_cases); ++i) {
760    AutocompleteInput input(ASCIIToUTF16(test_cases[i]), string16::npos,
761                            string16(), GURL(), AutocompleteInput::INVALID_SPEC,
762                            false, false, true, AutocompleteInput::ALL_MATCHES);
763    autocomplete_->Start(input, false);
764    if (!autocomplete_->done())
765      base::MessageLoop::current()->Run();
766  }
767}
768
769TEST_F(HistoryURLProviderTest, CullSearchResults) {
770  // Set up a default search engine.
771  TemplateURLData data;
772  data.SetKeyword(ASCIIToUTF16("TestEngine"));
773  data.SetURL("http://testsearch.com/?q={searchTerms}");
774  TemplateURLService* template_url_service =
775      TemplateURLServiceFactory::GetForProfile(profile_.get());
776  TemplateURL* template_url = new TemplateURL(profile_.get(), data);
777  template_url_service->Add(template_url);
778  template_url_service->SetDefaultSearchProvider(template_url);
779  template_url_service->Load();
780
781  // URLs we will be using, plus the visit counts they will initially get
782  // (the redirect set below will also increment the visit counts). We want
783  // the results to be in A,B,C order. Note also that our visit counts are
784  // all high enough so that domain synthesizing won't get triggered.
785  struct TestCase {
786    const char* url;
787    int count;
788  } test_cases[] = {
789    {"https://testsearch.com/", 30},
790    {"https://testsearch.com/?q=foobar", 20},
791    {"http://foobar.com/", 10}
792  };
793  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
794    history_service_->AddPageWithDetails(GURL(test_cases[i].url),
795        UTF8ToUTF16("Title"), test_cases[i].count, test_cases[i].count,
796        Time::Now(), false, history::SOURCE_BROWSED);
797  }
798
799  // We should not see search URLs when typing a previously used query.
800  const UrlAndLegalDefault expected_when_searching_query[] = {
801    { test_cases[2].url, false }
802  };
803  RunTest(ASCIIToUTF16("foobar"), string16(), true,
804      expected_when_searching_query, arraysize(expected_when_searching_query));
805
806  // We should not see search URLs when typing the search engine name.
807  const UrlAndLegalDefault expected_when_searching_site[] = {
808    { test_cases[0].url, false }
809  };
810  RunTest(ASCIIToUTF16("testsearch"), string16(), true,
811      expected_when_searching_site, arraysize(expected_when_searching_site));
812}
813
814TEST_F(HistoryURLProviderTest, SuggestExactInput) {
815  const size_t npos = std::string::npos;
816  struct TestCase {
817    // Inputs:
818    const char* input;
819    bool trim_http;
820    // Expected Outputs:
821    const char* contents;
822    // Offsets of the ACMatchClassifications, terminated by npos.
823    size_t offsets[3];
824    // The index of the ACMatchClassification that should have the MATCH bit
825    // set, npos if no ACMatchClassification should have the MATCH bit set.
826    size_t match_classification_index;
827  } test_cases[] = {
828    { "http://www.somesite.com", false,
829      "http://www.somesite.com", {0, npos, npos}, 0 },
830    { "www.somesite.com", true,
831      "www.somesite.com", {0, npos, npos}, 0 },
832    { "www.somesite.com", false,
833      "http://www.somesite.com", {0, 7, npos}, 1 },
834    { "somesite.com", true,
835      "somesite.com", {0, npos, npos}, 0 },
836    { "somesite.com", false,
837      "http://somesite.com", {0, 7, npos}, 1 },
838    { "w", true,
839      "w", {0, npos, npos}, 0 },
840    { "w", false,
841      "http://w", {0, 7, npos}, 1 },
842    { "w.com", true,
843      "w.com", {0, npos, npos}, 0 },
844    { "w.com", false,
845      "http://w.com", {0, 7, npos}, 1 },
846    { "www.w.com", true,
847      "www.w.com", {0, npos, npos}, 0 },
848    { "www.w.com", false,
849      "http://www.w.com", {0, 7, npos}, 1 },
850    { "view-source:www.w.com/", true,
851      "view-source:www.w.com", {0, npos, npos}, npos },
852    { "view-source:www.w.com/", false,
853      "view-source:http://www.w.com", {0, npos, npos}, npos },
854    { "view-source:http://www.w.com/", false,
855      "view-source:http://www.w.com", {0, npos, npos}, 0 },
856    { "   view-source:", true,
857      "view-source:", {0, npos, npos}, 0 },
858    { "http:////////w.com", false,
859      "http://w.com", {0, npos, npos}, npos },
860    { "    http:////////www.w.com", false,
861      "http://www.w.com", {0, npos, npos}, npos },
862    { "http:a///www.w.com", false,
863      "http://a///www.w.com", {0, npos, npos}, npos },
864    { "mailto://a@b.com", true,
865      "mailto://a@b.com", {0, npos, npos}, 0 },
866    { "mailto://a@b.com", false,
867      "mailto://a@b.com", {0, npos, npos}, 0 },
868  };
869  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
870    SCOPED_TRACE(testing::Message() << "Index " << i << " input: "
871                                    << test_cases[i].input << ", trim_http: "
872                                    << test_cases[i].trim_http);
873
874    AutocompleteInput input(ASCIIToUTF16(test_cases[i].input), string16::npos,
875                            string16(), GURL("about:blank"),
876                            AutocompleteInput::INVALID_SPEC, false, false, true,
877                            AutocompleteInput::ALL_MATCHES);
878    AutocompleteMatch match = HistoryURLProvider::SuggestExactInput(
879        autocomplete_.get(), input, test_cases[i].trim_http);
880    EXPECT_EQ(ASCIIToUTF16(test_cases[i].contents), match.contents);
881    for (size_t match_index = 0; match_index < match.contents_class.size();
882         ++match_index) {
883      EXPECT_EQ(test_cases[i].offsets[match_index],
884                match.contents_class[match_index].offset);
885      EXPECT_EQ(ACMatchClassification::URL |
886                (match_index == test_cases[i].match_classification_index ?
887                 ACMatchClassification::MATCH : 0),
888                match.contents_class[match_index].style);
889    }
890    EXPECT_EQ(npos, test_cases[i].offsets[match.contents_class.size()]);
891  }
892}
893