1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/command_line.h"
6#include "base/format_macros.h"
7#include "base/path_service.h"
8#include "base/strings/stringprintf.h"
9#include "base/strings/utf_string_conversions.h"
10#include "chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.h"
11#include "chrome/browser/extensions/extension_browsertest.h"
12#include "chrome/browser/extensions/extension_service.h"
13#include "chrome/browser/extensions/unpacked_installer.h"
14#include "chrome/browser/history/history_service.h"
15#include "chrome/browser/history/history_service_factory.h"
16#include "chrome/browser/profiles/profile.h"
17#include "chrome/browser/search_engines/template_url_service_factory.h"
18#include "chrome/browser/ui/browser.h"
19#include "chrome/browser/ui/browser_commands.h"
20#include "chrome/browser/ui/browser_tabstrip.h"
21#include "chrome/browser/ui/browser_window.h"
22#include "chrome/browser/ui/location_bar/location_bar.h"
23#include "chrome/browser/ui/omnibox/omnibox_popup_model.h"
24#include "chrome/browser/ui/omnibox/omnibox_view.h"
25#include "chrome/browser/ui/tabs/tab_strip_model.h"
26#include "chrome/common/chrome_paths.h"
27#include "chrome/common/url_constants.h"
28#include "chrome/test/base/in_process_browser_test.h"
29#include "chrome/test/base/test_switches.h"
30#include "chrome/test/base/ui_test_utils.h"
31#include "components/metrics/proto/omnibox_event.pb.h"
32#include "components/omnibox/autocomplete_input.h"
33#include "components/omnibox/autocomplete_match.h"
34#include "components/omnibox/autocomplete_provider.h"
35#include "content/public/browser/notification_service.h"
36#include "content/public/browser/notification_types.h"
37#include "testing/gtest/include/gtest/gtest.h"
38
39namespace {
40
41base::string16 AutocompleteResultAsString(const AutocompleteResult& result) {
42  std::string output(base::StringPrintf("{%" PRIuS "} ", result.size()));
43  for (size_t i = 0; i < result.size(); ++i) {
44    AutocompleteMatch match = result.match_at(i);
45    output.append(base::StringPrintf("[\"%s\" by \"%s\"] ",
46                                     base::UTF16ToUTF8(match.contents).c_str(),
47                                     match.provider->GetName()));
48  }
49  return base::UTF8ToUTF16(output);
50}
51
52}  // namespace
53
54class AutocompleteBrowserTest : public ExtensionBrowserTest {
55 protected:
56  void WaitForTemplateURLServiceToLoad() {
57    ui_test_utils::WaitForTemplateURLServiceToLoad(
58      TemplateURLServiceFactory::GetForProfile(browser()->profile()));
59  }
60
61  LocationBar* GetLocationBar() const {
62    return browser()->window()->GetLocationBar();
63  }
64
65  AutocompleteController* GetAutocompleteController() const {
66    return GetLocationBar()->GetOmniboxView()->model()->popup_model()->
67        autocomplete_controller();
68  }
69};
70
71IN_PROC_BROWSER_TEST_F(AutocompleteBrowserTest, Basic) {
72#if defined(OS_WIN) && defined(USE_ASH)
73  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
74  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
75    return;
76#endif
77
78  WaitForTemplateURLServiceToLoad();
79  LocationBar* location_bar = GetLocationBar();
80  OmniboxView* omnibox_view = location_bar->GetOmniboxView();
81
82  EXPECT_FALSE(location_bar->GetDestinationURL().is_valid());
83  EXPECT_EQ(base::UTF8ToUTF16(url::kAboutBlankURL), omnibox_view->GetText());
84  // TODO(phajdan.jr): check state of IsSelectAll when it's consistent across
85  // platforms.
86
87  location_bar->FocusLocation(true);
88
89  EXPECT_FALSE(location_bar->GetDestinationURL().is_valid());
90  EXPECT_EQ(base::UTF8ToUTF16(url::kAboutBlankURL), omnibox_view->GetText());
91  EXPECT_TRUE(omnibox_view->IsSelectAll());
92
93  omnibox_view->SetUserText(base::ASCIIToUTF16("chrome"));
94
95  EXPECT_FALSE(location_bar->GetDestinationURL().is_valid());
96  EXPECT_EQ(base::ASCIIToUTF16("chrome"), omnibox_view->GetText());
97  EXPECT_FALSE(omnibox_view->IsSelectAll());
98
99  omnibox_view->RevertAll();
100
101  EXPECT_FALSE(location_bar->GetDestinationURL().is_valid());
102  EXPECT_EQ(base::UTF8ToUTF16(url::kAboutBlankURL), omnibox_view->GetText());
103  EXPECT_FALSE(omnibox_view->IsSelectAll());
104
105  omnibox_view->SetUserText(base::ASCIIToUTF16("chrome"));
106  location_bar->Revert();
107
108  EXPECT_FALSE(location_bar->GetDestinationURL().is_valid());
109  EXPECT_EQ(base::UTF8ToUTF16(url::kAboutBlankURL), omnibox_view->GetText());
110  EXPECT_FALSE(omnibox_view->IsSelectAll());
111}
112
113// Autocomplete test is flaky on ChromeOS.
114// http://crbug.com/52928
115#if defined(OS_CHROMEOS)
116#define MAYBE_Autocomplete DISABLED_Autocomplete
117#else
118#define MAYBE_Autocomplete Autocomplete
119#endif
120
121IN_PROC_BROWSER_TEST_F(AutocompleteBrowserTest, MAYBE_Autocomplete) {
122#if defined(OS_WIN) && defined(USE_ASH)
123  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
124  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
125    return;
126#endif
127
128  WaitForTemplateURLServiceToLoad();
129  // The results depend on the history backend being loaded. Make sure it is
130  // loaded so that the autocomplete results are consistent.
131  ui_test_utils::WaitForHistoryToLoad(
132      HistoryServiceFactory::GetForProfile(browser()->profile(),
133                                           Profile::EXPLICIT_ACCESS));
134
135  LocationBar* location_bar = GetLocationBar();
136  OmniboxView* omnibox_view = location_bar->GetOmniboxView();
137  AutocompleteController* autocomplete_controller = GetAutocompleteController();
138
139  {
140    omnibox_view->model()->SetInputInProgress(true);
141    autocomplete_controller->Start(AutocompleteInput(
142        base::ASCIIToUTF16("chrome"), base::string16::npos, base::string16(),
143        GURL(), metrics::OmniboxEventProto::NTP, true, false, true, false,
144        ChromeAutocompleteSchemeClassifier(browser()->profile())));
145
146    EXPECT_TRUE(autocomplete_controller->done());
147    EXPECT_FALSE(location_bar->GetDestinationURL().is_valid());
148    EXPECT_TRUE(omnibox_view->GetText().empty());
149    EXPECT_TRUE(omnibox_view->IsSelectAll());
150    const AutocompleteResult& result = autocomplete_controller->result();
151    ASSERT_GE(result.size(), 1U) << AutocompleteResultAsString(result);
152    AutocompleteMatch match = result.match_at(0);
153    EXPECT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, match.type);
154    EXPECT_FALSE(match.deletable);
155  }
156
157  {
158    location_bar->Revert();
159    EXPECT_FALSE(location_bar->GetDestinationURL().is_valid());
160    EXPECT_EQ(base::UTF8ToUTF16(url::kAboutBlankURL), omnibox_view->GetText());
161    EXPECT_FALSE(omnibox_view->IsSelectAll());
162    const AutocompleteResult& result = autocomplete_controller->result();
163    EXPECT_TRUE(result.empty()) << AutocompleteResultAsString(result);
164  }
165}
166
167IN_PROC_BROWSER_TEST_F(AutocompleteBrowserTest, TabAwayRevertSelect) {
168#if defined(OS_WIN) && defined(USE_ASH)
169  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
170  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
171    return;
172#endif
173
174  WaitForTemplateURLServiceToLoad();
175  // http://code.google.com/p/chromium/issues/detail?id=38385
176  // Make sure that tabbing away from an empty omnibox causes a revert
177  // and select all.
178  LocationBar* location_bar = GetLocationBar();
179  OmniboxView* omnibox_view = location_bar->GetOmniboxView();
180  EXPECT_EQ(base::UTF8ToUTF16(url::kAboutBlankURL), omnibox_view->GetText());
181  omnibox_view->SetUserText(base::string16());
182  content::WindowedNotificationObserver observer(
183      content::NOTIFICATION_LOAD_STOP,
184      content::NotificationService::AllSources());
185  chrome::AddSelectedTabWithURL(browser(),
186                                GURL(url::kAboutBlankURL),
187                                ui::PAGE_TRANSITION_AUTO_TOPLEVEL);
188  observer.Wait();
189  EXPECT_EQ(base::UTF8ToUTF16(url::kAboutBlankURL), omnibox_view->GetText());
190  chrome::CloseTab(browser());
191  EXPECT_EQ(base::UTF8ToUTF16(url::kAboutBlankURL), omnibox_view->GetText());
192  EXPECT_TRUE(omnibox_view->IsSelectAll());
193}
194
195IN_PROC_BROWSER_TEST_F(AutocompleteBrowserTest, FocusSearch) {
196#if defined(OS_WIN) && defined(USE_ASH)
197  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
198  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
199    return;
200#endif
201
202  WaitForTemplateURLServiceToLoad();
203  LocationBar* location_bar = GetLocationBar();
204  OmniboxView* omnibox_view = location_bar->GetOmniboxView();
205
206  // Focus search when omnibox is blank
207  {
208    EXPECT_FALSE(location_bar->GetDestinationURL().is_valid());
209    EXPECT_EQ(base::UTF8ToUTF16(url::kAboutBlankURL), omnibox_view->GetText());
210
211    location_bar->FocusSearch();
212    EXPECT_FALSE(location_bar->GetDestinationURL().is_valid());
213    EXPECT_EQ(base::ASCIIToUTF16("?"), omnibox_view->GetText());
214
215    size_t selection_start, selection_end;
216    omnibox_view->GetSelectionBounds(&selection_start, &selection_end);
217    EXPECT_EQ(1U, selection_start);
218    EXPECT_EQ(1U, selection_end);
219  }
220
221  // Focus search when omnibox is _not_ alread in forced query mode.
222  {
223    omnibox_view->SetUserText(base::ASCIIToUTF16("foo"));
224    EXPECT_FALSE(location_bar->GetDestinationURL().is_valid());
225    EXPECT_EQ(base::ASCIIToUTF16("foo"), omnibox_view->GetText());
226
227    location_bar->FocusSearch();
228    EXPECT_FALSE(location_bar->GetDestinationURL().is_valid());
229    EXPECT_EQ(base::ASCIIToUTF16("?"), omnibox_view->GetText());
230
231    size_t selection_start, selection_end;
232    omnibox_view->GetSelectionBounds(&selection_start, &selection_end);
233    EXPECT_EQ(1U, selection_start);
234    EXPECT_EQ(1U, selection_end);
235  }
236
237  // Focus search when omnibox _is_ already in forced query mode, but no query
238  // has been typed.
239  {
240    omnibox_view->SetUserText(base::ASCIIToUTF16("?"));
241    EXPECT_FALSE(location_bar->GetDestinationURL().is_valid());
242    EXPECT_EQ(base::ASCIIToUTF16("?"), omnibox_view->GetText());
243
244    location_bar->FocusSearch();
245    EXPECT_FALSE(location_bar->GetDestinationURL().is_valid());
246    EXPECT_EQ(base::ASCIIToUTF16("?"), omnibox_view->GetText());
247
248    size_t selection_start, selection_end;
249    omnibox_view->GetSelectionBounds(&selection_start, &selection_end);
250    EXPECT_EQ(1U, selection_start);
251    EXPECT_EQ(1U, selection_end);
252  }
253
254  // Focus search when omnibox _is_ already in forced query mode, and some query
255  // has been typed.
256  {
257    omnibox_view->SetUserText(base::ASCIIToUTF16("?foo"));
258    EXPECT_FALSE(location_bar->GetDestinationURL().is_valid());
259    EXPECT_EQ(base::ASCIIToUTF16("?foo"), omnibox_view->GetText());
260
261    location_bar->FocusSearch();
262    EXPECT_FALSE(location_bar->GetDestinationURL().is_valid());
263    EXPECT_EQ(base::ASCIIToUTF16("?foo"), omnibox_view->GetText());
264
265    size_t selection_start, selection_end;
266    omnibox_view->GetSelectionBounds(&selection_start, &selection_end);
267    EXPECT_EQ(1U, std::min(selection_start, selection_end));
268    EXPECT_EQ(4U, std::max(selection_start, selection_end));
269  }
270
271  // Focus search when omnibox is in forced query mode with leading whitespace.
272  {
273    omnibox_view->SetUserText(base::ASCIIToUTF16("   ?foo"));
274    EXPECT_FALSE(location_bar->GetDestinationURL().is_valid());
275    EXPECT_EQ(base::ASCIIToUTF16("   ?foo"), omnibox_view->GetText());
276
277    location_bar->FocusSearch();
278    EXPECT_FALSE(location_bar->GetDestinationURL().is_valid());
279    EXPECT_EQ(base::ASCIIToUTF16("   ?foo"), omnibox_view->GetText());
280
281    size_t selection_start, selection_end;
282    omnibox_view->GetSelectionBounds(&selection_start, &selection_end);
283    EXPECT_EQ(4U, std::min(selection_start, selection_end));
284    EXPECT_EQ(7U, std::max(selection_start, selection_end));
285  }
286}
287