libei/test/test-ei.c
Peter Hutterer d99e42b808 Add timestamps to frame events
Currently only implemented for frame events, the vague plan for the
future is to merely queue the device events internally and "release"
them once a frame event was received, retrofitting the timestamp to the
C event struct (i.e. making ei_event_get_time() available on all device
events).

Meanwhile, the frame event it is.
2022-05-17 07:18:41 +10:00

952 lines
27 KiB
C

/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2020 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "config.h"
#include <unistd.h>
#include <fcntl.h>
#include "util-munit.h"
#include "util-strings.h"
#include "eierpecken.h"
MUNIT_TEST(test_ei_ref_unref)
{
struct ei *ei = ei_new(NULL);
struct ei *refd = ei_ref(ei);
munit_assert_ptr_equal(ei, refd);
struct ei *unrefd = ei_unref(ei);
munit_assert_ptr_null(unrefd);
unrefd = ei_unref(ei);
munit_assert_ptr_null(unrefd);
/* memleak only shows up in valgrind */
return MUNIT_OK;
}
MUNIT_TEST(test_ei_initial_properties)
{
_unref_(peck) *peck = peck_new();
char pid[64];
_cleanup_free_ char *cmdline = cmdline_as_str();
xsnprintf(pid, sizeof(pid), "%i", getpid());
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_NONE);
peck_dispatch_until_stable(peck);
with_server(peck) {
_unref_(eis_event) *connect =
peck_eis_next_event(eis, EIS_EVENT_CLIENT_CONNECT);
struct eis_client *client = eis_event_get_client(connect);
const char *pidprop = eis_client_property_get(client, "ei.application.pid");
munit_assert_ptr_not_null(pidprop);
munit_assert_string_equal(pidprop, pid);
const char *cmdprop = eis_client_property_get(client, "ei.application.cmdline");
munit_assert_ptr_not_null(cmdprop);
munit_assert_string_equal(cmdprop, cmdline);
}
return MUNIT_OK;
}
MUNIT_TEST(test_ei_properties)
{
_unref_(peck) *peck = peck_new();
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL);
peck_dispatch_until_stable(peck);
with_client(peck) {
ei_property_set(ei, "foo.bar", "value");
}
peck_dispatch_until_stable(peck);
with_server(peck) {
_unref_(eis_event) *e =
peck_eis_next_event(eis, EIS_EVENT_CLIENT_PROPERTY);
const char *name = eis_event_property_get_name(e);
const char *value = eis_event_property_get_value(e);
munit_assert_string_equal(name, "foo.bar");
munit_assert_string_equal(value, "value");
}
with_client(peck) {
int rc = ei_property_set(ei, "foo.bar", "newval");
munit_assert_int(rc, ==, 0);
}
peck_dispatch_until_stable(peck);
with_server(peck) {
_unref_(eis_event) *e =
peck_eis_next_event(eis, EIS_EVENT_CLIENT_PROPERTY);
const char *name = eis_event_property_get_name(e);
const char *value = eis_event_property_get_value(e);
munit_assert_string_equal(name, "foo.bar");
munit_assert_string_equal(value, "newval");
}
with_client(peck) {
int rc = ei_property_set(ei, "foo.bar", NULL);
munit_assert_int(rc, ==, 0);
}
peck_dispatch_until_stable(peck);
with_server(peck) {
_unref_(eis_event) *e =
peck_eis_next_event(eis, EIS_EVENT_CLIENT_PROPERTY);
const char *name = eis_event_property_get_name(e);
const char *value = eis_event_property_get_value(e);
munit_assert_string_equal(name, "foo.bar");
munit_assert_ptr_null(value);
}
return MUNIT_OK;
}
MUNIT_TEST(test_ei_properties_reserved)
{
_unref_(peck) *peck = peck_new();
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL);
peck_dispatch_until_stable(peck);
with_client(peck) {
int rc;
rc = ei_property_set(ei, "ei.bar", "value");
munit_assert_int(rc, ==, -EACCES);
rc = ei_property_set(ei, "eis.bar", "value");
munit_assert_int(rc, ==, -EACCES);
}
peck_dispatch_until_stable(peck);
with_server(peck) {
peck_assert_no_eis_events(eis);
}
peck_dispatch_until_stable(peck);
return MUNIT_OK;
}
MUNIT_TEST(test_ei_properties_permissions)
{
_unref_(peck) *peck = peck_new();
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL);
peck_dispatch_until_stable(peck);
with_client(peck) {
ei_property_set_with_permissions(ei, "cannot.delete", "v1",
EI_PROPERTY_PERM_READ|EI_PROPERTY_PERM_WRITE);
ei_property_set_with_permissions(ei, "cannot.write", "v2",
EI_PROPERTY_PERM_READ|EI_PROPERTY_PERM_DELETE);
ei_property_set_with_permissions(ei, "cannot.read", "v3",
EI_PROPERTY_PERM_DELETE|EI_PROPERTY_PERM_WRITE);
const char *value;
int rc;
/* can't delete but we can write to it */
value = ei_property_get(ei, "cannot.delete");
munit_assert_string_equal(value, "v1");
rc = ei_property_set(ei, "cannot.delete", NULL);
munit_assert_int(rc, ==, -EACCES);
value = ei_property_get(ei, "cannot.delete");
munit_assert_string_equal(value, "v1");
rc = ei_property_set(ei, "cannot.delete", "newv1");
munit_assert_int(rc, ==, 0);
value = ei_property_get(ei, "cannot.delete");
munit_assert_string_equal(value, "newv1");
/* can't modify it but we can delete it */
value = ei_property_get(ei, "cannot.write");
munit_assert_string_equal(value, "v2");
rc = ei_property_set(ei, "cannot.write", "newv2");
munit_assert_int(rc, ==, -EACCES);
value = ei_property_get(ei, "cannot.write");
munit_assert_string_equal(value, "v2");
rc = ei_property_set(ei, "cannot.write", NULL);
munit_assert_int(rc, ==, 0);
value = ei_property_get(ei, "cannot.write");
munit_assert_ptr_equal(value, NULL);
value = ei_property_get(ei, "cannot.read");
munit_assert_ptr_equal(value, NULL);
rc = ei_property_set(ei, "cannot.read", "newv3");
munit_assert_int(rc, ==, -EACCES);
value = ei_property_get(ei, "cannot.read");
munit_assert_ptr_equal(value, NULL);
rc = ei_property_set(ei, "cannot.read", NULL);
munit_assert_int(rc, ==, -EACCES);
}
return MUNIT_OK;
}
MUNIT_TEST(test_ei_properties_permissions_drop)
{
_unref_(peck) *peck = peck_new();
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL);
peck_dispatch_until_stable(peck);
with_client(peck) {
int rc;
ei_property_set_with_permissions(ei, "test.perms", "v1",
EI_PROPERTY_PERM_READ|EI_PROPERTY_PERM_WRITE|EI_PROPERTY_PERM_DELETE);
/* downgrading permissions, can't delete anymore */
rc = ei_property_set_with_permissions(ei, "test.perms", "v1",
EI_PROPERTY_PERM_READ|EI_PROPERTY_PERM_WRITE);
munit_assert_int(rc, ==, 0);
rc = ei_property_set(ei, "test.perms", NULL);
munit_assert_int(rc, ==, -EACCES);
/* upgrading permissions should fail */
rc = ei_property_set_with_permissions(ei, "test.perms", "v1",
EI_PROPERTY_PERM_READ|EI_PROPERTY_PERM_WRITE|EI_PROPERTY_PERM_DELETE);
munit_assert_int(rc, ==, -EPERM);
/* Drop the write permission */
rc = ei_property_set_with_permissions(ei, "test.perms", "v1",
EI_PROPERTY_PERM_READ);
munit_assert_int(rc, ==, 0);
rc = ei_property_set(ei, "test.perms", "new value");
munit_assert_int(rc, ==, -EACCES);
/* We need write permissions to change the permissions */
rc = ei_property_set_with_permissions(ei, "test.perms", "v1",
EI_PROPERTY_PERM_NONE);
munit_assert_int(rc, ==, -EACCES);
}
return MUNIT_OK;
}
MUNIT_TEST(test_ei_properties_events)
{
_unref_(peck) *peck = peck_new();
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL);
peck_dispatch_until_stable(peck);
with_client(peck) {
ei_property_set(ei, "test.events", "v1");
ei_property_set(ei, "test.events", "v2");
}
peck_dispatch_until_stable(peck);
with_server(peck) {
_unref_(eis_event) *e1 =
peck_eis_next_event(eis, EIS_EVENT_CLIENT_PROPERTY);
const char *name = eis_event_property_get_name(e1);
const char *value = eis_event_property_get_value(e1);
munit_assert_string_equal(name, "test.events");
munit_assert_string_equal(value, "v1");
struct eis_client *client = eis_event_get_client(e1);
const char *propval = eis_client_property_get(client, "test.events");
/*
* This probably needs fixing: because we processed the second
* event already, the actual property value is different to
* our current event value.
*/
munit_assert_string_equal(propval, "v2");
_unref_(eis_event) *e2 =
peck_eis_next_event(eis, EIS_EVENT_CLIENT_PROPERTY);
name = eis_event_property_get_name(e2);
value = eis_event_property_get_value(e2);
munit_assert_string_equal(name, "test.events");
munit_assert_string_equal(value, "v2");
}
/* delete it */
with_client(peck) {
ei_property_set(ei, "test.events", "v3");
ei_property_set(ei, "test.events", NULL);
}
peck_dispatch_until_stable(peck);
with_server(peck) {
_unref_(eis_event) *e3 =
peck_eis_next_event(eis, EIS_EVENT_CLIENT_PROPERTY);
const char *name = eis_event_property_get_name(e3);
const char *value = eis_event_property_get_value(e3);
munit_assert_string_equal(name, "test.events");
munit_assert_string_equal(value, "v3");
struct eis_client *client = eis_event_get_client(e3);
const char *propval = eis_client_property_get(client, "test.events");
/*
* This probably needs fixing: because we processed the second
* event already, the actual property value is different to
* our current event value.
*/
munit_assert_ptr_null(propval);
_unref_(eis_event) *e4 =
peck_eis_next_event(eis, EIS_EVENT_CLIENT_PROPERTY);
name = eis_event_property_get_name(e4);
value = eis_event_property_get_value(e4);
munit_assert_string_equal(name, "test.events");
munit_assert_ptr_null(value);
}
return MUNIT_OK;
}
MUNIT_TEST(test_ei_properties_events_server)
{
_unref_(peck) *peck = peck_new();
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL);
peck_dispatch_until_stable(peck);
with_server(peck) {
struct eis_client *client = peck_eis_get_default_client(peck);
eis_client_property_set(client, "test.events", "v1");
eis_client_property_set(client, "test.events", "v2");
}
peck_dispatch_until_stable(peck);
with_client(peck) {
_unref_(ei_event) *e1 =
peck_ei_next_event(ei, EI_EVENT_PROPERTY);
const char *name = ei_event_property_get_name(e1);
const char *value = ei_event_property_get_value(e1);
munit_assert_string_equal(name, "test.events");
munit_assert_string_equal(value, "v1");
const char *propval = ei_property_get(ei, "test.events");
/*
* This probably needs fixing: because we processed the second
* event already, the actual property value is different to
* our current event value.
*/
munit_assert_string_equal(propval, "v2");
_unref_(ei_event) *e2 =
peck_ei_next_event(ei, EI_EVENT_PROPERTY);
name = ei_event_property_get_name(e2);
value = ei_event_property_get_value(e2);
munit_assert_string_equal(name, "test.events");
munit_assert_string_equal(value, "v2");
}
/* delete it */
with_server(peck) {
struct eis_client *client = peck_eis_get_default_client(peck);
eis_client_property_set(client, "test.events", "v3");
eis_client_property_set(client, "test.events", NULL);
}
peck_dispatch_until_stable(peck);
with_client(peck) {
_unref_(ei_event) *e3 =
peck_ei_next_event(ei, EI_EVENT_PROPERTY);
const char *name = ei_event_property_get_name(e3);
const char *value = ei_event_property_get_value(e3);
munit_assert_string_equal(name, "test.events");
munit_assert_string_equal(value, "v3");
const char *propval = ei_property_get(ei, "test.events");
/*
* This probably needs fixing: because we processed the second
* event already, the actual property value is different to
* our current event value.
*/
munit_assert_ptr_null(propval);
_unref_(ei_event) *e4 =
peck_ei_next_event(ei, EI_EVENT_PROPERTY);
name = ei_event_property_get_name(e4);
value = ei_event_property_get_value(e4);
munit_assert_string_equal(name, "test.events");
munit_assert_ptr_null(value);
}
return MUNIT_OK;
}
MUNIT_TEST(test_ei_properties_events_pingpong)
{
_unref_(peck) *peck = peck_new();
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL);
peck_dispatch_until_stable(peck);
with_server(peck) {
struct eis_client *client = peck_eis_get_default_client(peck);
eis_client_property_set(client, "test.events", "ping");
}
peck_dispatch_until_stable(peck);
with_client(peck) {
_unref_(ei_event) *e =
peck_ei_next_event(ei, EI_EVENT_PROPERTY);
const char *name = ei_event_property_get_name(e);
const char *value = ei_event_property_get_value(e);
munit_assert_string_equal(name, "test.events");
munit_assert_string_equal(value, "ping");
const char *propval = ei_property_get(ei, "test.events");
munit_assert_string_equal(propval, "ping");
ei_property_set(ei, "test.events", "pong");
propval = ei_property_get(ei, "test.events");
munit_assert_string_equal(propval, "pong");
}
peck_dispatch_until_stable(peck);
with_server(peck) {
_unref_(eis_event) *e =
peck_eis_next_event(eis, EIS_EVENT_CLIENT_PROPERTY);
const char *name = eis_event_property_get_name(e);
const char *value = eis_event_property_get_value(e);
munit_assert_string_equal(name, "test.events");
munit_assert_string_equal(value, "pong");
struct eis_client *client = eis_event_get_client(e);
const char *propval = eis_client_property_get(client, "test.events");
munit_assert_string_equal(propval, "pong");
}
return MUNIT_OK;
}
MUNIT_TEST(test_ei_disconnect_immediately)
{
_unref_(peck) *peck = peck_new();
/* Client is immediately rejected */
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_REJECT_CLIENT);
peck_dispatch_until_stable(peck);
/* Expect the client to get a disconnect event */
with_client(peck) {
ei_dispatch(ei);
_unref_(ei_event) *disconnect =
peck_ei_next_event(ei, EI_EVENT_DISCONNECT);
}
return MUNIT_OK;
}
MUNIT_TEST(test_ei_disconnect_self_immediately)
{
_unref_(peck) *peck = peck_new();
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_NONE);
peck_dispatch_until_stable(peck);
/* Disconnect before server processed CONNECT */
with_client(peck) {
peck_drop_ei(peck);
ei_unref(ei);
}
peck_dispatch_until_stable(peck);
/* Expect the client to get a disconnect event */
with_server(peck) {
_unref_(eis_event) *connect =
peck_eis_next_event(eis, EIS_EVENT_CLIENT_CONNECT);
_unref_(eis_event) *disconnect =
peck_eis_next_event(eis, EIS_EVENT_CLIENT_DISCONNECT);
}
return MUNIT_OK;
}
MUNIT_TEST(test_ei_disconnect_after_connect)
{
_unref_(peck) *peck = peck_new();
_unref_(eis_client) *client = NULL;
peck_dispatch_until_stable(peck);
with_server(peck) {
eis_dispatch(eis);
_unref_(eis_event) *e =
peck_eis_next_event(eis, EIS_EVENT_CLIENT_CONNECT);
client = eis_client_ref(eis_event_get_client(e));
eis_client_connect(client);
}
with_client(peck) {
ei_dispatch(ei);
_unref_(ei_event) *e =
peck_ei_next_event(ei, EI_EVENT_CONNECT);
}
with_server(peck) {
eis_client_disconnect(client);
}
with_client(peck) {
ei_dispatch(ei);
_unref_(ei_event) *e =
peck_ei_next_event(ei, EI_EVENT_DISCONNECT);
}
return MUNIT_OK;
}
MUNIT_TEST(test_ei_disconnect_self_after_connect)
{
_unref_(peck) *peck = peck_new();
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_NONE);
peck_dispatch_until_stable(peck);
with_client(peck) {
peck_drop_ei(peck);
ei_unref(ei);
}
peck_dispatch_until_stable(peck);
with_server(peck) {
_unref_(eis_event) *connect =
peck_eis_next_event(eis, EIS_EVENT_CLIENT_CONNECT);
_unref_(eis_event) *disconnect =
peck_eis_next_event(eis, EIS_EVENT_CLIENT_DISCONNECT);
}
return MUNIT_OK;
}
MUNIT_TEST(test_ei_disconnect_after_seat)
{
_unref_(peck) *peck = peck_new();
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_CLIENT);
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_DEFAULT_SEAT);
peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_NONE);
peck_dispatch_until_stable(peck);
with_client(peck) {
_unref_(ei_event) *connect =
peck_ei_next_event(ei, EI_EVENT_CONNECT);
_unref_(ei_event) *seat =
peck_ei_next_event(ei, EI_EVENT_SEAT_ADDED);
}
with_server(peck) {
struct eis_client *client = peck_eis_get_default_client(peck);
eis_client_disconnect(client);
}
peck_dispatch_until_stable(peck);
with_client(peck) {
_unref_(ei_event) *seat =
peck_ei_next_event(ei, EI_EVENT_SEAT_REMOVED);
_unref_(ei_event) *disconnect =
peck_ei_next_event(ei, EI_EVENT_DISCONNECT);
}
return MUNIT_OK;
}
MUNIT_TEST(test_ei_disconnect_self_after_seat)
{
_unref_(peck) *peck = peck_new();
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_CLIENT);
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_DEFAULT_SEAT);
peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_NONE);
peck_dispatch_until_stable(peck);
with_client(peck) {
_unref_(ei_event) *connect =
peck_ei_next_event(ei, EI_EVENT_CONNECT);
_unref_(ei_event) *seat =
peck_ei_next_event(ei, EI_EVENT_SEAT_ADDED);
peck_drop_ei(peck);
/* Disconnect from client */
ei_unref(ei);
/* There is no way to disconnect from the server without
* destroying the context, so we don't care about the actual
* events here
*/
}
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_NONE);
peck_dispatch_until_stable(peck);
with_server(peck) {
_unref_(eis_event) *disconnect =
peck_eis_next_event(eis, EIS_EVENT_CLIENT_DISCONNECT);
}
return MUNIT_OK;
}
MUNIT_TEST(test_ei_disconnect_after_bind_before_received)
{
_unref_(peck) *peck = peck_new();
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_CLIENT);
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_DEFAULT_SEAT);
peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_NONE);
peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_AUTOCONNECT);
peck_dispatch_until_stable(peck);
with_client(peck) {
_unref_(ei_event) *event = peck_ei_next_event(ei, EI_EVENT_SEAT_ADDED);
struct ei_seat *seat = ei_event_get_seat(event);
ei_seat_bind_capability(seat, EI_DEVICE_CAP_POINTER);
}
/* We have *not* called eis_dispatch, so the seat bind hasn't been
* processed by the server yet */
with_server(peck) {
struct eis_client *client = peck_eis_get_default_client(peck);
eis_client_disconnect(client);
}
with_client(peck) {
ei_dispatch(ei);
_unref_(ei_event) *seat_removed =
peck_ei_next_event(ei, EI_EVENT_SEAT_REMOVED);
_unref_(ei_event) *disconnect =
peck_ei_next_event(ei, EI_EVENT_DISCONNECT);
}
return MUNIT_OK;
}
MUNIT_TEST(test_ei_disconnect_self_after_bind_before_received)
{
_unref_(peck) *peck = peck_new();
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_CLIENT);
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_DEFAULT_SEAT);
peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_NONE);
peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_AUTOCONNECT);
peck_dispatch_until_stable(peck);
with_client(peck) {
_unref_(ei_event) *event = peck_ei_next_event(ei, EI_EVENT_SEAT_ADDED);
struct ei_seat *seat = ei_event_get_seat(event);
ei_seat_bind_capability(seat, EI_DEVICE_CAP_POINTER);
/* Disconnect before the server can process the bind event */
peck_drop_ei(peck);
ei_unref(ei);
}
peck_dispatch_eis(peck);
with_server(peck) {
/* Server got the bind event but client disconnected
* immediately after */
_unref_(eis_event) *bind =
peck_eis_next_event(eis, EIS_EVENT_SEAT_BIND);
_unref_(eis_event) *unbind =
peck_eis_next_event(eis, EIS_EVENT_SEAT_BIND);
munit_assert_false(eis_event_seat_has_capability(unbind, EIS_DEVICE_CAP_POINTER));
munit_assert_false(eis_event_seat_has_capability(unbind, EIS_DEVICE_CAP_POINTER_ABSOLUTE));
munit_assert_false(eis_event_seat_has_capability(unbind, EIS_DEVICE_CAP_KEYBOARD));
munit_assert_false(eis_event_seat_has_capability(unbind, EIS_DEVICE_CAP_TOUCH));
_unref_(eis_event) *disconnect =
peck_eis_next_event(eis, EIS_EVENT_CLIENT_DISCONNECT);
}
return MUNIT_OK;
}
MUNIT_TEST(test_ei_disconnect_after_bind_after_received)
{
_unref_(peck) *peck = peck_new();
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_CLIENT);
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_DEFAULT_SEAT);
peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_NONE);
peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_AUTOCONNECT);
peck_dispatch_until_stable(peck);
with_client(peck) {
_unref_(ei_event) *event = peck_ei_next_event(ei, EI_EVENT_SEAT_ADDED);
struct ei_seat *seat = ei_event_get_seat(event);
ei_seat_bind_capability(seat, EI_DEVICE_CAP_POINTER);
}
/* Receive the Bind event but don't actually add any devices,
* disconnect the client instead */
peck_dispatch_eis(peck);
with_server(peck) {
struct eis_client *client = peck_eis_get_default_client(peck);
eis_client_disconnect(client);
}
with_client(peck) {
ei_dispatch(ei);
_unref_(ei_event) *seat_removed =
peck_ei_next_event(ei, EI_EVENT_SEAT_REMOVED);
_unref_(ei_event) *disconnect =
peck_ei_next_event(ei, EI_EVENT_DISCONNECT);
}
return MUNIT_OK;
}
MUNIT_TEST(test_ei_disconnect_self_after_bind_after_received)
{
_unref_(peck) *peck = peck_new();
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_CLIENT);
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_DEFAULT_SEAT);
peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_NONE);
peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_AUTOCONNECT);
peck_dispatch_until_stable(peck);
with_client(peck) {
_unref_(ei_event) *event = peck_ei_next_event(ei, EI_EVENT_SEAT_ADDED);
struct ei_seat *seat = ei_event_get_seat(event);
ei_seat_bind_capability(seat, EI_DEVICE_CAP_POINTER);
}
/* Make sure server sees Bind, then disconnect from server */
peck_dispatch_eis(peck);
with_client(peck) {
peck_drop_ei(peck);
ei_unref(ei);
}
peck_dispatch_eis(peck);
with_server(peck) {
_unref_(eis_event) *bind =
peck_eis_next_event(eis, EIS_EVENT_SEAT_BIND);
_unref_(eis_event) *unbind =
peck_eis_next_event(eis, EIS_EVENT_SEAT_BIND);
munit_assert_false(eis_event_seat_has_capability(unbind, EIS_DEVICE_CAP_POINTER));
munit_assert_false(eis_event_seat_has_capability(unbind, EIS_DEVICE_CAP_POINTER_ABSOLUTE));
munit_assert_false(eis_event_seat_has_capability(unbind, EIS_DEVICE_CAP_KEYBOARD));
munit_assert_false(eis_event_seat_has_capability(unbind, EIS_DEVICE_CAP_TOUCH));
_unref_(eis_event) *disconnect =
peck_eis_next_event(eis, EIS_EVENT_CLIENT_DISCONNECT);
}
return MUNIT_OK;
}
MUNIT_TEST(test_ei_disconnect_after_unbind_before_received)
{
_unref_(peck) *peck = peck_new();
_unref_(ei_seat) *seat = NULL;
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL);
peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_NONE);
peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_AUTOCONNECT);
peck_dispatch_until_stable(peck);
with_client(peck) {
_unref_(ei_event) *event = peck_ei_next_event(ei, EI_EVENT_SEAT_ADDED);
seat = ei_seat_ref(ei_event_get_seat(event));
ei_seat_bind_capability(seat, EI_DEVICE_CAP_POINTER);
}
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL);
/* server has the Bind event now */
peck_dispatch_until_stable(peck);
with_client(peck) {
ei_seat_unbind_capability(seat, EI_DEVICE_CAP_POINTER);
}
/* No server dispatch here so the server isn't aware of the
* ei_seat_unbind() call. Disconnect the client
*/
with_server(peck) {
struct eis_client *client = peck_eis_get_default_client(peck);
eis_client_disconnect(client);
}
with_client(peck) {
ei_dispatch(ei);
_unref_(ei_event) *seat_removed =
peck_ei_next_event(ei, EI_EVENT_SEAT_REMOVED);
_unref_(ei_event) *disconnect =
peck_ei_next_event(ei, EI_EVENT_DISCONNECT);
}
return MUNIT_OK;
}
MUNIT_TEST(test_ei_disconnect_after_unbind_after_received)
{
_unref_(peck) *peck = peck_new();
_unref_(ei_seat) *seat = NULL;
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL);
peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_NONE);
peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_AUTOCONNECT);
peck_dispatch_until_stable(peck);
with_client(peck) {
_unref_(ei_event) *event = peck_ei_next_event(ei, EI_EVENT_SEAT_ADDED);
seat = ei_seat_ref(ei_event_get_seat(event));
ei_seat_bind_capability(seat, EI_DEVICE_CAP_POINTER);
}
/* server has the Bind event now */
peck_dispatch_until_stable(peck);
with_client(peck) {
ei_seat_unbind_capability(seat, EI_DEVICE_CAP_POINTER);
}
/* Dispatch, server is aware of the ei_seat_unbind() */
peck_dispatch_eis(peck);
with_server(peck) {
struct eis_client *client = peck_eis_get_default_client(peck);
eis_client_disconnect(client);
}
peck_dispatch_ei(peck);
with_client(peck) {
_unref_(ei_event) *seat_removed =
peck_ei_next_event(ei, EI_EVENT_SEAT_REMOVED);
_unref_(ei_event) *disconnect =
peck_ei_next_event(ei, EI_EVENT_DISCONNECT);
}
return MUNIT_OK;
}
MUNIT_TEST(test_client_is_sender)
{
_unref_(peck) *peck = peck_new_context(PECK_EI_SENDER);
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_NONE);
peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_NONE);
peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_AUTOCONNECT);
peck_dispatch_until_stable(peck);
with_server(peck) {
_unref_(eis_event) *connect = peck_eis_next_event(eis, EIS_EVENT_CLIENT_CONNECT);
struct eis_client *client = eis_event_get_client(connect);
munit_assert_true(eis_client_is_sender(client));
}
return MUNIT_OK;
}
MUNIT_TEST(test_client_is_receiver)
{
_unref_(peck) *peck = peck_new_context(PECK_EI_RECEIVER);
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_NONE);
peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_NONE);
peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_AUTOCONNECT);
peck_dispatch_until_stable(peck);
with_server(peck) {
_unref_(eis_event) *connect = peck_eis_next_event(eis, EIS_EVENT_CLIENT_CONNECT);
struct eis_client *client = eis_event_get_client(connect);
munit_assert_false(eis_client_is_sender(client));
}
return MUNIT_OK;
}
/* Emulates the XWayland behavior for calling
* xdotool mousemove_relative -- -1 10
*/
MUNIT_TEST(test_xdotool_rel_motion)
{
_unref_(peck) *peck = peck_new();
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL);
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ADD_POINTER);
peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_AUTODEVICES);
peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_AUTOSTART);
peck_dispatch_until_stable(peck);
with_client(peck) {
struct ei_device *device = peck_ei_get_default_pointer(peck);
ei_device_pointer_motion(device, -1, 10);
ei_device_frame(device, peck_ei_now(peck));
ei_device_close(device);
ei_unref(ei);
peck_drop_ei(peck);
}
peck_dispatch_eis(peck);
with_server(peck) {
_unref_(eis_event) *motion =
peck_eis_next_event(eis, EIS_EVENT_POINTER_MOTION);
_unref_(eis_event) *stop =
peck_eis_next_event(eis, EIS_EVENT_DEVICE_STOP_EMULATING);
_unref_(eis_event) *close =
peck_eis_next_event(eis, EIS_EVENT_DEVICE_CLOSED);
_unref_(eis_event) *unbind =
peck_eis_next_event(eis, EIS_EVENT_SEAT_BIND);
munit_assert_false(eis_event_seat_has_capability(unbind, EIS_DEVICE_CAP_POINTER));
munit_assert_false(eis_event_seat_has_capability(unbind, EIS_DEVICE_CAP_POINTER_ABSOLUTE));
munit_assert_false(eis_event_seat_has_capability(unbind, EIS_DEVICE_CAP_KEYBOARD));
munit_assert_false(eis_event_seat_has_capability(unbind, EIS_DEVICE_CAP_TOUCH));
_unref_(eis_event) *disconnect =
peck_eis_next_event(eis, EIS_EVENT_CLIENT_DISCONNECT);
peck_assert_no_eis_events(eis);
}
return MUNIT_OK;
}