From 93b063fedfcf7409a67df035170ea5670cad22e1 Mon Sep 17 00:00:00 2001 From: Josh Rahm Date: Tue, 24 Nov 2020 13:46:41 -0700 Subject: Moved action to top level. Removed old iterations of the project and moved the files from 02-usart to the root directory since that's the sole place where the action is and that subproject has outgrown its initial title. --- test_harness/test_harness.c | 181 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 181 insertions(+) create mode 100644 test_harness/test_harness.c (limited to 'test_harness/test_harness.c') diff --git a/test_harness/test_harness.c b/test_harness/test_harness.c new file mode 100644 index 0000000..bf9249c --- /dev/null +++ b/test_harness/test_harness.c @@ -0,0 +1,181 @@ +#include "test_harness.h" +#include "fake_env.h" + +#include +#include +#include +#include +#include +#include +#include + + +static jmp_buf jmpbuf; + +volatile test_t dummy + __attribute((__section__("tests"))) + __attribute((__used__)) = { + "dummy", + "dummy", + NULL +}; + +extern unsigned char __data_start; +extern unsigned char _end; +extern test_t __start_tests; +extern test_t __stop_tests; + +test_t* iter = &__start_tests; + +static int execute_test(test_t* test); + +void test_printll(size_t sz, long long v1, long long v2) +{ + fprintf(stderr, "%lld == %lld\n", v1, v2); +} +void test_printul(size_t sz, unsigned long v1, unsigned long v2) +{ + fprintf(stderr, "%lu == %lu\n", v1, v2); +} +void test_printd(size_t sz, int v1, int v2) +{ + fprintf(stderr, "%d == %d\n", v1, v2); +} +void test_printl(size_t sz, long v1, long v2) +{ + fprintf(stderr, "%lu == %lu\n", v1, v2); +} +void test_printui(size_t sz, unsigned int v1, unsigned int v2) +{ + fprintf(stderr, "%u == %u\n", v1, v2); +} +void test_prints(size_t sz, short v1, short v2) +{ + fprintf(stderr, "%hu == %hu\n", v1, v2); +} +void test_printus(size_t sz, unsigned short v1, unsigned short v2) +{ + fprintf(stderr, "%hu == %hu\n", v1, v2); +} +void test_printc(size_t sz, char v1, char v2) +{ + fprintf(stderr, "'%c' == '%c'\n", v1, v2); +} +void test_printf(size_t sz, double v1, double v2) +{ + fprintf(stderr, "%f == %f\n", v1, v2); +} +void test_printp(size_t sz, void* v1, void* v2) +{ + fprintf(stderr, "%p == %p\n", v1, v2); +} +void test_printuc( + size_t sz, unsigned char v1, unsigned char v2) +{ + fprintf(stderr, "%02x == %02x\n", (int) v1, (int) v2); +} + +static int do_fork = 1; +static size_t saved_data_size; +static unsigned char* saved_data = NULL; + +int main(int argc, char** argv) { + /* Save all initialized data. */ + saved_data_size = &_end - &__data_start; + saved_data = malloc(saved_data_size); + memcpy(saved_data, &__data_start, saved_data_size); + + + if (argc > 1 && strcmp(argv[1], "--nofork") == 0) { + do_fork = 0; + } + + for( ; iter < &__stop_tests; ++ iter) { + if (iter->fn_ptr != NULL) { + execute_test(iter); + } + } +} + +void test_harness_abort(int ec) +{ + longjmp(jmpbuf, ec); + assert("Long jump failed.\n"); +} + +/* + * When nofork is true, this function will be called after each + * test to try and make each test hermetic. + * + * It does this by reseting the data segment to what it was when + * the program was first initialized. + * + * Of course, without forking, there's no way to guarantee hermetic + * testing in C. In fact a simple segementation fault will break + * the hermetic testing, but this does a pretty good job of at least + * reseting the environment so tests don't directly depend on eachother. + */ +static void nofork_reset() +{ + wipeout_fake_env(); + + /* Reset the data segment to what it was before. */ + memcpy(&__data_start, saved_data, saved_data_size); +} + +static int execute_test(test_t* test) +{ + char fullname[512]; + int status; + int ec = 0; + pid_t pid; + + snprintf( + fullname, sizeof(fullname), "%s::%s", iter->test_suite, iter->test_name); + + if (!do_fork) { + if ((ec = setjmp(jmpbuf)) == 0) { + test->fn_ptr(); + printf(GREEN "[PASS]" RESET " %s\n", fullname); + nofork_reset(); + return 0; + } else { + printf(RED "[FAIL] (%d)" RESET " %s\n", ec, fullname); + nofork_reset(); + return ec; + } + } + + if (!(pid = fork())) { + // child + + if ((ec = setjmp(jmpbuf))) { + exit(ec); + } else { + test->fn_ptr(); + exit(0); + } + } else { + if (waitpid(pid, &status, 0) == -1) { + fprintf(stderr, "waitpid() failed\n"); + return 1; + } + + if (WIFEXITED(status)) { + switch ((ec = WEXITSTATUS(status))) { + case 0: + printf(GREEN "[PASS]" RESET " %s\n", fullname); + return 0; + default: + printf(RED "[FAIL] (%d)" RESET " %s\n", ec, fullname); + return ec; + } + } else if (WIFSIGNALED(status)) { + int ec = WTERMSIG(status); + printf("%s " RED "[FAIL] signaled %d" RESET "\n", fullname, ec); + return ec; + } + + return ec; + } +} -- cgit