Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / profile_resetter / profile_resetter_unittest.cc
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/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);
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);
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"Tiësto"),
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"Tiësto"), 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