1 // Copyright 2014 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/extensions/extension_action_manager.h"
7 #include "base/strings/string_number_conversions.h"
8 #include "chrome/browser/extensions/extension_action.h"
9 #include "chrome/test/base/testing_profile.h"
10 #include "extensions/browser/extension_registry.h"
11 #include "extensions/common/extension_builder.h"
12 #include "extensions/common/manifest_handlers/icons_handler.h"
13 #include "extensions/common/value_builder.h"
14 #include "testing/gtest/include/gtest/gtest.h"
16 namespace extensions
{
20 const char kBrowserAction
[] = "browser_action";
21 const char kPageAction
[] = "page_action";
25 class ExtensionActionManagerTest
: public testing::Test
{
27 ExtensionActionManagerTest();
30 // Build an extension, populating |action_type| key with |action|, and
31 // "icons" key with |extension_icons|.
32 scoped_refptr
<Extension
> BuildExtension(DictionaryBuilder
& extension_icons
,
33 DictionaryBuilder
& action
,
34 const char* action_type
);
36 // Returns true if |action|'s title matches |extension|'s name.
37 bool TitlesMatch(const Extension
& extension
, const ExtensionAction
& action
);
39 // Returns true if |action|'s icon for size |action_key| matches
40 // |extension|'s icon for size |extension_key|;
41 bool IconsMatch(const Extension
& extension
,
43 const ExtensionAction
& action
,
46 // Returns the appropriate action for |extension| according to |action_type|.
47 ExtensionAction
* GetAction(const char* action_type
,
48 const Extension
& extension
);
50 // Tests that values that are missing from the |action_type| key are properly
51 // populated with values from the other keys in the manifest (e.g.
52 // "default_icon" key of |action_type| is populated with "icons" key).
53 void TestPopulateMissingValues(const char* action_type
);
55 ExtensionActionManager
* manager() { return manager_
; }
58 ExtensionRegistry
* registry_
;
60 ExtensionActionManager
* manager_
;
61 scoped_ptr
<TestingProfile
> profile_
;
64 ExtensionActionManagerTest::ExtensionActionManagerTest()
66 profile_(new TestingProfile
) {
67 registry_
= ExtensionRegistry::Get(profile_
.get());
68 manager_
= ExtensionActionManager::Get(profile_
.get());
71 scoped_refptr
<Extension
> ExtensionActionManagerTest::BuildExtension(
72 DictionaryBuilder
& extension_icons
,
73 DictionaryBuilder
& action
,
74 const char* action_type
) {
75 std::string id
= base::IntToString(curr_id_
++);
76 scoped_refptr
<Extension
> extension
= ExtensionBuilder()
77 .SetManifest(DictionaryBuilder().Set("version", "1")
78 .Set("manifest_version", 2)
79 .Set("icons", extension_icons
)
80 .Set(action_type
, action
)
82 std::string("Test Extension").append(id
)))
85 registry_
->AddEnabled(extension
);
89 bool ExtensionActionManagerTest::TitlesMatch(const Extension
& extension
,
90 const ExtensionAction
& action
) {
91 return action
.GetTitle(ExtensionAction::kDefaultTabId
) == extension
.name();
94 bool ExtensionActionManagerTest::IconsMatch(const Extension
& extension
,
96 const ExtensionAction
& action
,
98 return action
.default_icon()->Get(action_key
,
99 ExtensionIconSet::MATCH_EXACTLY
) ==
100 IconsInfo::GetIcons(&extension
).Get(extension_key
,
101 ExtensionIconSet::MATCH_EXACTLY
);
104 ExtensionAction
* ExtensionActionManagerTest::GetAction(
105 const char* action_type
,
106 const Extension
& extension
) {
107 return (action_type
== kBrowserAction
) ?
108 manager_
->GetBrowserAction(extension
) :
109 manager_
->GetPageAction(extension
);
112 void ExtensionActionManagerTest::TestPopulateMissingValues(
113 const char* action_type
) {
114 // Test that the largest icon from the extension's "icons" key is chosen as a
115 // replacement for missing action default_icons keys. "19" should not be
116 // replaced because "38" can always be used in its place.
117 scoped_refptr
<Extension
> extension
= BuildExtension(
118 DictionaryBuilder().Set("48", "icon48.png")
119 .Set("128", "icon128.png"),
120 DictionaryBuilder().Pass(),
123 ASSERT_TRUE(extension
.get());
124 const ExtensionAction
* action
= GetAction(action_type
, *extension
.get());
127 ASSERT_TRUE(TitlesMatch(*extension
.get(), *action
));
128 ASSERT_TRUE(IconsMatch(*extension
.get(), 128, *action
, 38));
130 // Test that the action's missing default_icons are not replaced with smaller
132 extension
= BuildExtension(
133 DictionaryBuilder().Set("24", "icon24.png"),
134 DictionaryBuilder().Pass(),
137 ASSERT_TRUE(extension
.get());
138 action
= GetAction(action_type
, *extension
.get());
141 ASSERT_TRUE(IconsMatch(*extension
.get(), 24, *action
, 19));
142 ASSERT_FALSE(IconsMatch(*extension
.get(), 24, *action
, 38));
144 // Test that an action's 19px icon is not replaced if a 38px action icon
146 extension
= BuildExtension(
147 DictionaryBuilder().Set("128", "icon128.png"),
148 DictionaryBuilder().Set("default_icon", DictionaryBuilder()
149 .Set("38", "action38.png")),
152 ASSERT_TRUE(extension
.get());
153 action
= GetAction(action_type
, *extension
.get());
156 ASSERT_FALSE(IconsMatch(*extension
.get(), 128, *action
, 19));
158 // Test that existing default_icons and default_title are not replaced.
159 extension
= BuildExtension(
160 DictionaryBuilder().Set("128", "icon128.png"),
161 DictionaryBuilder().Set("default_title", "Action!")
162 .Set("default_icon", DictionaryBuilder()
163 .Set("19", "action19.png")
164 .Set("38", "action38.png")),
167 ASSERT_TRUE(extension
.get());
168 action
= GetAction(action_type
, *extension
.get());
171 ASSERT_FALSE(TitlesMatch(*extension
.get(), *action
));
172 ASSERT_FALSE(IconsMatch(*extension
.get(), 128, *action
, 19));
173 ASSERT_FALSE(IconsMatch(*extension
.get(), 128, *action
, 38));
178 TEST_F(ExtensionActionManagerTest
, PopulateBrowserAction
) {
179 TestPopulateMissingValues(kBrowserAction
);
182 TEST_F(ExtensionActionManagerTest
, PopulatePageAction
) {
183 TestPopulateMissingValues(kPageAction
);
186 TEST_F(ExtensionActionManagerTest
, GetBestFitActionTest
) {
187 // Create an extension with page action defaults.
188 scoped_refptr
<Extension
> extension
= BuildExtension(
189 DictionaryBuilder().Set("48", "icon48.png"),
190 DictionaryBuilder().Set("default_title", "Action!")
191 .Set("default_icon", DictionaryBuilder()
192 .Set("38", "action38.png")),
194 ASSERT_TRUE(extension
.get());
196 // Get a "best fit" browser action for |extension|.
197 scoped_ptr
<ExtensionAction
> action
=
198 manager()->GetBestFitAction(*extension
.get(), ActionInfo::TYPE_BROWSER
);
199 ASSERT_TRUE(action
.get());
200 ASSERT_EQ(action
->action_type(), ActionInfo::TYPE_BROWSER
);
202 // |action|'s title and default icon should match |extension|'s page action's.
203 ASSERT_EQ(action
->GetTitle(ExtensionAction::kDefaultTabId
), "Action!");
204 ASSERT_EQ(action
->default_icon()->Get(38, ExtensionIconSet::MATCH_EXACTLY
),
207 // Create a new extension without page action defaults.
208 extension
= BuildExtension(
209 DictionaryBuilder().Set("48", "icon48.png"),
210 DictionaryBuilder().Pass(),
212 ASSERT_TRUE(extension
.get());
215 manager()->GetBestFitAction(*extension
.get(), ActionInfo::TYPE_BROWSER
);
217 // Now these values match because |extension| does not have page action
219 ASSERT_TRUE(TitlesMatch(*extension
.get(), *action
));
220 ASSERT_TRUE(IconsMatch(*extension
.get(), 48, *action
, 38));
224 } // namespace extensions