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.
5 #include "chrome/browser/extensions/extension_browsertest.h"
6 #include "chrome/browser/extensions/extension_service.h"
7 #include "chrome/browser/extensions/extension_system.h"
8 #include "chrome/browser/extensions/extension_toolbar_model.h"
9 #include "chrome/browser/profiles/profile.h"
10 #include "chrome/browser/ui/browser.h"
11 #include "chrome/test/base/in_process_browser_test.h"
13 using extensions::Extension
;
15 // An InProcessBrowserTest for testing the ExtensionToolbarModel.
16 // TODO(erikkay) It's unfortunate that this needs to be an in-proc browser test.
17 // It would be nice to refactor things so that ExtensionService could run
18 // without so much of the browser in place.
19 class ExtensionToolbarModelTest
: public ExtensionBrowserTest
,
20 public ExtensionToolbarModel::Observer
{
22 virtual void SetUp() {
27 ExtensionBrowserTest::SetUp();
30 virtual void SetUpOnMainThread() OVERRIDE
{
31 ExtensionService
* service
= extensions::ExtensionSystem::Get(
32 browser()->profile())->extension_service();
33 model_
= service
->toolbar_model();
34 model_
->AddObserver(this);
37 virtual void CleanUpOnMainThread() OVERRIDE
{
38 model_
->RemoveObserver(this);
41 virtual void BrowserActionAdded(const Extension
* extension
,
46 virtual void BrowserActionRemoved(const Extension
* extension
) OVERRIDE
{
50 virtual void BrowserActionMoved(const Extension
* extension
,
55 const Extension
* ExtensionAt(int index
) {
56 const extensions::ExtensionList
& toolbar_items
= model_
->toolbar_items();
57 for (extensions::ExtensionList::const_iterator i
= toolbar_items
.begin();
58 i
< toolbar_items
.end(); ++i
) {
66 ExtensionToolbarModel
* model_
;
73 IN_PROC_BROWSER_TEST_F(ExtensionToolbarModelTest
, Basic
) {
74 // Load an extension with no browser action.
75 ASSERT_TRUE(LoadExtension(test_data_dir_
.AppendASCII("api_test")
76 .AppendASCII("browser_action")
77 .AppendASCII("none")));
79 // This extension should not be in the model (has no browser action).
80 EXPECT_EQ(0, inserted_count_
);
81 EXPECT_EQ(0u, model_
->toolbar_items().size());
82 ASSERT_EQ(NULL
, ExtensionAt(0));
84 // Load an extension with a browser action.
85 ASSERT_TRUE(LoadExtension(test_data_dir_
.AppendASCII("api_test")
86 .AppendASCII("browser_action")
87 .AppendASCII("basics")));
89 // We should now find our extension in the model.
90 EXPECT_EQ(1, inserted_count_
);
91 EXPECT_EQ(1u, model_
->toolbar_items().size());
92 const Extension
* extension
= ExtensionAt(0);
93 ASSERT_TRUE(NULL
!= extension
);
94 EXPECT_STREQ("A browser action with no icon that makes the page red",
95 extension
->name().c_str());
97 // Should be a no-op, but still fires the events.
98 model_
->MoveBrowserAction(extension
, 0);
99 EXPECT_EQ(1, moved_count_
);
100 EXPECT_EQ(1u, model_
->toolbar_items().size());
101 const Extension
* extension2
= ExtensionAt(0);
102 EXPECT_EQ(extension
, extension2
);
104 UnloadExtension(extension
->id());
105 EXPECT_EQ(1, removed_count_
);
106 EXPECT_EQ(0u, model_
->toolbar_items().size());
107 EXPECT_EQ(NULL
, ExtensionAt(0));
110 #if defined(OS_MACOSX)
111 // Flaky on Mac 10.8 Blink canary bots: http://crbug.com/166580
112 #define MAYBE_ReorderAndReinsert DISABLED_ReorderAndReinsert
114 #define MAYBE_ReorderAndReinsert ReorderAndReinsert
116 IN_PROC_BROWSER_TEST_F(ExtensionToolbarModelTest
, MAYBE_ReorderAndReinsert
) {
117 // Load an extension with a browser action.
118 base::FilePath
extension_a_path(test_data_dir_
.AppendASCII("api_test")
119 .AppendASCII("browser_action")
120 .AppendASCII("basics"));
121 ASSERT_TRUE(LoadExtension(extension_a_path
));
123 // First extension loaded.
124 EXPECT_EQ(1, inserted_count_
);
125 EXPECT_EQ(1u, model_
->toolbar_items().size());
126 const Extension
* extensionA
= ExtensionAt(0);
127 ASSERT_TRUE(NULL
!= extensionA
);
128 EXPECT_STREQ("A browser action with no icon that makes the page red",
129 extensionA
->name().c_str());
131 // Load another extension with a browser action.
132 base::FilePath
extension_b_path(test_data_dir_
.AppendASCII("api_test")
133 .AppendASCII("browser_action")
134 .AppendASCII("popup"));
135 ASSERT_TRUE(LoadExtension(extension_b_path
));
137 // Second extension loaded.
138 EXPECT_EQ(2, inserted_count_
);
139 EXPECT_EQ(2u, model_
->toolbar_items().size());
140 const Extension
* extensionB
= ExtensionAt(1);
141 ASSERT_TRUE(NULL
!= extensionB
);
142 EXPECT_STREQ("Popup tester", extensionB
->name().c_str());
144 // Load yet another extension with a browser action.
145 base::FilePath
extension_c_path(test_data_dir_
.AppendASCII("api_test")
146 .AppendASCII("browser_action")
147 .AppendASCII("remove_popup"));
148 ASSERT_TRUE(LoadExtension(extension_c_path
));
150 // Third extension loaded.
151 EXPECT_EQ(3, inserted_count_
);
152 EXPECT_EQ(3u, model_
->toolbar_items().size());
153 const Extension
* extensionC
= ExtensionAt(2);
154 ASSERT_TRUE(NULL
!= extensionC
);
155 EXPECT_STREQ("A page action which removes a popup.",
156 extensionC
->name().c_str());
158 // Order is now A, B, C. Let's put C first.
159 model_
->MoveBrowserAction(extensionC
, 0);
160 EXPECT_EQ(1, moved_count_
);
161 EXPECT_EQ(3u, model_
->toolbar_items().size());
162 EXPECT_EQ(extensionC
, ExtensionAt(0));
163 EXPECT_EQ(extensionA
, ExtensionAt(1));
164 EXPECT_EQ(extensionB
, ExtensionAt(2));
165 EXPECT_EQ(NULL
, ExtensionAt(3));
167 // Order is now C, A, B. Let's put A last.
168 model_
->MoveBrowserAction(extensionA
, 2);
169 EXPECT_EQ(2, moved_count_
);
170 EXPECT_EQ(3u, model_
->toolbar_items().size());
171 EXPECT_EQ(extensionC
, ExtensionAt(0));
172 EXPECT_EQ(extensionB
, ExtensionAt(1));
173 EXPECT_EQ(extensionA
, ExtensionAt(2));
174 EXPECT_EQ(NULL
, ExtensionAt(3));
176 // Order is now C, B, A. Let's remove B.
177 std::string idB
= extensionB
->id();
178 UnloadExtension(idB
);
179 EXPECT_EQ(1, removed_count_
);
180 EXPECT_EQ(2u, model_
->toolbar_items().size());
181 EXPECT_EQ(extensionC
, ExtensionAt(0));
182 EXPECT_EQ(extensionA
, ExtensionAt(1));
183 EXPECT_EQ(NULL
, ExtensionAt(2));
185 // Load extension B again.
186 ASSERT_TRUE(LoadExtension(extension_b_path
));
188 // Extension B loaded again.
189 EXPECT_EQ(4, inserted_count_
);
190 EXPECT_EQ(3u, model_
->toolbar_items().size());
191 // Make sure it gets its old spot in the list. We should get the same
192 // extension again, otherwise the order has changed.
193 ASSERT_STREQ(idB
.c_str(), ExtensionAt(1)->id().c_str());
196 UnloadExtension(idB
);
197 EXPECT_EQ(2, removed_count_
);
198 EXPECT_EQ(2u, model_
->toolbar_items().size());
199 EXPECT_EQ(extensionC
, ExtensionAt(0));
200 EXPECT_EQ(extensionA
, ExtensionAt(1));
201 EXPECT_EQ(NULL
, ExtensionAt(2));
203 // Order is now C, A. Flip it.
204 model_
->MoveBrowserAction(extensionA
, 0);
205 EXPECT_EQ(3, moved_count_
);
206 EXPECT_EQ(2u, model_
->toolbar_items().size());
207 EXPECT_EQ(extensionA
, ExtensionAt(0));
208 EXPECT_EQ(extensionC
, ExtensionAt(1));
209 EXPECT_EQ(NULL
, ExtensionAt(2));
211 // Move A to the location it already occupies.
212 model_
->MoveBrowserAction(extensionA
, 0);
213 EXPECT_EQ(4, moved_count_
);
214 EXPECT_EQ(2u, model_
->toolbar_items().size());
215 EXPECT_EQ(extensionA
, ExtensionAt(0));
216 EXPECT_EQ(extensionC
, ExtensionAt(1));
217 EXPECT_EQ(NULL
, ExtensionAt(2));
219 // Order is now A, C. Remove C.
220 std::string idC
= extensionC
->id();
221 UnloadExtension(idC
);
222 EXPECT_EQ(3, removed_count_
);
223 EXPECT_EQ(1u, model_
->toolbar_items().size());
224 EXPECT_EQ(extensionA
, ExtensionAt(0));
225 EXPECT_EQ(NULL
, ExtensionAt(1));
227 // Load extension C again.
228 ASSERT_TRUE(LoadExtension(extension_c_path
));
230 // Extension C loaded again.
231 EXPECT_EQ(5, inserted_count_
);
232 EXPECT_EQ(2u, model_
->toolbar_items().size());
233 // Make sure it gets its old spot in the list (at the very end).
234 ASSERT_STREQ(idC
.c_str(), ExtensionAt(1)->id().c_str());
237 IN_PROC_BROWSER_TEST_F(ExtensionToolbarModelTest
, UnloadAndDisableMultiple
) {
238 // Load three extensions with browser action.
239 base::FilePath
extension_a_path(test_data_dir_
.AppendASCII("api_test")
240 .AppendASCII("browser_action")
241 .AppendASCII("basics"));
242 ASSERT_TRUE(LoadExtension(extension_a_path
));
243 base::FilePath
extension_b_path(test_data_dir_
.AppendASCII("api_test")
244 .AppendASCII("browser_action")
245 .AppendASCII("popup"));
246 ASSERT_TRUE(LoadExtension(extension_b_path
));
247 base::FilePath
extension_c_path(test_data_dir_
.AppendASCII("api_test")
248 .AppendASCII("browser_action")
249 .AppendASCII("remove_popup"));
250 ASSERT_TRUE(LoadExtension(extension_c_path
));
252 // Verify we got the three we asked for and that they are ordered as: A, B, C.
253 const Extension
* extensionA
= ExtensionAt(0);
254 const Extension
* extensionB
= ExtensionAt(1);
255 const Extension
* extensionC
= ExtensionAt(2);
256 std::string idA
= extensionA
->id();
257 std::string idB
= extensionB
->id();
258 std::string idC
= extensionC
->id();
259 EXPECT_STREQ("A browser action with no icon that makes the page red",
260 extensionA
->name().c_str());
261 EXPECT_STREQ("Popup tester", extensionB
->name().c_str());
262 EXPECT_STREQ("A page action which removes a popup.",
263 extensionC
->name().c_str());
265 // Unload B, then C, then A.
266 UnloadExtension(idB
);
267 UnloadExtension(idC
);
268 UnloadExtension(idA
);
270 // Load C, then A, then B.
271 ASSERT_TRUE(LoadExtension(extension_c_path
));
272 ASSERT_TRUE(LoadExtension(extension_a_path
));
273 ASSERT_TRUE(LoadExtension(extension_b_path
));
274 EXPECT_EQ(0, moved_count_
);
276 extensionA
= ExtensionAt(0);
277 extensionB
= ExtensionAt(1);
278 extensionC
= ExtensionAt(2);
280 // Make sure we get the order we started with (A, B, C).
281 EXPECT_STREQ(idA
.c_str(), extensionA
->id().c_str());
282 EXPECT_STREQ(idB
.c_str(), extensionB
->id().c_str());
283 EXPECT_STREQ(idC
.c_str(), extensionC
->id().c_str());
285 // Put C in the middle and A to the end.
286 model_
->MoveBrowserAction(extensionC
, 1);
287 model_
->MoveBrowserAction(extensionA
, 2);
289 // Make sure we get this order (C, B, A).
290 EXPECT_STREQ(idC
.c_str(), ExtensionAt(0)->id().c_str());
291 EXPECT_STREQ(idB
.c_str(), ExtensionAt(1)->id().c_str());
292 EXPECT_STREQ(idA
.c_str(), ExtensionAt(2)->id().c_str());
294 // Disable B, then C, then A.
295 DisableExtension(idB
);
296 DisableExtension(idC
);
297 DisableExtension(idA
);
299 // Enable C, then A, then B.
300 EnableExtension(idA
);
301 EnableExtension(idB
);
302 EnableExtension(idC
);
304 // Make sure we get the order we started with.
305 EXPECT_STREQ(idC
.c_str(), ExtensionAt(0)->id().c_str());
306 EXPECT_STREQ(idB
.c_str(), ExtensionAt(1)->id().c_str());
307 EXPECT_STREQ(idA
.c_str(), ExtensionAt(2)->id().c_str());
310 IN_PROC_BROWSER_TEST_F(ExtensionToolbarModelTest
, Uninstall
) {
311 // Load two extensions with browser action.
312 base::FilePath
extension_a_path(test_data_dir_
.AppendASCII("api_test")
313 .AppendASCII("browser_action")
314 .AppendASCII("basics"));
315 ASSERT_TRUE(LoadExtension(extension_a_path
));
316 base::FilePath
extension_b_path(test_data_dir_
.AppendASCII("api_test")
317 .AppendASCII("browser_action")
318 .AppendASCII("popup"));
319 ASSERT_TRUE(LoadExtension(extension_b_path
));
321 // Verify we got what we came for.
322 const Extension
* extensionA
= ExtensionAt(0);
323 const Extension
* extensionB
= ExtensionAt(1);
324 std::string idA
= extensionA
->id();
325 std::string idB
= extensionB
->id();
326 EXPECT_STREQ("A browser action with no icon that makes the page red",
327 extensionA
->name().c_str());
328 EXPECT_STREQ("Popup tester", extensionB
->name().c_str());
330 // Order is now A, B. Make B first.
331 model_
->MoveBrowserAction(extensionB
, 0);
333 // Order is now B, A. Uninstall Extension B.
334 UninstallExtension(idB
);
336 // List contains only A now. Validate that.
337 EXPECT_STREQ(idA
.c_str(), ExtensionAt(0)->id().c_str());
338 EXPECT_EQ(1u, model_
->toolbar_items().size());
340 // Load Extension B again.
341 ASSERT_TRUE(LoadExtension(extension_b_path
));
342 EXPECT_EQ(2u, model_
->toolbar_items().size());
344 // Make sure Extension B is _not_ first (should have been forgotten at
346 EXPECT_STREQ(idA
.c_str(), ExtensionAt(0)->id().c_str());
347 EXPECT_STREQ(idB
.c_str(), ExtensionAt(1)->id().c_str());
350 IN_PROC_BROWSER_TEST_F(ExtensionToolbarModelTest
, ReorderOnPrefChange
) {
351 // Load three extensions with browser action.
352 base::FilePath
extension_a_path(test_data_dir_
.AppendASCII("api_test")
353 .AppendASCII("browser_action")
354 .AppendASCII("basics"));
355 ASSERT_TRUE(LoadExtension(extension_a_path
));
356 base::FilePath
extension_b_path(test_data_dir_
.AppendASCII("api_test")
357 .AppendASCII("browser_action")
358 .AppendASCII("popup"));
359 ASSERT_TRUE(LoadExtension(extension_b_path
));
360 base::FilePath
extension_c_path(test_data_dir_
.AppendASCII("api_test")
361 .AppendASCII("browser_action")
362 .AppendASCII("remove_popup"));
363 ASSERT_TRUE(LoadExtension(extension_c_path
));
364 std::string id_a
= ExtensionAt(0)->id();
365 std::string id_b
= ExtensionAt(1)->id();
366 std::string id_c
= ExtensionAt(2)->id();
368 // Change value of toolbar preference.
369 extensions::ExtensionIdList new_order
;
370 new_order
.push_back(id_c
);
371 new_order
.push_back(id_b
);
372 extensions::ExtensionPrefs::Get(browser()->profile())->SetToolbarOrder(
375 // Verify order is changed.
376 EXPECT_EQ(id_c
, ExtensionAt(0)->id());
377 EXPECT_EQ(id_b
, ExtensionAt(1)->id());
378 EXPECT_EQ(id_a
, ExtensionAt(2)->id());