diff options
Diffstat (limited to 'source/kit_test')
-rw-r--r-- | source/kit_test/test.c | 79 | ||||
-rw-r--r-- | source/kit_test/test.h | 16 |
2 files changed, 78 insertions, 17 deletions
diff --git a/source/kit_test/test.c b/source/kit_test/test.c index dea8a23..505392e 100644 --- a/source/kit_test/test.c +++ b/source/kit_test/test.c @@ -4,15 +4,17 @@ #include <string.h> #include <time.h> +#include <setjmp.h> +#include <signal.h> + kit_tests_list_t kit_tests_list = { 0 }; -static void report(int i, char const *file, int line, int ok) { +static void report(int i, int line, int ok) { int const n = kit_tests_list.tests[i].assertions++; if (n >= KIT_TEST_ASSERTIONS_LIMIT) return; - kit_tests_list.tests[i].file[n] = file; kit_tests_list.tests[i].line[n] = line; kit_tests_list.tests[i].status[n] = ok; } @@ -40,16 +42,63 @@ static void color_code(int term_color, int c) { } } -void kit_test_register(char const *name, kit_test_run_fn fn) { +void kit_test_register(char const *name, char const *file, + kit_test_run_fn fn) { int n = kit_tests_list.size++; if (n < KIT_TESTS_SIZE_LIMIT) { kit_tests_list.tests[n].test_fn = fn; kit_tests_list.tests[n].test_name = name; + kit_tests_list.tests[n].test_file = file; kit_tests_list.tests[n].assertions = 0; } } +static jmp_buf kit_test_restore_execution; + +static int const signums[] = { SIGILL, SIGABRT, SIGFPE, SIGSEGV, + SIGTERM }; + +static char const *const signames[] = { + [SIGILL] = "Illegal instruction", + [SIGABRT] = "Abnormal termination", + [SIGFPE] = "Erroneous arithmetic operation", + [SIGSEGV] = "Invalid access to storage", + [SIGTERM] = "Termination request" +}; + +static void handle_signal(int signum) { + longjmp(kit_test_restore_execution, signum); +} + +static void setup_signals() { + for (int i = 0; i < sizeof signums / sizeof *signums; i++) { +#if defined(_WIN32) && !(defined __CYGWIN__) + signal(signums[i], handle_signal); +#else + struct sigaction action; + memset(&action, 0, sizeof action); + action.sa_handler = handle_signal; + + sigaction(signums[i], &action, NULL); +#endif + } +} + +static int run_test(volatile int i) { + int signum = setjmp(kit_test_restore_execution); + + if (signum != 0) { + kit_tests_list.tests[i].signal = signum; + return 0; + } + + kit_tests_list.tests[i].test_fn(i, report); + return 1; +} + int kit_run_tests(int argc, char **argv) { + setup_signals(); + int success_count = 0; int fail_assertion_count = 0; int total_assertion_count = 0; @@ -81,7 +130,7 @@ int kit_run_tests(int argc, char **argv) { struct timespec begin, end; timespec_get(&begin, TIME_UTC); - kit_tests_list.tests[i].test_fn(i, report); + int test_status = run_test(i); timespec_get(&end, TIME_UTC); int duration = (int) (ns_to_ms(end.tv_nsec - begin.tv_nsec) + @@ -90,8 +139,6 @@ int kit_run_tests(int argc, char **argv) { if (carriage_return) quiet || printf("\r"); - int test_status = 1; - for (int j = 0; j < kit_tests_list.tests[i].assertions; j++) if (kit_tests_list.tests[i].status[j] == 0) { fail_assertion_count++; @@ -139,18 +186,32 @@ int kit_run_tests(int argc, char **argv) { if (status != 0) { for (int i = 0; i < kit_tests_list.size && i < KIT_TESTS_SIZE_LIMIT; i++) { + if (kit_tests_list.tests[i].signal != 0) { + int signum = kit_tests_list.tests[i].signal; + if (signum >= 0 && + signum < sizeof signames / sizeof *signames) + quiet || + printf("Signal \"%s\" (%d) for \"%s\" in \"%s\"!\n", + signames[signum], signum, + kit_tests_list.tests[i].test_name, + kit_tests_list.tests[i].test_file); + else + quiet || + printf("Unknown signal (%d) for \"%s\" in \"%s\"!\n", + signum, kit_tests_list.tests[i].test_name, + kit_tests_list.tests[i].test_file); + } if (kit_tests_list.tests[i].assertions > KIT_TEST_ASSERTIONS_LIMIT) quiet || printf("Too many assertions for \"%s\" in \"%s\"!\n", kit_tests_list.tests[i].test_name, - kit_tests_list.tests[i] - .file[KIT_TEST_ASSERTIONS_LIMIT - 1]); + kit_tests_list.tests[i].test_file); else for (int j = 0; j < kit_tests_list.tests[i].assertions; j++) if (!kit_tests_list.tests[i].status[j]) quiet || printf("Assertion on line %d in \"%s\" failed\n", kit_tests_list.tests[i].line[j], - kit_tests_list.tests[i].file[j]); + kit_tests_list.tests[i].test_file); } quiet || printf("\n"); diff --git a/source/kit_test/test.h b/source/kit_test/test.h index 176d957..2ef339f 100644 --- a/source/kit_test/test.h +++ b/source/kit_test/test.h @@ -19,18 +19,18 @@ extern "C" { # define KIT_TEST_ASSERTIONS_LIMIT 0x50 #endif -typedef void (*kit_test_report_fn)(int test_index, char const *file, - int line, int ok); +typedef void (*kit_test_report_fn)(int test_index, int line, int ok); typedef void (*kit_test_run_fn)( int kit_test_index_, kit_test_report_fn kit_test_report_fn_); typedef struct { char const *test_name; + char const *test_file; kit_test_run_fn test_fn; int assertions; - char const *file[KIT_TEST_ASSERTIONS_LIMIT]; int line[KIT_TEST_ASSERTIONS_LIMIT]; int status[KIT_TEST_ASSERTIONS_LIMIT]; + int signal; } kit_test_case_t; typedef struct { @@ -75,7 +75,8 @@ extern kit_tests_list_t kit_tests_list; # endif #endif -void kit_test_register(char const *name, kit_test_run_fn fn); +void kit_test_register(char const *name, char const *file, + kit_test_run_fn fn); #define KIT_TEST(name) \ static void KIT_TEST_CONCAT3_(kit_test_run_, __LINE__, \ @@ -84,16 +85,15 @@ void kit_test_register(char const *name, kit_test_run_fn fn); KIT_TEST_ON_START_( \ KIT_TEST_CONCAT3_(kit_test_case_, __LINE__, KIT_TEST_FILE)) { \ kit_test_register( \ - name, \ + name, __FILE__, \ KIT_TEST_CONCAT3_(kit_test_run_, __LINE__, KIT_TEST_FILE)); \ } \ static void KIT_TEST_CONCAT3_(kit_test_run_, __LINE__, \ KIT_TEST_FILE)( \ int kit_test_index_, kit_test_report_fn kit_test_report_fn_) -#define KIT_REQUIRE(...) \ - kit_test_report_fn_(kit_test_index_, __FILE__, __LINE__, \ - (__VA_ARGS__)) +#define KIT_REQUIRE(...) \ + kit_test_report_fn_(kit_test_index_, __LINE__, (__VA_ARGS__)) int kit_run_tests(int argc, char **argv); |