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