test: add ability to collect test results from a nonforking test

Use longjmp to try to get out of a test error. This will only work for
errors triggered by our own test suite (i.e. not for SIGSEGV and
friends) but that's good enough for most things.

Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1067>
This commit is contained in:
Peter Hutterer 2024-10-17 08:29:22 +10:00 committed by Marge Bot
parent c1f744a6e5
commit 3c2e92d169
3 changed files with 38 additions and 9 deletions

View file

@ -34,6 +34,7 @@
#include <fcntl.h>
#include <stdlib.h>
#include <signal.h>
#include <setjmp.h>
#include <valgrind/valgrind.h>
#include "litest-runner.h"
@ -42,6 +43,9 @@
#include "util-list.h"
#include "util-stringbuf.h"
static bool use_jmpbuf; /* only used for max_forks = 0 */
static jmp_buf jmpbuf;
/* musl doesn't have this one but it's not that important */
#ifndef HAVE_SIGABBREV_NP
#define sigabbrev_np(...) "???"
@ -587,10 +591,20 @@ litest_runner_test_update_errno(struct litest_runner_test *t, int error)
}
}
__attribute__((noreturn))
void
litest_runner_abort(void) {
if (use_jmpbuf) {
longjmp(jmpbuf, SIGABRT);
} else {
abort();
}
}
static int
litest_runner_run_test(struct litest_runner *runner, struct litest_runner_test *t)
{
int r = 0;
int r;
t->result = LITEST_SYSTEM_ERROR;
@ -599,7 +613,12 @@ litest_runner_run_test(struct litest_runner *runner, struct litest_runner_test *
t->times.start_millis = us2ms(now);
if (runner->max_forks == 0) {
t->result = litest_runner_test_run(&t->desc);
if (use_jmpbuf && setjmp(jmpbuf) == 0) {
t->result = litest_runner_test_run(&t->desc);
} else {
t->result = LITEST_FAIL;
}
r = 0; /* -Wclobbered */
} else {
r = litest_runner_fork_test(runner, t);
if (r >= 0)
@ -845,6 +864,8 @@ litest_runner_run_tests(struct litest_runner *runner)
if (runner->global.setup)
runner->global.setup(runner->global.userdata);
use_jmpbuf = runner->max_forks == 0;
setup_sighandler(SIGINT);
uint64_t now = 0;

View file

@ -92,3 +92,11 @@ litest_runner_set_setup_funcs(struct litest_runner *runner,
void *userdata);
void litest_runner_destroy(struct litest_runner *runner);
/*
* Function to call abort(). Depending on the number of forks permitted,
* this function may simply abort() or it may longjmp back out to collect
* errors from non-forking tests.
*/
__attribute__((noreturn))
void litest_runner_abort(void);

View file

@ -185,7 +185,7 @@ litest_fail_condition(const char *file,
litest_log("in %s() (%s:%d)\n", func, file, line);
litest_backtrace();
abort();
litest_runner_abort();
}
__attribute__((noreturn))
@ -203,7 +203,7 @@ litest_fail_comparison_int(const char *file,
litest_log("Resolved to: %d %s %d\n", a, operator, b);
litest_log("in %s() (%s:%d)\n", func, file, line);
litest_backtrace();
abort();
litest_runner_abort();
}
__attribute__((noreturn))
@ -221,7 +221,7 @@ litest_fail_comparison_double(const char *file,
litest_log("Resolved to: %.3f %s %.3f\n", a, operator, b);
litest_log("in %s() (%s:%d)\n", func, file, line);
litest_backtrace();
abort();
litest_runner_abort();
}
__attribute__((noreturn))
@ -234,7 +234,7 @@ litest_fail_comparison_ptr(const char *file,
litest_log("FAILED COMPARISON: %s\n", comparison);
litest_log("in %s() (%s:%d)\n", func, file, line);
litest_backtrace();
abort();
litest_runner_abort();
}
__attribute__((noreturn))
@ -251,7 +251,7 @@ litest_fail_comparison_str(const char *file,
litest_log("Resolved to: %s %s %s\n", astr, operator, bstr);
litest_log("in %s() (%s:%d)\n", func, file, line);
litest_backtrace();
abort();
litest_runner_abort();
}
struct test {
@ -3257,7 +3257,7 @@ _litest_assert_event_type_is_one_of(struct libinput_event *event, ...)
fprintf(stderr, "\nWrong event is: ");
litest_print_event(event);
litest_backtrace();
abort();
litest_runner_abort();
}
void
@ -3298,7 +3298,7 @@ _litest_assert_event_type_not_one_of(struct libinput_event *event, ...)
fprintf(stderr, "\nWrong event is: ");
litest_print_event(event);
litest_backtrace();
abort();
litest_runner_abort();
}
void