Chromium Code Reviews| Index: ui/views/controls/menu/menu_controller_unittest.cc |
| diff --git a/ui/views/controls/menu/menu_controller_unittest.cc b/ui/views/controls/menu/menu_controller_unittest.cc |
| index 7aa23a317f5567796374d48308f376f97ab516ae..a645714182c538bbecad5122ae435433df1f1fd6 100644 |
| --- a/ui/views/controls/menu/menu_controller_unittest.cc |
| +++ b/ui/views/controls/menu/menu_controller_unittest.cc |
| @@ -5,8 +5,11 @@ |
| #include "ui/views/controls/menu/menu_controller.h" |
| #include "base/run_loop.h" |
| +#include "ui/aura/scoped_window_targeter.h" |
| #include "ui/aura/window.h" |
| +#include "ui/events/event_targeter.h" |
| #include "ui/events/platform/platform_event_source.h" |
| +#include "ui/views/controls/menu/menu_item_view.h" |
| #include "ui/views/test/views_test_base.h" |
| #include "ui/wm/public/dispatcher_client.h" |
| @@ -16,12 +19,22 @@ |
| #include <X11/Xlib.h> |
| #undef Bool |
| #undef None |
| +#include "ui/events/test/events_test_utils_x11.h" |
| #endif |
| namespace views { |
| namespace { |
| +class TestMenuItemView : public MenuItemView { |
| + public: |
| + TestMenuItemView() : MenuItemView(NULL) {} |
| + virtual ~TestMenuItemView() {} |
| + |
| + private: |
| + DISALLOW_COPY_AND_ASSIGN(TestMenuItemView); |
| +}; |
| + |
| class TestPlatformEventSource : public ui::PlatformEventSource { |
| public: |
| TestPlatformEventSource() {} |
| @@ -35,6 +48,20 @@ class TestPlatformEventSource : public ui::PlatformEventSource { |
| DISALLOW_COPY_AND_ASSIGN(TestPlatformEventSource); |
| }; |
| +class TestNullTargeter : public ui::EventTargeter { |
| + public: |
| + TestNullTargeter() {} |
| + virtual ~TestNullTargeter() {} |
| + |
| + virtual ui::EventTarget* FindTargetForEvent(ui::EventTarget* root, |
| + ui::Event* event) OVERRIDE { |
| + return NULL; |
| + } |
| + |
| + private: |
| + DISALLOW_COPY_AND_ASSIGN(TestNullTargeter); |
| +}; |
| + |
| class TestDispatcherClient : public aura::client::DispatcherClient { |
| public: |
| TestDispatcherClient() : dispatcher_(NULL) {} |
| @@ -70,7 +97,9 @@ class TestDispatcherClient : public aura::client::DispatcherClient { |
| class MenuControllerTest : public ViewsTestBase { |
| public: |
| MenuControllerTest() : controller_(NULL) {} |
| - virtual ~MenuControllerTest() {} |
| + virtual ~MenuControllerTest() { |
| + ResetMenuController(); |
| + } |
| // Dispatches |count| number of items, each in a separate iteration of the |
| // message-loop, by posting a task. |
| @@ -79,16 +108,7 @@ class MenuControllerTest : public ViewsTestBase { |
| base::MessageLoop::ScopedNestableTaskAllower allow(loop); |
| controller_->exit_type_ = MenuController::EXIT_ALL; |
| -#if defined(USE_X11) |
| - XEvent xevent; |
| - memset(&xevent, 0, sizeof(xevent)); |
| - event_source_.Dispatch(&xevent); |
| -#else |
| - MSG msg; |
| - memset(&msg, 0, sizeof(MSG)); |
| - dispatcher_client_.dispatcher()->Dispatch(msg); |
| -#endif |
| - |
| + DispatchEvent(); |
| if (count) { |
| base::MessageLoop::current()->PostTask( |
| FROM_HERE, |
| @@ -115,25 +135,73 @@ class MenuControllerTest : public ViewsTestBase { |
| } |
| void Step1_RunMenu() { |
| - Widget widget; |
| + base::MessageLoop::current()->PostTask( |
| + FROM_HERE, |
| + base::Bind(&MenuControllerTest::Step2_RunNestedLoop, |
| + base::Unretained(this))); |
| + scoped_ptr<Widget> owner(CreateOwnerWidget()); |
| + RunMenu(owner.get()); |
| + } |
| + |
| + scoped_ptr<Widget> CreateOwnerWidget() { |
| + scoped_ptr<Widget> widget(new Widget); |
| Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); |
| params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; |
| - widget.Init(params); |
| - widget.Show(); |
| + widget->Init(params); |
| + widget->Show(); |
| - aura::client::SetDispatcherClient(widget.GetNativeWindow()->GetRootWindow(), |
| - &dispatcher_client_); |
| + aura::client::SetDispatcherClient( |
| + widget->GetNativeWindow()->GetRootWindow(), &dispatcher_client_); |
| + return widget.Pass(); |
| + } |
| + void RunMenu(views::Widget* owner) { |
| + scoped_ptr<TestMenuItemView> menu_item(new TestMenuItemView); |
| + ResetMenuController(); |
| controller_ = new MenuController(NULL, true, NULL); |
| - controller_->owner_ = &widget; |
| - base::MessageLoop::current()->PostTask( |
| - FROM_HERE, |
| - base::Bind(&MenuControllerTest::Step2_RunNestedLoop, |
| - base::Unretained(this))); |
| + controller_->owner_ = owner; |
| + controller_->showing_ = true; |
| + controller_->SetSelection(menu_item.get(), |
| + MenuController::SELECTION_UPDATE_IMMEDIATELY); |
| controller_->RunMessageLoop(false); |
| } |
| +#if defined(USE_X11) |
| + void DispatchEscapeAndExpect(MenuController::ExitType exit_type) { |
| + ui::ScopedXI2Event key_event; |
| + key_event.InitKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_ESCAPE, 0); |
| + event_source_.Dispatch(key_event); |
| + EXPECT_EQ(exit_type, controller_->exit_type()); |
| + controller_->exit_type_ = MenuController::EXIT_ALL; |
| + DispatchEvent(); |
| + } |
| +#endif |
| + |
| + void DispatchEvent() { |
| +#if defined(USE_X11) |
| + XEvent xevent; |
| + memset(&xevent, 0, sizeof(xevent)); |
| + event_source_.Dispatch(&xevent); |
| +#else |
| + MSG msg; |
| + memset(&msg, 0, sizeof(MSG)); |
| + dispatcher_client_.dispatcher()->Dispatch(msg); |
| +#endif |
| + } |
| + |
| private: |
| + void ResetMenuController() { |
| + if (controller_) { |
| + // These properties are faked by RunMenu for the purposes of testing and |
| + // need to be undone before we call the destructor. |
| + controller_->owner_ = NULL; |
| + controller_->showing_ = false; |
| + delete controller_; |
| + controller_ = NULL; |
| + } |
| + } |
| + |
| + // A weak pointer to the MenuController owned by this class. |
| MenuController* controller_; |
|
sadrul
2014/05/20 19:55:45
Does it make sense to just have this as scoped_ptr
flackr
2014/05/20 20:33:41
It will fail to destruct unless we reset the owner
|
| scoped_ptr<base::RunLoop> run_loop_; |
| TestPlatformEventSource event_source_; |
| @@ -150,4 +218,36 @@ TEST_F(MenuControllerTest, Basic) { |
| base::Bind(&MenuControllerTest::Step1_RunMenu, base::Unretained(this))); |
| } |
| +#if defined(OS_LINUX) && defined(USE_X11) |
| +// Tests that an event targeter which blocks events will be honored by the menu |
| +// event dispatcher. |
| +TEST_F(MenuControllerTest, EventTargeter) { |
| + { |
| + // Verify that the menu handles the escape key under normal circumstances. |
| + scoped_ptr<Widget> owner(CreateOwnerWidget()); |
| + message_loop()->PostTask( |
| + FROM_HERE, |
| + base::Bind(&MenuControllerTest::DispatchEscapeAndExpect, |
| + base::Unretained(this), |
| + MenuController::EXIT_OUTERMOST)); |
| + RunMenu(owner.get()); |
| + } |
| + |
| + { |
| + // With the NULL targeter instantiated and assigned we expect the menu to |
| + // not handle the key event. |
| + scoped_ptr<Widget> owner(CreateOwnerWidget()); |
| + aura::ScopedWindowTargeter scoped_targeter( |
| + owner->GetNativeWindow()->GetRootWindow(), |
| + scoped_ptr<ui::EventTargeter>(new TestNullTargeter)); |
| + message_loop()->PostTask( |
| + FROM_HERE, |
| + base::Bind(&MenuControllerTest::DispatchEscapeAndExpect, |
| + base::Unretained(this), |
| + MenuController::EXIT_NONE)); |
| + RunMenu(owner.get()); |
| + } |
| +} |
| +#endif |
| + |
| } // namespace views |