• 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_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/common/extension.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24 
25 namespace theme_service_internal {
26 
27 class ThemeServiceTest : public ExtensionServiceTestBase {
28  public:
ThemeServiceTest()29   ThemeServiceTest() : is_managed_(false),
30                        manager_(TestingBrowserProcess::GetGlobal()) {}
~ThemeServiceTest()31   virtual ~ThemeServiceTest() {}
32 
33   // Moves a minimal theme to |temp_dir_path| and unpacks it from that
34   // directory.
LoadUnpackedThemeAt(const base::FilePath & temp_dir)35   std::string LoadUnpackedThemeAt(const base::FilePath& temp_dir) {
36     base::FilePath dst_manifest_path = temp_dir.AppendASCII("manifest.json");
37     base::FilePath test_data_dir;
38     EXPECT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir));
39     base::FilePath src_manifest_path =
40         test_data_dir.AppendASCII("extensions/theme_minimal/manifest.json");
41     EXPECT_TRUE(base::CopyFile(src_manifest_path, dst_manifest_path));
42 
43     scoped_refptr<extensions::UnpackedInstaller> installer(
44         extensions::UnpackedInstaller::Create(service_));
45     content::WindowedNotificationObserver observer(
46         chrome::NOTIFICATION_EXTENSION_LOADED,
47         content::Source<Profile>(profile_.get()));
48     installer->Load(temp_dir);
49     observer.Wait();
50 
51     std::string extension_id =
52         content::Details<extensions::Extension>(observer.details())->id();
53 
54     // Let the ThemeService finish creating the theme pack.
55     base::MessageLoop::current()->RunUntilIdle();
56 
57     return extension_id;
58   }
59 
60   // Update the theme with |extension_id|.
UpdateUnpackedTheme(const std::string & extension_id)61   void UpdateUnpackedTheme(const std::string& extension_id) {
62     int updated_notification = service_->IsExtensionEnabled(extension_id) ?
63         chrome::NOTIFICATION_EXTENSION_LOADED :
64         chrome::NOTIFICATION_EXTENSION_UPDATE_DISABLED;
65 
66     const base::FilePath& path =
67         service_->GetInstalledExtension(extension_id)->path();
68 
69     scoped_refptr<extensions::UnpackedInstaller> installer(
70         extensions::UnpackedInstaller::Create(service_));
71     content::WindowedNotificationObserver observer(updated_notification,
72         content::Source<Profile>(profile_.get()));
73     installer->Load(path);
74     observer.Wait();
75 
76     // Let the ThemeService finish creating the theme pack.
77     base::MessageLoop::current()->RunUntilIdle();
78   }
79 
SetUp()80   virtual void SetUp() {
81     ExtensionServiceTestBase::SetUp();
82     ExtensionServiceTestBase::ExtensionServiceInitParams params =
83         CreateDefaultInitParams();
84     params.profile_is_managed = is_managed_;
85     InitializeExtensionService(params);
86     service_->Init();
87     ASSERT_TRUE(manager_.SetUp());
88   }
89 
get_theme_supplier(ThemeService * theme_service)90   const CustomThemeSupplier* get_theme_supplier(ThemeService* theme_service) {
91     return theme_service->get_theme_supplier();
92   }
93 
manager()94   TestingProfileManager* manager() {
95     return &manager_;
96   }
97 
98  protected:
99   bool is_managed_;
100 
101  private:
102   TestingProfileManager manager_;
103 };
104 
105 // Installs then uninstalls a theme and makes sure that the ThemeService
106 // reverts to the default theme after the uninstall.
TEST_F(ThemeServiceTest,ThemeInstallUninstall)107 TEST_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.
TEST_F(ThemeServiceTest,DisableUnusedTheme)128 TEST_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(service_->GetExtensionById(extension1_id,
153       ExtensionService::INCLUDE_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(service_->GetExtensionById(extension2_id,
161       ExtensionService::INCLUDE_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(service_->GetExtensionById(extension1_id,
173       ExtensionService::INCLUDE_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.
TEST_F(ThemeServiceTest,ThemeUpgrade)188 TEST_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(service_->GetExtensionById(extension1_id,
208       ExtensionService::INCLUDE_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(service_->GetExtensionById(extension1_id,
223       ExtensionService::INCLUDE_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(service_->GetExtensionById(extension1_id,
229       ExtensionService::INCLUDE_DISABLED));
230 }
231 
232 class ThemeServiceManagedUserTest : public ThemeServiceTest {
233  public:
ThemeServiceManagedUserTest()234   ThemeServiceManagedUserTest() {}
~ThemeServiceManagedUserTest()235   virtual ~ThemeServiceManagedUserTest() {}
236 
SetUp()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.
TEST_F(ThemeServiceManagedUserTest,ManagedUserThemeReplacesDefaultTheme)244 TEST_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.
TEST_F(ThemeServiceManagedUserTest,ManagedUserThemeReplacesNativeTheme)257 TEST_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