Add ICU message format support
[chromium-blink-merge.git] / content / browser / renderer_host / input / touch_emulator_unittest.cc
blobf46703ca4e8c73aa1c9ee1e9839e040e672b4427
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include <vector>
7 #include "base/basictypes.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/time/time.h"
11 #include "content/browser/renderer_host/input/touch_emulator.h"
12 #include "content/browser/renderer_host/input/touch_emulator_client.h"
13 #include "content/common/input/web_input_event_traits.h"
14 #include "testing/gtest/include/gtest/gtest.h"
16 using blink::WebGestureEvent;
17 using blink::WebInputEvent;
18 using blink::WebKeyboardEvent;
19 using blink::WebMouseEvent;
20 using blink::WebMouseWheelEvent;
21 using blink::WebTouchEvent;
22 using blink::WebTouchPoint;
24 namespace content {
26 class TouchEmulatorTest : public testing::Test,
27 public TouchEmulatorClient {
28 public:
29 TouchEmulatorTest()
30 : shift_pressed_(false),
31 mouse_pressed_(false),
32 ack_touches_synchronously_(true),
33 last_mouse_x_(-1),
34 last_mouse_y_(-1) {
35 last_event_time_seconds_ =
36 (base::TimeTicks::Now() - base::TimeTicks()).InSecondsF();
37 event_time_delta_seconds_ = 0.1;
40 ~TouchEmulatorTest() override {}
42 // testing::Test
43 void SetUp() override {
44 emulator_.reset(new TouchEmulator(this, 1.0f));
45 emulator_->SetDoubleTapSupportForPageEnabled(false);
46 emulator_->Enable(ui::GestureProviderConfigType::GENERIC_MOBILE);
49 void TearDown() override {
50 emulator_->Disable();
51 EXPECT_EQ("", ExpectedEvents());
54 void ForwardGestureEvent(const blink::WebGestureEvent& event) override {
55 forwarded_events_.push_back(event.type);
58 void ForwardEmulatedTouchEvent(const blink::WebTouchEvent& event) override {
59 forwarded_events_.push_back(event.type);
60 EXPECT_EQ(1U, event.touchesLength);
61 EXPECT_EQ(last_mouse_x_, event.touches[0].position.x);
62 EXPECT_EQ(last_mouse_y_, event.touches[0].position.y);
63 bool expected_cancelable = event.type != WebInputEvent::TouchCancel;
64 EXPECT_EQ(expected_cancelable, !!event.cancelable);
65 if (ack_touches_synchronously_) {
66 emulator()->HandleTouchEventAck(
67 event, INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
71 void SetCursor(const WebCursor& cursor) override {}
73 void ShowContextMenuAtPoint(const gfx::Point& point) override {}
75 protected:
76 TouchEmulator* emulator() const {
77 return emulator_.get();
80 int modifiers() const {
81 return shift_pressed_ ? WebInputEvent::ShiftKey : 0;
84 std::string ExpectedEvents() {
85 std::string result;
86 for (size_t i = 0; i < forwarded_events_.size(); ++i) {
87 if (i != 0)
88 result += " ";
89 result += WebInputEventTraits::GetName(forwarded_events_[i]);
91 forwarded_events_.clear();
92 return result;
95 double GetNextEventTimeSeconds() {
96 last_event_time_seconds_ += event_time_delta_seconds_;
97 return last_event_time_seconds_;
100 void set_event_time_delta_seconds_(double delta) {
101 event_time_delta_seconds_ = delta;
104 void SendKeyboardEvent(WebInputEvent::Type type) {
105 WebKeyboardEvent event;
106 event.timeStampSeconds = GetNextEventTimeSeconds();
107 event.type = type;
108 event.modifiers = modifiers();
109 emulator()->HandleKeyboardEvent(event);
112 void PressShift() {
113 DCHECK(!shift_pressed_);
114 shift_pressed_ = true;
115 SendKeyboardEvent(WebInputEvent::KeyDown);
118 void ReleaseShift() {
119 DCHECK(shift_pressed_);
120 shift_pressed_ = false;
121 SendKeyboardEvent(WebInputEvent::KeyUp);
124 void SendMouseEvent(WebInputEvent::Type type, int x, int y) {
125 WebMouseEvent event;
126 event.timeStampSeconds = GetNextEventTimeSeconds();
127 event.type = type;
128 event.button = mouse_pressed_ ? WebMouseEvent::ButtonLeft :
129 WebMouseEvent::ButtonNone;
130 event.modifiers = modifiers();
131 last_mouse_x_ = x;
132 last_mouse_y_ = y;
133 event.x = event.windowX = event.globalX = x;
134 event.y = event.windowY = event.globalY = y;
135 emulator()->HandleMouseEvent(event);
138 bool SendMouseWheelEvent() {
139 WebMouseWheelEvent event;
140 event.type = WebInputEvent::MouseWheel;
141 event.timeStampSeconds = GetNextEventTimeSeconds();
142 // Return whether mouse wheel is forwarded.
143 return !emulator()->HandleMouseWheelEvent(event);
146 void MouseDown(int x, int y) {
147 DCHECK(!mouse_pressed_);
148 if (x != last_mouse_x_ || y != last_mouse_y_)
149 SendMouseEvent(WebInputEvent::MouseMove, x, y);
150 mouse_pressed_ = true;
151 SendMouseEvent(WebInputEvent::MouseDown, x, y);
154 void MouseDrag(int x, int y) {
155 DCHECK(mouse_pressed_);
156 SendMouseEvent(WebInputEvent::MouseMove, x, y);
159 void MouseMove(int x, int y) {
160 DCHECK(!mouse_pressed_);
161 SendMouseEvent(WebInputEvent::MouseMove, x, y);
164 void MouseUp(int x, int y) {
165 DCHECK(mouse_pressed_);
166 if (x != last_mouse_x_ || y != last_mouse_y_)
167 SendMouseEvent(WebInputEvent::MouseMove, x, y);
168 SendMouseEvent(WebInputEvent::MouseUp, x, y);
169 mouse_pressed_ = false;
172 bool TouchStart(int x, int y, bool ack) {
173 return SendTouchEvent(
174 WebInputEvent::TouchStart, WebTouchPoint::StatePressed, x, y, ack);
177 bool TouchMove(int x, int y, bool ack) {
178 return SendTouchEvent(
179 WebInputEvent::TouchMove, WebTouchPoint::StateMoved, x, y, ack);
182 bool TouchEnd(int x, int y, bool ack) {
183 return SendTouchEvent(
184 WebInputEvent::TouchEnd, WebTouchPoint::StateReleased, x, y, ack);
187 WebTouchEvent MakeTouchEvent(WebInputEvent::Type type,
188 WebTouchPoint::State state, int x, int y) {
189 WebTouchEvent event;
190 event.type = type;
191 event.timeStampSeconds = GetNextEventTimeSeconds();
192 event.touchesLength = 1;
193 event.touches[0].id = 0;
194 event.touches[0].state = state;
195 event.touches[0].position.x = x;
196 event.touches[0].position.y = y;
197 event.touches[0].screenPosition.x = x;
198 event.touches[0].screenPosition.y = y;
199 return event;
202 bool SendTouchEvent(WebInputEvent::Type type, WebTouchPoint::State state,
203 int x, int y, bool ack) {
204 WebTouchEvent event = MakeTouchEvent(type, state, x, y);
205 if (emulator()->HandleTouchEvent(event)) {
206 // Touch event is not forwarded.
207 return false;
210 if (ack) {
211 // Can't send ack if there are some pending acks.
212 DCHECK(!touch_events_to_ack_.size());
214 // Touch event is forwarded, ack should not be handled by emulator.
215 EXPECT_FALSE(emulator()->HandleTouchEventAck(
216 event, INPUT_EVENT_ACK_STATE_CONSUMED));
217 } else {
218 touch_events_to_ack_.push_back(event);
220 return true;
223 void AckOldestTouchEvent() {
224 DCHECK(touch_events_to_ack_.size());
225 WebTouchEvent event = touch_events_to_ack_[0];
226 touch_events_to_ack_.erase(touch_events_to_ack_.begin());
227 // Emulator should not handle ack from native stream.
228 EXPECT_FALSE(emulator()->HandleTouchEventAck(
229 event, INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS));
232 void DisableSynchronousTouchAck() { ack_touches_synchronously_ = false; }
234 private:
235 scoped_ptr<TouchEmulator> emulator_;
236 std::vector<WebInputEvent::Type> forwarded_events_;
237 double last_event_time_seconds_;
238 double event_time_delta_seconds_;
239 bool shift_pressed_;
240 bool mouse_pressed_;
241 bool ack_touches_synchronously_;
242 int last_mouse_x_;
243 int last_mouse_y_;
244 std::vector<WebTouchEvent> touch_events_to_ack_;
245 base::MessageLoopForUI message_loop_;
249 TEST_F(TouchEmulatorTest, NoTouches) {
250 MouseMove(100, 200);
251 MouseMove(300, 300);
252 EXPECT_EQ("", ExpectedEvents());
255 TEST_F(TouchEmulatorTest, Touch) {
256 MouseMove(100, 200);
257 EXPECT_EQ("", ExpectedEvents());
258 MouseDown(100, 200);
259 EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
260 MouseUp(200, 200);
261 EXPECT_EQ(
262 "TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate"
263 " TouchEnd GestureScrollEnd",
264 ExpectedEvents());
267 TEST_F(TouchEmulatorTest, DoubleTapSupport) {
268 emulator()->SetDoubleTapSupportForPageEnabled(true);
269 MouseMove(100, 200);
270 EXPECT_EQ("", ExpectedEvents());
271 MouseDown(100, 200);
272 EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
273 MouseUp(100, 200);
274 EXPECT_EQ("TouchEnd GestureTapUnconfirmed", ExpectedEvents());
275 MouseDown(100, 200);
276 EXPECT_EQ("TouchStart GestureTapCancel GestureTapDown", ExpectedEvents());
277 MouseUp(100, 200);
278 EXPECT_EQ("TouchEnd GestureTapCancel GestureDoubleTap", ExpectedEvents());
281 TEST_F(TouchEmulatorTest, MultipleTouches) {
282 MouseMove(100, 200);
283 EXPECT_EQ("", ExpectedEvents());
284 MouseDown(100, 200);
285 EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
286 MouseUp(200, 200);
287 EXPECT_EQ(
288 "TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate"
289 " TouchEnd GestureScrollEnd",
290 ExpectedEvents());
291 MouseMove(300, 200);
292 MouseMove(200, 200);
293 EXPECT_EQ("", ExpectedEvents());
294 MouseDown(300, 200);
295 EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
296 MouseDrag(300, 300);
297 EXPECT_EQ(
298 "TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate",
299 ExpectedEvents());
300 MouseDrag(300, 400);
301 EXPECT_EQ("TouchMove GestureScrollUpdate", ExpectedEvents());
302 MouseUp(300, 500);
303 EXPECT_EQ(
304 "TouchMove GestureScrollUpdate TouchEnd GestureScrollEnd",
305 ExpectedEvents());
308 TEST_F(TouchEmulatorTest, Pinch) {
309 MouseDown(100, 200);
310 EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
311 MouseDrag(200, 200);
312 EXPECT_EQ(
313 "TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate",
314 ExpectedEvents());
315 PressShift();
316 EXPECT_EQ("", ExpectedEvents());
317 MouseDrag(300, 200);
318 EXPECT_EQ("TouchMove GesturePinchBegin", ExpectedEvents());
319 ReleaseShift();
320 EXPECT_EQ("", ExpectedEvents());
321 MouseDrag(400, 200);
322 EXPECT_EQ(
323 "TouchMove GesturePinchEnd GestureScrollUpdate",
324 ExpectedEvents());
325 MouseUp(400, 200);
326 EXPECT_EQ("TouchEnd GestureScrollEnd", ExpectedEvents());
329 TEST_F(TouchEmulatorTest, CancelWithDelayedAck) {
330 DisableSynchronousTouchAck();
332 // Simulate a sequence that is interrupted by |CancelTouch()|.
333 MouseDown(100, 200);
334 EXPECT_EQ("TouchStart", ExpectedEvents());
335 MouseDrag(200, 200);
336 EXPECT_EQ("TouchMove", ExpectedEvents());
337 emulator()->CancelTouch();
338 EXPECT_EQ("TouchCancel", ExpectedEvents());
339 // The mouse up should have no effect as the sequence was already cancelled.
340 MouseUp(400, 200);
341 EXPECT_EQ("", ExpectedEvents());
343 // Simulate a sequence that fully completes before |CancelTouch()|.
344 MouseDown(100, 200);
345 EXPECT_EQ("TouchStart", ExpectedEvents());
346 MouseUp(100, 200);
347 EXPECT_EQ("TouchEnd", ExpectedEvents());
348 // |CancelTouch| should have no effect as the sequence was already terminated.
349 emulator()->CancelTouch();
350 EXPECT_EQ("", ExpectedEvents());
353 TEST_F(TouchEmulatorTest, DisableAndReenable) {
354 MouseDown(100, 200);
355 EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
356 MouseDrag(200, 200);
357 EXPECT_EQ(
358 "TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate",
359 ExpectedEvents());
360 PressShift();
361 MouseDrag(300, 200);
362 EXPECT_EQ("TouchMove GesturePinchBegin", ExpectedEvents());
364 // Disable while pinch is in progress.
365 emulator()->Disable();
366 EXPECT_EQ("TouchCancel GesturePinchEnd GestureScrollEnd", ExpectedEvents());
367 MouseUp(300, 200);
368 ReleaseShift();
369 MouseMove(300, 300);
370 EXPECT_EQ("", ExpectedEvents());
372 emulator()->Enable(ui::GestureProviderConfigType::GENERIC_MOBILE);
373 MouseDown(300, 300);
374 EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
375 MouseDrag(300, 400);
376 EXPECT_EQ(
377 "TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate",
378 ExpectedEvents());
380 // Disable while scroll is in progress.
381 emulator()->Disable();
382 EXPECT_EQ("TouchCancel GestureScrollEnd", ExpectedEvents());
385 TEST_F(TouchEmulatorTest, DisableAndReenableDifferentConfig) {
386 MouseDown(100, 200);
387 EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
388 MouseDrag(200, 200);
389 EXPECT_EQ(
390 "TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate",
391 ExpectedEvents());
392 PressShift();
393 MouseDrag(300, 200);
394 EXPECT_EQ("TouchMove GesturePinchBegin", ExpectedEvents());
396 // Disable while pinch is in progress.
397 emulator()->Disable();
398 EXPECT_EQ("TouchCancel GesturePinchEnd GestureScrollEnd", ExpectedEvents());
399 MouseUp(300, 200);
400 ReleaseShift();
401 MouseMove(300, 300);
402 EXPECT_EQ("", ExpectedEvents());
404 emulator()->Enable(ui::GestureProviderConfigType::GENERIC_DESKTOP);
405 MouseDown(300, 300);
406 EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
407 MouseDrag(300, 400);
408 EXPECT_EQ(
409 "TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate",
410 ExpectedEvents());
412 // Disable while scroll is in progress.
413 emulator()->Disable();
414 EXPECT_EQ("TouchCancel GestureScrollEnd", ExpectedEvents());
417 TEST_F(TouchEmulatorTest, MouseMovesDropped) {
418 MouseMove(100, 200);
419 EXPECT_EQ("", ExpectedEvents());
420 MouseDown(100, 200);
421 EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
423 // Mouse move after mouse down is never dropped.
424 set_event_time_delta_seconds_(0.001);
425 MouseDrag(200, 200);
426 EXPECT_EQ(
427 "TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate",
428 ExpectedEvents());
430 // The following mouse moves are dropped.
431 MouseDrag(300, 200);
432 EXPECT_EQ("", ExpectedEvents());
433 MouseDrag(350, 200);
434 EXPECT_EQ("", ExpectedEvents());
436 // Dispatching again.
437 set_event_time_delta_seconds_(0.1);
438 MouseDrag(400, 200);
439 EXPECT_EQ(
440 "TouchMove GestureScrollUpdate",
441 ExpectedEvents());
442 MouseUp(400, 200);
443 EXPECT_EQ(
444 "TouchEnd GestureScrollEnd",
445 ExpectedEvents());
448 TEST_F(TouchEmulatorTest, MouseWheel) {
449 MouseMove(100, 200);
450 EXPECT_EQ("", ExpectedEvents());
451 EXPECT_TRUE(SendMouseWheelEvent());
452 MouseDown(100, 200);
453 EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
454 EXPECT_FALSE(SendMouseWheelEvent());
455 MouseUp(100, 200);
456 EXPECT_EQ("TouchEnd GestureShowPress GestureTap", ExpectedEvents());
457 EXPECT_TRUE(SendMouseWheelEvent());
458 MouseDown(300, 200);
459 EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
460 EXPECT_FALSE(SendMouseWheelEvent());
461 emulator()->Disable();
462 EXPECT_EQ("TouchCancel GestureTapCancel", ExpectedEvents());
463 EXPECT_TRUE(SendMouseWheelEvent());
464 emulator()->Enable(ui::GestureProviderConfigType::GENERIC_MOBILE);
465 EXPECT_TRUE(SendMouseWheelEvent());
468 TEST_F(TouchEmulatorTest, MultipleTouchStreams) {
469 // Native stream should be blocked while emulated is active.
470 MouseMove(100, 200);
471 EXPECT_EQ("", ExpectedEvents());
472 MouseDown(100, 200);
473 EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
474 EXPECT_FALSE(TouchStart(10, 10, true));
475 EXPECT_FALSE(TouchMove(20, 20, true));
476 MouseUp(200, 200);
477 EXPECT_EQ(
478 "TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate"
479 " TouchEnd GestureScrollEnd",
480 ExpectedEvents());
481 EXPECT_FALSE(TouchEnd(20, 20, true));
483 // Emulated stream should be blocked while native is active.
484 EXPECT_TRUE(TouchStart(10, 10, true));
485 EXPECT_TRUE(TouchMove(20, 20, true));
486 MouseDown(300, 200);
487 EXPECT_EQ("", ExpectedEvents());
488 // Re-enabling in the middle of a touch sequence should not affect this.
489 emulator()->Disable();
490 emulator()->Enable(ui::GestureProviderConfigType::GENERIC_MOBILE);
491 MouseDrag(300, 300);
492 EXPECT_EQ("", ExpectedEvents());
493 MouseUp(300, 300);
494 EXPECT_EQ("", ExpectedEvents());
495 EXPECT_TRUE(TouchEnd(20, 20, true));
496 EXPECT_EQ("", ExpectedEvents());
498 // Late ack for TouchEnd should not mess things up.
499 EXPECT_TRUE(TouchStart(10, 10, false));
500 EXPECT_TRUE(TouchMove(20, 20, false));
501 emulator()->Disable();
502 EXPECT_TRUE(TouchEnd(20, 20, false));
503 EXPECT_TRUE(TouchStart(30, 30, false));
504 AckOldestTouchEvent(); // TouchStart.
505 emulator()->Enable(ui::GestureProviderConfigType::GENERIC_MOBILE);
506 AckOldestTouchEvent(); // TouchMove.
507 AckOldestTouchEvent(); // TouchEnd.
508 MouseDown(300, 200);
509 EXPECT_EQ("", ExpectedEvents());
510 MouseDrag(300, 300);
511 EXPECT_EQ("", ExpectedEvents());
512 MouseUp(300, 300);
513 EXPECT_EQ("", ExpectedEvents());
514 AckOldestTouchEvent(); // TouchStart.
515 MouseDown(300, 200);
516 EXPECT_EQ("", ExpectedEvents());
517 EXPECT_TRUE(TouchMove(30, 40, true));
518 EXPECT_TRUE(TouchEnd(30, 40, true));
519 MouseUp(300, 200);
520 EXPECT_EQ("", ExpectedEvents());
522 // Emulation should be back to normal.
523 MouseDown(100, 200);
524 EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
525 MouseUp(200, 200);
526 EXPECT_EQ(
527 "TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate"
528 " TouchEnd GestureScrollEnd",
529 ExpectedEvents());
532 TEST_F(TouchEmulatorTest, MultipleTouchStreamsLateEnable) {
533 // Enabling in the middle of native touch sequence should be handled.
534 // Send artificial late TouchEnd ack, like it is the first thing emulator
535 // does see.
536 WebTouchEvent event = MakeTouchEvent(
537 WebInputEvent::TouchEnd, WebTouchPoint::StateReleased, 10, 10);
538 EXPECT_FALSE(emulator()->HandleTouchEventAck(
539 event, INPUT_EVENT_ACK_STATE_CONSUMED));
541 MouseDown(100, 200);
542 EXPECT_EQ("TouchStart GestureTapDown", ExpectedEvents());
543 MouseUp(200, 200);
544 EXPECT_EQ(
545 "TouchMove GestureTapCancel GestureScrollBegin GestureScrollUpdate"
546 " TouchEnd GestureScrollEnd",
547 ExpectedEvents());
550 TEST_F(TouchEmulatorTest, CancelAfterDisableDoesNotCrash) {
551 DisableSynchronousTouchAck();
552 MouseDown(100, 200);
553 emulator()->Disable();
554 EXPECT_EQ("TouchStart TouchCancel", ExpectedEvents());
555 emulator()->CancelTouch();
558 TEST_F(TouchEmulatorTest, ConstructorWithHighDeviceScaleDoesNotCrash) {
559 TouchEmulator(this, 4.0f);
562 } // namespace content