| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <string> |
| |
| #include "content/common/view_messages.h" |
| #include "content/public/test/render_view_test.h" |
| #include "content/renderer/mouse_lock_dispatcher.h" |
| #include "content/renderer/render_view_impl.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| using ::testing::_; |
| |
| namespace content { |
| namespace { |
| |
| class MockLockTarget : public MouseLockDispatcher::LockTarget { |
| public: |
| MOCK_METHOD1(OnLockMouseACK, void(bool)); |
| MOCK_METHOD0(OnMouseLockLost, void()); |
| MOCK_METHOD1(HandleMouseLockedInputEvent, |
| bool(const blink::WebMouseEvent&)); |
| }; |
| |
| // MouseLockDispatcher is a RenderViewObserver, and we test it by creating a |
| // fixture containing a RenderViewImpl view() and interacting to that interface. |
| class MouseLockDispatcherTest : public RenderViewTest { |
| public: |
| void SetUp() override { |
| RenderViewTest::SetUp(); |
| route_id_ = view()->GetWidget()->routing_id(); |
| target_ = new MockLockTarget(); |
| alternate_target_ = new MockLockTarget(); |
| } |
| |
| void TearDown() override { |
| RenderViewTest::TearDown(); |
| delete target_; |
| delete alternate_target_; |
| } |
| |
| protected: |
| RenderViewImpl* view() { return static_cast<RenderViewImpl*>(view_); } |
| RenderWidget* widget() { return view()->GetWidget(); } |
| MouseLockDispatcher* dispatcher() { return view()->mouse_lock_dispatcher(); } |
| int route_id_; |
| MockLockTarget* target_; |
| MockLockTarget* alternate_target_; |
| }; |
| |
| } // namespace |
| |
| // Test simple use of RenderViewImpl interface to WebKit for pointer lock. |
| TEST_F(MouseLockDispatcherTest, BasicWebWidget) { |
| // Start unlocked. |
| EXPECT_FALSE(widget()->isPointerLocked()); |
| |
| // Lock. |
| EXPECT_TRUE(widget()->requestPointerLock()); |
| widget()->OnMessageReceived(ViewMsg_LockMouse_ACK(route_id_, true)); |
| EXPECT_TRUE(widget()->isPointerLocked()); |
| |
| // Unlock. |
| widget()->requestPointerUnlock(); |
| widget()->OnMessageReceived(ViewMsg_MouseLockLost(route_id_)); |
| EXPECT_FALSE(widget()->isPointerLocked()); |
| |
| // Attempt a lock, and have it fail. |
| EXPECT_TRUE(widget()->requestPointerLock()); |
| widget()->OnMessageReceived(ViewMsg_LockMouse_ACK(route_id_, false)); |
| EXPECT_FALSE(widget()->isPointerLocked()); |
| } |
| |
| // Test simple use of MouseLockDispatcher with a mock LockTarget. |
| TEST_F(MouseLockDispatcherTest, BasicMockLockTarget) { |
| ::testing::InSequence expect_calls_in_sequence; |
| EXPECT_CALL(*target_, OnLockMouseACK(true)); |
| EXPECT_CALL(*target_, HandleMouseLockedInputEvent(_)); |
| EXPECT_CALL(*target_, OnMouseLockLost()); |
| EXPECT_CALL(*target_, OnLockMouseACK(false)); |
| |
| // Start unlocked. |
| EXPECT_FALSE(dispatcher()->IsMouseLockedTo(NULL)); |
| EXPECT_FALSE(dispatcher()->IsMouseLockedTo(target_)); |
| |
| // Lock. |
| EXPECT_TRUE(dispatcher()->LockMouse(target_)); |
| widget()->OnMessageReceived(ViewMsg_LockMouse_ACK(route_id_, true)); |
| EXPECT_TRUE(dispatcher()->IsMouseLockedTo(target_)); |
| |
| // Receive mouse event. |
| dispatcher()->WillHandleMouseEvent(blink::WebMouseEvent()); |
| |
| // Unlock. |
| dispatcher()->UnlockMouse(target_); |
| widget()->OnMessageReceived(ViewMsg_MouseLockLost(route_id_)); |
| EXPECT_FALSE(dispatcher()->IsMouseLockedTo(target_)); |
| |
| // Attempt a lock, and have it fail. |
| EXPECT_TRUE(dispatcher()->LockMouse(target_)); |
| widget()->OnMessageReceived(ViewMsg_LockMouse_ACK(route_id_, false)); |
| EXPECT_FALSE(dispatcher()->IsMouseLockedTo(target_)); |
| } |
| |
| // Test deleting a target while it is in use by MouseLockDispatcher. |
| TEST_F(MouseLockDispatcherTest, DeleteAndUnlock) { |
| ::testing::InSequence expect_calls_in_sequence; |
| EXPECT_CALL(*target_, OnLockMouseACK(true)); |
| EXPECT_CALL(*target_, HandleMouseLockedInputEvent(_)).Times(0); |
| EXPECT_CALL(*target_, OnMouseLockLost()).Times(0); |
| |
| // Lock. |
| EXPECT_TRUE(dispatcher()->LockMouse(target_)); |
| widget()->OnMessageReceived(ViewMsg_LockMouse_ACK(route_id_, true)); |
| EXPECT_TRUE(dispatcher()->IsMouseLockedTo(target_)); |
| |
| // Unlock, with a deleted target. |
| // Don't receive mouse events or lock lost. |
| dispatcher()->OnLockTargetDestroyed(target_); |
| delete target_; |
| target_ = NULL; |
| dispatcher()->WillHandleMouseEvent(blink::WebMouseEvent()); |
| widget()->OnMessageReceived(ViewMsg_MouseLockLost(route_id_)); |
| EXPECT_FALSE(dispatcher()->IsMouseLockedTo(target_)); |
| } |
| |
| // Test deleting a target that is pending a lock request response. |
| TEST_F(MouseLockDispatcherTest, DeleteWithPendingLockSuccess) { |
| ::testing::InSequence expect_calls_in_sequence; |
| EXPECT_CALL(*target_, OnLockMouseACK(true)).Times(0); |
| EXPECT_CALL(*target_, OnMouseLockLost()).Times(0); |
| |
| // Lock request. |
| EXPECT_TRUE(dispatcher()->LockMouse(target_)); |
| |
| // Before receiving response delete the target. |
| dispatcher()->OnLockTargetDestroyed(target_); |
| delete target_; |
| target_ = NULL; |
| |
| // Lock response. |
| widget()->OnMessageReceived(ViewMsg_LockMouse_ACK(route_id_, true)); |
| } |
| |
| // Test deleting a target that is pending a lock request failure response. |
| TEST_F(MouseLockDispatcherTest, DeleteWithPendingLockFail) { |
| ::testing::InSequence expect_calls_in_sequence; |
| EXPECT_CALL(*target_, OnLockMouseACK(true)).Times(0); |
| EXPECT_CALL(*target_, OnMouseLockLost()).Times(0); |
| |
| // Lock request. |
| EXPECT_TRUE(dispatcher()->LockMouse(target_)); |
| |
| // Before receiving response delete the target. |
| dispatcher()->OnLockTargetDestroyed(target_); |
| delete target_; |
| target_ = NULL; |
| |
| // Lock response. |
| widget()->OnMessageReceived(ViewMsg_LockMouse_ACK(route_id_, false)); |
| } |
| |
| // Test not receiving mouse events when a target is not locked. |
| TEST_F(MouseLockDispatcherTest, MouseEventsNotReceived) { |
| ::testing::InSequence expect_calls_in_sequence; |
| EXPECT_CALL(*target_, HandleMouseLockedInputEvent(_)).Times(0); |
| EXPECT_CALL(*target_, OnLockMouseACK(true)); |
| EXPECT_CALL(*target_, HandleMouseLockedInputEvent(_)); |
| EXPECT_CALL(*target_, OnMouseLockLost()); |
| EXPECT_CALL(*target_, HandleMouseLockedInputEvent(_)).Times(0); |
| |
| // (Don't) receive mouse event. |
| dispatcher()->WillHandleMouseEvent(blink::WebMouseEvent()); |
| |
| // Lock. |
| EXPECT_TRUE(dispatcher()->LockMouse(target_)); |
| widget()->OnMessageReceived(ViewMsg_LockMouse_ACK(route_id_, true)); |
| EXPECT_TRUE(dispatcher()->IsMouseLockedTo(target_)); |
| |
| // Receive mouse event. |
| dispatcher()->WillHandleMouseEvent(blink::WebMouseEvent()); |
| |
| // Unlock. |
| dispatcher()->UnlockMouse(target_); |
| widget()->OnMessageReceived(ViewMsg_MouseLockLost(route_id_)); |
| EXPECT_FALSE(dispatcher()->IsMouseLockedTo(target_)); |
| |
| // (Don't) receive mouse event. |
| dispatcher()->WillHandleMouseEvent(blink::WebMouseEvent()); |
| } |
| |
| // Test multiple targets |
| TEST_F(MouseLockDispatcherTest, MultipleTargets) { |
| ::testing::InSequence expect_calls_in_sequence; |
| EXPECT_CALL(*target_, OnLockMouseACK(true)); |
| EXPECT_CALL(*target_, HandleMouseLockedInputEvent(_)); |
| EXPECT_CALL(*alternate_target_, HandleMouseLockedInputEvent(_)).Times(0); |
| EXPECT_CALL(*target_, OnMouseLockLost()).Times(0); |
| EXPECT_CALL(*alternate_target_, OnMouseLockLost()).Times(0); |
| EXPECT_CALL(*target_, OnMouseLockLost()); |
| |
| // Lock request for target. |
| EXPECT_TRUE(dispatcher()->LockMouse(target_)); |
| |
| // Fail attempt to lock alternate. |
| EXPECT_FALSE(dispatcher()->IsMouseLockedTo(alternate_target_)); |
| EXPECT_FALSE(dispatcher()->LockMouse(alternate_target_)); |
| |
| // Lock completion for target. |
| widget()->OnMessageReceived(ViewMsg_LockMouse_ACK(route_id_, true)); |
| EXPECT_TRUE(dispatcher()->IsMouseLockedTo(target_)); |
| |
| // Fail attempt to lock alternate. |
| EXPECT_FALSE(dispatcher()->IsMouseLockedTo(alternate_target_)); |
| EXPECT_FALSE(dispatcher()->LockMouse(alternate_target_)); |
| |
| // Receive mouse event to only one target. |
| dispatcher()->WillHandleMouseEvent(blink::WebMouseEvent()); |
| |
| // Unlock alternate target has no effect. |
| dispatcher()->UnlockMouse(alternate_target_); |
| EXPECT_TRUE(dispatcher()->IsMouseLockedTo(target_)); |
| EXPECT_FALSE(dispatcher()->IsMouseLockedTo(alternate_target_)); |
| |
| // Though the call to UnlockMouse should not unlock any target, we will |
| // cause an unlock (as if e.g. user escaped mouse lock) and verify the |
| // correct target is unlocked. |
| widget()->OnMessageReceived(ViewMsg_MouseLockLost(route_id_)); |
| EXPECT_FALSE(dispatcher()->IsMouseLockedTo(target_)); |
| } |
| |
| } // namespace content |