diff --git a/Makefile b/Makefile index 145a7ee..5067154 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ all: all-examples EXAMPLES = ex/example1 ex/example2 ex/example3 ex/example4 \ - ex/example5 ex/example6 ex/example7 ex/example8 \ + ex/example5 ex/example6 ex/example7 ex/example8 ex/example9 \ 'ex ws/example1 ws' 'ex ws/example2 ws' 'ex ws/example3 ws' 'ex ws/example4 ws' \ 'ex ws/example5 ws' 'ex ws/example6 ws' 'ex ws/example7 ws' 'ex ws/example8 ws' diff --git a/basic_testing.h b/basic_testing.h index 92b0437..1a90802 100644 --- a/basic_testing.h +++ b/basic_testing.h @@ -78,27 +78,33 @@ /* Assertion checks */ + struct bt_assertion_data { + const char *desc; + }; + /* Check for generic Boolean expressions */ -#define CHECK(expr) do { \ - if (!(expr)) { \ - printf("\n%s:%d: Assertion '"#expr"' failed\n", \ - __FILE__, __LINE__); \ - TEST_FAILED; \ - } \ +#define CHECK(expr, ...) do { \ + const struct bt_assertion_data data = { __VA_ARGS__ }; \ + if (!(expr)) { \ + printf("\n%s:%d: Assertion '"#expr"' failed\n %s\n", \ + __FILE__, __LINE__, data.desc); \ + TEST_FAILED; \ + } \ } while (0) /* Check for comparison between two C strings based on binary * relations/operators (==, >=, <=, !=, <, >). */ -#define CHECK_STRING_CMP(X,OP,Y) do { \ +#define CHECK_STRING_CMP(X,OP,Y, ...) do { \ + const struct bt_assertion_data data = { __VA_ARGS__ }; \ const char * x_ = (X); \ const char * y_ = (Y); \ - if (!(strcmp(x_, y_) OP 0)) { \ - printf("\n%s:%d: Assertion '"#X" "#OP" "#Y"' failed: %s "#OP" %s\n", \ - __FILE__, __LINE__, x_, y_); \ - TEST_FAILED; \ - } \ + if (!(strcmp(x_, y_) OP 0)) { \ + printf("\n%s:%d: Assertion '"#X" "#OP" "#Y"' failed: %s "#OP" %s\n %s\n", \ + __FILE__, __LINE__, x_, y_, data.desc); \ + TEST_FAILED; \ + } \ } while (0) /* Checks for comparisons based on binary relations/operators (==, >=, @@ -107,15 +113,18 @@ */ #ifdef __cplusplus -#define CHECK_CMP(X,OP,Y) do { \ - auto x_ = (X); \ +#define CHECK_CMP(X,OP,Y, ...) do { \ + const struct bt_assertion_data data = { __VA_ARGS__ }; \ + auto x_ = (X); \ decltype (x_) y_ = (Y); \ - if (!(x_ OP y_)) { \ - std::cout << std::endl <<__FILE__ << ":" << __LINE__ \ + if (!(x_ OP y_)) { \ + std::cout << std::endl <<__FILE__ << ":" << __LINE__\ << ": Assertion '"#X" "#OP" "#Y"' failed: " \ - << x_ << " "#OP" " << y_ << std::endl; \ - TEST_FAILED; \ - } \ + << x_ << " "#OP" " << y_ << std::endl \ + << " " << data.desc << std::endl \ + ;\ + TEST_FAILED; \ + } \ } while (0) #else @@ -143,7 +152,7 @@ static enum bt_cmp_operator bt_operator (const char * op) { BT_POSSIBLY_UNUSED static int check_cmp_int (int x, int y, const char * op, const char * x_str, const char * y_str, - const char * filename, int line) { + const char * filename, int line, const char* desc) { int res; switch (bt_operator(op)) { case BT_EQ: res = (x == y); break; @@ -155,15 +164,15 @@ static int check_cmp_int (int x, int y, const char * op, default: res = 0; } if (!res) - printf("\n%s:%d: Assertion '%s %s %s' failed: %d %s %d\n", \ - filename, line, x_str, op, y_str, x, op, y); + printf("\n%s:%d: Assertion '%s %s %s' failed: %d %s %d\n %s\n", \ + filename, line, x_str, op, y_str, x, op, y, desc); return res; } BT_POSSIBLY_UNUSED static int check_cmp_uint (unsigned int x, unsigned int y, const char * op, const char * x_str, const char * y_str, - const char * filename, int line) { + const char * filename, int line, const char* desc) { int res; switch (bt_operator(op)) { case BT_EQ: res = (x == y); break; @@ -175,15 +184,15 @@ static int check_cmp_uint (unsigned int x, unsigned int y, const char * op, default: res = 0; } if (!res) - printf("\n%s:%d: Assertion '%s %s %s' failed: %u %s %u\n", \ - filename, line, x_str, op, y_str, x, op, y); + printf("\n%s:%d: Assertion '%s %s %s' failed: %u %s %u\n %s\n", \ + filename, line, x_str, op, y_str, x, op, y, desc); return res; } BT_POSSIBLY_UNUSED static int check_cmp_double (double x, double y, const char * op, const char * x_str, const char * y_str, - const char * filename, int line) { + const char * filename, int line, const char* desc) { int res; switch (bt_operator(op)) { case BT_EQ: res = (x == y); break; @@ -195,28 +204,29 @@ static int check_cmp_double (double x, double y, const char * op, default: res = 0; } if (!res) - printf("\n%s:%d: Assertion '%s %s %s' failed: %f %s %f\n", \ - filename, line, x_str, op, y_str, x, op, y); + printf("\n%s:%d: Assertion '%s %s %s' failed: %f %s %f\n %s\n", \ + filename, line, x_str, op, y_str, x, op, y, desc); return res; } -#define CHECK_CMP(X,OP,Y) do { \ +#define CHECK_CMP(X,OP,Y, ...) do { \ + const struct bt_assertion_data data = { __VA_ARGS__ }; \ if (! _Generic ((Y), \ - int : check_cmp_int, \ - unsigned int : check_cmp_uint, \ - double : check_cmp_double) \ - ((X),(Y),#OP,#X,#Y,__FILE__,__LINE__)) { \ + int : check_cmp_int, \ + unsigned int : check_cmp_uint, \ + double : check_cmp_double) \ + ((X),(Y),#OP,#X,#Y,__FILE__,__LINE__, data.desc)) { \ TEST_FAILED; \ - } \ + } \ } while (0) #endif /* C++/C */ -#define CHECK_UINT_CMP(X,OP,Y) CHECK_CMP(X,OP,Y) +#define CHECK_UINT_CMP(X,OP,Y, ...) CHECK_CMP(X,OP,Y, __VA_ARGS__) -#define CHECK_INT_CMP(X,OP,Y) CHECK_CMP(X,OP,Y) +#define CHECK_INT_CMP(X,OP,Y, ...) CHECK_CMP(X,OP,Y, __VA_ARGS__) -#define CHECK_DOUBLE_CMP(X,OP,Y) CHECK_CMP(X,OP,Y) +#define CHECK_DOUBLE_CMP(X,OP,Y, ...) CHECK_CMP(X,OP,Y, __VA_ARGS__) @@ -229,11 +239,16 @@ static unsigned int bt_timeout = 3; /* three seconds */ BT_POSSIBLY_UNUSED static int bt_verbose = 1; +struct bt_test_additional_data { + const char *description; +}; + struct bt_test_descriptor { const char * name; int (*test_function)(); const char * file; int line; + struct bt_test_additional_data *data; struct bt_test_descriptor * next; }; @@ -249,19 +264,23 @@ static int bt_add_test(struct bt_test_descriptor * t) { } #ifdef __cplusplus -#define TEST(test_name) \ -BT_POSSIBLY_UNUSED static int test_name ## _test (); \ +#define TEST(test_name, ...) \ +BT_POSSIBLY_UNUSED static int test_name ## _test (); \ +BT_POSSIBLY_UNUSED static struct bt_test_additional_data test_name ## _data \ + = { __VA_ARGS__ }; \ BT_POSSIBLY_UNUSED static struct bt_test_descriptor test_name ## _descr \ - = { # test_name, test_name ## _test, __FILE__, __LINE__, 0}; \ -BT_POSSIBLY_UNUSED static struct bt_test_descriptor * test_name = & test_name ## _descr; \ + = { # test_name, test_name ## _test, __FILE__, __LINE__, & test_name ## _data, 0}; \ +BT_POSSIBLY_UNUSED static struct bt_test_descriptor * test_name = & test_name ## _descr;\ BT_POSSIBLY_UNUSED static const int test_name ## _init = bt_add_test(test_name); \ BT_POSSIBLY_UNUSED static int test_name ## _test () #else -#define TEST(test_name) \ -BT_POSSIBLY_UNUSED static int test_name ## _test (); \ +#define TEST(test_name, ...) \ +BT_POSSIBLY_UNUSED static int test_name ## _test (); \ +BT_POSSIBLY_UNUSED static struct bt_test_additional_data test_name ## _data \ + = { __VA_ARGS__ }; \ BT_POSSIBLY_UNUSED static struct bt_test_descriptor test_name ## _descr \ - = { # test_name, test_name ## _test, __FILE__, __LINE__, 0}; \ -BT_POSSIBLY_UNUSED static struct bt_test_descriptor * test_name = & test_name ## _descr; \ + = { # test_name, test_name ## _test, __FILE__, __LINE__, & test_name ## _data, 0}; \ +BT_POSSIBLY_UNUSED static struct bt_test_descriptor * test_name = & test_name ## _descr;\ BT_POSSIBLY_UNUSED static int test_name ## _test () #endif @@ -349,8 +368,10 @@ static void bt_run_and_record_test(const struct bt_test_descriptor * t) { switch (bt_run_test(t)) { case BT_FAILURE: bt_fail_count += 1; - if (bt_verbose) - printf("test %-40s FAIL\n", t->name); + if (bt_verbose) { + printf("FAIL\n"); + if (t->data->description) printf(" %s\n", t->data->description); + } break; case BT_SUCCESS: bt_pass_count += 1; diff --git a/ex/example9.expected b/ex/example9.expected new file mode 100644 index 0000000..b76f380 --- /dev/null +++ b/ex/example9.expected @@ -0,0 +1,18 @@ +Running test test0... +tests/test0.c:12: Assertion '0 == 1' failed + This assertion should fail + +tests/test0.c:17: Assertion '"str1" == "str2"' failed: str1 == str2 + This string comparison should fail + +tests/test0.c:23: Assertion 'a != a' failed: 0 != 0 + This integer comparison should fail + +tests/test0.c:29: Assertion 'a != a' failed: 0 != 0 + This uint assertion should fail + +tests/test0.c:35: Assertion 'a != a' failed: 0.000000 != 0.000000 + This double assertion should fail +FAIL +run 'tests/test0' to see what went wrong +run 'tests/test0 -d' with a debugger \ No newline at end of file diff --git a/ex/example9/Makefile b/ex/example9/Makefile new file mode 100644 index 0000000..58a6634 --- /dev/null +++ b/ex/example9/Makefile @@ -0,0 +1,3 @@ +OBJECTS = + +include ../../basic_testing.mk diff --git a/ex/example9/tests/test0.c b/ex/example9/tests/test0.c new file mode 100644 index 0000000..d7f93eb --- /dev/null +++ b/ex/example9/tests/test0.c @@ -0,0 +1,41 @@ +#include "basic_testing.h" + +TEST(test_no_doc) { + TEST_FAILED; +} + +TEST(test_doc, .description="Test description") { + TEST_FAILED; +} + +TEST(check_doc) { + CHECK(0 == 1, .desc="This assertion should fail"); + TEST_FAILED; +} + +TEST(check_str_cmp_doc) { + CHECK_STRING_CMP("str1", ==, "str2", .desc="This string comparison should fail"); + TEST_FAILED; +} + +TEST(check_cmp_int_doc) { + int a = 0; + CHECK_CMP(a, !=, a, .desc="This integer comparison should fail"); + TEST_FAILED; +} + +TEST(check_cmp_uint_doc) { + unsigned int a = 0; + CHECK_CMP(a, !=, a, .desc="This uint assertion should fail"); + TEST_FAILED; +} + +TEST(check_cmp_double_doc) { + double a = 0.0; + CHECK_CMP(a, !=, a, .desc="This double assertion should fail"); + TEST_FAILED; +} + +MAIN_TEST_DRIVER(test_no_doc, test_doc, check_doc, check_str_cmp_doc, +check_cmp_int_doc, check_cmp_uint_doc, check_cmp_double_doc +)