| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // 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_service.h" |
| |
| #include "base/files/file_util.h" |
| #include "base/path_service.h" |
| #include "chrome/browser/chrome_notification_types.h" |
| #include "chrome/browser/extensions/extension_service.h" |
| #include "chrome/browser/extensions/extension_service_test_base.h" |
| #include "chrome/browser/extensions/unpacked_installer.h" |
| #include "chrome/browser/themes/custom_theme_supplier.h" |
| #include "chrome/browser/themes/theme_service_factory.h" |
| #include "chrome/common/chrome_paths.h" |
| #include "chrome/common/pref_names.h" |
| #include "chrome/test/base/testing_browser_process.h" |
| #include "chrome/test/base/testing_profile.h" |
| #include "chrome/test/base/testing_profile_manager.h" |
| #include "content/public/test/test_utils.h" |
| #include "extensions/browser/extension_registry.h" |
| #include "extensions/browser/uninstall_reason.h" |
| #include "extensions/common/extension.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| #if defined(ENABLE_MANAGED_USERS) |
| #include "chrome/browser/supervised_user/supervised_user_service.h" |
| #include "chrome/browser/supervised_user/supervised_user_service_factory.h" |
| #endif |
| |
| using extensions::ExtensionRegistry; |
| |
| namespace theme_service_internal { |
| |
| class ThemeServiceTest : public extensions::ExtensionServiceTestBase { |
| public: |
| ThemeServiceTest() : is_supervised_(false), |
| registry_(NULL) {} |
| virtual ~ThemeServiceTest() {} |
| |
| // Moves a minimal theme to |temp_dir_path| and unpacks it from that |
| // directory. |
| std::string LoadUnpackedThemeAt(const base::FilePath& temp_dir) { |
| base::FilePath dst_manifest_path = temp_dir.AppendASCII("manifest.json"); |
| base::FilePath test_data_dir; |
| EXPECT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir)); |
| base::FilePath src_manifest_path = |
| test_data_dir.AppendASCII("extensions/theme_minimal/manifest.json"); |
| EXPECT_TRUE(base::CopyFile(src_manifest_path, dst_manifest_path)); |
| |
| scoped_refptr<extensions::UnpackedInstaller> installer( |
| extensions::UnpackedInstaller::Create(service_)); |
| content::WindowedNotificationObserver observer( |
| extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED, |
| content::Source<Profile>(profile_.get())); |
| installer->Load(temp_dir); |
| observer.Wait(); |
| |
| std::string extension_id = |
| content::Details<extensions::Extension>(observer.details())->id(); |
| |
| // Let the ThemeService finish creating the theme pack. |
| base::MessageLoop::current()->RunUntilIdle(); |
| |
| return extension_id; |
| } |
| |
| // Update the theme with |extension_id|. |
| void UpdateUnpackedTheme(const std::string& extension_id) { |
| int updated_notification = |
| service_->IsExtensionEnabled(extension_id) |
| ? extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED |
| : extensions::NOTIFICATION_EXTENSION_UPDATE_DISABLED; |
| |
| const base::FilePath& path = |
| service_->GetInstalledExtension(extension_id)->path(); |
| |
| scoped_refptr<extensions::UnpackedInstaller> installer( |
| extensions::UnpackedInstaller::Create(service_)); |
| content::WindowedNotificationObserver observer(updated_notification, |
| content::Source<Profile>(profile_.get())); |
| installer->Load(path); |
| observer.Wait(); |
| |
| // Let the ThemeService finish creating the theme pack. |
| base::MessageLoop::current()->RunUntilIdle(); |
| } |
| |
| virtual void SetUp() { |
| extensions::ExtensionServiceTestBase::SetUp(); |
| extensions::ExtensionServiceTestBase::ExtensionServiceInitParams params = |
| CreateDefaultInitParams(); |
| params.profile_is_supervised = is_supervised_; |
| InitializeExtensionService(params); |
| service_->Init(); |
| registry_ = ExtensionRegistry::Get(profile_.get()); |
| ASSERT_TRUE(registry_); |
| } |
| |
| const CustomThemeSupplier* get_theme_supplier(ThemeService* theme_service) { |
| return theme_service->get_theme_supplier(); |
| } |
| |
| protected: |
| bool is_supervised_; |
| ExtensionRegistry* registry_; |
| |
| }; |
| |
| // Installs then uninstalls a theme and makes sure that the ThemeService |
| // reverts to the default theme after the uninstall. |
| TEST_F(ThemeServiceTest, ThemeInstallUninstall) { |
| ThemeService* theme_service = |
| ThemeServiceFactory::GetForProfile(profile_.get()); |
| theme_service->UseDefaultTheme(); |
| // Let the ThemeService uninstall unused themes. |
| base::MessageLoop::current()->RunUntilIdle(); |
| |
| base::ScopedTempDir temp_dir; |
| ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); |
| const std::string& extension_id = LoadUnpackedThemeAt(temp_dir.path()); |
| EXPECT_FALSE(theme_service->UsingDefaultTheme()); |
| EXPECT_EQ(extension_id, theme_service->GetThemeID()); |
| |
| // Now uninstall the extension, should revert to the default theme. |
| service_->UninstallExtension(extension_id, |
| extensions::UNINSTALL_REASON_FOR_TESTING, |
| base::Bind(&base::DoNothing), |
| NULL); |
| EXPECT_TRUE(theme_service->UsingDefaultTheme()); |
| } |
| |
| // Test that a theme extension is disabled when not in use. A theme may be |
| // installed but not in use if it there is an infobar to revert to the previous |
| // theme. |
| TEST_F(ThemeServiceTest, DisableUnusedTheme) { |
| ThemeService* theme_service = |
| ThemeServiceFactory::GetForProfile(profile_.get()); |
| theme_service->UseDefaultTheme(); |
| // Let the ThemeService uninstall unused themes. |
| base::MessageLoop::current()->RunUntilIdle(); |
| |
| base::ScopedTempDir temp_dir1; |
| ASSERT_TRUE(temp_dir1.CreateUniqueTempDir()); |
| base::ScopedTempDir temp_dir2; |
| ASSERT_TRUE(temp_dir2.CreateUniqueTempDir()); |
| |
| // 1) Installing a theme should disable the previously active theme. |
| const std::string& extension1_id = LoadUnpackedThemeAt(temp_dir1.path()); |
| EXPECT_FALSE(theme_service->UsingDefaultTheme()); |
| EXPECT_EQ(extension1_id, theme_service->GetThemeID()); |
| EXPECT_TRUE(service_->IsExtensionEnabled(extension1_id)); |
| |
| // Show an infobar to prevent the current theme from being uninstalled. |
| theme_service->OnInfobarDisplayed(); |
| |
| const std::string& extension2_id = LoadUnpackedThemeAt(temp_dir2.path()); |
| EXPECT_EQ(extension2_id, theme_service->GetThemeID()); |
| EXPECT_TRUE(service_->IsExtensionEnabled(extension2_id)); |
| EXPECT_TRUE(registry_->GetExtensionById(extension1_id, |
| ExtensionRegistry::DISABLED)); |
| |
| // 2) Enabling a disabled theme extension should swap the current theme. |
| service_->EnableExtension(extension1_id); |
| base::MessageLoop::current()->RunUntilIdle(); |
| EXPECT_EQ(extension1_id, theme_service->GetThemeID()); |
| EXPECT_TRUE(service_->IsExtensionEnabled(extension1_id)); |
| EXPECT_TRUE(registry_->GetExtensionById(extension2_id, |
| ExtensionRegistry::DISABLED)); |
| |
| // 3) Using SetTheme() with a disabled theme should enable and set the |
| // theme. This is the case when the user reverts to the previous theme |
| // via an infobar. |
| const extensions::Extension* extension2 = |
| service_->GetInstalledExtension(extension2_id); |
| theme_service->SetTheme(extension2); |
| base::MessageLoop::current()->RunUntilIdle(); |
| EXPECT_EQ(extension2_id, theme_service->GetThemeID()); |
| EXPECT_TRUE(service_->IsExtensionEnabled(extension2_id)); |
| EXPECT_TRUE(registry_->GetExtensionById(extension1_id, |
| ExtensionRegistry::DISABLED)); |
| |
| // 4) Disabling the current theme extension should revert to the default theme |
| // and uninstall any installed theme extensions. |
| theme_service->OnInfobarDestroyed(); |
| EXPECT_FALSE(theme_service->UsingDefaultTheme()); |
| service_->DisableExtension(extension2_id, |
| extensions::Extension::DISABLE_USER_ACTION); |
| base::MessageLoop::current()->RunUntilIdle(); |
| EXPECT_TRUE(theme_service->UsingDefaultTheme()); |
| EXPECT_FALSE(service_->GetInstalledExtension(extension1_id)); |
| EXPECT_FALSE(service_->GetInstalledExtension(extension2_id)); |
| } |
| |
| // Test the ThemeService's behavior when a theme is upgraded. |
| TEST_F(ThemeServiceTest, ThemeUpgrade) { |
| // Setup. |
| ThemeService* theme_service = |
| ThemeServiceFactory::GetForProfile(profile_.get()); |
| theme_service->UseDefaultTheme(); |
| // Let the ThemeService uninstall unused themes. |
| base::MessageLoop::current()->RunUntilIdle(); |
| |
| theme_service->OnInfobarDisplayed(); |
| |
| base::ScopedTempDir temp_dir1; |
| ASSERT_TRUE(temp_dir1.CreateUniqueTempDir()); |
| base::ScopedTempDir temp_dir2; |
| ASSERT_TRUE(temp_dir2.CreateUniqueTempDir()); |
| |
| const std::string& extension1_id = LoadUnpackedThemeAt(temp_dir1.path()); |
| const std::string& extension2_id = LoadUnpackedThemeAt(temp_dir2.path()); |
| |
| // Test the initial state. |
| EXPECT_TRUE(registry_->GetExtensionById(extension1_id, |
| ExtensionRegistry::DISABLED)); |
| EXPECT_EQ(extension2_id, theme_service->GetThemeID()); |
| |
| // 1) Upgrading the current theme should not revert to the default theme. |
| content::WindowedNotificationObserver theme_change_observer( |
| chrome::NOTIFICATION_BROWSER_THEME_CHANGED, |
| content::Source<ThemeService>(theme_service)); |
| UpdateUnpackedTheme(extension2_id); |
| |
| // The ThemeService should have sent an theme change notification even though |
| // the id of the current theme did not change. |
| theme_change_observer.Wait(); |
| |
| EXPECT_EQ(extension2_id, theme_service->GetThemeID()); |
| EXPECT_TRUE(registry_->GetExtensionById(extension1_id, |
| ExtensionRegistry::DISABLED)); |
| |
| // 2) Upgrading a disabled theme should not change the current theme. |
| UpdateUnpackedTheme(extension1_id); |
| EXPECT_EQ(extension2_id, theme_service->GetThemeID()); |
| EXPECT_TRUE(registry_->GetExtensionById(extension1_id, |
| ExtensionRegistry::DISABLED)); |
| } |
| |
| #if defined(ENABLE_MANAGED_USERS) |
| class ThemeServiceSupervisedUserTest : public ThemeServiceTest { |
| public: |
| ThemeServiceSupervisedUserTest() {} |
| virtual ~ThemeServiceSupervisedUserTest() {} |
| |
| virtual void SetUp() override { |
| is_supervised_ = true; |
| ThemeServiceTest::SetUp(); |
| } |
| }; |
| |
| // Checks that supervised users have their own default theme. |
| TEST_F(ThemeServiceSupervisedUserTest, |
| SupervisedUserThemeReplacesDefaultTheme) { |
| ThemeService* theme_service = |
| ThemeServiceFactory::GetForProfile(profile_.get()); |
| theme_service->UseDefaultTheme(); |
| EXPECT_TRUE(theme_service->UsingDefaultTheme()); |
| EXPECT_TRUE(get_theme_supplier(theme_service)); |
| EXPECT_EQ(get_theme_supplier(theme_service)->get_theme_type(), |
| CustomThemeSupplier::SUPERVISED_USER_THEME); |
| } |
| |
| #if defined(OS_LINUX) && !defined(OS_CHROMEOS) |
| // Checks that supervised users don't use the system theme even if it is the |
| // default. The system theme is only available on Linux. |
| TEST_F(ThemeServiceSupervisedUserTest, SupervisedUserThemeReplacesNativeTheme) { |
| profile_->GetPrefs()->SetBoolean(prefs::kUsesSystemTheme, true); |
| ThemeService* theme_service = |
| ThemeServiceFactory::GetForProfile(profile_.get()); |
| theme_service->UseDefaultTheme(); |
| EXPECT_TRUE(theme_service->UsingDefaultTheme()); |
| EXPECT_TRUE(get_theme_supplier(theme_service)); |
| EXPECT_EQ(get_theme_supplier(theme_service)->get_theme_type(), |
| CustomThemeSupplier::SUPERVISED_USER_THEME); |
| } |
| #endif // defined(OS_LINUX) && !defined(OS_CHROMEOS) |
| #endif // defined(ENABLE_MANAGED_USERS) |
| |
| }; // namespace theme_service_internal |