Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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. | |
| 4 | |
| 5 #include "chrome/browser/extensions/extension_action_manager.h" | |
| 6 | |
| 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/common/extension_builder.h" | |
| 11 #include "extensions/common/manifest_handlers/icons_handler.h" | |
| 12 #include "extensions/common/value_builder.h" | |
| 13 #include "testing/gtest/include/gtest/gtest.h" | |
| 14 | |
| 15 namespace extensions { | |
| 16 | |
| 17 namespace { | |
| 18 | |
| 19 const char kBrowserAction[] = "browser_action"; | |
| 20 const char kPageAction[] = "page_action"; | |
| 21 | |
| 22 } // namespace | |
| 23 | |
| 24 class ExtensionActionManagerTest : public testing::Test { | |
| 25 public: | |
| 26 ExtensionActionManagerTest(); | |
| 27 | |
| 28 protected: | |
| 29 // Build an extension, populating |action_type| key with |action|, and | |
| 30 // "icons" key with |extension_icons|. | |
| 31 scoped_refptr<Extension> BuildExtension(DictionaryBuilder& extension_icons, | |
| 32 DictionaryBuilder& action, | |
| 33 const char* action_type); | |
| 34 | |
| 35 // Returns true if |action|'s title matches |extension|'s name. | |
| 36 bool TitlesMatch(const Extension& extension, const ExtensionAction& action); | |
| 37 | |
| 38 // Returns true if |action|'s icon for size |action_key| matches | |
| 39 // |extension|'s icon for size |extension_key|; | |
| 40 bool IconsMatch(const Extension& extension, | |
| 41 int extension_key, | |
| 42 const ExtensionAction& action, | |
| 43 int action_key); | |
| 44 | |
| 45 // Tests that values that are missing from the |action_type| key are properly | |
| 46 // populated with values from the other keys in the manifest (e.g. | |
| 47 // "default_icon" key of |action_type| is populated with "icons" key). | |
| 48 void TestPopulateMissingValues(const char* action_type); | |
| 49 | |
| 50 ExtensionActionManager* manager() { return manager_; } | |
| 51 | |
| 52 private: | |
| 53 int curr_id_; | |
| 54 ExtensionActionManager* manager_; | |
| 55 scoped_ptr<TestingProfile> profile_; | |
| 56 }; | |
| 57 | |
| 58 ExtensionActionManagerTest::ExtensionActionManagerTest() | |
| 59 : curr_id_(0), | |
| 60 profile_(new TestingProfile) { | |
| 61 manager_ = ExtensionActionManager::Get(profile_.get()); | |
| 62 } | |
| 63 | |
| 64 scoped_refptr<Extension> ExtensionActionManagerTest::BuildExtension( | |
| 65 DictionaryBuilder& extension_icons, | |
| 66 DictionaryBuilder& action, | |
| 67 const char* action_type) { | |
| 68 std::string id = base::IntToString(curr_id_++); | |
| 69 return ExtensionBuilder() | |
| 70 .SetManifest(DictionaryBuilder().Set("version", "1") | |
| 71 .Set("manifest_version", 2) | |
| 72 .Set("icons", extension_icons) | |
| 73 .Set(action_type, action) | |
| 74 .Set("name", | |
| 75 std::string("Test Extension").append(id))) | |
| 76 .SetID(id) | |
| 77 .Build(); | |
| 78 } | |
| 79 | |
| 80 bool ExtensionActionManagerTest::TitlesMatch(const Extension& extension, | |
| 81 const ExtensionAction& action) { | |
| 82 return action.GetTitle(ExtensionAction::kDefaultTabId) == extension.name(); | |
| 83 } | |
| 84 | |
| 85 bool ExtensionActionManagerTest::IconsMatch(const Extension& extension, | |
| 86 int extension_key, | |
| 87 const ExtensionAction& action, | |
| 88 int action_key) { | |
| 89 return action.default_icon()->Get(action_key, | |
| 90 ExtensionIconSet::MATCH_EXACTLY) == | |
| 91 IconsInfo::GetIcons(&extension).Get(extension_key, | |
| 92 ExtensionIconSet::MATCH_EXACTLY); | |
| 93 } | |
| 94 | |
| 95 void ExtensionActionManagerTest::TestPopulateMissingValues( | |
| 96 const char* action_type) { | |
| 97 // Determine the appropriate getter method for |action_type|. | |
| 98 const base::Callback<ExtensionAction*(const Extension&)> getter = base::Bind( | |
| 99 (action_type == kBrowserAction) ? | |
|
not at google - send to devlin
2014/08/07 16:03:37
why not just pass ExtensionActionManager::Get{Brow
gpdavis
2014/08/07 18:31:00
Well, I figured since we already need to pass |act
not at google - send to devlin
2014/08/07 20:50:18
ah, fair enough. I didn't notice you needed to pas
gpdavis
2014/08/07 21:28:18
Sure, I can dig this idea.
| |
| 100 &ExtensionActionManager::GetBrowserAction : | |
| 101 &ExtensionActionManager::GetPageAction, | |
| 102 base::Unretained(manager_)); | |
| 103 | |
| 104 // Test that the largest icon from the extension's "icons" key is chosen as a | |
| 105 // replacement for missing action default_icons keys. | |
| 106 scoped_ptr<DictionaryBuilder> extension_icons(new DictionaryBuilder()); | |
| 107 extension_icons->Set("48", "icon48.png") | |
| 108 .Set("128", "icon128.png"); | |
| 109 scoped_refptr<Extension> extension = BuildExtension( | |
| 110 extension_icons->Pass(), | |
|
not at google - send to devlin
2014/08/07 16:03:37
there are a lot of instances in this test where yo
gpdavis
2014/08/07 18:31:00
I was primarily concerned with the readability and
not at google - send to devlin
2014/08/07 20:50:18
yeah it looks odd to me, for example |extension_ic
gpdavis
2014/08/07 21:28:18
Alrighty. Will rewrite with inline DictionaryBuil
| |
| 111 DictionaryBuilder().Pass(), | |
| 112 action_type); | |
| 113 | |
| 114 ASSERT_TRUE(extension.get()); | |
| 115 const ExtensionAction* action = getter.Run(*extension); | |
| 116 ASSERT_TRUE(action); | |
| 117 | |
| 118 ASSERT_TRUE(TitlesMatch(*extension, *action)); | |
| 119 ASSERT_TRUE(IconsMatch(*extension, 128, *action, 19)); | |
| 120 ASSERT_TRUE(IconsMatch(*extension, 128, *action, 38)); | |
| 121 | |
| 122 // Test that the action's missing default_icons are not replaced with smaller | |
| 123 // icons. | |
| 124 extension_icons.reset(new DictionaryBuilder()); | |
| 125 extension_icons->Set("16", "icon16.png"); | |
| 126 extension = BuildExtension( | |
| 127 extension_icons->Pass(), | |
| 128 DictionaryBuilder().Pass(), | |
| 129 action_type); | |
| 130 | |
| 131 ASSERT_TRUE(extension.get()); | |
| 132 action = getter.Run(*extension); | |
| 133 ASSERT_TRUE(action); | |
| 134 | |
| 135 ASSERT_FALSE(IconsMatch(*extension, 16, *action, 19)); | |
| 136 ASSERT_FALSE(IconsMatch(*extension, 16, *action, 38)); | |
| 137 | |
| 138 // Test that an action's 38px icon is used as a replacement for the 19px icon | |
| 139 // if it is missing. No icons from the "icons" key should be used instead. | |
| 140 extension_icons.reset(new DictionaryBuilder()); | |
| 141 extension_icons->Set("128", "icon128.png"); | |
| 142 scoped_ptr<DictionaryBuilder> action_manifest(new DictionaryBuilder()); | |
| 143 action_manifest->Set("default_icon", DictionaryBuilder() | |
| 144 .Set("38", "action38.png")); | |
| 145 extension = BuildExtension( | |
| 146 extension_icons->Pass(), | |
| 147 action_manifest->Pass(), | |
| 148 action_type); | |
| 149 | |
| 150 ASSERT_TRUE(extension.get()); | |
| 151 action = getter.Run(*extension); | |
| 152 ASSERT_TRUE(action); | |
| 153 | |
| 154 ASSERT_FALSE(IconsMatch(*extension, 128, *action, 19)); | |
| 155 ASSERT_EQ(action->default_icon()->Get(19, ExtensionIconSet::MATCH_EXACTLY), | |
| 156 action->default_icon()->Get(38, ExtensionIconSet::MATCH_EXACTLY)); | |
| 157 | |
| 158 // Test that existing default_icons and default_title are not replaced. | |
| 159 extension_icons.reset(new DictionaryBuilder()); | |
| 160 extension_icons->Set("128", "icon128.png"); | |
| 161 action_manifest.reset(new DictionaryBuilder()); | |
| 162 action_manifest->Set("default_title", "Action!") | |
| 163 .Set("default_icon", DictionaryBuilder() | |
| 164 .Set("19", "action19.png") | |
| 165 .Set("38", "action38.png")); | |
| 166 extension = BuildExtension( | |
| 167 extension_icons->Pass(), | |
| 168 action_manifest->Pass(), | |
| 169 action_type); | |
| 170 | |
| 171 ASSERT_TRUE(extension.get()); | |
| 172 action = getter.Run(*extension); | |
| 173 ASSERT_TRUE(action); | |
| 174 | |
| 175 ASSERT_FALSE(TitlesMatch(*extension, *action)); | |
| 176 ASSERT_FALSE(IconsMatch(*extension, 128, *action, 19)); | |
| 177 ASSERT_FALSE(IconsMatch(*extension, 128, *action, 38)); | |
| 178 } | |
| 179 | |
| 180 namespace { | |
| 181 | |
| 182 TEST_F(ExtensionActionManagerTest, PopulateBrowserAction) { | |
| 183 TestPopulateMissingValues(kBrowserAction); | |
| 184 } | |
| 185 | |
| 186 TEST_F(ExtensionActionManagerTest, PopulatePageAction) { | |
| 187 TestPopulateMissingValues(kPageAction); | |
| 188 } | |
| 189 | |
| 190 TEST_F(ExtensionActionManagerTest, GetBestFitActionTest) { | |
| 191 // Create an extension with page action defaults. | |
| 192 scoped_ptr<DictionaryBuilder> extension_icons(new DictionaryBuilder()); | |
| 193 extension_icons->Set("48", "icon48.png"); | |
| 194 scoped_ptr<DictionaryBuilder> action_manifest(new DictionaryBuilder()); | |
| 195 action_manifest->Set("default_title", "Action!") | |
| 196 .Set("default_icon", DictionaryBuilder() | |
| 197 .Set("38", "action38.png")); | |
| 198 scoped_refptr<Extension> extension = BuildExtension(extension_icons->Pass(), | |
| 199 action_manifest->Pass(), | |
| 200 kPageAction); | |
| 201 ASSERT_TRUE(extension.get()); | |
| 202 | |
| 203 // Get a "best fit" browser action for |extension|. | |
| 204 scoped_ptr<ExtensionAction> action = | |
| 205 manager()->GetBestFitAction(*extension, ActionInfo::TYPE_BROWSER); | |
| 206 ASSERT_TRUE(action.get()); | |
| 207 | |
| 208 // |action|'s title and default icon should not match |extension|'s because | |
| 209 // the data should be pulled from |extension|'s page action manifest key. | |
| 210 ASSERT_FALSE(TitlesMatch(*extension, *action)); | |
|
not at google - send to devlin
2014/08/07 16:03:37
it's better to ASSERT_TRUE(TitlesMatch(*extension,
gpdavis
2014/08/07 18:31:00
I'm a little confused-- why would this pass if the
not at google - send to devlin
2014/08/07 20:50:18
TitlesMatch("Test Extension", "") --> false --> AS
gpdavis
2014/08/07 21:28:18
Ah, you said ASSERT_TRUE in the first comment. Th
not at google - send to devlin
2014/08/07 21:34:41
yep, that's pretty much what I'm suggesting. thoug
| |
| 211 ASSERT_FALSE(IconsMatch(*extension, 48, *action, 19)); | |
| 212 ASSERT_FALSE(IconsMatch(*extension, 48, *action, 38)); | |
| 213 | |
| 214 // Create a new extension without page action defaults. | |
| 215 extension_icons.reset(new DictionaryBuilder()); | |
| 216 extension_icons->Set("48", "icon48.png"); | |
| 217 extension = BuildExtension( | |
| 218 extension_icons->Pass(), | |
| 219 DictionaryBuilder().Pass(), | |
| 220 kPageAction); | |
| 221 ASSERT_TRUE(extension.get()); | |
| 222 | |
| 223 action = manager()->GetBestFitAction(*extension, ActionInfo::TYPE_BROWSER); | |
| 224 | |
| 225 // Now these values match because |extension| does not have page action | |
| 226 // defaults. | |
| 227 ASSERT_TRUE(TitlesMatch(*extension, *action)); | |
| 228 ASSERT_TRUE(IconsMatch(*extension, 48, *action, 19)); | |
| 229 ASSERT_TRUE(IconsMatch(*extension, 48, *action, 38)); | |
| 230 } | |
| 231 | |
| 232 } // namespace | |
| 233 } // namespace extensions | |
| OLD | NEW |