Home | History | Annotate | Download | only in toolbar
      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 }
    687