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