Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / ui / views / controls / menu / menu_controller_unittest.cc
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/menu/menu_controller.h"
6
7 #include "base/run_loop.h"
8 #include "ui/aura/scoped_window_targeter.h"
9 #include "ui/aura/window.h"
10 #include "ui/events/event_targeter.h"
11 #include "ui/events/platform/platform_event_source.h"
12 #include "ui/views/controls/menu/menu_item_view.h"
13 #include "ui/views/test/views_test_base.h"
14 #include "ui/wm/public/dispatcher_client.h"
15
16 #if defined(OS_WIN)
17 #include "base/message_loop/message_pump_dispatcher.h"
18 #elif defined(USE_X11)
19 #include <X11/Xlib.h>
20 #undef Bool
21 #undef None
22 #include "ui/events/devices/x11/device_data_manager_x11.h"
23 #include "ui/events/test/events_test_utils_x11.h"
24 #elif defined(USE_OZONE)
25 #include "ui/events/event.h"
26 #endif
27
28 namespace views {
29
30 namespace {
31
32 class TestMenuItemView : public MenuItemView {
33  public:
34   TestMenuItemView() : MenuItemView(NULL) {}
35   ~TestMenuItemView() override {}
36
37  private:
38   DISALLOW_COPY_AND_ASSIGN(TestMenuItemView);
39 };
40
41 class TestPlatformEventSource : public ui::PlatformEventSource {
42  public:
43   TestPlatformEventSource() {
44 #if defined(USE_X11)
45     ui::DeviceDataManagerX11::CreateInstance();
46 #endif
47   }
48   ~TestPlatformEventSource() override {}
49
50   uint32_t Dispatch(const ui::PlatformEvent& event) {
51     return DispatchEvent(event);
52   }
53
54  private:
55   DISALLOW_COPY_AND_ASSIGN(TestPlatformEventSource);
56 };
57
58 class TestNullTargeter : public ui::EventTargeter {
59  public:
60   TestNullTargeter() {}
61   ~TestNullTargeter() override {}
62
63   ui::EventTarget* FindTargetForEvent(ui::EventTarget* root,
64                                       ui::Event* event) override {
65     return NULL;
66   }
67
68  private:
69   DISALLOW_COPY_AND_ASSIGN(TestNullTargeter);
70 };
71
72 class TestDispatcherClient : public aura::client::DispatcherClient {
73  public:
74   TestDispatcherClient() : dispatcher_(NULL) {}
75   ~TestDispatcherClient() override {}
76
77   base::MessagePumpDispatcher* dispatcher() {
78     return dispatcher_;
79   }
80
81   // aura::client::DispatcherClient:
82   void PrepareNestedLoopClosures(base::MessagePumpDispatcher* dispatcher,
83                                  base::Closure* run_closure,
84                                  base::Closure* quit_closure) override {
85     scoped_ptr<base::RunLoop> run_loop(new base::RunLoop());
86     *quit_closure = run_loop->QuitClosure();
87     *run_closure = base::Bind(&TestDispatcherClient::RunNestedDispatcher,
88                               base::Unretained(this),
89                               base::Passed(&run_loop),
90                               dispatcher);
91   }
92
93  private:
94   void RunNestedDispatcher(scoped_ptr<base::RunLoop> run_loop,
95                            base::MessagePumpDispatcher* dispatcher) {
96     base::AutoReset<base::MessagePumpDispatcher*> reset_dispatcher(&dispatcher_,
97                                                                    dispatcher);
98     base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
99     base::MessageLoop::ScopedNestableTaskAllower allow(loop);
100     run_loop->Run();
101   }
102
103   base::MessagePumpDispatcher* dispatcher_;
104
105   DISALLOW_COPY_AND_ASSIGN(TestDispatcherClient);
106 };
107
108 }  // namespace
109
110 class MenuControllerTest : public ViewsTestBase {
111  public:
112   MenuControllerTest() : controller_(NULL) {}
113   ~MenuControllerTest() override { ResetMenuController(); }
114
115   // Dispatches |count| number of items, each in a separate iteration of the
116   // message-loop, by posting a task.
117   void Step3_DispatchEvents(int count) {
118     base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
119     base::MessageLoop::ScopedNestableTaskAllower allow(loop);
120     controller_->exit_type_ = MenuController::EXIT_ALL;
121
122     DispatchEvent();
123     if (count) {
124       base::MessageLoop::current()->PostTask(
125           FROM_HERE,
126           base::Bind(&MenuControllerTest::Step3_DispatchEvents,
127                      base::Unretained(this),
128                      count - 1));
129     } else {
130       EXPECT_TRUE(run_loop_->running());
131       run_loop_->Quit();
132     }
133   }
134
135   // Runs a nested message-loop that does not involve the menu itself.
136   void Step2_RunNestedLoop() {
137     base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
138     base::MessageLoop::ScopedNestableTaskAllower allow(loop);
139     base::MessageLoop::current()->PostTask(
140         FROM_HERE,
141         base::Bind(&MenuControllerTest::Step3_DispatchEvents,
142                    base::Unretained(this),
143                    3));
144     run_loop_.reset(new base::RunLoop());
145     run_loop_->Run();
146   }
147
148   void Step1_RunMenu() {
149     base::MessageLoop::current()->PostTask(
150         FROM_HERE,
151         base::Bind(&MenuControllerTest::Step2_RunNestedLoop,
152                    base::Unretained(this)));
153     scoped_ptr<Widget> owner(CreateOwnerWidget());
154     RunMenu(owner.get());
155   }
156
157   scoped_ptr<Widget> CreateOwnerWidget() {
158     scoped_ptr<Widget> widget(new Widget);
159     Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
160     params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
161     widget->Init(params);
162     widget->Show();
163
164     aura::client::SetDispatcherClient(
165         widget->GetNativeWindow()->GetRootWindow(), &dispatcher_client_);
166     return widget.Pass();
167   }
168
169   void RunMenu(views::Widget* owner) {
170     scoped_ptr<TestMenuItemView> menu_item(new TestMenuItemView);
171     ResetMenuController();
172     controller_ = new MenuController(NULL, true, NULL);
173     controller_->owner_ = owner;
174     controller_->showing_ = true;
175     controller_->SetSelection(menu_item.get(),
176                               MenuController::SELECTION_UPDATE_IMMEDIATELY);
177     controller_->RunMessageLoop(false);
178   }
179
180 #if defined(USE_X11)
181   void DispatchEscapeAndExpect(MenuController::ExitType exit_type) {
182     ui::ScopedXI2Event key_event;
183     key_event.InitKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_ESCAPE, 0);
184     event_source_.Dispatch(key_event);
185     EXPECT_EQ(exit_type, controller_->exit_type());
186     controller_->exit_type_ = MenuController::EXIT_ALL;
187     DispatchEvent();
188   }
189 #endif
190
191   void DispatchEvent() {
192 #if defined(USE_X11)
193     XEvent xevent;
194     memset(&xevent, 0, sizeof(xevent));
195     event_source_.Dispatch(&xevent);
196 #elif defined(OS_WIN)
197     MSG msg;
198     memset(&msg, 0, sizeof(MSG));
199     dispatcher_client_.dispatcher()->Dispatch(msg);
200 #elif defined(USE_OZONE)
201     ui::KeyEvent event(' ', ui::VKEY_SPACE, ui::EF_NONE);
202     event_source_.Dispatch(&event);
203 #else
204 #error Unsupported platform
205 #endif
206   }
207
208  private:
209   void ResetMenuController() {
210     if (controller_) {
211       // These properties are faked by RunMenu for the purposes of testing and
212       // need to be undone before we call the destructor.
213       controller_->owner_ = NULL;
214       controller_->showing_ = false;
215       delete controller_;
216       controller_ = NULL;
217     }
218   }
219
220   // A weak pointer to the MenuController owned by this class.
221   MenuController* controller_;
222   scoped_ptr<base::RunLoop> run_loop_;
223   TestPlatformEventSource event_source_;
224   TestDispatcherClient dispatcher_client_;
225
226   DISALLOW_COPY_AND_ASSIGN(MenuControllerTest);
227 };
228
229 TEST_F(MenuControllerTest, Basic) {
230   base::MessageLoop::ScopedNestableTaskAllower allow_nested(
231       base::MessageLoop::current());
232   message_loop()->PostTask(
233       FROM_HERE,
234       base::Bind(&MenuControllerTest::Step1_RunMenu, base::Unretained(this)));
235 }
236
237 #if defined(OS_LINUX) && defined(USE_X11)
238 // Tests that an event targeter which blocks events will be honored by the menu
239 // event dispatcher.
240 TEST_F(MenuControllerTest, EventTargeter) {
241   {
242     // Verify that the menu handles the escape key under normal circumstances.
243     scoped_ptr<Widget> owner(CreateOwnerWidget());
244     message_loop()->PostTask(
245         FROM_HERE,
246         base::Bind(&MenuControllerTest::DispatchEscapeAndExpect,
247                    base::Unretained(this),
248                    MenuController::EXIT_OUTERMOST));
249     RunMenu(owner.get());
250   }
251
252   {
253     // With the NULL targeter instantiated and assigned we expect the menu to
254     // not handle the key event.
255     scoped_ptr<Widget> owner(CreateOwnerWidget());
256     aura::ScopedWindowTargeter scoped_targeter(
257         owner->GetNativeWindow()->GetRootWindow(),
258         scoped_ptr<ui::EventTargeter>(new TestNullTargeter));
259     message_loop()->PostTask(
260         FROM_HERE,
261         base::Bind(&MenuControllerTest::DispatchEscapeAndExpect,
262                    base::Unretained(this),
263                    MenuController::EXIT_NONE));
264     RunMenu(owner.get());
265   }
266 }
267 #endif
268
269 }  // namespace views