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
34 namespace {
35
36 struct 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
157 class 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
ToolbarModelTest()178 ToolbarModelTest::ToolbarModelTest() {
179 }
180
~ToolbarModelTest()181 ToolbarModelTest::~ToolbarModelTest() {
182 }
183
SetUp()184 void 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
EnableOriginChipFieldTrial()193 void 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
NavigateAndCheckText(const GURL & url,const base::string16 & expected_text,bool would_perform_search_term_replacement,bool should_display_url)200 void 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.
TEST_F(ToolbarModelTest,ShouldDisplayURL_QueryExtraction)245 TEST_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.
TEST_F(ToolbarModelTest,ShouldDisplayURL_OriginChip)281 TEST_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.
TEST_F(ToolbarModelTest,SearchTermsWhileLoading)316 TEST_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.
TEST_F(ToolbarModelTest,GoogleBaseURL)342 TEST_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