summaryrefslogtreecommitdiff
path: root/source/kit_test
diff options
context:
space:
mode:
authorMitya Selivanov <0x7fffff@guattari.ru>2022-08-05 21:17:16 +0400
committerMitya Selivanov <0x7fffff@guattari.ru>2022-08-05 21:17:16 +0400
commit26dfa76faa883c35fe3e5ff4b2b33f4102059a81 (patch)
tree27b71a44b38fb4b64e991146e235ae327c86ef5d /source/kit_test
downloadkit-26dfa76faa883c35fe3e5ff4b2b33f4102059a81.zip
Async function & unit-testing
Diffstat (limited to 'source/kit_test')
-rw-r--r--source/kit_test/CMakeLists.txt6
-rw-r--r--source/kit_test/run_tests.c112
-rw-r--r--source/kit_test/test.h96
3 files changed, 214 insertions, 0 deletions
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
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/test.h>)
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 <stdio.h>
+#include <time.h>
+
+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 <stdbool.h>
+#include <stddef.h>
+#include <string.h>
+
+#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