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 <string> 6 7 #include "base/command_line.h" 8 #include "base/memory/scoped_ptr.h" 9 #include "base/message_loop/message_loop.h" 10 #include "chrome/browser/extensions/active_script_controller.h" 11 #include "chrome/browser/extensions/extension_action.h" 12 #include "chrome/browser/extensions/extension_action_manager.h" 13 #include "chrome/browser/extensions/extension_service.h" 14 #include "chrome/browser/extensions/location_bar_controller.h" 15 #include "chrome/browser/extensions/tab_helper.h" 16 #include "chrome/browser/extensions/test_extension_system.h" 17 #include "chrome/browser/sessions/session_tab_helper.h" 18 #include "chrome/test/base/chrome_render_view_host_test_harness.h" 19 #include "chrome/test/base/testing_profile.h" 20 #include "components/crx_file/id_util.h" 21 #include "extensions/common/extension.h" 22 #include "extensions/common/extension_builder.h" 23 #include "extensions/common/feature_switch.h" 24 #include "extensions/common/value_builder.h" 25 26 #if defined(OS_CHROMEOS) 27 #include "chrome/browser/chromeos/login/users/scoped_test_user_manager.h" 28 #include "chrome/browser/chromeos/settings/cros_settings.h" 29 #include "chrome/browser/chromeos/settings/device_settings_service.h" 30 #endif 31 32 namespace extensions { 33 namespace { 34 35 class LocationBarControllerUnitTest : public ChromeRenderViewHostTestHarness { 36 protected: 37 virtual void SetUp() OVERRIDE { 38 active_script_override_.reset(new FeatureSwitch::ScopedOverride( 39 FeatureSwitch::scripts_require_action(), true)); 40 41 ChromeRenderViewHostTestHarness::SetUp(); 42 #if defined OS_CHROMEOS 43 test_user_manager_.reset(new chromeos::ScopedTestUserManager()); 44 #endif 45 TabHelper::CreateForWebContents(web_contents()); 46 // Create an ExtensionService so the LocationBarController can find its 47 // extensions. 48 CommandLine command_line(CommandLine::NO_PROGRAM); 49 Profile* profile = 50 Profile::FromBrowserContext(web_contents()->GetBrowserContext()); 51 extension_service_ = static_cast<TestExtensionSystem*>( 52 ExtensionSystem::Get(profile))->CreateExtensionService( 53 &command_line, base::FilePath(), false); 54 } 55 56 virtual void TearDown() OVERRIDE { 57 #if defined OS_CHROMEOS 58 test_user_manager_.reset(); 59 #endif 60 ChromeRenderViewHostTestHarness::TearDown(); 61 } 62 63 int tab_id() { 64 return SessionTabHelper::IdForTab(web_contents()); 65 } 66 67 const Extension* AddExtension(bool has_page_actions, 68 const std::string& name) { 69 DictionaryBuilder manifest; 70 manifest.Set("name", name) 71 .Set("version", "1.0.0") 72 .Set("manifest_version", 2) 73 .Set("permissions", ListBuilder().Append("tabs")); 74 if (has_page_actions) { 75 manifest.Set("page_action", DictionaryBuilder() 76 .Set("default_title", "Hello")); 77 } 78 scoped_refptr<const Extension> extension = 79 ExtensionBuilder().SetManifest(manifest.Pass()) 80 .SetID(crx_file::id_util::GenerateId(name)) 81 .Build(); 82 extension_service_->AddExtension(extension.get()); 83 return extension.get(); 84 } 85 86 ExtensionService* extension_service_; 87 88 private: 89 #if defined OS_CHROMEOS 90 chromeos::ScopedTestDeviceSettingsService test_device_settings_service_; 91 chromeos::ScopedTestCrosSettings test_cros_settings_; 92 scoped_ptr<chromeos::ScopedTestUserManager> test_user_manager_; 93 #endif 94 95 // Since we also test that we show page actions for pending script requests, 96 // we need to enable that feature. 97 scoped_ptr<FeatureSwitch::ScopedOverride> active_script_override_; 98 }; 99 100 // Test that the location bar gets the proper current actions. 101 TEST_F(LocationBarControllerUnitTest, LocationBarDisplaysPageActions) { 102 // Load up two extensions, one with a page action and one without. 103 const Extension* page_action = AddExtension(true, "page_actions"); 104 const Extension* no_action = AddExtension(false, "no_actions"); 105 106 TabHelper* tab_helper = TabHelper::FromWebContents(web_contents()); 107 ASSERT_TRUE(tab_helper); 108 LocationBarController* controller = tab_helper->location_bar_controller(); 109 ASSERT_TRUE(controller); 110 111 // There should only be one action - the action for the extension with a 112 // page action. 113 std::vector<ExtensionAction*> current_actions = 114 controller->GetCurrentActions(); 115 ASSERT_EQ(1u, current_actions.size()); 116 EXPECT_EQ(page_action->id(), current_actions[0]->extension_id()); 117 118 // If we request a script injection, then the location bar controller should 119 // also show a page action for that extension. 120 ActiveScriptController* active_script_controller = 121 ActiveScriptController::GetForWebContents(web_contents()); 122 ASSERT_TRUE(active_script_controller); 123 active_script_controller->RequestScriptInjectionForTesting(no_action, 124 base::Closure()); 125 current_actions = controller->GetCurrentActions(); 126 ASSERT_EQ(2u, current_actions.size()); 127 // Check that each extension is present in the vector. 128 EXPECT_TRUE(current_actions[0]->extension_id() == no_action->id() || 129 current_actions[1]->extension_id() == no_action->id()); 130 EXPECT_TRUE(current_actions[0]->extension_id() == page_action->id() || 131 current_actions[1]->extension_id() == page_action->id()); 132 133 // If we request a script injection for an extension that already has a 134 // page action, only one action should be visible. 135 active_script_controller->RequestScriptInjectionForTesting(page_action, 136 base::Closure()); 137 current_actions = controller->GetCurrentActions(); 138 ASSERT_EQ(2u, current_actions.size()); 139 EXPECT_TRUE(current_actions[0]->extension_id() == no_action->id() || 140 current_actions[1]->extension_id() == no_action->id()); 141 EXPECT_TRUE(current_actions[0]->extension_id() == page_action->id() || 142 current_actions[1]->extension_id() == page_action->id()); 143 144 // Navigating away means that only page actions are shown again. 145 NavigateAndCommit(GURL("http://google.com")); 146 current_actions = controller->GetCurrentActions(); 147 ASSERT_EQ(1u, current_actions.size()); 148 EXPECT_EQ(page_action->id(), current_actions[0]->extension_id()); 149 } 150 151 // Test that navigating clears all state in a page action. 152 TEST_F(LocationBarControllerUnitTest, NavigationClearsState) { 153 const Extension* extension = AddExtension(true, "page_actions"); 154 155 NavigateAndCommit(GURL("http://www.google.com")); 156 157 ExtensionAction& page_action = 158 *ExtensionActionManager::Get(profile())->GetPageAction(*extension); 159 page_action.SetTitle(tab_id(), "Goodbye"); 160 page_action.SetPopupUrl(tab_id(), extension->GetResourceURL("popup.html")); 161 162 EXPECT_EQ("Goodbye", page_action.GetTitle(tab_id())); 163 EXPECT_EQ(extension->GetResourceURL("popup.html"), 164 page_action.GetPopupUrl(tab_id())); 165 166 // Within-page navigation should keep the settings. 167 NavigateAndCommit(GURL("http://www.google.com/#hash")); 168 169 EXPECT_EQ("Goodbye", page_action.GetTitle(tab_id())); 170 EXPECT_EQ(extension->GetResourceURL("popup.html"), 171 page_action.GetPopupUrl(tab_id())); 172 173 // Should discard the settings, and go back to the defaults. 174 NavigateAndCommit(GURL("http://www.yahoo.com")); 175 176 EXPECT_EQ("Hello", page_action.GetTitle(tab_id())); 177 EXPECT_EQ(GURL(), page_action.GetPopupUrl(tab_id())); 178 } 179 180 } // namespace 181 } // namespace extensions 182