| Index: content/browser/renderer_host/input/buffered_input_router_unittest.cc
|
| diff --git a/content/browser/renderer_host/input/buffered_input_router_unittest.cc b/content/browser/renderer_host/input/buffered_input_router_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..e34cf604a39ec56a64b836d812ae686f4db86713
|
| --- /dev/null
|
| +++ b/content/browser/renderer_host/input/buffered_input_router_unittest.cc
|
| @@ -0,0 +1,335 @@
|
| +// Copyright 2013 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 "base/basictypes.h"
|
| +#include "content/browser/renderer_host/input/buffered_input_router.h"
|
| +#include "content/browser/renderer_host/input/input_router_unittest.h"
|
| +#include "content/common/input/event_packet.h"
|
| +#include "content/common/input_messages.h"
|
| +#include "content/common/view_messages.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +using WebKit::WebGestureEvent;
|
| +using WebKit::WebInputEvent;
|
| +using WebKit::WebMouseEvent;
|
| +using WebKit::WebMouseWheelEvent;
|
| +using WebKit::WebTouchEvent;
|
| +using WebKit::WebTouchPoint;
|
| +
|
| +namespace content {
|
| +
|
| +class TestBufferedInputRouter : public BufferedInputRouter {
|
| + public:
|
| + TestBufferedInputRouter(IPC::Sender* sender,
|
| + InputRouterClient* client,
|
| + InputAckHandler* ack_handler,
|
| + int routing_id)
|
| + : BufferedInputRouter(sender, client, ack_handler, routing_id) {}
|
| +
|
| +
|
| + size_t QueuedEventCount() const { return input_queue()->QueuedEventCount(); }
|
| +};
|
| +
|
| +class BufferedInputRouterTest : public InputRouterTest {
|
| + public:
|
| + BufferedInputRouterTest() {}
|
| + virtual ~BufferedInputRouterTest() {}
|
| +
|
| + protected:
|
| + // InputRouterTest
|
| + virtual scoped_ptr<InputRouter> CreateInputRouter(RenderProcessHost* process,
|
| + InputRouterClient* client,
|
| + InputAckHandler* handler,
|
| + int routing_id) OVERRIDE {
|
| + return scoped_ptr<InputRouter>(
|
| + new TestBufferedInputRouter(process, client, handler, routing_id));
|
| + }
|
| +
|
| + bool FinishFlush(const InputEventDispositions& dispositions) {
|
| + if (!process_->sink().message_count())
|
| + return false;
|
| + IPC::Message message(*process_->sink().GetMessageAt(0));
|
| + process_->sink().ClearMessages();
|
| +
|
| + InputMsg_HandleEventPacket::Param param;
|
| + InputMsg_HandleEventPacket::Read(&message, ¶m);
|
| + EventPacket& packet = param.a;
|
| +
|
| + return SendEventPacketACK(packet.id(), dispositions);
|
| + }
|
| +
|
| + bool FinishFlush(InputEventDisposition disposition) {
|
| + if (!process_->sink().message_count())
|
| + return false;
|
| + IPC::Message message(*process_->sink().GetMessageAt(0));
|
| + process_->sink().ClearMessages();
|
| +
|
| + InputMsg_HandleEventPacket::Param param;
|
| + InputMsg_HandleEventPacket::Read(&message, ¶m);
|
| + EventPacket& packet = param.a;
|
| +
|
| + return SendEventPacketACK(
|
| + packet.id(), InputEventDispositions(packet.size(), disposition));
|
| + }
|
| +
|
| + bool SendEventPacketACK(int id, const InputEventDispositions& dispositions) {
|
| + return input_router_->OnMessageReceived(
|
| + InputHostMsg_HandleEventPacket_ACK(0, id, dispositions));
|
| + }
|
| +
|
| + size_t QueuedEventCount() const {
|
| + return buffered_input_router()->QueuedEventCount();
|
| + }
|
| +
|
| + TestBufferedInputRouter* buffered_input_router() const {
|
| + return static_cast<TestBufferedInputRouter*>(input_router_.get());
|
| + }
|
| +};
|
| +
|
| +TEST_F(BufferedInputRouterTest, InputEventsProperlyQueued) {
|
| + EXPECT_TRUE(input_router_->SendInput(
|
| + scoped_ptr<IPC::Message>(new InputMsg_Redo(MSG_ROUTING_NONE))));
|
| + EXPECT_EQ(1U, QueuedEventCount());
|
| +
|
| + EXPECT_TRUE(input_router_->SendInput(
|
| + scoped_ptr<IPC::Message>(new InputMsg_Cut(MSG_ROUTING_NONE))));
|
| + EXPECT_EQ(2U, QueuedEventCount());
|
| +
|
| + EXPECT_TRUE(input_router_->SendInput(
|
| + scoped_ptr<IPC::Message>(new InputMsg_Copy(MSG_ROUTING_NONE))));
|
| + EXPECT_EQ(3U, QueuedEventCount());
|
| +
|
| + EXPECT_TRUE(input_router_->SendInput(
|
| + scoped_ptr<IPC::Message>(new InputMsg_Paste(MSG_ROUTING_NONE))));
|
| + EXPECT_EQ(4U, QueuedEventCount());
|
| +}
|
| +
|
| +#define SCOPED_EXPECT(CALL, MESSAGE) { SCOPED_TRACE(MESSAGE); CALL; }
|
| +
|
| +TEST_F(BufferedInputRouterTest, ClientOnSendEventCalled) {
|
| + SimulateKeyboardEvent(WebInputEvent::RawKeyDown);
|
| + EXPECT_EQ(1U, QueuedEventCount());
|
| +
|
| + SimulateWheelEvent(5, 0, 0, false);
|
| + EXPECT_EQ(2U, QueuedEventCount());
|
| +
|
| + SimulateMouseMove(5, 0, 0);
|
| + EXPECT_EQ(3U, QueuedEventCount());
|
| +
|
| + SimulateGestureEvent(WebInputEvent::GestureScrollBegin,
|
| + WebGestureEvent::Touchpad);
|
| + EXPECT_EQ(4U, QueuedEventCount());
|
| +
|
| + SimulateTouchEvent(1, 1);
|
| + EXPECT_EQ(5U, QueuedEventCount());
|
| +}
|
| +
|
| +TEST_F(BufferedInputRouterTest, ClientOnSendEventHonored) {
|
| + client_->set_allow_send_event(false);
|
| +
|
| + SimulateKeyboardEvent(WebInputEvent::RawKeyDown);
|
| + EXPECT_EQ(0U, QueuedEventCount());
|
| +
|
| + SimulateWheelEvent(5, 0, 0, false);
|
| + EXPECT_EQ(0U, QueuedEventCount());
|
| +
|
| + SimulateMouseMove(5, 0, 0);
|
| + EXPECT_EQ(0U, QueuedEventCount());
|
| +
|
| + SimulateGestureEvent(WebInputEvent::GestureScrollBegin,
|
| + WebGestureEvent::Touchpad);
|
| + EXPECT_EQ(0U, QueuedEventCount());
|
| +
|
| + SimulateTouchEvent(1, 1);
|
| + EXPECT_EQ(0U, QueuedEventCount());
|
| +}
|
| +
|
| +TEST_F(BufferedInputRouterTest, FlightCountIncrementedOnDeliver) {
|
| + SimulateKeyboardEvent(WebInputEvent::RawKeyDown);
|
| + EXPECT_EQ(0, client_->in_flight_event_count());
|
| +
|
| + input_router_->Flush();
|
| + EXPECT_EQ(1, client_->in_flight_event_count());
|
| +}
|
| +
|
| +TEST_F(BufferedInputRouterTest, FlightCountDecrementedOnAck) {
|
| + SimulateKeyboardEvent(WebInputEvent::RawKeyDown);
|
| + EXPECT_EQ(0, client_->in_flight_event_count());
|
| +
|
| + input_router_->Flush();
|
| + EXPECT_EQ(1, client_->in_flight_event_count());
|
| +
|
| + // The in-flight count should continue until the flush has finished.
|
| + ASSERT_TRUE(FinishFlush(INPUT_EVENT_COULD_NOT_DELIVER));
|
| + EXPECT_EQ(1, client_->in_flight_event_count());
|
| +
|
| + ASSERT_TRUE(FinishFlush(INPUT_EVENT_IMPL_THREAD_CONSUMED));
|
| + EXPECT_EQ(0, client_->in_flight_event_count());
|
| +}
|
| +
|
| +TEST_F(BufferedInputRouterTest, FilteredEventsNeverQueued) {
|
| + // Event should not be queued, but should be ack'ed.
|
| + client_->set_filter_state(INPUT_EVENT_ACK_STATE_CONSUMED);
|
| + SimulateKeyboardEvent(WebInputEvent::RawKeyDown);
|
| + SCOPED_EXPECT(ack_handler_->ExpectAckCalled(1), "AckCalled");
|
| + EXPECT_EQ(0U, QueuedEventCount());
|
| + ASSERT_EQ(NULL, input_router_->GetLastKeyboardEvent());
|
| +
|
| + // Event should not be queued, but should be ack'ed.
|
| + client_->set_filter_state(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
|
| + SimulateKeyboardEvent(WebInputEvent::RawKeyDown);
|
| + SCOPED_EXPECT(ack_handler_->ExpectAckCalled(1), "AckCalled");
|
| + EXPECT_EQ(0U, QueuedEventCount());
|
| + ASSERT_EQ(NULL, input_router_->GetLastKeyboardEvent());
|
| +
|
| + // |INPUT_EVENT_DISPOSITION_UNKNOWN| should drop the event without ack'ing.
|
| + client_->set_filter_state(INPUT_EVENT_ACK_STATE_UNKNOWN);
|
| + SimulateKeyboardEvent(WebInputEvent::RawKeyDown);
|
| + SCOPED_EXPECT(ack_handler_->ExpectAckCalled(0), "AckNotCalled");
|
| + EXPECT_EQ(0U, QueuedEventCount());
|
| + ASSERT_EQ(NULL, input_router_->GetLastKeyboardEvent());
|
| +
|
| + // Event should be queued.
|
| + client_->set_filter_state(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
|
| + SimulateKeyboardEvent(WebInputEvent::RawKeyDown);
|
| + SCOPED_EXPECT(ack_handler_->ExpectAckCalled(0), "AckNotCalled");
|
| + EXPECT_EQ(1U, QueuedEventCount());
|
| +}
|
| +
|
| +TEST_F(BufferedInputRouterTest, FollowupEventsInjected) {
|
| + // Enable a followup gesture event.
|
| + WebGestureEvent followup_event;
|
| + followup_event.type = WebInputEvent::GestureScrollBegin;
|
| + followup_event.data.scrollUpdate.deltaX = 10;
|
| + ack_handler_->set_followup_touch_event(make_scoped_ptr(
|
| + new GestureEventWithLatencyInfo(followup_event, ui::LatencyInfo())));
|
| +
|
| + // Create an initial packet of { Touch, Key } and start flushing.
|
| + SimulateTouchEvent(1, 1);
|
| + EXPECT_EQ(1U, QueuedEventCount());
|
| + SimulateKeyboardEvent(WebInputEvent::RawKeyDown);
|
| + EXPECT_EQ(2U, QueuedEventCount());
|
| + input_router_->Flush();
|
| +
|
| + // Followup only triggered when event handled.
|
| + ASSERT_TRUE(FinishFlush(INPUT_EVENT_COULD_NOT_DELIVER));
|
| + SCOPED_EXPECT(client_->ExpectDidFlushCalled(false), "DidFlushNotCalled");
|
| + EXPECT_EQ(2U, QueuedEventCount());
|
| +
|
| + // Ack the touch event.
|
| + InputEventDispositions dispositions;
|
| + dispositions.push_back(INPUT_EVENT_MAIN_THREAD_NOT_PREVENT_DEFAULTED);
|
| + dispositions.push_back(INPUT_EVENT_COULD_NOT_DELIVER);
|
| + ASSERT_TRUE(FinishFlush(dispositions));
|
| +
|
| + // Ack'ing the touch event should have inserted the followup gesture event;
|
| + // the flush is not complete until the inserted event is ack'ed.
|
| + SCOPED_EXPECT(client_->ExpectDidFlushCalled(false), "DidFlushNotCalled");
|
| + SCOPED_EXPECT(client_->ExpectSendCalled(true), "SendGestureCalled");
|
| + EXPECT_EQ(followup_event.type, client_->sent_gesture_event().event.type);
|
| + EXPECT_EQ(2U, QueuedEventCount());
|
| +
|
| + // Our packet is now { Gesture, Key }.
|
| + InputMsg_HandleEventPacket::Param param;
|
| + ASSERT_EQ(1U, process_->sink().message_count());
|
| + ASSERT_TRUE(InputMsg_HandleEventPacket::Read(process_->sink().GetMessageAt(0),
|
| + ¶m));
|
| + EventPacket& followup_packet = param.a;
|
| + ASSERT_EQ(2U, followup_packet.size());
|
| + ASSERT_EQ(InputEvent::Payload::WEB_INPUT_EVENT,
|
| + followup_packet.events()[0]->payload()->GetType());
|
| + ASSERT_EQ(InputEvent::Payload::WEB_INPUT_EVENT,
|
| + followup_packet.events()[1]->payload()->GetType());
|
| + const WebInputEventPayload* payload0 =
|
| + WebInputEventPayload::Cast(followup_packet.events()[0]->payload());
|
| + const WebInputEventPayload* payload1 =
|
| + WebInputEventPayload::Cast(followup_packet.events()[1]->payload());
|
| + EXPECT_EQ(followup_event.type, payload0->web_event()->type);
|
| + EXPECT_EQ(WebInputEvent::RawKeyDown, payload1->web_event()->type);
|
| +
|
| + // Complete the flush; the gesture should have been ack'ed.
|
| + ASSERT_TRUE(FinishFlush(INPUT_EVENT_IMPL_THREAD_CONSUMED));
|
| + SCOPED_EXPECT(client_->ExpectDidFlushCalled(true), "DidFlushCalled");
|
| + EXPECT_EQ(followup_event.type, ack_handler_->acked_gesture_event().type);
|
| + EXPECT_EQ(0U, QueuedEventCount());
|
| +}
|
| +
|
| +TEST_F(BufferedInputRouterTest, FlushRequestedOnQueue) {
|
| + // The first queued event should trigger a flush request.
|
| + SimulateKeyboardEvent(WebInputEvent::RawKeyDown);
|
| + EXPECT_EQ(1U, QueuedEventCount());
|
| + SCOPED_EXPECT(client_->ExpectNeedsFlushCalled(true), "SetNeedsFlushCalled");
|
| +
|
| + // Subsequently queued events will not trigger another flush request.
|
| + SimulateWheelEvent(5, 0, 0, false);
|
| + EXPECT_EQ(2U, QueuedEventCount());
|
| + SCOPED_EXPECT(client_->ExpectNeedsFlushCalled(false), "SetNeedsFlushCalled");
|
| +}
|
| +
|
| +TEST_F(BufferedInputRouterTest, HasQueuedGestureEvents) {
|
| + EXPECT_FALSE(input_router_->HasQueuedGestureEvents());
|
| + SimulateGestureEvent(WebInputEvent::GestureScrollBegin,
|
| + WebGestureEvent::Touchpad);
|
| + EXPECT_TRUE(input_router_->HasQueuedGestureEvents());
|
| +
|
| + // Only an ack'ed gesture should clear it from the queue.
|
| + input_router_->Flush();
|
| + ASSERT_TRUE(FinishFlush(INPUT_EVENT_COULD_NOT_DELIVER));
|
| + EXPECT_TRUE(input_router_->HasQueuedGestureEvents());
|
| +
|
| + ASSERT_TRUE(FinishFlush(INPUT_EVENT_IMPL_THREAD_CONSUMED));
|
| + EXPECT_FALSE(input_router_->HasQueuedGestureEvents());
|
| +}
|
| +
|
| +TEST_F(BufferedInputRouterTest, GetLastKeyboardEvent) {
|
| + EXPECT_EQ(NULL, input_router_->GetLastKeyboardEvent());
|
| +
|
| + SimulateKeyboardEvent(WebInputEvent::RawKeyDown);
|
| + EXPECT_EQ(WebInputEvent::RawKeyDown,
|
| + input_router_->GetLastKeyboardEvent()->type);
|
| +
|
| + // Queueing another key event does not effect the "last" event.
|
| + SimulateKeyboardEvent(WebInputEvent::KeyUp);
|
| + EXPECT_EQ(WebInputEvent::RawKeyDown,
|
| + input_router_->GetLastKeyboardEvent()->type);
|
| +
|
| + input_router_->Flush();
|
| +
|
| + // Ack'ing the first event should make the second event the "last" event.
|
| + InputEventDispositions dispositions;
|
| + dispositions.push_back(INPUT_EVENT_IMPL_THREAD_CONSUMED);
|
| + dispositions.push_back(INPUT_EVENT_COULD_NOT_DELIVER);
|
| + ASSERT_TRUE(FinishFlush(dispositions));
|
| + EXPECT_EQ(WebInputEvent::KeyUp, input_router_->GetLastKeyboardEvent()->type);
|
| +
|
| + // A key event queued during a flush becomes "last" upon flush completion.
|
| + SimulateKeyboardEvent(WebInputEvent::Char);
|
| + ASSERT_TRUE(FinishFlush(INPUT_EVENT_IMPL_THREAD_CONSUMED));
|
| + EXPECT_EQ(WebInputEvent::Char, input_router_->GetLastKeyboardEvent()->type);
|
| +
|
| + // An empty queue should produce a null "last" event.
|
| + input_router_->Flush();
|
| + ASSERT_TRUE(FinishFlush(INPUT_EVENT_IMPL_THREAD_CONSUMED));
|
| + EXPECT_EQ(NULL, input_router_->GetLastKeyboardEvent());
|
| +}
|
| +
|
| +TEST_F(BufferedInputRouterTest, UnexpectedAck) {
|
| + ASSERT_FALSE(ack_handler_->unexpected_event_ack_called());
|
| + input_router_->OnMessageReceived(
|
| + InputHostMsg_HandleEventPacket_ACK(0, 0, InputEventDispositions()));
|
| + EXPECT_TRUE(ack_handler_->unexpected_event_ack_called());
|
| +}
|
| +
|
| +TEST_F(BufferedInputRouterTest, BadAck) {
|
| + SimulateKeyboardEvent(WebInputEvent::RawKeyDown);
|
| + input_router_->Flush();
|
| +
|
| + ASSERT_FALSE(ack_handler_->unexpected_event_ack_called());
|
| + EventPacket packet;
|
| + input_router_->OnMessageReceived(
|
| + InputHostMsg_HandleEventPacket_ACK(0, 0, InputEventDispositions()));
|
| + EXPECT_TRUE(ack_handler_->unexpected_event_ack_called());
|
| +}
|
| +
|
| +} // namespace content
|
|
|