| // Copyright 2012 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/themes/theme_syncable_service.h" |
| |
| #include <algorithm> |
| #include <memory> |
| #include <optional> |
| |
| #include "base/base64.h" |
| #include "base/command_line.h" |
| #include "base/compiler_specific.h" |
| #include "base/files/file_path.h" |
| #include "base/functional/bind.h" |
| #include "base/json/json_string_value_serializer.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/memory/raw_ptr.h" |
| #include "base/no_destructor.h" |
| #include "base/run_loop.h" |
| #include "base/task/current_thread.h" |
| #include "base/test/metrics/histogram_tester.h" |
| #include "base/test/protobuf_matchers.h" |
| #include "base/test/run_until.h" |
| #include "base/test/scoped_feature_list.h" |
| #include "base/test/values_test_util.h" |
| #include "base/time/time.h" |
| #include "base/values.h" |
| #include "build/build_config.h" |
| #include "chrome/browser/extensions/extension_service.h" |
| #include "chrome/browser/extensions/extension_service_test_base.h" |
| #include "chrome/browser/extensions/test_extension_system.h" |
| #include "chrome/browser/prefs/browser_prefs.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/search/background/ntp_custom_background_service_constants.h" |
| #include "chrome/browser/themes/test/theme_service_changed_waiter.h" |
| #include "chrome/browser/themes/theme_helper.h" |
| #include "chrome/browser/themes/theme_service.h" |
| #include "chrome/browser/themes/theme_service_factory.h" |
| #include "chrome/browser/themes/theme_service_test_utils.h" |
| #include "chrome/browser/themes/theme_service_utils.h" |
| #include "chrome/common/extensions/extension_test_util.h" |
| #include "chrome/common/pref_names.h" |
| #include "chrome/test/base/testing_profile.h" |
| #include "components/pref_registry/pref_registry_syncable.h" |
| #include "components/sync/base/client_tag_hash.h" |
| #include "components/sync/base/features.h" |
| #include "components/sync/model/sync_change.h" |
| #include "components/sync/protocol/entity_specifics.pb.h" |
| #include "components/sync/protocol/proto_value_conversions.h" |
| #include "components/sync/protocol/theme_specifics.pb.h" |
| #include "components/sync/test/fake_sync_change_processor.h" |
| #include "components/sync/test/sync_change_processor_wrapper_for_test.h" |
| #include "components/sync_preferences/pref_service_syncable.h" |
| #include "components/sync_preferences/testing_pref_service_syncable.h" |
| #include "content/public/test/browser_task_environment.h" |
| #include "extensions/browser/disable_reason.h" |
| #include "extensions/browser/extension_prefs.h" |
| #include "extensions/browser/extension_registrar.h" |
| #include "extensions/browser/extension_registry.h" |
| #include "extensions/browser/pending_extension_manager.h" |
| #include "extensions/common/extension.h" |
| #include "extensions/common/manifest_constants.h" |
| #include "extensions/common/manifest_url_handlers.h" |
| #include "extensions/common/permissions/api_permission_set.h" |
| #include "extensions/common/permissions/permission_set.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| #if BUILDFLAG(IS_CHROMEOS) |
| #include "chrome/browser/ash/login/users/user_manager_delegate_impl.h" |
| #include "chrome/browser/ash/settings/scoped_cros_settings_test_helper.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chromeos/ash/components/settings/cros_settings.h" |
| #include "components/user_manager/scoped_user_manager.h" |
| #include "components/user_manager/user_manager_impl.h" |
| #endif |
| |
| using std::string; |
| |
| namespace { |
| |
| using theme_service::test::MakeThemeChangeList; |
| using theme_service::test::MakeThemeDataList; |
| using theme_service::test::MakeThemeExtension; |
| |
| static const char* kCustomThemeId = "abcdefghijklmnopabcdefghijklmnop"; |
| static const char kCustomThemeName[] = "name"; |
| static const char kCustomThemeUrl[] = "http://update.url/foo"; |
| |
| #if BUILDFLAG(IS_WIN) |
| const base::FilePath::CharType kExtensionFilePath[] = |
| FILE_PATH_LITERAL("c:\\foo"); |
| #elif BUILDFLAG(IS_POSIX) |
| const base::FilePath::CharType kExtensionFilePath[] = FILE_PATH_LITERAL("/oo"); |
| #else |
| #error "Unknown platform" |
| #endif |
| |
| constexpr char kTestUrl[] = "https://www.foo.com"; |
| |
| const char kThemePrefMigrationAlreadyMigratedHistogram[] = |
| "Theme.ThemePrefMigration.AlreadyMigrated"; |
| const char kThemePrefMigrationMigratedPrefHistogram[] = |
| "Theme.ThemePrefMigration.MigratedPref"; |
| const char kThemePrefMigrationIncomingSyncingPrefAppliedHistogram[] = |
| "Theme.ThemePrefMigration.IncomingSyncingPrefApplied"; |
| |
| MATCHER_P2(DictionaryValuePtrHas, key, value, "") { |
| return testing::ExplainMatchResult( |
| testing::Pointee(base::test::DictionaryHasValue(key, base::Value(value))), |
| arg, result_listener); |
| } |
| |
| const ThemeHelper& GetThemeHelper() { |
| static base::NoDestructor<std::unique_ptr<ThemeHelper>> theme_helper( |
| std::make_unique<ThemeHelper>()); |
| return **theme_helper; |
| } |
| |
| class FakeThemeService : public ThemeService { |
| public: |
| FakeThemeService() : ThemeService(nullptr, GetThemeHelper()) {} |
| |
| // ThemeService: |
| void DoSetTheme(const extensions::Extension* extension, |
| bool suppress_infobar) override { |
| is_dirty_ = true; |
| theme_extension_ = extension; |
| using_system_theme_ = false; |
| using_default_theme_ = false; |
| using_policy_theme_ = false; |
| might_show_infobar_ = !suppress_infobar; |
| color_ = 0; |
| } |
| |
| void BuildAutogeneratedThemeFromColor(SkColor color) override { |
| is_dirty_ = true; |
| color_ = color; |
| theme_extension_.reset(); |
| using_system_theme_ = false; |
| using_default_theme_ = false; |
| using_policy_theme_ = false; |
| } |
| |
| void UseTheme(ui::SystemTheme system_theme) override { |
| if (system_theme == ui::SystemTheme::kDefault) { |
| UseDefaultTheme(); |
| } else { |
| UseSystemTheme(); |
| } |
| } |
| |
| void UseDefaultTheme() override { |
| is_dirty_ = true; |
| using_default_theme_ = true; |
| using_system_theme_ = false; |
| using_policy_theme_ = false; |
| theme_extension_.reset(); |
| color_ = 0; |
| } |
| |
| void UseSystemTheme() override { |
| is_dirty_ = true; |
| using_system_theme_ = true; |
| using_default_theme_ = false; |
| using_policy_theme_ = false; |
| theme_extension_.reset(); |
| color_ = 0; |
| } |
| |
| void BuildAutogeneratedPolicyTheme() override { |
| is_dirty_ = true; |
| color_ = SkColorSetRGB(100, 100, 0); |
| theme_extension_.reset(); |
| using_system_theme_ = false; |
| using_default_theme_ = false; |
| using_policy_theme_ = true; |
| } |
| |
| bool IsSystemThemeDistinctFromDefaultTheme() const override { |
| return distinct_from_default_theme_; |
| } |
| |
| void set_distinct_from_default_theme(bool is_distinct) { |
| distinct_from_default_theme_ = is_distinct; |
| } |
| |
| bool UsingDefaultTheme() const override { return using_default_theme_; } |
| |
| bool UsingSystemTheme() const override { return using_system_theme_; } |
| |
| bool UsingExtensionTheme() const override { return !!theme_extension_; } |
| |
| bool UsingAutogeneratedTheme() const override { return color_ != 0; } |
| |
| bool UsingPolicyTheme() const override { return using_policy_theme_; } |
| |
| string GetThemeID() const override { |
| return UsingExtensionTheme() ? theme_extension_->id() : std::string(); |
| } |
| |
| SkColor GetAutogeneratedThemeColor() const override { return color_; } |
| |
| bool GetIsGrayscale() const override { return false; } |
| |
| ThemeService::BrowserColorScheme GetBrowserColorScheme() const override { |
| return ThemeService::BrowserColorScheme::kSystem; |
| } |
| |
| const extensions::Extension* theme_extension() const { |
| return theme_extension_.get(); |
| } |
| |
| bool is_dirty() const { return is_dirty_; } |
| |
| void MarkClean() { is_dirty_ = false; } |
| |
| bool might_show_infobar() const { return might_show_infobar_; } |
| |
| private: |
| bool using_system_theme_ = false; |
| bool using_default_theme_ = false; |
| bool using_policy_theme_ = false; |
| bool distinct_from_default_theme_ = false; |
| scoped_refptr<const extensions::Extension> theme_extension_; |
| bool is_dirty_ = false; |
| bool might_show_infobar_ = false; |
| SkColor color_; |
| }; |
| |
| } // namespace |
| |
| // ThemeSyncableServiceTest ---------------------------------------------------- |
| |
| class ThemeSyncableServiceTest : public testing::Test, |
| public ThemeSyncableService::Observer { |
| protected: |
| ThemeSyncableServiceTest() : fake_theme_service_(nullptr) {} |
| |
| ~ThemeSyncableServiceTest() override = default; |
| |
| void SetUp() override { |
| // Setting a matching update URL is necessary to make the test theme |
| // considered syncable. |
| extension_test_util::SetGalleryUpdateURL(GURL(kCustomThemeUrl)); |
| |
| TestingProfile::Builder builder; |
| builder.AddTestingFactory( |
| ThemeServiceFactory::GetInstance(), |
| base::BindRepeating([](content::BrowserContext* context) |
| -> std::unique_ptr<KeyedService> { |
| return std::make_unique<FakeThemeService>(); |
| })); |
| profile_ = builder.Build(); |
| fake_theme_service_ = static_cast<FakeThemeService*>( |
| ThemeServiceFactory::GetForProfile(profile_.get())); |
| theme_sync_service_ = std::make_unique<ThemeSyncableService>( |
| profile_.get(), fake_theme_service_); |
| theme_sync_service_->AddObserver(this); |
| fake_change_processor_ = |
| std::make_unique<syncer::FakeSyncChangeProcessor>(); |
| SetUpExtension(); |
| } |
| |
| void TearDown() override { |
| theme_sync_service_.reset(); |
| profile_.reset(); |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| void SetUpExtension() { |
| base::CommandLine command_line(base::CommandLine::NO_PROGRAM); |
| extensions::TestExtensionSystem* test_ext_system = |
| static_cast<extensions::TestExtensionSystem*>( |
| extensions::ExtensionSystem::Get(profile_.get())); |
| extensions::ExtensionService* service = |
| test_ext_system->CreateExtensionService( |
| &command_line, base::FilePath(kExtensionFilePath), false); |
| auto* registrar = extensions::ExtensionRegistrar::Get(profile_.get()); |
| EXPECT_TRUE(registrar->extensions_enabled()); |
| service->Init(); |
| base::RunLoop().RunUntilIdle(); |
| |
| // Create and add custom theme extension so the ThemeSyncableService can |
| // find it. |
| theme_extension_ = MakeThemeExtension(base::FilePath(kExtensionFilePath), |
| kCustomThemeId, kCustomThemeName, |
| GetThemeLocation(), kCustomThemeUrl); |
| extensions::ExtensionPrefs::Get(profile_.get()) |
| ->AddGrantedPermissions(theme_extension_->id(), |
| extensions::PermissionSet()); |
| registrar->AddExtension(theme_extension_); |
| extensions::ExtensionRegistry* registry = |
| extensions::ExtensionRegistry::Get(profile_.get()); |
| ASSERT_EQ(1u, registry->enabled_extensions().size()); |
| } |
| |
| // Overridden in PolicyInstalledThemeTest below. |
| virtual extensions::mojom::ManifestLocation GetThemeLocation() { |
| return extensions::mojom::ManifestLocation::kInternal; |
| } |
| |
| void OnThemeSyncStarted(ThemeSyncableService::ThemeSyncState state) override { |
| state_ = state; |
| } |
| |
| bool HasThemeSyncStarted() { return state_ != std::nullopt; } |
| |
| bool HasThemeSyncTriggeredExtensionInstallation() { |
| return state_ && *state_ == ThemeSyncableService::ThemeSyncState:: |
| kWaitingForExtensionInstallation; |
| } |
| |
| // Needed for setting up extension service. |
| content::BrowserTaskEnvironment task_environment_; |
| |
| #if BUILDFLAG(IS_CHROMEOS) |
| ash::ScopedCrosSettingsTestHelper cros_settings_test_helper_; |
| user_manager::ScopedUserManager user_manager_{ |
| std::make_unique<user_manager::UserManagerImpl>( |
| std::make_unique<ash::UserManagerDelegateImpl>(), |
| g_browser_process->local_state(), |
| ash::CrosSettings::Get())}; |
| #endif |
| |
| std::unique_ptr<TestingProfile> profile_; |
| raw_ptr<FakeThemeService, DanglingUntriaged> fake_theme_service_; |
| scoped_refptr<extensions::Extension> theme_extension_; |
| std::unique_ptr<ThemeSyncableService> theme_sync_service_; |
| std::unique_ptr<syncer::FakeSyncChangeProcessor> fake_change_processor_; |
| std::optional<ThemeSyncableService::ThemeSyncState> state_; |
| }; |
| |
| TEST_F(ThemeSyncableServiceTest, AreThemeSpecificsEquivalent) { |
| sync_pb::ThemeSpecifics a, b; |
| EXPECT_TRUE(ThemeSyncableService::AreThemeSpecificsEquivalent(a, b, false)); |
| EXPECT_TRUE(ThemeSyncableService::AreThemeSpecificsEquivalent(a, b, true)); |
| |
| // Custom vs. non-custom. |
| |
| a.set_use_custom_theme(true); |
| EXPECT_FALSE(ThemeSyncableService::AreThemeSpecificsEquivalent(a, b, false)); |
| EXPECT_FALSE(ThemeSyncableService::AreThemeSpecificsEquivalent(a, b, true)); |
| |
| a.set_use_custom_theme(false); |
| b.set_use_custom_theme(true); |
| EXPECT_FALSE(ThemeSyncableService::AreThemeSpecificsEquivalent(a, b, false)); |
| EXPECT_FALSE(ThemeSyncableService::AreThemeSpecificsEquivalent(a, b, true)); |
| |
| // Custom theme equality for extensions. |
| a.set_use_custom_theme(true); |
| b.set_use_custom_theme(true); |
| EXPECT_TRUE(ThemeSyncableService::AreThemeSpecificsEquivalent(a, b, false)); |
| EXPECT_TRUE(ThemeSyncableService::AreThemeSpecificsEquivalent(a, b, true)); |
| |
| a.set_custom_theme_id("id"); |
| EXPECT_FALSE(ThemeSyncableService::AreThemeSpecificsEquivalent(a, b, false)); |
| EXPECT_FALSE(ThemeSyncableService::AreThemeSpecificsEquivalent(a, b, true)); |
| |
| b.set_custom_theme_id("id"); |
| EXPECT_TRUE(ThemeSyncableService::AreThemeSpecificsEquivalent(a, b, false)); |
| EXPECT_TRUE(ThemeSyncableService::AreThemeSpecificsEquivalent(a, b, true)); |
| |
| a.set_custom_theme_update_url("http://update.url"); |
| EXPECT_TRUE(ThemeSyncableService::AreThemeSpecificsEquivalent(a, b, false)); |
| EXPECT_TRUE(ThemeSyncableService::AreThemeSpecificsEquivalent(a, b, true)); |
| |
| a.set_custom_theme_name("name"); |
| EXPECT_TRUE(ThemeSyncableService::AreThemeSpecificsEquivalent(a, b, false)); |
| EXPECT_TRUE(ThemeSyncableService::AreThemeSpecificsEquivalent(a, b, true)); |
| |
| // Theme equality for autogenerated. |
| a.set_use_custom_theme(true); |
| b.set_use_custom_theme(false); |
| b.mutable_autogenerated_color_theme()->set_color(SkColorSetRGB(0, 0, 0)); |
| EXPECT_FALSE(ThemeSyncableService::AreThemeSpecificsEquivalent(a, b, false)); |
| EXPECT_FALSE(ThemeSyncableService::AreThemeSpecificsEquivalent(a, b, true)); |
| |
| b.set_use_custom_theme(true); |
| b.clear_autogenerated_color_theme(); |
| a.set_use_custom_theme(false); |
| a.mutable_autogenerated_color_theme()->set_color(SkColorSetRGB(0, 0, 0)); |
| EXPECT_FALSE(ThemeSyncableService::AreThemeSpecificsEquivalent(a, b, false)); |
| EXPECT_FALSE(ThemeSyncableService::AreThemeSpecificsEquivalent(a, b, true)); |
| |
| b.set_use_custom_theme(false); |
| b.mutable_autogenerated_color_theme()->set_color(SkColorSetRGB(0, 0, 100)); |
| a.mutable_autogenerated_color_theme()->set_color(SkColorSetRGB(0, 0, 100)); |
| EXPECT_TRUE(ThemeSyncableService::AreThemeSpecificsEquivalent(a, b, false)); |
| EXPECT_TRUE(ThemeSyncableService::AreThemeSpecificsEquivalent(a, b, true)); |
| |
| b.mutable_autogenerated_color_theme()->set_color(SkColorSetRGB(0, 0, 200)); |
| EXPECT_FALSE(ThemeSyncableService::AreThemeSpecificsEquivalent(a, b, false)); |
| EXPECT_FALSE(ThemeSyncableService::AreThemeSpecificsEquivalent(a, b, true)); |
| |
| // No theme equality. |
| |
| a.clear_autogenerated_color_theme(); |
| b.clear_autogenerated_color_theme(); |
| EXPECT_TRUE(ThemeSyncableService::AreThemeSpecificsEquivalent(a, b, false)); |
| EXPECT_TRUE(ThemeSyncableService::AreThemeSpecificsEquivalent(a, b, true)); |
| |
| a.set_use_system_theme_by_default(true); |
| EXPECT_TRUE(ThemeSyncableService::AreThemeSpecificsEquivalent(a, b, false)); |
| EXPECT_FALSE(ThemeSyncableService::AreThemeSpecificsEquivalent(a, b, true)); |
| |
| b.set_use_system_theme_by_default(true); |
| EXPECT_TRUE(ThemeSyncableService::AreThemeSpecificsEquivalent(a, b, false)); |
| EXPECT_TRUE(ThemeSyncableService::AreThemeSpecificsEquivalent(a, b, true)); |
| } |
| |
| TEST_F(ThemeSyncableServiceTest, SetCurrentThemeDefaultTheme) { |
| // Set up theme service to use custom theme. |
| fake_theme_service_->SetTheme(theme_extension_.get()); |
| |
| std::optional<syncer::ModelError> error = |
| theme_sync_service_->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(sync_pb::ThemeSpecifics()), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor_.get()))); |
| EXPECT_TRUE(HasThemeSyncStarted()); |
| EXPECT_FALSE(error.has_value()) << error.value().message(); |
| EXPECT_FALSE(fake_theme_service_->UsingDefaultTheme()); |
| EXPECT_EQ(fake_theme_service_->theme_extension(), theme_extension_.get()); |
| } |
| |
| TEST_F(ThemeSyncableServiceTest, SetCurrentThemeSystemTheme) { |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.set_use_system_theme_by_default(true); |
| |
| // Set up theme service to use custom theme. |
| fake_theme_service_->SetTheme(theme_extension_.get()); |
| std::optional<syncer::ModelError> error = |
| theme_sync_service_->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor_.get()))); |
| EXPECT_TRUE(HasThemeSyncStarted()); |
| EXPECT_FALSE(error.has_value()) << error.value().message(); |
| EXPECT_FALSE(fake_theme_service_->UsingSystemTheme()); |
| EXPECT_EQ(fake_theme_service_->theme_extension(), theme_extension_.get()); |
| } |
| |
| TEST_F(ThemeSyncableServiceTest, SetCurrentThemeCustomTheme_Extension) { |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.set_use_custom_theme(true); |
| theme_specifics.set_custom_theme_id(theme_extension_->id()); |
| theme_specifics.set_custom_theme_name(kCustomThemeName); |
| theme_specifics.set_custom_theme_update_url(kCustomThemeUrl); |
| |
| // Set up theme service to use default theme. |
| fake_theme_service_->UseDefaultTheme(); |
| std::optional<syncer::ModelError> error = |
| theme_sync_service_->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor_.get()))); |
| EXPECT_TRUE(HasThemeSyncStarted()); |
| EXPECT_FALSE(HasThemeSyncTriggeredExtensionInstallation()); |
| EXPECT_FALSE(error.has_value()) << error.value().message(); |
| EXPECT_EQ(fake_theme_service_->theme_extension(), theme_extension_.get()); |
| } |
| |
| TEST_F(ThemeSyncableServiceTest, SetCurrentThemeCustomTheme_Extension_Install) { |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.set_use_custom_theme(true); |
| // Use an arbitrary id (such an extension is not installed, yet). |
| theme_specifics.set_custom_theme_id("fake_extension_id"); |
| theme_specifics.set_custom_theme_name(kCustomThemeName); |
| theme_specifics.set_custom_theme_update_url(kCustomThemeUrl); |
| |
| // Set up theme service to use default theme. |
| fake_theme_service_->UseDefaultTheme(); |
| std::optional<syncer::ModelError> error = |
| theme_sync_service_->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor_.get()))); |
| EXPECT_TRUE(HasThemeSyncStarted()); |
| EXPECT_FALSE(error.has_value()) << error.value().message(); |
| // The theme is not installed yet and thus, the default theme is still used. |
| EXPECT_TRUE(fake_theme_service_->UsingDefaultTheme()); |
| EXPECT_TRUE(HasThemeSyncTriggeredExtensionInstallation()); |
| EXPECT_TRUE(extensions::PendingExtensionManager::Get(profile_.get()) |
| ->HasPendingExtensionFromSync()); |
| } |
| |
| TEST_F(ThemeSyncableServiceTest, SetCurrentThemeCustomTheme_Autogenerated) { |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.set_use_custom_theme(false); |
| theme_specifics.mutable_autogenerated_color_theme()->set_color( |
| SkColorSetRGB(0, 0, 100)); |
| |
| // Set up theme service to use default theme. |
| fake_theme_service_->UseDefaultTheme(); |
| std::optional<syncer::ModelError> error = |
| theme_sync_service_->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor_.get()))); |
| EXPECT_TRUE(HasThemeSyncStarted()); |
| EXPECT_FALSE(error.has_value()) << error.value().message(); |
| EXPECT_EQ(fake_theme_service_->GetAutogeneratedThemeColor(), |
| SkColorSetRGB(0, 0, 100)); |
| } |
| |
| TEST_F(ThemeSyncableServiceTest, DontResetThemeWhenSpecificsAreEqual) { |
| // Set up theme service to use default theme and expect no changes. |
| fake_theme_service_->UseDefaultTheme(); |
| fake_theme_service_->MarkClean(); |
| std::optional<syncer::ModelError> error = |
| theme_sync_service_->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(sync_pb::ThemeSpecifics()), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor_.get()))); |
| EXPECT_TRUE(HasThemeSyncStarted()); |
| EXPECT_FALSE(error.has_value()) << error.value().message(); |
| EXPECT_FALSE(fake_theme_service_->is_dirty()); |
| } |
| |
| TEST_F(ThemeSyncableServiceTest, UpdateThemeSpecifics_CurrentTheme_Extension) { |
| // Set up theme service to use custom theme. |
| fake_theme_service_->SetTheme(theme_extension_.get()); |
| |
| std::optional<syncer::ModelError> error = |
| theme_sync_service_->MergeDataAndStartSyncing( |
| syncer::THEMES, syncer::SyncDataList(), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor_.get()))); |
| EXPECT_FALSE(error.has_value()) << error.value().message(); |
| const syncer::SyncChangeList& changes = fake_change_processor_->changes(); |
| ASSERT_EQ(1u, changes.size()); |
| EXPECT_EQ(syncer::SyncChange::ACTION_ADD, changes[0].change_type()); |
| EXPECT_EQ(syncer::THEMES, changes[0].sync_data().GetDataType()); |
| |
| const sync_pb::ThemeSpecifics& theme_specifics = |
| changes[0].sync_data().GetSpecifics().theme(); |
| EXPECT_TRUE(theme_specifics.use_custom_theme()); |
| EXPECT_EQ(theme_extension_->id(), theme_specifics.custom_theme_id()); |
| EXPECT_EQ(theme_extension_->name(), theme_specifics.custom_theme_name()); |
| EXPECT_EQ( |
| extensions::ManifestURL::GetUpdateURL(theme_extension_.get()).spec(), |
| theme_specifics.custom_theme_update_url()); |
| } |
| |
| TEST_F(ThemeSyncableServiceTest, |
| UpdateThemeSpecifics_CurrentTheme_Autogenerated) { |
| // Set up theme service to use autogenerated theme. |
| fake_theme_service_->BuildAutogeneratedThemeFromColor( |
| SkColorSetRGB(0, 0, 100)); |
| |
| std::optional<syncer::ModelError> error = |
| theme_sync_service_->MergeDataAndStartSyncing( |
| syncer::THEMES, syncer::SyncDataList(), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor_.get()))); |
| EXPECT_FALSE(error.has_value()) << error.value().message(); |
| const syncer::SyncChangeList& changes = fake_change_processor_->changes(); |
| ASSERT_EQ(1u, changes.size()); |
| EXPECT_EQ(syncer::SyncChange::ACTION_ADD, changes[0].change_type()); |
| EXPECT_EQ(syncer::THEMES, changes[0].sync_data().GetDataType()); |
| |
| const sync_pb::ThemeSpecifics& theme_specifics = |
| changes[0].sync_data().GetSpecifics().theme(); |
| EXPECT_FALSE(theme_specifics.use_custom_theme()); |
| EXPECT_EQ(fake_theme_service_->GetAutogeneratedThemeColor(), |
| theme_specifics.autogenerated_color_theme().color()); |
| } |
| |
| TEST_F(ThemeSyncableServiceTest, UpdateThemeSpecifics_CurrentTheme_Policy) { |
| // Set up theme service to use policy theme. |
| fake_theme_service_->BuildAutogeneratedPolicyTheme(); |
| |
| std::optional<syncer::ModelError> error = |
| theme_sync_service_->MergeDataAndStartSyncing( |
| syncer::THEMES, syncer::SyncDataList(), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor_.get()))); |
| EXPECT_FALSE(error.has_value()) << error.value().message(); |
| // Applying policy theme doesn't trigger sync changes. |
| const syncer::SyncChangeList& changes = fake_change_processor_->changes(); |
| ASSERT_EQ(0u, changes.size()); |
| } |
| |
| TEST_F(ThemeSyncableServiceTest, GetAllSyncDataForTesting_Extension) { |
| // Set up theme service to use custom theme. |
| fake_theme_service_->SetTheme(theme_extension_.get()); |
| |
| syncer::SyncDataList data_list = |
| theme_sync_service_->GetAllSyncDataForTesting(syncer::THEMES); |
| |
| ASSERT_EQ(1u, data_list.size()); |
| const sync_pb::ThemeSpecifics& theme_specifics = |
| data_list[0].GetSpecifics().theme(); |
| EXPECT_TRUE(theme_specifics.use_custom_theme()); |
| EXPECT_EQ(theme_extension_->id(), theme_specifics.custom_theme_id()); |
| EXPECT_EQ(theme_extension_->name(), theme_specifics.custom_theme_name()); |
| EXPECT_EQ( |
| extensions::ManifestURL::GetUpdateURL(theme_extension_.get()).spec(), |
| theme_specifics.custom_theme_update_url()); |
| } |
| |
| TEST_F(ThemeSyncableServiceTest, GetAllSyncDataForTesting_Autogenerated) { |
| // Set up theme service to use autogenerated theme. |
| fake_theme_service_->BuildAutogeneratedThemeFromColor( |
| SkColorSetRGB(0, 0, 100)); |
| |
| syncer::SyncDataList data_list = |
| theme_sync_service_->GetAllSyncDataForTesting(syncer::THEMES); |
| |
| ASSERT_EQ(1u, data_list.size()); |
| const sync_pb::ThemeSpecifics& theme_specifics = |
| data_list[0].GetSpecifics().theme(); |
| EXPECT_FALSE(theme_specifics.use_custom_theme()); |
| EXPECT_EQ(fake_theme_service_->GetAutogeneratedThemeColor(), |
| theme_specifics.autogenerated_color_theme().color()); |
| } |
| |
| TEST_F(ThemeSyncableServiceTest, GetAllSyncDataForTesting_Policy) { |
| // Set up theme service to use policy theme. |
| fake_theme_service_->BuildAutogeneratedPolicyTheme(); |
| |
| // Themes applied through policy shouldn't be synced. |
| syncer::SyncDataList data_list = |
| theme_sync_service_->GetAllSyncDataForTesting(syncer::THEMES); |
| ASSERT_EQ(0u, data_list.size()); |
| } |
| |
| TEST_F(ThemeSyncableServiceTest, ProcessSyncThemeChange_Extension) { |
| // Set up theme service to use default theme. |
| fake_theme_service_->UseDefaultTheme(); |
| fake_theme_service_->MarkClean(); |
| |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service_->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(sync_pb::ThemeSpecifics()), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor_.get()))); |
| EXPECT_FALSE(error.has_value()) << error.value().message(); |
| // Don't expect theme change initially because specifics are equal. |
| EXPECT_FALSE(fake_theme_service_->is_dirty()); |
| |
| // Change specifics to use custom theme and update. |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.set_use_custom_theme(true); |
| theme_specifics.set_custom_theme_id(theme_extension_->id()); |
| theme_specifics.set_custom_theme_name(kCustomThemeName); |
| theme_specifics.set_custom_theme_update_url(kCustomThemeUrl); |
| sync_pb::EntitySpecifics entity_specifics; |
| entity_specifics.mutable_theme()->CopyFrom(theme_specifics); |
| syncer::SyncChangeList change_list; |
| change_list.emplace_back( |
| FROM_HERE, syncer::SyncChange::ACTION_UPDATE, |
| syncer::SyncData::CreateRemoteData( |
| entity_specifics, syncer::ClientTagHash::FromHashed("unused"))); |
| std::optional<syncer::ModelError> process_error = |
| theme_sync_service_->ProcessSyncChanges(FROM_HERE, change_list); |
| EXPECT_FALSE(process_error.has_value()) << process_error.value().message(); |
| EXPECT_EQ(fake_theme_service_->theme_extension(), theme_extension_.get()); |
| // Don't show an infobar for theme installation. Regression test for |
| // crbug.com/731688 |
| EXPECT_FALSE(fake_theme_service_->might_show_infobar()); |
| } |
| |
| TEST_F(ThemeSyncableServiceTest, ProcessSyncThemeChange_Autogenerated) { |
| // Set up theme service to use default theme. |
| fake_theme_service_->UseDefaultTheme(); |
| fake_theme_service_->MarkClean(); |
| |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service_->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(sync_pb::ThemeSpecifics()), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor_.get()))); |
| EXPECT_FALSE(error.has_value()) << error.value().message(); |
| // Don't expect theme change initially because specifics are equal. |
| EXPECT_FALSE(fake_theme_service_->is_dirty()); |
| |
| // Change specifics to use custom theme and update. |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.set_use_custom_theme(false); |
| theme_specifics.mutable_autogenerated_color_theme()->set_color( |
| SkColorSetRGB(0, 0, 100)); |
| sync_pb::EntitySpecifics entity_specifics; |
| entity_specifics.mutable_theme()->CopyFrom(theme_specifics); |
| syncer::SyncChangeList change_list; |
| change_list.emplace_back( |
| FROM_HERE, syncer::SyncChange::ACTION_UPDATE, |
| syncer::SyncData::CreateRemoteData( |
| entity_specifics, syncer::ClientTagHash::FromHashed("unused"))); |
| std::optional<syncer::ModelError> process_error = |
| theme_sync_service_->ProcessSyncChanges(FROM_HERE, change_list); |
| EXPECT_FALSE(process_error.has_value()) << process_error.value().message(); |
| EXPECT_EQ(fake_theme_service_->GetAutogeneratedThemeColor(), |
| SkColorSetRGB(0, 0, 100)); |
| } |
| |
| TEST_F(ThemeSyncableServiceTest, OnThemeChangeByUser_Extension) { |
| // Set up theme service to use default theme. |
| fake_theme_service_->UseDefaultTheme(); |
| |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service_->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(sync_pb::ThemeSpecifics()), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor_.get()))); |
| EXPECT_FALSE(error.has_value()) << error.value().message(); |
| const syncer::SyncChangeList& changes = fake_change_processor_->changes(); |
| EXPECT_EQ(0u, changes.size()); |
| |
| // Change current theme to custom theme and notify theme_sync_service_. |
| fake_theme_service_->SetTheme(theme_extension_.get()); |
| theme_sync_service_->OnThemeChanged(); |
| EXPECT_EQ(1u, changes.size()); |
| const sync_pb::ThemeSpecifics& change_specifics = |
| changes[0].sync_data().GetSpecifics().theme(); |
| EXPECT_TRUE(change_specifics.use_custom_theme()); |
| EXPECT_EQ(theme_extension_->id(), change_specifics.custom_theme_id()); |
| EXPECT_EQ(theme_extension_->name(), change_specifics.custom_theme_name()); |
| EXPECT_EQ( |
| extensions::ManifestURL::GetUpdateURL(theme_extension_.get()).spec(), |
| change_specifics.custom_theme_update_url()); |
| } |
| |
| TEST_F(ThemeSyncableServiceTest, OnThemeChangeByUser_Autogenerated) { |
| // Set up theme service to use default theme. |
| fake_theme_service_->UseDefaultTheme(); |
| |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service_->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(sync_pb::ThemeSpecifics()), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor_.get()))); |
| EXPECT_FALSE(error.has_value()) << error.value().message(); |
| const syncer::SyncChangeList& changes = fake_change_processor_->changes(); |
| EXPECT_EQ(0u, changes.size()); |
| |
| // Change current theme to custom theme and notify theme_sync_service_. |
| fake_theme_service_->BuildAutogeneratedThemeFromColor( |
| SkColorSetRGB(0, 0, 100)); |
| theme_sync_service_->OnThemeChanged(); |
| EXPECT_EQ(1u, changes.size()); |
| const sync_pb::ThemeSpecifics& change_specifics = |
| changes[0].sync_data().GetSpecifics().theme(); |
| EXPECT_FALSE(change_specifics.use_custom_theme()); |
| EXPECT_EQ(fake_theme_service_->GetAutogeneratedThemeColor(), |
| SkColorSetRGB(0, 0, 100)); |
| } |
| |
| TEST_F(ThemeSyncableServiceTest, StopSync) { |
| // Set up theme service to use default theme. |
| fake_theme_service_->UseDefaultTheme(); |
| |
| // Start syncing. |
| std::optional<syncer::ModelError> merge_error = |
| theme_sync_service_->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(sync_pb::ThemeSpecifics()), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor_.get()))); |
| EXPECT_FALSE(merge_error.has_value()) << merge_error.value().message(); |
| const syncer::SyncChangeList& changes = fake_change_processor_->changes(); |
| EXPECT_EQ(0u, changes.size()); |
| |
| // Stop syncing. |
| theme_sync_service_->StopSyncing(syncer::THEMES); |
| |
| // Change current theme to custom theme and notify theme_sync_service_. |
| // No change is output because sync has stopped. |
| fake_theme_service_->SetTheme(theme_extension_.get()); |
| theme_sync_service_->OnThemeChanged(); |
| EXPECT_EQ(0u, changes.size()); |
| |
| // ProcessSyncChanges() should return error when sync has stopped. |
| std::optional<syncer::ModelError> process_error = |
| theme_sync_service_->ProcessSyncChanges(FROM_HERE, changes); |
| EXPECT_TRUE(process_error.has_value()); |
| EXPECT_EQ("Theme syncable service is not started.", |
| process_error.value().message()); |
| } |
| |
| TEST_F(ThemeSyncableServiceTest, RestoreSystemThemeBitWhenChangeToCustomTheme) { |
| // Initialize to use system theme. |
| fake_theme_service_->UseDefaultTheme(); |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.set_use_system_theme_by_default(true); |
| std::optional<syncer::ModelError> error = |
| theme_sync_service_->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor_.get()))); |
| |
| // Change to custom theme and notify theme_sync_service_. |
| // use_system_theme_by_default bit should be preserved. |
| fake_theme_service_->SetTheme(theme_extension_.get()); |
| theme_sync_service_->OnThemeChanged(); |
| const syncer::SyncChangeList& changes = fake_change_processor_->changes(); |
| EXPECT_EQ(1u, changes.size()); |
| const sync_pb::ThemeSpecifics& change_specifics = |
| changes[0].sync_data().GetSpecifics().theme(); |
| EXPECT_TRUE(change_specifics.use_system_theme_by_default()); |
| } |
| |
| TEST_F(ThemeSyncableServiceTest, DistinctSystemTheme) { |
| fake_theme_service_->set_distinct_from_default_theme(true); |
| |
| // Initialize to use native theme. |
| fake_theme_service_->UseSystemTheme(); |
| fake_theme_service_->MarkClean(); |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.set_use_system_theme_by_default(true); |
| std::optional<syncer::ModelError> error = |
| theme_sync_service_->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor_.get()))); |
| EXPECT_FALSE(fake_theme_service_->is_dirty()); |
| |
| // Change to default theme and notify theme_sync_service_. |
| // use_system_theme_by_default bit should be false. |
| fake_theme_service_->UseDefaultTheme(); |
| theme_sync_service_->OnThemeChanged(); |
| syncer::SyncChangeList& changes = fake_change_processor_->changes(); |
| EXPECT_EQ(1u, changes.size()); |
| EXPECT_FALSE(changes[0] |
| .sync_data() |
| .GetSpecifics() |
| .theme() |
| .use_system_theme_by_default()); |
| |
| // Change to native theme and notify theme_sync_service_. |
| // use_system_theme_by_default bit should be true. |
| changes.clear(); |
| fake_theme_service_->UseSystemTheme(); |
| theme_sync_service_->OnThemeChanged(); |
| EXPECT_EQ(1u, changes.size()); |
| EXPECT_TRUE(changes[0] |
| .sync_data() |
| .GetSpecifics() |
| .theme() |
| .use_system_theme_by_default()); |
| } |
| |
| TEST_F(ThemeSyncableServiceTest, SystemThemeSameAsDefaultTheme) { |
| fake_theme_service_->set_distinct_from_default_theme(false); |
| |
| // Set up theme service to use default theme. |
| fake_theme_service_->UseDefaultTheme(); |
| |
| // Initialize to use custom theme with use_system_theme_by_default set true. |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.set_use_custom_theme(true); |
| theme_specifics.set_custom_theme_id(theme_extension_->id()); |
| theme_specifics.set_custom_theme_name(kCustomThemeName); |
| theme_specifics.set_custom_theme_update_url(kCustomThemeUrl); |
| theme_specifics.set_use_system_theme_by_default(true); |
| std::optional<syncer::ModelError> error = |
| theme_sync_service_->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor_.get()))); |
| EXPECT_EQ(fake_theme_service_->theme_extension(), theme_extension_.get()); |
| |
| // Change to default theme and notify theme_sync_service_. |
| // use_system_theme_by_default bit should be preserved. |
| fake_theme_service_->UseDefaultTheme(); |
| theme_sync_service_->OnThemeChanged(); |
| const syncer::SyncChangeList& changes = fake_change_processor_->changes(); |
| EXPECT_EQ(1u, changes.size()); |
| const sync_pb::ThemeSpecifics& change_specifics = |
| changes[0].sync_data().GetSpecifics().theme(); |
| EXPECT_FALSE(change_specifics.use_custom_theme()); |
| EXPECT_TRUE(change_specifics.use_system_theme_by_default()); |
| } |
| |
| TEST_F(ThemeSyncableServiceTest, GetThemePrefNameInMigrationIfFlagDisabled) { |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitAndDisableFeature(syncer::kMoveThemePrefsToSpecifics); |
| |
| // The syncing pref name is returned. |
| EXPECT_EQ(GetThemePrefNameInMigration(ThemePrefInMigration::kUserColor), |
| prefs::kUserColorDoNotUse); |
| } |
| |
| TEST_F(ThemeSyncableServiceTest, GetThemePrefNameInMigrationIfFlagEnabled) { |
| base::test::ScopedFeatureList feature_list( |
| syncer::kMoveThemePrefsToSpecifics); |
| |
| // The new non-syncing pref is returned. |
| EXPECT_EQ(GetThemePrefNameInMigration(ThemePrefInMigration::kUserColor), |
| prefs::kNonSyncingUserColorDoNotUse); |
| } |
| |
| // PolicyInstalledThemeTest ---------------------------------------------------- |
| |
| class PolicyInstalledThemeTest : public ThemeSyncableServiceTest { |
| extensions::mojom::ManifestLocation GetThemeLocation() override { |
| return extensions::mojom::ManifestLocation::kExternalPolicyDownload; |
| } |
| }; |
| |
| TEST_F(PolicyInstalledThemeTest, InstallThemeByPolicy) { |
| // Set up theme service to use custom theme that was installed by policy. |
| fake_theme_service_->SetTheme(theme_extension_.get()); |
| |
| syncer::SyncDataList data_list = |
| theme_sync_service_->GetAllSyncDataForTesting(syncer::THEMES); |
| |
| ASSERT_EQ(0u, data_list.size()); |
| } |
| |
| // RealThemeSyncableServiceTest ------------------------------------------------ |
| |
| // Uses the real `ThemeService` impl instead of the fake used by |
| // `ThemeSyncableServiceTest`, in order to more closely test production behavior |
| // and asserts. |
| class RealThemeSyncableServiceTest |
| : public extensions::ExtensionServiceTestBase { |
| protected: |
| void SetUp() override { |
| // Setting a matching update URL is necessary to make the test theme |
| // considered syncable. |
| extension_test_util::SetGalleryUpdateURL(GURL(kCustomThemeUrl)); |
| |
| // Trying to write the theme pak just produces error messages. |
| ThemeService::DisableThemePackForTesting(); |
| |
| extensions::ExtensionServiceTestBase::SetUp(); |
| InitializeExtensionService(ExtensionServiceInitParams()); |
| service_->Init(); |
| |
| theme_service_ = ThemeServiceFactory::GetForProfile(profile()); |
| |
| theme_sync_service_ = theme_service_->GetThemeSyncableService(); |
| ASSERT_TRUE(theme_sync_service_); |
| |
| fake_change_processor_ = |
| std::make_unique<syncer::FakeSyncChangeProcessor>(); |
| |
| // Create and add custom theme extension so the ThemeSyncableService can |
| // find it. |
| theme_extension_ = MakeThemeExtension( |
| base::FilePath(kExtensionFilePath), kCustomThemeId, kCustomThemeName, |
| extensions::mojom::ManifestLocation::kInternal, kCustomThemeUrl); |
| extensions::ExtensionPrefs::Get(profile())->AddGrantedPermissions( |
| theme_extension_->id(), extensions::PermissionSet()); |
| registrar()->AddExtension(theme_extension_); |
| ASSERT_EQ(1u, extensions::ExtensionRegistry::Get(profile()) |
| ->enabled_extensions() |
| .size()); |
| } |
| |
| ThemeService* theme_service() { return theme_service_; } |
| |
| ThemeSyncableService* theme_sync_service() { |
| return theme_sync_service_.get(); |
| } |
| |
| syncer::FakeSyncChangeProcessor* fake_change_processor() { |
| return fake_change_processor_.get(); |
| } |
| |
| const extensions::Extension* theme_extension() const { |
| return theme_extension_.get(); |
| } |
| |
| private: |
| raw_ptr<ThemeService> theme_service_; |
| raw_ptr<ThemeSyncableService> theme_sync_service_; |
| std::unique_ptr<syncer::FakeSyncChangeProcessor> fake_change_processor_; |
| scoped_refptr<extensions::Extension> theme_extension_; |
| }; |
| |
| // Regression test for crbug.com/1409996. |
| TEST_F(RealThemeSyncableServiceTest, ProcessSyncThemeChange_DisabledExtension) { |
| // Set up theme service to use custom theme. |
| { |
| test::ThemeServiceChangedWaiter waiter(theme_service()); |
| theme_service()->SetTheme(theme_extension()); |
| waiter.WaitForThemeChanged(); |
| } |
| |
| // The custom theme should be set and enabled. |
| EXPECT_TRUE(theme_service()->UsingExtensionTheme()); |
| EXPECT_EQ(theme_extension()->id(), theme_service()->GetThemeID()); |
| EXPECT_TRUE(registrar()->IsExtensionEnabled(theme_extension()->id())); |
| |
| // Now disable that theme by changing to an autogenerated theme. |
| { |
| test::ThemeServiceChangedWaiter waiter(theme_service()); |
| theme_service()->BuildAutogeneratedThemeFromColor(SkColorSetRGB(0, 0, 100)); |
| waiter.WaitForThemeChanged(); |
| } |
| |
| // The custom theme should no longer be set or enabled. |
| EXPECT_FALSE(theme_service()->UsingExtensionTheme()); |
| EXPECT_FALSE(registrar()->IsExtensionEnabled(theme_extension()->id())); |
| |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, syncer::SyncDataList(), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor())); |
| EXPECT_FALSE(error.has_value()) << error.value().message(); |
| |
| // Process a sync update that updates back to the custom theme. |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.set_use_custom_theme(true); |
| theme_specifics.set_custom_theme_id(theme_extension()->id()); |
| theme_specifics.set_custom_theme_name(kCustomThemeName); |
| theme_specifics.set_custom_theme_update_url(kCustomThemeUrl); |
| sync_pb::EntitySpecifics entity_specifics; |
| entity_specifics.mutable_theme()->CopyFrom(theme_specifics); |
| syncer::SyncChangeList change_list; |
| change_list.emplace_back( |
| FROM_HERE, syncer::SyncChange::ACTION_UPDATE, |
| syncer::SyncData::CreateRemoteData( |
| entity_specifics, syncer::ClientTagHash::FromHashed("unused"))); |
| { |
| test::ThemeServiceChangedWaiter waiter(theme_service()); |
| std::optional<syncer::ModelError> process_error = |
| theme_sync_service()->ProcessSyncChanges(FROM_HERE, change_list); |
| EXPECT_FALSE(process_error.has_value()) << process_error.value().message(); |
| waiter.WaitForThemeChanged(); |
| } |
| |
| // Ensure the custom theme has been re-set and re-enabled. |
| EXPECT_TRUE(theme_service()->UsingExtensionTheme()); |
| EXPECT_EQ(theme_extension()->id(), theme_service()->GetThemeID()); |
| EXPECT_TRUE(registrar()->IsExtensionEnabled(theme_extension()->id())); |
| } |
| |
| class ThemeSyncableServiceWithMigrationFlagDisabledTest |
| : public RealThemeSyncableServiceTest { |
| public: |
| ThemeSyncableServiceWithMigrationFlagDisabledTest() { |
| feature_list_.InitAndDisableFeature(syncer::kMoveThemePrefsToSpecifics); |
| } |
| |
| private: |
| base::test::ScopedFeatureList feature_list_; |
| }; |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagDisabledTest, |
| ShouldNotDownloadUserColorTheme) { |
| sync_pb::ThemeSpecifics theme_specifics; |
| sync_pb::ThemeSpecifics::UserColorTheme* user_color_theme = |
| theme_specifics.mutable_user_color_theme(); |
| user_color_theme->set_color(SK_ColorRED); |
| user_color_theme->set_browser_color_variant(BrowserColorVariantToProtoEnum( |
| ui::mojom::BrowserColorVariant::kTonalSpot)); |
| |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor())); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| EXPECT_EQ(theme_service()->GetUserColor(), std::nullopt); |
| EXPECT_NE(theme_service()->GetBrowserColorVariant(), |
| ui::mojom::BrowserColorVariant::kTonalSpot); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagDisabledTest, |
| ShouldNotUploadUserColorTheme) { |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, syncer::SyncDataList(), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor())); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| theme_service()->SetUserColorAndBrowserColorVariant( |
| SK_ColorRED, ui::mojom::BrowserColorVariant::kTonalSpot); |
| |
| const syncer::SyncChangeList& changes = fake_change_processor()->changes(); |
| ASSERT_GE(changes.size(), 0u); |
| EXPECT_FALSE( |
| changes.back().sync_data().GetSpecifics().theme().has_user_color_theme()); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagDisabledTest, |
| ShouldNotDownloadGrayscale) { |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.mutable_grayscale_theme_enabled(); |
| |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor())); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| EXPECT_FALSE(theme_service()->GetIsGrayscale()); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagDisabledTest, |
| ShouldNotUploadGrayscale) { |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, syncer::SyncDataList(), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor())); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| theme_service()->SetIsGrayscale(true); |
| |
| const syncer::SyncChangeList& changes = fake_change_processor()->changes(); |
| ASSERT_GE(changes.size(), 0u); |
| EXPECT_FALSE(changes.back() |
| .sync_data() |
| .GetSpecifics() |
| .theme() |
| .has_grayscale_theme_enabled()); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagDisabledTest, |
| ShouldNotDownloadBrowserColorScheme) { |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.set_browser_color_scheme( |
| BrowserColorSchemeToProtoEnum(ThemeService::BrowserColorScheme::kLight)); |
| |
| ASSERT_EQ(theme_service()->GetBrowserColorScheme(), |
| ThemeService::BrowserColorScheme::kSystem); |
| |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor())); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| EXPECT_EQ(theme_service()->GetBrowserColorScheme(), |
| ThemeService::BrowserColorScheme::kSystem); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagDisabledTest, |
| ShouldNotUploadBrowserColorScheme) { |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, syncer::SyncDataList(), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor())); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| theme_service()->SetBrowserColorScheme( |
| ThemeService::BrowserColorScheme::kLight); |
| |
| const syncer::SyncChangeList& changes = fake_change_processor()->changes(); |
| ASSERT_GE(changes.size(), 0u); |
| EXPECT_FALSE(changes.back() |
| .sync_data() |
| .GetSpecifics() |
| .theme() |
| .has_browser_color_scheme()); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagDisabledTest, |
| ShouldNotDownloadNtpBackground) { |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.mutable_ntp_background()->set_url(kTestUrl); |
| |
| ASSERT_EQ(theme_service()->GetBrowserColorScheme(), |
| ThemeService::BrowserColorScheme::kSystem); |
| |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor())); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| // TODO(crbug.com/356148174): Query NtpCustomBackgroundService for the |
| // background state instead of reading the pref directly. |
| EXPECT_FALSE(profile()->GetPrefs()->GetUserPrefValue( |
| prefs::kNonSyncingNtpCustomBackgroundDictDoNotUse)); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagDisabledTest, |
| ShouldNotUploadNtpBackground) { |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, syncer::SyncDataList(), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor())); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| { |
| ScopedDictPrefUpdate dict( |
| profile()->GetPrefs(), |
| prefs::kNonSyncingNtpCustomBackgroundDictDoNotUse); |
| dict->Set(kNtpCustomBackgroundURL, kTestUrl); |
| } |
| |
| const syncer::SyncChangeList& changes = fake_change_processor()->changes(); |
| ASSERT_GE(changes.size(), 0u); |
| EXPECT_FALSE( |
| changes.back().sync_data().GetSpecifics().theme().has_ntp_background()); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagDisabledTest, |
| ShouldApplyDefaultThemeFromOldSpecificsUponProcessSyncChanges) { |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, syncer::SyncDataList(), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor())); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| theme_service()->BuildAutogeneratedThemeFromColor(SK_ColorRED); |
| |
| ASSERT_FALSE(theme_sync_service()->ProcessSyncChanges( |
| FROM_HERE, MakeThemeChangeList(sync_pb::ThemeSpecifics()))); |
| |
| EXPECT_TRUE(theme_service()->UsingDefaultTheme()); |
| EXPECT_FALSE(theme_service()->UsingAutogeneratedTheme()); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagDisabledTest, |
| ShouldNotCopyFromNonSyncingPrefsUponThemeChanged) { |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, syncer::SyncDataList(), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor())); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| theme_service()->SetUserColorAndBrowserColorVariant( |
| SK_ColorRED, ui::mojom::BrowserColorVariant::kTonalSpot); |
| |
| // Verify that the syncing prefs are used. |
| EXPECT_EQ(profile()->GetPrefs()->GetInteger(prefs::kUserColorDoNotUse), |
| static_cast<int>(SK_ColorRED)); |
| EXPECT_EQ( |
| profile()->GetPrefs()->GetInteger(prefs::kBrowserColorVariantDoNotUse), |
| static_cast<int>(ui::mojom::BrowserColorVariant::kTonalSpot)); |
| |
| // Verify that the new non-syncing prefs are empty. |
| EXPECT_FALSE(profile()->GetPrefs()->GetUserPrefValue( |
| prefs::kNonSyncingUserColorDoNotUse)); |
| EXPECT_FALSE(profile()->GetPrefs()->GetUserPrefValue( |
| prefs::kNonSyncingBrowserColorVariantDoNotUse)); |
| } |
| |
| class ThemeSyncableServiceWithMigrationFlagEnabledTest |
| : public RealThemeSyncableServiceTest { |
| public: |
| ThemeSyncableServiceWithMigrationFlagEnabledTest() |
| : feature_list_(syncer::kMoveThemePrefsToSpecifics) {} |
| |
| private: |
| base::test::ScopedFeatureList feature_list_; |
| }; |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagEnabledTest, |
| ShouldDownloadUserColorTheme) { |
| sync_pb::ThemeSpecifics theme_specifics; |
| sync_pb::ThemeSpecifics::UserColorTheme* user_color_theme = |
| theme_specifics.mutable_user_color_theme(); |
| user_color_theme->set_color(SK_ColorRED); |
| user_color_theme->set_browser_color_variant(BrowserColorVariantToProtoEnum( |
| ui::mojom::BrowserColorVariant::kTonalSpot)); |
| |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor())); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| EXPECT_EQ(theme_service()->GetThemeID(), ThemeService::kUserColorThemeID); |
| EXPECT_EQ(theme_service()->GetUserColor(), SK_ColorRED); |
| EXPECT_EQ(theme_service()->GetBrowserColorVariant(), |
| ui::mojom::BrowserColorVariant::kTonalSpot); |
| EXPECT_FALSE(theme_service()->UsingExtensionTheme()); |
| EXPECT_FALSE(theme_service()->UsingAutogeneratedTheme()); |
| EXPECT_FALSE(theme_service()->GetIsGrayscale()); |
| EXPECT_EQ(theme_service()->GetBrowserColorScheme(), |
| ThemeService::BrowserColorScheme::kSystem); |
| |
| // Verify that the new prefs are used. |
| EXPECT_EQ( |
| profile()->GetPrefs()->GetInteger(prefs::kNonSyncingUserColorDoNotUse), |
| static_cast<int>(SK_ColorRED)); |
| EXPECT_EQ(profile()->GetPrefs()->GetInteger( |
| prefs::kNonSyncingBrowserColorVariantDoNotUse), |
| static_cast<int>(ui::mojom::BrowserColorVariant::kTonalSpot)); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagEnabledTest, |
| ShouldUploadUserColorTheme) { |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, syncer::SyncDataList(), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor())); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| theme_service()->SetUserColorAndBrowserColorVariant( |
| SK_ColorRED, ui::mojom::BrowserColorVariant::kTonalSpot); |
| |
| const syncer::SyncChangeList& changes = fake_change_processor()->changes(); |
| ASSERT_GE(changes.size(), 0u); |
| const sync_pb::ThemeSpecifics& change_specifics = |
| changes.back().sync_data().GetSpecifics().theme(); |
| |
| EXPECT_FALSE(change_specifics.use_custom_theme()); |
| ASSERT_TRUE(change_specifics.has_user_color_theme()); |
| EXPECT_EQ(SK_ColorRED, change_specifics.user_color_theme().color()); |
| EXPECT_EQ(ui::mojom::BrowserColorVariant::kTonalSpot, |
| ProtoEnumToBrowserColorVariant( |
| change_specifics.user_color_theme().browser_color_variant())); |
| EXPECT_EQ( |
| ThemeService::BrowserColorScheme::kSystem, |
| ProtoEnumToBrowserColorScheme(change_specifics.browser_color_scheme())); |
| |
| // Verify that the old prefs are updated. |
| EXPECT_EQ(profile()->GetPrefs()->GetInteger(prefs::kUserColorDoNotUse), |
| static_cast<int>(SK_ColorRED)); |
| EXPECT_EQ( |
| profile()->GetPrefs()->GetInteger(prefs::kBrowserColorVariantDoNotUse), |
| static_cast<int>(ui::mojom::BrowserColorVariant::kTonalSpot)); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagEnabledTest, |
| ShouldDownloadGrayscale) { |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.mutable_grayscale_theme_enabled(); |
| |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor())); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| EXPECT_TRUE(theme_service()->GetIsGrayscale()); |
| EXPECT_EQ(theme_service()->GetThemeID(), ""); |
| EXPECT_EQ(theme_service()->GetUserColor(), std::nullopt); |
| EXPECT_EQ(theme_service()->GetBrowserColorVariant(), |
| ui::mojom::BrowserColorVariant::kSystem); |
| EXPECT_FALSE(theme_service()->UsingExtensionTheme()); |
| EXPECT_FALSE(theme_service()->UsingAutogeneratedTheme()); |
| EXPECT_EQ(theme_service()->GetBrowserColorScheme(), |
| ThemeService::BrowserColorScheme::kSystem); |
| |
| // Verify that the new pref is used. |
| EXPECT_TRUE(profile()->GetPrefs()->GetBoolean( |
| prefs::kNonSyncingGrayscaleThemeEnabledDoNotUse)); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagEnabledTest, |
| ShouldUploadGrayscale) { |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, syncer::SyncDataList(), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor())); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| theme_service()->SetIsGrayscale(true); |
| |
| const syncer::SyncChangeList& changes = fake_change_processor()->changes(); |
| ASSERT_GE(changes.size(), 0u); |
| const sync_pb::ThemeSpecifics& change_specifics = |
| changes.back().sync_data().GetSpecifics().theme(); |
| EXPECT_FALSE(change_specifics.use_custom_theme()); |
| EXPECT_TRUE(change_specifics.has_grayscale_theme_enabled()); |
| EXPECT_EQ( |
| ThemeService::BrowserColorScheme::kSystem, |
| ProtoEnumToBrowserColorScheme(change_specifics.browser_color_scheme())); |
| |
| // Verify that the old pref is updated. |
| EXPECT_TRUE( |
| profile()->GetPrefs()->GetBoolean(prefs::kGrayscaleThemeEnabledDoNotUse)); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagEnabledTest, |
| ShouldDownloadBrowserColorScheme) { |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.set_browser_color_scheme( |
| BrowserColorSchemeToProtoEnum(ThemeService::BrowserColorScheme::kLight)); |
| |
| ASSERT_EQ(theme_service()->GetBrowserColorScheme(), |
| ThemeService::BrowserColorScheme::kSystem); |
| |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor())); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| EXPECT_EQ(theme_service()->GetBrowserColorScheme(), |
| ThemeService::BrowserColorScheme::kLight); |
| EXPECT_TRUE(theme_service()->UsingDefaultTheme()); |
| EXPECT_EQ(theme_service()->GetThemeID(), ""); |
| EXPECT_EQ(theme_service()->GetUserColor(), std::nullopt); |
| EXPECT_EQ(theme_service()->GetBrowserColorVariant(), |
| ui::mojom::BrowserColorVariant::kSystem); |
| EXPECT_FALSE(theme_service()->GetIsGrayscale()); |
| EXPECT_FALSE(theme_service()->UsingExtensionTheme()); |
| EXPECT_FALSE(theme_service()->UsingAutogeneratedTheme()); |
| |
| // Verify that the new pref is used. |
| EXPECT_EQ(profile()->GetPrefs()->GetInteger( |
| prefs::kNonSyncingBrowserColorSchemeDoNotUse), |
| static_cast<int>(ThemeService::BrowserColorScheme::kLight)); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagEnabledTest, |
| ShouldUploadBrowserColorScheme) { |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, syncer::SyncDataList(), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor())); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| theme_service()->SetBrowserColorScheme( |
| ThemeService::BrowserColorScheme::kLight); |
| |
| const syncer::SyncChangeList& changes = fake_change_processor()->changes(); |
| ASSERT_GE(changes.size(), 0u); |
| const sync_pb::ThemeSpecifics& change_specifics = |
| changes.back().sync_data().GetSpecifics().theme(); |
| |
| EXPECT_EQ( |
| ThemeService::BrowserColorScheme::kLight, |
| ProtoEnumToBrowserColorScheme(change_specifics.browser_color_scheme())); |
| EXPECT_FALSE(change_specifics.use_custom_theme()); |
| EXPECT_FALSE(change_specifics.has_user_color_theme()); |
| EXPECT_FALSE(change_specifics.has_autogenerated_color_theme()); |
| EXPECT_FALSE(change_specifics.has_grayscale_theme_enabled()); |
| |
| // Verify that the old pref is updated. |
| EXPECT_EQ( |
| profile()->GetPrefs()->GetInteger(prefs::kBrowserColorSchemeDoNotUse), |
| static_cast<int>(ThemeService::BrowserColorScheme::kLight)); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagEnabledTest, |
| ShouldDownloadNtpBackground) { |
| sync_pb::ThemeSpecifics theme_specifics; |
| sync_pb::ThemeSpecifics::NtpCustomBackground* ntp_background = |
| theme_specifics.mutable_ntp_background(); |
| ntp_background->set_url(kTestUrl); |
| ntp_background->set_attribution_line_1("attribution_line_1"); |
| ntp_background->set_attribution_line_2("attribution_line_2"); |
| ntp_background->set_attribution_action_url("attribution_action_url"); |
| ntp_background->set_collection_id("collection_id"); |
| ntp_background->set_resume_token("resume_token"); |
| ntp_background->set_refresh_timestamp_unix_epoch_seconds(1234567890); |
| ntp_background->set_main_color(SK_ColorRED); |
| |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor())); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| base::Value::Dict expected_value = |
| base::Value::Dict() |
| .Set(kNtpCustomBackgroundURL, kTestUrl) |
| .Set(kNtpCustomBackgroundAttributionLine1, "attribution_line_1") |
| .Set(kNtpCustomBackgroundAttributionLine2, "attribution_line_2") |
| .Set(kNtpCustomBackgroundAttributionActionURL, |
| "attribution_action_url") |
| .Set(kNtpCustomBackgroundCollectionId, "collection_id") |
| .Set(kNtpCustomBackgroundResumeToken, "resume_token") |
| .Set(kNtpCustomBackgroundRefreshTimestamp, |
| static_cast<int>(1234567890)) |
| .Set(kNtpCustomBackgroundMainColor, static_cast<int>(SK_ColorRED)); |
| const base::Value* value = profile()->GetPrefs()->GetUserPrefValue( |
| prefs::kNonSyncingNtpCustomBackgroundDictDoNotUse); |
| ASSERT_TRUE(value); |
| EXPECT_EQ(*value, expected_value); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagEnabledTest, |
| ShouldUploadNtpBackground) { |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, syncer::SyncDataList(), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor())); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| base::Value::Dict new_value = |
| base::Value::Dict() |
| .Set(kNtpCustomBackgroundURL, kTestUrl) |
| .Set(kNtpCustomBackgroundAttributionLine1, "attribution_line_1") |
| .Set(kNtpCustomBackgroundAttributionLine2, "attribution_line_2") |
| .Set(kNtpCustomBackgroundAttributionActionURL, |
| "attribution_action_url") |
| .Set(kNtpCustomBackgroundCollectionId, "collection_id") |
| .Set(kNtpCustomBackgroundResumeToken, "resume_token") |
| .Set(kNtpCustomBackgroundRefreshTimestamp, |
| static_cast<int>(1234567890)) |
| .Set(kNtpCustomBackgroundMainColor, static_cast<int>(SK_ColorRED)); |
| |
| profile()->GetPrefs()->Set(prefs::kNonSyncingNtpCustomBackgroundDictDoNotUse, |
| base::Value(new_value.Clone())); |
| |
| const syncer::SyncChangeList& changes = fake_change_processor()->changes(); |
| ASSERT_GE(changes.size(), 0u); |
| const sync_pb::ThemeSpecifics::NtpCustomBackground& ntp_background = |
| changes.back().sync_data().GetSpecifics().theme().ntp_background(); |
| EXPECT_EQ(ntp_background.url(), kTestUrl); |
| EXPECT_EQ(ntp_background.attribution_line_1(), "attribution_line_1"); |
| EXPECT_EQ(ntp_background.attribution_line_2(), "attribution_line_2"); |
| EXPECT_EQ(ntp_background.attribution_action_url(), "attribution_action_url"); |
| EXPECT_EQ(ntp_background.collection_id(), "collection_id"); |
| EXPECT_EQ(ntp_background.resume_token(), "resume_token"); |
| EXPECT_EQ(ntp_background.refresh_timestamp_unix_epoch_seconds(), 1234567890); |
| EXPECT_EQ(ntp_background.main_color(), SK_ColorRED); |
| |
| // Verify that the old pref is updated. |
| EXPECT_THAT(profile()->GetPrefs()->GetUserPrefValue( |
| prefs::kNtpCustomBackgroundDictDoNotUse), |
| DictionaryValuePtrHas(kNtpCustomBackgroundURL, kTestUrl)); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagEnabledTest, |
| ShouldNotUploadNtpBackgroundIfSetFromLocalResource) { |
| base::Value::Dict new_value = |
| base::Value::Dict() |
| .Set(kNtpCustomBackgroundURL, kTestUrl) |
| .Set(kNtpCustomBackgroundAttributionLine1, "attribution_line_1") |
| .Set(kNtpCustomBackgroundAttributionLine2, "attribution_line_2") |
| .Set(kNtpCustomBackgroundAttributionActionURL, |
| "attribution_action_url") |
| .Set(kNtpCustomBackgroundCollectionId, "collection_id") |
| .Set(kNtpCustomBackgroundResumeToken, "resume_token") |
| .Set(kNtpCustomBackgroundRefreshTimestamp, |
| static_cast<int>(1234567890)) |
| .Set(kNtpCustomBackgroundMainColor, static_cast<int>(SK_ColorRED)); |
| |
| profile()->GetPrefs()->Set(prefs::kNonSyncingNtpCustomBackgroundDictDoNotUse, |
| base::Value(new_value.Clone())); |
| |
| // Mark ntp background set from local resource. |
| profile()->GetPrefs()->SetBoolean(prefs::kNtpCustomBackgroundLocalToDevice, |
| true); |
| |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, syncer::SyncDataList(), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor())); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| theme_sync_service()->OnThemeChanged(); |
| |
| const syncer::SyncChangeList& changes = fake_change_processor()->changes(); |
| ASSERT_GE(changes.size(), 0u); |
| EXPECT_FALSE( |
| changes.back().sync_data().GetSpecifics().theme().has_ntp_background()); |
| |
| // Verify that the old pref is not updated. |
| EXPECT_FALSE(profile()->GetPrefs()->GetUserPrefValue( |
| prefs::kNtpCustomBackgroundDictDoNotUse)); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagEnabledTest, |
| ShouldApplyRemoteNtpBackgroundChange) { |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, syncer::SyncDataList(), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor())); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| EXPECT_FALSE(profile()->GetPrefs()->GetUserPrefValue( |
| prefs::kNonSyncingNtpCustomBackgroundDictDoNotUse)); |
| |
| // Process change with background set. |
| { |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.mutable_ntp_background()->set_url(kTestUrl); |
| |
| ASSERT_FALSE(theme_sync_service()->ProcessSyncChanges( |
| FROM_HERE, MakeThemeChangeList(theme_specifics))); |
| } |
| |
| EXPECT_THAT(profile()->GetPrefs()->GetUserPrefValue( |
| prefs::kNonSyncingNtpCustomBackgroundDictDoNotUse), |
| DictionaryValuePtrHas(kNtpCustomBackgroundURL, kTestUrl)); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagEnabledTest, |
| ShouldNotApplyEmptyRemoteNtpBackgroundChange) { |
| { |
| ScopedDictPrefUpdate dict( |
| profile()->GetPrefs(), |
| prefs::kNonSyncingNtpCustomBackgroundDictDoNotUse); |
| dict->Set(kNtpCustomBackgroundURL, kTestUrl); |
| } |
| |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, syncer::SyncDataList(), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor())); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| EXPECT_THAT(profile()->GetPrefs()->GetUserPrefValue( |
| prefs::kNonSyncingNtpCustomBackgroundDictDoNotUse), |
| DictionaryValuePtrHas(kNtpCustomBackgroundURL, kTestUrl)); |
| |
| // Process change with empty background. |
| { |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.mutable_ntp_background(); |
| ASSERT_FALSE(theme_sync_service()->ProcessSyncChanges( |
| FROM_HERE, MakeThemeChangeList(theme_specifics))); |
| } |
| |
| // Removed as the default theme is applied. |
| EXPECT_FALSE(profile()->GetPrefs()->GetUserPrefValue( |
| prefs::kNonSyncingNtpCustomBackgroundDictDoNotUse)); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagEnabledTest, |
| ShouldNotApplyMissingRemoteNtpBackgroundChange) { |
| { |
| ScopedDictPrefUpdate dict( |
| profile()->GetPrefs(), |
| prefs::kNonSyncingNtpCustomBackgroundDictDoNotUse); |
| dict->Set(kNtpCustomBackgroundURL, kTestUrl); |
| } |
| |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, syncer::SyncDataList(), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor())); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| EXPECT_THAT(profile()->GetPrefs()->GetUserPrefValue( |
| prefs::kNonSyncingNtpCustomBackgroundDictDoNotUse), |
| DictionaryValuePtrHas(kNtpCustomBackgroundURL, kTestUrl)); |
| |
| // Process change with background not set. |
| { |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.set_browser_color_scheme( |
| sync_pb::ThemeSpecifics_BrowserColorScheme_SYSTEM); |
| ASSERT_FALSE(theme_sync_service()->ProcessSyncChanges( |
| FROM_HERE, MakeThemeChangeList(theme_specifics))); |
| } |
| |
| // Removed as the default theme is applied. |
| EXPECT_FALSE(profile()->GetPrefs()->GetUserPrefValue( |
| prefs::kNonSyncingNtpCustomBackgroundDictDoNotUse)); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagEnabledTest, |
| ShouldApplyRemoteBrowserColorSchemeChanges) { |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, syncer::SyncDataList(), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor())); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| EXPECT_EQ(theme_service()->GetBrowserColorScheme(), |
| ThemeService::BrowserColorScheme::kSystem); |
| |
| // Process change with user color set. |
| { |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.set_browser_color_scheme(BrowserColorSchemeToProtoEnum( |
| ThemeService::BrowserColorScheme::kLight)); |
| |
| ASSERT_FALSE(theme_sync_service()->ProcessSyncChanges( |
| FROM_HERE, MakeThemeChangeList(theme_specifics))); |
| } |
| |
| EXPECT_EQ(theme_service()->GetBrowserColorScheme(), |
| ThemeService::BrowserColorScheme::kLight); |
| |
| // Process change with user color not set. |
| { |
| sync_pb::ThemeSpecifics theme_specifics; |
| // `theme_specifics` has to be non-default to be processed. |
| theme_specifics.mutable_autogenerated_color_theme()->set_color(SK_ColorRED); |
| ASSERT_FALSE(theme_sync_service()->ProcessSyncChanges( |
| FROM_HERE, MakeThemeChangeList(theme_specifics))); |
| } |
| |
| // No effect. |
| EXPECT_EQ(theme_service()->GetBrowserColorScheme(), |
| ThemeService::BrowserColorScheme::kLight); |
| |
| // Process change with user color set to default. |
| { |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.set_browser_color_scheme(BrowserColorSchemeToProtoEnum( |
| ThemeService::BrowserColorScheme::kSystem)); |
| |
| ASSERT_FALSE(theme_sync_service()->ProcessSyncChanges( |
| FROM_HERE, MakeThemeChangeList(theme_specifics))); |
| } |
| |
| // Changes to default. |
| EXPECT_EQ(theme_service()->GetBrowserColorScheme(), |
| ThemeService::BrowserColorScheme::kSystem); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagEnabledTest, |
| ShouldPriortizeExtensionThemeOverUserColor) { |
| sync_pb::ThemeSpecifics theme_specifics; |
| // Set all fields (all the different theme types). |
| theme_specifics.set_use_custom_theme(true); |
| theme_specifics.set_custom_theme_id(theme_extension()->id()); |
| theme_specifics.set_custom_theme_name(kCustomThemeName); |
| theme_specifics.set_custom_theme_update_url(kCustomThemeUrl); |
| |
| sync_pb::ThemeSpecifics::UserColorTheme* user_color_theme = |
| theme_specifics.mutable_user_color_theme(); |
| user_color_theme->set_color(SK_ColorRED); |
| user_color_theme->set_browser_color_variant(BrowserColorVariantToProtoEnum( |
| ui::mojom::BrowserColorVariant::kTonalSpot)); |
| |
| theme_specifics.set_browser_color_scheme( |
| BrowserColorSchemeToProtoEnum(ThemeService::BrowserColorScheme::kLight)); |
| |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor()))); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| EXPECT_TRUE(base::test::RunUntil( |
| [&]() { return theme_service()->UsingExtensionTheme(); })); |
| EXPECT_FALSE(theme_service()->UsingAutogeneratedTheme()); |
| EXPECT_NE(theme_service()->GetThemeID(), ThemeService::kUserColorThemeID); |
| EXPECT_EQ(theme_service()->GetUserColor(), std::nullopt); |
| EXPECT_NE(theme_service()->GetBrowserColorVariant(), |
| ui::mojom::BrowserColorVariant::kTonalSpot); |
| EXPECT_FALSE(theme_service()->GetIsGrayscale()); |
| // Browser color scheme is still applied. |
| EXPECT_EQ(theme_service()->GetBrowserColorScheme(), |
| ThemeService::BrowserColorScheme::kLight); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagEnabledTest, |
| ShouldPriortizeExtensionThemeOverAutogeneratedTheme) { |
| sync_pb::ThemeSpecifics theme_specifics; |
| // Set all fields (all the different theme types). |
| theme_specifics.set_use_custom_theme(true); |
| theme_specifics.set_custom_theme_id(theme_extension()->id()); |
| theme_specifics.set_custom_theme_name(kCustomThemeName); |
| theme_specifics.set_custom_theme_update_url(kCustomThemeUrl); |
| theme_specifics.mutable_autogenerated_color_theme()->set_color(SK_ColorBLUE); |
| theme_specifics.set_browser_color_scheme( |
| BrowserColorSchemeToProtoEnum(ThemeService::BrowserColorScheme::kLight)); |
| |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor()))); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| EXPECT_TRUE(base::test::RunUntil( |
| [&]() { return theme_service()->UsingExtensionTheme(); })); |
| EXPECT_FALSE(theme_service()->UsingAutogeneratedTheme()); |
| EXPECT_NE(theme_service()->GetThemeID(), ThemeService::kAutogeneratedThemeID); |
| EXPECT_EQ(theme_service()->GetUserColor(), std::nullopt); |
| EXPECT_FALSE(theme_service()->GetIsGrayscale()); |
| // Browser color scheme is still applied. |
| EXPECT_EQ(theme_service()->GetBrowserColorScheme(), |
| ThemeService::BrowserColorScheme::kLight); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagEnabledTest, |
| ShouldPriortizeExtensionThemeOverGrayscale) { |
| sync_pb::ThemeSpecifics theme_specifics; |
| // Set all fields (all the different theme types). |
| theme_specifics.set_use_custom_theme(true); |
| theme_specifics.set_custom_theme_id(theme_extension()->id()); |
| theme_specifics.set_custom_theme_name(kCustomThemeName); |
| theme_specifics.set_custom_theme_update_url(kCustomThemeUrl); |
| theme_specifics.mutable_grayscale_theme_enabled(); |
| theme_specifics.set_browser_color_scheme( |
| BrowserColorSchemeToProtoEnum(ThemeService::BrowserColorScheme::kLight)); |
| |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor()))); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| EXPECT_TRUE(base::test::RunUntil( |
| [&]() { return theme_service()->UsingExtensionTheme(); })); |
| EXPECT_FALSE(theme_service()->GetIsGrayscale()); |
| EXPECT_FALSE(theme_service()->UsingAutogeneratedTheme()); |
| EXPECT_EQ(theme_service()->GetUserColor(), std::nullopt); |
| EXPECT_EQ(theme_service()->GetBrowserColorVariant(), |
| ui::mojom::BrowserColorVariant::kSystem); |
| // Browser color scheme is still applied. |
| EXPECT_EQ(theme_service()->GetBrowserColorScheme(), |
| ThemeService::BrowserColorScheme::kLight); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagEnabledTest, |
| ShouldPrioritizeExtensionThemeInAreThemeSpecificsEquivalent) { |
| sync_pb::ThemeSpecifics a, b; |
| a.set_use_custom_theme(true); |
| a.set_browser_color_scheme( |
| BrowserColorSchemeToProtoEnum(ThemeService::BrowserColorScheme::kLight)); |
| a.mutable_autogenerated_color_theme()->set_color(SK_ColorBLUE); |
| a.set_use_system_theme_by_default(true); |
| |
| b.set_use_custom_theme(true); |
| b.set_browser_color_scheme( |
| BrowserColorSchemeToProtoEnum(ThemeService::BrowserColorScheme::kDark)); |
| b.mutable_grayscale_theme_enabled(); |
| b.set_use_system_theme_by_default(false); |
| |
| EXPECT_TRUE(ThemeSyncableService::AreThemeSpecificsEquivalent(a, b, true)); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagEnabledTest, |
| ShouldConsiderBrowserColorSchemeInAreThemeSpecificsEquivalent) { |
| sync_pb::ThemeSpecifics a, b; |
| a.set_use_custom_theme(false); |
| a.set_browser_color_scheme( |
| BrowserColorSchemeToProtoEnum(ThemeService::BrowserColorScheme::kLight)); |
| a.mutable_autogenerated_color_theme()->set_color(SK_ColorBLUE); |
| a.set_use_system_theme_by_default(true); |
| |
| b = a; |
| b.mutable_autogenerated_color_theme()->set_color(SK_ColorRED); |
| EXPECT_FALSE(ThemeSyncableService::AreThemeSpecificsEquivalent(a, b, false)); |
| |
| b.mutable_autogenerated_color_theme()->set_color(SK_ColorRED); |
| b.set_browser_color_scheme( |
| BrowserColorSchemeToProtoEnum(ThemeService::BrowserColorScheme::kDark)); |
| // AreThemeSpecificsEquivalent returns false even though only the browser |
| // color scheme differs. |
| EXPECT_FALSE(ThemeSyncableService::AreThemeSpecificsEquivalent(a, b, false)); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagEnabledTest, |
| ShouldConsiderNtpBackgroundInAreThemeSpecificsEquivalent) { |
| sync_pb::ThemeSpecifics a, b; |
| a.set_use_custom_theme(false); |
| a.mutable_autogenerated_color_theme()->set_color(SK_ColorBLUE); |
| a.mutable_ntp_background()->set_url(kTestUrl); |
| |
| b = a; |
| |
| sync_pb::ThemeSpecifics::NtpCustomBackground* background = |
| b.mutable_ntp_background(); |
| |
| EXPECT_TRUE(ThemeSyncableService::AreThemeSpecificsEquivalent(a, b, false)); |
| |
| // Set a different url. |
| background->set_url("https://www.bar.com"); |
| EXPECT_FALSE(ThemeSyncableService::AreThemeSpecificsEquivalent(a, b, false)); |
| |
| // Set a different collection id. |
| background->set_url(kTestUrl); |
| background->set_collection_id("collection_id"); |
| EXPECT_FALSE(ThemeSyncableService::AreThemeSpecificsEquivalent(a, b, false)); |
| |
| // Set a different main color. |
| background->clear_collection_id(); |
| background->set_main_color(SK_ColorRED); |
| EXPECT_FALSE(ThemeSyncableService::AreThemeSpecificsEquivalent(a, b, false)); |
| |
| // Set a different refresh timestamp. |
| background->clear_main_color(); |
| background->set_refresh_timestamp_unix_epoch_seconds(1234567890); |
| EXPECT_FALSE(ThemeSyncableService::AreThemeSpecificsEquivalent(a, b, false)); |
| |
| // Set a different resume token. |
| background->clear_refresh_timestamp_unix_epoch_seconds(); |
| background->set_resume_token("resume_token"); |
| EXPECT_FALSE(ThemeSyncableService::AreThemeSpecificsEquivalent(a, b, false)); |
| |
| // Set a different attribution action url. |
| background->clear_resume_token(); |
| background->set_attribution_action_url(kTestUrl); |
| EXPECT_FALSE(ThemeSyncableService::AreThemeSpecificsEquivalent(a, b, false)); |
| |
| // Set a different attribution line 1. |
| background->clear_attribution_action_url(); |
| background->set_attribution_line_1("attribution_line_1"); |
| EXPECT_FALSE(ThemeSyncableService::AreThemeSpecificsEquivalent(a, b, false)); |
| |
| // Set a different attribution line 2. |
| background->clear_attribution_line_1(); |
| background->set_attribution_line_2("attribution_line_2"); |
| EXPECT_FALSE(ThemeSyncableService::AreThemeSpecificsEquivalent(a, b, false)); |
| |
| background->clear_attribution_line_2(); |
| ASSERT_TRUE(ThemeSyncableService::AreThemeSpecificsEquivalent(a, b, false)); |
| |
| // Remove the ntp background. |
| b.clear_ntp_background(); |
| EXPECT_FALSE(ThemeSyncableService::AreThemeSpecificsEquivalent(a, b, false)); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagEnabledTest, |
| ShouldApplyBrowserColorSchemeWithUserColorTheme) { |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.set_use_custom_theme(false); |
| theme_specifics.set_browser_color_scheme( |
| BrowserColorSchemeToProtoEnum(ThemeService::BrowserColorScheme::kLight)); |
| sync_pb::ThemeSpecifics::UserColorTheme* user_color_theme = |
| theme_specifics.mutable_user_color_theme(); |
| user_color_theme->set_color(SK_ColorRED); |
| user_color_theme->set_browser_color_variant(BrowserColorVariantToProtoEnum( |
| ui::mojom::BrowserColorVariant::kTonalSpot)); |
| |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor()))); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| EXPECT_FALSE(theme_service()->UsingExtensionTheme()); |
| EXPECT_FALSE(theme_service()->UsingAutogeneratedTheme()); |
| EXPECT_FALSE(theme_service()->GetIsGrayscale()); |
| EXPECT_EQ(theme_service()->GetThemeID(), ThemeService::kUserColorThemeID); |
| EXPECT_EQ(theme_service()->GetUserColor(), SK_ColorRED); |
| EXPECT_EQ(theme_service()->GetBrowserColorVariant(), |
| ui::mojom::BrowserColorVariant::kTonalSpot); |
| EXPECT_EQ(theme_service()->GetBrowserColorScheme(), |
| ThemeService::BrowserColorScheme::kLight); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagEnabledTest, |
| ShouldApplyBrowserColorSchemeWithGrayscale) { |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.set_use_custom_theme(false); |
| theme_specifics.mutable_grayscale_theme_enabled(); |
| theme_specifics.set_browser_color_scheme( |
| BrowserColorSchemeToProtoEnum(ThemeService::BrowserColorScheme::kLight)); |
| |
| // Start syncing. |
| test::ThemeServiceChangedWaiter waiter(theme_service()); |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor()))); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| EXPECT_FALSE(theme_service()->UsingExtensionTheme()); |
| EXPECT_FALSE(theme_service()->UsingAutogeneratedTheme()); |
| EXPECT_EQ(theme_service()->GetThemeID(), ""); |
| EXPECT_EQ(theme_service()->GetUserColor(), std::nullopt); |
| EXPECT_EQ(theme_service()->GetBrowserColorVariant(), |
| ui::mojom::BrowserColorVariant::kSystem); |
| EXPECT_TRUE(theme_service()->GetIsGrayscale()); |
| EXPECT_EQ(theme_service()->GetBrowserColorScheme(), |
| ThemeService::BrowserColorScheme::kLight); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagEnabledTest, |
| ShouldApplyBrowserColorSchemeWithAutogeneratedTheme) { |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.set_use_custom_theme(false); |
| theme_specifics.mutable_autogenerated_color_theme()->set_color(SK_ColorBLUE); |
| theme_specifics.set_browser_color_scheme( |
| BrowserColorSchemeToProtoEnum(ThemeService::BrowserColorScheme::kLight)); |
| |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor()))); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| EXPECT_FALSE(theme_service()->UsingExtensionTheme()); |
| EXPECT_TRUE(theme_service()->UsingAutogeneratedTheme()); |
| EXPECT_EQ(theme_service()->GetAutogeneratedThemeColor(), SK_ColorBLUE); |
| EXPECT_EQ(theme_service()->GetThemeID(), ThemeService::kAutogeneratedThemeID); |
| EXPECT_EQ(theme_service()->GetUserColor(), std::nullopt); |
| EXPECT_EQ(theme_service()->GetBrowserColorVariant(), |
| ui::mojom::BrowserColorVariant::kSystem); |
| EXPECT_FALSE(theme_service()->GetIsGrayscale()); |
| EXPECT_EQ(theme_service()->GetBrowserColorScheme(), |
| ThemeService::BrowserColorScheme::kLight); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagEnabledTest, |
| ShouldApplyNtpBackgroundWithUserColorTheme) { |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.set_use_custom_theme(false); |
| theme_specifics.mutable_ntp_background()->set_url(kTestUrl); |
| sync_pb::ThemeSpecifics::UserColorTheme* user_color_theme = |
| theme_specifics.mutable_user_color_theme(); |
| user_color_theme->set_color(SK_ColorRED); |
| user_color_theme->set_browser_color_variant(BrowserColorVariantToProtoEnum( |
| ui::mojom::BrowserColorVariant::kTonalSpot)); |
| |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor()))); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| EXPECT_FALSE(theme_service()->UsingExtensionTheme()); |
| EXPECT_FALSE(theme_service()->UsingAutogeneratedTheme()); |
| EXPECT_FALSE(theme_service()->GetIsGrayscale()); |
| EXPECT_EQ(theme_service()->GetThemeID(), ThemeService::kUserColorThemeID); |
| EXPECT_EQ(theme_service()->GetUserColor(), SK_ColorRED); |
| EXPECT_EQ(theme_service()->GetBrowserColorVariant(), |
| ui::mojom::BrowserColorVariant::kTonalSpot); |
| EXPECT_THAT(profile()->GetPrefs()->GetUserPrefValue( |
| prefs::kNonSyncingNtpCustomBackgroundDictDoNotUse), |
| DictionaryValuePtrHas(kNtpCustomBackgroundURL, kTestUrl)); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagEnabledTest, |
| ShouldApplyNtpBackgroundWithGrayscale) { |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.set_use_custom_theme(false); |
| theme_specifics.mutable_grayscale_theme_enabled(); |
| theme_specifics.mutable_ntp_background()->set_url(kTestUrl); |
| |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor()))); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| EXPECT_FALSE(theme_service()->UsingExtensionTheme()); |
| EXPECT_FALSE(theme_service()->UsingAutogeneratedTheme()); |
| EXPECT_EQ(theme_service()->GetThemeID(), ""); |
| EXPECT_EQ(theme_service()->GetUserColor(), std::nullopt); |
| EXPECT_EQ(theme_service()->GetBrowserColorVariant(), |
| ui::mojom::BrowserColorVariant::kSystem); |
| EXPECT_TRUE(theme_service()->GetIsGrayscale()); |
| EXPECT_THAT(profile()->GetPrefs()->GetUserPrefValue( |
| prefs::kNonSyncingNtpCustomBackgroundDictDoNotUse), |
| DictionaryValuePtrHas(kNtpCustomBackgroundURL, kTestUrl)); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagEnabledTest, |
| ShouldApplyNtpBackgroundWithAutogeneratedTheme) { |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.set_use_custom_theme(false); |
| theme_specifics.mutable_autogenerated_color_theme()->set_color(SK_ColorBLUE); |
| theme_specifics.mutable_ntp_background()->set_url(kTestUrl); |
| |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor()))); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| EXPECT_FALSE(theme_service()->UsingExtensionTheme()); |
| EXPECT_TRUE(theme_service()->UsingAutogeneratedTheme()); |
| EXPECT_EQ(theme_service()->GetAutogeneratedThemeColor(), SK_ColorBLUE); |
| EXPECT_EQ(theme_service()->GetThemeID(), ThemeService::kAutogeneratedThemeID); |
| EXPECT_EQ(theme_service()->GetUserColor(), std::nullopt); |
| EXPECT_EQ(theme_service()->GetBrowserColorVariant(), |
| ui::mojom::BrowserColorVariant::kSystem); |
| EXPECT_FALSE(theme_service()->GetIsGrayscale()); |
| EXPECT_THAT(profile()->GetPrefs()->GetUserPrefValue( |
| prefs::kNonSyncingNtpCustomBackgroundDictDoNotUse), |
| DictionaryValuePtrHas(kNtpCustomBackgroundURL, kTestUrl)); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagEnabledTest, |
| ShouldNotApplyDefaultThemeFromOldSpecificsUponMergeDataAndStartSyncing) { |
| theme_service()->SetUserColorAndBrowserColorVariant( |
| SK_ColorRED, ui::mojom::BrowserColorVariant::kTonalSpot); |
| ASSERT_EQ(theme_service()->GetThemeID(), ThemeService::kUserColorThemeID); |
| ASSERT_EQ(theme_service()->GetUserColor(), SK_ColorRED); |
| |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(sync_pb::ThemeSpecifics()), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor()))); |
| |
| EXPECT_EQ(theme_service()->GetThemeID(), ThemeService::kUserColorThemeID); |
| EXPECT_EQ(theme_service()->GetUserColor(), SK_ColorRED); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagEnabledTest, |
| ShouldNotApplyDefaultThemeFromOldSpecificsUponProcessSyncChanges) { |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, syncer::SyncDataList(), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor())); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| theme_service()->SetUserColorAndBrowserColorVariant( |
| SK_ColorRED, ui::mojom::BrowserColorVariant::kTonalSpot); |
| ASSERT_EQ(theme_service()->GetThemeID(), ThemeService::kUserColorThemeID); |
| ASSERT_EQ(theme_service()->GetUserColor(), SK_ColorRED); |
| |
| ASSERT_FALSE(theme_sync_service()->ProcessSyncChanges( |
| FROM_HERE, MakeThemeChangeList(sync_pb::ThemeSpecifics()))); |
| |
| EXPECT_EQ(theme_service()->GetThemeID(), ThemeService::kUserColorThemeID); |
| EXPECT_EQ(theme_service()->GetUserColor(), SK_ColorRED); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagEnabledTest, |
| ShouldApplyDefaultThemeFromNewSpecificsUponProcessSyncChanges) { |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, syncer::SyncDataList(), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor())); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| theme_service()->SetUserColorAndBrowserColorVariant( |
| SK_ColorRED, ui::mojom::BrowserColorVariant::kTonalSpot); |
| ASSERT_EQ(theme_service()->GetThemeID(), ThemeService::kUserColorThemeID); |
| ASSERT_EQ(theme_service()->GetUserColor(), SK_ColorRED); |
| |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.set_browser_color_scheme( |
| sync_pb::ThemeSpecifics_BrowserColorScheme_SYSTEM); |
| ASSERT_FALSE(theme_sync_service()->ProcessSyncChanges( |
| FROM_HERE, MakeThemeChangeList(theme_specifics))); |
| |
| EXPECT_TRUE(theme_service()->UsingDefaultTheme()); |
| EXPECT_NE(theme_service()->GetThemeID(), ThemeService::kUserColorThemeID); |
| EXPECT_EQ(theme_service()->GetUserColor(), std::nullopt); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagEnabledTest, |
| ShouldApplyNonDefaultThemeFromOldSpecificsUponProcessSyncChanges) { |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, syncer::SyncDataList(), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor())); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| theme_service()->SetUserColorAndBrowserColorVariant( |
| SK_ColorRED, ui::mojom::BrowserColorVariant::kTonalSpot); |
| ASSERT_EQ(theme_service()->GetThemeID(), ThemeService::kUserColorThemeID); |
| ASSERT_EQ(theme_service()->GetUserColor(), SK_ColorRED); |
| |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.mutable_autogenerated_color_theme()->set_color(SK_ColorRED); |
| ASSERT_FALSE(theme_sync_service()->ProcessSyncChanges( |
| FROM_HERE, MakeThemeChangeList(theme_specifics))); |
| |
| EXPECT_TRUE(theme_service()->UsingAutogeneratedTheme()); |
| EXPECT_NE(theme_service()->GetThemeID(), ThemeService::kUserColorThemeID); |
| EXPECT_EQ(theme_service()->GetUserColor(), std::nullopt); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagEnabledTest, |
| ShouldUpdateOldSyncingThemePrefs) { |
| // Start syncing. |
| ASSERT_FALSE(theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, syncer::SyncDataList(), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor()))); |
| |
| ASSERT_FALSE( |
| profile()->GetPrefs()->GetUserPrefValue(prefs::kUserColorDoNotUse)); |
| ASSERT_FALSE(profile()->GetPrefs()->GetUserPrefValue( |
| prefs::kBrowserColorVariantDoNotUse)); |
| ASSERT_FALSE(profile()->GetPrefs()->GetUserPrefValue( |
| prefs::kGrayscaleThemeEnabledDoNotUse)); |
| ASSERT_FALSE(profile()->GetPrefs()->GetUserPrefValue( |
| prefs::kNonSyncingNtpCustomBackgroundDictDoNotUse)); |
| |
| // Set user color theme. |
| theme_service()->SetUserColorAndBrowserColorVariant( |
| SK_ColorRED, ui::mojom::BrowserColorVariant::kTonalSpot); |
| |
| ASSERT_TRUE( |
| profile()->GetPrefs()->GetUserPrefValue(prefs::kUserColorDoNotUse)); |
| ASSERT_TRUE(profile()->GetPrefs()->GetUserPrefValue( |
| prefs::kBrowserColorVariantDoNotUse)); |
| EXPECT_EQ(profile()->GetPrefs()->GetInteger(prefs::kUserColorDoNotUse), |
| static_cast<int>(SK_ColorRED)); |
| EXPECT_EQ( |
| profile()->GetPrefs()->GetInteger(prefs::kBrowserColorVariantDoNotUse), |
| static_cast<int>(ui::mojom::BrowserColorVariant::kTonalSpot)); |
| |
| // Other prefs are cleared. |
| EXPECT_FALSE(profile()->GetPrefs()->GetUserPrefValue( |
| prefs::kGrayscaleThemeEnabledDoNotUse)); |
| EXPECT_FALSE(profile()->GetPrefs()->GetUserPrefValue( |
| prefs::kNonSyncingNtpCustomBackgroundDictDoNotUse)); |
| |
| // Set grayscale theme. |
| theme_service()->SetIsGrayscale(true); |
| |
| ASSERT_TRUE(profile()->GetPrefs()->GetUserPrefValue( |
| prefs::kGrayscaleThemeEnabledDoNotUse)); |
| EXPECT_TRUE( |
| profile()->GetPrefs()->GetBoolean(prefs::kGrayscaleThemeEnabledDoNotUse)); |
| |
| // Other prefs are cleared. |
| EXPECT_FALSE( |
| profile()->GetPrefs()->GetUserPrefValue(prefs::kUserColorDoNotUse)); |
| EXPECT_FALSE(profile()->GetPrefs()->GetUserPrefValue( |
| prefs::kBrowserColorVariantDoNotUse)); |
| EXPECT_FALSE(profile()->GetPrefs()->GetUserPrefValue( |
| prefs::kNonSyncingNtpCustomBackgroundDictDoNotUse)); |
| |
| // Set ntp background. |
| { |
| ScopedDictPrefUpdate dict( |
| profile()->GetPrefs(), |
| prefs::kNonSyncingNtpCustomBackgroundDictDoNotUse); |
| dict->Set(kNtpCustomBackgroundURL, kTestUrl); |
| } |
| |
| EXPECT_TRUE(profile()->GetPrefs()->GetUserPrefValue( |
| prefs::kNonSyncingNtpCustomBackgroundDictDoNotUse)); |
| |
| // Other prefs are left as-is. |
| EXPECT_TRUE(profile()->GetPrefs()->GetUserPrefValue( |
| prefs::kGrayscaleThemeEnabledDoNotUse)); |
| EXPECT_FALSE( |
| profile()->GetPrefs()->GetUserPrefValue(prefs::kUserColorDoNotUse)); |
| EXPECT_FALSE(profile()->GetPrefs()->GetUserPrefValue( |
| prefs::kBrowserColorVariantDoNotUse)); |
| |
| // Set default theme. |
| theme_service()->UseDefaultTheme(); |
| |
| // All prefs are cleared. |
| EXPECT_FALSE( |
| profile()->GetPrefs()->GetUserPrefValue(prefs::kUserColorDoNotUse)); |
| EXPECT_FALSE(profile()->GetPrefs()->GetUserPrefValue( |
| prefs::kBrowserColorVariantDoNotUse)); |
| EXPECT_FALSE(profile()->GetPrefs()->GetUserPrefValue( |
| prefs::kGrayscaleThemeEnabledDoNotUse)); |
| EXPECT_FALSE(profile()->GetPrefs()->GetUserPrefValue( |
| prefs::kNonSyncingNtpCustomBackgroundDictDoNotUse)); |
| } |
| |
| // Regression test for crbug.com/389026436. |
| TEST_F(ThemeSyncableServiceWithMigrationFlagEnabledTest, |
| ClearLocalNtpBackgroundIfRemoteEmpty) { |
| // Set local ntp background. |
| base::Value::Dict new_value = |
| base::Value::Dict() |
| .Set(kNtpCustomBackgroundURL, kTestUrl) |
| .Set(kNtpCustomBackgroundAttributionLine1, "attribution_line_1") |
| .Set(kNtpCustomBackgroundAttributionLine2, "attribution_line_2") |
| .Set(kNtpCustomBackgroundAttributionActionURL, |
| "attribution_action_url") |
| .Set(kNtpCustomBackgroundCollectionId, "collection_id") |
| .Set(kNtpCustomBackgroundResumeToken, "resume_token") |
| .Set(kNtpCustomBackgroundRefreshTimestamp, 1234567890) |
| .Set(kNtpCustomBackgroundMainColor, static_cast<int>(SK_ColorRED)); |
| |
| profile()->GetPrefs()->Set(prefs::kNonSyncingNtpCustomBackgroundDictDoNotUse, |
| base::Value(new_value.Clone())); |
| |
| // Remote theme. |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.set_use_custom_theme(false); |
| theme_specifics.set_browser_color_scheme( |
| ::sync_pb::ThemeSpecifics_BrowserColorScheme_SYSTEM); |
| sync_pb::ThemeSpecifics::UserColorTheme* user_color_theme = |
| theme_specifics.mutable_user_color_theme(); |
| user_color_theme->set_color(SK_ColorRED); |
| user_color_theme->set_browser_color_variant( |
| sync_pb::ThemeSpecifics_UserColorTheme_BrowserColorVariant_TONAL_SPOT); |
| |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor())); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| // Local ntp background is cleared. |
| EXPECT_FALSE(profile()->GetPrefs()->GetUserPrefValue( |
| prefs::kNonSyncingNtpCustomBackgroundDictDoNotUse)); |
| } |
| |
| // Regression test for crbug.com/391114025. |
| TEST_F(ThemeSyncableServiceWithMigrationFlagEnabledTest, |
| KeepLocalNtpBackgroundUponNonDefaultOldThemeSpecifics) { |
| // Set local ntp background. |
| base::Value::Dict new_value = |
| base::Value::Dict() |
| .Set(kNtpCustomBackgroundURL, kTestUrl) |
| .Set(kNtpCustomBackgroundAttributionLine1, "attribution_line_1") |
| .Set(kNtpCustomBackgroundAttributionLine2, "attribution_line_2") |
| .Set(kNtpCustomBackgroundAttributionActionURL, |
| "attribution_action_url") |
| .Set(kNtpCustomBackgroundCollectionId, "collection_id") |
| .Set(kNtpCustomBackgroundResumeToken, "resume_token") |
| .Set(kNtpCustomBackgroundRefreshTimestamp, 1234567890) |
| .Set(kNtpCustomBackgroundMainColor, static_cast<int>(SK_ColorRED)); |
| |
| profile()->GetPrefs()->Set(prefs::kNonSyncingNtpCustomBackgroundDictDoNotUse, |
| base::Value(new_value.Clone())); |
| |
| // Remote theme does not contain new fields, thus an old ThemeSpecifics. |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.set_use_custom_theme(false); |
| theme_specifics.mutable_autogenerated_color_theme()->set_color(SK_ColorBLUE); |
| |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor())); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| // Local ntp background is still there. The remote theme was produced by an |
| // old client which didn't know about the new ThemeSpecifics fields. It didn't |
| // intentionally clear the background, just left it unset. |
| EXPECT_TRUE(theme_service()->UsingAutogeneratedTheme()); |
| EXPECT_EQ(theme_service()->GetAutogeneratedThemeColor(), SK_ColorBLUE); |
| EXPECT_TRUE(profile()->GetPrefs()->GetUserPrefValue( |
| prefs::kNonSyncingNtpCustomBackgroundDictDoNotUse)); |
| EXPECT_EQ(profile()->GetPrefs()->GetDict( |
| prefs::kNonSyncingNtpCustomBackgroundDictDoNotUse), |
| new_value); |
| |
| // The merged theme should be committed to the server. |
| const syncer::SyncChangeList& changes = fake_change_processor()->changes(); |
| ASSERT_EQ(changes.size(), 1u); |
| const sync_pb::ThemeSpecifics& change_specifics = |
| changes.back().sync_data().GetSpecifics().theme(); |
| ASSERT_TRUE(change_specifics.has_browser_color_scheme()); |
| ASSERT_TRUE(change_specifics.has_autogenerated_color_theme()); |
| EXPECT_EQ(change_specifics.autogenerated_color_theme().color(), SK_ColorBLUE); |
| ASSERT_TRUE(change_specifics.has_ntp_background()); |
| EXPECT_EQ(change_specifics.ntp_background().url(), kTestUrl); |
| } |
| |
| // Regression test for crbug.com/389026436. |
| TEST_F(ThemeSyncableServiceWithMigrationFlagEnabledTest, |
| KeepLocalNtpBackgroundUponDefaultOldThemeSpecifics) { |
| // Set local ntp background. |
| base::Value::Dict new_value = |
| base::Value::Dict() |
| .Set(kNtpCustomBackgroundURL, kTestUrl) |
| .Set(kNtpCustomBackgroundAttributionLine1, "attribution_line_1") |
| .Set(kNtpCustomBackgroundAttributionLine2, "attribution_line_2") |
| .Set(kNtpCustomBackgroundAttributionActionURL, |
| "attribution_action_url") |
| .Set(kNtpCustomBackgroundCollectionId, "collection_id") |
| .Set(kNtpCustomBackgroundResumeToken, "resume_token") |
| .Set(kNtpCustomBackgroundRefreshTimestamp, 1234567890) |
| .Set(kNtpCustomBackgroundMainColor, static_cast<int>(SK_ColorRED)); |
| |
| profile()->GetPrefs()->Set(prefs::kNonSyncingNtpCustomBackgroundDictDoNotUse, |
| base::Value(new_value.Clone())); |
| |
| // Remote theme does not contain new fields, thus an old ThemeSpecifics. |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.set_use_custom_theme(false); |
| |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor())); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| // Local ntp background is still there since default remote themes are ignored |
| // in the initial update. |
| EXPECT_TRUE(profile()->GetPrefs()->GetUserPrefValue( |
| prefs::kNonSyncingNtpCustomBackgroundDictDoNotUse)); |
| EXPECT_EQ(profile()->GetPrefs()->GetDict( |
| prefs::kNonSyncingNtpCustomBackgroundDictDoNotUse), |
| new_value); |
| |
| // The local theme should be committed to the server. |
| const syncer::SyncChangeList& changes = fake_change_processor()->changes(); |
| ASSERT_EQ(changes.size(), 1u); |
| const sync_pb::ThemeSpecifics& change_specifics = |
| changes.back().sync_data().GetSpecifics().theme(); |
| ASSERT_TRUE(change_specifics.has_browser_color_scheme()); |
| ASSERT_TRUE(change_specifics.has_ntp_background()); |
| EXPECT_EQ(change_specifics.ntp_background().url(), kTestUrl); |
| } |
| |
| // Regression test for crbug.com/389026436. |
| TEST_F(ThemeSyncableServiceWithMigrationFlagEnabledTest, |
| ClearLocalNtpBackgroundUponNonDefaultNewThemeSpecifics) { |
| // Set local ntp background. |
| base::Value::Dict new_value = |
| base::Value::Dict() |
| .Set(kNtpCustomBackgroundURL, kTestUrl) |
| .Set(kNtpCustomBackgroundAttributionLine1, "attribution_line_1") |
| .Set(kNtpCustomBackgroundAttributionLine2, "attribution_line_2") |
| .Set(kNtpCustomBackgroundAttributionActionURL, |
| "attribution_action_url") |
| .Set(kNtpCustomBackgroundCollectionId, "collection_id") |
| .Set(kNtpCustomBackgroundResumeToken, "resume_token") |
| .Set(kNtpCustomBackgroundRefreshTimestamp, 1234567890) |
| .Set(kNtpCustomBackgroundMainColor, static_cast<int>(SK_ColorRED)); |
| |
| profile()->GetPrefs()->Set(prefs::kNonSyncingNtpCustomBackgroundDictDoNotUse, |
| base::Value(new_value.Clone())); |
| |
| // Remote theme contains new fields, thus a new ThemeSpecifics. |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.set_use_custom_theme(false); |
| theme_specifics.set_browser_color_scheme( |
| ::sync_pb::ThemeSpecifics_BrowserColorScheme_SYSTEM); |
| theme_specifics.mutable_autogenerated_color_theme()->set_color(SK_ColorBLUE); |
| |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor())); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| // Local ntp background is cleared, because the remote client must have |
| // explicitly cleared it. |
| EXPECT_TRUE(theme_service()->UsingAutogeneratedTheme()); |
| EXPECT_FALSE(profile()->GetPrefs()->GetUserPrefValue( |
| prefs::kNonSyncingNtpCustomBackgroundDictDoNotUse)); |
| |
| // The remote theme wins and nothing is committed to the server. |
| ASSERT_EQ(fake_change_processor()->changes().size(), 0u); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagEnabledTest, |
| KeepLocalNtpBackgroundUponDefaultNewThemeSpecifics) { |
| // Set local ntp background. |
| base::Value::Dict new_value = |
| base::Value::Dict() |
| .Set(kNtpCustomBackgroundURL, kTestUrl) |
| .Set(kNtpCustomBackgroundAttributionLine1, "attribution_line_1") |
| .Set(kNtpCustomBackgroundAttributionLine2, "attribution_line_2") |
| .Set(kNtpCustomBackgroundAttributionActionURL, |
| "attribution_action_url") |
| .Set(kNtpCustomBackgroundCollectionId, "collection_id") |
| .Set(kNtpCustomBackgroundResumeToken, "resume_token") |
| .Set(kNtpCustomBackgroundRefreshTimestamp, 1234567890) |
| .Set(kNtpCustomBackgroundMainColor, static_cast<int>(SK_ColorRED)); |
| |
| profile()->GetPrefs()->Set(prefs::kNonSyncingNtpCustomBackgroundDictDoNotUse, |
| base::Value(new_value.Clone())); |
| |
| // Remote theme contains new fields, thus a new ThemeSpecifics. |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.set_use_custom_theme(false); |
| theme_specifics.set_browser_color_scheme( |
| ::sync_pb::ThemeSpecifics_BrowserColorScheme_SYSTEM); |
| |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor())); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| // Local ntp background is still there since default remote themes are ignored |
| // in the initial update. |
| EXPECT_TRUE(profile()->GetPrefs()->GetUserPrefValue( |
| prefs::kNonSyncingNtpCustomBackgroundDictDoNotUse)); |
| EXPECT_EQ(profile()->GetPrefs()->GetDict( |
| prefs::kNonSyncingNtpCustomBackgroundDictDoNotUse), |
| new_value); |
| |
| // The local theme should be committed to the server. |
| const syncer::SyncChangeList& changes = fake_change_processor()->changes(); |
| ASSERT_EQ(changes.size(), 1u); |
| const sync_pb::ThemeSpecifics& change_specifics = |
| changes.back().sync_data().GetSpecifics().theme(); |
| ASSERT_TRUE(change_specifics.has_browser_color_scheme()); |
| ASSERT_TRUE(change_specifics.has_ntp_background()); |
| EXPECT_EQ(change_specifics.ntp_background().url(), kTestUrl); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagEnabledTest, |
| ClearLocalUserColorUponNonDefaultOldThemeSpecifics) { |
| // Set local user color. |
| theme_service()->SetUserColorAndBrowserColorVariant( |
| SK_ColorBLUE, ui::mojom::BrowserColorVariant::kNeutral); |
| ASSERT_EQ(theme_service()->GetThemeID(), ThemeService::kUserColorThemeID); |
| ASSERT_EQ(theme_service()->GetUserColor(), SK_ColorBLUE); |
| |
| // Remote theme does not contain new fields, thus an old ThemeSpecifics. |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.set_use_custom_theme(false); |
| theme_specifics.mutable_autogenerated_color_theme()->set_color(SK_ColorBLUE); |
| |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor())); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| // Local user color is cleared because user color and autogenerated color |
| // cannot co-exist. |
| EXPECT_TRUE(theme_service()->UsingAutogeneratedTheme()); |
| EXPECT_NE(theme_service()->GetThemeID(), ThemeService::kUserColorThemeID); |
| EXPECT_FALSE(theme_service()->GetUserColor()); |
| |
| // The remote theme wins and nothing is committed to the server. |
| ASSERT_EQ(fake_change_processor()->changes().size(), 0u); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagEnabledTest, |
| KeepLocalUserColorUponDefaultOldThemeSpecifics) { |
| // Set local user color. |
| theme_service()->SetUserColorAndBrowserColorVariant( |
| SK_ColorBLUE, ui::mojom::BrowserColorVariant::kNeutral); |
| ASSERT_EQ(theme_service()->GetThemeID(), ThemeService::kUserColorThemeID); |
| ASSERT_EQ(theme_service()->GetUserColor(), SK_ColorBLUE); |
| |
| // Remote theme does not contain new fields, thus an old ThemeSpecifics. |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.set_use_custom_theme(false); |
| |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor())); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| // Local user color is still there since default remote themes are ignored in |
| // the initial update. |
| EXPECT_EQ(theme_service()->GetThemeID(), ThemeService::kUserColorThemeID); |
| EXPECT_EQ(theme_service()->GetUserColor(), SK_ColorBLUE); |
| |
| // The local theme should be committed to the server. |
| const syncer::SyncChangeList& changes = fake_change_processor()->changes(); |
| ASSERT_EQ(changes.size(), 1u); |
| const sync_pb::ThemeSpecifics& change_specifics = |
| changes.back().sync_data().GetSpecifics().theme(); |
| ASSERT_TRUE(change_specifics.has_browser_color_scheme()); |
| ASSERT_TRUE(change_specifics.has_user_color_theme()); |
| EXPECT_EQ(change_specifics.user_color_theme().color(), SK_ColorBLUE); |
| EXPECT_EQ(change_specifics.user_color_theme().browser_color_variant(), |
| sync_pb::ThemeSpecifics_UserColorTheme_BrowserColorVariant_NEUTRAL); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagEnabledTest, |
| ClearLocalUserColorUponNonDefaultNewThemeSpecifics) { |
| // Set local user color. |
| theme_service()->SetUserColorAndBrowserColorVariant( |
| SK_ColorBLUE, ui::mojom::BrowserColorVariant::kNeutral); |
| ASSERT_EQ(theme_service()->GetThemeID(), ThemeService::kUserColorThemeID); |
| ASSERT_EQ(theme_service()->GetUserColor(), SK_ColorBLUE); |
| |
| // Remote theme contains new fields, thus a new ThemeSpecifics. |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.set_use_custom_theme(false); |
| theme_specifics.set_browser_color_scheme( |
| ::sync_pb::ThemeSpecifics_BrowserColorScheme_SYSTEM); |
| theme_specifics.mutable_ntp_background()->set_url(kTestUrl); |
| ASSERT_FALSE(profile()->GetPrefs()->GetUserPrefValue( |
| prefs::kNonSyncingNtpCustomBackgroundDictDoNotUse)); |
| |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor())); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| EXPECT_TRUE(profile()->GetPrefs()->GetUserPrefValue( |
| prefs::kNonSyncingNtpCustomBackgroundDictDoNotUse)); |
| // Local user color is cleared since the remote client must have explicitly |
| // cleared it. |
| EXPECT_NE(theme_service()->GetThemeID(), ThemeService::kUserColorThemeID); |
| EXPECT_FALSE(theme_service()->GetUserColor()); |
| |
| // The remote theme wins and nothing is committed to the server. |
| ASSERT_EQ(fake_change_processor()->changes().size(), 0u); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagEnabledTest, |
| KeepLocalUserColorUponDefaultNewThemeSpecifics) { |
| // Set local user color. |
| theme_service()->SetUserColorAndBrowserColorVariant( |
| SK_ColorBLUE, ui::mojom::BrowserColorVariant::kNeutral); |
| ASSERT_EQ(theme_service()->GetThemeID(), ThemeService::kUserColorThemeID); |
| ASSERT_EQ(theme_service()->GetUserColor(), SK_ColorBLUE); |
| |
| // Remote theme contains new fields, thus a new ThemeSpecifics. |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.set_use_custom_theme(false); |
| theme_specifics.set_browser_color_scheme( |
| ::sync_pb::ThemeSpecifics_BrowserColorScheme_SYSTEM); |
| |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor())); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| // Local user color is still there since default remote themes are ignored in |
| // the initial update. |
| EXPECT_EQ(theme_service()->GetThemeID(), ThemeService::kUserColorThemeID); |
| EXPECT_EQ(theme_service()->GetUserColor(), SK_ColorBLUE); |
| |
| // The local theme should be committed to the server. |
| const syncer::SyncChangeList& changes = fake_change_processor()->changes(); |
| ASSERT_EQ(changes.size(), 1u); |
| const sync_pb::ThemeSpecifics& change_specifics = |
| changes.back().sync_data().GetSpecifics().theme(); |
| ASSERT_TRUE(change_specifics.has_browser_color_scheme()); |
| ASSERT_TRUE(change_specifics.has_user_color_theme()); |
| EXPECT_EQ(change_specifics.user_color_theme().color(), SK_ColorBLUE); |
| EXPECT_EQ(change_specifics.user_color_theme().browser_color_variant(), |
| sync_pb::ThemeSpecifics_UserColorTheme_BrowserColorVariant_NEUTRAL); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagEnabledTest, |
| ShouldNotCommitIfLocalAndRemoteThemeAreSame) { |
| // Set local user color. |
| theme_service()->SetUserColorAndBrowserColorVariant( |
| SK_ColorBLUE, ui::mojom::BrowserColorVariant::kNeutral); |
| |
| // Remote theme same as local theme. |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.set_use_custom_theme(false); |
| theme_specifics.set_use_system_theme_by_default(false); |
| theme_specifics.set_browser_color_scheme( |
| ::sync_pb::ThemeSpecifics_BrowserColorScheme_SYSTEM); |
| theme_specifics.mutable_user_color_theme()->set_color(SK_ColorBLUE); |
| theme_specifics.mutable_user_color_theme()->set_browser_color_variant( |
| ::sync_pb::ThemeSpecifics_UserColorTheme_BrowserColorVariant_NEUTRAL); |
| |
| ASSERT_EQ(theme_specifics.SerializeAsString(), |
| theme_sync_service() |
| ->GetThemeSpecificsFromCurrentThemeForTesting() |
| .SerializeAsString()); |
| |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor())); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| // Nothing is committed. |
| ASSERT_EQ(fake_change_processor()->changes().size(), 0u); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagEnabledTest, |
| ShouldNotCommitAnythingElseWithExtensionTheme) { |
| // Local extension theme. |
| { |
| test::ThemeServiceChangedWaiter waiter(theme_service()); |
| theme_service()->SetTheme(theme_extension()); |
| waiter.WaitForThemeChanged(); |
| } |
| ASSERT_TRUE(theme_service()->UsingExtensionTheme()); |
| |
| sync_pb::ThemeSpecifics expected_theme_specifics; |
| expected_theme_specifics.set_use_custom_theme(true); |
| expected_theme_specifics.set_browser_color_scheme( |
| expected_theme_specifics.SYSTEM); |
| expected_theme_specifics.set_use_system_theme_by_default(false); |
| expected_theme_specifics.set_custom_theme_name(kCustomThemeName); |
| expected_theme_specifics.set_custom_theme_id(kCustomThemeId); |
| expected_theme_specifics.set_custom_theme_update_url(kCustomThemeUrl); |
| EXPECT_THAT( |
| theme_sync_service()->GetThemeSpecificsFromCurrentThemeForTesting(), |
| base::test::EqualsProto(expected_theme_specifics)); |
| |
| // Set custom ntp background pref. |
| { |
| ScopedDictPrefUpdate dict( |
| profile()->GetPrefs(), |
| prefs::kNonSyncingNtpCustomBackgroundDictDoNotUse); |
| dict->Set(kNtpCustomBackgroundURL, kTestUrl); |
| } |
| task_environment()->RunUntilIdle(); |
| // Local extension theme is still there. |
| ASSERT_TRUE(theme_service()->UsingExtensionTheme()); |
| |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(sync_pb::ThemeSpecifics()), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor()))); |
| |
| // ThemeSpecifics should be valid, i.e. should not contain ntp background when |
| // there is an extension theme. |
| EXPECT_THAT( |
| theme_sync_service()->GetThemeSpecificsFromCurrentThemeForTesting(), |
| base::test::EqualsProto(expected_theme_specifics)); |
| // Nothing committed to the server. |
| ASSERT_EQ(fake_change_processor()->changes().size(), 1u); |
| EXPECT_THAT( |
| fake_change_processor()->changes()[0].sync_data().GetSpecifics().theme(), |
| base::test::EqualsProto(expected_theme_specifics)); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagEnabledTest, |
| ShouldApplyBrowserColorSchemeAlongsideExtensionTheme) { |
| theme_service()->SetBrowserColorScheme( |
| ThemeService::BrowserColorScheme::kLight); |
| |
| // Set remote extension theme with dark browser color scheme. |
| sync_pb::ThemeSpecifics theme_specifics = |
| theme_service::test::CreateThemeSpecificsWithExtensionTheme( |
| kCustomThemeId, kCustomThemeName, kCustomThemeUrl); |
| theme_specifics.set_browser_color_scheme( |
| ::sync_pb::ThemeSpecifics_BrowserColorScheme_DARK); |
| |
| ASSERT_FALSE(theme_sync_service() |
| ->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor()))) |
| .has_value()); |
| |
| // Remote extension theme with dark browser color scheme is applied. |
| EXPECT_TRUE(base::test::RunUntil( |
| [&]() { return theme_service()->UsingExtensionTheme(); })); |
| EXPECT_EQ(theme_service()->GetBrowserColorScheme(), |
| ThemeService::BrowserColorScheme::kDark); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagEnabledTest, |
| ShouldCommitExtensionThemeAndBrowserColorSchemeOnInitialSync) { |
| // Local extension theme with browser color scheme. |
| theme_service()->SetTheme(theme_extension()); |
| EXPECT_TRUE(base::test::RunUntil( |
| [&]() { return theme_service()->UsingExtensionTheme(); })); |
| theme_service()->SetBrowserColorScheme( |
| ThemeService::BrowserColorScheme::kLight); |
| |
| // Start syncing. |
| ASSERT_FALSE(theme_sync_service() |
| ->MergeDataAndStartSyncing( |
| syncer::THEMES, syncer::SyncDataList(), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor()))) |
| .has_value()); |
| |
| EXPECT_TRUE(theme_service()->UsingExtensionTheme()); |
| EXPECT_EQ(theme_service()->GetBrowserColorScheme(), |
| ThemeService::BrowserColorScheme::kLight); |
| EXPECT_THAT( |
| theme_sync_service()->GetThemeSpecificsFromCurrentThemeForTesting(), |
| testing::AllOf( |
| testing::Property(&sync_pb::ThemeSpecifics::use_custom_theme, true), |
| testing::Property(&sync_pb::ThemeSpecifics::browser_color_scheme, |
| sync_pb::ThemeSpecifics::LIGHT))); |
| // Local extension theme is committed along with the browser color scheme. |
| ASSERT_EQ(fake_change_processor()->changes().size(), 1u); |
| EXPECT_THAT( |
| fake_change_processor()->changes()[0].sync_data().GetSpecifics().theme(), |
| base::test::EqualsProto( |
| theme_sync_service()->GetThemeSpecificsFromCurrentThemeForTesting())); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagEnabledTest, |
| ShouldCommitBrowserColorSchemeAlongsideNewExtensionTheme) { |
| // Local browser color scheme. |
| theme_service()->SetBrowserColorScheme( |
| ThemeService::BrowserColorScheme::kLight); |
| // Start syncing. |
| ASSERT_FALSE(theme_sync_service() |
| ->MergeDataAndStartSyncing( |
| syncer::THEMES, syncer::SyncDataList(), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor()))) |
| .has_value()); |
| |
| // Set a new extension theme. |
| theme_service()->SetTheme(theme_extension()); |
| EXPECT_TRUE(base::test::RunUntil( |
| [&]() { return theme_service()->UsingExtensionTheme(); })); |
| |
| // Extension theme should be applied and committed alongside the browser color |
| // scheme. |
| ASSERT_EQ(theme_service()->GetBrowserColorScheme(), |
| ThemeService::BrowserColorScheme::kLight); |
| ASSERT_THAT(fake_change_processor()->changes(), Not(testing::IsEmpty())); |
| EXPECT_THAT( |
| fake_change_processor() |
| ->changes() |
| .back() |
| .sync_data() |
| .GetSpecifics() |
| .theme(), |
| testing::AllOf( |
| testing::Property(&sync_pb::ThemeSpecifics::use_custom_theme, true), |
| testing::Property(&sync_pb::ThemeSpecifics::browser_color_scheme, |
| sync_pb::ThemeSpecifics::LIGHT))); |
| } |
| |
| TEST_F(ThemeSyncableServiceWithMigrationFlagEnabledTest, |
| ShouldCommitBrowserColorSchemeIfPreexistingExtensionTheme) { |
| // Local extension theme. |
| theme_service()->SetTheme(theme_extension()); |
| EXPECT_TRUE(base::test::RunUntil( |
| [&]() { return theme_service()->UsingExtensionTheme(); })); |
| // Start syncing. |
| ASSERT_FALSE(theme_sync_service() |
| ->MergeDataAndStartSyncing( |
| syncer::THEMES, syncer::SyncDataList(), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor()))) |
| .has_value()); |
| |
| // Set a browser color scheme. This should be applied and committed alongside |
| // the extension theme. |
| theme_service()->SetBrowserColorScheme( |
| ThemeService::BrowserColorScheme::kLight); |
| ASSERT_TRUE(theme_service()->UsingExtensionTheme()); |
| |
| ASSERT_THAT(fake_change_processor()->changes(), Not(testing::IsEmpty())); |
| EXPECT_THAT( |
| fake_change_processor() |
| ->changes() |
| .back() |
| .sync_data() |
| .GetSpecifics() |
| .theme(), |
| testing::AllOf( |
| testing::Property(&sync_pb::ThemeSpecifics::use_custom_theme, true), |
| testing::Property(&sync_pb::ThemeSpecifics::browser_color_scheme, |
| sync_pb::ThemeSpecifics::LIGHT))); |
| } |
| |
| class ThemeSyncableServiceVerifyFinalStateTest |
| : public ThemeSyncableServiceWithMigrationFlagEnabledTest, |
| public testing::WithParamInterface<sync_pb::ThemeSpecifics> { |
| protected: |
| void MergeRemoteUpdateAndVerify() { |
| sync_pb::ThemeSpecifics theme_specifics = GetParam(); |
| |
| // Skip test if remote theme is the same. |
| if (theme_sync_service() |
| ->GetThemeSpecificsFromCurrentThemeForTesting() |
| .SerializeAsString() == theme_specifics.SerializeAsString()) { |
| return; |
| } |
| |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor()))); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| if (theme_specifics.use_custom_theme()) { |
| // Remote extension theme is not applied instantaneously. |
| EXPECT_TRUE(base::test::RunUntil( |
| [&]() { return theme_service()->UsingExtensionTheme(); })); |
| // Remote extension theme produces more than one commits. |
| EXPECT_GE(fake_change_processor()->changes().size(), 1u); |
| } else { |
| EXPECT_THAT(fake_change_processor()->changes(), testing::IsEmpty()); |
| } |
| |
| // Current theme matches the remote theme. |
| EXPECT_THAT( |
| theme_sync_service()->GetThemeSpecificsFromCurrentThemeForTesting(), |
| base::test::EqualsProto(theme_specifics)); |
| } |
| }; |
| |
| TEST_P(ThemeSyncableServiceVerifyFinalStateTest, LocalDefaultTheme) { |
| MergeRemoteUpdateAndVerify(); |
| } |
| |
| TEST_P(ThemeSyncableServiceVerifyFinalStateTest, LocalExtensionTheme) { |
| // Local extension theme. |
| { |
| test::ThemeServiceChangedWaiter waiter(theme_service()); |
| theme_service()->SetTheme(theme_extension()); |
| waiter.WaitForThemeChanged(); |
| } |
| ASSERT_TRUE(theme_service()->UsingExtensionTheme()); |
| |
| MergeRemoteUpdateAndVerify(); |
| } |
| |
| TEST_P(ThemeSyncableServiceVerifyFinalStateTest, LocalAutogeneratedColorTheme) { |
| // Local autogenerated color theme. |
| theme_service()->BuildAutogeneratedThemeFromColor(SK_ColorBLUE); |
| ASSERT_TRUE(theme_service()->UsingAutogeneratedTheme()); |
| |
| MergeRemoteUpdateAndVerify(); |
| } |
| |
| TEST_P(ThemeSyncableServiceVerifyFinalStateTest, LocalColorTheme) { |
| // Local color theme. |
| theme_service()->SetUserColorAndBrowserColorVariant( |
| SK_ColorBLUE, ui::mojom::BrowserColorVariant::kTonalSpot); |
| ASSERT_EQ(theme_service()->GetThemeID(), ThemeService::kUserColorThemeID); |
| |
| MergeRemoteUpdateAndVerify(); |
| } |
| |
| TEST_P(ThemeSyncableServiceVerifyFinalStateTest, LocalGrayscaleTheme) { |
| // Local grayscale theme. |
| theme_service()->SetIsGrayscale(true); |
| ASSERT_TRUE(theme_service()->GetIsGrayscale()); |
| |
| MergeRemoteUpdateAndVerify(); |
| } |
| |
| TEST_P(ThemeSyncableServiceVerifyFinalStateTest, LocalBackground) { |
| // Local custom ntp background. |
| { |
| ScopedDictPrefUpdate dict( |
| profile()->GetPrefs(), |
| prefs::kNonSyncingNtpCustomBackgroundDictDoNotUse); |
| dict->Set(kNtpCustomBackgroundURL, kTestUrl); |
| } |
| |
| MergeRemoteUpdateAndVerify(); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P( |
| , |
| ThemeSyncableServiceVerifyFinalStateTest, |
| testing::Values( |
| theme_service::test::CreateThemeSpecificsWithExtensionTheme( |
| kCustomThemeId, |
| kCustomThemeName, |
| kCustomThemeUrl), |
| theme_service::test::CreateThemeSpecificsWithAutogeneratedColorTheme(), |
| theme_service::test::CreateThemeSpecificsWithColorTheme(), |
| theme_service::test::CreateThemeSpecificsWithGrayscaleTheme(), |
| theme_service::test::CreateThemeSpecificsWithCustomNtpBackground( |
| kTestUrl))); |
| |
| class ThemeSyncableServiceTestWithoutAccountThemesSeparation |
| : public ThemeSyncableServiceWithMigrationFlagEnabledTest { |
| public: |
| ThemeSyncableServiceTestWithoutAccountThemesSeparation() { |
| feature_list_.InitAndDisableFeature(syncer::kSeparateLocalAndAccountThemes); |
| } |
| |
| private: |
| base::test::ScopedFeatureList feature_list_; |
| }; |
| |
| TEST_F(ThemeSyncableServiceTestWithoutAccountThemesSeparation, |
| LocalThemeIsCommitedUponInitialSync) { |
| theme_service()->BuildAutogeneratedThemeFromColor(SK_ColorBLUE); |
| ASSERT_TRUE(theme_service()->UsingAutogeneratedTheme()); |
| |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(sync_pb::ThemeSpecifics()), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor()))); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| // One pending change. |
| EXPECT_EQ(fake_change_processor()->changes().size(), 1u); |
| } |
| |
| class ThemeSyncableServiceTestWithAccountThemesSeparation |
| : public ThemeSyncableServiceWithMigrationFlagEnabledTest { |
| public: |
| ThemeSyncableServiceTestWithAccountThemesSeparation() |
| : feature_list_(syncer::kSeparateLocalAndAccountThemes) {} |
| |
| sync_pb::ThemeSpecifics ReadSavedLocalThemeSpecifics() { |
| std::string encoded_str = |
| profile_->GetPrefs()->GetString(prefs::kSavedLocalTheme); |
| std::string decoded_str; |
| EXPECT_TRUE(base::Base64Decode(encoded_str, &decoded_str)); |
| |
| sync_pb::ThemeSpecifics specifics; |
| EXPECT_TRUE(specifics.ParseFromString(decoded_str)); |
| return specifics; |
| } |
| |
| private: |
| base::test::ScopedFeatureList feature_list_; |
| }; |
| |
| TEST_F(ThemeSyncableServiceTestWithAccountThemesSeparation, |
| LocalThemeIsNotCommitedUponInitialSync) { |
| theme_service()->BuildAutogeneratedThemeFromColor(SK_ColorBLUE); |
| ASSERT_TRUE(theme_service()->UsingAutogeneratedTheme()); |
| |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(sync_pb::ThemeSpecifics()), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor()))); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| // No pending change. |
| EXPECT_THAT(fake_change_processor()->changes(), ::testing::IsEmpty()); |
| } |
| |
| TEST_F(ThemeSyncableServiceTestWithAccountThemesSeparation, |
| SaveLocalExtensionThemeToPrefUponInitialSync) { |
| // Set up theme service to use custom theme. |
| { |
| test::ThemeServiceChangedWaiter waiter(theme_service()); |
| theme_service()->SetTheme(theme_extension()); |
| waiter.WaitForThemeChanged(); |
| } |
| ASSERT_TRUE(theme_service()->UsingExtensionTheme()); |
| |
| // Start initial sync. |
| theme_sync_service()->WillStartInitialSync(); |
| |
| // Check the saved local theme. |
| sync_pb::ThemeSpecifics local_theme_specifics = |
| ReadSavedLocalThemeSpecifics(); |
| EXPECT_TRUE(local_theme_specifics.use_custom_theme()); |
| EXPECT_EQ(local_theme_specifics.custom_theme_name(), kCustomThemeName); |
| EXPECT_EQ(local_theme_specifics.custom_theme_id(), theme_extension()->id()); |
| EXPECT_EQ(local_theme_specifics.custom_theme_update_url(), kCustomThemeUrl); |
| } |
| |
| TEST_F(ThemeSyncableServiceTestWithAccountThemesSeparation, |
| SaveLocalAutogeneratedThemeToPrefUponInitialSync) { |
| theme_service()->BuildAutogeneratedThemeFromColor(SK_ColorBLUE); |
| ASSERT_TRUE(theme_service()->UsingAutogeneratedTheme()); |
| |
| // Start initial sync. |
| theme_sync_service()->WillStartInitialSync(); |
| |
| // Check the saved local theme. |
| sync_pb::ThemeSpecifics local_theme_specifics = |
| ReadSavedLocalThemeSpecifics(); |
| EXPECT_FALSE(local_theme_specifics.use_custom_theme()); |
| EXPECT_EQ(local_theme_specifics.browser_color_scheme(), |
| sync_pb::ThemeSpecifics_BrowserColorScheme_SYSTEM); |
| ASSERT_TRUE(local_theme_specifics.has_autogenerated_color_theme()); |
| EXPECT_EQ(local_theme_specifics.autogenerated_color_theme().color(), |
| SK_ColorBLUE); |
| } |
| |
| TEST_F(ThemeSyncableServiceTestWithAccountThemesSeparation, |
| SaveLocalUserColorThemeToPrefUponInitialSync) { |
| theme_service()->SetUserColorAndBrowserColorVariant( |
| SK_ColorRED, ui::mojom::BrowserColorVariant::kTonalSpot); |
| ASSERT_EQ(theme_service()->GetThemeID(), ThemeService::kUserColorThemeID); |
| |
| // Start initial sync. |
| theme_sync_service()->WillStartInitialSync(); |
| |
| // Check the saved local theme. |
| sync_pb::ThemeSpecifics local_theme_specifics = |
| ReadSavedLocalThemeSpecifics(); |
| EXPECT_FALSE(local_theme_specifics.use_custom_theme()); |
| EXPECT_EQ(local_theme_specifics.browser_color_scheme(), |
| sync_pb::ThemeSpecifics_BrowserColorScheme_SYSTEM); |
| ASSERT_TRUE(local_theme_specifics.has_user_color_theme()); |
| EXPECT_EQ(local_theme_specifics.user_color_theme().color(), SK_ColorRED); |
| EXPECT_EQ( |
| local_theme_specifics.user_color_theme().browser_color_variant(), |
| sync_pb::ThemeSpecifics_UserColorTheme_BrowserColorVariant_TONAL_SPOT); |
| } |
| |
| TEST_F(ThemeSyncableServiceTestWithAccountThemesSeparation, |
| SaveLocalGrayscaleThemeToPrefUponInitialSync) { |
| theme_service()->SetIsGrayscale(true); |
| |
| // Start initial sync. |
| theme_sync_service()->WillStartInitialSync(); |
| |
| // Check the saved local theme. |
| sync_pb::ThemeSpecifics local_theme_specifics = |
| ReadSavedLocalThemeSpecifics(); |
| EXPECT_FALSE(local_theme_specifics.use_custom_theme()); |
| EXPECT_EQ(local_theme_specifics.browser_color_scheme(), |
| sync_pb::ThemeSpecifics_BrowserColorScheme_SYSTEM); |
| EXPECT_TRUE(local_theme_specifics.has_grayscale_theme_enabled()); |
| } |
| |
| TEST_F(ThemeSyncableServiceTestWithAccountThemesSeparation, |
| SaveLocalUseSystemThemeToPrefUponInitialSync) { |
| if (!theme_service()->IsSystemThemeDistinctFromDefaultTheme()) { |
| return; |
| } |
| theme_service()->UseSystemTheme(); |
| |
| // Start initial sync. |
| theme_sync_service()->WillStartInitialSync(); |
| |
| // Check the saved local theme. |
| sync_pb::ThemeSpecifics local_theme_specifics = |
| ReadSavedLocalThemeSpecifics(); |
| EXPECT_FALSE(local_theme_specifics.use_custom_theme()); |
| EXPECT_EQ(local_theme_specifics.browser_color_scheme(), |
| sync_pb::ThemeSpecifics_BrowserColorScheme_SYSTEM); |
| ASSERT_TRUE(local_theme_specifics.has_use_system_theme_by_default()); |
| EXPECT_TRUE(local_theme_specifics.use_system_theme_by_default()); |
| } |
| |
| TEST_F(ThemeSyncableServiceTestWithAccountThemesSeparation, |
| SaveLocalBrowserColorSchemeToPrefUponInitialSync) { |
| theme_service()->SetBrowserColorScheme( |
| ThemeService::BrowserColorScheme::kLight); |
| |
| // Start initial sync. |
| theme_sync_service()->WillStartInitialSync(); |
| |
| // Check the saved local theme. |
| sync_pb::ThemeSpecifics local_theme_specifics = |
| ReadSavedLocalThemeSpecifics(); |
| EXPECT_FALSE(local_theme_specifics.use_custom_theme()); |
| EXPECT_EQ(local_theme_specifics.browser_color_scheme(), |
| sync_pb::ThemeSpecifics_BrowserColorScheme_LIGHT); |
| } |
| |
| TEST_F(ThemeSyncableServiceTestWithAccountThemesSeparation, |
| SaveLocalNtpBackgroundToPrefUponInitialSync) { |
| // Set custom background via pref. |
| base::Value::Dict background_dict = |
| base::Value::Dict() |
| .Set(kNtpCustomBackgroundURL, kTestUrl) |
| .Set(kNtpCustomBackgroundAttributionLine1, "attribution_line_1") |
| .Set(kNtpCustomBackgroundAttributionLine2, "attribution_line_2") |
| .Set(kNtpCustomBackgroundAttributionActionURL, |
| "attribution_action_url") |
| .Set(kNtpCustomBackgroundCollectionId, "collection_id") |
| .Set(kNtpCustomBackgroundResumeToken, "resume_token") |
| .Set(kNtpCustomBackgroundRefreshTimestamp, |
| static_cast<int>(1234567890)) |
| .Set(kNtpCustomBackgroundMainColor, static_cast<int>(SK_ColorRED)); |
| |
| profile()->GetPrefs()->Set(prefs::kNonSyncingNtpCustomBackgroundDictDoNotUse, |
| base::Value(background_dict.Clone())); |
| |
| // Start initial sync. |
| theme_sync_service()->WillStartInitialSync(); |
| |
| // Check the saved local theme. |
| sync_pb::ThemeSpecifics local_theme_specifics = |
| ReadSavedLocalThemeSpecifics(); |
| EXPECT_FALSE(local_theme_specifics.use_custom_theme()); |
| EXPECT_EQ(local_theme_specifics.browser_color_scheme(), |
| sync_pb::ThemeSpecifics_BrowserColorScheme_SYSTEM); |
| ASSERT_TRUE(local_theme_specifics.has_ntp_background()); |
| EXPECT_EQ(local_theme_specifics.ntp_background().url(), kTestUrl); |
| } |
| |
| TEST_F(ThemeSyncableServiceTestWithAccountThemesSeparation, |
| ShouldNotSaveLocalThemeToPrefUponBrowserRestart) { |
| theme_service()->SetUserColorAndBrowserColorVariant( |
| SK_ColorRED, ui::mojom::BrowserColorVariant::kTonalSpot); |
| ASSERT_EQ(theme_service()->GetThemeID(), ThemeService::kUserColorThemeID); |
| |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(sync_pb::ThemeSpecifics()), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor()))); |
| |
| // No theme was saved. |
| EXPECT_FALSE(profile_->GetPrefs()->GetUserPrefValue(prefs::kSavedLocalTheme)); |
| } |
| |
| TEST_F(ThemeSyncableServiceTestWithAccountThemesSeparation, |
| LoadsLocalExtensionThemeFromPrefUponSyncStop) { |
| // Set remote extension theme. |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.set_use_custom_theme(false); |
| theme_specifics.mutable_autogenerated_color_theme()->set_color(SK_ColorBLUE); |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor()))); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| EXPECT_TRUE(theme_service()->UsingAutogeneratedTheme()); |
| EXPECT_FALSE(theme_service()->UsingExtensionTheme()); |
| |
| // Set saved local theme pref. |
| sync_pb::ThemeSpecifics local_theme_specifics; |
| local_theme_specifics.set_use_custom_theme(true); |
| local_theme_specifics.set_custom_theme_id(theme_extension()->id()); |
| local_theme_specifics.set_custom_theme_name(kCustomThemeName); |
| local_theme_specifics.set_custom_theme_update_url(kCustomThemeUrl); |
| |
| profile()->GetPrefs()->SetString( |
| prefs::kSavedLocalTheme, |
| base::Base64Encode(local_theme_specifics.SerializeAsString())); |
| |
| base::HistogramTester histogram_tester; |
| // Stop syncing. |
| { |
| test::ThemeServiceChangedWaiter waiter(theme_service()); |
| theme_sync_service()->StopSyncing(syncer::THEMES); |
| waiter.WaitForThemeChanged(); |
| } |
| EXPECT_FALSE(theme_service()->UsingAutogeneratedTheme()); |
| EXPECT_TRUE(theme_service()->UsingExtensionTheme()); |
| EXPECT_EQ(theme_service()->GetThemeID(), theme_extension()->id()); |
| histogram_tester.ExpectUniqueSample("Theme.RestoredLocalThemeUponSignout", |
| true, 1); |
| } |
| |
| TEST_F(ThemeSyncableServiceTestWithAccountThemesSeparation, |
| LoadsLocalAutogeneratedColorThemeFromPrefUponSyncStop) { |
| // Set remote extension theme. |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.set_use_custom_theme(true); |
| theme_specifics.set_custom_theme_id(theme_extension()->id()); |
| theme_specifics.set_custom_theme_name(kCustomThemeName); |
| theme_specifics.set_custom_theme_update_url(kCustomThemeUrl); |
| |
| // Start syncing. |
| { |
| test::ThemeServiceChangedWaiter waiter(theme_service()); |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor()))); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| waiter.WaitForThemeChanged(); |
| } |
| EXPECT_TRUE(theme_service()->UsingExtensionTheme()); |
| EXPECT_FALSE(theme_service()->UsingAutogeneratedTheme()); |
| |
| // Set saved local theme pref. |
| sync_pb::ThemeSpecifics local_theme_specifics; |
| local_theme_specifics.set_use_custom_theme(false); |
| local_theme_specifics.mutable_autogenerated_color_theme()->set_color( |
| SK_ColorBLUE); |
| |
| profile()->GetPrefs()->SetString( |
| prefs::kSavedLocalTheme, |
| base::Base64Encode(local_theme_specifics.SerializeAsString())); |
| |
| base::HistogramTester histogram_tester; |
| // Stop syncing. |
| { |
| test::ThemeServiceChangedWaiter waiter(theme_service()); |
| theme_sync_service()->StopSyncing(syncer::THEMES); |
| waiter.WaitForThemeChanged(); |
| } |
| EXPECT_FALSE(theme_service()->UsingExtensionTheme()); |
| EXPECT_TRUE(theme_service()->UsingAutogeneratedTheme()); |
| EXPECT_EQ(theme_service()->GetAutogeneratedThemeColor(), SK_ColorBLUE); |
| histogram_tester.ExpectUniqueSample("Theme.RestoredLocalThemeUponSignout", |
| true, 1); |
| } |
| |
| TEST_F(ThemeSyncableServiceTestWithAccountThemesSeparation, |
| LoadsLocalUserColorThemeFromPrefUponSyncStop) { |
| // Set remote extension theme. |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.set_use_custom_theme(false); |
| theme_specifics.mutable_autogenerated_color_theme()->set_color(SK_ColorBLUE); |
| |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor()))); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| EXPECT_TRUE(theme_service()->UsingAutogeneratedTheme()); |
| EXPECT_NE(theme_service()->GetThemeID(), ThemeService::kUserColorThemeID); |
| |
| // Set saved local theme pref. |
| sync_pb::ThemeSpecifics local_theme_specifics; |
| local_theme_specifics.set_use_custom_theme(false); |
| sync_pb::ThemeSpecifics::UserColorTheme* user_color_theme = |
| local_theme_specifics.mutable_user_color_theme(); |
| user_color_theme->set_color(SK_ColorRED); |
| user_color_theme->set_browser_color_variant( |
| sync_pb::ThemeSpecifics_UserColorTheme_BrowserColorVariant_TONAL_SPOT); |
| |
| profile()->GetPrefs()->SetString( |
| prefs::kSavedLocalTheme, |
| base::Base64Encode(local_theme_specifics.SerializeAsString())); |
| |
| base::HistogramTester histogram_tester; |
| // Stop syncing. |
| theme_sync_service()->StopSyncing(syncer::THEMES); |
| |
| // Theme is restored to user color theme. |
| EXPECT_FALSE(theme_service()->UsingAutogeneratedTheme()); |
| EXPECT_EQ(theme_service()->GetThemeID(), ThemeService::kUserColorThemeID); |
| EXPECT_EQ(theme_service()->GetUserColor(), static_cast<int>(SK_ColorRED)); |
| EXPECT_EQ(theme_service()->GetBrowserColorVariant(), |
| ui::mojom::BrowserColorVariant::kTonalSpot); |
| histogram_tester.ExpectUniqueSample("Theme.RestoredLocalThemeUponSignout", |
| true, 1); |
| } |
| |
| TEST_F(ThemeSyncableServiceTestWithAccountThemesSeparation, |
| LoadsLocalGrayscaleThemeFromPrefUponSyncStop) { |
| // Set remote extension theme. |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.set_use_custom_theme(true); |
| theme_specifics.set_custom_theme_id(theme_extension()->id()); |
| theme_specifics.set_custom_theme_name(kCustomThemeName); |
| theme_specifics.set_custom_theme_update_url(kCustomThemeUrl); |
| |
| // Start syncing. |
| { |
| test::ThemeServiceChangedWaiter waiter(theme_service()); |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor()))); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| waiter.WaitForThemeChanged(); |
| } |
| EXPECT_TRUE(theme_service()->UsingExtensionTheme()); |
| EXPECT_FALSE(theme_service()->GetIsGrayscale()); |
| |
| // Set saved local theme pref. |
| sync_pb::ThemeSpecifics local_theme_specifics; |
| local_theme_specifics.set_use_custom_theme(false); |
| local_theme_specifics.mutable_grayscale_theme_enabled(); |
| |
| profile()->GetPrefs()->SetString( |
| prefs::kSavedLocalTheme, |
| base::Base64Encode(local_theme_specifics.SerializeAsString())); |
| |
| base::HistogramTester histogram_tester; |
| // Stop syncing. |
| { |
| test::ThemeServiceChangedWaiter waiter(theme_service()); |
| theme_sync_service()->StopSyncing(syncer::THEMES); |
| waiter.WaitForThemeChanged(); |
| } |
| EXPECT_FALSE(theme_service()->UsingExtensionTheme()); |
| EXPECT_TRUE(theme_service()->GetIsGrayscale()); |
| histogram_tester.ExpectUniqueSample("Theme.RestoredLocalThemeUponSignout", |
| true, 1); |
| } |
| |
| TEST_F(ThemeSyncableServiceTestWithAccountThemesSeparation, |
| LoadsLocalUseSystemThemeFromPrefUponSyncStop) { |
| if (!theme_service()->IsSystemThemeDistinctFromDefaultTheme()) { |
| return; |
| } |
| |
| // Set remote extension theme. |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.set_use_custom_theme(true); |
| theme_specifics.set_custom_theme_id(theme_extension()->id()); |
| theme_specifics.set_custom_theme_name(kCustomThemeName); |
| theme_specifics.set_custom_theme_update_url(kCustomThemeUrl); |
| |
| // Start syncing. |
| { |
| test::ThemeServiceChangedWaiter waiter(theme_service()); |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor()))); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| waiter.WaitForThemeChanged(); |
| } |
| EXPECT_TRUE(theme_service()->UsingExtensionTheme()); |
| EXPECT_FALSE(theme_service()->UsingSystemTheme()); |
| |
| // Set saved local theme pref. |
| sync_pb::ThemeSpecifics local_theme_specifics; |
| local_theme_specifics.set_use_custom_theme(false); |
| local_theme_specifics.set_browser_color_scheme( |
| sync_pb::ThemeSpecifics_BrowserColorScheme_SYSTEM); |
| local_theme_specifics.set_use_system_theme_by_default(true); |
| |
| profile()->GetPrefs()->SetString( |
| prefs::kSavedLocalTheme, |
| base::Base64Encode(local_theme_specifics.SerializeAsString())); |
| |
| base::HistogramTester histogram_tester; |
| // Stop syncing. |
| { |
| test::ThemeServiceChangedWaiter waiter(theme_service()); |
| theme_sync_service()->StopSyncing(syncer::THEMES); |
| waiter.WaitForThemeChanged(); |
| } |
| EXPECT_FALSE(theme_service()->UsingExtensionTheme()); |
| EXPECT_TRUE(theme_service()->UsingSystemTheme()); |
| histogram_tester.ExpectUniqueSample("Theme.RestoredLocalThemeUponSignout", |
| true, 1); |
| } |
| |
| TEST_F(ThemeSyncableServiceTestWithAccountThemesSeparation, |
| LoadsLocalBrowserColorSchemeFromPrefUponSyncStop) { |
| // Set remote extension theme. |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.set_use_custom_theme(true); |
| theme_specifics.set_custom_theme_id(theme_extension()->id()); |
| theme_specifics.set_custom_theme_name(kCustomThemeName); |
| theme_specifics.set_custom_theme_update_url(kCustomThemeUrl); |
| |
| // Start syncing. |
| { |
| test::ThemeServiceChangedWaiter waiter(theme_service()); |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor()))); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| waiter.WaitForThemeChanged(); |
| } |
| EXPECT_TRUE(theme_service()->UsingExtensionTheme()); |
| EXPECT_EQ(theme_service()->GetBrowserColorScheme(), |
| ThemeService::BrowserColorScheme::kSystem); |
| |
| // Set saved local theme pref. |
| sync_pb::ThemeSpecifics local_theme_specifics; |
| local_theme_specifics.set_use_custom_theme(false); |
| local_theme_specifics.set_browser_color_scheme( |
| sync_pb::ThemeSpecifics_BrowserColorScheme_LIGHT); |
| |
| profile()->GetPrefs()->SetString( |
| prefs::kSavedLocalTheme, |
| base::Base64Encode(local_theme_specifics.SerializeAsString())); |
| |
| base::HistogramTester histogram_tester; |
| // Stop syncing. |
| { |
| test::ThemeServiceChangedWaiter waiter(theme_service()); |
| theme_sync_service()->StopSyncing(syncer::THEMES); |
| waiter.WaitForThemeChanged(); |
| } |
| EXPECT_FALSE(theme_service()->UsingExtensionTheme()); |
| EXPECT_EQ(theme_service()->GetBrowserColorScheme(), |
| ThemeService::BrowserColorScheme::kLight); |
| histogram_tester.ExpectUniqueSample("Theme.RestoredLocalThemeUponSignout", |
| true, 1); |
| } |
| |
| TEST_F(ThemeSyncableServiceTestWithAccountThemesSeparation, |
| LoadsLocalNtpBackgroundFromPrefUponSyncStop) { |
| // Set remote extension theme. |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.set_use_custom_theme(true); |
| theme_specifics.set_custom_theme_id(theme_extension()->id()); |
| theme_specifics.set_custom_theme_name(kCustomThemeName); |
| theme_specifics.set_custom_theme_update_url(kCustomThemeUrl); |
| |
| // Start syncing. |
| { |
| test::ThemeServiceChangedWaiter waiter(theme_service()); |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor()))); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| waiter.WaitForThemeChanged(); |
| } |
| EXPECT_TRUE(theme_service()->UsingExtensionTheme()); |
| EXPECT_FALSE(profile()->GetPrefs()->GetUserPrefValue( |
| prefs::kNonSyncingNtpCustomBackgroundDictDoNotUse)); |
| |
| // Set saved local theme pref. |
| sync_pb::ThemeSpecifics local_theme_specifics; |
| local_theme_specifics.set_use_custom_theme(false); |
| sync_pb::ThemeSpecifics::NtpCustomBackground* background = |
| local_theme_specifics.mutable_ntp_background(); |
| background->set_url(kTestUrl); |
| background->set_attribution_line_1("attribution_line_1"); |
| background->set_attribution_line_2("attribution_line_2"); |
| background->set_attribution_action_url("attribution_action_url"); |
| background->set_collection_id("collection_id"); |
| background->set_resume_token("resume_token"); |
| background->set_refresh_timestamp_unix_epoch_seconds(1234567890); |
| background->set_main_color(static_cast<int>(SK_ColorRED)); |
| |
| profile()->GetPrefs()->SetString( |
| prefs::kSavedLocalTheme, |
| base::Base64Encode(local_theme_specifics.SerializeAsString())); |
| |
| base::HistogramTester histogram_tester; |
| // Stop syncing. |
| { |
| test::ThemeServiceChangedWaiter waiter(theme_service()); |
| theme_sync_service()->StopSyncing(syncer::THEMES); |
| waiter.WaitForThemeChanged(); |
| } |
| EXPECT_FALSE(theme_service()->UsingExtensionTheme()); |
| EXPECT_EQ( |
| profile()->GetPrefs()->GetDict( |
| prefs::kNonSyncingNtpCustomBackgroundDictDoNotUse), |
| base::Value::Dict() |
| .Set(kNtpCustomBackgroundURL, kTestUrl) |
| .Set(kNtpCustomBackgroundAttributionLine1, "attribution_line_1") |
| .Set(kNtpCustomBackgroundAttributionLine2, "attribution_line_2") |
| .Set(kNtpCustomBackgroundAttributionActionURL, |
| "attribution_action_url") |
| .Set(kNtpCustomBackgroundCollectionId, "collection_id") |
| .Set(kNtpCustomBackgroundResumeToken, "resume_token") |
| .Set(kNtpCustomBackgroundRefreshTimestamp, |
| static_cast<int>(1234567890)) |
| .Set(kNtpCustomBackgroundMainColor, static_cast<int>(SK_ColorRED))); |
| histogram_tester.ExpectUniqueSample("Theme.RestoredLocalThemeUponSignout", |
| true, 1); |
| } |
| |
| TEST_F(ThemeSyncableServiceTestWithAccountThemesSeparation, |
| LoadsDefaultThemeUponSyncStopIfNoLocalThemeExistedInPref) { |
| // Set remote extension theme. |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.set_use_custom_theme(true); |
| theme_specifics.set_custom_theme_id(theme_extension()->id()); |
| theme_specifics.set_custom_theme_name(kCustomThemeName); |
| theme_specifics.set_custom_theme_update_url(kCustomThemeUrl); |
| |
| // Start syncing. |
| { |
| test::ThemeServiceChangedWaiter waiter(theme_service()); |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor()))); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| waiter.WaitForThemeChanged(); |
| } |
| EXPECT_TRUE(theme_service()->UsingExtensionTheme()); |
| EXPECT_FALSE(profile()->GetPrefs()->GetUserPrefValue( |
| prefs::kNonSyncingNtpCustomBackgroundDictDoNotUse)); |
| |
| base::HistogramTester histogram_tester; |
| // Stop syncing. |
| { |
| test::ThemeServiceChangedWaiter waiter(theme_service()); |
| theme_sync_service()->StopSyncing(syncer::THEMES); |
| waiter.WaitForThemeChanged(); |
| } |
| EXPECT_FALSE(theme_service()->UsingExtensionTheme()); |
| EXPECT_TRUE(theme_service()->UsingDefaultTheme()); |
| histogram_tester.ExpectUniqueSample("Theme.RestoredLocalThemeUponSignout", |
| false, 1); |
| } |
| |
| TEST_F(ThemeSyncableServiceTestWithAccountThemesSeparation, |
| ShouldNotLoadLocalThemeFromPrefUponBrowserShutdown) { |
| // Set remote extension theme. |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.set_use_custom_theme(false); |
| theme_specifics.mutable_autogenerated_color_theme()->set_color(SK_ColorBLUE); |
| |
| // Start syncing. |
| std::optional<syncer::ModelError> error = |
| theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor()))); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| EXPECT_TRUE(theme_service()->UsingAutogeneratedTheme()); |
| EXPECT_NE(theme_service()->GetThemeID(), ThemeService::kUserColorThemeID); |
| |
| // Set saved local theme pref. |
| sync_pb::ThemeSpecifics local_theme_specifics; |
| local_theme_specifics.set_use_custom_theme(false); |
| sync_pb::ThemeSpecifics::UserColorTheme* user_color_theme = |
| local_theme_specifics.mutable_user_color_theme(); |
| user_color_theme->set_color(SK_ColorRED); |
| user_color_theme->set_browser_color_variant( |
| sync_pb::ThemeSpecifics_UserColorTheme_BrowserColorVariant_TONAL_SPOT); |
| |
| profile()->GetPrefs()->SetString( |
| prefs::kSavedLocalTheme, |
| base::Base64Encode(local_theme_specifics.SerializeAsString())); |
| |
| base::HistogramTester histogram_tester; |
| // Browser shutdown. |
| theme_sync_service()->OnBrowserShutdown(syncer::THEMES); |
| |
| // Theme remains the same. |
| EXPECT_TRUE(theme_service()->UsingAutogeneratedTheme()); |
| EXPECT_NE(theme_service()->GetThemeID(), ThemeService::kUserColorThemeID); |
| histogram_tester.ExpectTotalCount("Theme.RestoredLocalThemeUponSignout", 0); |
| } |
| |
| class ThemeSyncableServiceTestForThemeExtension |
| : public ThemeSyncableServiceTestWithAccountThemesSeparation { |
| public: |
| void SetUp() override { |
| ThemeSyncableServiceTestWithAccountThemesSeparation::SetUp(); |
| |
| // Remove theme extension added during parent SetUp(). |
| service_->UnloadAllExtensionsForTest(); |
| ASSERT_FALSE( |
| extensions::ExtensionRegistry::Get(profile())->GetExtensionById( |
| kCustomThemeId, extensions::ExtensionRegistry::EVERYTHING)); |
| ASSERT_FALSE(extensions::PendingExtensionManager::Get(profile()) |
| ->HasPendingExtensions()); |
| |
| pending_extension_manager_ = |
| extensions::PendingExtensionManager::Get(profile()); |
| extension_registry_ = extensions::ExtensionRegistry::Get(profile()); |
| } |
| |
| void InstallExtension() { |
| registrar()->OnExtensionInstalled( |
| theme_extension(), syncer::StringOrdinal(), |
| extensions::kInstallFlagInstallImmediately); |
| EXPECT_TRUE(base::test::RunUntil( |
| [&]() { return theme_service()->UsingExtensionTheme(); })); |
| EXPECT_TRUE(extensions::ExtensionRegistry::Get(profile())->GetExtensionById( |
| kCustomThemeId, extensions::ExtensionRegistry::EVERYTHING)); |
| } |
| |
| protected: |
| raw_ptr<extensions::PendingExtensionManager> pending_extension_manager_ = |
| nullptr; |
| raw_ptr<extensions::ExtensionRegistry> extension_registry_ = nullptr; |
| }; |
| |
| TEST_F(ThemeSyncableServiceTestForThemeExtension, |
| ShouldRemovePendingThemeExtensionUponSignout) { |
| // Set remote theme extension. |
| sync_pb::ThemeSpecifics theme_specifics = |
| theme_service::test::CreateThemeSpecificsWithExtensionTheme( |
| kCustomThemeId, kCustomThemeName, kCustomThemeUrl); |
| |
| // Start syncing. |
| theme_sync_service()->WillStartInitialSync(); |
| ASSERT_FALSE(theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor())))); |
| |
| // The theme extension is pending install, hence the current theme is still |
| // the default theme. |
| EXPECT_TRUE(theme_service()->UsingDefaultTheme()); |
| EXPECT_TRUE(pending_extension_manager_->IsIdPending(kCustomThemeId)); |
| |
| // Stop syncing. |
| theme_sync_service()->StopSyncing(syncer::THEMES); |
| EXPECT_TRUE(theme_service()->UsingDefaultTheme()); |
| // The pending theme extension should be cleared. |
| EXPECT_FALSE(pending_extension_manager_->HasPendingExtensions()); |
| } |
| |
| TEST_F(ThemeSyncableServiceTestForThemeExtension, |
| ShouldRemoveInstalledThemeExtensionUponSignout) { |
| // Set remote theme extension. |
| sync_pb::ThemeSpecifics theme_specifics = |
| theme_service::test::CreateThemeSpecificsWithExtensionTheme( |
| kCustomThemeId, kCustomThemeName, kCustomThemeUrl); |
| |
| // Start syncing. |
| theme_sync_service()->WillStartInitialSync(); |
| ASSERT_FALSE(theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor())))); |
| |
| // Simulate installing theme extension. |
| InstallExtension(); |
| |
| // Stop syncing. |
| theme_sync_service()->StopSyncing(syncer::THEMES); |
| EXPECT_TRUE(theme_service()->UsingDefaultTheme()); |
| // The extension was removed. |
| EXPECT_FALSE(extension_registry_->GetExtensionById( |
| kCustomThemeId, extensions::ExtensionRegistry::EVERYTHING)); |
| } |
| |
| // This tests that remote theme extension is neither installed nor removed upon |
| // signout if the same theme extension was already applied. |
| TEST_F(ThemeSyncableServiceTestForThemeExtension, |
| ShouldNotRemoveThemeExtensionUponSignoutIfPreexistingTheme) { |
| InstallExtension(); |
| |
| // Set the same remote theme extension. |
| sync_pb::ThemeSpecifics theme_specifics = |
| theme_service::test::CreateThemeSpecificsWithExtensionTheme( |
| kCustomThemeId, kCustomThemeName, kCustomThemeUrl); |
| |
| // Start syncing. |
| theme_sync_service()->WillStartInitialSync(); |
| ASSERT_FALSE(theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor())))); |
| |
| // Theme extension is already applied and doesn't need installation. |
| ASSERT_TRUE(theme_service()->UsingExtensionTheme()); |
| EXPECT_FALSE(pending_extension_manager_->IsIdPending(kCustomThemeId)); |
| |
| // Stop syncing. |
| theme_sync_service()->StopSyncing(syncer::THEMES); |
| EXPECT_TRUE(theme_service()->UsingExtensionTheme()); |
| // The extension was not removed. |
| EXPECT_TRUE(extension_registry_->GetExtensionById( |
| kCustomThemeId, extensions::ExtensionRegistry::EVERYTHING)); |
| } |
| |
| // This tests that remote theme extension is neither installed nor removed upon |
| // signout if the theme extension already exists (for example, if the extension |
| // is disabled). |
| TEST_F(ThemeSyncableServiceTestForThemeExtension, |
| ShouldNotRemoveThemeExtensionUponSignoutIfPreexisting) { |
| // Theme extension pre-exists but is disabled. |
| InstallExtension(); |
| registrar()->DisableExtension( |
| kCustomThemeId, {extensions::disable_reason::DISABLE_USER_ACTION}); |
| ASSERT_TRUE(extension_registry_->GetExtensionById( |
| kCustomThemeId, extensions::ExtensionRegistry::EVERYTHING)); |
| ASSERT_FALSE(theme_service()->UsingExtensionTheme()); |
| |
| // Set the same remote theme extension. |
| sync_pb::ThemeSpecifics theme_specifics = |
| theme_service::test::CreateThemeSpecificsWithExtensionTheme( |
| kCustomThemeId, kCustomThemeName, kCustomThemeUrl); |
| |
| // Start syncing. |
| theme_sync_service()->WillStartInitialSync(); |
| ASSERT_FALSE(theme_sync_service()->MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::unique_ptr<syncer::SyncChangeProcessor>( |
| new syncer::SyncChangeProcessorWrapperForTest( |
| fake_change_processor())))); |
| // Theme extension doesn't need installation. |
| EXPECT_FALSE(pending_extension_manager_->IsIdPending(kCustomThemeId)); |
| ASSERT_TRUE(base::test::RunUntil( |
| [&]() { return theme_service()->UsingExtensionTheme(); })); |
| |
| // Stop syncing. |
| theme_sync_service()->StopSyncing(syncer::THEMES); |
| // The extension was not removed. |
| EXPECT_TRUE(extension_registry_->GetExtensionById( |
| kCustomThemeId, extensions::ExtensionRegistry::EVERYTHING)); |
| } |
| |
| class ThemePrefsMigrationTest : public ::testing::Test { |
| public: |
| void SetUp() override { |
| user_prefs::PrefRegistrySyncable* registry = pref_service_.registry(); |
| // Register all the prefs involved in the migration. |
| registry->RegisterBooleanPref(prefs::kSyncingThemePrefsMigratedToNonSyncing, |
| false); |
| registry->RegisterIntegerPref( |
| prefs::kBrowserColorSchemeDoNotUse, |
| static_cast<int>(ThemeService::BrowserColorScheme::kSystem), |
| user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); |
| registry->RegisterIntegerPref( |
| prefs::kNonSyncingBrowserColorSchemeDoNotUse, |
| static_cast<int>(ThemeService::BrowserColorScheme::kSystem)); |
| registry->RegisterIntegerPref( |
| prefs::kUserColorDoNotUse, SK_ColorTRANSPARENT, |
| user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); |
| registry->RegisterIntegerPref(prefs::kNonSyncingUserColorDoNotUse, |
| SK_ColorTRANSPARENT); |
| registry->RegisterIntegerPref( |
| prefs::kBrowserColorVariantDoNotUse, |
| static_cast<int>(ui::mojom::BrowserColorVariant::kSystem), |
| user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); |
| registry->RegisterIntegerPref( |
| prefs::kNonSyncingBrowserColorVariantDoNotUse, |
| static_cast<int>(ui::mojom::BrowserColorVariant::kSystem)); |
| registry->RegisterBooleanPref( |
| prefs::kGrayscaleThemeEnabledDoNotUse, false, |
| user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); |
| registry->RegisterBooleanPref( |
| prefs::kNonSyncingGrayscaleThemeEnabledDoNotUse, false); |
| registry->RegisterDictionaryPref(prefs::kNtpCustomBackgroundDictDoNotUse); |
| registry->RegisterDictionaryPref( |
| prefs::kNonSyncingNtpCustomBackgroundDictDoNotUse); |
| } |
| |
| protected: |
| sync_preferences::TestingPrefServiceSyncable pref_service_; |
| }; |
| |
| TEST_F(ThemePrefsMigrationTest, MigrateSyncingThemePrefsToNonSyncing) { |
| base::test::ScopedFeatureList feature_list( |
| syncer::kMoveThemePrefsToSpecifics); |
| |
| ASSERT_FALSE( |
| pref_service_.GetBoolean(prefs::kSyncingThemePrefsMigratedToNonSyncing)); |
| |
| pref_service_.SetInteger(prefs::kUserColorDoNotUse, SK_ColorBLUE); |
| EXPECT_FALSE(pref_service_.HasPrefPath(prefs::kNonSyncingUserColorDoNotUse)); |
| |
| base::HistogramTester histogram_tester; |
| MigrateSyncingThemePrefsToNonSyncingIfNeeded(&pref_service_); |
| EXPECT_TRUE( |
| pref_service_.GetBoolean(prefs::kSyncingThemePrefsMigratedToNonSyncing)); |
| EXPECT_EQ(pref_service_.GetInteger(prefs::kNonSyncingUserColorDoNotUse), |
| static_cast<int>(SK_ColorBLUE)); |
| histogram_tester.ExpectUniqueSample( |
| kThemePrefMigrationAlreadyMigratedHistogram, false, 1); |
| histogram_tester.ExpectUniqueSample(kThemePrefMigrationMigratedPrefHistogram, |
| ThemePrefInMigration::kUserColor, 1); |
| } |
| |
| TEST_F(ThemePrefsMigrationTest, MigrateSyncingNtpPrefToNonSyncing) { |
| base::test::ScopedFeatureList feature_list( |
| syncer::kMoveThemePrefsToSpecifics); |
| |
| ASSERT_FALSE( |
| pref_service_.GetBoolean(prefs::kSyncingThemePrefsMigratedToNonSyncing)); |
| |
| pref_service_.SetInteger(prefs::kUserColorDoNotUse, SK_ColorBLUE); |
| EXPECT_FALSE(pref_service_.HasPrefPath(prefs::kNonSyncingUserColorDoNotUse)); |
| |
| pref_service_.SetDict( |
| prefs::kNtpCustomBackgroundDictDoNotUse, |
| base::Value::Dict() |
| .Set(kNtpCustomBackgroundURL, kTestUrl) |
| .Set(kNtpCustomBackgroundAttributionLine1, "attribution_line_1") |
| .Set(kNtpCustomBackgroundAttributionLine2, "attribution_line_2") |
| .Set(kNtpCustomBackgroundAttributionActionURL, |
| "attribution_action_url") |
| .Set(kNtpCustomBackgroundCollectionId, "collection_id") |
| .Set(kNtpCustomBackgroundResumeToken, "resume_token") |
| .Set(kNtpCustomBackgroundRefreshTimestamp, |
| static_cast<int>(1234567890)) |
| .Set(kNtpCustomBackgroundMainColor, static_cast<int>(SK_ColorRED))); |
| |
| base::HistogramTester histogram_tester; |
| MigrateSyncingThemePrefsToNonSyncingIfNeeded(&pref_service_); |
| EXPECT_TRUE( |
| pref_service_.GetBoolean(prefs::kSyncingThemePrefsMigratedToNonSyncing)); |
| EXPECT_EQ(pref_service_.GetInteger(prefs::kNonSyncingUserColorDoNotUse), |
| static_cast<int>(SK_ColorBLUE)); |
| histogram_tester.ExpectUniqueSample( |
| kThemePrefMigrationAlreadyMigratedHistogram, false, 1); |
| histogram_tester.ExpectBucketCount(kThemePrefMigrationMigratedPrefHistogram, |
| ThemePrefInMigration::kUserColor, 1); |
| histogram_tester.ExpectBucketCount( |
| kThemePrefMigrationMigratedPrefHistogram, |
| ThemePrefInMigration::kNtpCustomBackgroundDict, 1); |
| } |
| |
| TEST_F(ThemePrefsMigrationTest, |
| DoNotMigrateSyncingThemePrefsToNonSyncingIfFlagDisabled) { |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitAndDisableFeature(syncer::kMoveThemePrefsToSpecifics); |
| |
| ASSERT_FALSE( |
| pref_service_.GetBoolean(prefs::kSyncingThemePrefsMigratedToNonSyncing)); |
| |
| base::HistogramTester histogram_tester; |
| MigrateSyncingThemePrefsToNonSyncingIfNeeded(&pref_service_); |
| EXPECT_FALSE( |
| pref_service_.GetBoolean(prefs::kSyncingThemePrefsMigratedToNonSyncing)); |
| histogram_tester.ExpectTotalCount(kThemePrefMigrationAlreadyMigratedHistogram, |
| 0); |
| histogram_tester.ExpectTotalCount(kThemePrefMigrationMigratedPrefHistogram, |
| 0); |
| } |
| |
| TEST_F(ThemePrefsMigrationTest, |
| DoNotMigrateSyncingThemePrefsToNonSyncingIfAlreadyDone) { |
| base::test::ScopedFeatureList feature_list( |
| syncer::kMoveThemePrefsToSpecifics); |
| |
| pref_service_.SetBoolean(prefs::kSyncingThemePrefsMigratedToNonSyncing, true); |
| pref_service_.SetInteger(prefs::kUserColorDoNotUse, SK_ColorBLUE); |
| |
| base::HistogramTester histogram_tester; |
| MigrateSyncingThemePrefsToNonSyncingIfNeeded(&pref_service_); |
| EXPECT_FALSE(pref_service_.HasPrefPath(prefs::kNonSyncingUserColorDoNotUse)); |
| histogram_tester.ExpectUniqueSample( |
| kThemePrefMigrationAlreadyMigratedHistogram, true, 1); |
| histogram_tester.ExpectTotalCount(kThemePrefMigrationMigratedPrefHistogram, |
| 0); |
| } |
| |
| TEST_F(ThemePrefsMigrationTest, |
| ClearFlagUponMigrateSyncingThemePrefsToNonSyncingIfFlagDisabled) { |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitAndDisableFeature(syncer::kMoveThemePrefsToSpecifics); |
| |
| // Migration has run before. |
| pref_service_.SetBoolean(prefs::kSyncingThemePrefsMigratedToNonSyncing, true); |
| |
| MigrateSyncingThemePrefsToNonSyncingIfNeeded(&pref_service_); |
| // Flag gets cleared to allow re-migration. |
| EXPECT_FALSE( |
| pref_service_.GetBoolean(prefs::kSyncingThemePrefsMigratedToNonSyncing)); |
| } |
| |
| class ThemePrefsMigrationShouldReadPrefsTestBase : public ::testing::Test { |
| public: |
| explicit ThemePrefsMigrationShouldReadPrefsTestBase(bool is_flag_enabled) { |
| if (is_flag_enabled) { |
| feature_list_.InitAndEnableFeature(syncer::kMoveThemePrefsToSpecifics); |
| } else { |
| feature_list_.InitAndDisableFeature(syncer::kMoveThemePrefsToSpecifics); |
| } |
| profile_ = std::make_unique<TestingProfile>(); |
| // TestingProfile init automatically leads to creation of |
| // ThemeSyncableService. To allow for more control for tests, reset the |
| // ThemeSyncableService instance. |
| theme_service()->ResetThemeSyncableServiceForTest(); |
| |
| prefs()->SetBoolean(prefs::kShouldReadIncomingSyncingThemePrefs, true); |
| } |
| |
| syncer::SyncDataList InitialPrefsSyncData() { |
| syncer::SyncDataList initial_data; |
| initial_data.push_back(CreateRemotePrefsSyncData( |
| prefs::kBrowserColorSchemeDoNotUse, |
| base::Value( |
| static_cast<int>(ThemeService::BrowserColorScheme::kLight)))); |
| initial_data.push_back(CreateRemotePrefsSyncData( |
| prefs::kUserColorDoNotUse, base::Value(static_cast<int>(SK_ColorRED)))); |
| initial_data.push_back(CreateRemotePrefsSyncData( |
| prefs::kBrowserColorVariantDoNotUse, |
| base::Value( |
| static_cast<int>(ui::mojom::BrowserColorVariant::kTonalSpot)))); |
| return initial_data; |
| } |
| |
| sync_preferences::TestingPrefServiceSyncable* prefs() { |
| return profile_->GetTestingPrefService(); |
| } |
| |
| ThemeService* theme_service() { |
| return ThemeServiceFactory::GetForProfile(profile_.get()); |
| } |
| |
| protected: |
| syncer::SyncData CreateRemotePrefsSyncData(const std::string& name, |
| const base::Value& value) { |
| std::string serialized; |
| JSONStringValueSerializer json(&serialized); |
| EXPECT_TRUE(json.Serialize(value)); |
| sync_pb::EntitySpecifics entity_specifics; |
| sync_pb::PreferenceSpecifics* specifics = |
| entity_specifics.mutable_preference(); |
| specifics->set_name(name); |
| specifics->set_value(serialized); |
| return syncer::SyncData::CreateRemoteData( |
| entity_specifics, syncer::ClientTagHash::FromUnhashed( |
| syncer::DataType::PREFERENCES, name)); |
| } |
| |
| base::test::ScopedFeatureList feature_list_; |
| content::BrowserTaskEnvironment task_environment_; |
| std::unique_ptr<syncer::FakeSyncChangeProcessor> fake_change_processor_ = |
| std::make_unique<syncer::FakeSyncChangeProcessor>(); |
| std::unique_ptr<TestingProfile> profile_; |
| }; |
| |
| class ThemePrefsMigrationShouldReadPrefsTestWithFlagDisabled |
| : public ThemePrefsMigrationShouldReadPrefsTestBase { |
| public: |
| ThemePrefsMigrationShouldReadPrefsTestWithFlagDisabled() |
| : ThemePrefsMigrationShouldReadPrefsTestBase(false) {} |
| }; |
| |
| // Verifies that if kMoveThemePrefsToSpecifics feature flag is not set, the |
| // migration flag is marked unset to allow migration again once the feature flag |
| // is enabled again. |
| TEST_F(ThemePrefsMigrationShouldReadPrefsTestWithFlagDisabled, |
| ClearShouldReadPrefFlagIfFeatureDisabled) { |
| // Migration has run before. |
| prefs()->SetBoolean(prefs::kShouldReadIncomingSyncingThemePrefs, false); |
| |
| ThemeSyncableService theme_syncable_service(profile_.get(), theme_service()); |
| |
| // Flag gets cleared to allow re-migration. |
| EXPECT_TRUE(prefs()->GetBoolean(prefs::kShouldReadIncomingSyncingThemePrefs)); |
| } |
| |
| class ThemePrefsMigrationShouldReadPrefsTestWithFlagEnabled |
| : public ThemePrefsMigrationShouldReadPrefsTestBase { |
| public: |
| ThemePrefsMigrationShouldReadPrefsTestWithFlagEnabled() |
| : ThemePrefsMigrationShouldReadPrefsTestBase(true) {} |
| }; |
| |
| // Verifies that syncing prefs are read upon construction of |
| // ThemeSyncableService if prefs sync has already started. |
| TEST_F(ThemePrefsMigrationShouldReadPrefsTestWithFlagEnabled, |
| ShouldReadThemePrefsOnContructionIfPrefsAlreadySyncing) { |
| ASSERT_TRUE(prefs()->GetBoolean(prefs::kShouldReadIncomingSyncingThemePrefs)); |
| |
| // Start prefs sync. |
| syncer::SyncableService* pref_sync_service = |
| prefs()->GetSyncableService(syncer::PREFERENCES); |
| ASSERT_FALSE(pref_sync_service->MergeDataAndStartSyncing( |
| syncer::PREFERENCES, InitialPrefsSyncData(), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor_.get()))); |
| |
| ASSERT_TRUE(prefs()->IsSyncing()); |
| |
| base::HistogramTester histogram_tester; |
| ThemeSyncableService theme_syncable_service(profile_.get(), theme_service()); |
| |
| // Syncing prefs were copied. |
| EXPECT_FALSE( |
| prefs()->GetBoolean(prefs::kShouldReadIncomingSyncingThemePrefs)); |
| EXPECT_EQ(prefs()->GetInteger(prefs::kNonSyncingBrowserColorSchemeDoNotUse), |
| static_cast<int>(ThemeService::BrowserColorScheme::kLight)); |
| EXPECT_EQ(prefs()->GetInteger(prefs::kNonSyncingUserColorDoNotUse), |
| static_cast<int>(SK_ColorRED)); |
| EXPECT_EQ(prefs()->GetInteger(prefs::kNonSyncingBrowserColorVariantDoNotUse), |
| static_cast<int>(ui::mojom::BrowserColorVariant::kTonalSpot)); |
| |
| // The applied prefs were logged. |
| EXPECT_THAT( |
| histogram_tester.GetAllSamples( |
| kThemePrefMigrationIncomingSyncingPrefAppliedHistogram), |
| testing::ElementsAre( |
| base::Bucket( |
| static_cast<int>(ThemePrefInMigration::kBrowserColorScheme), 1), |
| base::Bucket(static_cast<int>(ThemePrefInMigration::kUserColor), 1), |
| base::Bucket( |
| static_cast<int>(ThemePrefInMigration::kBrowserColorVariant), |
| 1))); |
| } |
| |
| // Verifies that syncing theme prefs are read when prefs sync starts. |
| TEST_F(ThemePrefsMigrationShouldReadPrefsTestWithFlagEnabled, |
| ShouldReadThemePrefsWhenPrefsStartSyncing) { |
| ASSERT_TRUE(prefs()->GetBoolean(prefs::kShouldReadIncomingSyncingThemePrefs)); |
| |
| ASSERT_FALSE(prefs()->IsSyncing()); |
| base::HistogramTester histogram_tester; |
| ThemeSyncableService theme_syncable_service(profile_.get(), theme_service()); |
| |
| // No pref logged yet since prefs hasn't started syncing. |
| histogram_tester.ExpectTotalCount( |
| kThemePrefMigrationIncomingSyncingPrefAppliedHistogram, 0); |
| |
| // Start prefs sync. |
| syncer::SyncableService* pref_sync_service = |
| prefs()->GetSyncableService(syncer::PREFERENCES); |
| ASSERT_FALSE(pref_sync_service->MergeDataAndStartSyncing( |
| syncer::PREFERENCES, InitialPrefsSyncData(), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor_.get()))); |
| |
| // Syncing prefs have been copied. |
| EXPECT_FALSE( |
| prefs()->GetBoolean(prefs::kShouldReadIncomingSyncingThemePrefs)); |
| EXPECT_EQ(prefs()->GetInteger(prefs::kNonSyncingBrowserColorSchemeDoNotUse), |
| static_cast<int>(ThemeService::BrowserColorScheme::kLight)); |
| EXPECT_EQ(prefs()->GetInteger(prefs::kNonSyncingUserColorDoNotUse), |
| static_cast<int>(SK_ColorRED)); |
| EXPECT_EQ(prefs()->GetInteger(prefs::kNonSyncingBrowserColorVariantDoNotUse), |
| static_cast<int>(ui::mojom::BrowserColorVariant::kTonalSpot)); |
| |
| // The applied prefs were logged. |
| EXPECT_THAT( |
| histogram_tester.GetAllSamples( |
| kThemePrefMigrationIncomingSyncingPrefAppliedHistogram), |
| testing::ElementsAre( |
| base::Bucket( |
| static_cast<int>(ThemePrefInMigration::kBrowserColorScheme), 1), |
| base::Bucket(static_cast<int>(ThemePrefInMigration::kUserColor), 1), |
| base::Bucket( |
| static_cast<int>(ThemePrefInMigration::kBrowserColorVariant), |
| 1))); |
| } |
| |
| // Verifies that syncing theme prefs are not read if they have already been read |
| // before or if the migration flag has already been set. |
| TEST_F(ThemePrefsMigrationShouldReadPrefsTestWithFlagEnabled, |
| ShouldNotReadThemePrefsIfAlreadyRead) { |
| // Mark as already read. |
| prefs()->SetBoolean(prefs::kShouldReadIncomingSyncingThemePrefs, false); |
| |
| base::HistogramTester histogram_tester; |
| ThemeSyncableService theme_syncable_service(profile_.get(), theme_service()); |
| |
| // Start prefs sync. |
| syncer::SyncableService* pref_sync_service = |
| prefs()->GetSyncableService(syncer::PREFERENCES); |
| ASSERT_FALSE(pref_sync_service->MergeDataAndStartSyncing( |
| syncer::PREFERENCES, InitialPrefsSyncData(), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor_.get()))); |
| |
| // Prefs are unchanged. |
| EXPECT_FALSE( |
| prefs()->GetBoolean(prefs::kShouldReadIncomingSyncingThemePrefs)); |
| EXPECT_NE(prefs()->GetInteger(prefs::kNonSyncingBrowserColorSchemeDoNotUse), |
| static_cast<int>(ThemeService::BrowserColorScheme::kLight)); |
| EXPECT_NE(prefs()->GetInteger(prefs::kNonSyncingUserColorDoNotUse), |
| static_cast<int>(SK_ColorRED)); |
| EXPECT_NE(prefs()->GetInteger(prefs::kNonSyncingBrowserColorVariantDoNotUse), |
| static_cast<int>(ui::mojom::BrowserColorVariant::kTonalSpot)); |
| |
| // No pref logged. |
| histogram_tester.ExpectTotalCount( |
| kThemePrefMigrationIncomingSyncingPrefAppliedHistogram, 0); |
| } |
| |
| // Verifies that the migration flag is set and (thus) syncing prefs are not read |
| // if the incoming ThemeSpecifics contains the new fields. |
| TEST_F(ThemePrefsMigrationShouldReadPrefsTestWithFlagEnabled, |
| ShouldNotReadThemePrefsIfReadViaThemeSpecifics) { |
| ASSERT_TRUE(prefs()->GetBoolean(prefs::kShouldReadIncomingSyncingThemePrefs)); |
| |
| ASSERT_FALSE(prefs()->IsSyncing()); |
| ThemeSyncableService theme_syncable_service(profile_.get(), theme_service()); |
| |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.set_browser_color_scheme( |
| sync_pb::ThemeSpecifics_BrowserColorScheme_DARK); |
| |
| // Start themes sync with specifics containing new field. |
| std::optional<syncer::ModelError> error = |
| theme_syncable_service.MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor_.get())); |
| ASSERT_FALSE(error.has_value()) << error.value().message(); |
| |
| // Migration flag is already set. |
| EXPECT_FALSE( |
| prefs()->GetBoolean(prefs::kShouldReadIncomingSyncingThemePrefs)); |
| EXPECT_EQ(prefs()->GetInteger(prefs::kNonSyncingBrowserColorSchemeDoNotUse), |
| static_cast<int>(ThemeService::BrowserColorScheme::kDark)); |
| |
| // Start prefs sync. |
| syncer::SyncableService* pref_sync_service = |
| prefs()->GetSyncableService(syncer::PREFERENCES); |
| ASSERT_FALSE(pref_sync_service->MergeDataAndStartSyncing( |
| syncer::PREFERENCES, InitialPrefsSyncData(), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor_.get()))); |
| |
| // Syncing prefs have not been copied since ThemeSpecifics had the new fields. |
| EXPECT_FALSE( |
| prefs()->GetBoolean(prefs::kShouldReadIncomingSyncingThemePrefs)); |
| EXPECT_NE(prefs()->GetInteger(prefs::kNonSyncingBrowserColorSchemeDoNotUse), |
| static_cast<int>(ThemeService::BrowserColorScheme::kLight)); |
| EXPECT_NE(prefs()->GetInteger(prefs::kNonSyncingUserColorDoNotUse), |
| static_cast<int>(SK_ColorRED)); |
| EXPECT_NE(prefs()->GetInteger(prefs::kNonSyncingBrowserColorVariantDoNotUse), |
| static_cast<int>(ui::mojom::BrowserColorVariant::kTonalSpot)); |
| } |
| |
| // Verifies that syncing theme prefs are read if the incoming ThemeSpecifics |
| // didn't have the new fields. |
| TEST_F(ThemePrefsMigrationShouldReadPrefsTestWithFlagEnabled, |
| ShouldReadThemePrefsIfThemeSpecificsDoesNotHaveNewFields) { |
| ASSERT_TRUE(prefs()->GetBoolean(prefs::kShouldReadIncomingSyncingThemePrefs)); |
| |
| ASSERT_FALSE(prefs()->IsSyncing()); |
| ThemeSyncableService theme_syncable_service(profile_.get(), theme_service()); |
| |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.mutable_autogenerated_color_theme()->set_color(SK_ColorBLUE); |
| |
| // Start themes sync with specifics containing new field. |
| ASSERT_FALSE(theme_syncable_service.MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor_.get()))); |
| |
| EXPECT_TRUE(prefs()->GetBoolean(prefs::kShouldReadIncomingSyncingThemePrefs)); |
| |
| // Start prefs sync. |
| syncer::SyncableService* pref_sync_service = |
| prefs()->GetSyncableService(syncer::PREFERENCES); |
| ASSERT_FALSE(pref_sync_service->MergeDataAndStartSyncing( |
| syncer::PREFERENCES, InitialPrefsSyncData(), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor_.get()))); |
| |
| // Syncing prefs copied since ThemeSpecifics didn't have the new fields. |
| EXPECT_FALSE( |
| prefs()->GetBoolean(prefs::kShouldReadIncomingSyncingThemePrefs)); |
| EXPECT_EQ(prefs()->GetInteger(prefs::kNonSyncingBrowserColorSchemeDoNotUse), |
| static_cast<int>(ThemeService::BrowserColorScheme::kLight)); |
| EXPECT_EQ(prefs()->GetInteger(prefs::kNonSyncingUserColorDoNotUse), |
| static_cast<int>(SK_ColorRED)); |
| EXPECT_EQ(prefs()->GetInteger(prefs::kNonSyncingBrowserColorVariantDoNotUse), |
| static_cast<int>(ui::mojom::BrowserColorVariant::kTonalSpot)); |
| } |
| |
| // Verifies that the incoming ThemeSpecifics overwrites the value copied from |
| // the syncing theme prefs. |
| TEST_F(ThemePrefsMigrationShouldReadPrefsTestWithFlagEnabled, |
| ShouldPrioritizeThemeSpecifics) { |
| ASSERT_TRUE(prefs()->GetBoolean(prefs::kShouldReadIncomingSyncingThemePrefs)); |
| |
| ASSERT_FALSE(prefs()->IsSyncing()); |
| ThemeSyncableService theme_syncable_service(profile_.get(), theme_service()); |
| |
| // Start prefs sync. |
| syncer::SyncableService* pref_sync_service = |
| prefs()->GetSyncableService(syncer::PREFERENCES); |
| ASSERT_FALSE(pref_sync_service->MergeDataAndStartSyncing( |
| syncer::PREFERENCES, InitialPrefsSyncData(), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor_.get()))); |
| |
| EXPECT_FALSE( |
| prefs()->GetBoolean(prefs::kShouldReadIncomingSyncingThemePrefs)); |
| EXPECT_EQ(prefs()->GetInteger(prefs::kNonSyncingBrowserColorSchemeDoNotUse), |
| static_cast<int>(ThemeService::BrowserColorScheme::kLight)); |
| |
| sync_pb::ThemeSpecifics theme_specifics; |
| theme_specifics.set_browser_color_scheme( |
| sync_pb::ThemeSpecifics_BrowserColorScheme_DARK); |
| |
| // Start themes sync with specifics containing new field. |
| ASSERT_FALSE(theme_syncable_service.MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(theme_specifics), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor_.get()))); |
| |
| EXPECT_FALSE( |
| prefs()->GetBoolean(prefs::kShouldReadIncomingSyncingThemePrefs)); |
| // Overwrites the theme set by prefs. |
| EXPECT_EQ(prefs()->GetInteger(prefs::kNonSyncingBrowserColorSchemeDoNotUse), |
| static_cast<int>(ThemeService::BrowserColorScheme::kDark)); |
| } |
| |
| // Regression test for crbug.com/375553464. |
| TEST_F(ThemePrefsMigrationShouldReadPrefsTestWithFlagEnabled, |
| ShouldOnlyNotifyOnceUponReadingThemePrefs) { |
| ASSERT_FALSE(prefs()->IsSyncing()); |
| ThemeSyncableService theme_syncable_service(profile_.get(), theme_service()); |
| |
| theme_service()->SetUserColorAndBrowserColorVariant( |
| SK_ColorBLUE, ui::mojom::BrowserColorVariant::kNeutral); |
| |
| ASSERT_EQ(fake_change_processor_->changes().size(), 0u); |
| |
| // Start themes sync. |
| ASSERT_FALSE(theme_syncable_service.MergeDataAndStartSyncing( |
| syncer::THEMES, MakeThemeDataList(sync_pb::ThemeSpecifics()), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor_.get()))); |
| |
| ASSERT_EQ(fake_change_processor_->changes().size(), 1u); |
| ASSERT_EQ(prefs()->GetInteger(prefs::kNonSyncingUserColorDoNotUse), |
| static_cast<int>(SK_ColorBLUE)); |
| ASSERT_EQ(prefs()->GetInteger(prefs::kNonSyncingBrowserColorVariantDoNotUse), |
| static_cast<int>(ui::mojom::BrowserColorVariant::kNeutral)); |
| |
| ASSERT_TRUE(prefs()->GetBoolean(prefs::kShouldReadIncomingSyncingThemePrefs)); |
| // Start prefs sync. |
| syncer::SyncableService* pref_sync_service = |
| prefs()->GetSyncableService(syncer::PREFERENCES); |
| ASSERT_FALSE(pref_sync_service->MergeDataAndStartSyncing( |
| syncer::PREFERENCES, InitialPrefsSyncData(), |
| std::make_unique<syncer::SyncChangeProcessorWrapperForTest>( |
| fake_change_processor_.get()))); |
| |
| EXPECT_EQ(2, std::ranges::count_if( |
| fake_change_processor_->changes(), [](const auto& e) { |
| return e.sync_data().GetSpecifics().has_theme(); |
| })); |
| EXPECT_EQ(prefs()->GetInteger(prefs::kNonSyncingUserColorDoNotUse), |
| static_cast<int>(SK_ColorRED)); |
| EXPECT_EQ(prefs()->GetInteger(prefs::kNonSyncingBrowserColorVariantDoNotUse), |
| static_cast<int>(ui::mojom::BrowserColorVariant::kTonalSpot)); |
| } |