[PATCH 4/7] test: add a backtrace facility to litest

Peter Hutterer peter.hutterer at who-t.net
Thu May 7 22:57:47 PDT 2015


The check unit test framework isn't particularly suited to having ck_assert*
calls in helper functions. A failed assertion in a helper function or the
litest framework merely gives us a the failed line in litest.c.
which doesn't tell us which test actually failed.

Add a backtracing facility with litest_backtrace(). And since this requires
wrapping all ck_assert macros with litest_assert() this patch ended up
replacing/duplicating a bunch of ck_assert_* bits. So rather than
ck_assert_int_eq() we now use litest_assert_int_eq(), etc. in the litest
framework itself.

The int comparison macros are more type-safe than ck_assert()'s macros which
just cast all the ints to intmax_t.

Backtrace is spewed to stderr, which is good enough for debugging. Example
backtrace:

	FAILED COMPARISON: status != expected
	Resolved to: 0 != 0
	in disable_button_scrolling() (pointer.c:115)

	Backtrace:
	0: ./test/test-pointer (litest_fail_comparison_int+0xab) [0x40973b]
	1: ./test/test-pointer (disable_button_scrolling+0x174) [0x40421b]
	2: ./test/test-pointer (middlebutton_middleclick+0x40) [0x40829c]
	3: /lib64/libcheck.so.0 (srunner_run+0x7f5) [0x7f0e8a277025]
	4: ./test/test-pointer (litest_run+0x107) [0x40a42b]
	5: ./test/test-pointer (main+0x2fa) [0x4090e7]
	6: /lib64/libc.so.6 (__libc_start_main+0xf0) [0x7f0e88f5e790]
	7: ./test/test-pointer (_start+0x29) [0x403ce9]
	8: ? (?+0x29) [0x29]

litest_backtrace() itself is copied from xserver/os/backtrace.c which git
blame attributes to Marcin.

CC:  Marcin Slusarz <marcin.slusarz at gmail.com>
Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
 configure.ac               |  10 ++
 test/Makefile.am           |  16 ++-
 test/litest-selftest.c     | 228 +++++++++++++++++++++++++++++++++++++
 test/litest.c              | 272 +++++++++++++++++++++++++++++++++------------
 test/litest.h              |  73 ++++++++++++
 test/valgrind.suppressions |   8 ++
 6 files changed, 537 insertions(+), 70 deletions(-)
 create mode 100644 test/litest-selftest.c

diff --git a/configure.ac b/configure.ac
index cdde4fa..75951fd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -60,6 +60,15 @@ PKG_PROG_PKG_CONFIG()
 PKG_CHECK_MODULES(MTDEV, [mtdev >= 1.1.0])
 PKG_CHECK_MODULES(LIBUDEV, [libudev])
 PKG_CHECK_MODULES(LIBEVDEV, [libevdev >= 0.4])
+PKG_CHECK_MODULES(LIBUNWIND,
+		  [libunwind],
+		  [HAVE_LIBUNWIND=yes],
+		  [HAVE_LIBUNWIND=no])
+if test "x$HAVE_LIBUNWIND" = "xyes"; then
+	AC_DEFINE(HAVE_LIBUNWIND, 1, [Have libunwind support])
+fi
+AM_CONDITIONAL(HAVE_LIBUNWIND, [test "x$HAVE_LIBUNWIND" = xyes])
+
 AC_CHECK_LIB([m], [atan2])
 AC_CHECK_LIB([rt], [clock_gettime])
 
@@ -190,5 +199,6 @@ AC_MSG_RESULT([
 	Build documentation	${build_documentation}
 	Build tests		${build_tests}
 	Tests use valgrind	${VALGRIND}
+	Tests use libunwind	${HAVE_LIBUNWIND}
 	Build GUI event tool	${build_eventgui}
 	])
diff --git a/test/Makefile.am b/test/Makefile.am
index 0df89b2..a36d368 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -38,6 +38,11 @@ liblitest_la_SOURCES = \
 	litest-vmware-virtual-usb-mouse.c \
 	litest.c
 liblitest_la_LIBADD = $(top_builddir)/src/libinput-util.la
