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 "chrome/browser/ui/toolbar/toolbar_model.h"
6
7#include <vector>
8
9#include "base/command_line.h"
10#include "base/metrics/field_trial.h"
11#include "base/strings/utf_string_conversions.h"
12#include "chrome/browser/autocomplete/autocomplete_classifier_factory.h"
13#include "chrome/browser/search/search.h"
14#include "chrome/browser/search_engines/search_terms_data.h"
15#include "chrome/browser/search_engines/template_url.h"
16#include "chrome/browser/search_engines/template_url_service.h"
17#include "chrome/browser/search_engines/template_url_service_factory.h"
18#include "chrome/browser/ui/browser.h"
19#include "chrome/browser/ui/tabs/tab_strip_model.h"
20#include "chrome/browser/ui/toolbar/toolbar_model.h"
21#include "chrome/common/chrome_switches.h"
22#include "chrome/test/base/browser_with_test_window_test.h"
23#include "components/variations/entropy_provider.h"
24#include "content/public/browser/navigation_entry.h"
25#include "content/public/browser/render_process_host.h"
26#include "content/public/browser/web_contents.h"
27#include "content/public/common/ssl_status.h"
28#include "content/public/common/url_constants.h"
29#include "net/base/escape.h"
30
31
32// Test data ------------------------------------------------------------------
33
34namespace {
35
36struct TestItem {
37  GURL url;
38  // The expected text to display when both forms of URL replacement are
39  // inactive.
40  base::string16 expected_text_url_replacement_inactive;
41  // The expected text to display when query extraction is active.
42  base::string16 expected_text_query_extraction;
43  // The expected text to display when the origin chip (URL removal) is active.
44  base::string16 expected_text_origin_chip;
45  // The expected text to display when both query extraction and URL removal are
46  // active.
47  base::string16 expected_text_both;
48  bool would_perform_search_term_replacement;
49  bool should_display_url;
50} test_items[] = {
51  {
52    GURL("view-source:http://www.google.com"),
53    ASCIIToUTF16("view-source:www.google.com"),
54    ASCIIToUTF16("view-source:www.google.com"),
55    base::string16(),
56    base::string16(),
57    false,
58    true
59  },
60  {
61    GURL("view-source:chrome://newtab/"),
62    ASCIIToUTF16("view-source:chrome://newtab"),
63    ASCIIToUTF16("view-source:chrome://newtab"),
64    base::string16(),
65    base::string16(),
66    false,
67    true
68  },
69  {
70    GURL("chrome-extension://monkey/balls.html"),
71    ASCIIToUTF16("chrome-extension://monkey/balls.html"),
72    ASCIIToUTF16("chrome-extension://monkey/balls.html"),
73    base::string16(),
74    base::string16(),
75    false,
76    true
77  },
78  {
79    GURL(content::kAboutBlankURL),
80    ASCIIToUTF16(content::kAboutBlankURL),
81    ASCIIToUTF16(content::kAboutBlankURL),
82    base::string16(),
83    base::string16(),
84    false,
85    true
86  },
87  {
88    GURL("http://searchurl/?q=tractor+supply"),
89    ASCIIToUTF16("searchurl/?q=tractor+supply"),
90    ASCIIToUTF16("searchurl/?q=tractor+supply"),
91    base::string16(),
92    base::string16(),
93    false,
94    true
95  },
96  {
97    GURL("http://google.com/search?q=tractor+supply&espv=1"),
98    ASCIIToUTF16("google.com/search?q=tractor+supply&espv=1"),
99    ASCIIToUTF16("google.com/search?q=tractor+supply&espv=1"),
100    base::string16(),
101    base::string16(),
102    false,
103    true
104  },
105  {
106    GURL("https://google.ca/search?q=tractor+supply"),
107    ASCIIToUTF16("https://google.ca/search?q=tractor+supply"),
108    ASCIIToUTF16("https://google.ca/search?q=tractor+supply"),
109    base::string16(),
110    base::string16(),
111    false,
112    true
113  },
114  {
115    GURL("https://google.com/search?q=tractor+supply"),
116    ASCIIToUTF16("https://google.com/search?q=tractor+supply"),
117    ASCIIToUTF16("https://google.com/search?q=tractor+supply"),
118    base::string16(),
119    base::string16(),
120    false,
121    true
122  },
123  {
124    GURL("https://google.com/search?q=tractor+supply&espv=1"),
125    ASCIIToUTF16("https://google.com/search?q=tractor+supply&espv=1"),
126    ASCIIToUTF16("tractor supply"),
127    base::string16(),
128    ASCIIToUTF16("tractor supply"),
129    true,
130    true
131  },
132  {
133    GURL("https://google.com/search?q=tractorsupply.com&espv=1"),
134    ASCIIToUTF16("https://google.com/search?q=tractorsupply.com&espv=1"),
135    ASCIIToUTF16("tractorsupply.com"),
136    base::string16(),
137    ASCIIToUTF16("tractorsupply.com"),
138    true,
139    true
140  },
141  {
142    GURL("https://google.com/search?q=ftp://tractorsupply.ie&espv=1"),
143    ASCIIToUTF16("https://google.com/search?q=ftp://tractorsupply.ie&espv=1"),
144    ASCIIToUTF16("ftp://tractorsupply.ie"),
145    base::string16(),
146    ASCIIToUTF16("ftp://tractorsupply.ie"),
147    true,
148    true
149  },
150};
151
152}  // namespace
153
154
155// ToolbarModelTest -----------------------------------------------------------
156
157class ToolbarModelTest : public BrowserWithTestWindowTest {
158 public:
159  ToolbarModelTest();
160  virtual ~ToolbarModelTest();
161
162  // BrowserWithTestWindowTest:
163  virtual void SetUp() OVERRIDE;
164
165 protected:
166  void NavigateAndCheckText(const GURL& url,
167                            const base::string16& expected_text,
168                            bool would_perform_search_term_replacement,
169                            bool should_display_url);
170  void EnableOriginChipFieldTrial();
171
172 private:
173  scoped_ptr<base::FieldTrialList> field_trial_list_;
174
175  DISALLOW_COPY_AND_ASSIGN(ToolbarModelTest);
176};
177
178ToolbarModelTest::ToolbarModelTest() {
179}
180
181ToolbarModelTest::~ToolbarModelTest() {
182}
183
184void ToolbarModelTest::SetUp() {
185  BrowserWithTestWindowTest::SetUp();
186  TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse(
187      profile(), &TemplateURLServiceFactory::BuildInstanceFor);
188  AutocompleteClassifierFactory::GetInstance()->SetTestingFactoryAndUse(
189      profile(), &AutocompleteClassifierFactory::BuildInstanceFor);
190  UIThreadSearchTermsData::SetGoogleBaseURL("http://google.com/");
191}
192
193void ToolbarModelTest::EnableOriginChipFieldTrial() {
194  field_trial_list_.reset(new base::FieldTrialList(
195      new metrics::SHA1EntropyProvider("platypus")));
196  base::FieldTrialList::CreateFieldTrial(
197            "EmbeddedSearch", "Group1 espv:2 origin_chip:1");
198}
199
200void ToolbarModelTest::NavigateAndCheckText(
201    const GURL& url,
202    const base::string16& expected_text,
203    bool would_perform_search_term_replacement,
204    bool should_display_url) {
205  // Check while loading.
206  content::NavigationController* controller =
207      &browser()->tab_strip_model()->GetWebContentsAt(0)->GetController();
208  controller->LoadURL(url, content::Referrer(), content::PAGE_TRANSITION_LINK,
209                      std::string());
210  ToolbarModel* toolbar_model = browser()->toolbar_model();
211  EXPECT_EQ(expected_text, toolbar_model->GetText());
212  EXPECT_EQ(would_perform_search_term_replacement,
213            toolbar_model->WouldPerformSearchTermReplacement(false));
214  EXPECT_EQ(should_display_url, toolbar_model->ShouldDisplayURL());
215
216  // Check after commit.
217  CommitPendingLoad(controller);
218  // Fake a secure connection for HTTPS URLs, or the toolbar will refuse to
219  // extract search terms.
220  if (url.SchemeIsSecure()) {
221    controller->GetVisibleEntry()->GetSSL().security_style =
222        content::SECURITY_STYLE_AUTHENTICATED;
223  }
224  EXPECT_EQ(expected_text, toolbar_model->GetText());
225  EXPECT_EQ(would_perform_search_term_replacement,
226            toolbar_model->WouldPerformSearchTermReplacement(false));
227  EXPECT_EQ(should_display_url, toolbar_model->ShouldDisplayURL());
228
229  // Now pretend the user started modifying the omnibox.
230  toolbar_model->set_input_in_progress(true);
231  EXPECT_FALSE(toolbar_model->WouldPerformSearchTermReplacement(false));
232  EXPECT_EQ(would_perform_search_term_replacement,
233            toolbar_model->WouldPerformSearchTermReplacement(true));
234
235  // Tell the ToolbarModel that the user has stopped editing.  This prevents
236  // this function from having side effects.
237  toolbar_model->set_input_in_progress(false);
238}
239
240
241// Actual tests ---------------------------------------------------------------
242
243// Test that we only replace URLs when query extraction and URL replacement
244// are enabled.
245TEST_F(ToolbarModelTest, ShouldDisplayURL_QueryExtraction) {
246  AddTab(browser(), GURL(content::kAboutBlankURL));
247
248  // Before we enable instant extended, query extraction is disabled.
249  EXPECT_FALSE(chrome::IsQueryExtractionEnabled())
250      << "This test expects query extraction to be disabled.";
251  for (size_t i = 0; i < arraysize(test_items); ++i) {
252    const TestItem& test_item = test_items[i];
253    NavigateAndCheckText(test_item.url,
254                         test_item.expected_text_url_replacement_inactive,
255                         false, test_item.should_display_url);
256  }
257
258  chrome::EnableQueryExtractionForTesting();
259  EXPECT_TRUE(chrome::IsQueryExtractionEnabled());
260  EXPECT_TRUE(browser()->toolbar_model()->url_replacement_enabled());
261  for (size_t i = 0; i < arraysize(test_items); ++i) {
262    const TestItem& test_item = test_items[i];
263    NavigateAndCheckText(test_item.url,
264                         test_item.expected_text_query_extraction,
265                         test_item.would_perform_search_term_replacement,
266                         test_item.should_display_url);
267  }
268
269  // Disabling URL replacement should reset to only showing URLs.
270  browser()->toolbar_model()->set_url_replacement_enabled(false);
271  for (size_t i = 0; i < arraysize(test_items); ++i) {
272    const TestItem& test_item = test_items[i];
273    NavigateAndCheckText(test_item.url,
274                         test_item.expected_text_url_replacement_inactive,
275                         false, test_item.should_display_url);
276  }
277}
278
279// Test that we remove or replace URLs appropriately when the origin chip is
280// enabled.
281TEST_F(ToolbarModelTest, ShouldDisplayURL_OriginChip) {
282  EnableOriginChipFieldTrial();
283  AddTab(browser(), GURL(content::kAboutBlankURL));
284
285  // Check each case with the origin chip enabled but query extraction disabled.
286  EXPECT_TRUE(chrome::ShouldDisplayOriginChip());
287  EXPECT_FALSE(chrome::IsQueryExtractionEnabled());
288  for (size_t i = 0; i < arraysize(test_items); ++i) {
289    const TestItem& test_item = test_items[i];
290    NavigateAndCheckText(test_item.url, test_item.expected_text_origin_chip,
291                         false, test_item.should_display_url);
292  }
293
294  // Check with both enabled.
295  chrome::EnableQueryExtractionForTesting();
296  EXPECT_TRUE(chrome::IsQueryExtractionEnabled());
297  EXPECT_TRUE(browser()->toolbar_model()->url_replacement_enabled());
298  for (size_t i = 0; i < arraysize(test_items); ++i) {
299    const TestItem& test_item = test_items[i];
300    NavigateAndCheckText(test_item.url, test_item.expected_text_both,
301                         test_item.would_perform_search_term_replacement,
302                         test_item.should_display_url);
303  }
304
305  // Disabling URL replacement should reset to only showing URLs.
306  browser()->toolbar_model()->set_url_replacement_enabled(false);
307  for (size_t i = 0; i < arraysize(test_items); ++i) {
308    const TestItem& test_item = test_items[i];
309    NavigateAndCheckText(test_item.url,
310                         test_item.expected_text_url_replacement_inactive,
311                         false, test_item.should_display_url);
312  }
313}
314
315// Verify that search terms are extracted while the page is loading.
316TEST_F(ToolbarModelTest, SearchTermsWhileLoading) {
317  chrome::EnableQueryExtractionForTesting();
318  AddTab(browser(), GURL(content::kAboutBlankURL));
319
320  // While loading, we should be willing to extract search terms.
321  content::NavigationController* controller =
322      &browser()->tab_strip_model()->GetWebContentsAt(0)->GetController();
323  controller->LoadURL(GURL("https://google.com/search?q=tractor+supply&espv=1"),
324                      content::Referrer(), content::PAGE_TRANSITION_LINK,
325                      std::string());
326  ToolbarModel* toolbar_model = browser()->toolbar_model();
327  controller->GetVisibleEntry()->GetSSL().security_style =
328      content::SECURITY_STYLE_UNKNOWN;
329  EXPECT_TRUE(toolbar_model->WouldPerformSearchTermReplacement(false));
330
331  // When done loading, we shouldn't extract search terms if we didn't get an
332  // authenticated connection.
333  CommitPendingLoad(controller);
334  controller->GetVisibleEntry()->GetSSL().security_style =
335      content::SECURITY_STYLE_UNKNOWN;
336  EXPECT_FALSE(toolbar_model->WouldPerformSearchTermReplacement(false));
337}
338
339// When the Google base URL is overridden on the command line, we should extract
340// search terms from URLs that start with that base URL even when they're not
341// secure.
342TEST_F(ToolbarModelTest, GoogleBaseURL) {
343  chrome::EnableQueryExtractionForTesting();
344  AddTab(browser(), GURL(content::kAboutBlankURL));
345
346  // If the Google base URL wasn't specified on the command line, then if it's
347  // HTTP, we should not extract search terms.
348  UIThreadSearchTermsData::SetGoogleBaseURL("http://www.foo.com/");
349  NavigateAndCheckText(
350      GURL("http://www.foo.com/search?q=tractor+supply&espv=1"),
351      ASCIIToUTF16("www.foo.com/search?q=tractor+supply&espv=1"), false, true);
352
353  // The same URL, when specified on the command line, should allow search term
354  // extraction.
355  UIThreadSearchTermsData::SetGoogleBaseURL(std::string());
356  CommandLine::ForCurrentProcess()->AppendSwitchASCII(switches::kGoogleBaseURL,
357                                                      "http://www.foo.com/");
358  NavigateAndCheckText(
359      GURL("http://www.foo.com/search?q=tractor+supply&espv=1"),
360      ASCIIToUTF16("tractor supply"), true, true);
361}
362