1 // Copyright (c) 2013 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/profile_resetter/profile_resetter.h" 6 7 #include "base/json/json_string_value_serializer.h" 8 #include "base/prefs/pref_service.h" 9 #include "base/strings/utf_string_conversions.h" 10 #include "base/test/scoped_path_override.h" 11 #include "chrome/browser/content_settings/host_content_settings_map.h" 12 #include "chrome/browser/extensions/extension_service.h" 13 #include "chrome/browser/extensions/extension_service_test_base.h" 14 #include "chrome/browser/extensions/tab_helper.h" 15 #include "chrome/browser/notifications/desktop_notification_service.h" 16 #include "chrome/browser/notifications/desktop_notification_service_factory.h" 17 #include "chrome/browser/prefs/session_startup_pref.h" 18 #include "chrome/browser/profile_resetter/brandcode_config_fetcher.h" 19 #include "chrome/browser/profile_resetter/profile_resetter_test_base.h" 20 #include "chrome/browser/profile_resetter/resettable_settings_snapshot.h" 21 #include "chrome/browser/search_engines/template_url_service.h" 22 #include "chrome/browser/search_engines/template_url_service_factory.h" 23 #include "chrome/browser/themes/theme_service.h" 24 #include "chrome/browser/themes/theme_service_factory.h" 25 #include "chrome/browser/ui/tabs/tab_strip_model.h" 26 #include "chrome/common/pref_names.h" 27 #include "chrome/test/base/browser_with_test_window_test.h" 28 #include "components/google/core/browser/google_pref_names.h" 29 #include "content/public/browser/web_contents.h" 30 #include "content/public/test/test_browser_thread.h" 31 #include "extensions/common/extension.h" 32 #include "extensions/common/manifest_constants.h" 33 #include "net/http/http_response_headers.h" 34 #include "net/http/http_status_code.h" 35 #include "net/url_request/test_url_fetcher_factory.h" 36 #include "net/url_request/url_request_status.h" 37 #include "url/gurl.h" 38 39 #if defined(OS_WIN) 40 #include "base/file_util.h" 41 #include "base/path_service.h" 42 #include "base/process/process_handle.h" 43 #include "base/rand_util.h" 44 #include "base/strings/string_number_conversions.h" 45 #include "base/win/scoped_com_initializer.h" 46 #include "base/win/shortcut.h" 47 #endif 48 49 50 namespace { 51 52 const char kDistributionConfig[] = "{" 53 " \"homepage\" : \"http://www.foo.com\"," 54 " \"homepage_is_newtabpage\" : false," 55 " \"browser\" : {" 56 " \"show_home_button\" : true" 57 " }," 58 " \"session\" : {" 59 " \"restore_on_startup\" : 4," 60 " \"startup_urls\" : [\"http://goo.gl\", \"http://foo.de\"]" 61 " }," 62 " \"search_provider_overrides\" : [" 63 " {" 64 " \"name\" : \"first\"," 65 " \"keyword\" : \"firstkey\"," 66 " \"search_url\" : \"http://www.foo.com/s?q={searchTerms}\"," 67 " \"favicon_url\" : \"http://www.foo.com/favicon.ico\"," 68 " \"suggest_url\" : \"http://www.foo.com/s?q={searchTerms}\"," 69 " \"encoding\" : \"UTF-8\"," 70 " \"id\" : 1001" 71 " }" 72 " ]," 73 " \"extensions\" : {" 74 " \"settings\" : {" 75 " \"placeholder_for_id\": {" 76 " }" 77 " }" 78 " }" 79 "}"; 80 81 const char kXmlConfig[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" 82 "<response protocol=\"3.0\" server=\"prod\">" 83 "<app appid=\"{8A69D345-D564-463C-AFF1-A69D9E530F96}\" status=\"ok\">" 84 "<data index=\"skipfirstrunui-importsearch-defaultbrowser\" " 85 "name=\"install\" status=\"ok\">" 86 "placeholder_for_data" 87 "</data>" 88 "</app>" 89 "</response>"; 90 91 using extensions::Extension; 92 using extensions::Manifest; 93 94 95 // ProfileResetterTest -------------------------------------------------------- 96 97 // ProfileResetterTest sets up the extension, WebData and TemplateURL services. 98 class ProfileResetterTest : public extensions::ExtensionServiceTestBase, 99 public ProfileResetterTestBase { 100 public: 101 ProfileResetterTest(); 102 virtual ~ProfileResetterTest(); 103 104 protected: 105 virtual void SetUp() OVERRIDE; 106 107 TestingProfile* profile() { return profile_.get(); } 108 109 static KeyedService* CreateTemplateURLService( 110 content::BrowserContext* context); 111 112 private: 113 #if defined(OS_WIN) 114 base::ScopedPathOverride user_desktop_override_; 115 base::ScopedPathOverride app_dir_override_; 116 base::ScopedPathOverride start_menu_override_; 117 base::ScopedPathOverride taskbar_pins_override_; 118 base::win::ScopedCOMInitializer com_init_; 119 #endif 120 }; 121 122 ProfileResetterTest::ProfileResetterTest() 123 #if defined(OS_WIN) 124 : user_desktop_override_(base::DIR_USER_DESKTOP), 125 app_dir_override_(base::DIR_APP_DATA), 126 start_menu_override_(base::DIR_START_MENU), 127 taskbar_pins_override_(base::DIR_TASKBAR_PINS) 128 #endif 129 {} 130 131 ProfileResetterTest::~ProfileResetterTest() { 132 } 133 134 void ProfileResetterTest::SetUp() { 135 extensions::ExtensionServiceTestBase::SetUp(); 136 InitializeEmptyExtensionService(); 137 138 profile()->CreateWebDataService(); 139 TemplateURLServiceFactory::GetInstance()->SetTestingFactory( 140 profile(), 141 &ProfileResetterTest::CreateTemplateURLService); 142 resetter_.reset(new ProfileResetter(profile())); 143 } 144 145 // static 146 KeyedService* ProfileResetterTest::CreateTemplateURLService( 147 content::BrowserContext* context) { 148 return new TemplateURLService(static_cast<Profile*>(context)); 149 } 150 151 152 // PinnedTabsResetTest -------------------------------------------------------- 153 154 class PinnedTabsResetTest : public BrowserWithTestWindowTest, 155 public ProfileResetterTestBase { 156 protected: 157 virtual void SetUp() OVERRIDE; 158 159 content::WebContents* CreateWebContents(); 160 }; 161 162 void PinnedTabsResetTest::SetUp() { 163 BrowserWithTestWindowTest::SetUp(); 164 resetter_.reset(new ProfileResetter(profile())); 165 } 166 167 content::WebContents* PinnedTabsResetTest::CreateWebContents() { 168 return content::WebContents::Create( 169 content::WebContents::CreateParams(profile())); 170 } 171 172 173 // ConfigParserTest ----------------------------------------------------------- 174 175 // URLFetcher delegate that simply records the upload data. 176 struct URLFetcherRequestListener : net::URLFetcherDelegate { 177 URLFetcherRequestListener(); 178 virtual ~URLFetcherRequestListener(); 179 180 virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE; 181 182 std::string upload_data; 183 net::URLFetcherDelegate* real_delegate; 184 }; 185 186 URLFetcherRequestListener::URLFetcherRequestListener() 187 : real_delegate(NULL) { 188 } 189 190 URLFetcherRequestListener::~URLFetcherRequestListener() { 191 } 192 193 void URLFetcherRequestListener::OnURLFetchComplete( 194 const net::URLFetcher* source) { 195 const net::TestURLFetcher* test_fetcher = 196 static_cast<const net::TestURLFetcher*>(source); 197 upload_data = test_fetcher->upload_data(); 198 DCHECK(real_delegate); 199 real_delegate->OnURLFetchComplete(source); 200 } 201 202 class ConfigParserTest : public testing::Test { 203 protected: 204 ConfigParserTest(); 205 virtual ~ConfigParserTest(); 206 207 scoped_ptr<BrandcodeConfigFetcher> WaitForRequest(const GURL& url); 208 209 net::FakeURLFetcherFactory& factory() { return factory_; } 210 211 private: 212 scoped_ptr<net::FakeURLFetcher> CreateFakeURLFetcher( 213 const GURL& url, 214 net::URLFetcherDelegate* fetcher_delegate, 215 const std::string& response_data, 216 net::HttpStatusCode response_code, 217 net::URLRequestStatus::Status status); 218 219 MOCK_METHOD0(Callback, void(void)); 220 221 base::MessageLoopForIO loop_; 222 content::TestBrowserThread ui_thread_; 223 content::TestBrowserThread io_thread_; 224 URLFetcherRequestListener request_listener_; 225 net::FakeURLFetcherFactory factory_; 226 }; 227 228 ConfigParserTest::ConfigParserTest() 229 : ui_thread_(content::BrowserThread::UI, &loop_), 230 io_thread_(content::BrowserThread::IO, &loop_), 231 factory_(NULL, base::Bind(&ConfigParserTest::CreateFakeURLFetcher, 232 base::Unretained(this))) { 233 } 234 235 ConfigParserTest::~ConfigParserTest() {} 236 237 scoped_ptr<BrandcodeConfigFetcher> ConfigParserTest::WaitForRequest( 238 const GURL& url) { 239 EXPECT_CALL(*this, Callback()); 240 scoped_ptr<BrandcodeConfigFetcher> fetcher( 241 new BrandcodeConfigFetcher(base::Bind(&ConfigParserTest::Callback, 242 base::Unretained(this)), 243 url, 244 "ABCD")); 245 base::MessageLoop::current()->RunUntilIdle(); 246 EXPECT_FALSE(fetcher->IsActive()); 247 // Look for the brand code in the request. 248 EXPECT_NE(std::string::npos, request_listener_.upload_data.find("ABCD")); 249 return fetcher.Pass(); 250 } 251 252 scoped_ptr<net::FakeURLFetcher> ConfigParserTest::CreateFakeURLFetcher( 253 const GURL& url, 254 net::URLFetcherDelegate* fetcher_delegate, 255 const std::string& response_data, 256 net::HttpStatusCode response_code, 257 net::URLRequestStatus::Status status) { 258 request_listener_.real_delegate = fetcher_delegate; 259 scoped_ptr<net::FakeURLFetcher> fetcher( 260 new net::FakeURLFetcher( 261 url, &request_listener_, response_data, response_code, status)); 262 scoped_refptr<net::HttpResponseHeaders> download_headers = 263 new net::HttpResponseHeaders(""); 264 download_headers->AddHeader("Content-Type: text/xml"); 265 fetcher->set_response_headers(download_headers); 266 return fetcher.Pass(); 267 } 268 269 // A helper class to create/delete/check a Chrome desktop shortcut on Windows. 270 class ShortcutHandler { 271 public: 272 ShortcutHandler(); 273 ~ShortcutHandler(); 274 275 static bool IsSupported(); 276 ShortcutCommand CreateWithArguments(const base::string16& name, 277 const base::string16& args); 278 void CheckShortcutHasArguments(const base::string16& desired_args) const; 279 void Delete(); 280 281 private: 282 #if defined(OS_WIN) 283 base::FilePath shortcut_path_; 284 #endif 285 DISALLOW_COPY_AND_ASSIGN(ShortcutHandler); 286 }; 287 288 #if defined(OS_WIN) 289 ShortcutHandler::ShortcutHandler() { 290 } 291 292 ShortcutHandler::~ShortcutHandler() { 293 if (!shortcut_path_.empty()) 294 Delete(); 295 } 296 297 // static 298 bool ShortcutHandler::IsSupported() { 299 return true; 300 } 301 302 ShortcutCommand ShortcutHandler::CreateWithArguments( 303 const base::string16& name, 304 const base::string16& args) { 305 EXPECT_TRUE(shortcut_path_.empty()); 306 base::FilePath path_to_create; 307 EXPECT_TRUE(PathService::Get(base::DIR_USER_DESKTOP, &path_to_create)); 308 path_to_create = path_to_create.Append(name); 309 EXPECT_FALSE(base::PathExists(path_to_create)) << path_to_create.value(); 310 311 base::FilePath path_exe; 312 EXPECT_TRUE(PathService::Get(base::FILE_EXE, &path_exe)); 313 base::win::ShortcutProperties shortcut_properties; 314 shortcut_properties.set_target(path_exe); 315 shortcut_properties.set_arguments(args); 316 EXPECT_TRUE(base::win::CreateOrUpdateShortcutLink( 317 path_to_create, shortcut_properties, 318 base::win::SHORTCUT_CREATE_ALWAYS)) << path_to_create.value(); 319 shortcut_path_ = path_to_create; 320 return ShortcutCommand(shortcut_path_, args); 321 } 322 323 void ShortcutHandler::CheckShortcutHasArguments( 324 const base::string16& desired_args) const { 325 EXPECT_FALSE(shortcut_path_.empty()); 326 base::string16 args; 327 EXPECT_TRUE(base::win::ResolveShortcut(shortcut_path_, NULL, &args)); 328 EXPECT_EQ(desired_args, args); 329 } 330 331 void ShortcutHandler::Delete() { 332 EXPECT_FALSE(shortcut_path_.empty()); 333 EXPECT_TRUE(base::DeleteFile(shortcut_path_, false)); 334 shortcut_path_.clear(); 335 } 336 #else 337 ShortcutHandler::ShortcutHandler() {} 338 339 ShortcutHandler::~ShortcutHandler() {} 340 341 // static 342 bool ShortcutHandler::IsSupported() { 343 return false; 344 } 345 346 ShortcutCommand ShortcutHandler::CreateWithArguments( 347 const base::string16& name, 348 const base::string16& args) { 349 return ShortcutCommand(); 350 } 351 352 void ShortcutHandler::CheckShortcutHasArguments( 353 const base::string16& desired_args) const { 354 } 355 356 void ShortcutHandler::Delete() { 357 } 358 #endif // defined(OS_WIN) 359 360 361 // helper functions ----------------------------------------------------------- 362 363 scoped_refptr<Extension> CreateExtension(const base::string16& name, 364 const base::FilePath& path, 365 Manifest::Location location, 366 extensions::Manifest::Type type, 367 bool installed_by_default) { 368 base::DictionaryValue manifest; 369 manifest.SetString(extensions::manifest_keys::kVersion, "1.0.0.0"); 370 manifest.SetString(extensions::manifest_keys::kName, name); 371 switch (type) { 372 case extensions::Manifest::TYPE_THEME: 373 manifest.Set(extensions::manifest_keys::kTheme, 374 new base::DictionaryValue); 375 break; 376 case extensions::Manifest::TYPE_HOSTED_APP: 377 manifest.SetString(extensions::manifest_keys::kLaunchWebURL, 378 "http://www.google.com"); 379 manifest.SetString(extensions::manifest_keys::kUpdateURL, 380 "http://clients2.google.com/service/update2/crx"); 381 break; 382 case extensions::Manifest::TYPE_EXTENSION: 383 // do nothing 384 break; 385 default: 386 NOTREACHED(); 387 } 388 manifest.SetString(extensions::manifest_keys::kOmniboxKeyword, name); 389 std::string error; 390 scoped_refptr<Extension> extension = Extension::Create( 391 path, 392 location, 393 manifest, 394 installed_by_default ? Extension::WAS_INSTALLED_BY_DEFAULT 395 : Extension::NO_FLAGS, 396 &error); 397 EXPECT_TRUE(extension.get() != NULL) << error; 398 return extension; 399 } 400 401 void ReplaceString(std::string* str, 402 const std::string& placeholder, 403 const std::string& substitution) { 404 ASSERT_NE(static_cast<std::string*>(NULL), str); 405 size_t placeholder_pos = str->find(placeholder); 406 ASSERT_NE(std::string::npos, placeholder_pos); 407 str->replace(placeholder_pos, placeholder.size(), substitution); 408 } 409 410 411 /********************* Tests *********************/ 412 413 TEST_F(ProfileResetterTest, ResetNothing) { 414 // The callback should be called even if there is nothing to reset. 415 ResetAndWait(0); 416 } 417 418 TEST_F(ProfileResetterTest, ResetDefaultSearchEngineNonOrganic) { 419 PrefService* prefs = profile()->GetPrefs(); 420 DCHECK(prefs); 421 prefs->SetString(prefs::kLastPromptedGoogleURL, "http://www.foo.com/"); 422 423 ResetAndWait(ProfileResetter::DEFAULT_SEARCH_ENGINE, kDistributionConfig); 424 425 TemplateURLService* model = 426 TemplateURLServiceFactory::GetForProfile(profile()); 427 TemplateURL* default_engine = model->GetDefaultSearchProvider(); 428 ASSERT_NE(static_cast<TemplateURL*>(NULL), default_engine); 429 EXPECT_EQ(base::ASCIIToUTF16("first"), default_engine->short_name()); 430 EXPECT_EQ(base::ASCIIToUTF16("firstkey"), default_engine->keyword()); 431 EXPECT_EQ("http://www.foo.com/s?q={searchTerms}", default_engine->url()); 432 433 EXPECT_EQ("", prefs->GetString(prefs::kLastPromptedGoogleURL)); 434 } 435 436 TEST_F(ProfileResetterTest, ResetDefaultSearchEnginePartially) { 437 // Search engine's logic is tested by 438 // TemplateURLServiceTest.RepairPrepopulatedSearchEngines. 439 PrefService* prefs = profile()->GetPrefs(); 440 DCHECK(prefs); 441 prefs->SetString(prefs::kLastPromptedGoogleURL, "http://www.foo.com/"); 442 443 // Make sure TemplateURLService has loaded. 444 ResetAndWait(ProfileResetter::DEFAULT_SEARCH_ENGINE); 445 446 TemplateURLService* model = 447 TemplateURLServiceFactory::GetForProfile(profile()); 448 TemplateURLService::TemplateURLVector urls = model->GetTemplateURLs(); 449 450 // The second call should produce no effect. 451 ResetAndWait(ProfileResetter::DEFAULT_SEARCH_ENGINE); 452 453 EXPECT_EQ(urls, model->GetTemplateURLs()); 454 EXPECT_EQ(std::string(), prefs->GetString(prefs::kLastPromptedGoogleURL)); 455 } 456 457 TEST_F(ProfileResetterTest, ResetHomepageNonOrganic) { 458 PrefService* prefs = profile()->GetPrefs(); 459 DCHECK(prefs); 460 prefs->SetBoolean(prefs::kHomePageIsNewTabPage, true); 461 prefs->SetString(prefs::kHomePage, "http://google.com"); 462 prefs->SetBoolean(prefs::kShowHomeButton, false); 463 464 ResetAndWait(ProfileResetter::HOMEPAGE, kDistributionConfig); 465 466 EXPECT_FALSE(prefs->GetBoolean(prefs::kHomePageIsNewTabPage)); 467 EXPECT_EQ("http://www.foo.com", prefs->GetString(prefs::kHomePage)); 468 EXPECT_TRUE(prefs->GetBoolean(prefs::kShowHomeButton)); 469 } 470 471 TEST_F(ProfileResetterTest, ResetHomepagePartially) { 472 PrefService* prefs = profile()->GetPrefs(); 473 DCHECK(prefs); 474 prefs->SetBoolean(prefs::kHomePageIsNewTabPage, false); 475 prefs->SetString(prefs::kHomePage, "http://www.foo.com"); 476 prefs->SetBoolean(prefs::kShowHomeButton, true); 477 478 ResetAndWait(ProfileResetter::HOMEPAGE); 479 480 EXPECT_TRUE(prefs->GetBoolean(prefs::kHomePageIsNewTabPage)); 481 EXPECT_EQ("http://www.foo.com", prefs->GetString(prefs::kHomePage)); 482 EXPECT_FALSE(prefs->GetBoolean(prefs::kShowHomeButton)); 483 } 484 485 TEST_F(ProfileResetterTest, ResetContentSettings) { 486 HostContentSettingsMap* host_content_settings_map = 487 profile()->GetHostContentSettingsMap(); 488 DesktopNotificationService* notification_service = 489 DesktopNotificationServiceFactory::GetForProfile(profile()); 490 ContentSettingsPattern pattern = 491 ContentSettingsPattern::FromString("[*.]example.org"); 492 std::map<ContentSettingsType, ContentSetting> default_settings; 493 494 for (int type = 0; type < CONTENT_SETTINGS_NUM_TYPES; ++type) { 495 if (type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS) { 496 notification_service->SetDefaultContentSetting(CONTENT_SETTING_BLOCK); 497 notification_service->GrantPermission(GURL("http://foo.de")); 498 } else if (type == CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE || 499 type == CONTENT_SETTINGS_TYPE_MIXEDSCRIPT || 500 type == CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS) { 501 // These types are excluded because one can't call 502 // GetDefaultContentSetting() for them. 503 } else { 504 ContentSettingsType content_type = static_cast<ContentSettingsType>(type); 505 ContentSetting default_setting = 506 host_content_settings_map->GetDefaultContentSetting(content_type, 507 NULL); 508 default_settings[content_type] = default_setting; 509 ContentSetting wildcard_setting = 510 default_setting == CONTENT_SETTING_BLOCK ? CONTENT_SETTING_ALLOW 511 : CONTENT_SETTING_BLOCK; 512 ContentSetting site_setting = 513 default_setting == CONTENT_SETTING_ALLOW ? CONTENT_SETTING_ALLOW 514 : CONTENT_SETTING_BLOCK; 515 if (HostContentSettingsMap::IsSettingAllowedForType( 516 profile()->GetPrefs(), 517 wildcard_setting, 518 content_type)) { 519 host_content_settings_map->SetDefaultContentSetting( 520 content_type, 521 wildcard_setting); 522 } 523 if (!HostContentSettingsMap::ContentTypeHasCompoundValue(content_type) && 524 HostContentSettingsMap::IsSettingAllowedForType( 525 profile()->GetPrefs(), 526 site_setting, 527 content_type)) { 528 host_content_settings_map->SetContentSetting( 529 pattern, 530 ContentSettingsPattern::Wildcard(), 531 content_type, 532 std::string(), 533 site_setting); 534 ContentSettingsForOneType host_settings; 535 host_content_settings_map->GetSettingsForOneType( 536 content_type, std::string(), &host_settings); 537 EXPECT_EQ(2U, host_settings.size()); 538 } 539 } 540 } 541 542 ResetAndWait(ProfileResetter::CONTENT_SETTINGS); 543 544 for (int type = 0; type < CONTENT_SETTINGS_NUM_TYPES; ++type) { 545 if (type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS) { 546 EXPECT_EQ(CONTENT_SETTING_ASK, 547 notification_service->GetDefaultContentSetting(NULL)); 548 EXPECT_EQ(CONTENT_SETTING_ASK, 549 notification_service->GetContentSetting(GURL("http://foo.de"))); 550 } else { 551 ContentSettingsType content_type = static_cast<ContentSettingsType>(type); 552 if (HostContentSettingsMap::ContentTypeHasCompoundValue(content_type) || 553 type == CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE || 554 content_type == CONTENT_SETTINGS_TYPE_MIXEDSCRIPT || 555 content_type == CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS) 556 continue; 557 ContentSetting default_setting = 558 host_content_settings_map->GetDefaultContentSetting(content_type, 559 NULL); 560 EXPECT_TRUE(default_settings.count(content_type)); 561 EXPECT_EQ(default_settings[content_type], default_setting); 562 if (!HostContentSettingsMap::ContentTypeHasCompoundValue(content_type)) { 563 ContentSetting site_setting = 564 host_content_settings_map->GetContentSetting( 565 GURL("example.org"), 566 GURL(), 567 content_type, 568 std::string()); 569 EXPECT_EQ(default_setting, site_setting); 570 } 571 572 ContentSettingsForOneType host_settings; 573 host_content_settings_map->GetSettingsForOneType( 574 content_type, std::string(), &host_settings); 575 EXPECT_EQ(1U, host_settings.size()); 576 } 577 } 578 } 579 580 TEST_F(ProfileResetterTest, ResetExtensionsByDisabling) { 581 service_->Init(); 582 583 base::ScopedTempDir temp_dir; 584 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 585 586 scoped_refptr<Extension> theme = 587 CreateExtension(base::ASCIIToUTF16("example1"), 588 temp_dir.path(), 589 Manifest::INVALID_LOCATION, 590 extensions::Manifest::TYPE_THEME, 591 false); 592 service_->FinishInstallationForTest(theme.get()); 593 // Let ThemeService finish creating the theme pack. 594 base::MessageLoop::current()->RunUntilIdle(); 595 596 ThemeService* theme_service = 597 ThemeServiceFactory::GetForProfile(profile()); 598 EXPECT_FALSE(theme_service->UsingDefaultTheme()); 599 600 scoped_refptr<Extension> ext2 = CreateExtension( 601 base::ASCIIToUTF16("example2"), 602 base::FilePath(FILE_PATH_LITERAL("//nonexistent")), 603 Manifest::INVALID_LOCATION, 604 extensions::Manifest::TYPE_EXTENSION, 605 false); 606 service_->AddExtension(ext2.get()); 607 // Component extensions and policy-managed extensions shouldn't be disabled. 608 scoped_refptr<Extension> ext3 = CreateExtension( 609 base::ASCIIToUTF16("example3"), 610 base::FilePath(FILE_PATH_LITERAL("//nonexistent2")), 611 Manifest::COMPONENT, 612 extensions::Manifest::TYPE_EXTENSION, 613 false); 614 service_->AddExtension(ext3.get()); 615 scoped_refptr<Extension> ext4 = 616 CreateExtension(base::ASCIIToUTF16("example4"), 617 base::FilePath(FILE_PATH_LITERAL("//nonexistent3")), 618 Manifest::EXTERNAL_POLICY_DOWNLOAD, 619 extensions::Manifest::TYPE_EXTENSION, 620 false); 621 service_->AddExtension(ext4.get()); 622 scoped_refptr<Extension> ext5 = CreateExtension( 623 base::ASCIIToUTF16("example5"), 624 base::FilePath(FILE_PATH_LITERAL("//nonexistent4")), 625 Manifest::EXTERNAL_COMPONENT, 626 extensions::Manifest::TYPE_EXTENSION, 627 false); 628 service_->AddExtension(ext5.get()); 629 scoped_refptr<Extension> ext6 = CreateExtension( 630 base::ASCIIToUTF16("example6"), 631 base::FilePath(FILE_PATH_LITERAL("//nonexistent5")), 632 Manifest::EXTERNAL_POLICY, 633 extensions::Manifest::TYPE_EXTENSION, 634 false); 635 service_->AddExtension(ext6.get()); 636 EXPECT_EQ(6u, service_->extensions()->size()); 637 638 ResetAndWait(ProfileResetter::EXTENSIONS); 639 EXPECT_EQ(4u, service_->extensions()->size()); 640 EXPECT_FALSE(service_->extensions()->Contains(theme->id())); 641 EXPECT_FALSE(service_->extensions()->Contains(ext2->id())); 642 EXPECT_TRUE(service_->extensions()->Contains(ext3->id())); 643 EXPECT_TRUE(service_->extensions()->Contains(ext4->id())); 644 EXPECT_TRUE(service_->extensions()->Contains(ext5->id())); 645 EXPECT_TRUE(service_->extensions()->Contains(ext6->id())); 646 EXPECT_TRUE(theme_service->UsingDefaultTheme()); 647 } 648 649 TEST_F(ProfileResetterTest, ResetExtensionsByDisablingNonOrganic) { 650 scoped_refptr<Extension> ext2 = CreateExtension( 651 base::ASCIIToUTF16("example2"), 652 base::FilePath(FILE_PATH_LITERAL("//nonexistent")), 653 Manifest::INVALID_LOCATION, 654 extensions::Manifest::TYPE_EXTENSION, 655 false); 656 service_->AddExtension(ext2.get()); 657 // Components and external policy extensions shouldn't be deleted. 658 scoped_refptr<Extension> ext3 = CreateExtension( 659 base::ASCIIToUTF16("example3"), 660 base::FilePath(FILE_PATH_LITERAL("//nonexistent2")), 661 Manifest::INVALID_LOCATION, 662 extensions::Manifest::TYPE_EXTENSION, 663 false); 664 service_->AddExtension(ext3.get()); 665 EXPECT_EQ(2u, service_->extensions()->size()); 666 667 std::string master_prefs(kDistributionConfig); 668 ReplaceString(&master_prefs, "placeholder_for_id", ext3->id()); 669 670 ResetAndWait(ProfileResetter::EXTENSIONS, master_prefs); 671 672 EXPECT_EQ(1u, service_->extensions()->size()); 673 EXPECT_TRUE(service_->extensions()->Contains(ext3->id())); 674 } 675 676 TEST_F(ProfileResetterTest, ResetExtensionsAndDefaultApps) { 677 service_->Init(); 678 679 base::ScopedTempDir temp_dir; 680 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 681 682 scoped_refptr<Extension> ext1 = 683 CreateExtension(base::ASCIIToUTF16("example1"), 684 temp_dir.path(), 685 Manifest::INVALID_LOCATION, 686 extensions::Manifest::TYPE_THEME, 687 false); 688 service_->FinishInstallationForTest(ext1.get()); 689 // Let ThemeService finish creating the theme pack. 690 base::MessageLoop::current()->RunUntilIdle(); 691 692 ThemeService* theme_service = 693 ThemeServiceFactory::GetForProfile(profile()); 694 EXPECT_FALSE(theme_service->UsingDefaultTheme()); 695 696 scoped_refptr<Extension> ext2 = 697 CreateExtension(base::ASCIIToUTF16("example2"), 698 base::FilePath(FILE_PATH_LITERAL("//nonexistent2")), 699 Manifest::INVALID_LOCATION, 700 extensions::Manifest::TYPE_EXTENSION, 701 false); 702 service_->AddExtension(ext2.get()); 703 704 scoped_refptr<Extension> ext3 = 705 CreateExtension(base::ASCIIToUTF16("example2"), 706 base::FilePath(FILE_PATH_LITERAL("//nonexistent3")), 707 Manifest::INVALID_LOCATION, 708 extensions::Manifest::TYPE_HOSTED_APP, 709 true); 710 service_->AddExtension(ext3.get()); 711 EXPECT_EQ(3u, service_->extensions()->size()); 712 713 ResetAndWait(ProfileResetter::EXTENSIONS); 714 715 EXPECT_EQ(1u, service_->extensions()->size()); 716 EXPECT_FALSE(service_->extensions()->Contains(ext1->id())); 717 EXPECT_FALSE(service_->extensions()->Contains(ext2->id())); 718 EXPECT_TRUE(service_->extensions()->Contains(ext3->id())); 719 EXPECT_TRUE(theme_service->UsingDefaultTheme()); 720 } 721 722 TEST_F(ProfileResetterTest, ResetStartPageNonOrganic) { 723 PrefService* prefs = profile()->GetPrefs(); 724 DCHECK(prefs); 725 726 SessionStartupPref startup_pref(SessionStartupPref::LAST); 727 SessionStartupPref::SetStartupPref(prefs, startup_pref); 728 729 ResetAndWait(ProfileResetter::STARTUP_PAGES, kDistributionConfig); 730 731 startup_pref = SessionStartupPref::GetStartupPref(prefs); 732 EXPECT_EQ(SessionStartupPref::URLS, startup_pref.type); 733 const GURL urls[] = {GURL("http://goo.gl"), GURL("http://foo.de")}; 734 EXPECT_EQ(std::vector<GURL>(urls, urls + arraysize(urls)), startup_pref.urls); 735 } 736 737 738 TEST_F(ProfileResetterTest, ResetStartPagePartially) { 739 PrefService* prefs = profile()->GetPrefs(); 740 DCHECK(prefs); 741 742 const GURL urls[] = {GURL("http://foo"), GURL("http://bar")}; 743 SessionStartupPref startup_pref(SessionStartupPref::URLS); 744 startup_pref.urls.assign(urls, urls + arraysize(urls)); 745 SessionStartupPref::SetStartupPref(prefs, startup_pref); 746 747 ResetAndWait(ProfileResetter::STARTUP_PAGES, std::string()); 748 749 startup_pref = SessionStartupPref::GetStartupPref(prefs); 750 EXPECT_EQ(SessionStartupPref::GetDefaultStartupType(), startup_pref.type); 751 EXPECT_EQ(std::vector<GURL>(urls, urls + arraysize(urls)), startup_pref.urls); 752 } 753 754 TEST_F(PinnedTabsResetTest, ResetPinnedTabs) { 755 scoped_refptr<Extension> extension_app = CreateExtension( 756 base::ASCIIToUTF16("hello!"), 757 base::FilePath(FILE_PATH_LITERAL("//nonexistent")), 758 Manifest::INVALID_LOCATION, 759 extensions::Manifest::TYPE_HOSTED_APP, 760 false); 761 scoped_ptr<content::WebContents> contents1(CreateWebContents()); 762 extensions::TabHelper::CreateForWebContents(contents1.get()); 763 extensions::TabHelper::FromWebContents(contents1.get())-> 764 SetExtensionApp(extension_app.get()); 765 scoped_ptr<content::WebContents> contents2(CreateWebContents()); 766 scoped_ptr<content::WebContents> contents3(CreateWebContents()); 767 scoped_ptr<content::WebContents> contents4(CreateWebContents()); 768 TabStripModel* tab_strip_model = browser()->tab_strip_model(); 769 770 tab_strip_model->AppendWebContents(contents4.get(), true); 771 tab_strip_model->AppendWebContents(contents3.get(), true); 772 tab_strip_model->AppendWebContents(contents2.get(), true); 773 tab_strip_model->SetTabPinned(2, true); 774 tab_strip_model->AppendWebContents(contents1.get(), true); 775 tab_strip_model->SetTabPinned(3, true); 776 777 EXPECT_EQ(contents2, tab_strip_model->GetWebContentsAt(0)); 778 EXPECT_EQ(contents1, tab_strip_model->GetWebContentsAt(1)); 779 EXPECT_EQ(contents3, tab_strip_model->GetWebContentsAt(2)); 780 EXPECT_EQ(contents4, tab_strip_model->GetWebContentsAt(3)); 781 EXPECT_EQ(3, tab_strip_model->IndexOfFirstNonMiniTab()); 782 783 ResetAndWait(ProfileResetter::PINNED_TABS); 784 785 EXPECT_EQ(contents1, tab_strip_model->GetWebContentsAt(0)); 786 EXPECT_EQ(contents2, tab_strip_model->GetWebContentsAt(1)); 787 EXPECT_EQ(contents3, tab_strip_model->GetWebContentsAt(2)); 788 EXPECT_EQ(contents4, tab_strip_model->GetWebContentsAt(3)); 789 EXPECT_EQ(1, tab_strip_model->IndexOfFirstNonMiniTab()); 790 } 791 792 TEST_F(ProfileResetterTest, ResetShortcuts) { 793 ShortcutHandler shortcut; 794 ShortcutCommand command_line = shortcut.CreateWithArguments( 795 base::ASCIIToUTF16("chrome.lnk"), 796 base::ASCIIToUTF16("--profile-directory=Default foo.com")); 797 shortcut.CheckShortcutHasArguments(base::ASCIIToUTF16( 798 "--profile-directory=Default foo.com")); 799 800 ResetAndWait(ProfileResetter::SHORTCUTS); 801 802 shortcut.CheckShortcutHasArguments(base::ASCIIToUTF16( 803 "--profile-directory=Default")); 804 } 805 806 TEST_F(ProfileResetterTest, ResetFewFlags) { 807 // mock_object_ is a StrictMock, so we verify that it is called only once. 808 ResetAndWait(ProfileResetter::DEFAULT_SEARCH_ENGINE | 809 ProfileResetter::HOMEPAGE | 810 ProfileResetter::CONTENT_SETTINGS); 811 } 812 813 // Tries to load unavailable config file. 814 TEST_F(ConfigParserTest, NoConnectivity) { 815 const GURL url("http://test"); 816 factory().SetFakeResponse(url, "", net::HTTP_INTERNAL_SERVER_ERROR, 817 net::URLRequestStatus::FAILED); 818 819 scoped_ptr<BrandcodeConfigFetcher> fetcher = WaitForRequest(GURL(url)); 820 EXPECT_FALSE(fetcher->GetSettings()); 821 } 822 823 // Tries to load available config file. 824 TEST_F(ConfigParserTest, ParseConfig) { 825 const GURL url("http://test"); 826 std::string xml_config(kXmlConfig); 827 ReplaceString(&xml_config, "placeholder_for_data", kDistributionConfig); 828 ReplaceString(&xml_config, 829 "placeholder_for_id", 830 "abbaabbaabbaabbaabbaabbaabbaabba"); 831 factory().SetFakeResponse(url, xml_config, net::HTTP_OK, 832 net::URLRequestStatus::SUCCESS); 833 834 scoped_ptr<BrandcodeConfigFetcher> fetcher = WaitForRequest(GURL(url)); 835 scoped_ptr<BrandcodedDefaultSettings> settings = fetcher->GetSettings(); 836 ASSERT_TRUE(settings); 837 838 std::vector<std::string> extension_ids; 839 EXPECT_TRUE(settings->GetExtensions(&extension_ids)); 840 EXPECT_EQ(1u, extension_ids.size()); 841 EXPECT_EQ("abbaabbaabbaabbaabbaabbaabbaabba", extension_ids[0]); 842 843 std::string homepage; 844 EXPECT_TRUE(settings->GetHomepage(&homepage)); 845 EXPECT_EQ("http://www.foo.com", homepage); 846 847 scoped_ptr<base::ListValue> startup_list( 848 settings->GetUrlsToRestoreOnStartup()); 849 EXPECT_TRUE(startup_list); 850 std::vector<std::string> startup_pages; 851 for (base::ListValue::iterator i = startup_list->begin(); 852 i != startup_list->end(); ++i) { 853 std::string url; 854 EXPECT_TRUE((*i)->GetAsString(&url)); 855 startup_pages.push_back(url); 856 } 857 ASSERT_EQ(2u, startup_pages.size()); 858 EXPECT_EQ("http://goo.gl", startup_pages[0]); 859 EXPECT_EQ("http://foo.de", startup_pages[1]); 860 } 861 862 TEST_F(ProfileResetterTest, CheckSnapshots) { 863 ResettableSettingsSnapshot empty_snap(profile()); 864 EXPECT_EQ(0, empty_snap.FindDifferentFields(empty_snap)); 865 866 scoped_refptr<Extension> ext = CreateExtension( 867 base::ASCIIToUTF16("example"), 868 base::FilePath(FILE_PATH_LITERAL("//nonexistent")), 869 Manifest::INVALID_LOCATION, 870 extensions::Manifest::TYPE_EXTENSION, 871 false); 872 ASSERT_TRUE(ext); 873 service_->AddExtension(ext.get()); 874 875 std::string master_prefs(kDistributionConfig); 876 std::string ext_id = ext->id(); 877 ReplaceString(&master_prefs, "placeholder_for_id", ext_id); 878 879 // Reset to non organic defaults. 880 ResetAndWait(ProfileResetter::DEFAULT_SEARCH_ENGINE | 881 ProfileResetter::HOMEPAGE | 882 ProfileResetter::STARTUP_PAGES, 883 master_prefs); 884 ShortcutHandler shortcut_hijacked; 885 ShortcutCommand command_line = shortcut_hijacked.CreateWithArguments( 886 base::ASCIIToUTF16("chrome1.lnk"), 887 base::ASCIIToUTF16("--profile-directory=Default foo.com")); 888 shortcut_hijacked.CheckShortcutHasArguments( 889 base::ASCIIToUTF16("--profile-directory=Default foo.com")); 890 ShortcutHandler shortcut_ok; 891 shortcut_ok.CreateWithArguments( 892 base::ASCIIToUTF16("chrome2.lnk"), 893 base::ASCIIToUTF16("--profile-directory=Default1")); 894 895 ResettableSettingsSnapshot nonorganic_snap(profile()); 896 nonorganic_snap.RequestShortcuts(base::Closure()); 897 // Let it enumerate shortcuts on the FILE thread. 898 base::MessageLoop::current()->RunUntilIdle(); 899 int diff_fields = ResettableSettingsSnapshot::ALL_FIELDS; 900 if (!ShortcutHandler::IsSupported()) 901 diff_fields &= ~ResettableSettingsSnapshot::SHORTCUTS; 902 EXPECT_EQ(diff_fields, 903 empty_snap.FindDifferentFields(nonorganic_snap)); 904 empty_snap.Subtract(nonorganic_snap); 905 EXPECT_TRUE(empty_snap.startup_urls().empty()); 906 EXPECT_EQ(SessionStartupPref::GetDefaultStartupType(), 907 empty_snap.startup_type()); 908 EXPECT_TRUE(empty_snap.homepage().empty()); 909 EXPECT_TRUE(empty_snap.homepage_is_ntp()); 910 EXPECT_NE(std::string::npos, empty_snap.dse_url().find("{google:baseURL}")); 911 EXPECT_EQ(ResettableSettingsSnapshot::ExtensionList(), 912 empty_snap.enabled_extensions()); 913 EXPECT_EQ(std::vector<ShortcutCommand>(), empty_snap.shortcuts()); 914 915 // Reset to organic defaults. 916 ResetAndWait(ProfileResetter::DEFAULT_SEARCH_ENGINE | 917 ProfileResetter::HOMEPAGE | 918 ProfileResetter::STARTUP_PAGES | 919 ProfileResetter::EXTENSIONS | 920 ProfileResetter::SHORTCUTS); 921 922 ResettableSettingsSnapshot organic_snap(profile()); 923 organic_snap.RequestShortcuts(base::Closure()); 924 // Let it enumerate shortcuts on the FILE thread. 925 base::MessageLoop::current()->RunUntilIdle(); 926 EXPECT_EQ(diff_fields, nonorganic_snap.FindDifferentFields(organic_snap)); 927 nonorganic_snap.Subtract(organic_snap); 928 const GURL urls[] = {GURL("http://foo.de"), GURL("http://goo.gl")}; 929 EXPECT_EQ(std::vector<GURL>(urls, urls + arraysize(urls)), 930 nonorganic_snap.startup_urls()); 931 EXPECT_EQ(SessionStartupPref::URLS, nonorganic_snap.startup_type()); 932 EXPECT_EQ("http://www.foo.com", nonorganic_snap.homepage()); 933 EXPECT_FALSE(nonorganic_snap.homepage_is_ntp()); 934 EXPECT_EQ("http://www.foo.com/s?q={searchTerms}", nonorganic_snap.dse_url()); 935 EXPECT_EQ(ResettableSettingsSnapshot::ExtensionList( 936 1, std::make_pair(ext_id, "example")), 937 nonorganic_snap.enabled_extensions()); 938 if (ShortcutHandler::IsSupported()) { 939 std::vector<ShortcutCommand> shortcuts = nonorganic_snap.shortcuts(); 940 ASSERT_EQ(1u, shortcuts.size()); 941 EXPECT_EQ(command_line.first.value(), shortcuts[0].first.value()); 942 EXPECT_EQ(command_line.second, shortcuts[0].second); 943 } 944 } 945 946 TEST_F(ProfileResetterTest, FeedbackSerializationTest) { 947 // Reset to non organic defaults. 948 ResetAndWait(ProfileResetter::DEFAULT_SEARCH_ENGINE | 949 ProfileResetter::HOMEPAGE | 950 ProfileResetter::STARTUP_PAGES, 951 kDistributionConfig); 952 953 scoped_refptr<Extension> ext = CreateExtension( 954 base::ASCIIToUTF16("example"), 955 base::FilePath(FILE_PATH_LITERAL("//nonexistent")), 956 Manifest::INVALID_LOCATION, 957 extensions::Manifest::TYPE_EXTENSION, 958 false); 959 ASSERT_TRUE(ext); 960 service_->AddExtension(ext.get()); 961 962 ShortcutHandler shortcut; 963 ShortcutCommand command_line = shortcut.CreateWithArguments( 964 base::ASCIIToUTF16("chrome.lnk"), 965 base::ASCIIToUTF16("--profile-directory=Default foo.com")); 966 967 ResettableSettingsSnapshot nonorganic_snap(profile()); 968 nonorganic_snap.RequestShortcuts(base::Closure()); 969 // Let it enumerate shortcuts on the FILE thread. 970 base::MessageLoop::current()->RunUntilIdle(); 971 972 COMPILE_ASSERT(ResettableSettingsSnapshot::ALL_FIELDS == 31, 973 expand_this_test); 974 for (int field_mask = 0; field_mask <= ResettableSettingsSnapshot::ALL_FIELDS; 975 ++field_mask) { 976 std::string report = SerializeSettingsReport(nonorganic_snap, field_mask); 977 JSONStringValueSerializer json(report); 978 std::string error; 979 scoped_ptr<base::Value> root(json.Deserialize(NULL, &error)); 980 ASSERT_TRUE(root) << error; 981 ASSERT_TRUE(root->IsType(base::Value::TYPE_DICTIONARY)) << error; 982 983 base::DictionaryValue* dict = 984 static_cast<base::DictionaryValue*>(root.get()); 985 986 base::ListValue* startup_urls = NULL; 987 int startup_type = 0; 988 std::string homepage; 989 bool homepage_is_ntp = true; 990 std::string default_search_engine; 991 base::ListValue* extensions = NULL; 992 base::ListValue* shortcuts = NULL; 993 994 EXPECT_EQ(!!(field_mask & ResettableSettingsSnapshot::STARTUP_MODE), 995 dict->GetList("startup_urls", &startup_urls)); 996 EXPECT_EQ(!!(field_mask & ResettableSettingsSnapshot::STARTUP_MODE), 997 dict->GetInteger("startup_type", &startup_type)); 998 EXPECT_EQ(!!(field_mask & ResettableSettingsSnapshot::HOMEPAGE), 999 dict->GetString("homepage", &homepage)); 1000 EXPECT_EQ(!!(field_mask & ResettableSettingsSnapshot::HOMEPAGE), 1001 dict->GetBoolean("homepage_is_ntp", &homepage_is_ntp)); 1002 EXPECT_EQ(!!(field_mask & ResettableSettingsSnapshot::DSE_URL), 1003 dict->GetString("default_search_engine", &default_search_engine)); 1004 EXPECT_EQ(!!(field_mask & ResettableSettingsSnapshot::EXTENSIONS), 1005 dict->GetList("enabled_extensions", &extensions)); 1006 EXPECT_EQ(!!(field_mask & ResettableSettingsSnapshot::SHORTCUTS), 1007 dict->GetList("shortcuts", &shortcuts)); 1008 } 1009 } 1010 1011 struct FeedbackCapture { 1012 void SetFeedback(Profile* profile, 1013 const ResettableSettingsSnapshot& snapshot) { 1014 list_ = GetReadableFeedbackForSnapshot(profile, snapshot).Pass(); 1015 OnUpdatedList(); 1016 } 1017 1018 void Fail() { 1019 ADD_FAILURE() << "This method shouldn't be called."; 1020 } 1021 1022 MOCK_METHOD0(OnUpdatedList, void(void)); 1023 1024 scoped_ptr<base::ListValue> list_; 1025 }; 1026 1027 // Make sure GetReadableFeedback handles non-ascii letters. 1028 TEST_F(ProfileResetterTest, GetReadableFeedback) { 1029 scoped_refptr<Extension> ext = CreateExtension( 1030 base::WideToUTF16(L"Tisto"), 1031 base::FilePath(FILE_PATH_LITERAL("//nonexistent")), 1032 Manifest::INVALID_LOCATION, 1033 extensions::Manifest::TYPE_EXTENSION, 1034 false); 1035 ASSERT_TRUE(ext); 1036 service_->AddExtension(ext.get()); 1037 1038 PrefService* prefs = profile()->GetPrefs(); 1039 DCHECK(prefs); 1040 // The URL is "http://.". 1041 std::wstring url(L"http://" 1042 L"\u0440\u043e\u0441\u0441\u0438\u044f.\u0440\u0444"); 1043 prefs->SetBoolean(prefs::kHomePageIsNewTabPage, false); 1044 prefs->SetString(prefs::kHomePage, base::WideToUTF8(url)); 1045 1046 SessionStartupPref startup_pref(SessionStartupPref::URLS); 1047 startup_pref.urls.push_back(GURL(base::WideToUTF8(url))); 1048 SessionStartupPref::SetStartupPref(prefs, startup_pref); 1049 1050 ShortcutHandler shortcut; 1051 ShortcutCommand command_line = shortcut.CreateWithArguments( 1052 base::ASCIIToUTF16("chrome.lnk"), 1053 base::ASCIIToUTF16("--profile-directory=Default foo.com")); 1054 1055 FeedbackCapture capture; 1056 EXPECT_CALL(capture, OnUpdatedList()); 1057 ResettableSettingsSnapshot snapshot(profile()); 1058 snapshot.RequestShortcuts(base::Bind(&FeedbackCapture::SetFeedback, 1059 base::Unretained(&capture), 1060 profile(), 1061 base::ConstRef(snapshot))); 1062 // Let it enumerate shortcuts on the FILE thread. 1063 base::MessageLoop::current()->RunUntilIdle(); 1064 ::testing::Mock::VerifyAndClearExpectations(&capture); 1065 // The homepage and the startup page are in punycode. They are unreadable. 1066 // Trying to find the extension name. 1067 scoped_ptr<base::ListValue> list = capture.list_.Pass(); 1068 ASSERT_TRUE(list); 1069 bool checked_extensions = false; 1070 bool checked_shortcuts = false; 1071 for (size_t i = 0; i < list->GetSize(); ++i) { 1072 base::DictionaryValue* dict = NULL; 1073 ASSERT_TRUE(list->GetDictionary(i, &dict)); 1074 std::string value; 1075 ASSERT_TRUE(dict->GetString("key", &value)); 1076 if (value == "Extensions") { 1077 base::string16 extensions; 1078 EXPECT_TRUE(dict->GetString("value", &extensions)); 1079 EXPECT_EQ(base::WideToUTF16(L"Tisto"), extensions); 1080 checked_extensions = true; 1081 } else if (value == "Shortcut targets") { 1082 base::string16 targets; 1083 EXPECT_TRUE(dict->GetString("value", &targets)); 1084 EXPECT_NE(base::string16::npos, 1085 targets.find(base::ASCIIToUTF16("foo.com"))) << targets; 1086 checked_shortcuts = true; 1087 } 1088 } 1089 EXPECT_TRUE(checked_extensions); 1090 EXPECT_EQ(ShortcutHandler::IsSupported(), checked_shortcuts); 1091 } 1092 1093 TEST_F(ProfileResetterTest, DestroySnapshotFast) { 1094 FeedbackCapture capture; 1095 scoped_ptr<ResettableSettingsSnapshot> deleted_snapshot( 1096 new ResettableSettingsSnapshot(profile())); 1097 deleted_snapshot->RequestShortcuts(base::Bind(&FeedbackCapture::Fail, 1098 base::Unretained(&capture))); 1099 deleted_snapshot.reset(); 1100 // Running remaining tasks shouldn't trigger the callback to be called as 1101 // |deleted_snapshot| was deleted before it could run. 1102 base::MessageLoop::current()->RunUntilIdle(); 1103 } 1104 1105 } // namespace 1106