Chromium Code Reviews| Index: ui/views/widget/root_view_unittest.cc |
| diff --git a/ui/views/widget/root_view_unittest.cc b/ui/views/widget/root_view_unittest.cc |
| index fcefb7033020c19e0e19b8890838937b54e233f4..51f5892425c94f650f588d911bfa533a6883b2c1 100644 |
| --- a/ui/views/widget/root_view_unittest.cc |
| +++ b/ui/views/widget/root_view_unittest.cc |
| @@ -4,6 +4,7 @@ |
| #include "ui/views/widget/root_view.h" |
| +#include "ui/events/event_utils.h" |
| #include "ui/views/context_menu_controller.h" |
| #include "ui/views/test/views_test_base.h" |
| #include "ui/views/view_targeter.h" |
| @@ -337,5 +338,68 @@ TEST_F(RootViewTest, ContextMenuFromLongPressOnDisabledView) { |
| EXPECT_EQ(0, controller.show_context_menu_calls()); |
| } |
| +// This view class provides functionality to delete itself in the context of |
| +// mouse exit event and helps test that we don't crash when we return from |
| +// the mouse exit handler. |
| +class DeleteViewOnMouseExit : public View { |
| + public: |
| + explicit DeleteViewOnMouseExit(bool* got_mouse_exit) |
| + : got_mouse_exit_(got_mouse_exit) { |
| + } |
| + |
| + ~DeleteViewOnMouseExit() override {} |
| + |
| + void OnMouseExited(const ui::MouseEvent& event) override { |
| + *got_mouse_exit_ = true; |
| + delete this; |
| + } |
| + |
| + private: |
| + // Set to true in OnMouseExited(). |
| + bool* got_mouse_exit_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(DeleteViewOnMouseExit); |
| +}; |
| + |
| +// Verifies deleting a View in OnMouseExited() doesn't crash. |
| +TEST_F(RootViewTest, DeleteViewOnMouseExitDispatch) { |
| + Widget widget; |
| + Widget::InitParams init_params = |
| + CreateParams(Widget::InitParams::TYPE_POPUP); |
| + init_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; |
| + widget.Init(init_params); |
| + widget.SetBounds(gfx::Rect(10, 10, 500, 500)); |
| + |
| + View* content = new View; |
| + widget.SetContentsView(content); |
| + |
| + bool got_mouse_exit = false; |
| + View* child = new DeleteViewOnMouseExit(&got_mouse_exit); |
| + content->AddChildView(child); |
| + child->SetBounds(10, 10, 500, 500); |
| + |
| + child->SetFocusable(true); |
| + child->RequestFocus(); |
|
sadrul
2015/03/18 22:30:00
Don't need focus, right?
ananta
2015/03/19 00:02:55
Done.
|
| + |
| + internal::RootView* root_view = |
| + static_cast<internal::RootView*>(widget.GetRootView()); |
| + |
| + // Generate a mouse move event which ensures that the mouse_moved_handler_ |
| + // member is set in the RootView class. |
| + ui::MouseEvent moved_event(ui::ET_MOUSE_MOVED, gfx::Point(15, 15), |
| + gfx::Point(100, 100), ui::EventTimeForNow(), 0, |
| + 0); |
| + root_view->OnMouseMoved(moved_event); |
|
sadrul
2015/03/18 22:30:00
EXPECT_FALSE here that !got_mouse_exit?
ananta
2015/03/19 00:02:55
Done.
|
| + |
| + // Generate a mouse exit event which in turn will delete the child view which |
| + // was the target of the mouse move event above. This should not crash when |
| + // the mouse exit handler returns from the child. |
| + ui::MouseEvent exit_event(ui::ET_MOUSE_EXITED, gfx::Point(), gfx::Point(), |
| + ui::EventTimeForNow(), 0, 0); |
| + root_view->OnMouseExited(exit_event); |
| + |
| + EXPECT_TRUE(got_mouse_exit); |
|
sadrul
2015/03/18 22:30:00
Also check that content->has_children() == false?
ananta
2015/03/19 00:02:55
Done.
|
| +} |
| + |
| } // namespace test |
| } // namespace views |