76191e9eb7cc2fe611ba378fc989f3ab6005ea95
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / views / toolbar / browser_actions_container_browsertest.cc
1 // Copyright 2013 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/ui/views/toolbar/browser_actions_container.h"
6
7 #include "chrome/browser/chrome_notification_types.h"
8 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
9 #include "chrome/browser/extensions/browser_action_test_util.h"
10 #include "chrome/browser/extensions/extension_browsertest.h"
11 #include "chrome/browser/extensions/extension_toolbar_model.h"
12 #include "chrome/browser/ui/browser_window.h"
13 #include "chrome/browser/ui/browser_window_testing_views.h"
14 #include "chrome/browser/ui/views/extensions/browser_action_drag_data.h"
15 #include "chrome/browser/ui/views/frame/browser_view.h"
16 #include "chrome/browser/ui/views/toolbar/browser_action_view.h"
17 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
18 #include "content/public/test/test_utils.h"
19 #include "extensions/browser/extension_prefs.h"
20 #include "extensions/common/extension.h"
21 #include "ui/base/dragdrop/drop_target_event.h"
22 #include "ui/base/dragdrop/os_exchange_data.h"
23 #include "ui/gfx/geometry/point.h"
24 #include "ui/views/view.h"
25
26 using extensions::Extension;
27
28 class BrowserActionsContainerTest : public ExtensionBrowserTest {
29  public:
30   BrowserActionsContainerTest() {
31   }
32   virtual ~BrowserActionsContainerTest() {}
33
34   virtual void SetUpCommandLine(base::CommandLine* command_line) OVERRIDE {
35     BrowserActionsContainer::disable_animations_during_testing_ = true;
36     ExtensionBrowserTest::SetUpCommandLine(command_line);
37   }
38
39   virtual void SetUpOnMainThread() OVERRIDE {
40     ExtensionBrowserTest::SetUpOnMainThread();
41     browser_actions_bar_.reset(new BrowserActionTestUtil(browser()));
42   }
43
44   virtual void TearDownOnMainThread() OVERRIDE {
45     BrowserActionsContainer::disable_animations_during_testing_ = false;
46   }
47
48   BrowserActionTestUtil* browser_actions_bar() {
49     return browser_actions_bar_.get();
50   }
51
52  private:
53   scoped_ptr<BrowserActionTestUtil> browser_actions_bar_;
54 };
55
56 // Test the basic functionality.
57 // http://crbug.com/120770
58 #if defined(OS_WIN)
59 IN_PROC_BROWSER_TEST_F(BrowserActionsContainerTest, DISABLED_Basic) {
60 #else
61 IN_PROC_BROWSER_TEST_F(BrowserActionsContainerTest, Basic) {
62 #endif
63   // Load an extension with no browser action.
64   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test")
65                                           .AppendASCII("browser_action")
66                                           .AppendASCII("none")));
67   // This extension should not be in the model (has no browser action).
68   EXPECT_EQ(0, browser_actions_bar()->NumberOfBrowserActions());
69
70   // Load an extension with a browser action.
71   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test")
72                                           .AppendASCII("browser_action")
73                                           .AppendASCII("basics")));
74   EXPECT_EQ(1, browser_actions_bar()->NumberOfBrowserActions());
75   EXPECT_TRUE(browser_actions_bar()->HasIcon(0));
76
77
78   // Unload the extension.
79   std::string id = browser_actions_bar()->GetExtensionId(0);
80   UnloadExtension(id);
81   EXPECT_EQ(0, browser_actions_bar()->NumberOfBrowserActions());
82 }
83
84 // Test moving various browser actions. This is not to check the logic of the
85 // move (that's in the toolbar model tests), but just to check our ui.
86 IN_PROC_BROWSER_TEST_F(BrowserActionsContainerTest,
87                        MoveBrowserActions) {
88   base::FilePath data_dir =
89       test_data_dir_.AppendASCII("api_test").AppendASCII("browser_action");
90   // Load three extensions with browser actions.
91   const extensions::Extension* extension_a =
92       LoadExtension(data_dir.AppendASCII("basics"));
93   ASSERT_TRUE(extension_a);
94   const extensions::Extension* extension_b =
95       LoadExtension(data_dir.AppendASCII("add_popup"));
96   ASSERT_TRUE(extension_b);
97   const extensions::Extension* extension_c =
98       LoadExtension(data_dir.AppendASCII("remove_popup"));
99   ASSERT_TRUE(extension_c);
100
101   EXPECT_EQ(3, browser_actions_bar()->VisibleBrowserActions());
102   EXPECT_EQ(3, browser_actions_bar()->NumberOfBrowserActions());
103
104   extensions::ExtensionToolbarModel* model =
105       extensions::ExtensionToolbarModel::Get(profile());
106   ASSERT_TRUE(model);
107
108   // Order is now A B C.
109   EXPECT_EQ(extension_a->id(), browser_actions_bar()->GetExtensionId(0));
110   EXPECT_EQ(extension_b->id(), browser_actions_bar()->GetExtensionId(1));
111   EXPECT_EQ(extension_c->id(), browser_actions_bar()->GetExtensionId(2));
112
113   // Move C to first position. Order is C A B.
114   model->MoveExtensionIcon(extension_c, 0);
115   EXPECT_EQ(extension_c->id(), browser_actions_bar()->GetExtensionId(0));
116   EXPECT_EQ(extension_a->id(), browser_actions_bar()->GetExtensionId(1));
117   EXPECT_EQ(extension_b->id(), browser_actions_bar()->GetExtensionId(2));
118
119   // Move B to third position. Order is still C A B.
120   model->MoveExtensionIcon(extension_b, 2);
121   EXPECT_EQ(extension_c->id(), browser_actions_bar()->GetExtensionId(0));
122   EXPECT_EQ(extension_a->id(), browser_actions_bar()->GetExtensionId(1));
123   EXPECT_EQ(extension_b->id(), browser_actions_bar()->GetExtensionId(2));
124
125   // Move B to middle position. Order is C B A.
126   model->MoveExtensionIcon(extension_b, 1);
127   EXPECT_EQ(extension_c->id(), browser_actions_bar()->GetExtensionId(0));
128   EXPECT_EQ(extension_b->id(), browser_actions_bar()->GetExtensionId(1));
129   EXPECT_EQ(extension_a->id(), browser_actions_bar()->GetExtensionId(2));
130 }
131
132 // Test that dragging browser actions works, and that dragging a browser action
133 // from the overflow menu results in it "popping" out (growing the container
134 // size by 1), rather than just reordering the extensions.
135 IN_PROC_BROWSER_TEST_F(BrowserActionsContainerTest, DragBrowserActions) {
136   base::FilePath data_dir =
137       test_data_dir_.AppendASCII("api_test").AppendASCII("browser_action");
138   // Load three extensions with browser actions.
139   const extensions::Extension* extension_a =
140       LoadExtension(data_dir.AppendASCII("basics"));
141   ASSERT_TRUE(extension_a);
142   const extensions::Extension* extension_b =
143       LoadExtension(data_dir.AppendASCII("add_popup"));
144   ASSERT_TRUE(extension_b);
145   const extensions::Extension* extension_c =
146       LoadExtension(data_dir.AppendASCII("remove_popup"));
147   ASSERT_TRUE(extension_c);
148
149   // Sanity check: All extensions showing; order is A B C.
150   EXPECT_EQ(3, browser_actions_bar()->VisibleBrowserActions());
151   EXPECT_EQ(3, browser_actions_bar()->NumberOfBrowserActions());
152   EXPECT_EQ(extension_a->id(), browser_actions_bar()->GetExtensionId(0));
153   EXPECT_EQ(extension_b->id(), browser_actions_bar()->GetExtensionId(1));
154   EXPECT_EQ(extension_c->id(), browser_actions_bar()->GetExtensionId(2));
155
156   BrowserActionsContainer* container =
157       BrowserView::GetBrowserViewForBrowser(browser())
158           ->toolbar()->browser_actions();
159
160   // Simulate a drag and drop to the right.
161   ui::OSExchangeData drop_data;
162   // Drag extension A from index 0...
163   BrowserActionDragData browser_action_drag_data(extension_a->id(), 0u);
164   browser_action_drag_data.Write(profile(), &drop_data);
165   BrowserActionView* view = container->GetViewForExtension(extension_b);
166   // ...to the right of extension B.
167   gfx::Point location(view->x() + view->width(), view->y());
168   ui::DropTargetEvent target_event(
169       drop_data, location, location, ui::DragDropTypes::DRAG_MOVE);
170
171   // Drag and drop.
172   container->OnDragUpdated(target_event);
173   container->OnPerformDrop(target_event);
174
175   // The order should now be B A C, since A was dragged to the right of B.
176   EXPECT_EQ(extension_b->id(), browser_actions_bar()->GetExtensionId(0));
177   EXPECT_EQ(extension_a->id(), browser_actions_bar()->GetExtensionId(1));
178   EXPECT_EQ(extension_c->id(), browser_actions_bar()->GetExtensionId(2));
179
180   // This order should be reflected in the underlying model.
181   extensions::ExtensionToolbarModel* model =
182       extensions::ExtensionToolbarModel::Get(profile());
183   EXPECT_EQ(extension_b, model->toolbar_items()[0].get());
184   EXPECT_EQ(extension_a, model->toolbar_items()[1].get());
185   EXPECT_EQ(extension_c, model->toolbar_items()[2].get());
186
187   // Simulate a drag and drop to the left.
188   ui::OSExchangeData drop_data2;
189   // Drag extension A from index 1...
190   BrowserActionDragData browser_action_drag_data2(extension_a->id(), 1u);
191   browser_action_drag_data2.Write(profile(), &drop_data2);
192   // ...to the left of extension B (which is now at index 0).
193   location = gfx::Point(view->x(), view->y());
194   ui::DropTargetEvent target_event2(
195       drop_data2, location, location, ui::DragDropTypes::DRAG_MOVE);
196
197   // Drag and drop.
198   container->OnDragUpdated(target_event2);
199   container->OnPerformDrop(target_event2);
200
201   // Order should be restored to A B C.
202   EXPECT_EQ(extension_a->id(), browser_actions_bar()->GetExtensionId(0));
203   EXPECT_EQ(extension_b->id(), browser_actions_bar()->GetExtensionId(1));
204   EXPECT_EQ(extension_c->id(), browser_actions_bar()->GetExtensionId(2));
205
206   // Shrink the size of the container so we have an overflow menu.
207   model->SetVisibleIconCountForTest(2u);
208   EXPECT_EQ(2u, container->VisibleBrowserActions());
209   ASSERT_TRUE(container->chevron());
210   EXPECT_TRUE(container->chevron()->visible());
211
212   // Simulate a drag and drop from the overflow menu.
213   ui::OSExchangeData drop_data3;
214   // Drag extension C from index 2 (in the overflow menu)...
215   BrowserActionDragData browser_action_drag_data3(extension_c->id(), 2u);
216   browser_action_drag_data3.Write(profile(), &drop_data3);
217   // ...to the left of extension B (which is back in index 1 on the main bar).
218   location = gfx::Point(view->x(), view->y());
219   ui::DropTargetEvent target_event3(
220       drop_data3, location, location, ui::DragDropTypes::DRAG_MOVE);
221
222   // Drag and drop.
223   container->OnDragUpdated(target_event3);
224   container->OnPerformDrop(target_event3);
225
226   // The order should have changed *and* the container should have grown to
227   // accommodate extension C. The new order should be A C B, and all three
228   // extensions should be visible, with no overflow menu.
229   EXPECT_EQ(extension_a->id(), browser_actions_bar()->GetExtensionId(0));
230   EXPECT_EQ(extension_c->id(), browser_actions_bar()->GetExtensionId(1));
231   EXPECT_EQ(extension_b->id(), browser_actions_bar()->GetExtensionId(2));
232   EXPECT_EQ(3u, container->VisibleBrowserActions());
233   EXPECT_FALSE(container->chevron()->visible());
234   EXPECT_EQ(-1, model->GetVisibleIconCount());
235
236   // TODO(devlin): Ideally, we'd also have tests for dragging from the legacy
237   // overflow menu (i.e., chevron) to the main bar, but this requires either
238   // having a fairly complicated interactive UI test or finding a good way to
239   // mock up the BrowserActionOverflowMenuController.
240 }
241
242 IN_PROC_BROWSER_TEST_F(BrowserActionsContainerTest, Visibility) {
243   // Load extension A (contains browser action).
244   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test")
245                                           .AppendASCII("browser_action")
246                                           .AppendASCII("basics")));
247   EXPECT_EQ(1, browser_actions_bar()->NumberOfBrowserActions());
248   EXPECT_TRUE(browser_actions_bar()->HasIcon(0));
249   EXPECT_EQ(1, browser_actions_bar()->VisibleBrowserActions());
250   std::string idA = browser_actions_bar()->GetExtensionId(0);
251
252   // Load extension B (contains browser action).
253   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test")
254                                           .AppendASCII("browser_action")
255                                           .AppendASCII("add_popup")));
256   EXPECT_EQ(2, browser_actions_bar()->NumberOfBrowserActions());
257   EXPECT_TRUE(browser_actions_bar()->HasIcon(0));
258   EXPECT_EQ(2, browser_actions_bar()->VisibleBrowserActions());
259   std::string idB = browser_actions_bar()->GetExtensionId(1);
260
261   EXPECT_NE(idA, idB);
262
263   // Load extension C (contains browser action).
264   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test")
265                                           .AppendASCII("browser_action")
266                                           .AppendASCII("remove_popup")));
267   EXPECT_EQ(3, browser_actions_bar()->NumberOfBrowserActions());
268   EXPECT_TRUE(browser_actions_bar()->HasIcon(2));
269   EXPECT_EQ(3, browser_actions_bar()->VisibleBrowserActions());
270   std::string idC = browser_actions_bar()->GetExtensionId(2);
271
272   // Change container to show only one action, rest in overflow: A, [B, C].
273   browser_actions_bar()->SetIconVisibilityCount(1);
274   EXPECT_EQ(1, browser_actions_bar()->VisibleBrowserActions());
275
276   // Disable extension A (should disappear). State becomes: B [C].
277   DisableExtension(idA);
278   EXPECT_EQ(2, browser_actions_bar()->NumberOfBrowserActions());
279   EXPECT_EQ(1, browser_actions_bar()->VisibleBrowserActions());
280   EXPECT_EQ(idB, browser_actions_bar()->GetExtensionId(0));
281
282   // Enable A again. A should get its spot in the same location and the bar
283   // should not grow (chevron is showing). For details: http://crbug.com/35349.
284   // State becomes: A, [B, C].
285   EnableExtension(idA);
286   EXPECT_EQ(3, browser_actions_bar()->NumberOfBrowserActions());
287   EXPECT_EQ(1, browser_actions_bar()->VisibleBrowserActions());
288   EXPECT_EQ(idA, browser_actions_bar()->GetExtensionId(0));
289
290   // Disable C (in overflow). State becomes: A, [B].
291   DisableExtension(idC);
292   EXPECT_EQ(2, browser_actions_bar()->NumberOfBrowserActions());
293   EXPECT_EQ(1, browser_actions_bar()->VisibleBrowserActions());
294   EXPECT_EQ(idA, browser_actions_bar()->GetExtensionId(0));
295
296   // Enable C again. State becomes: A, [B, C].
297   EnableExtension(idC);
298   EXPECT_EQ(3, browser_actions_bar()->NumberOfBrowserActions());
299   EXPECT_EQ(1, browser_actions_bar()->VisibleBrowserActions());
300   EXPECT_EQ(idA, browser_actions_bar()->GetExtensionId(0));
301
302   // Now we have 3 extensions. Make sure they are all visible. State: A, B, C.
303   browser_actions_bar()->SetIconVisibilityCount(3);
304   EXPECT_EQ(3, browser_actions_bar()->VisibleBrowserActions());
305
306   // Disable extension A (should disappear). State becomes: B, C.
307   DisableExtension(idA);
308   EXPECT_EQ(2, browser_actions_bar()->NumberOfBrowserActions());
309   EXPECT_EQ(2, browser_actions_bar()->VisibleBrowserActions());
310   EXPECT_EQ(idB, browser_actions_bar()->GetExtensionId(0));
311
312   // Disable extension B (should disappear). State becomes: C.
313   DisableExtension(idB);
314   EXPECT_EQ(1, browser_actions_bar()->NumberOfBrowserActions());
315   EXPECT_EQ(1, browser_actions_bar()->VisibleBrowserActions());
316   EXPECT_EQ(idC, browser_actions_bar()->GetExtensionId(0));
317
318   // Enable B. State becomes: B, C.
319   EnableExtension(idB);
320   EXPECT_EQ(2, browser_actions_bar()->NumberOfBrowserActions());
321   EXPECT_EQ(2, browser_actions_bar()->VisibleBrowserActions());
322   EXPECT_EQ(idB, browser_actions_bar()->GetExtensionId(0));
323
324   // Enable A. State becomes: A, B, C.
325   EnableExtension(idA);
326   EXPECT_EQ(3, browser_actions_bar()->NumberOfBrowserActions());
327   EXPECT_EQ(3, browser_actions_bar()->VisibleBrowserActions());
328   EXPECT_EQ(idA, browser_actions_bar()->GetExtensionId(0));
329
330   // Shrink the browser actions bar to zero visible icons.
331   // No icons should be visible, but we *should* show the chevron and have a
332   // non-empty size.
333   browser_actions_bar()->SetIconVisibilityCount(0);
334   EXPECT_EQ(0, browser_actions_bar()->VisibleBrowserActions());
335   BrowserActionsContainer* container =
336       BrowserView::GetBrowserViewForBrowser(browser())
337           ->toolbar()->browser_actions();
338   ASSERT_TRUE(container->chevron());
339   EXPECT_TRUE(container->chevron()->visible());
340   EXPECT_FALSE(container->GetPreferredSize().IsEmpty());
341
342   // Reset visibility count to 2. State should be A, B, [C], and the chevron
343   // should be visible.
344   browser_actions_bar()->SetIconVisibilityCount(2);
345   EXPECT_EQ(2, browser_actions_bar()->VisibleBrowserActions());
346   EXPECT_EQ(idA, browser_actions_bar()->GetExtensionId(0));
347   EXPECT_EQ(idB, browser_actions_bar()->GetExtensionId(1));
348   EXPECT_TRUE(container->chevron()->visible());
349
350   // Disable C (the overflowed extension). State should now be A, B, and the
351   // chevron should be hidden.
352   DisableExtension(idC);
353   EXPECT_EQ(2, browser_actions_bar()->VisibleBrowserActions());
354   EXPECT_EQ(idA, browser_actions_bar()->GetExtensionId(0));
355   EXPECT_EQ(idB, browser_actions_bar()->GetExtensionId(1));
356   EXPECT_FALSE(container->chevron()->visible());
357
358   // Re-enable C. We should still only have 2 visible icons, and the chevron
359   // should be visible.
360   EnableExtension(idC);
361   EXPECT_EQ(2, browser_actions_bar()->VisibleBrowserActions());
362   EXPECT_EQ(idA, browser_actions_bar()->GetExtensionId(0));
363   EXPECT_EQ(idB, browser_actions_bar()->GetExtensionId(1));
364   EXPECT_TRUE(container->chevron()->visible());
365 }
366
367 IN_PROC_BROWSER_TEST_F(BrowserActionsContainerTest, ForceHide) {
368   // Load extension A (contains browser action).
369   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test")
370                                           .AppendASCII("browser_action")
371                                           .AppendASCII("basics")));
372   EXPECT_EQ(1, browser_actions_bar()->NumberOfBrowserActions());
373   EXPECT_TRUE(browser_actions_bar()->HasIcon(0));
374   EXPECT_EQ(1, browser_actions_bar()->VisibleBrowserActions());
375   std::string idA = browser_actions_bar()->GetExtensionId(0);
376
377   // Force hide this browser action.
378   extensions::ExtensionActionAPI::SetBrowserActionVisibility(
379       extensions::ExtensionPrefs::Get(browser()->profile()), idA, false);
380   EXPECT_EQ(0, browser_actions_bar()->VisibleBrowserActions());
381 }
382
383 // Test that the BrowserActionsContainer responds correctly when the underlying
384 // model enters highlight mode, and that browser actions are undraggable in
385 // highlight mode. (Highlight mode itself it tested more thoroughly in the
386 // ExtensionToolbarModel browsertests).
387 IN_PROC_BROWSER_TEST_F(BrowserActionsContainerTest, HighlightMode) {
388   // Load three extensions with browser actions.
389   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test")
390                                           .AppendASCII("browser_action")
391                                           .AppendASCII("basics")));
392   std::string id_a = browser_actions_bar()->GetExtensionId(0);
393   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test")
394                                           .AppendASCII("browser_action")
395                                           .AppendASCII("add_popup")));
396   std::string id_b = browser_actions_bar()->GetExtensionId(1);
397   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test")
398                                           .AppendASCII("browser_action")
399                                           .AppendASCII("remove_popup")));
400
401   EXPECT_EQ(3, browser_actions_bar()->VisibleBrowserActions());
402   EXPECT_EQ(3, browser_actions_bar()->NumberOfBrowserActions());
403
404   BrowserActionsContainer* container = browser()
405                                            ->window()
406                                            ->GetBrowserWindowTesting()
407                                            ->GetToolbarView()
408                                            ->browser_actions();
409
410   // Currently, dragging should be enabled.
411   BrowserActionView* action_view = container->GetBrowserActionViewAt(0);
412   ASSERT_TRUE(action_view);
413   gfx::Point point(action_view->x(), action_view->y());
414   EXPECT_TRUE(container->CanStartDragForView(action_view, point, point));
415
416   extensions::ExtensionToolbarModel* model =
417       extensions::ExtensionToolbarModel::Get(profile());
418
419   extensions::ExtensionIdList extension_ids;
420   extension_ids.push_back(id_a);
421   extension_ids.push_back(id_b);
422   model->HighlightExtensions(extension_ids);
423
424   // Only two browser actions should be visible.
425   EXPECT_EQ(2, browser_actions_bar()->VisibleBrowserActions());
426   EXPECT_EQ(2, browser_actions_bar()->NumberOfBrowserActions());
427
428   // We shouldn't be able to drag in highlight mode.
429   action_view = container->GetBrowserActionViewAt(0);
430   EXPECT_FALSE(container->CanStartDragForView(action_view, point, point));
431
432   // We should go back to normal after leaving highlight mode.
433   model->StopHighlighting();
434   EXPECT_EQ(3, browser_actions_bar()->VisibleBrowserActions());
435   EXPECT_EQ(3, browser_actions_bar()->NumberOfBrowserActions());
436   action_view = container->GetBrowserActionViewAt(0);
437   EXPECT_TRUE(container->CanStartDragForView(action_view, point, point));
438 }
439
440 // Test the behavior of the overflow container for Extension Actions.
441 class BrowserActionsContainerOverflowTest : public BrowserActionsContainerTest {
442  public:
443   BrowserActionsContainerOverflowTest() : main_bar_(NULL), model_(NULL) {
444   }
445   virtual ~BrowserActionsContainerOverflowTest() {
446   }
447
448  protected:
449   // Returns true if the order of the BrowserActionViews in |main_bar_|
450   // and |overflow_bar_| match.
451   bool ViewOrdersMatch();
452
453   // Returns Success if the visible count matches |expected_visible|. This means
454   // that the number of visible browser actions in |main_bar_| is
455   // |expected_visible| and shows the first icons, and that the overflow bar
456   // shows all (and only) the remainder.
457   testing::AssertionResult VerifyVisibleCount(size_t expected_visible);
458
459   // Accessors.
460   BrowserActionsContainer* main_bar() { return main_bar_; }
461   BrowserActionsContainer* overflow_bar() { return overflow_bar_.get(); }
462   extensions::ExtensionToolbarModel* model() { return model_; }
463
464  private:
465   virtual void SetUpCommandLine(base::CommandLine* command_line) OVERRIDE;
466   virtual void SetUpOnMainThread() OVERRIDE;
467   virtual void TearDownOnMainThread() OVERRIDE;
468
469   // The main BrowserActionsContainer (owned by the browser view).
470   BrowserActionsContainer* main_bar_;
471
472   // The overflow BrowserActionsContainer. We manufacture this so that we don't
473   // have to open the wrench menu.
474   scoped_ptr<BrowserActionsContainer> overflow_bar_;
475
476   // The associated toolbar model.
477   extensions::ExtensionToolbarModel* model_;
478
479   // Enable the feature redesign switch.
480   scoped_ptr<extensions::FeatureSwitch::ScopedOverride> enable_redesign_;
481
482   DISALLOW_COPY_AND_ASSIGN(BrowserActionsContainerOverflowTest);
483 };
484
485 void BrowserActionsContainerOverflowTest::SetUpCommandLine(
486     base::CommandLine* command_line) {
487   BrowserActionsContainerTest::SetUpCommandLine(command_line);
488   enable_redesign_.reset(new extensions::FeatureSwitch::ScopedOverride(
489       extensions::FeatureSwitch::extension_action_redesign(),
490       true));
491 }
492
493 void BrowserActionsContainerOverflowTest::SetUpOnMainThread() {
494   BrowserActionsContainerTest::SetUpOnMainThread();
495   main_bar_ = BrowserView::GetBrowserViewForBrowser(browser())
496                   ->toolbar()->browser_actions();
497   overflow_bar_.reset(new BrowserActionsContainer(browser(), NULL, main_bar_));
498   overflow_bar_->set_owned_by_client();
499   model_ = extensions::ExtensionToolbarModel::Get(profile());
500 }
501
502 void BrowserActionsContainerOverflowTest::TearDownOnMainThread() {
503   overflow_bar_.reset();
504   enable_redesign_.reset();
505   BrowserActionsContainerTest::TearDownOnMainThread();
506 }
507
508 bool BrowserActionsContainerOverflowTest::ViewOrdersMatch() {
509   if (main_bar_->num_browser_actions() !=
510       overflow_bar_->num_browser_actions())
511     return false;
512   for (size_t i = 0; i < main_bar_->num_browser_actions(); ++i) {
513     if (main_bar_->GetBrowserActionViewAt(i)->extension() !=
514         overflow_bar_->GetBrowserActionViewAt(i)->extension())
515       return false;
516   }
517   return true;
518 }
519
520 testing::AssertionResult
521 BrowserActionsContainerOverflowTest::VerifyVisibleCount(
522     size_t expected_visible) {
523   // Views order should always match (as it is based directly off the model).
524   if (!ViewOrdersMatch())
525     return testing::AssertionFailure() << "View orders don't match";
526
527   // Loop through and check each browser action for proper visibility (which
528   // implicitly also guarantees that the proper number are visible).
529   for (size_t i = 0; i < overflow_bar_->num_browser_actions(); ++i) {
530     bool visible = i < expected_visible;
531     if (main_bar_->GetBrowserActionViewAt(i)->visible() != visible) {
532       return testing::AssertionFailure() << "Index " << i <<
533           " has improper visibility in main: " << !visible;
534     }
535     if (overflow_bar_->GetBrowserActionViewAt(i)->visible() == visible) {
536       return testing::AssertionFailure() << "Index " << i <<
537           " has improper visibility in overflow: " << visible;
538     }
539   }
540   return testing::AssertionSuccess();
541 }
542
543 // Test the basic functionality of the BrowserActionsContainer in overflow mode.
544 IN_PROC_BROWSER_TEST_F(BrowserActionsContainerOverflowTest,
545                        TestBasicActionOverflow) {
546   // Load three extensions with browser actions.
547   // TODO(devlin): Make a method to load these, and generate them rather than
548   // using files.
549   base::FilePath test_data_path =
550       test_data_dir_.AppendASCII("api_test").AppendASCII("browser_action");
551   const extensions::Extension* extension_a =
552       LoadExtension(test_data_path.AppendASCII("basics"));
553   const extensions::Extension* extension_b =
554       LoadExtension(test_data_path.AppendASCII("add_popup"));
555   const extensions::Extension* extension_c =
556       LoadExtension(test_data_path.AppendASCII("remove_popup"));
557
558   // Since the overflow bar isn't attached to a view, we have to kick it in
559   // order to retrigger layout each time we change the number of icons in the
560   // bar.
561   overflow_bar()->Layout();
562
563   // Sanity checks:
564   // All extensions loaded.
565   ASSERT_TRUE(extension_a);
566   ASSERT_TRUE(extension_b);
567   ASSERT_TRUE(extension_c);
568
569   // All actions are showing, and are in the installation order.
570   EXPECT_EQ(-1, model()->GetVisibleIconCount());
571   ASSERT_EQ(3u, main_bar()->num_browser_actions());
572   EXPECT_EQ(extension_a, main_bar()->GetBrowserActionViewAt(0)->extension());
573   EXPECT_EQ(extension_b, main_bar()->GetBrowserActionViewAt(1)->extension());
574   EXPECT_EQ(extension_c, main_bar()->GetBrowserActionViewAt(2)->extension());
575   EXPECT_TRUE(VerifyVisibleCount(3u));
576
577   // Reduce the visible count to 2. Order should be unchanged (A B C), but
578   // only A and B should be visible on the main bar.
579   model()->SetVisibleIconCountForTest(2u);
580   overflow_bar()->Layout();  // Kick.
581   EXPECT_EQ(extension_a, main_bar()->GetBrowserActionViewAt(0)->extension());
582   EXPECT_EQ(extension_b, main_bar()->GetBrowserActionViewAt(1)->extension());
583   EXPECT_EQ(extension_c, main_bar()->GetBrowserActionViewAt(2)->extension());
584   EXPECT_TRUE(VerifyVisibleCount(2u));
585
586   // Move extension C to the first position. Order should now be C A B, with
587   // C and A visible in the main bar.
588   model()->MoveExtensionIcon(extension_c, 0);
589   overflow_bar()->Layout();  // Kick.
590   EXPECT_EQ(extension_c, main_bar()->GetBrowserActionViewAt(0)->extension());
591   EXPECT_EQ(extension_a, main_bar()->GetBrowserActionViewAt(1)->extension());
592   EXPECT_EQ(extension_b, main_bar()->GetBrowserActionViewAt(2)->extension());
593   EXPECT_TRUE(VerifyVisibleCount(2u));
594
595   // Hide action A. This results in it being sent to overflow, and reducing the
596   // visible size to 1, so the order should be C A B, with only C visible in the
597   // main bar.
598   extensions::ExtensionActionAPI::SetBrowserActionVisibility(
599       extensions::ExtensionPrefs::Get(profile()),
600       extension_a->id(),
601       false);
602   overflow_bar()->Layout();  // Kick.
603   EXPECT_EQ(extension_c, main_bar()->GetBrowserActionViewAt(0)->extension());
604   EXPECT_EQ(extension_a, main_bar()->GetBrowserActionViewAt(1)->extension());
605   EXPECT_EQ(extension_b, main_bar()->GetBrowserActionViewAt(2)->extension());
606   EXPECT_TRUE(VerifyVisibleCount(1u));
607 }
608
609 // Test drag and drop between the overflow container and the main container.
610 IN_PROC_BROWSER_TEST_F(BrowserActionsContainerOverflowTest,
611                        TestOverflowDragging) {
612   base::FilePath test_data_path =
613       test_data_dir_.AppendASCII("api_test").AppendASCII("browser_action");
614   const extensions::Extension* extension_a =
615       LoadExtension(test_data_path.AppendASCII("basics"));
616   const extensions::Extension* extension_b =
617       LoadExtension(test_data_path.AppendASCII("add_popup"));
618   const extensions::Extension* extension_c =
619       LoadExtension(test_data_path.AppendASCII("remove_popup"));
620
621   // Start with one extension in overflow.
622   model()->SetVisibleIconCountForTest(2u);
623   overflow_bar()->Layout();
624
625   // Verify starting state is A B [C].
626   ASSERT_EQ(3u, main_bar()->num_browser_actions());
627   EXPECT_EQ(extension_a, main_bar()->GetBrowserActionViewAt(0)->extension());
628   EXPECT_EQ(extension_b, main_bar()->GetBrowserActionViewAt(1)->extension());
629   EXPECT_EQ(extension_c, main_bar()->GetBrowserActionViewAt(2)->extension());
630   EXPECT_TRUE(VerifyVisibleCount(2u));
631
632   // Drag extension A (on the main bar) to the left of extension C (in
633   // overflow).
634   ui::OSExchangeData drop_data;
635   BrowserActionDragData browser_action_drag_data(extension_a->id(), 0u);
636   browser_action_drag_data.Write(profile(), &drop_data);
637   BrowserActionView* view = overflow_bar()->GetViewForExtension(extension_c);
638   gfx::Point location(view->x(), view->y());
639   ui::DropTargetEvent target_event(
640       drop_data, location, location, ui::DragDropTypes::DRAG_MOVE);
641
642   overflow_bar()->OnDragUpdated(target_event);
643   overflow_bar()->OnPerformDrop(target_event);
644   overflow_bar()->Layout();
645
646   // Order should now be B [A C].
647   EXPECT_EQ(extension_b, main_bar()->GetBrowserActionViewAt(0)->extension());
648   EXPECT_EQ(extension_a, main_bar()->GetBrowserActionViewAt(1)->extension());
649   EXPECT_EQ(extension_c, main_bar()->GetBrowserActionViewAt(2)->extension());
650   VerifyVisibleCount(1u);
651
652   // Drag extension A back from overflow to the main bar.
653   ui::OSExchangeData drop_data2;
654   BrowserActionDragData browser_action_drag_data2(extension_a->id(), 1u);
655   browser_action_drag_data2.Write(profile(), &drop_data2);
656   view = main_bar()->GetViewForExtension(extension_b);
657   location = gfx::Point(view->x(), view->y());
658   ui::DropTargetEvent target_event2(
659       drop_data2, location, location, ui::DragDropTypes::DRAG_MOVE);
660
661   main_bar()->OnDragUpdated(target_event2);
662   main_bar()->OnPerformDrop(target_event2);
663
664   // Order should be A B [C] again.
665   EXPECT_EQ(extension_a, main_bar()->GetBrowserActionViewAt(0)->extension());
666   EXPECT_EQ(extension_b, main_bar()->GetBrowserActionViewAt(1)->extension());
667   EXPECT_EQ(extension_c, main_bar()->GetBrowserActionViewAt(2)->extension());
668   VerifyVisibleCount(2u);
669
670   // Drag extension C from overflow to the main bar (before extension B).
671   ui::OSExchangeData drop_data3;
672   BrowserActionDragData browser_action_drag_data3(extension_c->id(), 2u);
673   browser_action_drag_data3.Write(profile(), &drop_data3);
674   location = gfx::Point(view->x(), view->y());
675   ui::DropTargetEvent target_event3(
676       drop_data3, location, location, ui::DragDropTypes::DRAG_MOVE);
677
678   main_bar()->OnDragUpdated(target_event3);
679   main_bar()->OnPerformDrop(target_event3);
680
681   // Order should be A C B, and there should be no extensions in overflow.
682   EXPECT_EQ(extension_a, main_bar()->GetBrowserActionViewAt(0)->extension());
683   EXPECT_EQ(extension_c, main_bar()->GetBrowserActionViewAt(1)->extension());
684   EXPECT_EQ(extension_b, main_bar()->GetBrowserActionViewAt(2)->extension());
685   VerifyVisibleCount(3u);
686 }