From 5070426785a69dc0b5bd3bbf1cfe7968329b732c Mon Sep 17 00:00:00 2001 From: sanine Date: Mon, 19 Dec 2022 19:42:05 -0600 Subject: add basic assertion macros --- CMakeLists.txt | 1 + lily-test.h | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++++ tests/assertions.c | 79 ++++++++++++++++++++++++++++++++++++++++ tests/main.c | 2 ++ tests/tests.h | 2 ++ 5 files changed, 188 insertions(+) create mode 100644 tests/assertions.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 15f0ce8..0758722 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,6 +13,7 @@ add_executable(lily-metatest ${TEST_SRC}/main.c ${TEST_SRC}/helpers.c ${TEST_SRC}/macro-tests.c + ${TEST_SRC}/assertions.c ) set_target_properties(lily-metatest PROPERTIES C_STANDARD 90 diff --git a/lily-test.h b/lily-test.h index 8f8b61c..c3f6f8c 100644 --- a/lily-test.h +++ b/lily-test.h @@ -53,6 +53,8 @@ #include #include #include +#include +#include #define STR_IMP(x) #x #define STR(x) STR_IMP(x) @@ -106,6 +108,108 @@ static void f() #define LILY_TEST(description) LILY_TEST_(LILY_ANON_FUNC, LILY_ANON_DESC, description) +/* assertions */ +typedef struct lily_test_msg_t { + struct lily_test_msg_t *next; + char *msg; + const char *location; +} lily_test_msg_t; +void lily_msg_destroy(lily_test_msg_t *m); + +void lily_check(int x, const char *location, const char *fmt, ...); +#define LILY_CHECK_(str, x, location) \ + lily_check(x, location, "%s", str) +#define LILY_CHECK(x) LILY_CHECK_(STR(x), x, LILY_LOCATION) +#define CHECK(x) LILY_CHECK(x) + + +void lily_require(int x, const char *location, const char *fmt, ...); +#define LILY_REQUIRE_(str, x, location) \ + lily_require(x, location, "%s", str) +#define LILY_REQUIRE(x) LILY_REQUIRE_(STR(x), x, LILY_LOCATION) +#define REQUIRE(x) LILY_REQUIRE(x) + + +struct lily_global_t { + int failed; + jmp_buf env; + lily_test_msg_t HEAD; + lily_test_msg_t *TAIL; +} extern lily_g; + +#ifdef LILY_IMPLEMENTATION +struct lily_global_t lily_g; + +lily_test_msg_t *lily_msg_create(const char *location, const char *fmt, va_list args) +{ + lily_test_msg_t *m = malloc(sizeof(lily_test_msg_t)); + if (m == NULL) { + return NULL; + } + m->next = NULL; + m->location = location; + + va_list args_len; + va_copy(args_len, args); + size_t len = vsnprintf(NULL, 0, fmt, args_len) + 1; + va_end(args_len); + + m->msg = malloc(len * sizeof(char)); + if (m->msg == NULL) { + free(m); + return NULL; + } + vsnprintf(m->msg, len, fmt, args); + + return m; +} + +void lily_msg_destroy(lily_test_msg_t *m) +{ + if (m->next != NULL) { + // destroy the whole chain + lily_msg_destroy(m->next); + } + + free(m->msg); + free(m); +} + +void lily_check(int x, const char *location, const char *fmt, ...) +{ + if (!x) { + // assertion failed + va_list args; + va_start(args, fmt); + lily_test_msg_t *m = lily_msg_create(location, fmt, args); + va_end(args); + + lily_g.TAIL->next = m; + lily_g.TAIL = m; + lily_g.failed = 1; + } +} + + +void lily_require(int x, const char *location, const char *fmt, ...) +{ + if (!x) { + // assertion failed + va_list args; + va_start(args, fmt); + lily_test_msg_t *m = lily_msg_create(location, fmt, args); + va_end(args); + + lily_g.TAIL->next = m; + lily_g.TAIL = m; + lily_g.failed = 1; + + /* longjump out of test */ + longjmp(lily_g.env, 1); + } +} +#endif + /* ifdef LILY_TEST_H */ #else diff --git a/tests/assertions.c b/tests/assertions.c new file mode 100644 index 0000000..6ad855a --- /dev/null +++ b/tests/assertions.c @@ -0,0 +1,79 @@ +#include "lily-test.h" +#include "tests.h" + + +const char * test_CHECK() +{ + lily_g.HEAD.next = NULL; + lily_g.TAIL = &(lily_g.HEAD); + lily_g.failed = 0; + CHECK(1 == 0); + CHECK(0 == 0); + CHECK(4 == 3); + + if (lily_g.HEAD.next == NULL) + return "CHECK did not append any failure messages"; + lily_test_msg_t *m = lily_g.HEAD.next; + + if (strcmp(m->msg, "1 == 0") != 0) + return "first assert has wrong message"; + + if (m->next == NULL) + return "only one message appended"; + m = m->next; + + if (strcmp(m->msg, "4 == 3") != 0) + return "second message is incorrect"; + + if (m->next != NULL) + return "more than two messages appended!"; + + if (!lily_g.failed) + return "test did not fail!"; + + lily_msg_destroy(lily_g.HEAD.next); + + return 0; +} + + +int aR, bR; +static void f_test_REQUIRE() +{ + aR = 5; + REQUIRE(2+2 == 5); + bR = 5; +} + +const char * test_REQUIRE() +{ + lily_g.HEAD.next = NULL; + lily_g.TAIL = &(lily_g.HEAD); + lily_g.failed = 0; + aR = 0; bR = 0; + int test_failed = setjmp(lily_g.env); + + if (test_failed) { + if (!lily_g.failed) + return "test did not fail!"; + + if (lily_g.HEAD.next == NULL) + return "test did not generate any messages"; + + if (strcmp(lily_g.HEAD.next->msg, "2+2 == 5") != 0) + return "test generated incorrect message"; + + if (lily_g.HEAD.next->next != NULL) + return "test generated too many messages"; + + if (bR == 5) + return "test kept executing after failed REQUIRE"; + + lily_msg_destroy(lily_g.HEAD.next); + return 0; + } + else { + f_test_REQUIRE(); + return "test function did not longjump!"; + } +} diff --git a/tests/main.c b/tests/main.c index 1598190..f1a6de6 100644 --- a/tests/main.c +++ b/tests/main.c @@ -3,6 +3,8 @@ #include #include +#define LILY_IMPLEMENTATION +#include "lily-test.h" #include "tests.h" int main() diff --git a/tests/tests.h b/tests/tests.h index 481260e..06c35af 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -12,6 +12,8 @@ int validate_message(const char* received, const char* expected, X(test_LILY_COUNTER) \ X(test_LILY_COUNTER_DECREMENT) \ X(test_auto_registration) \ + X(test_CHECK) \ + X(test_REQUIRE) \ #define X(test) const char * test(); TESTS -- cgit v1.2.1