+liblitest_la_CFLAGS = $(AM_CFLAGS)
+if HAVE_LIBUNWIND
+liblitest_la_LIBADD += $(LIBUNWIND_LIBS) -ldl
+liblitest_la_CFLAGS += $(LIBUNWIND_CFLAGS)
+endif
 
 run_tests = \
 	test-touchpad \
@@ -49,7 +54,9 @@ run_tests = \
 	test-path \
 	test-log \
 	test-misc \
-	test-keyboard
+	test-keyboard \
+	test-litest-selftest
+
 build_tests = \
 	test-build-cxx \
 	test-build-linker \
@@ -102,6 +109,11 @@ test_device_SOURCES = device.c
 test_device_LDADD = $(TEST_LIBS)
 test_device_LDFLAGS = -no-install
 
+test_litest_selftest_SOURCES = litest-selftest.c litest.c litest-int.h litest.h
+test_litest_selftest_CFLAGS = -DLITEST_DISABLE_BACKTRACE_LOGGING
+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
@@ -125,7 +137,7 @@ VALGRIND_FLAGS=--leak-check=full \
 	       --suppressions=$(srcdir)/valgrind.suppressions
 
 valgrind:
-	$(MAKE) check-TESTS LOG_COMPILER="$(VALGRIND)" LOG_FLAGS="$(VALGRIND_FLAGS)" CK_FORK=no
+	$(MAKE) check-TESTS LOG_COMPILER="$(VALGRIND)" LOG_FLAGS="$(VALGRIND_FLAGS)" CK_FORK=no USING_VALGRIND=yes
 
 check: valgrind
 
