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/strings/string16.h"
6#include "base/strings/utf_string_conversions.h"
7#include "chrome/browser/autocomplete/autocomplete_controller.h"
8#include "chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.h"
9#include "chrome/browser/extensions/api/omnibox/omnibox_api_testbase.h"
10#include "chrome/browser/profiles/profile.h"
11#include "chrome/browser/search_engines/template_url_service_factory.h"
12#include "chrome/browser/ui/browser.h"
13#include "chrome/browser/ui/location_bar/location_bar.h"
14#include "chrome/browser/ui/omnibox/omnibox_view.h"
15#include "chrome/test/base/ui_test_utils.h"
16#include "components/metrics/proto/omnibox_event.pb.h"
17#include "components/omnibox/autocomplete_input.h"
18#include "components/omnibox/autocomplete_match.h"
19#include "components/omnibox/autocomplete_result.h"
20#include "extensions/test/result_catcher.h"
21#include "ui/base/window_open_disposition.h"
22
23using base::ASCIIToUTF16;
24using extensions::ResultCatcher;
25using metrics::OmniboxEventProto;
26
27// http://crbug.com/167158
28IN_PROC_BROWSER_TEST_F(OmniboxApiTest, DISABLED_Basic) {
29  ASSERT_TRUE(RunExtensionTest("omnibox")) << message_;
30
31  // The results depend on the TemplateURLService being loaded. Make sure it is
32  // loaded so that the autocomplete results are consistent.
33  Profile* profile = browser()->profile();
34  ui_test_utils::WaitForTemplateURLServiceToLoad(
35      TemplateURLServiceFactory::GetForProfile(profile));
36
37  AutocompleteController* autocomplete_controller =
38      GetAutocompleteController(browser());
39
40  // Test that our extension's keyword is suggested to us when we partially type
41  // it.
42  {
43    autocomplete_controller->Start(AutocompleteInput(
44        ASCIIToUTF16("keywor"), base::string16::npos, base::string16(), GURL(),
45        OmniboxEventProto::NTP, true, false, true, true,
46        ChromeAutocompleteSchemeClassifier(profile)));
47    WaitForAutocompleteDone(autocomplete_controller);
48    EXPECT_TRUE(autocomplete_controller->done());
49
50    // Now, peek into the controller to see if it has the results we expect.
51    // First result should be to search for what was typed, second should be to
52    // enter "extension keyword" mode.
53    const AutocompleteResult& result = autocomplete_controller->result();
54    ASSERT_EQ(2U, result.size()) << AutocompleteResultAsString(result);
55    AutocompleteMatch match = result.match_at(0);
56    EXPECT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, match.type);
57    EXPECT_FALSE(match.deletable);
58
59    match = result.match_at(1);
60    EXPECT_EQ(ASCIIToUTF16("keyword"), match.keyword);
61  }
62
63  // Test that our extension can send suggestions back to us.
64  {
65    autocomplete_controller->Start(AutocompleteInput(
66        ASCIIToUTF16("keyword suggestio"), base::string16::npos,
67        base::string16(), GURL(), OmniboxEventProto::NTP, true, false, true,
68        true, ChromeAutocompleteSchemeClassifier(profile)));
69    WaitForAutocompleteDone(autocomplete_controller);
70    EXPECT_TRUE(autocomplete_controller->done());
71
72    // Now, peek into the controller to see if it has the results we expect.
73    // First result should be to invoke the keyword with what we typed, 2-4
74    // should be to invoke with suggestions from the extension, and the last
75    // should be to search for what we typed.
76    const AutocompleteResult& result = autocomplete_controller->result();
77    ASSERT_EQ(5U, result.size()) << AutocompleteResultAsString(result);
78
79    EXPECT_EQ(ASCIIToUTF16("keyword"), result.match_at(0).keyword);
80    EXPECT_EQ(ASCIIToUTF16("keyword suggestio"),
81              result.match_at(0).fill_into_edit);
82    EXPECT_EQ(AutocompleteMatchType::SEARCH_OTHER_ENGINE,
83              result.match_at(0).type);
84    EXPECT_EQ(AutocompleteProvider::TYPE_KEYWORD,
85              result.match_at(0).provider->type());
86    EXPECT_EQ(ASCIIToUTF16("keyword"), result.match_at(1).keyword);
87    EXPECT_EQ(ASCIIToUTF16("keyword suggestion1"),
88              result.match_at(1).fill_into_edit);
89    EXPECT_EQ(AutocompleteProvider::TYPE_KEYWORD,
90              result.match_at(1).provider->type());
91    EXPECT_EQ(ASCIIToUTF16("keyword"), result.match_at(2).keyword);
92    EXPECT_EQ(ASCIIToUTF16("keyword suggestion2"),
93              result.match_at(2).fill_into_edit);
94    EXPECT_EQ(AutocompleteProvider::TYPE_KEYWORD,
95              result.match_at(2).provider->type());
96    EXPECT_EQ(ASCIIToUTF16("keyword"), result.match_at(3).keyword);
97    EXPECT_EQ(ASCIIToUTF16("keyword suggestion3"),
98              result.match_at(3).fill_into_edit);
99    EXPECT_EQ(AutocompleteProvider::TYPE_KEYWORD,
100              result.match_at(3).provider->type());
101
102    base::string16 description =
103        ASCIIToUTF16("Description with style: <match>, [dim], (url till end)");
104    EXPECT_EQ(description, result.match_at(1).contents);
105    ASSERT_EQ(6u, result.match_at(1).contents_class.size());
106
107    EXPECT_EQ(0u,
108              result.match_at(1).contents_class[0].offset);
109    EXPECT_EQ(ACMatchClassification::NONE,
110              result.match_at(1).contents_class[0].style);
111
112    EXPECT_EQ(description.find('<'),
113              result.match_at(1).contents_class[1].offset);
114    EXPECT_EQ(ACMatchClassification::MATCH,
115              result.match_at(1).contents_class[1].style);
116
117    EXPECT_EQ(description.find('>') + 1u,
118              result.match_at(1).contents_class[2].offset);
119    EXPECT_EQ(ACMatchClassification::NONE,
120              result.match_at(1).contents_class[2].style);
121
122    EXPECT_EQ(description.find('['),
123              result.match_at(1).contents_class[3].offset);
124    EXPECT_EQ(ACMatchClassification::DIM,
125              result.match_at(1).contents_class[3].style);
126
127    EXPECT_EQ(description.find(']') + 1u,
128              result.match_at(1).contents_class[4].offset);
129    EXPECT_EQ(ACMatchClassification::NONE,
130              result.match_at(1).contents_class[4].style);
131
132    EXPECT_EQ(description.find('('),
133              result.match_at(1).contents_class[5].offset);
134    EXPECT_EQ(ACMatchClassification::URL,
135              result.match_at(1).contents_class[5].style);
136
137    AutocompleteMatch match = result.match_at(4);
138    EXPECT_EQ(AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, match.type);
139    EXPECT_EQ(AutocompleteProvider::TYPE_SEARCH,
140              result.match_at(4).provider->type());
141    EXPECT_FALSE(match.deletable);
142  }
143
144  // Flaky, see http://crbug.com/167158
145  /*
146  {
147    LocationBar* location_bar = GetLocationBar(browser());
148    ResultCatcher catcher;
149    OmniboxView* omnibox_view = location_bar->GetOmniboxView();
150    omnibox_view->OnBeforePossibleChange();
151    omnibox_view->SetUserText(ASCIIToUTF16("keyword command"));
152    omnibox_view->OnAfterPossibleChange();
153    location_bar->AcceptInput();
154    // This checks that the keyword provider (via javascript)
155    // gets told to navigate to the string "command".
156    EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
157  }
158  */
159}
160
161IN_PROC_BROWSER_TEST_F(OmniboxApiTest, OnInputEntered) {
162  ASSERT_TRUE(RunExtensionTest("omnibox")) << message_;
163  Profile* profile = browser()->profile();
164  ui_test_utils::WaitForTemplateURLServiceToLoad(
165      TemplateURLServiceFactory::GetForProfile(profile));
166
167  LocationBar* location_bar = GetLocationBar(browser());
168  OmniboxView* omnibox_view = location_bar->GetOmniboxView();
169  ResultCatcher catcher;
170  AutocompleteController* autocomplete_controller =
171      GetAutocompleteController(browser());
172  omnibox_view->OnBeforePossibleChange();
173  omnibox_view->SetUserText(ASCIIToUTF16("keyword command"));
174  omnibox_view->OnAfterPossibleChange();
175
176  autocomplete_controller->Start(AutocompleteInput(
177      ASCIIToUTF16("keyword command"), base::string16::npos, base::string16(),
178      GURL(), OmniboxEventProto::NTP, true, false, true, true,
179      ChromeAutocompleteSchemeClassifier(profile)));
180  omnibox_view->model()->AcceptInput(CURRENT_TAB, false);
181  WaitForAutocompleteDone(autocomplete_controller);
182  EXPECT_TRUE(autocomplete_controller->done());
183  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
184
185  omnibox_view->OnBeforePossibleChange();
186  omnibox_view->SetUserText(ASCIIToUTF16("keyword newtab"));
187  omnibox_view->OnAfterPossibleChange();
188  WaitForAutocompleteDone(autocomplete_controller);
189  EXPECT_TRUE(autocomplete_controller->done());
190
191  autocomplete_controller->Start(AutocompleteInput(
192      ASCIIToUTF16("keyword newtab"), base::string16::npos, base::string16(),
193      GURL(), OmniboxEventProto::NTP, true, false, true, true,
194      ChromeAutocompleteSchemeClassifier(profile)));
195  omnibox_view->model()->AcceptInput(NEW_FOREGROUND_TAB, false);
196  WaitForAutocompleteDone(autocomplete_controller);
197  EXPECT_TRUE(autocomplete_controller->done());
198  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
199}
200
201// Tests that we get suggestions from and send input to the incognito context
202// of an incognito split mode extension.
203// http://crbug.com/100927
204// Test is flaky: http://crbug.com/101219
205IN_PROC_BROWSER_TEST_F(OmniboxApiTest, DISABLED_IncognitoSplitMode) {
206  Profile* profile = browser()->profile();
207  ResultCatcher catcher_incognito;
208  catcher_incognito.RestrictToBrowserContext(profile->GetOffTheRecordProfile());
209
210  ASSERT_TRUE(RunExtensionTestIncognito("omnibox")) << message_;
211
212  // Open an incognito window and wait for the incognito extension process to
213  // respond.
214  Browser* incognito_browser = CreateIncognitoBrowser();
215  ASSERT_TRUE(catcher_incognito.GetNextResult()) << catcher_incognito.message();
216
217  // The results depend on the TemplateURLService being loaded. Make sure it is
218  // loaded so that the autocomplete results are consistent.
219  ui_test_utils::WaitForTemplateURLServiceToLoad(
220      TemplateURLServiceFactory::GetForProfile(browser()->profile()));
221
222  LocationBar* location_bar = GetLocationBar(incognito_browser);
223  AutocompleteController* autocomplete_controller =
224      GetAutocompleteController(incognito_browser);
225
226  // Test that we get the incognito-specific suggestions.
227  {
228    autocomplete_controller->Start(AutocompleteInput(
229        ASCIIToUTF16("keyword suggestio"), base::string16::npos,
230        base::string16(), GURL(), OmniboxEventProto::NTP, true, false, true,
231        true, ChromeAutocompleteSchemeClassifier(profile)));
232    WaitForAutocompleteDone(autocomplete_controller);
233    EXPECT_TRUE(autocomplete_controller->done());
234
235    // First result should be to invoke the keyword with what we typed, 2-4
236    // should be to invoke with suggestions from the extension, and the last
237    // should be to search for what we typed.
238    const AutocompleteResult& result = autocomplete_controller->result();
239    ASSERT_EQ(5U, result.size()) << AutocompleteResultAsString(result);
240    ASSERT_FALSE(result.match_at(0).keyword.empty());
241    EXPECT_EQ(ASCIIToUTF16("keyword suggestion3 incognito"),
242              result.match_at(3).fill_into_edit);
243  }
244
245  // Test that our input is sent to the incognito context. The test will do a
246  // text comparison and succeed only if "command incognito" is sent to the
247  // incognito context.
248  {
249    ResultCatcher catcher;
250    autocomplete_controller->Start(AutocompleteInput(
251        ASCIIToUTF16("keyword command incognito"), base::string16::npos,
252        base::string16(), GURL(), OmniboxEventProto::NTP, true, false, true,
253        true, ChromeAutocompleteSchemeClassifier(profile)));
254    location_bar->AcceptInput();
255    EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
256  }
257}
258