summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--example/sum.c29
-rw-r--r--lily-test.h81
-rw-r--r--tests/assertions.c30
-rw-r--r--tests/tests.h1
4 files changed, 131 insertions, 10 deletions
diff --git a/example/sum.c b/example/sum.c
new file mode 100644
index 0000000..d9d1221
--- /dev/null
+++ b/example/sum.c
@@ -0,0 +1,29 @@
+#define LILY_IMPLEMENTATION
+#include "lily-test.h"
+
+int sum(int a, int b)
+{
+ return 0;
+}
+
+
+LILY_FILE_BEGIN(sum_suite)
+
+LILY_TEST("sums are correct")
+{
+ CHECK_EQ(sum(0, 0), 0, "%d");
+ CHECK_EQ(sum(1, 0), 1, "%d");
+ INFO("this is some info");
+ CHECK_EQ(sum(2, 2), 4, "%d");
+}
+#include LILY_PUSH_TEST()
+
+#define LILY_FILE_END
+#include LILY_REGISTER_TESTS()
+
+
+int main()
+{
+ sum_suite();
+ return 0;
+}
diff --git a/lily-test.h b/lily-test.h
index c9ae02d..1bc4e74 100644
--- a/lily-test.h
+++ b/lily-test.h
@@ -55,6 +55,7 @@
#include <setjmp.h>
#include <stdio.h>
#include <stdarg.h>
+#include <stdlib.h>
#define STR_IMP(x) #x
#define STR(x) STR_IMP(x)
@@ -89,7 +90,10 @@ typedef struct lily_ll_node_t {
void (*f)();
} lily_ll_node_t;
#define LILY_FILE_BEGIN(unique_id) \
-static lily_ll_node_t lily_ll_last = { NULL, NULL };
+static lily_ll_node_t lily_ll_last = { NULL, NULL }; \
+static void file_runner(); \
+void (*unique_id)() = file_runner;
+
#define LILY_LIST_HEAD lily_ll_last
#define LILY_LIST_NEXT lily_ll_last
#define LILY_PUSH_TEST() LILY_TEST_H_LOCATION
@@ -98,15 +102,21 @@ static lily_ll_node_t lily_ll_last = { NULL, NULL };
#define LILY_CAT_(x, y) x##y
#define LILY_CAT(x, y) LILY_CAT_(x, y)
#define LILY_ANON(x) LILY_CAT(x, LILY_COUNTER)
+#define LILY_ANON_WRAP LILY_ANON(LILY_WRAP_)
#define LILY_ANON_FUNC LILY_ANON(LILY_FUNCTION_)
#define LILY_ANON_NODE LILY_ANON(LILY_NODE_)
#define LILY_ANON_DESC LILY_ANON(LILY_DESCRIPTION_)
-#define LILY_TEST_(f, desc_str, description) \
-static const char * const desc_str = description; \
+#define LILY_TEST_(wrap, f, desc_str, description) \
+static void f(); \
+static void wrap() \
+{ \
+ lily_g.test_name = description; \
+ f(); \
+} \
static void f()
-#define LILY_TEST(description) LILY_TEST_(LILY_ANON_FUNC, LILY_ANON_DESC, description)
+#define LILY_TEST(description) LILY_TEST_(LILY_ANON_WRAP, LILY_ANON_FUNC, LILY_ANON_DESC, description)
/* assertions */
typedef struct lily_test_msg_t {
@@ -124,23 +134,36 @@ void lily_info(const char *location, const char *fmt, ...);
void lily_check(int x, const char *location, const char *fmt, ...);
#define LILY_CHECK_(str, x, location) \
- lily_check(x, location, "%s", str)
+ lily_check(x, location, "CHECK failed: %s", str)
#define LILY_CHECK(x) LILY_CHECK_(STR(x), x, LILY_LOCATION)
#define CHECK(x) LILY_CHECK(x)
+#define LILY_CHECK_EQ_(test, location, fmt, x, y, xstr, ystr) \
+ lily_check(test, location, "CHECK failed: %s == %s (" fmt " == " fmt ")", xstr, ystr, x, y)
+#define LILY_CHECK_EQ(x, y, xstr, ystr, fmt) LILY_CHECK_EQ_(x == y, LILY_LOCATION, fmt, x, y, xstr, ystr)
+#define CHECK_EQ(x, y, fmt) LILY_CHECK_EQ(x, y, #x, #y, fmt)
+
void lily_require(int x, const char *location, const char *fmt, ...);
#define LILY_REQUIRE_(str, x, location) \
- lily_require(x, location, "%s", str)
+ lily_require(x, location, "REQUIRE failed: %s", str)
#define LILY_REQUIRE(x) LILY_REQUIRE_(STR(x), x, LILY_LOCATION)
#define REQUIRE(x) LILY_REQUIRE(x)
+void lily_run_test(void (*test)());
+
+
struct lily_global_t {
int failed;
jmp_buf env;
+ const char *test_name;
lily_test_msg_t HEAD;
lily_test_msg_t *TAIL;
+ int n_assertions;
+ int n_assertions_failed;
+ int n_tests;
+ int n_tests_failed;
} extern lily_g;
#ifdef LILY_IMPLEMENTATION
@@ -172,6 +195,11 @@ lily_test_msg_t *lily_msg_create(const char *location, const char *fmt, va_list
void lily_msg_destroy(lily_test_msg_t *m)
{
+ if (m == NULL) {
+ /* ignore */
+ return;
+ }
+
if (m->next != NULL) {
// destroy the whole chain
lily_msg_destroy(m->next);
@@ -182,6 +210,31 @@ void lily_msg_destroy(lily_test_msg_t *m)
}
+void lily_run_test(void (*test)())
+{
+ lily_g.n_tests += 1;
+ lily_g.HEAD.next = NULL;
+ lily_g.TAIL = &(lily_g.HEAD);
+ lily_g.failed = 0;
+ int jumped = setjmp(lily_g.env);
+
+ if (!jumped) {
+ test();
+ }
+
+ if (lily_g.failed) {
+ printf("================================================================================\n\n");
+ printf("test \"%s\" failed!\n\n", lily_g.test_name);
+ lily_test_msg_t *n = lily_g.HEAD.next;
+ while(n != NULL) {
+ printf(" %s\n [%s]\n\n", n->msg, n->location);
+ n = n->next;
+ }
+ lily_msg_destroy(lily_g.HEAD.next);
+ }
+}
+
+
void lily_info(const char *location, const char *fmt, ...)
{
va_list args;
@@ -195,8 +248,11 @@ void lily_info(const char *location, const char *fmt, ...)
void lily_check(int x, const char *location, const char *fmt, ...)
{
+ lily_g.n_assertions += 1;
if (!x) {
// assertion failed
+ lily_g.n_assertions_failed += 1;
+
va_list args;
va_start(args, fmt);
lily_test_msg_t *m = lily_msg_create(location, fmt, args);
@@ -211,8 +267,11 @@ void lily_check(int x, const char *location, const char *fmt, ...)
void lily_require(int x, const char *location, const char *fmt, ...)
{
+ lily_g.n_assertions += 1;
if (!x) {
// assertion failed
+ lily_g.n_assertions_failed += 1;
+
va_list args;
va_start(args, fmt);
lily_test_msg_t *m = lily_msg_create(location, fmt, args);
@@ -548,6 +607,14 @@ void lily_require(int x, const char *location, const char *fmt, ...)
#define LILY_COUNTER_DECREMENT
#include LILY_TEST_H_LOCATION
+void file_runner()
+{
+ lily_ll_node_t *n = &LILY_LIST_HEAD;
+ while (n->next != NULL) {
+ lily_run_test(n->f);
+ n = n->next;
+ }
+}
#else
/* register new test */
@@ -558,7 +625,7 @@ static lily_ll_node_t LILY_ANON_NODE = {
&LILY_LIST_HEAD,
#define LILY_COUNTER_INCREMENT
#include LILY_TEST_H_LOCATION
- LILY_ANON_FUNC,
+ LILY_ANON_WRAP,
};
#undef LILY_LIST_HEAD
#define LILY_LIST_HEAD LILY_ANON_NODE
diff --git a/tests/assertions.c b/tests/assertions.c
index 156a484..5a32854 100644
--- a/tests/assertions.c
+++ b/tests/assertions.c
@@ -49,14 +49,14 @@ const char * test_CHECK()
return "CHECK did not append any failure messages";
lily_test_msg_t *m = lily_g.HEAD.next;
- if (strcmp(m->msg, "1 == 0") != 0)
+ if (strcmp(m->msg, "CHECK failed: 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)
+ if (strcmp(m->msg, "CHECK failed: 4 == 3") != 0)
return "second message is incorrect";
if (m->next != NULL)
@@ -71,6 +71,30 @@ const char * test_CHECK()
}
+const char * test_CHECK_EQ()
+{
+ lily_g.HEAD.next = NULL;
+ lily_g.TAIL = &(lily_g.HEAD);
+ lily_g.failed = 0;
+
+ int k = 5;
+ CHECK_EQ(k, 5, "%d");
+ CHECK_EQ(4, k, "%02d");
+
+ if (lily_g.HEAD.next == NULL)
+ return "CHECK_EQ did not append any failure message";
+
+ if (lily_g.HEAD.next->next != NULL)
+ return "CHECK_EQ appended more than one message";
+
+ if (strcmp(lily_g.HEAD.next->msg, "CHECK failed: 4 == k (04 == 05)") != 0)
+ return "incorrect message";
+
+ lily_msg_destroy(lily_g.HEAD.next);
+ return 0;
+}
+
+
int aR, bR;
static void f_test_REQUIRE()
{
@@ -94,7 +118,7 @@ const char * test_REQUIRE()
if (lily_g.HEAD.next == NULL)
return "test did not generate any messages";
- if (strcmp(lily_g.HEAD.next->msg, "2+2 == 5") != 0)
+ if (strcmp(lily_g.HEAD.next->msg, "REQUIRE failed: 2+2 == 5") != 0)
return "test generated incorrect message";
if (lily_g.HEAD.next->next != NULL)
diff --git a/tests/tests.h b/tests/tests.h
index 2942fa3..393da87 100644
--- a/tests/tests.h
+++ b/tests/tests.h
@@ -14,6 +14,7 @@ int validate_message(const char* received, const char* expected,
X(test_auto_registration) \
X(test_INFO) \
X(test_CHECK) \
+ X(test_CHECK_EQ) \
X(test_REQUIRE) \
#define X(test) const char * test();