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