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:
BrowserActionsContainerTest()16 BrowserActionsContainerTest() : browser_(NULL) {
17 }
~BrowserActionsContainerTest()18 virtual ~BrowserActionsContainerTest() {}
19
CreateBrowser(Profile * profile)20 virtual Browser* CreateBrowser(Profile* profile) {
21 browser_ = InProcessBrowserTest::CreateBrowser(profile);
22 browser_actions_bar_.reset(new BrowserActionTestUtil(browser_));
23 return browser_;
24 }
25
browser()26 Browser* browser() { return browser_; }
27
browser_actions_bar()28 BrowserActionTestUtil* browser_actions_bar() {
29 return browser_actions_bar_.get();
30 }
31
32 // Make sure extension with index |extension_index| has an icon.
EnsureExtensionHasIcon(int extension_index)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.
IN_PROC_BROWSER_TEST_F(BrowserActionsContainerTest,Basic)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
IN_PROC_BROWSER_TEST_F(BrowserActionsContainerTest,Visibility)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
IN_PROC_BROWSER_TEST_F(BrowserActionsContainerTest,ForceHide)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
IN_PROC_BROWSER_TEST_F(BrowserActionsContainerTest,TestCrash57536)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