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 3b29d7bc1b4ee2cf40a7da00199d083675f09e54..786b158d2c6127abca20f6460a127c9a0e323c56 100644 |
--- a/ui/views/controls/menu/menu_controller_unittest.cc |
+++ b/ui/views/controls/menu/menu_controller_unittest.cc |
@@ -4,28 +4,22 @@ |
#include "ui/views/controls/menu/menu_controller.h" |
-#include "base/run_loop.h" |
#include "base/strings/utf_string_conversions.h" |
#include "ui/aura/scoped_window_targeter.h" |
#include "ui/aura/window.h" |
#include "ui/events/event_handler.h" |
#include "ui/events/null_event_targeter.h" |
-#include "ui/events/platform/platform_event_source.h" |
+#include "ui/events/test/event_generator.h" |
#include "ui/views/controls/menu/menu_item_view.h" |
#include "ui/views/controls/menu/submenu_view.h" |
#include "ui/views/test/views_test_base.h" |
-#include "ui/wm/public/dispatcher_client.h" |
-#if defined(OS_WIN) |
-#include "base/message_loop/message_pump_dispatcher.h" |
-#elif defined(USE_X11) |
+#if defined(USE_X11) |
#include <X11/Xlib.h> |
#undef Bool |
#undef None |
#include "ui/events/devices/x11/device_data_manager_x11.h" |
#include "ui/events/test/events_test_utils_x11.h" |
-#elif defined(USE_OZONE) |
-#include "ui/events/event.h" |
#endif |
namespace views { |
@@ -41,357 +35,241 @@ class TestMenuItemView : public MenuItemView { |
DISALLOW_COPY_AND_ASSIGN(TestMenuItemView); |
}; |
-class TestPlatformEventSource : public ui::PlatformEventSource { |
- public: |
- TestPlatformEventSource() { |
-#if defined(USE_X11) |
- ui::DeviceDataManagerX11::CreateInstance(); |
-#endif |
- } |
- ~TestPlatformEventSource() override {} |
- |
- uint32_t Dispatch(const ui::PlatformEvent& event) { |
- return DispatchEvent(event); |
- } |
- |
- private: |
- DISALLOW_COPY_AND_ASSIGN(TestPlatformEventSource); |
-}; |
- |
-class TestDispatcherClient : public aura::client::DispatcherClient { |
+class TestEventHandler : public ui::EventHandler { |
public: |
- TestDispatcherClient() : dispatcher_(nullptr) {} |
- ~TestDispatcherClient() override {} |
+ TestEventHandler() : outstanding_touches_(0) {} |
- base::MessagePumpDispatcher* dispatcher() { |
- return dispatcher_; |
+ void OnTouchEvent(ui::TouchEvent* event) override { |
+ switch(event->type()) { |
+ case ui::ET_TOUCH_PRESSED: |
+ outstanding_touches_++; |
+ break; |
+ case ui::ET_TOUCH_RELEASED: |
+ case ui::ET_TOUCH_CANCELLED: |
+ outstanding_touches_--; |
+ break; |
+ default: |
+ break; |
+ } |
} |
- // aura::client::DispatcherClient: |
- void PrepareNestedLoopClosures(base::MessagePumpDispatcher* dispatcher, |
- base::Closure* run_closure, |
- base::Closure* quit_closure) override { |
- scoped_ptr<base::RunLoop> run_loop(new base::RunLoop()); |
- *quit_closure = run_loop->QuitClosure(); |
- *run_closure = base::Bind(&TestDispatcherClient::RunNestedDispatcher, |
- base::Unretained(this), |
- base::Passed(&run_loop), |
- dispatcher); |
- } |
+ int outstanding_touches() const { return outstanding_touches_; } |
private: |
- void RunNestedDispatcher(scoped_ptr<base::RunLoop> run_loop, |
- base::MessagePumpDispatcher* dispatcher) { |
- base::AutoReset<base::MessagePumpDispatcher*> reset_dispatcher(&dispatcher_, |
- dispatcher); |
- base::MessageLoopForUI* loop = base::MessageLoopForUI::current(); |
- base::MessageLoop::ScopedNestableTaskAllower allow(loop); |
- run_loop->Run(); |
- } |
- |
- base::MessagePumpDispatcher* dispatcher_; |
- |
- DISALLOW_COPY_AND_ASSIGN(TestDispatcherClient); |
+ int outstanding_touches_; |
}; |
} // namespace |
class MenuControllerTest : public ViewsTestBase { |
public: |
- MenuControllerTest() : controller_(nullptr) {} |
- ~MenuControllerTest() override { ResetMenuController(); } |
- |
- // Dispatches |count| number of items, each in a separate iteration of the |
- // message-loop, by posting a task. |
- void Step3_DispatchEvents(int count) { |
- base::MessageLoopForUI* loop = base::MessageLoopForUI::current(); |
- base::MessageLoop::ScopedNestableTaskAllower allow(loop); |
- controller_->exit_type_ = MenuController::EXIT_ALL; |
- |
- DispatchEvent(); |
- if (count) { |
- base::MessageLoop::current()->PostTask( |
- FROM_HERE, |
- base::Bind(&MenuControllerTest::Step3_DispatchEvents, |
- base::Unretained(this), |
- count - 1)); |
- } else { |
- EXPECT_TRUE(run_loop_->running()); |
- run_loop_->Quit(); |
- } |
+ MenuControllerTest() |
+ : owner_(), |
+ event_generator_(), |
+ menu_item_(), |
oshima
2015/06/12 19:59:18
you can skip these
afakhry
2015/06/12 23:50:46
I know but I always like to be explicit .. however
|
+ menu_controller_(nullptr) { |
} |
- // Runs a nested message-loop that does not involve the menu itself. |
- void Step2_RunNestedLoop() { |
- base::MessageLoopForUI* loop = base::MessageLoopForUI::current(); |
- base::MessageLoop::ScopedNestableTaskAllower allow(loop); |
- base::MessageLoop::current()->PostTask( |
- FROM_HERE, |
- base::Bind(&MenuControllerTest::Step3_DispatchEvents, |
- base::Unretained(this), |
- 3)); |
- run_loop_.reset(new base::RunLoop()); |
- run_loop_->Run(); |
+ ~MenuControllerTest() override {} |
+ |
+ void SetUp() override { |
+ ViewsTestBase::SetUp(); |
+ Init(); |
} |
- void Step1_RunMenu() { |
- base::MessageLoop::current()->PostTask( |
- FROM_HERE, |
- base::Bind(&MenuControllerTest::Step2_RunNestedLoop, |
- base::Unretained(this))); |
- scoped_ptr<Widget> owner(CreateOwnerWidget()); |
- RunMenu(owner.get()); |
+ void TearDown() override { |
+ if (menu_controller_) { |
+ menu_controller_->owner_ = nullptr; |
+ menu_controller_->showing_ = false; |
oshima
2015/06/12 19:59:18
do you need these?
afakhry
2015/06/12 23:50:46
Yes the destructor will crash on a DCHECK() if |sh
|
+ delete menu_controller_; |
+ menu_controller_ = nullptr; |
oshima
2015/06/12 19:59:18
any reason why we shouldn't use scoped_ptr for thi
afakhry
2015/06/12 23:50:46
Done. Using a scoped_ptr with a specialized Delete
|
+ } |
+ |
+ ViewsTestBase::TearDown(); |
} |
- 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(); |
+ void ReleaseTouchId(int id) { |
+ event_generator_->ReleaseTouchId(id); |
+ } |
- aura::client::SetDispatcherClient( |
- widget->GetNativeWindow()->GetRootWindow(), &dispatcher_client_); |
- return widget.Pass(); |
+ void PressKey(ui::KeyboardCode key_code) { |
+ event_generator_->PressKey(key_code, 0); |
} |
- const MenuItemView* pending_state_item() const { |
- return controller_->pending_state_.item; |
+ void TestEventTargeter() { |
+ // With the NULL targeter instantiated and assigned we expect the menu to |
oshima
2015/06/12 19:59:18
nullptr
afakhry
2015/06/12 23:50:46
Actually NULL here refers to the ui::NullEventTarg
|
+ // not handle the key event. |
+ scoped_ptr<aura::ScopedWindowTargeter> scoped_targeter( |
+ new aura::ScopedWindowTargeter( |
+ owner()->GetNativeWindow()->GetRootWindow(), |
+ scoped_ptr<ui::EventTargeter>(new ui::NullEventTargeter))); |
+ event_generator_->PressKey(ui::VKEY_ESCAPE, 0); |
+ EXPECT_EQ(MenuController::EXIT_NONE, menu_exit_type()); |
+ |
+ // Now remove the targeter an expect to exit the menu normally. |
+ scoped_targeter.reset(); |
+ event_generator_->PressKey(ui::VKEY_ESCAPE, 0); |
+ EXPECT_EQ(MenuController::EXIT_OUTERMOST, menu_exit_type()); |
} |
+ protected: |
void SetPendingStateItem(MenuItemView* item) { |
- controller_->pending_state_.item = item; |
+ menu_controller_->pending_state_.item = item; |
} |
void ResetSelection() { |
- controller_->SetSelection(nullptr, |
- MenuController::SELECTION_EXIT | |
- MenuController::SELECTION_UPDATE_IMMEDIATELY); |
+ menu_controller_->SetSelection( |
+ nullptr, |
+ MenuController::SELECTION_EXIT | |
+ MenuController::SELECTION_UPDATE_IMMEDIATELY); |
} |
void IncrementSelection(int delta) { |
- controller_->IncrementSelection(delta); |
+ menu_controller_->IncrementSelection(delta); |
} |
MenuItemView* FindFirstSelectableMenuItem(MenuItemView* parent) { |
- return controller_->FindFirstSelectableMenuItem(parent); |
+ return menu_controller_->FindFirstSelectableMenuItem(parent); |
} |
MenuItemView* FindNextSelectableMenuItem(MenuItemView* parent, |
int index, |
int delta) { |
- return controller_->FindNextSelectableMenuItem(parent, index, delta); |
- } |
- void SetupMenu(views::Widget* owner, views::MenuItemView* item) { |
- ResetMenuController(); |
- controller_ = new MenuController(nullptr, true, nullptr); |
- controller_->owner_ = owner; |
- controller_->showing_ = true; |
- controller_->SetSelection(item, |
- MenuController::SELECTION_UPDATE_IMMEDIATELY); |
+ |
+ return menu_controller_->FindNextSelectableMenuItem(parent, index, delta); |
} |
- void RunMenu(views::Widget* owner) { |
- scoped_ptr<TestMenuItemView> menu_item(new TestMenuItemView); |
- SetupMenu(owner, menu_item.get()); |
- controller_->RunMessageLoop(false); |
+ void RunMenu() { |
+ menu_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(); |
+ Widget* owner() { return owner_.get(); } |
+ ui::test::EventGenerator* event_generator() { return event_generator_.get(); } |
+ TestMenuItemView* menu_item() { return menu_item_.get(); } |
+ MenuController* menu_controller() { return menu_controller_; } |
+ const MenuItemView* pending_state_item() const { |
+ return menu_controller_->pending_state_.item; |
} |
+ const MenuController::ExitType menu_exit_type() const { |
+ return menu_controller_->exit_type_; |
+ } |
+ |
+ private: |
+ void Init() { |
+ owner_.reset(new Widget); |
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); |
+ params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; |
+ owner_->Init(params); |
+ event_generator_.reset(new ui::test::EventGenerator( |
+ owner_->GetNativeWindow()->GetRootWindow(), owner_->GetNativeWindow())); |
+ owner_->Show(); |
- void DispatchTouch(int evtype, int id) { |
- ui::ScopedXI2Event touch_event; |
- std::vector<ui::Valuator> valuators; |
- touch_event.InitTouchEvent(1, evtype, id, gfx::Point(10, 10), valuators); |
- event_source_.Dispatch(touch_event); |
- DispatchEvent(); |
+ SetupMenuItem(); |
+ |
+ SetupMenuController(); |
} |
-#endif |
- void DispatchEvent() { |
-#if defined(USE_X11) |
- XEvent xevent; |
- memset(&xevent, 0, sizeof(xevent)); |
- event_source_.Dispatch(&xevent); |
-#elif defined(OS_WIN) |
- MSG msg; |
- memset(&msg, 0, sizeof(MSG)); |
- dispatcher_client_.dispatcher()->Dispatch(msg); |
-#elif defined(USE_OZONE) |
- ui::KeyEvent event(' ', ui::VKEY_SPACE, ui::EF_NONE); |
- event_source_.Dispatch(&event); |
-#else |
-#error Unsupported platform |
-#endif |
+ void SetupMenuItem() { |
+ menu_item_.reset(new TestMenuItemView); |
+ menu_item_->AppendMenuItemWithLabel(1, base::ASCIIToUTF16("One")); |
+ menu_item_->AppendMenuItemWithLabel(2, base::ASCIIToUTF16("Two")); |
+ menu_item_->AppendMenuItemWithLabel(3, base::ASCIIToUTF16("Three")); |
+ menu_item_->AppendMenuItemWithLabel(4, base::ASCIIToUTF16("Four")); |
} |
- 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_ = nullptr; |
- controller_->showing_ = false; |
- delete controller_; |
- controller_ = nullptr; |
- } |
+ void SetupMenuController() { |
+ menu_controller_ = new MenuController(nullptr, true, nullptr); |
+ menu_controller_->owner_ = owner_.get(); |
+ menu_controller_->showing_ = true; |
+ menu_controller_->SetSelection( |
+ menu_item_.get(), MenuController::SELECTION_UPDATE_IMMEDIATELY); |
} |
- // A weak pointer to the MenuController owned by this class. |
- MenuController* controller_; |
- scoped_ptr<base::RunLoop> run_loop_; |
- TestPlatformEventSource event_source_; |
- TestDispatcherClient dispatcher_client_; |
+ scoped_ptr<Widget> owner_; |
+ scoped_ptr<ui::test::EventGenerator> event_generator_; |
+ scoped_ptr<TestMenuItemView> menu_item_; |
+ MenuController* menu_controller_; |
DISALLOW_COPY_AND_ASSIGN(MenuControllerTest); |
}; |
-TEST_F(MenuControllerTest, Basic) { |
- base::MessageLoop::ScopedNestableTaskAllower allow_nested( |
- base::MessageLoop::current()); |
- message_loop()->PostTask( |
- FROM_HERE, |
- 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 ui::NullEventTargeter)); |
- message_loop()->PostTask( |
- FROM_HERE, |
- base::Bind(&MenuControllerTest::DispatchEscapeAndExpect, |
- base::Unretained(this), |
- MenuController::EXIT_NONE)); |
- RunMenu(owner.get()); |
- } |
+ base::MessageLoopForUI::current()->PostTask( |
+ FROM_HERE, |
+ base::Bind(&MenuControllerTest::TestEventTargeter, |
+ base::Unretained(this))); |
+ RunMenu(); |
} |
-#endif |
#if defined(USE_X11) |
-class TestEventHandler : public ui::EventHandler { |
- public: |
- TestEventHandler() : outstanding_touches_(0) {} |
- |
- void OnTouchEvent(ui::TouchEvent* event) override { |
- switch(event->type()) { |
- case ui::ET_TOUCH_PRESSED: |
- outstanding_touches_++; |
- break; |
- case ui::ET_TOUCH_RELEASED: |
- case ui::ET_TOUCH_CANCELLED: |
- outstanding_touches_--; |
- break; |
- default: |
- break; |
- } |
- } |
- |
- int outstanding_touches() const { return outstanding_touches_; } |
- |
- private: |
- int outstanding_touches_; |
-}; |
- |
// Tests that touch event ids are released correctly. See |
// crbug.com/439051 for details. When the ids aren't managed |
// correctly, we get stuck down touches. |
TEST_F(MenuControllerTest, TouchIdsReleasedCorrectly) { |
- scoped_ptr<Widget> owner(CreateOwnerWidget()); |
TestEventHandler test_event_handler; |
- owner->GetNativeWindow()->GetRootWindow()->AddPreTargetHandler( |
+ owner()->GetNativeWindow()->GetRootWindow()->AddPreTargetHandler( |
&test_event_handler); |
std::vector<int> devices; |
devices.push_back(1); |
ui::SetUpTouchDevicesForTest(devices); |
- DispatchTouch(XI_TouchBegin, 0); |
- DispatchTouch(XI_TouchBegin, 1); |
- DispatchTouch(XI_TouchEnd, 0); |
+ event_generator()->PressTouchId(0); |
+ event_generator()->PressTouchId(1); |
+ event_generator()->ReleaseTouchId(0); |
- message_loop()->PostTask(FROM_HERE, |
- base::Bind(&MenuControllerTest::DispatchTouch, |
- base::Unretained(this), XI_TouchEnd, 1)); |
+ base::MessageLoopForUI::current()->PostTask( |
+ FROM_HERE, |
+ base::Bind(&MenuControllerTest::ReleaseTouchId, |
+ base::Unretained(this), |
+ 1)); |
- message_loop()->PostTask( |
+ base::MessageLoopForUI::current()->PostTask( |
FROM_HERE, |
- base::Bind(&MenuControllerTest::DispatchEscapeAndExpect, |
- base::Unretained(this), MenuController::EXIT_OUTERMOST)); |
+ base::Bind(&MenuControllerTest::PressKey, |
+ base::Unretained(this), |
+ ui::VKEY_ESCAPE)); |
+ |
+ RunMenu(); |
- RunMenu(owner.get()); |
+ EXPECT_EQ(MenuController::EXIT_OUTERMOST, menu_exit_type()); |
EXPECT_EQ(0, test_event_handler.outstanding_touches()); |
- owner->GetNativeWindow()->GetRootWindow()->RemovePreTargetHandler( |
+ owner()->GetNativeWindow()->GetRootWindow()->RemovePreTargetHandler( |
&test_event_handler); |
} |
-#endif // defined(USE_X11) |
-TEST_F(MenuControllerTest, FirstSelectedItem) { |
- scoped_ptr<Widget> owner(CreateOwnerWidget()); |
- scoped_ptr<TestMenuItemView> menu_item(new TestMenuItemView); |
- menu_item->AppendMenuItemWithLabel(1, base::ASCIIToUTF16("One")); |
- menu_item->AppendMenuItemWithLabel(2, base::ASCIIToUTF16("Two")); |
- // Disabling the item "One" gets it skipped when a menu is first opened. |
- menu_item->GetSubmenu()->GetMenuItemAt(0)->SetEnabled(false); |
+#endif // defined(USE_X11) |
- SetupMenu(owner.get(), menu_item.get()); |
+TEST_F(MenuControllerTest, FirstSelectedItem) { |
+ // disabling all items but "Two". |
+ menu_item()->GetSubmenu()->GetMenuItemAt(0)->SetEnabled(false); |
+ menu_item()->GetSubmenu()->GetMenuItemAt(2)->SetEnabled(false); |
+ menu_item()->GetSubmenu()->GetMenuItemAt(3)->SetEnabled(false); |
- // First selectable item should be item "Two". |
- MenuItemView* first_selectable = FindFirstSelectableMenuItem(menu_item.get()); |
+ // "Two" should be the first selectable item. |
+ MenuItemView* first_selectable = FindFirstSelectableMenuItem(menu_item()); |
EXPECT_EQ(2, first_selectable->GetCommand()); |
// There should be no next or previous selectable item since there is only a |
// single enabled item in the menu. |
SetPendingStateItem(first_selectable); |
- EXPECT_EQ(nullptr, FindNextSelectableMenuItem(menu_item.get(), 1, 1)); |
- EXPECT_EQ(nullptr, FindNextSelectableMenuItem(menu_item.get(), 1, -1)); |
+ EXPECT_EQ(nullptr, FindNextSelectableMenuItem(menu_item(), 1, 1)); |
+ EXPECT_EQ(nullptr, FindNextSelectableMenuItem(menu_item(), 1, -1)); |
// Clear references in menu controller to the menu item that is going away. |
ResetSelection(); |
} |
TEST_F(MenuControllerTest, NextSelectedItem) { |
- scoped_ptr<Widget> owner(CreateOwnerWidget()); |
- scoped_ptr<TestMenuItemView> menu_item(new TestMenuItemView); |
- menu_item->AppendMenuItemWithLabel(1, base::ASCIIToUTF16("One")); |
- menu_item->AppendMenuItemWithLabel(2, base::ASCIIToUTF16("Two")); |
- menu_item->AppendMenuItemWithLabel(3, base::ASCIIToUTF16("Three")); |
- menu_item->AppendMenuItemWithLabel(4, base::ASCIIToUTF16("Four")); |
// Disabling the item "Three" gets it skipped when using keyboard to navigate. |
- menu_item->GetSubmenu()->GetMenuItemAt(2)->SetEnabled(false); |
- |
- SetupMenu(owner.get(), menu_item.get()); |
+ menu_item()->GetSubmenu()->GetMenuItemAt(2)->SetEnabled(false); |
// Fake initial hot selection. |
- SetPendingStateItem(menu_item->GetSubmenu()->GetMenuItemAt(0)); |
+ SetPendingStateItem(menu_item()->GetSubmenu()->GetMenuItemAt(0)); |
EXPECT_EQ(1, pending_state_item()->GetCommand()); |
// Move down in the menu. |