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