Refactor android test results logging.
[chromium-blink-merge.git] / ppapi / tests / test_input_event.cc
blobc55912d2046fb3687eb74ce718ed176b914d6158
1 // Copyright (c) 2012 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 "ppapi/tests/test_input_event.h"
7 #include "ppapi/c/dev/ppb_testing_dev.h"
8 #include "ppapi/c/pp_errors.h"
9 #include "ppapi/c/ppb_input_event.h"
10 #include "ppapi/cpp/input_event.h"
11 #include "ppapi/cpp/module.h"
12 #include "ppapi/tests/test_utils.h"
13 #include "ppapi/tests/testing_instance.h"
15 REGISTER_TEST_CASE(InputEvent);
17 namespace {
19 const uint32_t kSpaceChar = 0x20;
20 const char* kSpaceString = " ";
22 #define FINISHED_WAITING_MESSAGE "TEST_INPUT_EVENT_FINISHED_WAITING"
24 pp::Point GetCenter(const pp::Rect& rect) {
25 return pp::Point(
26 rect.x() + rect.width() / 2,
27 rect.y() + rect.height() / 2);
30 } // namespace
32 void TestInputEvent::RunTests(const std::string& filter) {
33 RUN_TEST(Events, filter);
35 // Like RUN_TEST, but does an exact match with the filter (which means it does
36 // not run the test if filter is empty).
37 #define RUN_TEST_EXACT_MATCH(name, test_filter) \
38 if (test_filter == #name) { \
39 set_callback_type(PP_OPTIONAL); \
40 instance_->LogTest(#name, CheckResourcesAndVars(Test##name())); \
43 RUN_TEST_EXACT_MATCH(AcceptTouchEvent_1, filter);
44 RUN_TEST_EXACT_MATCH(AcceptTouchEvent_2, filter);
45 RUN_TEST_EXACT_MATCH(AcceptTouchEvent_3, filter);
46 RUN_TEST_EXACT_MATCH(AcceptTouchEvent_4, filter);
48 #undef RUN_TEST_EXACT_MATCH
51 TestInputEvent::TestInputEvent(TestingInstance* instance)
52 : TestCase(instance),
53 input_event_interface_(NULL),
54 mouse_input_event_interface_(NULL),
55 wheel_input_event_interface_(NULL),
56 keyboard_input_event_interface_(NULL),
57 touch_input_event_interface_(NULL),
58 view_rect_(),
59 expected_input_event_(0),
60 received_expected_event_(false),
61 received_finish_message_(false) {
64 TestInputEvent::~TestInputEvent() {
65 // Remove the special listener that only responds to a
66 // FINISHED_WAITING_MESSAGE string. See Init for where it gets added.
67 std::string js_code;
68 js_code += "var plugin = document.getElementById('plugin');"
69 "plugin.removeEventListener('message',"
70 " plugin.wait_for_messages_handler);"
71 "delete plugin.wait_for_messages_handler;";
72 instance_->EvalScript(js_code);
75 bool TestInputEvent::Init() {
76 input_event_interface_ = static_cast<const PPB_InputEvent*>(
77 pp::Module::Get()->GetBrowserInterface(PPB_INPUT_EVENT_INTERFACE));
78 mouse_input_event_interface_ = static_cast<const PPB_MouseInputEvent*>(
79 pp::Module::Get()->GetBrowserInterface(
80 PPB_MOUSE_INPUT_EVENT_INTERFACE));
81 wheel_input_event_interface_ = static_cast<const PPB_WheelInputEvent*>(
82 pp::Module::Get()->GetBrowserInterface(
83 PPB_WHEEL_INPUT_EVENT_INTERFACE));
84 keyboard_input_event_interface_ = static_cast<const PPB_KeyboardInputEvent*>(
85 pp::Module::Get()->GetBrowserInterface(
86 PPB_KEYBOARD_INPUT_EVENT_INTERFACE));
87 touch_input_event_interface_ = static_cast<const PPB_TouchInputEvent*>(
88 pp::Module::Get()->GetBrowserInterface(
89 PPB_TOUCH_INPUT_EVENT_INTERFACE));
91 bool success =
92 input_event_interface_ &&
93 mouse_input_event_interface_ &&
94 wheel_input_event_interface_ &&
95 keyboard_input_event_interface_ &&
96 touch_input_event_interface_ &&
97 CheckTestingInterface();
99 // Set up a listener for our message that signals that all input events have
100 // been received.
101 std::string js_code;
102 // Note the following code is dependent on some features of test_case.html.
103 // E.g., it is assumed that the DOM element where the plugin is embedded has
104 // an id of 'plugin', and there is a function 'IsTestingMessage' that allows
105 // us to ignore the messages that are intended for use by the testing
106 // framework itself.
107 js_code += "var plugin = document.getElementById('plugin');"
108 "var wait_for_messages_handler = function(message_event) {"
109 " if (!IsTestingMessage(message_event.data) &&"
110 " message_event.data === '" FINISHED_WAITING_MESSAGE "') {"
111 " plugin.postMessage('" FINISHED_WAITING_MESSAGE "');"
112 " }"
113 "};"
114 "plugin.addEventListener('message', wait_for_messages_handler);"
115 // Stash it on the plugin so we can remove it in the destructor.
116 "plugin.wait_for_messages_handler = wait_for_messages_handler;";
117 instance_->EvalScript(js_code);
119 return success;
122 pp::InputEvent TestInputEvent::CreateMouseEvent(
123 PP_InputEvent_Type type,
124 PP_InputEvent_MouseButton buttons) {
125 return pp::MouseInputEvent(
126 instance_,
127 type,
128 100, // time_stamp
129 0, // modifiers
130 buttons,
131 GetCenter(view_rect_),
132 1, // click count
133 pp::Point()); // movement
136 pp::InputEvent TestInputEvent::CreateWheelEvent() {
137 return pp::WheelInputEvent(
138 instance_,
139 100, // time_stamp
140 0, // modifiers
141 pp::FloatPoint(1, 2),
142 pp::FloatPoint(3, 4),
143 PP_TRUE); // scroll_by_page
146 pp::InputEvent TestInputEvent::CreateKeyEvent(PP_InputEvent_Type type,
147 uint32_t key_code) {
148 return pp::KeyboardInputEvent(
149 instance_,
150 type,
151 100, // time_stamp
152 0, // modifiers
153 key_code,
154 pp::Var());
157 pp::InputEvent TestInputEvent::CreateCharEvent(const std::string& text) {
158 return pp::KeyboardInputEvent(
159 instance_,
160 PP_INPUTEVENT_TYPE_CHAR,
161 100, // time_stamp
162 0, // modifiers
163 0, // keycode
164 pp::Var(text));
167 pp::InputEvent TestInputEvent::CreateTouchEvent(PP_InputEvent_Type type,
168 const pp::FloatPoint& point) {
169 PP_TouchPoint touch_point = PP_MakeTouchPoint();
170 touch_point.position = point;
172 pp::TouchInputEvent touch_event(instance_, type, 100, 0);
173 touch_event.AddTouchPoint(PP_TOUCHLIST_TYPE_TOUCHES, touch_point);
174 touch_event.AddTouchPoint(PP_TOUCHLIST_TYPE_CHANGEDTOUCHES, touch_point);
175 touch_event.AddTouchPoint(PP_TOUCHLIST_TYPE_TARGETTOUCHES, touch_point);
177 return touch_event;
180 // Simulates the input event and calls PostMessage to let us know when
181 // we have received all resulting events from the browser.
182 bool TestInputEvent::SimulateInputEvent(
183 const pp::InputEvent& input_event) {
184 expected_input_event_ = pp::InputEvent(input_event.pp_resource());
185 received_expected_event_ = false;
186 received_finish_message_ = false;
187 testing_interface_->SimulateInputEvent(instance_->pp_instance(),
188 input_event.pp_resource());
189 instance_->PostMessage(pp::Var(FINISHED_WAITING_MESSAGE));
190 testing_interface_->RunMessageLoop(instance_->pp_instance());
191 return received_finish_message_ && received_expected_event_;
194 bool TestInputEvent::AreEquivalentEvents(PP_Resource received,
195 PP_Resource expected) {
196 if (!input_event_interface_->IsInputEvent(received) ||
197 !input_event_interface_->IsInputEvent(expected)) {
198 return false;
201 // Test common fields, except modifiers and time stamp, which may be changed
202 // by the browser.
203 int32_t received_type = input_event_interface_->GetType(received);
204 int32_t expected_type = input_event_interface_->GetType(expected);
205 if (received_type != expected_type) {
206 // Allow key down events to match "raw" key down events.
207 if (expected_type != PP_INPUTEVENT_TYPE_KEYDOWN &&
208 received_type != PP_INPUTEVENT_TYPE_RAWKEYDOWN) {
209 return false;
213 // Test event type-specific fields.
214 switch (input_event_interface_->GetType(received)) {
215 case PP_INPUTEVENT_TYPE_MOUSEDOWN:
216 case PP_INPUTEVENT_TYPE_MOUSEUP:
217 case PP_INPUTEVENT_TYPE_MOUSEMOVE:
218 case PP_INPUTEVENT_TYPE_MOUSEENTER:
219 case PP_INPUTEVENT_TYPE_MOUSELEAVE:
220 // Check mouse fields, except position and movement, which may be
221 // modified by the renderer.
222 return
223 mouse_input_event_interface_->GetButton(received) ==
224 mouse_input_event_interface_->GetButton(expected) &&
225 mouse_input_event_interface_->GetClickCount(received) ==
226 mouse_input_event_interface_->GetClickCount(expected);
228 case PP_INPUTEVENT_TYPE_WHEEL:
229 return
230 pp::FloatPoint(wheel_input_event_interface_->GetDelta(received)) ==
231 pp::FloatPoint(wheel_input_event_interface_->GetDelta(expected)) &&
232 pp::FloatPoint(wheel_input_event_interface_->GetTicks(received)) ==
233 pp::FloatPoint(wheel_input_event_interface_->GetTicks(expected)) &&
234 wheel_input_event_interface_->GetScrollByPage(received) ==
235 wheel_input_event_interface_->GetScrollByPage(expected);
237 case PP_INPUTEVENT_TYPE_RAWKEYDOWN:
238 case PP_INPUTEVENT_TYPE_KEYDOWN:
239 case PP_INPUTEVENT_TYPE_KEYUP:
240 return
241 keyboard_input_event_interface_->GetKeyCode(received) ==
242 keyboard_input_event_interface_->GetKeyCode(expected);
244 case PP_INPUTEVENT_TYPE_CHAR:
245 return
246 keyboard_input_event_interface_->GetKeyCode(received) ==
247 keyboard_input_event_interface_->GetKeyCode(expected) &&
248 pp::Var(pp::PASS_REF,
249 keyboard_input_event_interface_->GetCharacterText(received)) ==
250 pp::Var(pp::PASS_REF,
251 keyboard_input_event_interface_->GetCharacterText(expected));
253 case PP_INPUTEVENT_TYPE_TOUCHSTART:
254 case PP_INPUTEVENT_TYPE_TOUCHMOVE:
255 case PP_INPUTEVENT_TYPE_TOUCHEND:
256 case PP_INPUTEVENT_TYPE_TOUCHCANCEL: {
257 if (!touch_input_event_interface_->IsTouchInputEvent(received) ||
258 !touch_input_event_interface_->IsTouchInputEvent(expected))
259 return false;
261 uint32_t touch_count = touch_input_event_interface_->GetTouchCount(
262 received, PP_TOUCHLIST_TYPE_TOUCHES);
263 if (touch_count <= 0 ||
264 touch_count != touch_input_event_interface_->GetTouchCount(expected,
265 PP_TOUCHLIST_TYPE_TOUCHES))
266 return false;
268 for (uint32_t i = 0; i < touch_count; ++i) {
269 PP_TouchPoint expected_point = touch_input_event_interface_->
270 GetTouchByIndex(expected, PP_TOUCHLIST_TYPE_TOUCHES, i);
271 PP_TouchPoint received_point = touch_input_event_interface_->
272 GetTouchByIndex(received, PP_TOUCHLIST_TYPE_TOUCHES, i);
274 if (expected_point.id != received_point.id ||
275 expected_point.radius != received_point.radius ||
276 expected_point.rotation_angle != received_point.rotation_angle ||
277 expected_point.pressure != received_point.pressure)
278 return false;
280 if (expected_point.position.x != received_point.position.x ||
281 expected_point.position.y != received_point.position.y)
282 return false;
284 return true;
287 default:
288 break;
291 return false;
294 bool TestInputEvent::HandleInputEvent(const pp::InputEvent& input_event) {
295 // Some events may cause extra events to be generated, so look for the
296 // first one that matches.
297 if (!received_expected_event_) {
298 received_expected_event_ = AreEquivalentEvents(
299 input_event.pp_resource(),
300 expected_input_event_.pp_resource());
302 // Handle all input events.
303 return true;
306 void TestInputEvent::HandleMessage(const pp::Var& message_data) {
307 if (message_data.is_string() &&
308 (message_data.AsString() == FINISHED_WAITING_MESSAGE)) {
309 testing_interface_->QuitMessageLoop(instance_->pp_instance());
310 received_finish_message_ = true;
314 void TestInputEvent::DidChangeView(const pp::View& view) {
315 view_rect_ = view.GetRect();
318 std::string TestInputEvent::TestEvents() {
319 // Request all input event classes.
320 input_event_interface_->RequestInputEvents(instance_->pp_instance(),
321 PP_INPUTEVENT_CLASS_MOUSE |
322 PP_INPUTEVENT_CLASS_WHEEL |
323 PP_INPUTEVENT_CLASS_KEYBOARD |
324 PP_INPUTEVENT_CLASS_TOUCH);
325 // Send the events and check that we received them.
326 ASSERT_TRUE(
327 SimulateInputEvent(CreateMouseEvent(PP_INPUTEVENT_TYPE_MOUSEDOWN,
328 PP_INPUTEVENT_MOUSEBUTTON_LEFT)));
329 ASSERT_TRUE(
330 SimulateInputEvent(CreateWheelEvent()));
331 ASSERT_TRUE(
332 SimulateInputEvent(CreateKeyEvent(PP_INPUTEVENT_TYPE_KEYDOWN,
333 kSpaceChar)));
334 ASSERT_TRUE(
335 SimulateInputEvent(CreateCharEvent(kSpaceString)));
336 ASSERT_TRUE(SimulateInputEvent(CreateTouchEvent(PP_INPUTEVENT_TYPE_TOUCHSTART,
337 pp::FloatPoint(12, 23))));
338 // Request only mouse events.
339 input_event_interface_->ClearInputEventRequest(instance_->pp_instance(),
340 PP_INPUTEVENT_CLASS_WHEEL |
341 PP_INPUTEVENT_CLASS_KEYBOARD);
342 // Check that we only receive mouse events.
343 ASSERT_TRUE(
344 SimulateInputEvent(CreateMouseEvent(PP_INPUTEVENT_TYPE_MOUSEDOWN,
345 PP_INPUTEVENT_MOUSEBUTTON_LEFT)));
346 ASSERT_FALSE(
347 SimulateInputEvent(CreateWheelEvent()));
348 ASSERT_FALSE(
349 SimulateInputEvent(CreateKeyEvent(PP_INPUTEVENT_TYPE_KEYDOWN,
350 kSpaceChar)));
351 ASSERT_FALSE(
352 SimulateInputEvent(CreateCharEvent(kSpaceString)));
354 PASS();
357 std::string TestInputEvent::TestAcceptTouchEvent_1() {
358 // The browser normally sends touch-events to the renderer only if the page
359 // has touch-event handlers. Since test-case.html does not have any
360 // touch-event handler, it would normally not receive any touch events from
361 // the browser. However, if a plugin in the page does accept touch events,
362 // then the browser should start sending touch-events to the page. In this
363 // test, the plugin simply registers for touch-events. The real test is to
364 // verify that the browser knows to send touch-events to the renderer.
365 // If the plugin is removed from the page, then there are no more touch-event
366 // handlers in the page, and browser stops sending touch-events. So to make
367 // it possible to test this properly, the plugin is not removed from the page
368 // at the end of the test.
369 instance_->set_remove_plugin(false);
370 input_event_interface_->RequestInputEvents(instance_->pp_instance(),
371 PP_INPUTEVENT_CLASS_MOUSE |
372 PP_INPUTEVENT_CLASS_WHEEL |
373 PP_INPUTEVENT_CLASS_KEYBOARD |
374 PP_INPUTEVENT_CLASS_TOUCH);
375 PASS();
378 std::string TestInputEvent::TestAcceptTouchEvent_2() {
379 // See comment in TestAcceptTouchEvent_1.
380 instance_->set_remove_plugin(false);
381 input_event_interface_->RequestInputEvents(instance_->pp_instance(),
382 PP_INPUTEVENT_CLASS_MOUSE |
383 PP_INPUTEVENT_CLASS_WHEEL |
384 PP_INPUTEVENT_CLASS_KEYBOARD |
385 PP_INPUTEVENT_CLASS_TOUCH);
386 input_event_interface_->ClearInputEventRequest(instance_->pp_instance(),
387 PP_INPUTEVENT_CLASS_TOUCH);
388 PASS();
391 std::string TestInputEvent::TestAcceptTouchEvent_3() {
392 // See comment in TestAcceptTouchEvent_1.
393 instance_->set_remove_plugin(false);
394 input_event_interface_->RequestInputEvents(instance_->pp_instance(),
395 PP_INPUTEVENT_CLASS_MOUSE |
396 PP_INPUTEVENT_CLASS_WHEEL |
397 PP_INPUTEVENT_CLASS_KEYBOARD);
398 input_event_interface_->RequestFilteringInputEvents(instance_->pp_instance(),
399 PP_INPUTEVENT_CLASS_TOUCH);
400 PASS();
403 std::string TestInputEvent::TestAcceptTouchEvent_4() {
404 // See comment in TestAcceptTouchEvent_1.
405 instance_->set_remove_plugin(false);
406 input_event_interface_->RequestInputEvents(instance_->pp_instance(),
407 PP_INPUTEVENT_CLASS_MOUSE |
408 PP_INPUTEVENT_CLASS_WHEEL |
409 PP_INPUTEVENT_CLASS_KEYBOARD);
410 input_event_interface_->RequestInputEvents(instance_->pp_instance(),
411 PP_INPUTEVENT_CLASS_TOUCH);
412 PASS();