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 <X11/extensions/XI2.h>
#include <linux/input-event-codes.h>
enum test_expect_event_kind
{
POINTER_ENTER_EVENT,
POINTER_FRAME_EVENT,
POINTER_MOTION_EVENT,
POINTER_LEAVE_EVENT,
POINTER_BUTTON_EVENT,
};
struct test_expect_data
struct test_recorded_event
{
/* The coordinates of the event. */
double x, y;
/* What kind of event is being waited for. */
/* What kind of event this is. */
enum test_expect_event_kind kind;
/* Whether or not the expected event arrived. */
bool arrived;
/* The last event. */
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
{
MAP_WINDOW_KIND,
TEST_ENTRY_KIND,
TEST_CLICK_KIND,
};
static const char *test_names[] =
{
"map_window",
"test_entry",
"test_click",
};
#define LAST_TEST TEST_ENTRY_KIND
#define LAST_TEST TEST_CLICK_KIND
#define TEST_SOURCE_DEVICE 4500000
/* The display. */
@ -71,11 +115,11 @@ static Window test_surface_window;
static struct test_surface *test_surface;
static struct wl_surface *wayland_surface;
/* How many elements are in the current listener data. */
static int num_listener_data;
/* Whether or not events are being recorded. */
static bool recording_events;
/* The current listener data. */
struct test_expect_data *current_listener_data;
/* If so, the tail of the event list. */
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 expect_surface_enter (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
test_single_step (enum test_kind kind)
{
struct wl_buffer *buffer;
struct test_XIButtonState *button_state;
again:
test_log ("running test step: %s", test_names[kind]);
switch (kind)
@ -169,7 +357,39 @@ test_single_step (enum test_kind kind)
/* Expect mouse motion at the specified coordinates. */
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)
@ -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
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);
memset (data, 0, sizeof data);
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");
/* Expect an enter event, followed by a frame event. */
expect_frame_event ();
expect_enter_event (x, y);
expect_no_events ();
}
static void
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);
memset (data, 0, sizeof data);
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");
/* Expect a motion event followed by a frame event. */
expect_frame_event ();
expect_motion_event (x, y);
expect_no_events ();
}
@ -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
handle_pointer_enter (void *data, struct wl_pointer *wl_pointer,
uint32_t serial, struct wl_surface *surface,
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 (!test_data)
if (!recording_events)
{
test_log ("ignored enter event at %g %g",
wl_fixed_to_double (surface_x),
@ -297,26 +597,40 @@ handle_pointer_enter (void *data, struct wl_pointer *wl_pointer,
return;
}
if (test_data->kind != POINTER_ENTER_EVENT)
return;
event = malloc (sizeof *event);
test_log ("got enter event at %g, %g",
wl_fixed_to_double (surface_x),
wl_fixed_to_double (surface_y));
if (!event)
report_test_failure ("failed to record event");
if (test_data->x == wl_fixed_to_double (surface_x)
&& test_data->y == wl_fixed_to_double (surface_y))
test_data->arrived = true;
else
report_test_failure ("missed enter event at %g %g",
test_data->x, test_data->y);
event->header.kind = POINTER_ENTER_EVENT;
event->header.last = record_tail;
record_tail = &event->header;
event->x = wl_fixed_to_double (surface_x);
event->y = wl_fixed_to_double (surface_x);
event->surface = surface;
}
static void
handle_pointer_leave (void *data, struct wl_pointer *wl_pointer,
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
@ -324,11 +638,9 @@ handle_pointer_motion (void *data, struct wl_pointer *wl_pointer,
uint32_t time, wl_fixed_t surface_x,
wl_fixed_t surface_y)
{
struct test_expect_data *test_data;
struct test_recorded_motion_event *event;
test_data = get_next_expect_data ();
if (!test_data)
if (!recording_events)
{
test_log ("ignored motion event at %g %g",
wl_fixed_to_double (surface_x),
@ -336,19 +648,17 @@ handle_pointer_motion (void *data, struct wl_pointer *wl_pointer,
return;
}
if (test_data->kind != POINTER_MOTION_EVENT)
return;
event = malloc (sizeof *event);
test_log ("got motion event at %g, %g",
wl_fixed_to_double (surface_x),
wl_fixed_to_double (surface_y));
if (!event)
report_test_failure ("failed to record event");
if (test_data->x == wl_fixed_to_double (surface_x)
&& test_data->y == wl_fixed_to_double (surface_y))
test_data->arrived = true;
else
report_test_failure ("missed motion event at %g %g",
test_data->x, test_data->y);
event->header.kind = POINTER_MOTION_EVENT;
event->header.last = record_tail;
record_tail = &event->header;
event->x = wl_fixed_to_double (surface_x);
event->y = wl_fixed_to_double (surface_y);
}
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 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
@ -369,21 +706,31 @@ handle_pointer_axis (void *data, struct wl_pointer *wl_pointer,
static void
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 (!test_data)
if (!recording_events)
{
test_log ("ignored frame event");
return;
}
if (test_data->kind != POINTER_FRAME_EVENT)
return;
event = malloc (sizeof *event);
test_log ("got frame event");
test_data->arrived = true;
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_FRAME_EVENT;
event->header.last = record_tail;
record_tail = &event->header;
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
}
static void