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