• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 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/themes/theme_syncable_service.h"
6 
7 #include "base/command_line.h"
8 #include "base/compiler_specific.h"
9 #include "base/files/file_path.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/time/time.h"
12 #include "chrome/browser/extensions/extension_service.h"
13 #include "chrome/browser/extensions/test_extension_system.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/themes/theme_service.h"
16 #include "chrome/browser/themes/theme_service_factory.h"
17 #include "chrome/common/extensions/manifest_url_handler.h"
18 #include "chrome/test/base/testing_profile.h"
19 #include "content/public/test/test_browser_thread.h"
20 #include "extensions/browser/extension_prefs.h"
21 #include "extensions/common/extension.h"
22 #include "extensions/common/extension_messages.h"
23 #include "extensions/common/manifest_constants.h"
24 #include "extensions/common/permissions/api_permission_set.h"
25 #include "extensions/common/permissions/permission_set.h"
26 #include "sync/api/attachments/attachment_id.h"
27 #include "sync/api/attachments/attachment_service_proxy_for_test.h"
28 #include "sync/api/fake_sync_change_processor.h"
29 #include "sync/api/sync_change_processor_wrapper_for_test.h"
30 #include "sync/api/sync_error.h"
31 #include "sync/api/sync_error_factory_mock.h"
32 #include "sync/protocol/sync.pb.h"
33 #include "sync/protocol/theme_specifics.pb.h"
34 #include "testing/gtest/include/gtest/gtest.h"
35 
36 #if defined(OS_CHROMEOS)
37 #include "chrome/browser/chromeos/login/users/user_manager.h"
38 #include "chrome/browser/chromeos/settings/cros_settings.h"
39 #include "chrome/browser/chromeos/settings/device_settings_service.h"
40 #endif
41 
42 using std::string;
43 
44 namespace {
45 
46 static const char kCustomThemeName[] = "name";
47 static const char kCustomThemeUrl[] = "http://update.url/foo";
48 
49 #if defined(OS_WIN)
50 const base::FilePath::CharType kExtensionFilePath[] =
51     FILE_PATH_LITERAL("c:\\foo");
52 #elif defined(OS_POSIX)
53 const base::FilePath::CharType kExtensionFilePath[] = FILE_PATH_LITERAL("/oo");
54 #endif
55 
56 class FakeThemeService : public ThemeService {
57  public:
FakeThemeService()58   FakeThemeService() :
59     using_system_theme_(false),
60     using_default_theme_(false),
61     theme_extension_(NULL),
62     is_dirty_(false) {}
63 
64   // ThemeService implementation
SetTheme(const extensions::Extension * extension)65   virtual void SetTheme(const extensions::Extension* extension) OVERRIDE {
66     is_dirty_ = true;
67     theme_extension_ = extension;
68     using_system_theme_ = false;
69     using_default_theme_ = false;
70   }
71 
UseDefaultTheme()72   virtual void UseDefaultTheme() OVERRIDE {
73     is_dirty_ = true;
74     using_default_theme_ = true;
75     using_system_theme_ = false;
76     theme_extension_ = NULL;
77   }
78 
UseSystemTheme()79   virtual void UseSystemTheme() OVERRIDE {
80     is_dirty_ = true;
81     using_system_theme_ = true;
82     using_default_theme_ = false;
83     theme_extension_ = NULL;
84   }
85 
UsingDefaultTheme() const86   virtual bool UsingDefaultTheme() const OVERRIDE {
87     return using_default_theme_;
88   }
89 
UsingSystemTheme() const90   virtual bool UsingSystemTheme() const OVERRIDE {
91     return using_system_theme_;
92   }
93 
GetThemeID() const94   virtual string GetThemeID() const OVERRIDE {
95     if (theme_extension_.get())
96       return theme_extension_->id();
97     else
98       return std::string();
99   }
100 
theme_extension() const101   const extensions::Extension* theme_extension() const {
102     return theme_extension_.get();
103   }
104 
is_dirty() const105   bool is_dirty() const {
106     return is_dirty_;
107   }
108 
MarkClean()109   void MarkClean() {
110     is_dirty_ = false;
111   }
112 
113  private:
114   bool using_system_theme_;
115   bool using_default_theme_;
116   scoped_refptr<const extensions::Extension> theme_extension_;
117   bool is_dirty_;
118 };
119 
BuildMockThemeService(content::BrowserContext * profile)120 KeyedService* BuildMockThemeService(content::BrowserContext* profile) {
121   return new FakeThemeService;
122 }
123 
MakeThemeExtension(const base::FilePath & extension_path,const string & name,extensions::Manifest::Location location,const string & update_url)124 scoped_refptr<extensions::Extension> MakeThemeExtension(
125     const base::FilePath& extension_path,
126     const string& name,
127     extensions::Manifest::Location location,
128     const string& update_url) {
129   base::DictionaryValue source;
130   source.SetString(extensions::manifest_keys::kName, name);
131   source.Set(extensions::manifest_keys::kTheme, new base::DictionaryValue());
132   source.SetString(extensions::manifest_keys::kUpdateURL, update_url);
133   source.SetString(extensions::manifest_keys::kVersion, "0.0.0.0");
134   string error;
135   scoped_refptr<extensions::Extension> extension =
136       extensions::Extension::Create(
137           extension_path, location, source,
138           extensions::Extension::NO_FLAGS, &error);
139   EXPECT_TRUE(extension.get());
140   EXPECT_EQ("", error);
141   return extension;
142 }
143 
144 }  // namespace
145 
146 class ThemeSyncableServiceTest : public testing::Test {
147  protected:
ThemeSyncableServiceTest()148   ThemeSyncableServiceTest()
149       : ui_thread_(content::BrowserThread::UI, &loop_),
150         file_thread_(content::BrowserThread::FILE, &loop_),
151         fake_theme_service_(NULL) {}
152 
~ThemeSyncableServiceTest()153   virtual ~ThemeSyncableServiceTest() {}
154 
SetUp()155   virtual void SetUp() {
156     profile_.reset(new TestingProfile);
157     fake_theme_service_ = BuildForProfile(profile_.get());
158     theme_sync_service_.reset(new ThemeSyncableService(profile_.get(),
159                                                        fake_theme_service_));
160     fake_change_processor_.reset(new syncer::FakeSyncChangeProcessor);
161     SetUpExtension();
162   }
163 
TearDown()164   virtual void TearDown() {
165     profile_.reset();
166     loop_.RunUntilIdle();
167   }
168 
SetUpExtension()169   void SetUpExtension() {
170     CommandLine command_line(CommandLine::NO_PROGRAM);
171     extensions::TestExtensionSystem* test_ext_system =
172         static_cast<extensions::TestExtensionSystem*>(
173                 extensions::ExtensionSystem::Get(profile_.get()));
174     ExtensionService* service = test_ext_system->CreateExtensionService(
175         &command_line, base::FilePath(kExtensionFilePath), false);
176     EXPECT_TRUE(service->extensions_enabled());
177     service->Init();
178     loop_.RunUntilIdle();
179 
180     // Create and add custom theme extension so the ThemeSyncableService can
181     // find it.
182     theme_extension_ = MakeThemeExtension(base::FilePath(kExtensionFilePath),
183                                           kCustomThemeName,
184                                           GetThemeLocation(),
185                                           kCustomThemeUrl);
186     extensions::APIPermissionSet empty_set;
187     extensions::ManifestPermissionSet empty_manifest_permissions;
188     extensions::URLPatternSet empty_extent;
189     scoped_refptr<extensions::PermissionSet> permissions =
190         new extensions::PermissionSet(empty_set, empty_manifest_permissions,
191                                       empty_extent, empty_extent);
192     extensions::ExtensionPrefs::Get(profile_.get())
193         ->AddGrantedPermissions(theme_extension_->id(), permissions.get());
194     service->AddExtension(theme_extension_.get());
195     ASSERT_EQ(1u, service->extensions()->size());
196   }
197 
198   // Overridden in PolicyInstalledThemeTest below.
GetThemeLocation()199   virtual extensions::Manifest::Location GetThemeLocation() {
200     return extensions::Manifest::INTERNAL;
201   }
202 
BuildForProfile(Profile * profile)203   FakeThemeService* BuildForProfile(Profile* profile) {
204     return static_cast<FakeThemeService*>(
205         ThemeServiceFactory::GetInstance()->SetTestingFactoryAndUse(
206             profile, &BuildMockThemeService));
207   }
208 
MakeThemeDataList(const sync_pb::ThemeSpecifics & theme_specifics)209   syncer::SyncDataList MakeThemeDataList(
210       const sync_pb::ThemeSpecifics& theme_specifics) {
211     syncer::SyncDataList list;
212     sync_pb::EntitySpecifics entity_specifics;
213     entity_specifics.mutable_theme()->CopyFrom(theme_specifics);
214     list.push_back(syncer::SyncData::CreateLocalData(
215         ThemeSyncableService::kCurrentThemeClientTag,
216         ThemeSyncableService::kCurrentThemeNodeTitle,
217         entity_specifics));
218     return list;
219   }
220 
221   // Needed for setting up extension service.
222   base::MessageLoop loop_;
223   content::TestBrowserThread ui_thread_;
224   content::TestBrowserThread file_thread_;
225 
226 #if defined OS_CHROMEOS
227   chromeos::ScopedTestDeviceSettingsService test_device_settings_service_;
228   chromeos::ScopedTestCrosSettings test_cros_settings_;
229   chromeos::ScopedTestUserManager test_user_manager_;
230 #endif
231 
232   scoped_ptr<TestingProfile> profile_;
233   FakeThemeService* fake_theme_service_;
234   scoped_refptr<extensions::Extension> theme_extension_;
235   scoped_ptr<ThemeSyncableService> theme_sync_service_;
236   scoped_ptr<syncer::FakeSyncChangeProcessor> fake_change_processor_;
237 };
238 
239 class PolicyInstalledThemeTest : public ThemeSyncableServiceTest {
GetThemeLocation()240   virtual extensions::Manifest::Location GetThemeLocation() OVERRIDE {
241     return extensions::Manifest::EXTERNAL_POLICY_DOWNLOAD;
242   }
243 };
244 
TEST_F(ThemeSyncableServiceTest,AreThemeSpecificsEqual)245 TEST_F(ThemeSyncableServiceTest, AreThemeSpecificsEqual) {
246   sync_pb::ThemeSpecifics a, b;
247   EXPECT_TRUE(ThemeSyncableService::AreThemeSpecificsEqual(a, b, false));
248   EXPECT_TRUE(ThemeSyncableService::AreThemeSpecificsEqual(a, b, true));
249 
250   // Custom vs. non-custom.
251 
252   a.set_use_custom_theme(true);
253   EXPECT_FALSE(ThemeSyncableService::AreThemeSpecificsEqual(a, b, false));
254   EXPECT_FALSE(ThemeSyncableService::AreThemeSpecificsEqual(a, b, true));
255 
256   // Custom theme equality.
257 
258   b.set_use_custom_theme(true);
259   EXPECT_TRUE(ThemeSyncableService::AreThemeSpecificsEqual(a, b, false));
260   EXPECT_TRUE(ThemeSyncableService::AreThemeSpecificsEqual(a, b, true));
261 
262   a.set_custom_theme_id("id");
263   EXPECT_FALSE(ThemeSyncableService::AreThemeSpecificsEqual(a, b, false));
264   EXPECT_FALSE(ThemeSyncableService::AreThemeSpecificsEqual(a, b, true));
265 
266   b.set_custom_theme_id("id");
267   EXPECT_TRUE(ThemeSyncableService::AreThemeSpecificsEqual(a, b, false));
268   EXPECT_TRUE(ThemeSyncableService::AreThemeSpecificsEqual(a, b, true));
269 
270   a.set_custom_theme_update_url("http://update.url");
271   EXPECT_TRUE(ThemeSyncableService::AreThemeSpecificsEqual(a, b, false));
272   EXPECT_TRUE(ThemeSyncableService::AreThemeSpecificsEqual(a, b, true));
273 
274   a.set_custom_theme_name("name");
275   EXPECT_TRUE(ThemeSyncableService::AreThemeSpecificsEqual(a, b, false));
276   EXPECT_TRUE(ThemeSyncableService::AreThemeSpecificsEqual(a, b, true));
277 
278   // Non-custom theme equality.
279 
280   a.set_use_custom_theme(false);
281   b.set_use_custom_theme(false);
282   EXPECT_TRUE(ThemeSyncableService::AreThemeSpecificsEqual(a, b, false));
283   EXPECT_TRUE(ThemeSyncableService::AreThemeSpecificsEqual(a, b, true));
284 
285   a.set_use_system_theme_by_default(true);
286   EXPECT_TRUE(ThemeSyncableService::AreThemeSpecificsEqual(a, b, false));
287   EXPECT_FALSE(ThemeSyncableService::AreThemeSpecificsEqual(a, b, true));
288 
289   b.set_use_system_theme_by_default(true);
290   EXPECT_TRUE(ThemeSyncableService::AreThemeSpecificsEqual(a, b, false));
291   EXPECT_TRUE(ThemeSyncableService::AreThemeSpecificsEqual(a, b, true));
292 }
293 
TEST_F(ThemeSyncableServiceTest,SetCurrentThemeDefaultTheme)294 TEST_F(ThemeSyncableServiceTest, SetCurrentThemeDefaultTheme) {
295   // Set up theme service to use custom theme.
296   fake_theme_service_->SetTheme(theme_extension_.get());
297 
298   syncer::SyncError error =
299       theme_sync_service_
300           ->MergeDataAndStartSyncing(
301                 syncer::THEMES,
302                 MakeThemeDataList(sync_pb::ThemeSpecifics()),
303                 scoped_ptr<syncer::SyncChangeProcessor>(
304                     new syncer::SyncChangeProcessorWrapperForTest(
305                         fake_change_processor_.get())),
306                 scoped_ptr<syncer::SyncErrorFactory>(
307                     new syncer::SyncErrorFactoryMock()))
308           .error();
309   EXPECT_FALSE(error.IsSet()) << error.message();
310   EXPECT_TRUE(fake_theme_service_->UsingDefaultTheme());
311 }
312 
TEST_F(ThemeSyncableServiceTest,SetCurrentThemeSystemTheme)313 TEST_F(ThemeSyncableServiceTest, SetCurrentThemeSystemTheme) {
314   sync_pb::ThemeSpecifics theme_specifics;
315   theme_specifics.set_use_system_theme_by_default(true);
316 
317   // Set up theme service to use custom theme.
318   fake_theme_service_->SetTheme(theme_extension_.get());
319   syncer::SyncError error =
320       theme_sync_service_
321           ->MergeDataAndStartSyncing(
322                 syncer::THEMES,
323                 MakeThemeDataList(theme_specifics),
324                 scoped_ptr<syncer::SyncChangeProcessor>(
325                     new syncer::SyncChangeProcessorWrapperForTest(
326                         fake_change_processor_.get())),
327                 scoped_ptr<syncer::SyncErrorFactory>(
328                     new syncer::SyncErrorFactoryMock()))
329           .error();
330   EXPECT_FALSE(error.IsSet()) << error.message();
331   EXPECT_TRUE(fake_theme_service_->UsingSystemTheme());
332 }
333 
TEST_F(ThemeSyncableServiceTest,SetCurrentThemeCustomTheme)334 TEST_F(ThemeSyncableServiceTest, SetCurrentThemeCustomTheme) {
335   sync_pb::ThemeSpecifics theme_specifics;
336   theme_specifics.set_use_custom_theme(true);
337   theme_specifics.set_custom_theme_id(theme_extension_->id());
338   theme_specifics.set_custom_theme_name(kCustomThemeName);
339   theme_specifics.set_custom_theme_name(kCustomThemeUrl);
340 
341   // Set up theme service to use default theme.
342   fake_theme_service_->UseDefaultTheme();
343   syncer::SyncError error =
344       theme_sync_service_
345           ->MergeDataAndStartSyncing(
346                 syncer::THEMES,
347                 MakeThemeDataList(theme_specifics),
348                 scoped_ptr<syncer::SyncChangeProcessor>(
349                     new syncer::SyncChangeProcessorWrapperForTest(
350                         fake_change_processor_.get())),
351                 scoped_ptr<syncer::SyncErrorFactory>(
352                     new syncer::SyncErrorFactoryMock()))
353           .error();
354   EXPECT_FALSE(error.IsSet()) << error.message();
355   EXPECT_EQ(fake_theme_service_->theme_extension(), theme_extension_.get());
356 }
357 
TEST_F(ThemeSyncableServiceTest,DontResetThemeWhenSpecificsAreEqual)358 TEST_F(ThemeSyncableServiceTest, DontResetThemeWhenSpecificsAreEqual) {
359   // Set up theme service to use default theme and expect no changes.
360   fake_theme_service_->UseDefaultTheme();
361   fake_theme_service_->MarkClean();
362   syncer::SyncError error =
363       theme_sync_service_
364           ->MergeDataAndStartSyncing(
365                 syncer::THEMES,
366                 MakeThemeDataList(sync_pb::ThemeSpecifics()),
367                 scoped_ptr<syncer::SyncChangeProcessor>(
368                     new syncer::SyncChangeProcessorWrapperForTest(
369                         fake_change_processor_.get())),
370                 scoped_ptr<syncer::SyncErrorFactory>(
371                     new syncer::SyncErrorFactoryMock()))
372           .error();
373   EXPECT_FALSE(error.IsSet()) << error.message();
374   EXPECT_FALSE(fake_theme_service_->is_dirty());
375 }
376 
TEST_F(ThemeSyncableServiceTest,UpdateThemeSpecificsFromCurrentTheme)377 TEST_F(ThemeSyncableServiceTest, UpdateThemeSpecificsFromCurrentTheme) {
378   // Set up theme service to use custom theme.
379   fake_theme_service_->SetTheme(theme_extension_.get());
380 
381   syncer::SyncError error =
382       theme_sync_service_
383           ->MergeDataAndStartSyncing(
384                 syncer::THEMES,
385                 syncer::SyncDataList(),
386                 scoped_ptr<syncer::SyncChangeProcessor>(
387                     new syncer::SyncChangeProcessorWrapperForTest(
388                         fake_change_processor_.get())),
389                 scoped_ptr<syncer::SyncErrorFactory>(
390                     new syncer::SyncErrorFactoryMock()))
391           .error();
392   EXPECT_FALSE(error.IsSet()) << error.message();
393   const syncer::SyncChangeList& changes = fake_change_processor_->changes();
394   ASSERT_EQ(1u, changes.size());
395   EXPECT_TRUE(changes[0].IsValid());
396   EXPECT_EQ(syncer::SyncChange::ACTION_ADD, changes[0].change_type());
397   EXPECT_EQ(syncer::THEMES, changes[0].sync_data().GetDataType());
398 
399   const sync_pb::ThemeSpecifics& theme_specifics =
400       changes[0].sync_data().GetSpecifics().theme();
401   EXPECT_TRUE(theme_specifics.use_custom_theme());
402   EXPECT_EQ(theme_extension_->id(), theme_specifics.custom_theme_id());
403   EXPECT_EQ(theme_extension_->name(), theme_specifics.custom_theme_name());
404   EXPECT_EQ(
405       extensions::ManifestURL::GetUpdateURL(theme_extension_.get()).spec(),
406       theme_specifics.custom_theme_update_url());
407 }
408 
TEST_F(ThemeSyncableServiceTest,GetAllSyncData)409 TEST_F(ThemeSyncableServiceTest, GetAllSyncData) {
410   // Set up theme service to use custom theme.
411   fake_theme_service_->SetTheme(theme_extension_.get());
412 
413   syncer::SyncDataList data_list =
414       theme_sync_service_->GetAllSyncData(syncer::THEMES);
415 
416   ASSERT_EQ(1u, data_list.size());
417   const sync_pb::ThemeSpecifics& theme_specifics =
418       data_list[0].GetSpecifics().theme();
419   EXPECT_TRUE(theme_specifics.use_custom_theme());
420   EXPECT_EQ(theme_extension_->id(), theme_specifics.custom_theme_id());
421   EXPECT_EQ(theme_extension_->name(), theme_specifics.custom_theme_name());
422   EXPECT_EQ(
423       extensions::ManifestURL::GetUpdateURL(theme_extension_.get()).spec(),
424       theme_specifics.custom_theme_update_url());
425 }
426 
TEST_F(ThemeSyncableServiceTest,ProcessSyncThemeChange)427 TEST_F(ThemeSyncableServiceTest, ProcessSyncThemeChange) {
428   // Set up theme service to use default theme.
429   fake_theme_service_->UseDefaultTheme();
430   fake_theme_service_->MarkClean();
431 
432   // Start syncing.
433   syncer::SyncError error =
434       theme_sync_service_
435           ->MergeDataAndStartSyncing(
436                 syncer::THEMES,
437                 MakeThemeDataList(sync_pb::ThemeSpecifics()),
438                 scoped_ptr<syncer::SyncChangeProcessor>(
439                     new syncer::SyncChangeProcessorWrapperForTest(
440                         fake_change_processor_.get())),
441                 scoped_ptr<syncer::SyncErrorFactory>(
442                     new syncer::SyncErrorFactoryMock()))
443           .error();
444   EXPECT_FALSE(error.IsSet()) << error.message();
445   // Don't expect theme change initially because specifics are equal.
446   EXPECT_FALSE(fake_theme_service_->is_dirty());
447 
448   // Change specifics to use custom theme and update.
449   sync_pb::ThemeSpecifics theme_specifics;
450   theme_specifics.set_use_custom_theme(true);
451   theme_specifics.set_custom_theme_id(theme_extension_->id());
452   theme_specifics.set_custom_theme_name(kCustomThemeName);
453   theme_specifics.set_custom_theme_name(kCustomThemeUrl);
454   sync_pb::EntitySpecifics entity_specifics;
455   entity_specifics.mutable_theme()->CopyFrom(theme_specifics);
456   syncer::SyncChangeList change_list;
457   change_list.push_back(
458       syncer::SyncChange(FROM_HERE,
459                          syncer::SyncChange::ACTION_UPDATE,
460                          syncer::SyncData::CreateRemoteData(
461                              1,
462                              entity_specifics,
463                              base::Time(),
464                              syncer::AttachmentIdList(),
465                              syncer::AttachmentServiceProxyForTest::Create())));
466   error = theme_sync_service_->ProcessSyncChanges(FROM_HERE, change_list);
467   EXPECT_FALSE(error.IsSet()) << error.message();
468   EXPECT_EQ(fake_theme_service_->theme_extension(), theme_extension_.get());
469 }
470 
TEST_F(ThemeSyncableServiceTest,OnThemeChangeByUser)471 TEST_F(ThemeSyncableServiceTest, OnThemeChangeByUser) {
472   // Set up theme service to use default theme.
473   fake_theme_service_->UseDefaultTheme();
474 
475   // Start syncing.
476   syncer::SyncError error =
477       theme_sync_service_
478           ->MergeDataAndStartSyncing(
479                 syncer::THEMES,
480                 MakeThemeDataList(sync_pb::ThemeSpecifics()),
481                 scoped_ptr<syncer::SyncChangeProcessor>(
482                     new syncer::SyncChangeProcessorWrapperForTest(
483                         fake_change_processor_.get())),
484                 scoped_ptr<syncer::SyncErrorFactory>(
485                     new syncer::SyncErrorFactoryMock()))
486           .error();
487   EXPECT_FALSE(error.IsSet()) << error.message();
488   const syncer::SyncChangeList& changes = fake_change_processor_->changes();
489   EXPECT_EQ(0u, changes.size());
490 
491   // Change current theme to custom theme and notify theme_sync_service_.
492   fake_theme_service_->SetTheme(theme_extension_.get());
493   theme_sync_service_->OnThemeChange();
494   EXPECT_EQ(1u, changes.size());
495   const sync_pb::ThemeSpecifics& change_specifics =
496       changes[0].sync_data().GetSpecifics().theme();
497   EXPECT_TRUE(change_specifics.use_custom_theme());
498   EXPECT_EQ(theme_extension_->id(), change_specifics.custom_theme_id());
499   EXPECT_EQ(theme_extension_->name(), change_specifics.custom_theme_name());
500   EXPECT_EQ(
501       extensions::ManifestURL::GetUpdateURL(theme_extension_.get()).spec(),
502       change_specifics.custom_theme_update_url());
503 }
504 
TEST_F(ThemeSyncableServiceTest,StopSync)505 TEST_F(ThemeSyncableServiceTest, StopSync) {
506   // Set up theme service to use default theme.
507   fake_theme_service_->UseDefaultTheme();
508 
509   // Start syncing.
510   syncer::SyncError error =
511       theme_sync_service_
512           ->MergeDataAndStartSyncing(
513                 syncer::THEMES,
514                 MakeThemeDataList(sync_pb::ThemeSpecifics()),
515                 scoped_ptr<syncer::SyncChangeProcessor>(
516                     new syncer::SyncChangeProcessorWrapperForTest(
517                         fake_change_processor_.get())),
518                 scoped_ptr<syncer::SyncErrorFactory>(
519                     new syncer::SyncErrorFactoryMock()))
520           .error();
521   EXPECT_FALSE(error.IsSet()) << error.message();
522   const syncer::SyncChangeList& changes = fake_change_processor_->changes();
523   EXPECT_EQ(0u, changes.size());
524 
525   // Stop syncing.
526   theme_sync_service_->StopSyncing(syncer::THEMES);
527 
528   // Change current theme to custom theme and notify theme_sync_service_.
529   // No change is output because sync has stopped.
530   fake_theme_service_->SetTheme(theme_extension_.get());
531   theme_sync_service_->OnThemeChange();
532   EXPECT_EQ(0u, changes.size());
533 
534   // ProcessSyncChanges() should return error when sync has stopped.
535   error = theme_sync_service_->ProcessSyncChanges(FROM_HERE, changes);
536   EXPECT_TRUE(error.IsSet());
537   EXPECT_EQ(syncer::THEMES, error.model_type());
538   EXPECT_EQ("datatype error was encountered: Theme syncable service is not "
539                 "started.",
540             error.message());
541 }
542 
TEST_F(ThemeSyncableServiceTest,RestoreSystemThemeBitWhenChangeToCustomTheme)543 TEST_F(ThemeSyncableServiceTest, RestoreSystemThemeBitWhenChangeToCustomTheme) {
544   // Initialize to use system theme.
545   fake_theme_service_->UseDefaultTheme();
546   sync_pb::ThemeSpecifics theme_specifics;
547   theme_specifics.set_use_system_theme_by_default(true);
548   syncer::SyncError error =
549       theme_sync_service_
550           ->MergeDataAndStartSyncing(
551                 syncer::THEMES,
552                 MakeThemeDataList(theme_specifics),
553                 scoped_ptr<syncer::SyncChangeProcessor>(
554                     new syncer::SyncChangeProcessorWrapperForTest(
555                         fake_change_processor_.get())),
556                 scoped_ptr<syncer::SyncErrorFactory>(
557                     new syncer::SyncErrorFactoryMock()))
558           .error();
559 
560   // Change to custom theme and notify theme_sync_service_.
561   // use_system_theme_by_default bit should be preserved.
562   fake_theme_service_->SetTheme(theme_extension_.get());
563   theme_sync_service_->OnThemeChange();
564   const syncer::SyncChangeList& changes = fake_change_processor_->changes();
565   EXPECT_EQ(1u, changes.size());
566   const sync_pb::ThemeSpecifics& change_specifics =
567       changes[0].sync_data().GetSpecifics().theme();
568   EXPECT_TRUE(change_specifics.use_system_theme_by_default());
569 }
570 
571 #if defined(TOOLKIT_GTK)
TEST_F(ThemeSyncableServiceTest,GtkUpdateSystemThemeBitWhenChangeBetweenSystemAndDefault)572 TEST_F(ThemeSyncableServiceTest,
573        GtkUpdateSystemThemeBitWhenChangeBetweenSystemAndDefault) {
574   // Initialize to use native theme.
575   fake_theme_service_->UseSystemTheme();
576   fake_theme_service_->MarkClean();
577   sync_pb::ThemeSpecifics theme_specifics;
578   theme_specifics.set_use_system_theme_by_default(true);
579   syncer::SyncError error =
580       theme_sync_service_
581           ->MergeDataAndStartSyncing(
582                 syncer::THEMES,
583                 MakeThemeDataList(theme_specifics),
584                 scoped_ptr<syncer::SyncChangeProcessor>(
585                     new syncer::SyncChangeProcessorWrapperForTest(
586                         fake_change_processor_.get())),
587                 scoped_ptr<syncer::SyncErrorFactory>(
588                     new syncer::SyncErrorFactoryMock()))
589           .error();
590   EXPECT_FALSE(fake_theme_service_->is_dirty());
591 
592   // Change to default theme and notify theme_sync_service_.
593   // use_system_theme_by_default bit should be false.
594   fake_theme_service_->UseDefaultTheme();
595   theme_sync_service_->OnThemeChange();
596   syncer::SyncChangeList& changes = fake_change_processor_->changes();
597   EXPECT_EQ(1u, changes.size());
598   EXPECT_FALSE(changes[0]
599                    .sync_data()
600                    .GetSpecifics()
601                    .theme()
602                    .use_system_theme_by_default());
603 
604   // Change to native theme and notify theme_sync_service_.
605   // use_system_theme_by_default bit should be true.
606   changes.clear();
607   fake_theme_service_->UseSystemTheme();
608   theme_sync_service_->OnThemeChange();
609   EXPECT_EQ(1u, changes.size());
610   EXPECT_TRUE(changes[0]
611                   .sync_data()
612                   .GetSpecifics()
613                   .theme()
614                   .use_system_theme_by_default());
615 }
616 #endif
617 
618 #ifndef TOOLKIT_GTK
TEST_F(ThemeSyncableServiceTest,NonGtkPreserveSystemThemeBitWhenChangeToDefaultTheme)619 TEST_F(ThemeSyncableServiceTest,
620        NonGtkPreserveSystemThemeBitWhenChangeToDefaultTheme) {
621   // Set up theme service to use default theme.
622   fake_theme_service_->UseDefaultTheme();
623 
624   // Initialize to use custom theme with use_system_theme_by_default set true.
625   sync_pb::ThemeSpecifics theme_specifics;
626   theme_specifics.set_use_custom_theme(true);
627   theme_specifics.set_custom_theme_id(theme_extension_->id());
628   theme_specifics.set_custom_theme_name(kCustomThemeName);
629   theme_specifics.set_custom_theme_name(kCustomThemeUrl);
630   theme_specifics.set_use_system_theme_by_default(true);
631   syncer::SyncError error =
632       theme_sync_service_
633           ->MergeDataAndStartSyncing(
634                 syncer::THEMES,
635                 MakeThemeDataList(theme_specifics),
636                 scoped_ptr<syncer::SyncChangeProcessor>(
637                     new syncer::SyncChangeProcessorWrapperForTest(
638                         fake_change_processor_.get())),
639                 scoped_ptr<syncer::SyncErrorFactory>(
640                     new syncer::SyncErrorFactoryMock()))
641           .error();
642   EXPECT_EQ(fake_theme_service_->theme_extension(), theme_extension_.get());
643 
644   // Change to default theme and notify theme_sync_service_.
645   // use_system_theme_by_default bit should be preserved.
646   fake_theme_service_->UseDefaultTheme();
647   theme_sync_service_->OnThemeChange();
648   const syncer::SyncChangeList& changes = fake_change_processor_->changes();
649   EXPECT_EQ(1u, changes.size());
650   const sync_pb::ThemeSpecifics& change_specifics =
651       changes[0].sync_data().GetSpecifics().theme();
652   EXPECT_FALSE(change_specifics.use_custom_theme());
653   EXPECT_TRUE(change_specifics.use_system_theme_by_default());
654 }
655 #endif
656 
TEST_F(PolicyInstalledThemeTest,InstallThemeByPolicy)657 TEST_F(PolicyInstalledThemeTest, InstallThemeByPolicy) {
658   // Set up theme service to use custom theme that was installed by policy.
659   fake_theme_service_->SetTheme(theme_extension_.get());
660 
661   syncer::SyncDataList data_list =
662       theme_sync_service_->GetAllSyncData(syncer::THEMES);
663 
664   ASSERT_EQ(0u, data_list.size());
665 }
666