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