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.
5 #include "chrome/browser/themes/theme_service.h"
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"
26 using extensions::ExtensionRegistry
;
28 namespace theme_service_internal
{
30 class ThemeServiceTest
: public ExtensionServiceTestBase
{
32 ThemeServiceTest() : is_managed_(false),
34 virtual ~ThemeServiceTest() {}
36 // Moves a minimal theme to |temp_dir_path| and unpacks it from that
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
));
46 scoped_refptr
<extensions::UnpackedInstaller
> installer(
47 extensions::UnpackedInstaller::Create(service_
));
48 content::WindowedNotificationObserver
observer(
49 chrome::NOTIFICATION_EXTENSION_LOADED
,
50 content::Source
<Profile
>(profile_
.get()));
51 installer
->Load(temp_dir
);
54 std::string extension_id
=
55 content::Details
<extensions::Extension
>(observer
.details())->id();
57 // Let the ThemeService finish creating the theme pack.
58 base::MessageLoop::current()->RunUntilIdle();
63 // Update the theme with |extension_id|.
64 void UpdateUnpackedTheme(const std::string
& extension_id
) {
65 int updated_notification
= service_
->IsExtensionEnabled(extension_id
) ?
66 chrome::NOTIFICATION_EXTENSION_LOADED
:
67 chrome::NOTIFICATION_EXTENSION_UPDATE_DISABLED
;
69 const base::FilePath
& path
=
70 service_
->GetInstalledExtension(extension_id
)->path();
72 scoped_refptr
<extensions::UnpackedInstaller
> installer(
73 extensions::UnpackedInstaller::Create(service_
));
74 content::WindowedNotificationObserver
observer(updated_notification
,
75 content::Source
<Profile
>(profile_
.get()));
76 installer
->Load(path
);
79 // Let the ThemeService finish creating the theme pack.
80 base::MessageLoop::current()->RunUntilIdle();
83 virtual void SetUp() {
84 ExtensionServiceTestBase::SetUp();
85 ExtensionServiceTestBase::ExtensionServiceInitParams params
=
86 CreateDefaultInitParams();
87 params
.profile_is_managed
= is_managed_
;
88 InitializeExtensionService(params
);
90 registry_
= ExtensionRegistry::Get(profile_
.get());
91 ASSERT_TRUE(registry_
);
94 const CustomThemeSupplier
* get_theme_supplier(ThemeService
* theme_service
) {
95 return theme_service
->get_theme_supplier();
100 ExtensionRegistry
* registry_
;
104 // Installs then uninstalls a theme and makes sure that the ThemeService
105 // reverts to the default theme after the uninstall.
106 TEST_F(ThemeServiceTest
, ThemeInstallUninstall
) {
107 ThemeService
* theme_service
=
108 ThemeServiceFactory::GetForProfile(profile_
.get());
109 theme_service
->UseDefaultTheme();
110 // Let the ThemeService uninstall unused themes.
111 base::MessageLoop::current()->RunUntilIdle();
113 base::ScopedTempDir temp_dir
;
114 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
115 const std::string
& extension_id
= LoadUnpackedThemeAt(temp_dir
.path());
116 EXPECT_FALSE(theme_service
->UsingDefaultTheme());
117 EXPECT_EQ(extension_id
, theme_service
->GetThemeID());
119 // Now uninstall the extension, should revert to the default theme.
120 service_
->UninstallExtension(extension_id
, false, NULL
);
121 EXPECT_TRUE(theme_service
->UsingDefaultTheme());
124 // Test that a theme extension is disabled when not in use. A theme may be
125 // installed but not in use if it there is an infobar to revert to the previous
127 TEST_F(ThemeServiceTest
, DisableUnusedTheme
) {
128 ThemeService
* theme_service
=
129 ThemeServiceFactory::GetForProfile(profile_
.get());
130 theme_service
->UseDefaultTheme();
131 // Let the ThemeService uninstall unused themes.
132 base::MessageLoop::current()->RunUntilIdle();
134 base::ScopedTempDir temp_dir1
;
135 ASSERT_TRUE(temp_dir1
.CreateUniqueTempDir());
136 base::ScopedTempDir temp_dir2
;
137 ASSERT_TRUE(temp_dir2
.CreateUniqueTempDir());
139 // 1) Installing a theme should disable the previously active theme.
140 const std::string
& extension1_id
= LoadUnpackedThemeAt(temp_dir1
.path());
141 EXPECT_FALSE(theme_service
->UsingDefaultTheme());
142 EXPECT_EQ(extension1_id
, theme_service
->GetThemeID());
143 EXPECT_TRUE(service_
->IsExtensionEnabled(extension1_id
));
145 // Show an infobar to prevent the current theme from being uninstalled.
146 theme_service
->OnInfobarDisplayed();
148 const std::string
& extension2_id
= LoadUnpackedThemeAt(temp_dir2
.path());
149 EXPECT_EQ(extension2_id
, theme_service
->GetThemeID());
150 EXPECT_TRUE(service_
->IsExtensionEnabled(extension2_id
));
151 EXPECT_TRUE(registry_
->GetExtensionById(extension1_id
,
152 ExtensionRegistry::DISABLED
));
154 // 2) Enabling a disabled theme extension should swap the current theme.
155 service_
->EnableExtension(extension1_id
);
156 base::MessageLoop::current()->RunUntilIdle();
157 EXPECT_EQ(extension1_id
, theme_service
->GetThemeID());
158 EXPECT_TRUE(service_
->IsExtensionEnabled(extension1_id
));
159 EXPECT_TRUE(registry_
->GetExtensionById(extension2_id
,
160 ExtensionRegistry::DISABLED
));
162 // 3) Using SetTheme() with a disabled theme should enable and set the
163 // theme. This is the case when the user reverts to the previous theme
165 const extensions::Extension
* extension2
=
166 service_
->GetInstalledExtension(extension2_id
);
167 theme_service
->SetTheme(extension2
);
168 base::MessageLoop::current()->RunUntilIdle();
169 EXPECT_EQ(extension2_id
, theme_service
->GetThemeID());
170 EXPECT_TRUE(service_
->IsExtensionEnabled(extension2_id
));
171 EXPECT_TRUE(registry_
->GetExtensionById(extension1_id
,
172 ExtensionRegistry::DISABLED
));
174 // 4) Disabling the current theme extension should revert to the default theme
175 // and uninstall any installed theme extensions.
176 theme_service
->OnInfobarDestroyed();
177 EXPECT_FALSE(theme_service
->UsingDefaultTheme());
178 service_
->DisableExtension(extension2_id
,
179 extensions::Extension::DISABLE_USER_ACTION
);
180 base::MessageLoop::current()->RunUntilIdle();
181 EXPECT_TRUE(theme_service
->UsingDefaultTheme());
182 EXPECT_FALSE(service_
->GetInstalledExtension(extension1_id
));
183 EXPECT_FALSE(service_
->GetInstalledExtension(extension2_id
));
186 // Test the ThemeService's behavior when a theme is upgraded.
187 TEST_F(ThemeServiceTest
, ThemeUpgrade
) {
189 ThemeService
* theme_service
=
190 ThemeServiceFactory::GetForProfile(profile_
.get());
191 theme_service
->UseDefaultTheme();
192 // Let the ThemeService uninstall unused themes.
193 base::MessageLoop::current()->RunUntilIdle();
195 theme_service
->OnInfobarDisplayed();
197 base::ScopedTempDir temp_dir1
;
198 ASSERT_TRUE(temp_dir1
.CreateUniqueTempDir());
199 base::ScopedTempDir temp_dir2
;
200 ASSERT_TRUE(temp_dir2
.CreateUniqueTempDir());
202 const std::string
& extension1_id
= LoadUnpackedThemeAt(temp_dir1
.path());
203 const std::string
& extension2_id
= LoadUnpackedThemeAt(temp_dir2
.path());
205 // Test the initial state.
206 EXPECT_TRUE(registry_
->GetExtensionById(extension1_id
,
207 ExtensionRegistry::DISABLED
));
208 EXPECT_EQ(extension2_id
, theme_service
->GetThemeID());
210 // 1) Upgrading the current theme should not revert to the default theme.
211 content::WindowedNotificationObserver
theme_change_observer(
212 chrome::NOTIFICATION_BROWSER_THEME_CHANGED
,
213 content::Source
<ThemeService
>(theme_service
));
214 UpdateUnpackedTheme(extension2_id
);
216 // The ThemeService should have sent an theme change notification even though
217 // the id of the current theme did not change.
218 theme_change_observer
.Wait();
220 EXPECT_EQ(extension2_id
, theme_service
->GetThemeID());
221 EXPECT_TRUE(registry_
->GetExtensionById(extension1_id
,
222 ExtensionRegistry::DISABLED
));
224 // 2) Upgrading a disabled theme should not change the current theme.
225 UpdateUnpackedTheme(extension1_id
);
226 EXPECT_EQ(extension2_id
, theme_service
->GetThemeID());
227 EXPECT_TRUE(registry_
->GetExtensionById(extension1_id
,
228 ExtensionRegistry::DISABLED
));
231 class ThemeServiceManagedUserTest
: public ThemeServiceTest
{
233 ThemeServiceManagedUserTest() {}
234 virtual ~ThemeServiceManagedUserTest() {}
236 virtual void SetUp() OVERRIDE
{
238 ThemeServiceTest::SetUp();
242 // Checks that managed users have their own default theme.
243 TEST_F(ThemeServiceManagedUserTest
, ManagedUserThemeReplacesDefaultTheme
) {
244 ThemeService
* theme_service
=
245 ThemeServiceFactory::GetForProfile(profile_
.get());
246 theme_service
->UseDefaultTheme();
247 EXPECT_TRUE(theme_service
->UsingDefaultTheme());
248 EXPECT_TRUE(get_theme_supplier(theme_service
));
249 EXPECT_EQ(get_theme_supplier(theme_service
)->get_theme_type(),
250 CustomThemeSupplier::MANAGED_USER_THEME
);
253 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
254 // Checks that managed users don't use the system theme even if it is the
255 // default. The system theme is only available on Linux.
256 TEST_F(ThemeServiceManagedUserTest
, ManagedUserThemeReplacesNativeTheme
) {
257 profile_
->GetPrefs()->SetBoolean(prefs::kUsesSystemTheme
, true);
258 ThemeService
* theme_service
=
259 ThemeServiceFactory::GetForProfile(profile_
.get());
260 theme_service
->UseDefaultTheme();
261 EXPECT_TRUE(theme_service
->UsingDefaultTheme());
262 EXPECT_TRUE(get_theme_supplier(theme_service
));
263 EXPECT_EQ(get_theme_supplier(theme_service
)->get_theme_type(),
264 CustomThemeSupplier::MANAGED_USER_THEME
);
268 }; // namespace theme_service_internal