Add button press and grab test

* tests/seat_test.c (enum test_expect_event_kind): Add leave and
button events.
(struct test_expect_data): Remove structure.
(struct test_recorded_event): New structure.
(struct test_recorded_leave_event)
(struct test_recorded_button_event)
(struct test_recorded_frame_event)
(struct test_recorded_enter_event)
(struct test_recorded_motion_event): New structures.  Replace
old event verification mechanism with a mechanism for recording
events sent from the pointer device. and verifying them later.
(enum test_kind, test_names): Add TEST_CLICK_KIND.
(LAST_TEST): Set to TEST_CLICK_KIND.
(num_listener_data, current_listener_data): Remove variables.
(recording_events, record_tail): New variables.
(run_click_test, test_single_step): Implement new kind of test.
(record_events, expect_button_event, expect_frame_event)
(expect_enter_event, expect_motion_event, expect_leave_event)
(expect_button_event, expect_no_events): New functions for
recording and inspecting input events.
(expect_surface_enter, expect_surface_motion): Reimplement in
terms of those functions.
(get_next_expect_data): Delete function.
(handle_pointer_enter, handle_pointer_leave, handle_pointer_motion)
(handle_pointer_button, handle_pointer_frame): Record events
instead of matching them against a list of verified events.
This commit is contained in:
hujianwei 2022-11-07 10:23:12 +00:00
parent 13a399bd35
commit b487cbe320

View file

