1 // Copyright (c) 2011 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/browser_action_test_util.h" 6 #include "chrome/browser/extensions/extension_browsertest.h" 7 #include "chrome/browser/extensions/extension_service.h" 8 #include "chrome/browser/profiles/profile.h" 9 #include "chrome/browser/ui/browser.h" 10 #include "chrome/browser/ui/views/browser_actions_container.h" 11 #include "chrome/common/extensions/extension_action.h" 12 #include "chrome/common/extensions/extension_resource.h" 13 14 class BrowserActionsContainerTest : public ExtensionBrowserTest { 15 public: 16 BrowserActionsContainerTest() : browser_(NULL) { 17 } 18 virtual ~BrowserActionsContainerTest() {} 19 20 virtual Browser* CreateBrowser(Profile* profile) { 21 browser_ = InProcessBrowserTest::CreateBrowser(profile); 22 browser_actions_bar_.reset(new BrowserActionTestUtil(browser_)); 23 return browser_; 24 } 25 26 Browser* browser() { return browser_; } 27 28 BrowserActionTestUtil* browser_actions_bar() { 29 return browser_actions_bar_.get(); 30 } 31 32 // Make sure extension with index |extension_index| has an icon. 33 void EnsureExtensionHasIcon(int extension_index) { 34 if (!browser_actions_bar_->HasIcon(extension_index)) { 35 // The icon is loaded asynchronously and a notification is then sent to 36 // observers. So we wait on it. 37 browser_actions_bar_->WaitForBrowserActionUpdated(extension_index); 38 } 39 EXPECT_TRUE(browser_actions_bar()->HasIcon(extension_index)); 40 } 41 42 private: 43 scoped_ptr<BrowserActionTestUtil> browser_actions_bar_; 44 45 Browser* browser_; // Weak. 46 }; 47 48 // Test the basic functionality. 49 IN_PROC_BROWSER_TEST_F(BrowserActionsContainerTest, Basic) { 50 BrowserActionsContainer::disable_animations_during_testing_ = true; 51 52 // Load an extension with no browser action. 53 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test") 54 .AppendASCII("browser_action") 55 .AppendASCII("none"))); 56 // This extension should not be in the model (has no browser action). 57 EXPECT_EQ(0, browser_actions_bar()->NumberOfBrowserActions()); 58 59 // Load an extension with a browser action. 60 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test") 61 .AppendASCII("browser_action") 62 .AppendASCII("basics"))); 63 EXPECT_EQ(1, browser_actions_bar()->NumberOfBrowserActions()); 64 EnsureExtensionHasIcon(0); 65 66 // Unload the extension. 67 std::string id = browser_actions_bar()->GetExtensionId(0); 68 UnloadExtension(id); 69 EXPECT_EQ(0, browser_actions_bar()->NumberOfBrowserActions()); 70 } 71 72 // TODO(mpcomplete): http://code.google.com/p/chromium/issues/detail?id=38992 73 IN_PROC_BROWSER_TEST_F(BrowserActionsContainerTest, Visibility) { 74 BrowserActionsContainer::disable_animations_during_testing_ = true; 75 76 base::TimeTicks start_time = base::TimeTicks::Now(); 77 78 // Load extension A (contains browser action). 79 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test") 80 .AppendASCII("browser_action") 81 .AppendASCII("basics"))); 82 EXPECT_EQ(1, browser_actions_bar()->NumberOfBrowserActions()); 83 EnsureExtensionHasIcon(0); 84 EXPECT_EQ(1, browser_actions_bar()->VisibleBrowserActions()); 85 std::string idA = browser_actions_bar()->GetExtensionId(0); 86 87 LOG(INFO) << "Load extension A done : " 88 << (base::TimeTicks::Now() - start_time).InMilliseconds() 89 << " ms" << std::flush; 90 91 // Load extension B (contains browser action). 92 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test") 93 .AppendASCII("browser_action") 94 .AppendASCII("add_popup"))); 95 EXPECT_EQ(2, browser_actions_bar()->NumberOfBrowserActions()); 96 EnsureExtensionHasIcon(0); 97 EXPECT_EQ(2, browser_actions_bar()->VisibleBrowserActions()); 98 std::string idB = browser_actions_bar()->GetExtensionId(1); 99 100 LOG(INFO) << "Load extension B done : " 101 << (base::TimeTicks::Now() - start_time).InMilliseconds() 102 << " ms" << std::flush; 103 104 EXPECT_NE(idA, idB); 105 106 // Load extension C (contains browser action). 107 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test") 108 .AppendASCII("browser_action") 109 .AppendASCII("remove_popup"))); 110 EXPECT_EQ(3, browser_actions_bar()->NumberOfBrowserActions()); 111 EnsureExtensionHasIcon(2); 112 EXPECT_EQ(3, browser_actions_bar()->VisibleBrowserActions()); 113 std::string idC = browser_actions_bar()->GetExtensionId(2); 114 115 LOG(INFO) << "Load extension C done : " 116 << (base::TimeTicks::Now() - start_time).InMilliseconds() 117 << " ms" << std::flush; 118 119 // Change container to show only one action, rest in overflow: A, [B, C]. 120 browser_actions_bar()->SetIconVisibilityCount(1); 121 EXPECT_EQ(1, browser_actions_bar()->VisibleBrowserActions()); 122 123 LOG(INFO) << "Icon visibility count 1: " 124 << (base::TimeTicks::Now() - start_time).InMilliseconds() 125 << " ms" << std::flush; 126 127 // Disable extension A (should disappear). State becomes: B [C]. 128 DisableExtension(idA); 129 EXPECT_EQ(2, browser_actions_bar()->NumberOfBrowserActions()); 130 EXPECT_EQ(1, browser_actions_bar()->VisibleBrowserActions()); 131 EXPECT_EQ(idB, browser_actions_bar()->GetExtensionId(0)); 132 133 LOG(INFO) << "Disable extension A : " 134 << (base::TimeTicks::Now() - start_time).InMilliseconds() 135 << " ms" << std::flush; 136 137 // Enable A again. A should get its spot in the same location and the bar 138 // should not grow (chevron is showing). For details: http://crbug.com/35349. 139 // State becomes: A, [B, C]. 140 EnableExtension(idA); 141 EXPECT_EQ(3, browser_actions_bar()->NumberOfBrowserActions()); 142 EXPECT_EQ(1, browser_actions_bar()->VisibleBrowserActions()); 143 EXPECT_EQ(idA, browser_actions_bar()->GetExtensionId(0)); 144 145 LOG(INFO) << "Enable extension A : " 146 << (base::TimeTicks::Now() - start_time).InMilliseconds() 147 << " ms" << std::flush; 148 149 // Disable C (in overflow). State becomes: A, [B]. 150 DisableExtension(idC); 151 EXPECT_EQ(2, browser_actions_bar()->NumberOfBrowserActions()); 152 EXPECT_EQ(1, browser_actions_bar()->VisibleBrowserActions()); 153 EXPECT_EQ(idA, browser_actions_bar()->GetExtensionId(0)); 154 155 LOG(INFO) << "Disable extension C : " 156 << (base::TimeTicks::Now() - start_time).InMilliseconds() 157 << " ms" << std::flush; 158 159 // Enable C again. State becomes: A, [B, C]. 160 EnableExtension(idC); 161 EXPECT_EQ(3, browser_actions_bar()->NumberOfBrowserActions()); 162 EXPECT_EQ(1, browser_actions_bar()->VisibleBrowserActions()); 163 EXPECT_EQ(idA, browser_actions_bar()->GetExtensionId(0)); 164 165 LOG(INFO) << "Enable extension C : " 166 << (base::TimeTicks::Now() - start_time).InMilliseconds() 167 << " ms" << std::flush; 168 169 // Now we have 3 extensions. Make sure they are all visible. State: A, B, C. 170 browser_actions_bar()->SetIconVisibilityCount(3); 171 EXPECT_EQ(3, browser_actions_bar()->VisibleBrowserActions()); 172 173 LOG(INFO) << "Checkpoint : " 174 << (base::TimeTicks::Now() - start_time).InMilliseconds() 175 << " ms" << std::flush; 176 177 // Disable extension A (should disappear). State becomes: B, C. 178 DisableExtension(idA); 179 EXPECT_EQ(2, browser_actions_bar()->NumberOfBrowserActions()); 180 EXPECT_EQ(2, browser_actions_bar()->VisibleBrowserActions()); 181 EXPECT_EQ(idB, browser_actions_bar()->GetExtensionId(0)); 182 183 LOG(INFO) << "Disable extension A : " 184 << (base::TimeTicks::Now() - start_time).InMilliseconds() 185 << " ms" << std::flush; 186 187 // Disable extension B (should disappear). State becomes: C. 188 DisableExtension(idB); 189 EXPECT_EQ(1, browser_actions_bar()->NumberOfBrowserActions()); 190 EXPECT_EQ(1, browser_actions_bar()->VisibleBrowserActions()); 191 EXPECT_EQ(idC, browser_actions_bar()->GetExtensionId(0)); 192 193 LOG(INFO) << "Disable extension B : " 194 << (base::TimeTicks::Now() - start_time).InMilliseconds() 195 << " ms" << std::flush; 196 197 // Enable B (makes B and C showing now). State becomes: B, C. 198 EnableExtension(idB); 199 EXPECT_EQ(2, browser_actions_bar()->NumberOfBrowserActions()); 200 EXPECT_EQ(2, browser_actions_bar()->VisibleBrowserActions()); 201 EXPECT_EQ(idB, browser_actions_bar()->GetExtensionId(0)); 202 203 LOG(INFO) << "Enable extension B : " 204 << (base::TimeTicks::Now() - start_time).InMilliseconds() 205 << " ms" << std::flush; 206 207 // Enable A (makes A, B and C showing now). State becomes: B, C, A. 208 EnableExtension(idA); 209 EXPECT_EQ(3, browser_actions_bar()->NumberOfBrowserActions()); 210 EXPECT_EQ(3, browser_actions_bar()->VisibleBrowserActions()); 211 EXPECT_EQ(idA, browser_actions_bar()->GetExtensionId(2)); 212 213 LOG(INFO) << "Test complete : " 214 << (base::TimeTicks::Now() - start_time).InMilliseconds() 215 << " ms" << std::flush; 216 } 217 218 IN_PROC_BROWSER_TEST_F(BrowserActionsContainerTest, ForceHide) { 219 BrowserActionsContainer::disable_animations_during_testing_ = true; 220 221 // Load extension A (contains browser action). 222 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test") 223 .AppendASCII("browser_action") 224 .AppendASCII("basics"))); 225 EXPECT_EQ(1, browser_actions_bar()->NumberOfBrowserActions()); 226 EnsureExtensionHasIcon(0); 227 EXPECT_EQ(1, browser_actions_bar()->VisibleBrowserActions()); 228 std::string idA = browser_actions_bar()->GetExtensionId(0); 229 230 // Force hide this browser action. 231 ExtensionService* service = browser()->profile()->GetExtensionService(); 232 service->SetBrowserActionVisibility(service->GetExtensionById(idA, false), 233 false); 234 EXPECT_EQ(0, browser_actions_bar()->VisibleBrowserActions()); 235 236 ReloadExtension(idA); 237 238 // The browser action should become visible again. 239 EXPECT_EQ(1, browser_actions_bar()->VisibleBrowserActions()); 240 } 241 242 IN_PROC_BROWSER_TEST_F(BrowserActionsContainerTest, TestCrash57536) { 243 LOG(INFO) << "Test starting\n" << std::flush; 244 245 ExtensionService* service = browser()->profile()->GetExtensionService(); 246 const size_t size_before = service->extensions()->size(); 247 248 LOG(INFO) << "Loading extension\n" << std::flush; 249 250 // Load extension A (contains browser action). 251 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test") 252 .AppendASCII("browser_action") 253 .AppendASCII("crash_57536"))); 254 255 const Extension* extension = service->extensions()->at(size_before); 256 257 LOG(INFO) << "Creating bitmap\n" << std::flush; 258 259 // Create and cache and empty bitmap. 260 SkBitmap bitmap; 261 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 262 Extension::kBrowserActionIconMaxSize, 263 Extension::kBrowserActionIconMaxSize); 264 bitmap.allocPixels(); 265 266 LOG(INFO) << "Set as cached image\n" << std::flush; 267 268 gfx::Size size(Extension::kBrowserActionIconMaxSize, 269 Extension::kBrowserActionIconMaxSize); 270 extension->SetCachedImage( 271 extension->GetResource(extension->browser_action()->default_icon_path()), 272 bitmap, 273 size); 274 275 LOG(INFO) << "Disabling extension\n" << std::flush; 276 DisableExtension(extension->id()); 277 LOG(INFO) << "Enabling extension\n" << std::flush; 278 EnableExtension(extension->id()); 279 LOG(INFO) << "Test ending\n" << std::flush; 280 } 281