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