@ -20,39 +20,83 @@ along with 12to11. If not, see <https://www.gnu.org/licenses/>. */
#include "test_harness.h" #include "test_harness.h"
#include <X11/extensions/XI2.h> #include <X11/extensions/XI2.h>
#include <linux/input-event-codes.h>
enum test_expect_event_kind enum test_expect_event_kind
{ {
POINTER_ENTER_EVENT, POINTER_ENTER_EVENT,
POINTER_FRAME_EVENT, POINTER_FRAME_EVENT,
POINTER_MOTION_EVENT, POINTER_MOTION_EVENT,
POINTER_LEAVE_EVENT,
POINTER_BUTTON_EVENT,
}; };
struct test_expect_data struct test_recorded_event
{ {
/* The coordinates of the event. */ /* What kind of event this is. */
double x, y;
/* What kind of event is being waited for. */
enum test_expect_event_kind kind; enum test_expect_event_kind kind;
/* Whether or not the expected event arrived. */ /* The last event. */
bool arrived; struct test_recorded_event *last;
};
struct test_recorded_enter_event
{
/* The event header. */
struct test_recorded_event header;
/* The surface of the event. */
struct wl_surface *surface;
/* The coordinates of the event. */
double x, y;
};
struct test_recorded_frame_event
{
/* The event header. */
struct test_recorded_event header;
};
struct test_recorded_motion_event
{
/* The event header. */
struct test_recorded_event header;
/* The coordinates of the event. */
double x, y;
};
struct test_recorded_leave_event
{
/* The event header. */
struct test_recorded_event header;
};
struct test_recorded_button_event
{
/* The event header. */
struct test_recorded_event header;
/* The button and state. */
uint32_t button, state;
}; };
enum test_kind enum test_kind
{ {
MAP_WINDOW_KIND, MAP_WINDOW_KIND,
TEST_ENTRY_KIND, TEST_ENTRY_KIND,
TEST_CLICK_KIND,
}; };
static const char *test_names[] = static const char *test_names[] =
{ {
"map_window", "map_window",
"test_entry", "test_entry",
"test_click",
}; };
#define LAST_TEST TEST_ENTRY_KIND #define LAST_TEST TEST_CLICK_KIND
#define TEST_SOURCE_DEVICE 4500000 #define TEST_SOURCE_DEVICE 4500000
/* The display. */ /* The display. */
@ -71,11 +115,11 @@ static Window test_surface_window;
static struct test_surface *test_surface; static struct test_surface *test_surface;
static struct wl_surface *wayland_surface; static struct wl_surface *wayland_surface;
/* How many elements are in the current listener data. */ /* Whether or not events are being recorded. */
static int num_listener_data; static bool recording_events;
/* The current listener data. */ /* If so, the tail of the event list. */
struct test_expect_data *current_listener_data; static struct test_recorded_event *record_tail;
@ -83,6 +127,13 @@ struct test_expect_data *current_listener_data;
static void submit_surface_damage (struct wl_surface *, int, int, int, int); static void submit_surface_damage (struct wl_surface *, int, int, int, int);
static void expect_surface_enter (double, double); static void expect_surface_enter (double, double);
static void expect_surface_motion (double, double); static void expect_surface_motion (double, double);
static void record_events (void);
static void expect_frame_event (void);
static void expect_enter_event (double, double);
static void expect_motion_event (double, double);
static void expect_leave_event (void);
static void expect_button_event (int, int);
static void expect_no_events (void);
@ -110,11 +161,148 @@ test_get_root (void)
static void
run_click_test (struct test_XIButtonState *button_state)
{
/* First, get all events that should already have arrived. */
wl_display_roundtrip (display->display);
/* Next, dispatch the button press events. */
test_seat_controller_dispatch_XI_ButtonPress (display->seat->controller,
test_get_time (),
TEST_SOURCE_DEVICE,
1,
test_get_root (),
test_surface_window,
None,
wl_fixed_from_double (1.0),
wl_fixed_from_double (2.0),
wl_fixed_from_double (1.0),
wl_fixed_from_double (2.0),
0,
button_state,
NULL, NULL, NULL);
test_XIButtonState_add_button (button_state, 1);
test_seat_controller_dispatch_XI_ButtonPress (display->seat->controller,
test_get_time (),
TEST_SOURCE_DEVICE,
2,
test_get_root (),
test_surface_window,
None,
wl_fixed_from_double (1.0),
wl_fixed_from_double (2.0),
wl_fixed_from_double (1.0),
wl_fixed_from_double (2.0),
0,
button_state,
NULL, NULL, NULL);
test_XIButtonState_add_button (button_state, 2);
/* Now, dispatch the motion and leave events. */
test_seat_controller_dispatch_XI_Motion (display->seat->controller,
test_get_time (),
TEST_SOURCE_DEVICE,
0,
test_get_root (),
test_surface_window,
None,
wl_fixed_from_double (550.0),
wl_fixed_from_double (550.0),
wl_fixed_from_double (550.0),
wl_fixed_from_double (550.0),
0,
button_state,
NULL, NULL, NULL);
test_seat_controller_dispatch_XI_Leave (display->seat->controller,
test_get_time (),
TEST_SOURCE_DEVICE,
XINotifyAncestor,
test_get_root (),
test_surface_window,
None,
wl_fixed_from_double (550.0),
wl_fixed_from_double (550.0),
wl_fixed_from_double (550.0),
wl_fixed_from_double (550.0),
XINotifyNormal,
False, True,
button_state, NULL, NULL);
/* And release the buttons. */
test_seat_controller_dispatch_XI_ButtonRelease (display->seat->controller,
test_get_time (),
TEST_SOURCE_DEVICE,
1,
test_get_root (),
test_surface_window,
None,
wl_fixed_from_double (550.0),
wl_fixed_from_double (550.0),
wl_fixed_from_double (550.0),
wl_fixed_from_double (550.0),
0,
button_state,
NULL, NULL, NULL);
test_XIButtonState_remove_button (button_state, 2);
test_seat_controller_dispatch_XI_ButtonRelease (display->seat->controller,
test_get_time (),
TEST_SOURCE_DEVICE,
2,
test_get_root (),
test_surface_window,
None,
wl_fixed_from_double (550.0),
wl_fixed_from_double (550.0),
wl_fixed_from_double (550.0),
wl_fixed_from_double (550.0),
0,
button_state,
NULL, NULL, NULL);
test_XIButtonState_remove_button (button_state, 1);
/* Send the ungrab leave event. */
test_seat_controller_dispatch_XI_Leave (display->seat->controller,
test_get_time (),
TEST_SOURCE_DEVICE,
XINotifyAncestor,
test_get_root (),
test_surface_window,
None,
wl_fixed_from_double (550.0),
wl_fixed_from_double (550.0),
wl_fixed_from_double (550.0),
wl_fixed_from_double (550.0),
XINotifyUngrab,
False, True,
button_state, NULL, NULL);
/* Now, verify the events that arrive. */
record_events ();
expect_frame_event ();
expect_leave_event ();
expect_frame_event ();
expect_button_event (BTN_MIDDLE, WL_POINTER_BUTTON_STATE_RELEASED);
expect_frame_event ();
expect_button_event (BTN_LEFT, WL_POINTER_BUTTON_STATE_RELEASED);
expect_frame_event ();
expect_motion_event (550.0, 550.0);
expect_frame_event ();
expect_button_event (BTN_MIDDLE, WL_POINTER_BUTTON_STATE_PRESSED);
expect_frame_event ();
expect_button_event (BTN_LEFT, WL_POINTER_BUTTON_STATE_PRESSED);
expect_no_events ();
}
static void static void
test_single_step (enum test_kind kind) test_single_step (enum test_kind kind)
{ {
struct wl_buffer *buffer; struct wl_buffer *buffer;
struct test_XIButtonState *button_state;
again:
test_log ("running test step: %s", test_names[kind]); test_log ("running test step: %s", test_names[kind]);
switch (kind) switch (kind)
@ -169,7 +357,39 @@ test_single_step (enum test_kind kind)
/* Expect mouse motion at the specified coordinates. */ /* Expect mouse motion at the specified coordinates. */
expect_surface_motion (1.0, 2.0); expect_surface_motion (1.0, 2.0);
break;
/* Run the click test. */
kind = TEST_CLICK_KIND;
goto again;
case TEST_CLICK_KIND:
/* Test clicking and grab processing. Press buttons 1 and 2,
dispatch a motion event at 550, 550, a NotifyNormal leave
event at 550, 550, and finally button release events for both
buttons followed by a NotifyUngrab leave event. Verify that
only the following events are sent in the given order:
button (SERIAL, TIME, BTN_LEFT, WL_POINTER_BUTTON_STATE_PRESSED)
frame ()
button (SERIAL, TIME, BTN_MIDDLE, WL_POINTER_BUTTON_STATE_PRESSED)
frame ()
motion (TIME, 550.0, 550.0)
frame ()
button (SERIAL, TIME, BTN_LEFT, WL_POINTER_BUTTON_STATE_RELEASED)
frame ()
button (SERIAL, TIME, BTN_MIDDLE, WL_POINTER_BUTTON_STATE_RELEASED)
frame ()
leave ()
frame () */
/* Initialize the button state. */
button_state
= test_seat_controller_get_XIButtonState (display->seat->controller);
if (!button_state)
report_test_failure ("failed to obtain button state resource");
run_click_test (button_state);
} }
if (kind == LAST_TEST) if (kind == LAST_TEST)
@ -178,62 +398,164 @@ test_single_step (enum test_kind kind)
/* Record events previously sent to the seat's pointer or keyboard
device, and place them into `record_tail'. */
static void
record_events (void)
{
recording_events = true;
wl_display_roundtrip (display->display);
recording_events = false;
}
static void
expect_frame_event (void)
{
struct test_recorded_event *event;
event = record_tail;
if (!event)
report_test_failure ("expected event not sent");
record_tail = event->last;
if (event->kind == POINTER_FRAME_EVENT)
free (event);
else
report_test_failure ("a frame event was expected, but not received");
}
static void
expect_enter_event (double x, double y)
{
struct test_recorded_event *event;
struct test_recorded_enter_event *enter;
event = record_tail;
if (!event)
report_test_failure ("expected event not sent");
record_tail = event->last;
if (event->kind == POINTER_ENTER_EVENT)
{
enter = (struct test_recorded_enter_event *) event;
if (enter->x == x && enter->y == y)
free (event);
else
report_test_failure ("expected enter event received "
"with incorrect coordinates");
}
else
report_test_failure ("expected enter event, but it was not received");
}
static void
expect_motion_event (double x, double y)
{
struct test_recorded_event *event;
struct test_recorded_motion_event *motion;
event = record_tail;
if (!event)
report_test_failure ("expected event not sent");
record_tail = event->last;
if (event->kind == POINTER_MOTION_EVENT)
{
motion = (struct test_recorded_motion_event *) event;
if (motion->x == x && motion->y == y)
free (event);
else
report_test_failure ("expected motion event received "
"with incorrect coordinates");
}
else
report_test_failure ("expected motion event, but it was not received");
}
static void
expect_leave_event (void)
{
struct test_recorded_event *event;
event = record_tail;
if (!event)
report_test_failure ("expected event not sent");
record_tail = event->last;
if (event->kind == POINTER_LEAVE_EVENT)
free (event);
else
report_test_failure ("a leave event was expected, but not received");
}
static void
expect_button_event (int button, int state)
{
struct test_recorded_event *event;
struct test_recorded_button_event *button_event;
event = record_tail;
if (!event)
report_test_failure ("expected event not sent");
record_tail = event->last;
if (event->kind == POINTER_BUTTON_EVENT)
{
button_event = (struct test_recorded_button_event *) event;
if (button_event->button == button && button_event->state == state)
free (event);
else
report_test_failure ("expected button event received "
"with incorrect parameters");
}
else
report_test_failure ("expected button event, but it was not received");
}
static void
expect_no_events (void)
{
if (record_tail)
report_test_failure ("expected there to be no more events, "
"yet some arrived");
}
static void static void
expect_surface_enter (double x, double y) expect_surface_enter (double x, double y)
{ {
struct test_expect_data data[2]; /* Record events. */
record_events ();
test_log ("waiting for enter at %g, %g", x, y); /* Expect an enter event, followed by a frame event. */
expect_frame_event ();
memset (data, 0, sizeof data); expect_enter_event (x, y);
expect_no_events ();
data[0].x = x;
data[0].y = y;
data[0].kind = POINTER_ENTER_EVENT;
data[1].kind = POINTER_FRAME_EVENT;
/* Set the current listener data and do a roundtrip. */
current_listener_data = data;
num_listener_data = 2;
wl_display_roundtrip (display->display);
current_listener_data = NULL;
num_listener_data = 0;
/* See whether or not the event arrived. */
if (!data[0].arrived || !data[1].arrived)
report_test_failure ("expected events did not arrive");
else
test_log ("received enter followed by frame");
} }
static void static void
expect_surface_motion (double x, double y) expect_surface_motion (double x, double y)
{ {
struct test_expect_data data[2]; /* Record events. */
record_events ();
test_log ("waiting for motion at %g, %g", x, y); /* Expect a motion event followed by a frame event. */
expect_frame_event ();
memset (data, 0, sizeof data); expect_motion_event (x, y);
expect_no_events ();
data[0].x = x;
data[0].y = y;
data[0].kind = POINTER_MOTION_EVENT;
data[1].kind = POINTER_FRAME_EVENT;
/* Set the current listener data and do a roundtrip. */
current_listener_data = data;
num_listener_data = 2;
wl_display_roundtrip (display->display);
current_listener_data = NULL;
num_listener_data = 0;
/* See whether or not the event arrived. */
if (!data[0].arrived || !data[1].arrived)
report_test_failure ("expected events did not arrive");
else
test_log ("received motion followed by frame");
} }
@ -260,36 +582,14 @@ static const struct test_surface_listener test_surface_listener =
/* Obtain the next test data record. The events arriving are checked
to be in the order in which they arrive in
current_listener_data. */
static struct test_expect_data *
get_next_expect_data (void)
{
int i;
for (i = 0; i < num_listener_data; ++i)
{
if (current_listener_data[i].arrived)
continue;
return &current_listener_data[i];
}
return NULL;
}
static void static void
handle_pointer_enter (void *data, struct wl_pointer *wl_pointer, handle_pointer_enter (void *data, struct wl_pointer *wl_pointer,
uint32_t serial, struct wl_surface *surface, uint32_t serial, struct wl_surface *surface,
wl_fixed_t surface_x, wl_fixed_t surface_y) wl_fixed_t surface_x, wl_fixed_t surface_y)
{ {
struct test_expect_data *test_data; struct test_recorded_enter_event *event;
test_data = get_next_expect_data (); if (!recording_events)
if (!test_data)
{ {
test_log ("ignored enter event at %g %g", test_log ("ignored enter event at %g %g",
wl_fixed_to_double (surface_x), wl_fixed_to_double (surface_x),
@ -297,26 +597,40 @@ handle_pointer_enter (void *data, struct wl_pointer *wl_pointer,
return; return;
} }
if (test_data->kind != POINTER_ENTER_EVENT) event = malloc (sizeof *event);
return;
test_log ("got enter event at %g, %g", if (!event)
wl_fixed_to_double (surface_x), report_test_failure ("failed to record event");
wl_fixed_to_double (surface_y));
if (test_data->x == wl_fixed_to_double (surface_x) event->header.kind = POINTER_ENTER_EVENT;
&& test_data->y == wl_fixed_to_double (surface_y)) event->header.last = record_tail;
test_data->arrived = true; record_tail = &event->header;
else
report_test_failure ("missed enter event at %g %g", event->x = wl_fixed_to_double (surface_x);
test_data->x, test_data->y); event->y = wl_fixed_to_double (surface_x);
event->surface = surface;
} }
static void static void
handle_pointer_leave (void *data, struct wl_pointer *wl_pointer, handle_pointer_leave (void *data, struct wl_pointer *wl_pointer,
uint32_t serial, struct wl_surface *surface) uint32_t serial, struct wl_surface *surface)
{ {
/* ... */ struct test_recorded_leave_event *event;
if (!recording_events)
{
test_log ("ignored leave event");
return;
}
event = malloc (sizeof *event);
if (!event)
report_test_failure ("failed to record event");
event->header.kind = POINTER_LEAVE_EVENT;
event->header.last = record_tail;
record_tail = &event->header;
} }
static void static void
@ -324,11 +638,9 @@ handle_pointer_motion (void *data, struct wl_pointer *wl_pointer,
uint32_t time, wl_fixed_t surface_x, uint32_t time, wl_fixed_t surface_x,
wl_fixed_t surface_y) wl_fixed_t surface_y)
{ {
struct test_expect_data *test_data; struct test_recorded_motion_event *event;
test_data = get_next_expect_data (); if (!recording_events)
if (!test_data)
{ {
test_log ("ignored motion event at %g %g", test_log ("ignored motion event at %g %g",
wl_fixed_to_double (surface_x), wl_fixed_to_double (surface_x),
@ -336,19 +648,17 @@ handle_pointer_motion (void *data, struct wl_pointer *wl_pointer,
return; return;
} }
if (test_data->kind != POINTER_MOTION_EVENT) event = malloc (sizeof *event);
return;
test_log ("got motion event at %g, %g", if (!event)
wl_fixed_to_double (surface_x), report_test_failure ("failed to record event");
wl_fixed_to_double (surface_y));
if (test_data->x == wl_fixed_to_double (surface_x) event->header.kind = POINTER_MOTION_EVENT;
&& test_data->y == wl_fixed_to_double (surface_y)) event->header.last = record_tail;
test_data->arrived = true; record_tail = &event->header;
else
report_test_failure ("missed motion event at %g %g", event->x = wl_fixed_to_double (surface_x);
test_data->x, test_data->y); event->y = wl_fixed_to_double (surface_y);
} }
static void static void
@ -356,7 +666,34 @@ handle_pointer_button (void *data, struct wl_pointer *wl_pointer,
uint32_t serial, uint32_t time, uint32_t button, uint32_t serial, uint32_t time, uint32_t button,
uint32_t state) uint32_t state)
{ {
/* TODO... */ struct test_recorded_button_event *event;
if (!recording_events)
{
test_log ("ignored button event");
return;
}
event = malloc (sizeof *event);
if (!event)
report_test_failure ("failed to record event");
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak"
#endif
event->header.kind = POINTER_BUTTON_EVENT;
event->header.last = record_tail;
record_tail = &event->header;
event->button = button;
event->state = state;
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
} }
static void static void
@ -369,21 +706,31 @@ handle_pointer_axis (void *data, struct wl_pointer *wl_pointer,
static void static void
handle_pointer_frame (void *data, struct wl_pointer *wl_pointer) handle_pointer_frame (void *data, struct wl_pointer *wl_pointer)
{ {
struct test_expect_data *test_data; struct test_recorded_frame_event *event;
test_data = get_next_expect_data (); if (!recording_events)
if (!test_data)
{ {
test_log ("ignored frame event"); test_log ("ignored frame event");
return; return;
} }
if (test_data->kind != POINTER_FRAME_EVENT) event = malloc (sizeof *event);
return;
test_log ("got frame event"); if (!event)
test_data->arrived = true; report_test_failure ("failed to record event");
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak"
#endif
event->header.kind = POINTER_FRAME_EVENT;
event->header.last = record_tail;
record_tail = &event->header;
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
} }
static void static void