From 26dfa76faa883c35fe3e5ff4b2b33f4102059a81 Mon Sep 17 00:00:00 2001 From: Mitya Selivanov <0x7fffff@guattari.ru> Date: Fri, 5 Aug 2022 21:17:16 +0400 Subject: Async function & unit-testing --- source/kit_test/CMakeLists.txt | 6 +++ source/kit_test/run_tests.c | 112 +++++++++++++++++++++++++++++++++++++++++ source/kit_test/test.h | 96 +++++++++++++++++++++++++++++++++++ 3 files changed, 214 insertions(+) create mode 100644 source/kit_test/CMakeLists.txt create mode 100644 source/kit_test/run_tests.c create mode 100644 source/kit_test/test.h (limited to 'source/kit_test') diff --git a/source/kit_test/CMakeLists.txt b/source/kit_test/CMakeLists.txt new file mode 100644 index 0000000..f7315a1 --- /dev/null +++ b/source/kit_test/CMakeLists.txt @@ -0,0 +1,6 @@ +target_sources( + ${KIT_TEST_LIBRARY} + PRIVATE + run_tests.c + PUBLIC + $) diff --git a/source/kit_test/run_tests.c b/source/kit_test/run_tests.c new file mode 100644 index 0000000..191982a --- /dev/null +++ b/source/kit_test/run_tests.c @@ -0,0 +1,112 @@ +#include "test.h" + +#include +#include + +struct kit_tests_list kit_tests_list = { 0 }; + +static void report(int i, char const *file, int line, bool ok) { + int const n = kit_tests_list.tests[i].assertions++; + + kit_tests_list.tests[i].file[n] = file; + kit_tests_list.tests[i].line[n] = line; + kit_tests_list.tests[i].status[n] = ok; +} + +static long long ns_to_ms(long long ns) { + return (ns + 500000) / 1000000; +} + +static long long sec_to_ms(long long sec) { + return 1000 * sec; +} + +enum code_value { white, yellow, red, green }; + +static void color_code(bool term_color, int c) { + if (term_color) { + if (c == white) + printf("\x1b[37m"); + if (c == yellow) + printf("\x1b[33m"); + if (c == red) + printf("\x1b[31m"); + if (c == green) + printf("\x1b[32m"); + } +} + +int kit_run_tests(int argc, char **argv) { + int fail_test_count = 0; + int fail_assertion_count = 0; + int total_assertion_count = 0; + int status = 0; + bool term_color = true; + + for (int i = 0; i < argc; i++) + if (strcmp("--no-term-color", argv[i]) == 0) + term_color = false; + + for (int i = 0; i < kit_tests_list.size; i++) { + color_code(term_color, yellow); + printf("[ RUN... ] %s ", kit_tests_list.tests[i].test_name); + color_code(term_color, white); + + struct timespec begin, end; + timespec_get(&begin, TIME_UTC); + + kit_tests_list.tests[i].test_fn(i, report); + + timespec_get(&end, TIME_UTC); + int duration = (int) (ns_to_ms(end.tv_nsec - begin.tv_nsec) + + sec_to_ms(end.tv_sec - begin.tv_sec)); + + printf("\r"); + + bool test_status = true; + + for (int j = 0; j < kit_tests_list.tests[i].assertions; j++) + if (kit_tests_list.tests[i].status[j] == false) { + fail_assertion_count++; + test_status = false; + } + + total_assertion_count += kit_tests_list.tests[i].assertions; + + if (test_status == false) { + color_code(term_color, red); + printf("[ RUN ] %s\n", kit_tests_list.tests[i].test_name); + printf("[ FAILED ] %s - %d ms\n", + kit_tests_list.tests[i].test_name, duration); + color_code(term_color, white); + fail_test_count++; + status = 1; + } else { + color_code(term_color, green); + printf("[ RUN ] %s\n", kit_tests_list.tests[i].test_name); + printf("[ OK ] %s - %d ms\n", + kit_tests_list.tests[i].test_name, duration); + color_code(term_color, white); + } + } + + printf("\n%d of %d tests passed.\n", + kit_tests_list.size - fail_test_count, kit_tests_list.size); + + printf("%d of %d assertions passed.\n\n", + total_assertion_count - fail_assertion_count, + total_assertion_count); + + if (status != 0) { + for (int i = 0; i < kit_tests_list.size; i++) + for (int j = 0; j < kit_tests_list.tests[i].assertions; j++) + if (!kit_tests_list.tests[i].status[j]) + printf("Assertion on line %d in \"%s\" failed\n", + kit_tests_list.tests[i].line[j], + kit_tests_list.tests[i].file[j]); + + printf("\n"); + } + + return status; +} diff --git a/source/kit_test/test.h b/source/kit_test/test.h new file mode 100644 index 0000000..da6c59b --- /dev/null +++ b/source/kit_test/test.h @@ -0,0 +1,96 @@ +#ifndef KIT_TEST_TEST_H +#define KIT_TEST_TEST_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +#ifndef KIT_TEST_FILE +# define kit_test +#endif + +#ifndef KIT_TESTS_SIZE_LIMIT +# define KIT_TESTS_SIZE_LIMIT 0x1000 +#endif + +#ifndef KIT_TEST_ASSERTIONS_LIMIT +# define KIT_TEST_ASSERTIONS_LIMIT 0x50 +#endif + +#ifndef KIT_TEST_STRING_SIZE +# define KIT_TEST_STRING_SIZE 0x100 +#endif + +typedef void (*kit_test_report)(int, char const *file, int line, + bool); +typedef void (*kit_test_function)(int, kit_test_report); + +struct kit_test_case { + char test_name[KIT_TEST_STRING_SIZE]; + kit_test_function test_fn; + int assertions; + char const *file[KIT_TEST_ASSERTIONS_LIMIT]; + int line[KIT_TEST_ASSERTIONS_LIMIT]; + bool status[KIT_TEST_ASSERTIONS_LIMIT]; +}; + +struct kit_tests_list { + int size; + struct kit_test_case tests[KIT_TESTS_SIZE_LIMIT]; +}; + +extern struct kit_tests_list kit_tests_list; + +#ifdef _MSC_VER +# pragma section(".CRT$XCU", read) +# define KIT_TEST_ON_START_2(f, p) \ + static void f(void); \ + __declspec(allocate(".CRT$XCU")) void (*f##_)(void) = f; \ + __pragma(comment(linker, "/include:" p #f "_")) static void f( \ + void) +# ifdef _WIN64 +# define KIT_TEST_ON_START(f) KIT_TEST_ON_START_2(f, "") +# else +# define KIT_TEST_ON_START(f) KIT_TEST_ON_START_2(f, "_") +# endif +#else +# define KIT_TEST_ON_START(f) \ + static void f(void) __attribute__((constructor)); \ + static void f(void) +#endif + +#define KIT_TEST_CONCAT4(a, b, c, d) a##b##c##d +#define KIT_TEST_CONCAT3(a, b, c) KIT_TEST_CONCAT4(a, b, _, c) + +#define TEST(name) \ + static void KIT_TEST_CONCAT3(kit_test_run_, __LINE__, \ + KIT_TEST_FILE)(int, kit_test_report); \ + KIT_TEST_ON_START( \ + KIT_TEST_CONCAT3(kit_test_case_, __LINE__, KIT_TEST_FILE)) { \ + int n = kit_tests_list.size; \ + if (n < KIT_TESTS_SIZE_LIMIT) { \ + kit_tests_list.size++; \ + kit_tests_list.tests[n].test_fn = KIT_TEST_CONCAT3( \ + kit_test_run_, __LINE__, KIT_TEST_FILE); \ + strcpy(kit_tests_list.tests[n].test_name, name); \ + kit_tests_list.tests[n].assertions = 0; \ + } \ + } \ + static void KIT_TEST_CONCAT3(kit_test_run_, __LINE__, \ + KIT_TEST_FILE)( \ + int kit_test_index_, kit_test_report kit_test_report_) + +#define REQUIRE(ok) \ + kit_test_report_(kit_test_index_, __FILE__, __LINE__, (ok)) + +int kit_run_tests(int argc, char **argv); + +#ifdef __cplusplus +} +#endif + +#endif -- cgit v1.2.3