Home | History | Annotate | Download | only in themes
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/themes/theme_service.h"
      6 
      7 #include "base/files/file_util.h"
      8 #include "base/path_service.h"
      9 #include "chrome/browser/chrome_notification_types.h"
     10 #include "chrome/browser/extensions/extension_service.h"
     11 #include "chrome/browser/extensions/extension_service_test_base.h"
     12 #include "chrome/browser/extensions/unpacked_installer.h"
     13 #include "chrome/browser/supervised_user/supervised_user_service.h"
     14 #include "chrome/browser/supervised_user/supervised_user_service_factory.h"
     15 #include "chrome/browser/themes/custom_theme_supplier.h"
     16 #include "chrome/browser/themes/theme_service_factory.h"
     17 #include "chrome/common/chrome_paths.h"
     18 #include "chrome/common/pref_names.h"
     19 #include "chrome/test/base/testing_browser_process.h"
     20 #include "chrome/test/base/testing_profile.h"
     21 #include "chrome/test/base/testing_profile_manager.h"
     22 #include "content/public/test/test_utils.h"
     23 #include "extensions/browser/extension_registry.h"
     24 #include "extensions/browser/uninstall_reason.h"
     25 #include "extensions/common/extension.h"
     26 #include "testing/gtest/include/gtest/gtest.h"
     27 
     28 using extensions::ExtensionRegistry;
     29 
     30 namespace theme_service_internal {
     31 
     32 class ThemeServiceTest : public extensions::ExtensionServiceTestBase {
     33  public:
     34   ThemeServiceTest() : is_supervised_(false),
     35                        registry_(NULL) {}
     36   virtual ~ThemeServiceTest() {}
     37 
     38   // Moves a minimal theme to |temp_dir_path| and unpacks it from that
     39   // directory.
     40   std::string LoadUnpackedThemeAt(const base::FilePath& temp_dir) {
     41     base::FilePath dst_manifest_path = temp_dir.AppendASCII("manifest.json");
     42     base::FilePath test_data_dir;
     43     EXPECT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir));
     44     base::FilePath src_manifest_path =
     45         test_data_dir.AppendASCII("extensions/theme_minimal/manifest.json");
     46     EXPECT_TRUE(base::CopyFile(src_manifest_path, dst_manifest_path));
     47 
     48     scoped_refptr<extensions::UnpackedInstaller> installer(
     49         extensions::UnpackedInstaller::Create(service_));
     50     content::WindowedNotificationObserver observer(
     51         extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED,
     52         content::Source<Profile>(profile_.get()));
     53     installer->Load(temp_dir);
     54     observer.Wait();
     55 
     56     std::string extension_id =
     57         content::Details<extensions::Extension>(observer.details())->id();
     58 
     59     // Let the ThemeService finish creating the theme pack.
     60     base::MessageLoop::current()->RunUntilIdle();
     61 
     62     return extension_id;
     63   }
     64 
     65   // Update the theme with |extension_id|.
     66   void UpdateUnpackedTheme(const std::string& extension_id) {
     67     int updated_notification =
     68         service_->IsExtensionEnabled(extension_id)
     69             ? extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED
     70             : extensions::NOTIFICATION_EXTENSION_UPDATE_DISABLED;
     71 
     72     const base::FilePath& path =
     73         service_->GetInstalledExtension(extension_id)->path();
     74 
     75     scoped_refptr<extensions::UnpackedInstaller> installer(
     76         extensions::UnpackedInstaller::Create(service_));
     77     content::WindowedNotificationObserver observer(updated_notification,
     78         content::Source<Profile>(profile_.get()));
     79     installer->Load(path);
     80     observer.Wait();
     81 
     82     // Let the ThemeService finish creating the theme pack.
     83     base::MessageLoop::current()->RunUntilIdle();
     84   }
     85 
     86   virtual void SetUp() {
     87     extensions::ExtensionServiceTestBase::SetUp();
     88     extensions::ExtensionServiceTestBase::ExtensionServiceInitParams params =
     89         CreateDefaultInitParams();
     90     params.profile_is_supervised = is_supervised_;
     91     InitializeExtensionService(params);
     92     service_->Init();
     93     registry_ = ExtensionRegistry::Get(profile_.get());
     94     ASSERT_TRUE(registry_);
     95   }
     96 
     97   const CustomThemeSupplier* get_theme_supplier(ThemeService* theme_service) {
     98     return theme_service->get_theme_supplier();
     99   }
    100 
    101  protected:
    102   bool is_supervised_;
    103   ExtensionRegistry* registry_;
    104 
    105 };
    106 
    107 // Installs then uninstalls a theme and makes sure that the ThemeService
    108 // reverts to the default theme after the uninstall.
    109 TEST_F(ThemeServiceTest, ThemeInstallUninstall) {
    110   ThemeService* theme_service =
    111       ThemeServiceFactory::GetForProfile(profile_.get());
    112   theme_service->UseDefaultTheme();
    113   // Let the ThemeService uninstall unused themes.
    114   base::MessageLoop::current()->RunUntilIdle();
    115 
    116   base::ScopedTempDir temp_dir;
    117   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
    118   const std::string& extension_id = LoadUnpackedThemeAt(temp_dir.path());
    119   EXPECT_FALSE(theme_service->UsingDefaultTheme());
    120   EXPECT_EQ(extension_id, theme_service->GetThemeID());
    121 
    122   // Now uninstall the extension, should revert to the default theme.
    123   service_->UninstallExtension(extension_id,
    124                                extensions::UNINSTALL_REASON_FOR_TESTING,
    125                                base::Bind(&base::DoNothing),
    126                                NULL);
    127   EXPECT_TRUE(theme_service->UsingDefaultTheme());
    128 }
    129 
    130 // Test that a theme extension is disabled when not in use. A theme may be
    131 // installed but not in use if it there is an infobar to revert to the previous
    132 // theme.
    133 TEST_F(ThemeServiceTest, DisableUnusedTheme) {
    134   ThemeService* theme_service =
    135       ThemeServiceFactory::GetForProfile(profile_.get());
    136   theme_service->UseDefaultTheme();
    137   // Let the ThemeService uninstall unused themes.
    138   base::MessageLoop::current()->RunUntilIdle();
    139 
    140   base::ScopedTempDir temp_dir1;
    141   ASSERT_TRUE(temp_dir1.CreateUniqueTempDir());
    142   base::ScopedTempDir temp_dir2;
    143   ASSERT_TRUE(temp_dir2.CreateUniqueTempDir());
    144 
    145   // 1) Installing a theme should disable the previously active theme.
    146   const std::string& extension1_id = LoadUnpackedThemeAt(temp_dir1.path());
    147   EXPECT_FALSE(theme_service->UsingDefaultTheme());
    148   EXPECT_EQ(extension1_id, theme_service->GetThemeID());
    149   EXPECT_TRUE(service_->IsExtensionEnabled(extension1_id));
    150 
    151   // Show an infobar to prevent the current theme from being uninstalled.
    152   theme_service->OnInfobarDisplayed();
    153 
    154   const std::string& extension2_id = LoadUnpackedThemeAt(temp_dir2.path());
    155   EXPECT_EQ(extension2_id, theme_service->GetThemeID());
    156   EXPECT_TRUE(service_->IsExtensionEnabled(extension2_id));
    157   EXPECT_TRUE(registry_->GetExtensionById(extension1_id,
    158                                           ExtensionRegistry::DISABLED));
    159 
    160   // 2) Enabling a disabled theme extension should swap the current theme.
    161   service_->EnableExtension(extension1_id);
    162   base::MessageLoop::current()->RunUntilIdle();
    163   EXPECT_EQ(extension1_id, theme_service->GetThemeID());
    164   EXPECT_TRUE(service_->IsExtensionEnabled(extension1_id));
    165   EXPECT_TRUE(registry_->GetExtensionById(extension2_id,
    166                                           ExtensionRegistry::DISABLED));
    167 
    168   // 3) Using SetTheme() with a disabled theme should enable and set the
    169   // theme. This is the case when the user reverts to the previous theme
    170   // via an infobar.
    171   const extensions::Extension* extension2 =
    172       service_->GetInstalledExtension(extension2_id);
    173   theme_service->SetTheme(extension2);
    174   base::MessageLoop::current()->RunUntilIdle();
    175   EXPECT_EQ(extension2_id, theme_service->GetThemeID());
    176   EXPECT_TRUE(service_->IsExtensionEnabled(extension2_id));
    177   EXPECT_TRUE(registry_->GetExtensionById(extension1_id,
    178                                           ExtensionRegistry::DISABLED));
    179 
    180   // 4) Disabling the current theme extension should revert to the default theme
    181   // and uninstall any installed theme extensions.
    182   theme_service->OnInfobarDestroyed();
    183   EXPECT_FALSE(theme_service->UsingDefaultTheme());
    184   service_->DisableExtension(extension2_id,
    185       extensions::Extension::DISABLE_USER_ACTION);
    186   base::MessageLoop::current()->RunUntilIdle();
    187   EXPECT_TRUE(theme_service->UsingDefaultTheme());
    188   EXPECT_FALSE(service_->GetInstalledExtension(extension1_id));
    189   EXPECT_FALSE(service_->GetInstalledExtension(extension2_id));
    190 }
    191 
    192 // Test the ThemeService's behavior when a theme is upgraded.
    193 TEST_F(ThemeServiceTest, ThemeUpgrade) {
    194   // Setup.
    195   ThemeService* theme_service =
    196       ThemeServiceFactory::GetForProfile(profile_.get());
    197   theme_service->UseDefaultTheme();
    198   // Let the ThemeService uninstall unused themes.
    199   base::MessageLoop::current()->RunUntilIdle();
    200 
    201   theme_service->OnInfobarDisplayed();
    202 
    203   base::ScopedTempDir temp_dir1;
    204   ASSERT_TRUE(temp_dir1.CreateUniqueTempDir());
    205   base::ScopedTempDir temp_dir2;
    206   ASSERT_TRUE(temp_dir2.CreateUniqueTempDir());
    207 
    208   const std::string& extension1_id = LoadUnpackedThemeAt(temp_dir1.path());
    209   const std::string& extension2_id = LoadUnpackedThemeAt(temp_dir2.path());
    210 
    211   // Test the initial state.
    212   EXPECT_TRUE(registry_->GetExtensionById(extension1_id,
    213                                           ExtensionRegistry::DISABLED));
    214   EXPECT_EQ(extension2_id, theme_service->GetThemeID());
    215 
    216   // 1) Upgrading the current theme should not revert to the default theme.
    217   content::WindowedNotificationObserver theme_change_observer(
    218       chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
    219       content::Source<ThemeService>(theme_service));
    220   UpdateUnpackedTheme(extension2_id);
    221 
    222   // The ThemeService should have sent an theme change notification even though
    223   // the id of the current theme did not change.
    224   theme_change_observer.Wait();
    225 
    226   EXPECT_EQ(extension2_id, theme_service->GetThemeID());
    227   EXPECT_TRUE(registry_->GetExtensionById(extension1_id,
    228                                           ExtensionRegistry::DISABLED));
    229 
    230   // 2) Upgrading a disabled theme should not change the current theme.
    231   UpdateUnpackedTheme(extension1_id);
    232   EXPECT_EQ(extension2_id, theme_service->GetThemeID());
    233   EXPECT_TRUE(registry_->GetExtensionById(extension1_id,
    234                                           ExtensionRegistry::DISABLED));
    235 }
    236 
    237 class ThemeServiceSupervisedUserTest : public ThemeServiceTest {
    238  public:
    239   ThemeServiceSupervisedUserTest() {}
    240   virtual ~ThemeServiceSupervisedUserTest() {}
    241 
    242   virtual void SetUp() OVERRIDE {
    243     is_supervised_ = true;
    244     ThemeServiceTest::SetUp();
    245   }
    246 };
    247 
    248 // Checks that supervised users have their own default theme.
    249 TEST_F(ThemeServiceSupervisedUserTest,
    250        SupervisedUserThemeReplacesDefaultTheme) {
    251   ThemeService* theme_service =
    252       ThemeServiceFactory::GetForProfile(profile_.get());
    253   theme_service->UseDefaultTheme();
    254   EXPECT_TRUE(theme_service->UsingDefaultTheme());
    255   EXPECT_TRUE(get_theme_supplier(theme_service));
    256   EXPECT_EQ(get_theme_supplier(theme_service)->get_theme_type(),
    257             CustomThemeSupplier::SUPERVISED_USER_THEME);
    258 }
    259 
    260 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
    261 // Checks that supervised users don't use the system theme even if it is the
    262 // default. The system theme is only available on Linux.
    263 TEST_F(ThemeServiceSupervisedUserTest, SupervisedUserThemeReplacesNativeTheme) {
    264   profile_->GetPrefs()->SetBoolean(prefs::kUsesSystemTheme, true);
    265   ThemeService* theme_service =
    266       ThemeServiceFactory::GetForProfile(profile_.get());
    267   theme_service->UseDefaultTheme();
    268   EXPECT_TRUE(theme_service->UsingDefaultTheme());
    269   EXPECT_TRUE(get_theme_supplier(theme_service));
    270   EXPECT_EQ(get_theme_supplier(theme_service)->get_theme_type(),
    271             CustomThemeSupplier::SUPERVISED_USER_THEME);
    272 }
    273 #endif
    274 
    275 }; // namespace theme_service_internal
    276