GoogleURLTrackerInfoBarDelegate: Initialize uninitialized member in constructor.
[chromium-blink-merge.git] / ui / views / controls / menu / menu_controller_unittest.cc
blob1c98f95bc9c10cfe26db53c654787ff9c35900a3
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/menu/menu_controller.h"
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"
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/test/events_test_utils_x11.h"
23 #elif defined(USE_OZONE)
24 #include "ui/events/event.h"
25 #endif
27 namespace views {
29 namespace {
31 class TestMenuItemView : public MenuItemView {
32 public:
33 TestMenuItemView() : MenuItemView(NULL) {}
34 virtual ~TestMenuItemView() {}
36 private:
37 DISALLOW_COPY_AND_ASSIGN(TestMenuItemView);
40 class TestPlatformEventSource : public ui::PlatformEventSource {
41 public:
42 TestPlatformEventSource() {}
43 virtual ~TestPlatformEventSource() {}
45 uint32_t Dispatch(const ui::PlatformEvent& event) {
46 return DispatchEvent(event);
49 private:
50 DISALLOW_COPY_AND_ASSIGN(TestPlatformEventSource);
53 class TestNullTargeter : public ui::EventTargeter {
54 public:
55 TestNullTargeter() {}
56 virtual ~TestNullTargeter() {}
58 virtual ui::EventTarget* FindTargetForEvent(ui::EventTarget* root,
59 ui::Event* event) OVERRIDE {
60 return NULL;
63 private:
64 DISALLOW_COPY_AND_ASSIGN(TestNullTargeter);
67 class TestDispatcherClient : public aura::client::DispatcherClient {
68 public:
69 TestDispatcherClient() : dispatcher_(NULL) {}
70 virtual ~TestDispatcherClient() {}
72 base::MessagePumpDispatcher* dispatcher() {
73 return dispatcher_;
76 // aura::client::DispatcherClient:
77 virtual void PrepareNestedLoopClosures(
78 base::MessagePumpDispatcher* dispatcher,
79 base::Closure* run_closure,
80 base::Closure* quit_closure) OVERRIDE {
81 scoped_ptr<base::RunLoop> run_loop(new base::RunLoop());
82 *quit_closure = run_loop->QuitClosure();
83 *run_closure = base::Bind(&TestDispatcherClient::RunNestedDispatcher,
84 base::Unretained(this),
85 base::Passed(&run_loop),
86 dispatcher);
89 private:
90 void RunNestedDispatcher(scoped_ptr<base::RunLoop> run_loop,
91 base::MessagePumpDispatcher* dispatcher) {
92 base::AutoReset<base::MessagePumpDispatcher*> reset_dispatcher(&dispatcher_,
93 dispatcher);
94 base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
95 base::MessageLoop::ScopedNestableTaskAllower allow(loop);
96 run_loop->Run();
99 base::MessagePumpDispatcher* dispatcher_;
101 DISALLOW_COPY_AND_ASSIGN(TestDispatcherClient);
104 } // namespace
106 class MenuControllerTest : public ViewsTestBase {
107 public:
108 MenuControllerTest() : controller_(NULL) {}
109 virtual ~MenuControllerTest() {
110 ResetMenuController();
113 // Dispatches |count| number of items, each in a separate iteration of the
114 // message-loop, by posting a task.
115 void Step3_DispatchEvents(int count) {
116 base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
117 base::MessageLoop::ScopedNestableTaskAllower allow(loop);
118 controller_->exit_type_ = MenuController::EXIT_ALL;
120 DispatchEvent();
121 if (count) {
122 base::MessageLoop::current()->PostTask(
123 FROM_HERE,
124 base::Bind(&MenuControllerTest::Step3_DispatchEvents,
125 base::Unretained(this),
126 count - 1));
127 } else {
128 EXPECT_TRUE(run_loop_->running());
129 run_loop_->Quit();
133 // Runs a nested message-loop that does not involve the menu itself.
134 void Step2_RunNestedLoop() {
135 base::MessageLoopForUI* loop = base::MessageLoopForUI::current();
136 base::MessageLoop::ScopedNestableTaskAllower allow(loop);
137 base::MessageLoop::current()->PostTask(
138 FROM_HERE,
139 base::Bind(&MenuControllerTest::Step3_DispatchEvents,
140 base::Unretained(this),
141 3));
142 run_loop_.reset(new base::RunLoop());
143 run_loop_->Run();
146 void Step1_RunMenu() {
147 base::MessageLoop::current()->PostTask(
148 FROM_HERE,
149 base::Bind(&MenuControllerTest::Step2_RunNestedLoop,
150 base::Unretained(this)));
151 scoped_ptr<Widget> owner(CreateOwnerWidget());
152 RunMenu(owner.get());
155 scoped_ptr<Widget> CreateOwnerWidget() {
156 scoped_ptr<Widget> widget(new Widget);
157 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
158 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
159 widget->Init(params);
160 widget->Show();
162 aura::client::SetDispatcherClient(
163 widget->GetNativeWindow()->GetRootWindow(), &dispatcher_client_);
164 return widget.Pass();
167 void RunMenu(views::Widget* owner) {
168 scoped_ptr<TestMenuItemView> menu_item(new TestMenuItemView);
169 ResetMenuController();
170 controller_ = new MenuController(NULL, true, NULL);
171 controller_->owner_ = owner;
172 controller_->showing_ = true;
173 controller_->SetSelection(menu_item.get(),
174 MenuController::SELECTION_UPDATE_IMMEDIATELY);
175 controller_->RunMessageLoop(false);
178 #if defined(USE_X11)
179 void DispatchEscapeAndExpect(MenuController::ExitType exit_type) {
180 ui::ScopedXI2Event key_event;
181 key_event.InitKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_ESCAPE, 0);
182 event_source_.Dispatch(key_event);
183 EXPECT_EQ(exit_type, controller_->exit_type());
184 controller_->exit_type_ = MenuController::EXIT_ALL;
185 DispatchEvent();
187 #endif
189 void DispatchEvent() {
190 #if defined(USE_X11)
191 XEvent xevent;
192 memset(&xevent, 0, sizeof(xevent));
193 event_source_.Dispatch(&xevent);
194 #elif defined(OS_WIN)
195 MSG msg;
196 memset(&msg, 0, sizeof(MSG));
197 dispatcher_client_.dispatcher()->Dispatch(msg);
198 #elif defined(USE_OZONE)
199 ui::KeyEvent event(ui::ET_KEY_PRESSED, ui::VKEY_SPACE, 0, true);
200 dispatcher_client_.dispatcher()->Dispatch(&event);
201 #else
202 #error Unsupported platform
203 #endif
206 private:
207 void ResetMenuController() {
208 if (controller_) {
209 // These properties are faked by RunMenu for the purposes of testing and
210 // need to be undone before we call the destructor.
211 controller_->owner_ = NULL;
212 controller_->showing_ = false;
213 delete controller_;
214 controller_ = NULL;
218 // A weak pointer to the MenuController owned by this class.
219 MenuController* controller_;
220 scoped_ptr<base::RunLoop> run_loop_;
221 TestPlatformEventSource event_source_;
222 TestDispatcherClient dispatcher_client_;
224 DISALLOW_COPY_AND_ASSIGN(MenuControllerTest);
227 TEST_F(MenuControllerTest, Basic) {
228 base::MessageLoop::ScopedNestableTaskAllower allow_nested(
229 base::MessageLoop::current());
230 message_loop()->PostTask(
231 FROM_HERE,
232 base::Bind(&MenuControllerTest::Step1_RunMenu, base::Unretained(this)));
235 #if defined(OS_LINUX) && defined(USE_X11)
236 // Tests that an event targeter which blocks events will be honored by the menu
237 // event dispatcher.
238 TEST_F(MenuControllerTest, EventTargeter) {
240 // Verify that the menu handles the escape key under normal circumstances.
241 scoped_ptr<Widget> owner(CreateOwnerWidget());
242 message_loop()->PostTask(
243 FROM_HERE,
244 base::Bind(&MenuControllerTest::DispatchEscapeAndExpect,
245 base::Unretained(this),
246 MenuController::EXIT_OUTERMOST));
247 RunMenu(owner.get());
251 // With the NULL targeter instantiated and assigned we expect the menu to
252 // not handle the key event.
253 scoped_ptr<Widget> owner(CreateOwnerWidget());
254 aura::ScopedWindowTargeter scoped_targeter(
255 owner->GetNativeWindow()->GetRootWindow(),
256 scoped_ptr<ui::EventTargeter>(new TestNullTargeter));
257 message_loop()->PostTask(
258 FROM_HERE,
259 base::Bind(&MenuControllerTest::DispatchEscapeAndExpect,
260 base::Unretained(this),
261 MenuController::EXIT_NONE));
262 RunMenu(owner.get());
265 #endif
267 } // namespace views