Home | History | Annotate | Download | only in profile_resetter
      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