Home | History | Annotate | Download | only in button
      1 // Copyright 2014 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 "ui/views/controls/button/menu_button.h"
      6 
      7 #include "base/memory/scoped_ptr.h"
      8 #include "base/strings/utf_string_conversions.h"
      9 #include "ui/events/test/event_generator.h"
     10 #include "ui/views/controls/button/menu_button_listener.h"
     11 #include "ui/views/test/views_test_base.h"
     12 
     13 using base::ASCIIToUTF16;
     14 
     15 namespace views {
     16 
     17 class MenuButtonTest : public ViewsTestBase {
     18  public:
     19   MenuButtonTest() : widget_(NULL), button_(NULL) {}
     20   virtual ~MenuButtonTest() {}
     21 
     22   virtual void TearDown() OVERRIDE {
     23     if (widget_ && !widget_->IsClosed())
     24       widget_->Close();
     25 
     26     ViewsTestBase::TearDown();
     27   }
     28 
     29   Widget* widget() { return widget_; }
     30   MenuButton* button() { return button_; }
     31 
     32  protected:
     33   // Creates a MenuButton with no button listener.
     34   void CreateMenuButtonWithNoListener() {
     35     CreateMenuButton(NULL, NULL);
     36   }
     37 
     38   // Creates a MenuButton with a ButtonListener. In this case, the MenuButton
     39   // acts like a regular button.
     40   void CreateMenuButtonWithButtonListener(ButtonListener* button_listener) {
     41     CreateMenuButton(button_listener, NULL);
     42   }
     43 
     44   // Creates a MenuButton with a MenuButtonListener. In this case, when the
     45   // MenuButton is pushed, it notifies the MenuButtonListener to open a
     46   // drop-down menu.
     47   void CreateMenuButtonWithMenuButtonListener(
     48       MenuButtonListener* menu_button_listener) {
     49     CreateMenuButton(NULL, menu_button_listener);
     50   }
     51 
     52  private:
     53   void CreateMenuButton(ButtonListener* button_listener,
     54                         MenuButtonListener* menu_button_listener) {
     55     CreateWidget();
     56 
     57     const base::string16 label(ASCIIToUTF16("button"));
     58     button_ =
     59         new MenuButton(button_listener, label, menu_button_listener, false);
     60     button_->SetBoundsRect(gfx::Rect(0, 0, 200, 20));
     61     widget_->SetContentsView(button_);
     62 
     63     widget_->Show();
     64   }
     65 
     66   void CreateWidget() {
     67     DCHECK(!widget_);
     68 
     69     widget_ = new Widget;
     70     Widget::InitParams params =
     71         CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
     72     params.bounds = gfx::Rect(0, 0, 200, 200);
     73     widget_->Init(params);
     74   }
     75 
     76   Widget* widget_;
     77   MenuButton* button_;
     78 };
     79 
     80 class TestButtonListener : public ButtonListener {
     81  public:
     82   TestButtonListener()
     83       : last_sender_(NULL),
     84         last_sender_state_(Button::STATE_NORMAL),
     85         last_event_type_(ui::ET_UNKNOWN) {}
     86   virtual ~TestButtonListener() {}
     87 
     88   virtual void ButtonPressed(Button* sender, const ui::Event& event) OVERRIDE {
     89     last_sender_ = sender;
     90     CustomButton* custom_button = CustomButton::AsCustomButton(sender);
     91     DCHECK(custom_button);
     92     last_sender_state_ = custom_button->state();
     93     last_event_type_ = event.type();
     94   }
     95 
     96   Button* last_sender() { return last_sender_; }
     97   Button::ButtonState last_sender_state() { return last_sender_state_; }
     98   ui::EventType last_event_type() { return last_event_type_; }
     99 
    100  private:
    101   Button* last_sender_;
    102   Button::ButtonState last_sender_state_;
    103   ui::EventType last_event_type_;
    104 
    105   DISALLOW_COPY_AND_ASSIGN(TestButtonListener);
    106 };
    107 
    108 class TestMenuButtonListener : public MenuButtonListener {
    109  public:
    110   TestMenuButtonListener() {}
    111   virtual ~TestMenuButtonListener() {}
    112 
    113   virtual void OnMenuButtonClicked(View* source,
    114                                    const gfx::Point& /*point*/) OVERRIDE {
    115     last_source_ = source;
    116     CustomButton* custom_button = CustomButton::AsCustomButton(source);
    117     DCHECK(custom_button);
    118     last_source_state_ = custom_button->state();
    119   }
    120 
    121   View* last_source() { return last_source_; }
    122   Button::ButtonState last_source_state() { return last_source_state_; }
    123 
    124  private:
    125   View* last_source_;
    126   Button::ButtonState last_source_state_;
    127 };
    128 
    129 // Tests if the listener is notified correctly, when a mouse click happens on a
    130 // MenuButton that has a regular ButtonListener.
    131 TEST_F(MenuButtonTest, ActivateNonDropDownOnMouseClick) {
    132   scoped_ptr<TestButtonListener> button_listener(new TestButtonListener);
    133   CreateMenuButtonWithButtonListener(button_listener.get());
    134 
    135   ui::test::EventGenerator generator(GetContext(), widget()->GetNativeWindow());
    136 
    137   generator.set_current_location(gfx::Point(10, 10));
    138   generator.ClickLeftButton();
    139 
    140   // Check that MenuButton has notified the listener on mouse-released event,
    141   // while it was in hovered state.
    142   EXPECT_EQ(button(), button_listener->last_sender());
    143   EXPECT_EQ(ui::ET_MOUSE_RELEASED, button_listener->last_event_type());
    144   EXPECT_EQ(Button::STATE_HOVERED, button_listener->last_sender_state());
    145 }
    146 
    147 // Tests if the listener is notified correctly when a gesture tap happens on a
    148 // MenuButton that has a regular ButtonListener.
    149 TEST_F(MenuButtonTest, ActivateNonDropDownOnGestureTap) {
    150   scoped_ptr<TestButtonListener> button_listener(new TestButtonListener);
    151   CreateMenuButtonWithButtonListener(button_listener.get());
    152 
    153   ui::test::EventGenerator generator(GetContext(), widget()->GetNativeWindow());
    154   generator.GestureTapAt(gfx::Point(10, 10));
    155 
    156   // Check that MenuButton has notified the listener on gesture tap event, while
    157   // it was in hovered state.
    158   EXPECT_EQ(button(), button_listener->last_sender());
    159   EXPECT_EQ(ui::ET_GESTURE_TAP, button_listener->last_event_type());
    160   EXPECT_EQ(Button::STATE_HOVERED, button_listener->last_sender_state());
    161 }
    162 
    163 // Tests if the listener is notified correctly when a mouse click happens on a
    164 // MenuButton that has a MenuButtonListener.
    165 TEST_F(MenuButtonTest, ActivateDropDownOnMouseClick) {
    166   scoped_ptr<TestMenuButtonListener> menu_button_listener(
    167       new TestMenuButtonListener);
    168   CreateMenuButtonWithMenuButtonListener(menu_button_listener.get());
    169 
    170   ui::test::EventGenerator generator(GetContext(), widget()->GetNativeWindow());
    171 
    172   generator.set_current_location(gfx::Point(10, 10));
    173   generator.ClickLeftButton();
    174 
    175   // Check that MenuButton has notified the listener, while it was in pressed
    176   // state.
    177   EXPECT_EQ(button(), menu_button_listener->last_source());
    178   EXPECT_EQ(Button::STATE_PRESSED, menu_button_listener->last_source_state());
    179 }
    180 
    181 // Tests if the listener is notified correctly when a gesture tap happens on a
    182 // MenuButton that has a MenuButtonListener.
    183 TEST_F(MenuButtonTest, ActivateDropDownOnGestureTap) {
    184   scoped_ptr<TestMenuButtonListener> menu_button_listener(
    185       new TestMenuButtonListener);
    186   CreateMenuButtonWithMenuButtonListener(menu_button_listener.get());
    187 
    188   ui::test::EventGenerator generator(GetContext(), widget()->GetNativeWindow());
    189   generator.GestureTapAt(gfx::Point(10, 10));
    190 
    191   // Check that MenuButton has notified the listener, while it was in pressed
    192   // state.
    193   EXPECT_EQ(button(), menu_button_listener->last_source());
    194   EXPECT_EQ(Button::STATE_PRESSED, menu_button_listener->last_source_state());
    195 }
    196 
    197 // Test that the MenuButton stays pressed while there are any PressedLocks.
    198 TEST_F(MenuButtonTest, MenuButtonPressedLock) {
    199   CreateMenuButtonWithNoListener();
    200 
    201   // Move the mouse over the button; the button should be in a hovered state.
    202   ui::test::EventGenerator generator(GetContext(), widget()->GetNativeWindow());
    203   generator.MoveMouseTo(gfx::Point(10, 10));
    204   EXPECT_EQ(Button::STATE_HOVERED, button()->state());
    205 
    206   // Introduce a PressedLock, which should make the button pressed.
    207   scoped_ptr<MenuButton::PressedLock> pressed_lock1(
    208       new MenuButton::PressedLock(button()));
    209   EXPECT_EQ(Button::STATE_PRESSED, button()->state());
    210 
    211   // Even if we move the mouse outside of the button, it should remain pressed.
    212   generator.MoveMouseTo(gfx::Point(300, 10));
    213   EXPECT_EQ(Button::STATE_PRESSED, button()->state());
    214 
    215   // Creating a new lock should obviously keep the button pressed.
    216   scoped_ptr<MenuButton::PressedLock> pressed_lock2(
    217       new MenuButton::PressedLock(button()));
    218   EXPECT_EQ(Button::STATE_PRESSED, button()->state());
    219 
    220   // The button should remain pressed while any locks are active.
    221   pressed_lock1.reset();
    222   EXPECT_EQ(Button::STATE_PRESSED, button()->state());
    223 
    224   // Reseting the final lock should return the button's state to normal...
    225   pressed_lock2.reset();
    226   EXPECT_EQ(Button::STATE_NORMAL, button()->state());
    227 
    228   // ...And it should respond to mouse movement again.
    229   generator.MoveMouseTo(gfx::Point(10, 10));
    230   EXPECT_EQ(Button::STATE_HOVERED, button()->state());
    231 }
    232 
    233 }  // namespace views
    234