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 178 ToolbarModelTest::ToolbarModelTest() { 179 } 180 181 ToolbarModelTest::~ToolbarModelTest() { 182 } 183 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 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 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. 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. 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. 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. 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