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