test_device_LDADD = $(TEST_LIBS)
test_device_LDFLAGS = -no-install
- test_litest_selftest_CFLAGS = -DLITEST_DISABLE_BACKTRACE_LOGGING
+test_litest_selftest_SOURCES = litest-selftest.c litest.c litest-int.h litest.h
++test_litest_selftest_CFLAGS = -DLITEST_DISABLE_BACKTRACE_LOGGING -DLITEST_NO_MAIN
+test_litest_selftest_LDADD = $(TEST_LIBS)
+test_litest_selftest_LDFLAGS = -no-install
+
# build-test only
test_build_pedantic_c99_SOURCES = build-pedantic.c
test_build_pedantic_c99_CFLAGS = -std=c99 -pedantic -Werror
static int in_debugger = -1;
static int verbose = 0;
+ const char *filter_test = NULL;
+ const char *filter_device = NULL;
+ const char *filter_group = NULL;
+#ifdef HAVE_LIBUNWIND
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#include <dlfcn.h>
+
+/* defined for the litest selftest */
+#ifndef LITEST_DISABLE_BACKTRACE_LOGGING
+#define litest_log(...) fprintf(stderr, __VA_ARGS__)
+#define litest_vlog(format_, args_) vfprintf(stderr, format_, args_)
+#else
+#define litest_log(...) /* __VA_ARGS__ */
+#define litest_vlog(...) /* __VA_ARGS__ */
+#endif
+
+static char cwd[PATH_MAX];
+
+static bool
+litest_backtrace_get_lineno(const char *executable,
+ unw_word_t addr,
+ char *file_return,
+ int *line_return)
+{
+#if HAVE_ADDR2LINE
+ FILE* f;
+ char buffer[PATH_MAX];
+ char *s;
+ int i;
+
+ if (!cwd[0])
+ getcwd(cwd, sizeof(cwd));
+
+ sprintf (buffer,
+ ADDR2LINE " -C -e %s -i %lx",
+ executable,
+ (unsigned long) addr);
+
+ f = popen(buffer, "r");
+ if (f == NULL) {
+ litest_log("Failed to execute: %s\n", buffer);
+ return false;
+ }
+
+ buffer[0] = '?';
+ fgets(buffer, sizeof(buffer), f);
+ fclose(f);
+
+ if (buffer[0] == '?')
+ return false;
+
+ s = strrchr(buffer, ':');
+ if (!s)
+ return false;
+
+ *s = '\0';
+ s++;
+ sscanf(s, "%d", line_return);
+
+ /* now strip cwd from buffer */
+ s = buffer;
+ i = 0;
+ while(cwd[i] == *s) {
+ *s = '\0';
+ s++;
+ i++;
+ }
+
+ if (i > 0)
+ *(--s) = '.';
+ strcpy(file_return, s);
+
+ return true;
+#else /* HAVE_ADDR2LINE */
+ return false;
+#endif
+}
+
+static void
+litest_backtrace(void)
+{
+ unw_cursor_t cursor;
+ unw_context_t context;
+ unw_word_t off;
+ unw_proc_info_t pip;
+ int ret;
+ char procname[256];
+ Dl_info dlinfo;
+ /* filename and i are unused ifdef LITEST_SHUTUP */
+ const char *filename __attribute__((unused));
+ int i __attribute__((unused)) = 0;
+
+ pip.unwind_info = NULL;
+ ret = unw_getcontext(&context);
+ if (ret) {
+ litest_log("unw_getcontext failed: %s [%d]\n",
+ unw_strerror(ret),
+ ret);
+ return;
+ }
+
+ ret = unw_init_local(&cursor, &context);
+ if (ret) {
+ litest_log("unw_init_local failed: %s [%d]\n",
+ unw_strerror(ret),
+ ret);
+ return;
+ }
+
+ litest_log("\nBacktrace:\n");
+ ret = unw_step(&cursor);
+ while (ret > 0) {
+ char file[PATH_MAX];
+ int line;
+ bool have_lineno = false;
+
+ ret = unw_get_proc_info(&cursor, &pip);
+ if (ret) {
+ litest_log("unw_get_proc_info failed: %s [%d]\n",
+ unw_strerror(ret),
+ ret);
+ break;
+ }
+
+ ret = unw_get_proc_name(&cursor, procname, 256, &off);
+ if (ret && ret != -UNW_ENOMEM) {
+ if (ret != -UNW_EUNSPEC)
+ litest_log("unw_get_proc_name failed: %s [%d]\n",
+ unw_strerror(ret),
+ ret);
+ procname[0] = '?';
+ procname[1] = 0;
+ }
+
+ if (dladdr((void *)(pip.start_ip + off), &dlinfo) &&
+ dlinfo.dli_fname &&
+ *dlinfo.dli_fname) {
+ filename = dlinfo.dli_fname;
+ have_lineno = litest_backtrace_get_lineno(filename,
+ (pip.start_ip + off),
+ file,
+ &line);
+ } else {
+ filename = "?";
+ }
+
+ if (have_lineno) {
+ litest_log("%u: %s() (%s:%d)\n",
+ i,
+ procname,
+ file,
+ line);
+ } else {
+ litest_log("%u: %s (%s%s+%#x) [%p]\n",
+ i,
+ filename,
+ procname,
+ ret == -UNW_ENOMEM ? "..." : "",
+ (int)off,
+ (void *)(pip.start_ip + off));
+ }
+
+ i++;
+ ret = unw_step(&cursor);
+ if (ret < 0)
+ litest_log("unw_step failed: %s [%d]\n",
+ unw_strerror(ret),
+ ret);
+ }
+ litest_log("\n");
+}
+#else /* HAVE_LIBUNWIND */
+static inline void
+litest_backtrace(void)
+{
+ /* thou shall install libunwind */
+}
+#endif
+
+void
+litest_fail_condition(const char *file,
+ int line,
+ const char *func,
+ const char *condition,
+ const char *message,
+ ...)
+{
+ litest_log("FAILED: %s\n", condition);
+
+ if (message) {
+ va_list args;
+ va_start(args, message);
+ litest_vlog(message, args);
+ va_end(args);
+ }
+
+ litest_log("in %s() (%s:%d)\n", func, file, line);
+ litest_backtrace();
+ abort();
+}
+
+void
+litest_fail_comparison_int(const char *file,
+ int line,
+ const char *func,
+ const char *operator,
+ int a,
+ int b,
+ const char *astr,
+ const char *bstr)
+{
+ litest_log("FAILED COMPARISON: %s %s %s\n", astr, operator, bstr);
+ litest_log("Resolved to: %d %s %d\n", a, operator, b);
+ litest_log("in %s() (%s:%d)\n", func, file, line);
+ litest_backtrace();
+ abort();
+}
+
+void
+litest_fail_comparison_ptr(const char *file,
+ int line,
+ const char *func,
+ const char *comparison)
+{
+ litest_log("FAILED COMPARISON: %s\n", comparison);
+ litest_log("in %s() (%s:%d)\n", func, file, line);
+ litest_backtrace();
+ abort();
+}
+
struct test {
struct list node;
char *name;
assert(type < LITEST_NO_DEVICE);
+ if (filter_group &&
+ fnmatch(filter_group, name, 0) != 0)
+ return;
+
s = get_suite(name);
- while (*dev) {
+ for (; *dev; dev++) {
+ if (filter_device &&
+ fnmatch(filter_device, (*dev)->shortname, 0) != 0)
+ continue;
+
if ((*dev)->type == type) {
- litest_add_tcase_for_device(s, func, *dev, range);
+ litest_add_tcase_for_device(s,
+ funcname,
+ func,
+ *dev,
+ range);
return;
}
- dev++;
}
- ck_abort_msg("Invalid test device type");
+ litest_abort_msg("Invalid test device type");
}
static int
.close_restricted = close_restricted,
};
- static const struct option opts[] = {
- { "list", 0, 0, 'l' },
- { "verbose", 0, 0, 'v' },
- { 0, 0, 0, 0}
- };
-
- int
-static int
++static inline int
litest_run(int argc, char **argv)
{
struct suite *s, *snext;
litest_event(d, EV_SYN, SYN_REPORT, 0);
}
-static int
+
++static inline int
+ litest_parse_argv(int argc, char **argv)
+ {
+ enum {
+ OPT_FILTER_TEST,
+ OPT_FILTER_DEVICE,
+ OPT_FILTER_GROUP,
+ OPT_LIST,
+ OPT_VERBOSE,
+ };
+ static const struct option opts[] = {
+ { "filter-test", 1, 0, OPT_FILTER_TEST },
+ { "filter-device", 1, 0, OPT_FILTER_DEVICE },
+ { "filter-group", 1, 0, OPT_FILTER_GROUP },
+ { "list", 0, 0, OPT_LIST },
+ { "verbose", 0, 0, OPT_VERBOSE },
+ { 0, 0, 0, 0}
+ };
+
+ while(1) {
+ int c;
+ int option_index = 0;
+
+ c = getopt_long(argc, argv, "", opts, &option_index);
+ if (c == -1)
+ break;
+ switch(c) {
+ case OPT_FILTER_TEST:
+ filter_test = optarg;
+ break;
+ case OPT_FILTER_DEVICE:
+ filter_device = optarg;
+ break;
+ case OPT_FILTER_GROUP:
+ filter_group = optarg;
+ break;
+ case OPT_LIST:
+ litest_list_tests(&all_tests);
+ exit(0);
+ case OPT_VERBOSE:
+ verbose = 1;
+ break;
+ default:
+ fprintf(stderr, "usage: %s [--list]\n", argv[0]);
+ return 1;
+ }
+ }
+
+ return 0;
+ }
+
++#ifndef LITEST_NO_MAIN
+ int
+ main(int argc, char **argv)
+ {
+ if (litest_parse_argv(argc, argv) != 0)
+ return EXIT_FAILURE;
+
+ litest_setup_tests();
+
+ return litest_run(argc, argv);
+ }
++#endif
void litest_disable_log_handler(struct libinput *libinput);
void litest_restore_log_handler(struct libinput *libinput);
- void litest_add(const char *name, void *func,
- enum litest_device_feature required_feature,
- enum litest_device_feature excluded_feature);
- void litest_add_ranged(const char *name,
- void *func,
- enum litest_device_feature required,
- enum litest_device_feature excluded,
- const struct range *range);
- void
- litest_add_for_device(const char *name,
- void *func,
- enum litest_device_type type);
- void litest_add_ranged_for_device(const char *name,
+void
+litest_fail_condition(const char *file,
+ int line,
+ const char *func,
+ const char *condition,
+ const char *message,
+ ...);
+void
+litest_fail_comparison_int(const char *file,
+ int line,
+ const char *func,
+ const char *operator,
+ int a,
+ int b,
+ const char *astr,
+ const char *bstr);
+void
+litest_fail_comparison_ptr(const char *file,
+ int line,
+ const char *func,
+ const char *comparison);
+
+ #define litest_add(name_, func_, ...) \
+ _litest_add(name_, #func_, func_, __VA_ARGS__)
+ #define litest_add_ranged(name_, func_, ...) \
+ _litest_add_ranged(name_, #func_, func_, __VA_ARGS__)
+ #define litest_add_for_device(name_, func_, ...) \
+ _litest_add_for_device(name_, #func_, func_, __VA_ARGS__)
+ #define litest_add_ranged_for_device(name_, func_, ...) \
+ _litest_add_ranged_for_device(name_, #func_, func_, __VA_ARGS__)
+ #define litest_add_no_device(name_, func_) \
+ _litest_add_no_device(name_, #func_, func_)
+ #define litest_add_ranged_no_device(name_, func_, ...) \
+ _litest_add_ranged_no_device(name_, #func_, func_, __VA_ARGS__)
+ void _litest_add(const char *name,
+ const char *funcname,
+ void *func,
+ enum litest_device_feature required_feature,
+ enum litest_device_feature excluded_feature);
+ void _litest_add_ranged(const char *name,
+ const char *funcname,
+ void *func,
+ enum litest_device_feature required,
+ enum litest_device_feature excluded,
+ const struct range *range);
+ void _litest_add_for_device(const char *name,
+ const char *funcname,
+ void *func,
+ enum litest_device_type type);
+ void _litest_add_ranged_for_device(const char *name,
+ const char *funcname,
+ void *func,
+ enum litest_device_type type,
+ const struct range *range);
+ void _litest_add_no_device(const char *name,
+ const char *funcname,
+ void *func);
+ void _litest_add_ranged_no_device(const char *name,
+ const char *funcname,
void *func,
- enum litest_device_type type,
const struct range *range);
- void litest_add_no_device(const char *name, void *func);
- void litest_add_ranged_no_device(const char *name,
- void *func,
- const struct range *range);
- int litest_run(int argc, char **argv);
+ extern void litest_setup_tests(void);
struct litest_device * litest_create_device(enum litest_device_type which);
struct litest_device * litest_add_device(struct libinput *libinput,
enum litest_device_type which);
}
END_TEST
- int main (int argc, char **argv)
+ void
+ litest_setup_tests(void)
{
+ struct range axis_range = {ABS_X, ABS_Y + 1};
+
litest_add("pointer:motion", pointer_motion_relative, LITEST_RELATIVE, LITEST_ANY);
litest_add("pointer:motion", pointer_motion_absolute, LITEST_ABSOLUTE, LITEST_ANY);
litest_add("pointer:motion", pointer_motion_unaccel, LITEST_RELATIVE, LITEST_ANY);
litest_add("pointer:middlebutton", middlebutton_default_clickpad, LITEST_CLICKPAD, LITEST_ANY);
litest_add("pointer:middlebutton", middlebutton_default_touchpad, LITEST_TOUCHPAD, LITEST_CLICKPAD);
litest_add("pointer:middlebutton", middlebutton_default_disabled, LITEST_ANY, LITEST_BUTTON);
-
- return litest_run(argc, argv);
+
+ litest_add_ranged("pointer:state", pointer_absolute_initial_state, LITEST_ABSOLUTE, LITEST_ANY, &axis_range);
}
}
END_TEST
- int
- main(int argc, char **argv)
+START_TEST(touch_initial_state)
+{
+ struct litest_device *dev;
+ struct libinput *libinput1, *libinput2;
+ struct libinput_event *ev1, *ev2;
+ struct libinput_event_touch *t1, *t2;
+ struct libinput_device *device1, *device2;
+ int axis = _i; /* looped test */
+
+ dev = litest_current_device();
+ device1 = dev->libinput_device;
+ libinput_device_config_tap_set_enabled(device1,
+ LIBINPUT_CONFIG_TAP_DISABLED);
+
+ libinput1 = dev->libinput;
+ litest_touch_down(dev, 0, 40, 60);
+ litest_touch_up(dev, 0);
+
+ /* device is now on some x/y value */
+ litest_drain_events(libinput1);
+
+ libinput2 = litest_create_context();
+ device2 = libinput_path_add_device(libinput2,
+ libevdev_uinput_get_devnode(
+ dev->uinput));
+ libinput_device_config_tap_set_enabled(device2,
+ LIBINPUT_CONFIG_TAP_DISABLED);
+ litest_drain_events(libinput2);
+
+ if (axis == ABS_X)
+ litest_touch_down(dev, 0, 40, 70);
+ else
+ litest_touch_down(dev, 0, 70, 60);
+ litest_touch_up(dev, 0);
+
+ litest_wait_for_event(libinput1);
+ litest_wait_for_event(libinput2);
+
+ while (libinput_next_event_type(libinput1)) {
+ ev1 = libinput_get_event(libinput1);
+ ev2 = libinput_get_event(libinput2);
+
+ t1 = litest_is_touch_event(ev1, 0);
+ t2 = litest_is_touch_event(ev2, 0);
+
+ ck_assert_int_eq(libinput_event_get_type(ev1),
+ libinput_event_get_type(ev2));
+
+ if (libinput_event_get_type(ev1) == LIBINPUT_EVENT_TOUCH_UP ||
+ libinput_event_get_type(ev1) == LIBINPUT_EVENT_TOUCH_FRAME)
+ break;
+
+ ck_assert_int_eq(libinput_event_touch_get_x(t1),
+ libinput_event_touch_get_x(t2));
+ ck_assert_int_eq(libinput_event_touch_get_y(t1),
+ libinput_event_touch_get_y(t2));
+
+ libinput_event_destroy(ev1);
+ libinput_event_destroy(ev2);
+ }
+
+ libinput_event_destroy(ev1);
+ libinput_event_destroy(ev2);
+
+ libinput_unref(libinput2);
+}
+END_TEST
+
+ void
+ litest_setup_tests(void)
{
+ struct range axes = { ABS_X, ABS_Y + 1};
+
litest_add("touch:frame", touch_frame_events, LITEST_TOUCH, LITEST_ANY);
litest_add_no_device("touch:abs-transform", touch_abs_transform);
litest_add_no_device("touch:many-slots", touch_many_slots);
litest_add("touch:protocol a", touch_protocol_a_init, LITEST_PROTOCOL_A, LITEST_ANY);
litest_add("touch:protocol a", touch_protocol_a_touch, LITEST_PROTOCOL_A, LITEST_ANY);
litest_add("touch:protocol a", touch_protocol_a_2fg_touch, LITEST_PROTOCOL_A, LITEST_ANY);
-
- return litest_run(argc, argv);
+
+ litest_add_ranged("touch:state", touch_initial_state, LITEST_TOUCH, LITEST_PROTOCOL_A, &axes);
}
}
END_TEST
- int main(int argc, char **argv)
+START_TEST(touchpad_initial_state)
+{
+ struct litest_device *dev;
+ struct libinput *libinput1, *libinput2;
+ struct libinput_event *ev1, *ev2;
+ struct libinput_event_pointer *p1, *p2;
+ int axis = _i; /* looped test */
+ int x = 40, y = 60;
+
+ dev = litest_current_device();
+ libinput1 = dev->libinput;
+
+ libinput_device_config_tap_set_enabled(dev->libinput_device,
+ LIBINPUT_CONFIG_TAP_DISABLED);
+
+ litest_touch_down(dev, 0, x, y);
+ litest_touch_up(dev, 0);
+
+ /* device is now on some x/y value */
+ litest_drain_events(libinput1);
+
+ libinput2 = litest_create_context();
+ libinput_path_add_device(libinput2,
+ libevdev_uinput_get_devnode(dev->uinput));
+ litest_drain_events(libinput2);
+
+ if (axis == ABS_X)
+ x = 30;
+ else
+ y = 30;
+ litest_touch_down(dev, 0, x, y);
+ litest_touch_move_to(dev, 0, x, y, 80, 80, 10, 1);
+ litest_touch_up(dev, 0);
+
+ litest_wait_for_event(libinput1);
+ litest_wait_for_event(libinput2);
+
+ while (libinput_next_event_type(libinput1)) {
+ ev1 = libinput_get_event(libinput1);
+ ev2 = libinput_get_event(libinput2);
+
+ p1 = litest_is_motion_event(ev1);
+ p2 = litest_is_motion_event(ev2);
+
+ ck_assert_int_eq(libinput_event_get_type(ev1),
+ libinput_event_get_type(ev2));
+
+ ck_assert_int_eq(libinput_event_pointer_get_dx(p1),
+ libinput_event_pointer_get_dx(p2));
+ ck_assert_int_eq(libinput_event_pointer_get_dy(p1),
+ libinput_event_pointer_get_dy(p2));
+ libinput_event_destroy(ev1);
+ libinput_event_destroy(ev2);
+ }
+
+ libinput_unref(libinput2);
+}
+END_TEST
+
+ void
+ litest_setup_tests(void)
{
struct range multitap_range = {3, 8};
+ struct range axis_range = {ABS_X, ABS_Y + 1};
litest_add("touchpad:motion", touchpad_1fg_motion, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("touchpad:motion", touchpad_2fg_no_motion, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
litest_add_for_device("touchpad:trackpoint", touchpad_trackpoint_buttons_softbuttons, LITEST_SYNAPTICS_TRACKPOINT_BUTTONS);
litest_add_for_device("touchpad:trackpoint", touchpad_trackpoint_buttons_2fg_scroll, LITEST_SYNAPTICS_TRACKPOINT_BUTTONS);
litest_add_for_device("touchpad:trackpoint", touchpad_trackpoint_no_trackpoint, LITEST_SYNAPTICS_TRACKPOINT_BUTTONS);
-
- return litest_run(argc, argv);
+
+ litest_add_ranged("touchpad:state", touchpad_initial_state, LITEST_TOUCHPAD, LITEST_ANY, &axis_range);
}