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