From 8f17684810718973c8ea0f1150e46d6c1b8c0ef1 Mon Sep 17 00:00:00 2001 From: Tom Smeding Date: Fri, 7 Aug 2020 22:47:46 +0200 Subject: server: Add basic unit test framework --- test/hashtable.c | 8 ++++++++ test/main.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ test/test_framework.c | 14 ++++++++++++++ test/test_framework.h | 25 +++++++++++++++++++++++++ 4 files changed, 96 insertions(+) create mode 100644 test/hashtable.c create mode 100644 test/main.c create mode 100644 test/test_framework.c create mode 100644 test/test_framework.h (limited to 'test') diff --git a/test/hashtable.c b/test/hashtable.c new file mode 100644 index 0000000..cfb2d9d --- /dev/null +++ b/test/hashtable.c @@ -0,0 +1,8 @@ +#include "test_framework.h" + + +DEFINE_TEST(hashtable) { + EXPECT(1); + EXPECT(0); + return 0; +} diff --git a/test/main.c b/test/main.c new file mode 100644 index 0000000..ebfe3da --- /dev/null +++ b/test/main.c @@ -0,0 +1,49 @@ +#include +#include +#include +#include "test_framework.h" +#include "test_declarations.h" + +#define STR_(x) #x +#define STR(x) STR_(x) + + +// Referred to via extern in 'test_framework.c' +atomic_flag test_framework_assertion_failed = ATOMIC_FLAG_INIT; + + +static void report(const char *clr, const char *label, const char *name, clock_t taken) { + printf("\x1B[%sm[%s] %s (%lfs)\n", + clr, label, name, (double)taken / CLOCKS_PER_SEC); +} + +static void report_success(const char *name, clock_t taken) { + report("32", " OK ", name, taken); +} + +static void report_failure(const char *name, clock_t taken) { + report("31", "FAILED", name, taken); +} + +#define RUN_TEST(name) do { \ + atomic_flag_clear(&test_framework_assertion_failed); \ + clock_t start_ = clock(); \ + int ret_ = TEST(name)(); \ + clock_t diff_ = clock() - start_; \ + if (ret_ == 0 && !atomic_flag_test_and_set(&test_framework_assertion_failed)) { \ + report_success(STR(name), diff_); \ + } else { \ + report_failure(STR(name), diff_); \ + return 1; \ + } \ + } while (0) + +static int run_tests(void) { + RUN_TEST(hashtable); + return 0; +} + + +int main(void) { + return run_tests(); +} diff --git a/test/test_framework.c b/test/test_framework.c new file mode 100644 index 0000000..8cd53ac --- /dev/null +++ b/test/test_framework.c @@ -0,0 +1,14 @@ +#include +#include +#include "test_framework.h" + + +extern atomic_flag test_framework_assertion_failed; + + +void test_report_error( + const char *type, const char *condition, const char *fname, int lineno) { + printf("\x1B[31;1m%s:%d: Assertion failed:\n %s(%s)\x1B[0m\n", + fname, lineno, type, condition); + atomic_flag_test_and_set(&test_framework_assertion_failed); +} diff --git a/test/test_framework.h b/test/test_framework.h new file mode 100644 index 0000000..7ab4816 --- /dev/null +++ b/test/test_framework.h @@ -0,0 +1,25 @@ +#pragma once + + +#define TEST(name) testfn__ ## name + +// Test function should return 0 on success, nonzero value on error +#ifdef TEST_HEADER_GENERATION +#define DEFINE_TEST(name) XXTEST_DECLARATION(TEST(name)) +#else +#define DEFINE_TEST(name) int TEST(name)(void) +#endif + +void test_report_error( + const char *type, const char *condition, const char *fname, int lineno); + +#define EXPECT(cond_) do { \ + if (!(cond_)) test_report_error("EXPECT", #cond_, __FILE__, __LINE__); \ + } while (0) + +#define EXPECTRET(cond_, ret_) do { \ + if (!(cond_)) { \ + test_report_error("EXPECT", #cond_, __FILE__, __LINE__); \ + return (ret_); \ + } \ + } -- cgit v1.2.3-54-g00ecf