ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / ui / views / controls / button / menu_button_unittest.cc
blobd00743e82f7637eed8d3047e47886bec5256aa80
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.
5 #include "ui/views/controls/button/menu_button.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "ui/base/dragdrop/drag_drop_types.h"
10 #include "ui/events/test/event_generator.h"
11 #include "ui/views/controls/button/menu_button_listener.h"
12 #include "ui/views/drag_controller.h"
13 #include "ui/views/test/views_test_base.h"
15 #if defined(USE_AURA)
16 #include "ui/events/event.h"
17 #include "ui/events/event_handler.h"
18 #include "ui/wm/public/drag_drop_client.h"
19 #endif
21 using base::ASCIIToUTF16;
23 namespace views {
25 class MenuButtonTest : public ViewsTestBase {
26 public:
27 MenuButtonTest() : widget_(nullptr), button_(nullptr) {}
28 ~MenuButtonTest() override {}
30 void TearDown() override {
31 if (widget_ && !widget_->IsClosed())
32 widget_->Close();
34 ViewsTestBase::TearDown();
37 Widget* widget() { return widget_; }
38 MenuButton* button() { return button_; }
40 protected:
41 // Creates a MenuButton with no button listener.
42 void CreateMenuButtonWithNoListener() { CreateMenuButton(nullptr, nullptr); }
44 // Creates a MenuButton with a ButtonListener. In this case, the MenuButton
45 // acts like a regular button.
46 void CreateMenuButtonWithButtonListener(ButtonListener* button_listener) {
47 CreateMenuButton(button_listener, nullptr);
50 // Creates a MenuButton with a MenuButtonListener. In this case, when the
51 // MenuButton is pushed, it notifies the MenuButtonListener to open a
52 // drop-down menu.
53 void CreateMenuButtonWithMenuButtonListener(
54 MenuButtonListener* menu_button_listener) {
55 CreateMenuButton(nullptr, menu_button_listener);
58 private:
59 void CreateMenuButton(ButtonListener* button_listener,
60 MenuButtonListener* menu_button_listener) {
61 CreateWidget();
63 const base::string16 label(ASCIIToUTF16("button"));
64 button_ =
65 new MenuButton(button_listener, label, menu_button_listener, false);
66 button_->SetBoundsRect(gfx::Rect(0, 0, 200, 20));
67 widget_->SetContentsView(button_);
69 widget_->Show();
72 void CreateWidget() {
73 DCHECK(!widget_);
75 widget_ = new Widget;
76 Widget::InitParams params =
77 CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
78 params.bounds = gfx::Rect(0, 0, 200, 200);
79 widget_->Init(params);
82 Widget* widget_;
83 MenuButton* button_;
86 class TestButtonListener : public ButtonListener {
87 public:
88 TestButtonListener()
89 : last_sender_(nullptr),
90 last_sender_state_(Button::STATE_NORMAL),
91 last_event_type_(ui::ET_UNKNOWN) {}
92 ~TestButtonListener() override {}
94 void ButtonPressed(Button* sender, const ui::Event& event) override {
95 last_sender_ = sender;
96 CustomButton* custom_button = CustomButton::AsCustomButton(sender);
97 DCHECK(custom_button);
98 last_sender_state_ = custom_button->state();
99 last_event_type_ = event.type();
102 Button* last_sender() { return last_sender_; }
103 Button::ButtonState last_sender_state() { return last_sender_state_; }
104 ui::EventType last_event_type() { return last_event_type_; }
106 private:
107 Button* last_sender_;
108 Button::ButtonState last_sender_state_;
109 ui::EventType last_event_type_;
111 DISALLOW_COPY_AND_ASSIGN(TestButtonListener);
114 class TestMenuButtonListener : public MenuButtonListener {
115 public:
116 TestMenuButtonListener()
117 : last_source_(nullptr), last_source_state_(Button::STATE_NORMAL) {}
118 ~TestMenuButtonListener() override {}
120 void OnMenuButtonClicked(View* source, const gfx::Point& /*point*/) override {
121 last_source_ = source;
122 CustomButton* custom_button = CustomButton::AsCustomButton(source);
123 DCHECK(custom_button);
124 last_source_state_ = custom_button->state();
127 View* last_source() { return last_source_; }
128 Button::ButtonState last_source_state() { return last_source_state_; }
130 private:
131 View* last_source_;
132 Button::ButtonState last_source_state_;
135 // Basic implementation of a DragController, to test input behaviour for
136 // MenuButtons that can be dragged.
137 class TestDragController : public DragController {
138 public:
139 TestDragController() {}
140 ~TestDragController() override {}
142 void WriteDragDataForView(View* sender,
143 const gfx::Point& press_pt,
144 ui::OSExchangeData* data) override {}
146 int GetDragOperationsForView(View* sender, const gfx::Point& p) override {
147 return ui::DragDropTypes::DRAG_MOVE;
150 bool CanStartDragForView(View* sender,
151 const gfx::Point& press_pt,
152 const gfx::Point& p) override {
153 return true;
156 private:
157 DISALLOW_COPY_AND_ASSIGN(TestDragController);
160 #if defined(USE_AURA)
161 // Basic implementation of a DragDropClient, tracking the state of the drag
162 // operation. While dragging addition mouse events are consumed, preventing the
163 // target view from receiving them.
164 class TestDragDropClient : public aura::client::DragDropClient,
165 public ui::EventHandler {
166 public:
167 TestDragDropClient();
168 ~TestDragDropClient() override;
170 // aura::client::DragDropClient:
171 int StartDragAndDrop(const ui::OSExchangeData& data,
172 aura::Window* root_window,
173 aura::Window* source_window,
174 const gfx::Point& screen_location,
175 int operation,
176 ui::DragDropTypes::DragEventSource source) override;
177 void DragUpdate(aura::Window* target, const ui::LocatedEvent& event) override;
178 void Drop(aura::Window* target, const ui::LocatedEvent& event) override;
179 void DragCancel() override;
180 bool IsDragDropInProgress() override;
182 // ui::EventHandler:
183 void OnMouseEvent(ui::MouseEvent* event) override;
185 private:
186 // True while receiving ui::LocatedEvents for drag operations.
187 bool drag_in_progress_;
189 // Target window where drag operations are occuring.
190 aura::Window* target_;
192 DISALLOW_COPY_AND_ASSIGN(TestDragDropClient);
195 TestDragDropClient::TestDragDropClient()
196 : drag_in_progress_(false), target_(nullptr) {
199 TestDragDropClient::~TestDragDropClient() {
202 int TestDragDropClient::StartDragAndDrop(
203 const ui::OSExchangeData& data,
204 aura::Window* root_window,
205 aura::Window* source_window,
206 const gfx::Point& screen_location,
207 int operation,
208 ui::DragDropTypes::DragEventSource source) {
209 if (IsDragDropInProgress())
210 return ui::DragDropTypes::DRAG_NONE;
211 drag_in_progress_ = true;
212 target_ = root_window;
213 return operation;
216 void TestDragDropClient::DragUpdate(aura::Window* target,
217 const ui::LocatedEvent& event) {
220 void TestDragDropClient::Drop(aura::Window* target,
221 const ui::LocatedEvent& event) {
222 drag_in_progress_ = false;
225 void TestDragDropClient::DragCancel() {
226 drag_in_progress_ = false;
229 bool TestDragDropClient::IsDragDropInProgress() {
230 return drag_in_progress_;
233 void TestDragDropClient::OnMouseEvent(ui::MouseEvent* event) {
234 if (!IsDragDropInProgress())
235 return;
236 switch (event->type()) {
237 case ui::ET_MOUSE_DRAGGED:
238 DragUpdate(target_, *event);
239 event->StopPropagation();
240 break;
241 case ui::ET_MOUSE_RELEASED:
242 Drop(target_, *event);
243 event->StopPropagation();
244 break;
245 default:
246 break;
249 #endif // defined(USE_AURA)
251 // Tests if the listener is notified correctly, when a mouse click happens on a
252 // MenuButton that has a regular ButtonListener.
253 TEST_F(MenuButtonTest, ActivateNonDropDownOnMouseClick) {
254 TestButtonListener button_listener;
255 CreateMenuButtonWithButtonListener(&button_listener);
257 ui::test::EventGenerator generator(GetContext(), widget()->GetNativeWindow());
259 generator.set_current_location(gfx::Point(10, 10));
260 generator.ClickLeftButton();
262 // Check that MenuButton has notified the listener on mouse-released event,
263 // while it was in hovered state.
264 EXPECT_EQ(button(), button_listener.last_sender());
265 EXPECT_EQ(ui::ET_MOUSE_RELEASED, button_listener.last_event_type());
266 EXPECT_EQ(Button::STATE_HOVERED, button_listener.last_sender_state());
269 // Tests if the listener is notified correctly when a gesture tap happens on a
270 // MenuButton that has a regular ButtonListener.
271 TEST_F(MenuButtonTest, ActivateNonDropDownOnGestureTap) {
272 TestButtonListener button_listener;
273 CreateMenuButtonWithButtonListener(&button_listener);
275 ui::test::EventGenerator generator(GetContext(), widget()->GetNativeWindow());
276 generator.GestureTapAt(gfx::Point(10, 10));
278 // Check that MenuButton has notified the listener on gesture tap event, while
279 // it was in hovered state.
280 EXPECT_EQ(button(), button_listener.last_sender());
281 EXPECT_EQ(ui::ET_GESTURE_TAP, button_listener.last_event_type());
282 EXPECT_EQ(Button::STATE_HOVERED, button_listener.last_sender_state());
285 // Tests if the listener is notified correctly when a mouse click happens on a
286 // MenuButton that has a MenuButtonListener.
287 TEST_F(MenuButtonTest, ActivateDropDownOnMouseClick) {
288 TestMenuButtonListener menu_button_listener;
289 CreateMenuButtonWithMenuButtonListener(&menu_button_listener);
291 ui::test::EventGenerator generator(GetContext(), widget()->GetNativeWindow());
293 generator.set_current_location(gfx::Point(10, 10));
294 generator.ClickLeftButton();
296 // Check that MenuButton has notified the listener, while it was in pressed
297 // state.
298 EXPECT_EQ(button(), menu_button_listener.last_source());
299 EXPECT_EQ(Button::STATE_PRESSED, menu_button_listener.last_source_state());
302 // Tests if the listener is notified correctly when a gesture tap happens on a
303 // MenuButton that has a MenuButtonListener.
304 TEST_F(MenuButtonTest, ActivateDropDownOnGestureTap) {
305 TestMenuButtonListener menu_button_listener;
306 CreateMenuButtonWithMenuButtonListener(&menu_button_listener);
308 ui::test::EventGenerator generator(GetContext(), widget()->GetNativeWindow());
309 generator.GestureTapAt(gfx::Point(10, 10));
311 // Check that MenuButton has notified the listener, while it was in pressed
312 // state.
313 EXPECT_EQ(button(), menu_button_listener.last_source());
314 EXPECT_EQ(Button::STATE_PRESSED, menu_button_listener.last_source_state());
317 // Test that the MenuButton stays pressed while there are any PressedLocks.
318 TEST_F(MenuButtonTest, MenuButtonPressedLock) {
319 CreateMenuButtonWithNoListener();
321 // Move the mouse over the button; the button should be in a hovered state.
322 ui::test::EventGenerator generator(GetContext(), widget()->GetNativeWindow());
323 generator.MoveMouseTo(gfx::Point(10, 10));
324 EXPECT_EQ(Button::STATE_HOVERED, button()->state());
326 // Introduce a PressedLock, which should make the button pressed.
327 scoped_ptr<MenuButton::PressedLock> pressed_lock1(
328 new MenuButton::PressedLock(button()));
329 EXPECT_EQ(Button::STATE_PRESSED, button()->state());
331 // Even if we move the mouse outside of the button, it should remain pressed.
332 generator.MoveMouseTo(gfx::Point(300, 10));
333 EXPECT_EQ(Button::STATE_PRESSED, button()->state());
335 // Creating a new lock should obviously keep the button pressed.
336 scoped_ptr<MenuButton::PressedLock> pressed_lock2(
337 new MenuButton::PressedLock(button()));
338 EXPECT_EQ(Button::STATE_PRESSED, button()->state());
340 // The button should remain pressed while any locks are active.
341 pressed_lock1.reset();
342 EXPECT_EQ(Button::STATE_PRESSED, button()->state());
344 // Reseting the final lock should return the button's state to normal...
345 pressed_lock2.reset();
346 EXPECT_EQ(Button::STATE_NORMAL, button()->state());
348 // ...And it should respond to mouse movement again.
349 generator.MoveMouseTo(gfx::Point(10, 10));
350 EXPECT_EQ(Button::STATE_HOVERED, button()->state());
352 // Test that the button returns to the appropriate state after the press; if
353 // the mouse ends over the button, the button should be hovered.
354 pressed_lock1.reset(new MenuButton::PressedLock(button()));
355 EXPECT_EQ(Button::STATE_PRESSED, button()->state());
356 pressed_lock1.reset();
357 EXPECT_EQ(Button::STATE_HOVERED, button()->state());
359 // If the button is disabled before the pressed lock, it should be disabled
360 // after the pressed lock.
361 button()->SetState(Button::STATE_DISABLED);
362 pressed_lock1.reset(new MenuButton::PressedLock(button()));
363 EXPECT_EQ(Button::STATE_PRESSED, button()->state());
364 pressed_lock1.reset();
365 EXPECT_EQ(Button::STATE_DISABLED, button()->state());
367 generator.MoveMouseTo(gfx::Point(300, 10));
369 // Edge case: the button is disabled, a pressed lock is added, and then the
370 // button is re-enabled. It should be enabled after the lock is removed.
371 pressed_lock1.reset(new MenuButton::PressedLock(button()));
372 EXPECT_EQ(Button::STATE_PRESSED, button()->state());
373 button()->SetState(Button::STATE_NORMAL);
374 pressed_lock1.reset();
375 EXPECT_EQ(Button::STATE_NORMAL, button()->state());
378 // Test that the MenuButton does not become pressed if it can be dragged, until
379 // a release occurs.
380 TEST_F(MenuButtonTest, DraggableMenuButtonActivatesOnRelease) {
381 TestMenuButtonListener menu_button_listener;
382 CreateMenuButtonWithMenuButtonListener(&menu_button_listener);
383 TestDragController drag_controller;
384 button()->set_drag_controller(&drag_controller);
386 ui::test::EventGenerator generator(GetContext(), widget()->GetNativeWindow());
388 generator.set_current_location(gfx::Point(10, 10));
389 generator.PressLeftButton();
390 EXPECT_EQ(nullptr, menu_button_listener.last_source());
392 generator.ReleaseLeftButton();
393 EXPECT_EQ(button(), menu_button_listener.last_source());
394 EXPECT_EQ(Button::STATE_PRESSED, menu_button_listener.last_source_state());
397 #if defined(USE_AURA)
398 // Tests that the MenuButton does not become pressed if it can be dragged, and a
399 // DragDropClient is processing the events.
400 TEST_F(MenuButtonTest, DraggableMenuButtonDoesNotActivateOnDrag) {
401 TestMenuButtonListener menu_button_listener;
402 CreateMenuButtonWithMenuButtonListener(&menu_button_listener);
403 TestDragController drag_controller;
404 button()->set_drag_controller(&drag_controller);
406 TestDragDropClient drag_client;
407 SetDragDropClient(GetContext(), &drag_client);
408 button()->PrependPreTargetHandler(&drag_client);
410 ui::test::EventGenerator generator(GetContext(), widget()->GetNativeWindow());
411 generator.set_current_location(gfx::Point(10, 10));
412 generator.DragMouseBy(10, 0);
413 EXPECT_EQ(nullptr, menu_button_listener.last_source());
414 EXPECT_EQ(Button::STATE_NORMAL, menu_button_listener.last_source_state());
416 #endif
418 // Tests that the button enters a hovered state upon a tap down, before becoming
419 // pressed at activation.
420 TEST_F(MenuButtonTest, TouchFeedbackDuringTap) {
421 TestMenuButtonListener menu_button_listener;
422 CreateMenuButtonWithMenuButtonListener(&menu_button_listener);
423 ui::test::EventGenerator generator(GetContext(), widget()->GetNativeWindow());
424 generator.set_current_location(gfx::Point(10, 10));
425 generator.PressTouch();
426 EXPECT_EQ(Button::STATE_HOVERED, button()->state());
428 generator.ReleaseTouch();
429 EXPECT_EQ(Button::STATE_PRESSED, menu_button_listener.last_source_state());
432 // Tests that a move event that exits the button returns it to the normal state,
433 // and that the button did not activate the listener.
434 TEST_F(MenuButtonTest, TouchFeedbackDuringTapCancel) {
435 TestMenuButtonListener menu_button_listener;
436 CreateMenuButtonWithMenuButtonListener(&menu_button_listener);
437 ui::test::EventGenerator generator(GetContext(), widget()->GetNativeWindow());
438 generator.set_current_location(gfx::Point(10, 10));
439 generator.PressTouch();
440 EXPECT_EQ(Button::STATE_HOVERED, button()->state());
442 generator.MoveTouch(gfx::Point(10, 30));
443 generator.ReleaseTouch();
444 EXPECT_EQ(Button::STATE_NORMAL, button()->state());
445 EXPECT_EQ(nullptr, menu_button_listener.last_source());
448 } // namespace views