// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/extensions/extension_action_manager.h" #include "base/strings/string_number_conversions.h" #include "chrome/browser/extensions/extension_action.h" #include "chrome/test/base/testing_profile.h" #include "extensions/browser/extension_registry.h" #include "extensions/common/extension_builder.h" #include "extensions/common/manifest_handlers/icons_handler.h" #include "extensions/common/value_builder.h" #include "testing/gtest/include/gtest/gtest.h" namespace extensions { namespace { const char kBrowserAction[] = "browser_action"; const char kPageAction[] = "page_action"; } // namespace class ExtensionActionManagerTest : public testing::Test { public: ExtensionActionManagerTest(); protected: // Build an extension, populating |action_type| key with |action|, and // "icons" key with |extension_icons|. scoped_refptr BuildExtension(DictionaryBuilder& extension_icons, DictionaryBuilder& action, const char* action_type); // Returns true if |action|'s title matches |extension|'s name. bool TitlesMatch(const Extension& extension, const ExtensionAction& action); // Returns true if |action|'s icon for size |action_key| matches // |extension|'s icon for size |extension_key|; bool IconsMatch(const Extension& extension, int extension_key, const ExtensionAction& action, int action_key); // Returns the appropriate action for |extension| according to |action_type|. ExtensionAction* GetAction(const char* action_type, const Extension& extension); // Tests that values that are missing from the |action_type| key are properly // populated with values from the other keys in the manifest (e.g. // "default_icon" key of |action_type| is populated with "icons" key). void TestPopulateMissingValues(const char* action_type); ExtensionActionManager* manager() { return manager_; } private: ExtensionRegistry* registry_; int curr_id_; ExtensionActionManager* manager_; scoped_ptr profile_; }; ExtensionActionManagerTest::ExtensionActionManagerTest() : curr_id_(0), profile_(new TestingProfile) { registry_ = ExtensionRegistry::Get(profile_.get()); manager_ = ExtensionActionManager::Get(profile_.get()); } scoped_refptr ExtensionActionManagerTest::BuildExtension( DictionaryBuilder& extension_icons, DictionaryBuilder& action, const char* action_type) { std::string id = base::IntToString(curr_id_++); scoped_refptr extension = ExtensionBuilder() .SetManifest(DictionaryBuilder().Set("version", "1") .Set("manifest_version", 2) .Set("icons", extension_icons) .Set(action_type, action) .Set("name", std::string("Test Extension").append(id))) .SetID(id) .Build(); registry_->AddEnabled(extension); return extension; } bool ExtensionActionManagerTest::TitlesMatch(const Extension& extension, const ExtensionAction& action) { return action.GetTitle(ExtensionAction::kDefaultTabId) == extension.name(); } bool ExtensionActionManagerTest::IconsMatch(const Extension& extension, int extension_key, const ExtensionAction& action, int action_key) { return action.default_icon()->Get(action_key, ExtensionIconSet::MATCH_EXACTLY) == IconsInfo::GetIcons(&extension).Get(extension_key, ExtensionIconSet::MATCH_EXACTLY); } ExtensionAction* ExtensionActionManagerTest::GetAction( const char* action_type, const Extension& extension) { return (action_type == kBrowserAction) ? manager_->GetBrowserAction(extension) : manager_->GetPageAction(extension); } void ExtensionActionManagerTest::TestPopulateMissingValues( const char* action_type) { // Test that the largest icon from the extension's "icons" key is chosen as a // replacement for missing action default_icons keys. "19" should not be // replaced because "38" can always be used in its place. scoped_refptr extension = BuildExtension( DictionaryBuilder().Set("48", "icon48.png") .Set("128", "icon128.png"), DictionaryBuilder().Pass(), action_type); ASSERT_TRUE(extension.get()); const ExtensionAction* action = GetAction(action_type, *extension.get()); ASSERT_TRUE(action); ASSERT_TRUE(TitlesMatch(*extension.get(), *action)); ASSERT_TRUE(IconsMatch(*extension.get(), 128, *action, 38)); // Test that the action's missing default_icons are not replaced with smaller // icons. extension = BuildExtension( DictionaryBuilder().Set("24", "icon24.png"), DictionaryBuilder().Pass(), action_type); ASSERT_TRUE(extension.get()); action = GetAction(action_type, *extension.get()); ASSERT_TRUE(action); ASSERT_TRUE(IconsMatch(*extension.get(), 24, *action, 19)); ASSERT_FALSE(IconsMatch(*extension.get(), 24, *action, 38)); // Test that an action's 19px icon is not replaced if a 38px action icon // exists. extension = BuildExtension( DictionaryBuilder().Set("128", "icon128.png"), DictionaryBuilder().Set("default_icon", DictionaryBuilder() .Set("38", "action38.png")), action_type); ASSERT_TRUE(extension.get()); action = GetAction(action_type, *extension.get()); ASSERT_TRUE(action); ASSERT_FALSE(IconsMatch(*extension.get(), 128, *action, 19)); // Test that existing default_icons and default_title are not replaced. extension = BuildExtension( DictionaryBuilder().Set("128", "icon128.png"), DictionaryBuilder().Set("default_title", "Action!") .Set("default_icon", DictionaryBuilder() .Set("19", "action19.png") .Set("38", "action38.png")), action_type); ASSERT_TRUE(extension.get()); action = GetAction(action_type, *extension.get()); ASSERT_TRUE(action); ASSERT_FALSE(TitlesMatch(*extension.get(), *action)); ASSERT_FALSE(IconsMatch(*extension.get(), 128, *action, 19)); ASSERT_FALSE(IconsMatch(*extension.get(), 128, *action, 38)); } namespace { TEST_F(ExtensionActionManagerTest, PopulateBrowserAction) { TestPopulateMissingValues(kBrowserAction); } TEST_F(ExtensionActionManagerTest, PopulatePageAction) { TestPopulateMissingValues(kPageAction); } TEST_F(ExtensionActionManagerTest, GetBestFitActionTest) { // Create an extension with page action defaults. scoped_refptr extension = BuildExtension( DictionaryBuilder().Set("48", "icon48.png"), DictionaryBuilder().Set("default_title", "Action!") .Set("default_icon", DictionaryBuilder() .Set("38", "action38.png")), kPageAction); ASSERT_TRUE(extension.get()); // Get a "best fit" browser action for |extension|. scoped_ptr action = manager()->GetBestFitAction(*extension.get(), ActionInfo::TYPE_BROWSER); ASSERT_TRUE(action.get()); ASSERT_EQ(action->action_type(), ActionInfo::TYPE_BROWSER); // |action|'s title and default icon should match |extension|'s page action's. ASSERT_EQ(action->GetTitle(ExtensionAction::kDefaultTabId), "Action!"); ASSERT_EQ(action->default_icon()->Get(38, ExtensionIconSet::MATCH_EXACTLY), "action38.png"); // Create a new extension without page action defaults. extension = BuildExtension( DictionaryBuilder().Set("48", "icon48.png"), DictionaryBuilder().Pass(), kPageAction); ASSERT_TRUE(extension.get()); action = manager()->GetBestFitAction(*extension.get(), ActionInfo::TYPE_BROWSER); // Now these values match because |extension| does not have page action // defaults. ASSERT_TRUE(TitlesMatch(*extension.get(), *action)); ASSERT_TRUE(IconsMatch(*extension.get(), 48, *action, 38)); } } // namespace } // namespace extensions