diff --git a/test/litest-selftest.c b/test/litest-selftest.c
new file mode 100644
index 0000000..5ed20ff
--- /dev/null
+++ b/test/litest-selftest.c
@@ -0,0 +1,228 @@
+#include <config.h>
+
+#include <check.h>
+#include <signal.h>
+
+#include "litest.h"
+
+START_TEST(litest_assert_trigger)
+{
+	litest_assert(1 == 2);
+}
+END_TEST
+
+START_TEST(litest_assert_notrigger)
+{
+	litest_assert(1 == 1);
+}
+END_TEST
+
+START_TEST(litest_assert_msg_trigger)
+{
+	litest_assert_msg(1 == 2, "1 is not 2\n");
+}
+END_TEST
+
+START_TEST(litest_assert_msg_NULL_trigger)
+{
+	litest_assert_msg(1 == 2, NULL);
+}
+END_TEST
+
+START_TEST(litest_assert_msg_notrigger)
+{
+	litest_assert_msg(1 == 1, "1 is not 2\n");
+	litest_assert_msg(1 == 1, NULL);
+}
+END_TEST
+
+START_TEST(litest_abort_msg_trigger)
+{
+	litest_abort_msg("message\n");
+}
+END_TEST
+
+START_TEST(litest_abort_msg_NULL_trigger)
+{
+	litest_abort_msg(NULL);
+}
+END_TEST
+
+START_TEST(litest_int_eq_trigger)
+{
+	int a = 10;
+	int b = 20;
+	litest_assert_int_eq(a, b);
+}
+END_TEST
+
+START_TEST(litest_int_eq_notrigger)
+{
+	int a = 10;
+	int b = 10;
+	litest_assert_int_eq(a, b);
+}
+END_TEST
+
+START_TEST(litest_int_ne_trigger)
+{
+	int a = 10;
+	int b = 10;
+	litest_assert_int_ne(a, b);
+}
+END_TEST
+
+START_TEST(litest_int_ne_notrigger)
+{
+	int a = 10;
+	int b = 20;
+	litest_assert_int_ne(a, b);
+}
+END_TEST
+
+START_TEST(litest_int_lt_trigger_eq)
+{
+	int a = 10;
+	int b = 10;
+	litest_assert_int_lt(a, b);
+}
+END_TEST
+
+START_TEST(litest_int_lt_trigger_gt)
+{
+	int a = 11;
+	int b = 10;
+	litest_assert_int_lt(a, b);
+}
+END_TEST
+
+START_TEST(litest_int_lt_notrigger)
+{
+	int a = 10;
+	int b = 11;
+	litest_assert_int_lt(a, b);
+}
+END_TEST
+
+START_TEST(litest_int_le_trigger)
+{
+	int a = 11;
+	int b = 10;
+	litest_assert_int_le(a, b);
+}
+END_TEST
+
+START_TEST(litest_int_le_notrigger)
+{
+	int a = 10;
+	int b = 11;
+	int c = 10;
+	litest_assert_int_le(a, b);
+	litest_assert_int_le(a, c);
+}
+END_TEST
+
+START_TEST(litest_int_gt_trigger_eq)
+{
+	int a = 10;
+	int b = 10;
+	litest_assert_int_gt(a, b);
+}
+END_TEST
+
+START_TEST(litest_int_gt_trigger_lt)
+{
+	int a = 9;
+	int b = 10;
+	litest_assert_int_gt(a, b);
+}
+END_TEST
+
+START_TEST(litest_int_gt_notrigger)
+{
+	int a = 10;
+	int b = 9;
+	litest_assert_int_gt(a, b);
+}
+END_TEST
+
+START_TEST(litest_int_ge_trigger)
+{
+	int a = 9;
+	int b = 10;
+	litest_assert_int_ge(a, b);
+}
+END_TEST
+
+START_TEST(litest_int_ge_notrigger)
+{
+	int a = 10;
+	int b = 9;
+	int c = 10;
+	litest_assert_int_ge(a, b);
+	litest_assert_int_ge(a, c);
+}
+END_TEST
+
+static Suite *
+litest_assert_macros_suite(void)
+{
+	TCase *tc;
+	Suite *s;
+
+	s = suite_create("litest:assert macros");
+	tc = tcase_create("assert");
+	tcase_add_test_raise_signal(tc, litest_assert_trigger, SIGABRT);
+	tcase_add_test(tc, litest_assert_notrigger);
+	tcase_add_test_raise_signal(tc, litest_assert_msg_trigger, SIGABRT);
+	tcase_add_test_raise_signal(tc, litest_assert_msg_NULL_trigger, SIGABRT);
+	tcase_add_test(tc, litest_assert_msg_notrigger);
+	suite_add_tcase(s, tc);
+
+	tc = tcase_create("abort");
+	tcase_add_test_raise_signal(tc, litest_abort_msg_trigger, SIGABRT);
+	tcase_add_test_raise_signal(tc, litest_abort_msg_NULL_trigger, SIGABRT);
+	suite_add_tcase(s, tc);
+
+	tc = tcase_create("int comparison ");
+	tcase_add_test_raise_signal(tc, litest_int_eq_trigger, SIGABRT);
+	tcase_add_test(tc, litest_int_eq_notrigger);
+	tcase_add_test_raise_signal(tc, litest_int_ne_trigger, SIGABRT);
+	tcase_add_test(tc, litest_int_ne_notrigger);
+	tcase_add_test_raise_signal(tc, litest_int_le_trigger, SIGABRT);
+	tcase_add_test(tc, litest_int_le_notrigger);
+	tcase_add_test_raise_signal(tc, litest_int_lt_trigger_gt, SIGABRT);
+	tcase_add_test_raise_signal(tc, litest_int_lt_trigger_eq, SIGABRT);
+	tcase_add_test(tc, litest_int_lt_notrigger);
+	tcase_add_test_raise_signal(tc, litest_int_ge_trigger, SIGABRT);
+	tcase_add_test(tc, litest_int_ge_notrigger);
+	tcase_add_test_raise_signal(tc, litest_int_gt_trigger_eq, SIGABRT);
+	tcase_add_test_raise_signal(tc, litest_int_gt_trigger_lt, SIGABRT);
+	tcase_add_test(tc, litest_int_gt_notrigger);
+	suite_add_tcase(s, tc);
+
+	return s;
+}
+
+int
+main (int argc, char **argv)
+{
+	int nfailed;
+	Suite *s;
+	SRunner *sr;
+
+        /* when running under valgrind we're using nofork mode, so a signal
+         * raised by a test will fail in valgrind. There's nothing to
+         * memcheck here anyway, so just skip the valgrind test */
+        if (getenv("USING_VALGRIND"))
+            return EXIT_SUCCESS;
+
+	s = litest_assert_macros_suite();
+        sr = srunner_create(s);
+
+	srunner_run_all(sr, CK_ENV);
+	nfailed = srunner_ntests_failed(sr);
+	srunner_free(sr);
+
+	return (nfailed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/test/litest.c b/test/litest.c
index 355c591..f284d22 100644
--- a/test/litest.c
+++ b/test/litest.c
@@ -1,5 +1,6 @@
 /*
  * Copyright © 2013 Red Hat, Inc.
+ * Copyright © 2013 Marcin Slusarz <marcin.slusarz at gmail.com>
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation for any purpose is hereby granted without fee, provided that
@@ -51,6 +52,142 @@
 static int in_debugger = -1;
 static int verbose = 0;
 
+#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 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) {
+		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;
+		else
+			filename = "?";
+
+		litest_log("%u: %s (%s%s+%#x) [%p]\n",
+			   i++,
+			   filename,
+			   procname,
+			   ret == -UNW_ENOMEM ? "..." : "",
+			   (int)off,
+			   (void *)(pip.start_ip + off));
+
+		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();
+}
+
 struct test {
 	struct list node;
 	char *name;
@@ -326,7 +463,7 @@ litest_add_for_device(const char *name,
 		dev++;
 	}
 
-	ck_abort_msg("Invalid test device type");
+	litest_abort_msg("Invalid test device type");
 }
 
 static int
@@ -489,13 +626,13 @@ merge_absinfo(const struct input_absinfo *orig,
 		return NULL;
 
 	abs = calloc(sz, sizeof(*abs));
-	ck_assert(abs != NULL);
+	litest_assert(abs != NULL);
 
 	nelem = 0;
 	while (orig[nelem].value != -1) {
 		abs[nelem] = orig[nelem];
 		nelem++;
-		ck_assert_int_lt(nelem, sz);
+		litest_assert_int_lt(nelem, sz);
 	}
 
 	/* just append, if the same axis is present twice, libevdev will
@@ -503,10 +640,10 @@ merge_absinfo(const struct input_absinfo *orig,
 	i = 0;
 	while (override && override[i].value != -1) {
 		abs[nelem++] = override[i++];
-		ck_assert_int_lt(nelem, sz);
+		litest_assert_int_lt(nelem, sz);
 	}
 
-	ck_assert_int_lt(nelem, sz);
+	litest_assert_int_lt(nelem, sz);
 	abs[nelem].value = -1;
 
 	return abs;
@@ -523,13 +660,13 @@ merge_events(const int *orig, const int *override)
 		return NULL;
 
 	events = calloc(sz, sizeof(int));
-	ck_assert(events != NULL);
+	litest_assert(events != NULL);
 
 	nelem = 0;
 	while (orig[nelem] != -1) {
 		events[nelem] = orig[nelem];
 		nelem++;
-		ck_assert_int_lt(nelem, sz);
+		litest_assert_int_lt(nelem, sz);
 	}
 
 	/* just append, if the same axis is present twice, libevdev will
@@ -537,10 +674,10 @@ merge_events(const int *orig, const int *override)
 	i = 0;
 	while (override && override[i] != -1) {
 		events[nelem++] = override[i++];
-		ck_assert_int_le(nelem, sz);
+		litest_assert_int_le(nelem, sz);
 	}
 
-	ck_assert_int_lt(nelem, sz);
+	litest_assert_int_lt(nelem, sz);
 	events[nelem] = -1;
 
 	return events;
@@ -566,14 +703,14 @@ litest_init_udev_rules(struct litest_test_device *dev)
 		      UDEV_RULES_D,
 		      UDEV_RULE_PREFIX,
 		      dev->shortname);
-	ck_assert_int_eq(rc,
-			 (int)(
-			 strlen(UDEV_RULES_D) +
-			 strlen(UDEV_RULE_PREFIX) +
-			 strlen(dev->shortname) + 7));
+	litest_assert_int_eq(rc,
+			     (int)(
+				   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);
+	litest_assert_notnull(f);
+	litest_assert_int_ge(fputs(dev->udev_rule, f), 0);
 	fclose(f);
 
 	litest_reload_udev_rules();
@@ -607,7 +744,7 @@ litest_create(enum litest_device_type which,
 		ck_abort_msg("Invalid device type %d\n", which);
 
 	d = zalloc(sizeof(*d));
-	ck_assert(d != NULL);
+	litest_assert(d != NULL);
 
 	udev_file = litest_init_udev_rules(*dev);
 
@@ -617,8 +754,7 @@ litest_create(enum litest_device_type which,
 		if (abs_override || events_override) {
 			if (udev_file)
 				unlink(udev_file);
-			ck_abort_msg("Custom create cannot"
-				     "be overridden");
+			litest_abort_msg("Custom create cannot be overridden");
 		}
 
 		return d;
@@ -647,7 +783,7 @@ litest_create_context(void)
 {
 	struct libinput *libinput =
 		libinput_path_create_context(&interface, NULL);
-	ck_assert_notnull(libinput);
+	litest_assert_notnull(libinput);
 
 	libinput_log_set_handler(libinput, litest_log_handler);
 	if (verbose)
@@ -688,16 +824,16 @@ litest_add_device_with_overrides(struct libinput *libinput,
 			  events_override);
 
 	path = libevdev_uinput_get_devnode(d->uinput);
-	ck_assert(path != NULL);
+	litest_assert(path != NULL);
 	fd = open(path, O_RDWR|O_NONBLOCK);
-	ck_assert_int_ne(fd, -1);
+	litest_assert_int_ne(fd, -1);
 
 	rc = libevdev_new_from_fd(fd, &d->evdev);
-	ck_assert_int_eq(rc, 0);
+	litest_assert_int_eq(rc, 0);
 
 	d->libinput = libinput;
 	d->libinput_device = libinput_path_add_device(d->libinput, path);
-	ck_assert(d->libinput_device != NULL);
+	litest_assert(d->libinput_device != NULL);
 	libinput_device_ref(d->libinput_device);
 
 	if (d->interface) {
@@ -792,7 +928,7 @@ litest_event(struct litest_device *d, unsigned int type,
 		return;
 
 	ret = libevdev_uinput_write_event(d->uinput, type, code, value);
-	ck_assert_int_eq(ret, 0);
+	litest_assert_int_eq(ret, 0);
 }
 
 int
@@ -1125,9 +1261,9 @@ int
 litest_scale(const struct litest_device *d, unsigned int axis, double val)
 {
 	int min, max;
-	ck_assert_int_ge((int)val, 0);
-	ck_assert_int_le((int)val, 100);
-	ck_assert_int_le(axis, (unsigned int)ABS_Y);
+	litest_assert_int_ge((int)val, 0);
+	litest_assert_int_le((int)val, 100);
+	litest_assert_int_le(axis, (unsigned int)ABS_Y);
 
 	min = d->interface->min[axis];
 	max = d->interface->max[axis];
@@ -1308,7 +1444,7 @@ litest_assert_empty_queue(struct libinput *li)
 		libinput_dispatch(li);
 	}
 
-	ck_assert(empty_queue);
+	litest_assert(empty_queue);
 }
 
 struct libevdev_uinput *
@@ -1334,7 +1470,7 @@ litest_create_uinput_device_from_description(const char *name,
 	const char *devnode;
 
 	dev = libevdev_new();
-	ck_assert(dev != NULL);
+	litest_assert(dev != NULL);
 
 	snprintf(buf, sizeof(buf), "litest %s", name);
 	libevdev_set_name(dev, buf);
@@ -1349,7 +1485,7 @@ litest_create_uinput_device_from_description(const char *name,
 	while (abs && abs->value != -1) {
 		rc = libevdev_enable_event_code(dev, EV_ABS,
 						abs->value, abs);
-		ck_assert_int_eq(rc, 0);
+		litest_assert_int_eq(rc, 0);
 		abs++;
 	}
 
@@ -1362,7 +1498,7 @@ litest_create_uinput_device_from_description(const char *name,
 			rc = libevdev_enable_event_code(dev, type, code,
 							type == EV_ABS ? &default_abs : NULL);
 		}
-		ck_assert_int_eq(rc, 0);
+		litest_assert_int_eq(rc, 0);
 	}
 
 	rc = libevdev_uinput_create_from_device(dev,
@@ -1372,16 +1508,16 @@ litest_create_uinput_device_from_description(const char *name,
 	   http://cgit.freedesktop.org/libevdev/commit/?id=debe9b030c8069cdf78307888ef3b65830b25122 */
 	if (rc == -EBADF)
 		rc = -EACCES;
-	ck_assert_msg(rc == 0, "Failed to create uinput device: %s", strerror(-rc));
+	litest_assert_msg(rc == 0, "Failed to create uinput device: %s", strerror(-rc));
 
 	libevdev_free(dev);
 
 	devnode = libevdev_uinput_get_devnode(uinput);
-	ck_assert_notnull(devnode);
+	litest_assert_notnull(devnode);
 	fd = open(devnode, O_RDONLY);
-	ck_assert_int_gt(fd, -1);
+	litest_assert_int_gt(fd, -1);
 	rc = libevdev_new_from_fd(fd, &dev);
-	ck_assert_int_eq(rc, 0);
+	litest_assert_int_eq(rc, 0);
 
 	/* uinput does not yet support setting the resolution, so we set it
 	 * afterwards. This is of course racy as hell but the way we
@@ -1393,7 +1529,7 @@ litest_create_uinput_device_from_description(const char *name,
 			rc = libevdev_kernel_set_abs_info(dev,
 							  abs->value,
 							  abs);
-			ck_assert_int_eq(rc, 0);
+			litest_assert_int_eq(rc, 0);
 		}
 		abs++;
 	}
@@ -1417,7 +1553,7 @@ litest_create_uinput_abs_device_v(const char *name,
 	       (code = va_arg(args, int)) != -1) {
 		*event++ = type;
 		*event++ = code;
-		ck_assert(event < &events[ARRAY_LENGTH(events) - 2]);
+		litest_assert(event < &events[ARRAY_LENGTH(events) - 2]);
 	}
 
 	*event++ = -1;
@@ -1464,13 +1600,13 @@ litest_is_button_event(struct libinput_event *event,
 	struct libinput_event_pointer *ptrev;
 	enum libinput_event_type type = LIBINPUT_EVENT_POINTER_BUTTON;
 
-	ck_assert(event != NULL);
-	ck_assert_int_eq(libinput_event_get_type(event), type);
+	litest_assert(event != NULL);
+	litest_assert_int_eq(libinput_event_get_type(event), type);
 	ptrev = libinput_event_get_pointer_event(event);
-	ck_assert_int_eq(libinput_event_pointer_get_button(ptrev),
-			 button);
-	ck_assert_int_eq(libinput_event_pointer_get_button_state(ptrev),
-			 state);
+	litest_assert_int_eq(libinput_event_pointer_get_button(ptrev),
+			     button);
+	litest_assert_int_eq(libinput_event_pointer_get_button_state(ptrev),
+			     state);
 
 	return ptrev;
 }
@@ -1483,14 +1619,14 @@ litest_is_axis_event(struct libinput_event *event,
 	struct libinput_event_pointer *ptrev;
 	enum libinput_event_type type = LIBINPUT_EVENT_POINTER_AXIS;
 
-	ck_assert(event != NULL);
-	ck_assert_int_eq(libinput_event_get_type(event), type);
+	litest_assert(event != NULL);
+	litest_assert_int_eq(libinput_event_get_type(event), type);
 	ptrev = libinput_event_get_pointer_event(event);
-	ck_assert(libinput_event_pointer_has_axis(ptrev, axis));
+	litest_assert(libinput_event_pointer_has_axis(ptrev, axis));
 
 	if (source != 0)
-		ck_assert_int_eq(libinput_event_pointer_get_axis_source(ptrev),
-				 source);
+		litest_assert_int_eq(libinput_event_pointer_get_axis_source(ptrev),
+				     source);
 
 	return ptrev;
 }
@@ -1502,8 +1638,8 @@ litest_is_motion_event(struct libinput_event *event)
 	enum libinput_event_type type = LIBINPUT_EVENT_POINTER_MOTION;
 	double x, y, ux, uy;
 
-	ck_assert(event != NULL);
-	ck_assert_int_eq(libinput_event_get_type(event), type);
+	litest_assert(event != NULL);
+	litest_assert_int_eq(libinput_event_get_type(event), type);
 	ptrev = libinput_event_get_pointer_event(event);
 
 	x = libinput_event_pointer_get_dx(ptrev);
@@ -1512,8 +1648,8 @@ litest_is_motion_event(struct libinput_event *event)
 	uy = libinput_event_pointer_get_dy_unaccelerated(ptrev);
 
 	/* No 0 delta motion events */
-	ck_assert(x != 0.0 || y != 0.0 ||
-		  ux != 0.0 || uy != 0.0);
+	litest_assert(x != 0.0 || y != 0.0 ||
+		      ux != 0.0 || uy != 0.0);
 
 	return ptrev;
 }
@@ -1538,7 +1674,7 @@ litest_is_touch_event(struct libinput_event *event,
 {
 	struct libinput_event_touch *touch;
 
-	ck_assert(event != NULL);
+	litest_assert(event != NULL);
 
 	if (type == 0)
 		type = libinput_event_get_type(event);
@@ -1548,7 +1684,7 @@ litest_is_touch_event(struct libinput_event *event,
 	case LIBINPUT_EVENT_TOUCH_UP:
 	case LIBINPUT_EVENT_TOUCH_MOTION:
 	case LIBINPUT_EVENT_TOUCH_FRAME:
-		ck_assert_int_eq(libinput_event_get_type(event), type);
+		litest_assert_int_eq(libinput_event_get_type(event), type);
 		break;
 	default:
 		ck_abort_msg("%s: invalid touch type %d\n", __func__, type);
@@ -1567,15 +1703,15 @@ litest_is_keyboard_event(struct libinput_event *event,
 	struct libinput_event_keyboard *kevent;
 	enum libinput_event_type type = LIBINPUT_EVENT_KEYBOARD_KEY;
 
-	ck_assert_notnull(event);
-	ck_assert_int_eq(libinput_event_get_type(event), type);
+	litest_assert(event != NULL);
+	litest_assert_int_eq(libinput_event_get_type(event), type);
 
 	kevent = libinput_event_get_keyboard_event(event);
-	ck_assert_notnull(kevent);
+	litest_assert(kevent != NULL);
 
-	ck_assert_int_eq(libinput_event_keyboard_get_key(kevent), key);
-	ck_assert_int_eq(libinput_event_keyboard_get_key_state(kevent),
-			 state);
+	litest_assert_int_eq(libinput_event_keyboard_get_key(kevent), key);
+	litest_assert_int_eq(libinput_event_keyboard_get_key_state(kevent),
+			     state);
 	return kevent;
 }
 
@@ -1590,7 +1726,7 @@ litest_assert_scroll(struct libinput *li,
 
 	event = libinput_get_event(li);
 	next_event = libinput_get_event(li);
-	ck_assert(next_event != NULL); /* At least 1 scroll + stop scroll */
+	litest_assert(next_event != NULL); /* At least 1 scroll + stop scroll */
 
 	while (event) {
 		ptrev = litest_is_axis_event(event, axis, 0);
@@ -1600,13 +1736,13 @@ litest_assert_scroll(struct libinput *li,
 								      axis);
 			/* Normal scroll event, check dir */
 			if (minimum_movement > 0) {
-				ck_assert_int_ge(value, minimum_movement);
+				litest_assert_int_ge(value, minimum_movement);
 			} else {
-				ck_assert_int_le(value, minimum_movement);
+				litest_assert_int_le(value, minimum_movement);
 			}
 		} else {
 			/* Last scroll event, must be 0 */
-			ck_assert_int_eq(
+			litest_assert_int_eq(
 				libinput_event_pointer_get_axis_value(ptrev, axis),
 				0);
 		}
@@ -1626,11 +1762,11 @@ litest_assert_only_typed_events(struct libinput *li,
 
 	libinput_dispatch(li);
 	event = libinput_get_event(li);
-	ck_assert_notnull(event);
+	litest_assert_notnull(event);
 
 	while (event) {
-		ck_assert_int_eq(libinput_event_get_type(event),
-				 type);
+		litest_assert_int_eq(libinput_event_get_type(event),
+                                     type);
 		libinput_event_destroy(event);
 		libinput_dispatch(li);
 		event = libinput_get_event(li);
diff --git a/test/litest.h b/test/litest.h
index 664b49a..f13ea7e 100644
--- a/test/litest.h
+++ b/test/litest.h
@@ -32,6 +32,62 @@
 #include <libevdev/libevdev.h>
 #include <libevdev/libevdev-uinput.h>
 #include <libinput.h>
+#include <math.h>
+
+#define litest_assert(cond) \
+	do { \
+		if (!(cond)) \
+			litest_fail_condition(__FILE__, __LINE__, __func__, \
+					      #cond, NULL); \
+	} while(0)
+
+#define litest_assert_msg(cond, ...) \
+	do { \
+		if (!(cond)) \
+			litest_fail_condition(__FILE__, __LINE__, __func__, \
+					      #cond, __VA_ARGS__); \
+	} while(0)
+
+#define litest_abort_msg(...) \
+	litest_fail_condition(__FILE__, __LINE__, __func__, \
+			      "aborting", __VA_ARGS__); \
+
+#define litest_assert_notnull(cond) \
+	do { \
+		if ((cond) == NULL) \
+			litest_fail_condition(__FILE__, __LINE__, __func__, \
+					      #cond, " expected to be not NULL"); \
+	} while(0)
+
+#define litest_assert_comparison_int_(a_, op_, b_) \
+	do { \
+		__typeof__(a_) _a = a_; \
+		__typeof__(b_) _b = b_; \
+		if (trunc(_a) != _a || trunc(_b) != _b) \
+			litest_abort_msg("litest_assert_int_* used for non-integer value\n"); \
+		if (!((_a) op_ (_b))) \
+			litest_fail_comparison_int(__FILE__, __LINE__, __func__,\
+						   #op_, _a, _b, \
+						   #a_, #b_); \
+	} while(0)
+
+#define litest_assert_int_eq(a_, b_) \
+	litest_assert_comparison_int_(a_, ==, b_)
+
+#define litest_assert_int_ne(a_, b_) \
+	litest_assert_comparison_int_(a_, !=, b_)
+
+#define litest_assert_int_lt(a_, b_) \
+	litest_assert_comparison_int_(a_, <, b_)
+
+#define litest_assert_int_le(a_, b_) \
+	litest_assert_comparison_int_(a_, <=, b_)
+
+#define litest_assert_int_ge(a_, b_) \
+	litest_assert_comparison_int_(a_, >=, b_)
+
+#define litest_assert_int_gt(a_, b_) \
+	litest_assert_comparison_int_(a_, >, b_)
 
 enum litest_device_type {
 	LITEST_NO_DEVICE = -1,
@@ -101,6 +157,23 @@ struct libinput *litest_create_context(void);
 void litest_disable_log_handler(struct libinput *libinput);
 void litest_restore_log_handler(struct libinput *libinput);
 
+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_add(const char *name, void *func,
 		enum litest_device_feature required_feature,
 		enum litest_device_feature excluded_feature);
diff --git a/test/valgrind.suppressions b/test/valgrind.suppressions
index 5aef8a4..50b5c58 100644
--- a/test/valgrind.suppressions
+++ b/test/valgrind.suppressions
@@ -13,3 +13,11 @@
    ...
    fun:mtdev_put_event
 }
+{
+   libunwind:msync_uninitialized_bytes
+   Memcheck:Param
+   msync(start)
+   fun:__msync_nocancel
+   ...
+   fun:litest_backtrace
+}
-- 
2.3.5



More information about the wayland-devel mailing list