---
configure.ac | 1 +
src/evdev-mt-touchpad.c | 6 --
test/litest-int.h | 2 +
test/litest-synaptics-x1-carbon-3rd.c | 14 ++++-
test/litest.c | 106 +++++++++++++++++++++++++++++++++-
test/litest.h | 2 +
6 files changed, 122 insertions(+), 9 deletions(-)
diff --git a/configure.ac b/configure.ac
index 39e42d0..803d573 100644
--- a/configure.ac
+++ b/configure.ac
@@ -34,6 +34,7 @@ LIBINPUT_LT_VERSION=8:0:1
AC_SUBST(LIBINPUT_LT_VERSION)
AM_SILENT_RULES([yes])
+AC_USE_SYSTEM_EXTENSIONS
# Check for programs
AC_PROG_CC_C99
diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c
index 94cbc13..ae37ab1 100644
--- a/src/evdev-mt-touchpad.c
+++ b/src/evdev-mt-touchpad.c
@@ -1107,12 +1107,6 @@ tp_tag_device(struct evdev_device *device,
if (udev_device_get_property_value(udev_device,
"TOUCHPAD_HAS_TRACKPOINT_BUTTONS"))
device->tags |= EVDEV_TAG_TOUCHPAD_TRACKPOINT;
-
- /* Magic version tag: used by the litest device. Should never be set
- * in real life but allows us to test for these features without
- * requiring custom udev rules during make check */
- if (libevdev_get_id_version(device->evdev) == 0xfffa)
- device->tags |= EVDEV_TAG_TOUCHPAD_TRACKPOINT;
}
static struct evdev_dispatch_interface tp_interface = {
diff --git a/test/litest-int.h b/test/litest-int.h
index 95bc248..12746f1 100644
--- a/test/litest-int.h
+++ b/test/litest-int.h
@@ -69,6 +69,8 @@ struct litest_test_device {
*/
struct input_absinfo *absinfo;
struct litest_device_interface *interface;
+
+ const char *udev_rule;
};
struct litest_device_interface {
diff --git a/test/litest-synaptics-x1-carbon-3rd.c
b/test/litest-synaptics-x1-carbon-3rd.c
index 8be29e0..67d6f46 100644
--- a/test/litest-synaptics-x1-carbon-3rd.c
+++ b/test/litest-synaptics-x1-carbon-3rd.c
@@ -65,7 +65,6 @@ static struct input_id input_id = {
.bustype = 0x11,
.vendor = 0x2,
.product = 0x7,
- .version = 0xfffa, /* Magic value, used to detect this test device */
};
static int events[] = {
@@ -97,6 +96,16 @@ static struct input_absinfo absinfo[] = {
{ .value = -1 }
};
+static const char udev_rule[] =
+"ACTION==\"remove\", GOTO=\"touchpad_end\"\n"
+"KERNEL!=\"event*\", GOTO=\"touchpad_end\"\n"
+"ENV{ID_INPUT_TOUCHPAD}==\"\", GOTO=\"touchpad_end\"\n"
+"\n"
+"ATTRS{name}==\"litest*X1C3rd*\",\\\n"
+" ENV{TOUCHPAD_HAS_TRACKPOINT_BUTTONS}=\"1\"\n"
+"\n"
+"LABEL=\"touchpad_end\"";
+
struct litest_test_device litest_synaptics_carbon3rd_device = {
.type = LITEST_SYNAPTICS_TRACKPOINT_BUTTONS,
.features = LITEST_TOUCHPAD | LITEST_CLICKPAD | LITEST_BUTTON,
@@ -104,8 +113,9 @@ struct litest_test_device litest_synaptics_carbon3rd_device
= {
.setup = litest_synaptics_carbon3rd_setup,
.interface = &interface,
- .name = "SynPS/2 Synaptics TouchPad",
+ .name = "SynPS/2 Synaptics TouchPad X1C3rd",
.id = &input_id,
.events = events,
.absinfo = absinfo,
+ .udev_rule = udev_rule,
};
diff --git a/test/litest.c b/test/litest.c
index 2a336e9..7f55d47 100644
--- a/test/litest.c
+++ b/test/litest.c
@@ -26,6 +26,7 @@
#include <assert.h>
#include <check.h>
+#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
@@ -44,6 +45,9 @@
#include "litest-int.h"
#include "libinput-util.h"
+#define UDEV_RULES_D "/run/udev/rules.d"
+#define UDEV_RULE_PREFIX "99-litest-"
+
static int in_debugger = -1;
static int verbose = 0;
@@ -115,6 +119,55 @@ struct litest_test_device* devices[] = {
static struct list all_tests;
static void
+litest_reload_udev_rules(void)
+{
+ system("udevadm control --reload-rules");
+}
+
+static int
+litest_udev_rule_filter(const struct dirent *entry)
+{
+ return strncmp(entry->d_name,
+ UDEV_RULE_PREFIX,
+ strlen(UDEV_RULE_PREFIX)) == 0;
+}
+
+static void
+litest_drop_udev_rules(void)
+{
+ int n;
+ int rc;
+ struct dirent **entries;
+ char path[PATH_MAX];
+
+ n = scandir(UDEV_RULES_D,
+ &entries,
+ litest_udev_rule_filter,
+ alphasort);
+ if (n < 0)
+ return;
+
+ while (n--) {
+ rc = snprintf(path, sizeof(path),
+ "%s/%s",
+ UDEV_RULES_D,
+ entries[n]->d_name);
+ if (rc > 0 &&
+ (size_t)rc == strlen(UDEV_RULES_D) +
+ strlen(entries[n]->d_name) + 1)
+ unlink(path);
+ else
+ fprintf(stderr,
+ "Failed to delete %s. Remaining tests are
unreliable\n",
+ entries[n]->d_name);
+ free(entries[n]);
+ }
+ free(entries);
+
+ litest_reload_udev_rules();
+}
+
+static void
litest_add_tcase_for_device(struct suite *suite,
void *func,
const struct litest_test_device *dev)
@@ -134,6 +187,13 @@ litest_add_tcase_for_device(struct suite *suite,
t->name = strdup(test_name);
t->tc = tcase_create(test_name);
list_insert(&suite->tests, &t->node);
+ /* we can't guarantee that we clean up properly if a test fails, the
+ udev rules used for a previous test may still be in place. Add an
+ unchecked fixture to always clean up all rules before/after a
+ test case completes */
+ tcase_add_unchecked_fixture(t->tc,
+ litest_drop_udev_rules,
+ litest_drop_udev_rules);
tcase_add_checked_fixture(t->tc, dev->setup,
dev->teardown ? dev->teardown :
litest_generic_device_teardown);
tcase_add_test(t->tc, func);
@@ -464,6 +524,40 @@ merge_events(const int *orig, const int *override)
return events;
}
+static char *
+litest_init_udev_rules(struct litest_test_device *dev)
+{
+ int rc;
+ FILE *f;
+ char *path;
+
+ if (!dev->udev_rule)
+ return NULL;
+
+ rc = mkdir(UDEV_RULES_D, 0755);
+ if (rc == -1 && errno != EEXIST)
+ ck_abort_msg("Failed to create udev rules directory (%s)\n",
+ strerror(errno));
+
+ rc = asprintf(&path,
+ "%s/%s%s.rules",
+ UDEV_RULES_D,
+ UDEV_RULE_PREFIX,
+ dev->shortname);
+ ck_assert_int_eq(rc,
+ strlen(UDEV_RULES_D) +
+ strlen(UDEV_RULE_PREFIX) +
+ strlen(dev->shortname) + 7);
+ f = fopen(path, "w");
+ ck_assert_notnull(f);
+ ck_assert_int_ge(fputs(dev->udev_rule, f), 0);
+ fclose(f);
+
+ litest_reload_udev_rules();
+
+ return path;
+}
+
static struct litest_device *
litest_create(enum litest_device_type which,
const char *name_override,
@@ -477,6 +571,7 @@ litest_create(enum litest_device_type which,
const struct input_id *id;
struct input_absinfo *abs;
int *events;
+ char *udev_file;
dev = devices;
while (*dev) {
@@ -491,12 +586,17 @@ litest_create(enum litest_device_type which,
d = zalloc(sizeof(*d));
ck_assert(d != NULL);
+ udev_file = litest_init_udev_rules(*dev);
+
/* device has custom create method */
if ((*dev)->create) {
(*dev)->create(d);
- if (abs_override || events_override)
+ if (abs_override || events_override) {
+ if (udev_file)
+ unlink(udev_file);
ck_abort_msg("Custom create cannot"
"be overridden");
+ }
return d;
}
@@ -511,6 +611,7 @@ litest_create(enum litest_device_type which,
abs,
events);
d->interface = (*dev)->interface;
+ d->udev_rule_file = udev_file;
free(abs);
free(events);
@@ -629,6 +730,9 @@ litest_delete_device(struct litest_device *d)
if (!d)
return;
+ if (d->udev_rule_file)
+ unlink(d->udev_rule_file);
+
libinput_device_unref(d->libinput_device);
libinput_path_remove_device(d->libinput_device);
if (d->owns_context)
diff --git a/test/litest.h b/test/litest.h
index 0625a71..60ec458 100644
--- a/test/litest.h
+++ b/test/litest.h
@@ -84,6 +84,8 @@ struct litest_device {
bool skip_ev_syn;
void *private; /* device-specific data */
+
+ char *udev_rule_file;
};
struct libinput *litest_create_context(void);