From 8561b9541e1d9d6361e66c9d9bb205b21f065bea Mon Sep 17 00:00:00 2001 From: katherine Date: Wed, 21 Mar 2018 00:59:40 -0700 Subject: update documentation for new version --- README.md | 246 ++++++++++++++----------- doc/a_simple_example.c | 68 ------- doc/example.c | 103 +++++++++++ doc/run-01.png | Bin 2766 -> 0 bytes doc/run-02.png | Bin 1065 -> 0 bytes doc/run-03.png | Bin 1273 -> 0 bytes doc/run_01.png | Bin 0 -> 21120 bytes doc/run_02.png | Bin 0 -> 34615 bytes doc/run_03.png | Bin 0 -> 16912 bytes simple-test.h | 473 +++++++++++++++++++++++++++++++++++++++++++++++++ src/simple-test.h | 472 ------------------------------------------------ 11 files changed, 719 insertions(+), 643 deletions(-) delete mode 100644 doc/a_simple_example.c create mode 100644 doc/example.c delete mode 100644 doc/run-01.png delete mode 100644 doc/run-02.png delete mode 100644 doc/run-03.png create mode 100644 doc/run_01.png create mode 100644 doc/run_02.png create mode 100644 doc/run_03.png create mode 100644 simple-test.h delete mode 100644 src/simple-test.h diff --git a/README.md b/README.md index e6709cf..619972d 100644 --- a/README.md +++ b/README.md @@ -1,154 +1,194 @@ simple-test =========== -simple unit testing for C implemented as a single header file +[simple-test.h](simple-test.h) is a single header file which implements +quick-and-dirty unit testing for C. robust unit testing suites for C exist, but +require a degree of boilerplate which can be prohibitive for their use in +spare-time projects. if you're writing something for fun, lots of boilerplate +defeats the purpose of writing it. simple-test is made to be as easy to use as +possible: include the header, compile, and run. + +_note:_ although it has no dependencies outside the standard library, this +project makes heavy use of `_Generic`, so C11 support is required. + brief summary ------------- -Your tests should be written as a single .c file separate from -the body of text containing your functionality to be tested. -Write the tests, include simple-test.h, point your compiler at -the necessary files / libs, and you're done! +test suites are to be written as a single .c file separate from the body of +functionality to be tested. include the functionality needed (including headers +and linking against objects) to produce an executable file from the .c file, +then run the executable to test. simple-test internally defines a `main` +function, so none is required, and the `argc` and `argv` arguments are made +available to all `TEST`s. -an example ----------- -consider the following simple program: +example +------- -```c -/* keep this include at the very top of the file */ -#include "simple-test.h" +the following example file is available as [example.c](doc/example.c), which +you can compile and play with yourself. -/* any global variables, functions, other inclusions, etc. - * should be declared here */ -#include "header_with_stuff_to_be_tested.h" +```C +#include "../simple-test.h" -int add_here(int a, int b) +/* global variables, functions, and includes must come before BEGIN_TEST */ +char *global_s; + +/* a teardown function is called by TESTs which include USE_TEARDOWN. the call + * occurs either after an ASSERT fails or after the TEST is finished. + * + * defining one is optional, but, if used, REGISTER_TEARDOWN must appear + * between BEGIN_TEST and the first TEST + * + * here i'm using it to free memory that's alloced inside tests below */ +void teardown(void) { - /* ASSERT / ECHO statements within functions - * like this are perfectly valid. this is - * useful for writing initialisation functions - * called at the beginning of multiple TESTs */ - ECHO("this is the local add"); + free(global_s); +} - /* ensure a and b are non-0 using generic ASSERT */ - ASSERT(a); - ASSERT(b); +/* must appear before an (optional) REGISTER_TEARDOWN and all TESTs */ +BEGIN_TEST + +/* if used, must appear before first TEST and after BEGIN_TEST */ +REGISTER_TEARDOWN(teardown); - return a + b; +/* run a test. provided description must be a string literal */ +TEST("basic assertion") +{ + /* ASSERT fails if passed some sort of non-true value (0, false, NULL) */ + ASSERT(1); } -/* must come before all TESTs */ -BEGIN_TEST +TEST("basic not assertion") +{ + bool b = false; + + ASSERT_NOT(b); +} -/* the string is a description of the test being run */ -TEST("check add()'s return value") +TEST("boolean comparison") { - /* mixing different precisions is allowed */ - long var1 = 2; - int8_t var2 = 2; + bool a = false, b = true; - /* add is a function included from our hypothetical - * header_with_stuff_to_be_tested.h */ - ASSERT_INT_EQ(var1+var2, add(var1, var2)); + /* fail if parameters are not equal */ + ASSERT_EQ(a, b); +} - /* generic versions of ASSERTions are also valid, - * but only for number types (int / uint / float ) */ - ASSERT_EQ(var1+var2, add_here(var1, var2)); +TEST("type mismatch") +{ + char a = 'a'; + int i = 97; + char *b = NULL; + + /* for convenience's sake, when presented with unmatched types, assertions + * try to resolve them in a way that's most likely to match the + * programmer's intentions. here 'i' is interpreted as a char */ + ASSERT_EQ(a, i); + + /* if there isn't a straightforward comparison to make, though (as is the + * case here, with a 'char' and 'char *'), a type mismatch error occurs */ + ASSERT_EQ(a, b); } -TEST("compare two arrays of strings") +TEST("ECHO example") { int i; - char array1[][10] = { - "str1", - "str2", - "str3", - }; - char array2[][10] = { - "str1", - "str2", - /* matching will fail here */ - "different", - }; - - for(i = 0; i < sizeof(array1) / sizeof(char[10]); i++) { - /* ECHO can be used to print (with pretty - * formatting) the current state within the - * test */ - ECHO("checking strs at i == %i", i); - - ASSERT_STR_EQ(array1[i], array2[i]); + + /* ECHO can be used to neatly report information during a run */ + if (true) + ECHO("loop until i not less than 1"); + + for (i = 0; i < 2; i++) { + /* it takes printf format strings and variable args as well */ + ECHO("i == %d", i); + ASSERT_LT(i, 1); } } +TEST("string comparison") +{ + char *s = "test"; + global_s = strdup("test"); + + /* USE_TEARDOWN; tells this test to call the previously defined teardown + * function on exiting (successfully or otherwise) */ + USE_TEARDOWN; + + /* strings are compared by content, so this assertion succeeds */ + ASSERT_EQ(s, global_s); +} + +TEST("pointer comparison") +{ + char *s = "test"; + global_s = strdup("test"); + USE_TEARDOWN; + + /* you can cast parameters in order to use a different type of comparison. + * here i'm casting the 'char *' to 'void *' so assertion performs a + * pointer comparison, which fails */ + ASSERT_EQ((void*)s, (void*)global_s); +} + /* must come after all TESTs */ END_TEST ``` -running this test, the output might look something like this: +on compiling and running this file, the output will look something like this: + +![run 1](doc/run_01.png) -![run 1](doc/run-01.png) +an error, because the types passed to the second assertion in the "type +mismatch" test are... well, mismatched. simple-test does its best to +accommodate mismatched types when it makes sense to do so (e.g. comparing a +signed and unsigned integer), but there is no meaningful comparison to be made +between a `char` and a `char *`, so the error is returned. -if var1 in the first test were changed to 0, like so: +if that assertion is commented out: -```c - /* mixing different precisions is allowed */ - long var1 = 0; - int8_t var2 = 2; +```C + /* if there isn't a straightforward comparison to make, though (as is the + * case here, with a 'char' and 'char *'), a type mismatch error occurs */ + /* ASSERT_EQ(a, b); */ ``` -ASSERT(a); in add_here() would fail like this: +and the tests re-run, the output would look like this: -![run 2](doc/run-02.png) +![run 2](doc/run_02.png) -if array2 were modified instead so the third strings would match, -a successful output would look like this: +as you can see, there are multiple failing assertions, and their failures are +reported and a total count of failing tests printed. if all of these failing +asserts are commented out and the tests re-run, the output looks like this: -![run 3](doc/run-03.png) +![run 3](doc/run_03.png) +hooray! ^_^ -defined macros --------------- + +interface +--------- + +simple-test's interface consists of a series of preprocessor macros: | **NAME** | **DESCRIPTION** | |---------:|:----------------| -| **BEGIN_TEST** | must be included once, after includes and global declarations and before the first TEST statement | -| **END_TEST** | must be included once, after the final TEST statement | +| **BEGIN_TEST** | must be included once, after includes and global declarations and before the first `TEST` statement | +| **END_TEST** | must be included once, after the final `TEST` statement | | **TEST()**{} | declare a test, described by `description`, which consists of statements between the {} | +| **REGISTER_TEARDOWN()** | optionally included after `BEGIN_TEST` and before the first `TEST` statement. registers function `func`, which must be of type `void func(void)`, as a teardown function to be called after subscribing tests exit | +| **USE_TEARDOWN;** | if included within a `TEST` body (before any `ASSERT` statements), the designated `TEST` will call the function registered with `REGISTER_TEARDOWN` on terminating | | **ECHO(<...>)** | print a formatted description of the state within the current test | -| **ASSERT<_type_name><_condition>()** | assert, on either one or two `args` of type `_type_name`, that `_condition` is true | +| **ASSERT<_condition>()** | assert, on either one or two `args`, that `_condition` is true | -valid `_type_name` and `_condition` values for ASSERT statements are: - -| **_type_name** | **DESCRIPTION** | -|---------------:|:----------------| -| | if the _type_name is omitted, generic assertions which automatically determine type are used. valid only for number types, i.e. int, unsigned, double. | -| **_BOOL** | operate on args of type `bool` | -| **_INT** | operate on signed integer types | -| **_UINT** | operate on unsigned integer types | -| **_HEX** | operate on unsigned integer types. output with %X formatting | -| **_FLOAT** | operate on floating point types | -| **_PTR** | operate on generic pointer types. casts to void* | -| **_CHAR** | operate on args of type `char` | -| **_STR** | operate on strings pointed to by args of type `char*`. | -| **_WCHAR** | operate on wide character types | -| **_WSTR** | operate on wide strings pointed to by args of type `wchar_t*` | +valid values for `_condition` are: | **_condition** | **DESCRIPTION** | |---------------:|:----------------| -| | if the _condition is omitted, fail if the single arg is a "not" value, i.e. NULL, 0, '\0' etc. | -| **_EQ** | fail if the two args are not equal | -| **_NEQ** | fail if the two args are equal | -| **_G** | fail if the first arg is not greater than the second | -| **_GEQ** | fail if the first arg is not greater than or equal to the second | -| **_L** | fail if the first arg is not less than the second | -| **_LEQ** | fail if the first arg is not less than or equal to the second | - -note ----- - -this makes heavy use of _Generic, so C11 support is required - -tested successfully with both gcc and clang +| | if the _condition is omitted, fail if the single argument is a "not" value, i.e. NULL, 0, '\0' etc. | +| **_EQ** | fail if the two arguments are not equal | +| **_NEQ** | fail if the two arguments are equal | +| **_GT** | fail if the first argument is not greater than the second | +| **_GEQ** | fail if the first argument is not greater than or equal to the second | +| **_LT** | fail if the first argument is not less than the second | +| **_LEQ** | fail if the first argument is not less than or equal to the second | diff --git a/doc/a_simple_example.c b/doc/a_simple_example.c deleted file mode 100644 index 6784713..0000000 --- a/doc/a_simple_example.c +++ /dev/null @@ -1,68 +0,0 @@ -/* keep this include at the very top of the file */ -#include "../src/simple-test.h" - -/* any global variables, functions, other inclusions, etc. - * should be declared here */ -#include "header_with_stuff_to_be_tested.h" - -int add_here(int a, int b) -{ - /* ASSERT / ECHO statements within functions - * like this are perfectly valid. this is - * useful for writing initialisation functions - * called at the beginning of multiple TESTs */ - ECHO("this is the local add"); - - /* ensure a and b are non-0 using generic ASSERT */ - ASSERT(a); - ASSERT(b); - - return a + b; -} - -/* must come before all TESTs */ -BEGIN_TEST - -/* the string is a description of the test being run */ -TEST("check add()'s return value") -{ - /* mixing different precisions is allowed */ - long var1 = 2; - int8_t var2 = 2; - - /* add is a function included from our hypothetical - * header_with_stuff_to_be_tested.h */ - ASSERT_INT_EQ(var1+var2, add(var1, var2)); - - /* generic versions of ASSERTions are also valid, - * but only for number types (int / uint / float ) */ - ASSERT_EQ(var1+var2, add_here(var1, var2)); -} - -TEST("compare two arrays of strings") -{ - int i; - char array1[][10] = { - "str1", - "str2", - "str3", - }; - char array2[][10] = { - "str1", - "str2", - /* matching will fail here */ - "different", - }; - - for(i = 0; i < sizeof(array1) / sizeof(char[10]); i++) { - /* ECHO can be used to print (with pretty - * formatting) the current state within the - * test */ - ECHO("checking strs at i == %i", i); - - ASSERT_STR_EQ(array1[i], array2[i]); - } -} - -/* must come after all TESTs */ -END_TEST diff --git a/doc/example.c b/doc/example.c new file mode 100644 index 0000000..26d8f66 --- /dev/null +++ b/doc/example.c @@ -0,0 +1,103 @@ +#include "../simple-test.h" + +/* global variables, functions, and includes must come before BEGIN_TEST */ +char *global_s; + +/* a teardown function is called by TESTs which include USE_TEARDOWN. the call + * occurs either after an ASSERT fails or after the TEST is finished. + * + * defining one is optional, but, if used, REGISTER_TEARDOWN must appear + * between BEGIN_TEST and the first TEST + * + * here i'm using it to free memory that's alloced inside tests below */ +void teardown(void) +{ + free(global_s); +} + +/* must appear before an (optional) REGISTER_TEARDOWN and all TESTs */ +BEGIN_TEST + +/* if used, must appear before first TEST and after BEGIN_TEST */ +REGISTER_TEARDOWN(teardown); + +/* run a test. provided description must be a string literal */ +TEST("basic assertion") +{ + /* ASSERT fails if passed some sort of non-true value (0, false, NULL) */ + ASSERT(1); +} + +TEST("basic not assertion") +{ + bool b = false; + + ASSERT_NOT(b); +} + +TEST("boolean comparison") +{ + bool a = false, b = true; + + /* fail if parameters are not equal */ + ASSERT_EQ(a, b); +} + +TEST("type mismatch") +{ + char a = 'a'; + int i = 97; + char *b = NULL; + + /* for convenience's sake, when presented with unmatched types, assertions + * try to resolve them in a way that's most likely to match the + * programmer's intentions. here 'i' is interpreted as a char */ + ASSERT_EQ(a, i); + + /* if there isn't a straightforward comparison to make, though (as is the + * case here, with a 'char' and 'char *'), a type mismatch error occurs */ + ASSERT_EQ(a, b); +} + +TEST("ECHO example") +{ + int i; + + /* ECHO can be used to neatly report information during a run */ + if (true) + ECHO("loop until i not less than 1"); + + for (i = 0; i < 2; i++) { + /* it takes printf format strings and variable args as well */ + ECHO("i == %d", i); + ASSERT_LT(i, 1); + } +} + +TEST("string comparison") +{ + char *s = "test"; + global_s = strdup("test"); + + /* USE_TEARDOWN; tells this test to call the previously defined teardown + * function on exiting (successfully or otherwise) */ + USE_TEARDOWN; + + /* strings are compared by content, so this assertion succeeds */ + ASSERT_EQ(s, global_s); +} + +TEST("pointer comparison") +{ + char *s = "test"; + global_s = strdup("test"); + USE_TEARDOWN; + + /* you can cast parameters in order to use a different type of comparison. + * here i'm casting the 'char *' to 'void *' so assertion performs a + * pointer comparison, which fails */ + ASSERT_EQ((void*)s, (void*)global_s); +} + +/* must come after all TESTs */ +END_TEST diff --git a/doc/run-01.png b/doc/run-01.png deleted file mode 100644 index b7c6838..0000000 Binary files a/doc/run-01.png and /dev/null differ diff --git a/doc/run-02.png b/doc/run-02.png deleted file mode 100644 index aedd395..0000000 Binary files a/doc/run-02.png and /dev/null differ diff --git a/doc/run-03.png b/doc/run-03.png deleted file mode 100644 index f6843dc..0000000 Binary files a/doc/run-03.png and /dev/null differ diff --git a/doc/run_01.png b/doc/run_01.png new file mode 100644 index 0000000..df74574 Binary files /dev/null and b/doc/run_01.png differ diff --git a/doc/run_02.png b/doc/run_02.png new file mode 100644 index 0000000..b84d5e5 Binary files /dev/null and b/doc/run_02.png differ diff --git a/doc/run_03.png b/doc/run_03.png new file mode 100644 index 0000000..05fd99c Binary files /dev/null and b/doc/run_03.png differ diff --git a/simple-test.h b/simple-test.h new file mode 100644 index 0000000..fa05d36 --- /dev/null +++ b/simple-test.h @@ -0,0 +1,473 @@ +#ifndef SIMPLE_TEST_H +#define SIMPLE_TEST_H + +#include +#include +#include +#include +#include +#include +#include + + +/************************************************** + * INTERNAL FUNCTIONALITY. DO NOT CALL DIRECTLY * + **************************************************/ + +enum simple_test_type { + SIMPLE_TEST_BOOL, + SIMPLE_TEST_INT, + SIMPLE_TEST_UNSIGNED, + SIMPLE_TEST_CHAR, + SIMPLE_TEST_STRING, + SIMPLE_TEST_POINTER, + SIMPLE_TEST_UNKNOWN, + SIMPLE_TEST_MISMATCH, +}; + +enum simple_test_cond { + SIMPLE_TEST_TRUE, + SIMPLE_TEST_FALSE, + SIMPLE_TEST_EQ, + SIMPLE_TEST_NEQ, + SIMPLE_TEST_GT, + SIMPLE_TEST_LT, + SIMPLE_TEST_GEQ, + SIMPLE_TEST_LEQ +}; + +static intmax_t simple_test_il, simple_test_ir; +static uintmax_t simple_test_ul, simple_test_ur; +static char *simple_test_sl, *simple_test_sr; +static void *simple_test_pl, *simple_test_pr; + +static int simple_test_assert(enum simple_test_type t, + enum simple_test_cond c, ...) +{ + va_list ap; + bool two = !(c == SIMPLE_TEST_TRUE || c == SIMPLE_TEST_FALSE); + + int r; + + va_start(ap, c); + + switch (t) { + case SIMPLE_TEST_MISMATCH: + return -2; + case SIMPLE_TEST_BOOL: + case SIMPLE_TEST_INT: + case SIMPLE_TEST_CHAR: + simple_test_il = va_arg(ap, intmax_t); + if (two) simple_test_ir = va_arg(ap, intmax_t); + switch (c) { + case SIMPLE_TEST_TRUE: + r = simple_test_il; + goto end; + case SIMPLE_TEST_FALSE: + r = !simple_test_il; + goto end; + case SIMPLE_TEST_EQ: + r = simple_test_il == simple_test_ir; + goto end; + case SIMPLE_TEST_NEQ: + r = simple_test_il != simple_test_ir; + goto end; + case SIMPLE_TEST_GT: + r = simple_test_il > simple_test_ir; + goto end; + case SIMPLE_TEST_LT: + r = simple_test_il < simple_test_ir; + goto end; + case SIMPLE_TEST_GEQ: + r = simple_test_il >= simple_test_ir; + goto end; + case SIMPLE_TEST_LEQ: + r = simple_test_il <= simple_test_ir; + goto end; + } + + case SIMPLE_TEST_UNSIGNED: + simple_test_ul = va_arg(ap, uintmax_t); + if (two) simple_test_ur = va_arg(ap, uintmax_t); + switch (c) { + case SIMPLE_TEST_TRUE: + r = simple_test_ul; + goto end; + case SIMPLE_TEST_FALSE: + r = !simple_test_ul; + goto end; + case SIMPLE_TEST_EQ: + r = simple_test_ul == simple_test_ur; + goto end; + case SIMPLE_TEST_NEQ: + r = simple_test_ul != simple_test_ur; + goto end; + case SIMPLE_TEST_GT: + r = simple_test_ul > simple_test_ur; + goto end; + case SIMPLE_TEST_LT: + r = simple_test_ul < simple_test_ur; + goto end; + case SIMPLE_TEST_GEQ: + r = simple_test_ul >= simple_test_ur; + goto end; + case SIMPLE_TEST_LEQ: + r = simple_test_ul <= simple_test_ur; + goto end; + } + + case SIMPLE_TEST_STRING: + simple_test_sl = va_arg(ap, char *); + if (two) simple_test_sr = va_arg(ap, char *); + switch (c) { + case SIMPLE_TEST_TRUE: + r = simple_test_sl != NULL; + goto end; + case SIMPLE_TEST_FALSE: + r = simple_test_sl == NULL; + goto end; + case SIMPLE_TEST_EQ: + if (simple_test_sl == NULL || simple_test_sr == NULL) + r = simple_test_sl == simple_test_sr; + else + r = strcmp(simple_test_sl, simple_test_sr) ? 0 : 1; + goto end; + case SIMPLE_TEST_NEQ: + if (simple_test_sl == NULL || simple_test_sr == NULL) + r = simple_test_sl != simple_test_sr; + else + r = strcmp(simple_test_sl, simple_test_sr) ? 1 : 0; + goto end; + case SIMPLE_TEST_GT: + if (simple_test_sl == NULL || simple_test_sr == NULL) + r = false; + else + r = strcmp(simple_test_sl, simple_test_sr) > 0 ? 1 : 0; + goto end; + case SIMPLE_TEST_LT: + if (simple_test_sl == NULL || simple_test_sr == NULL) + r = false; + else + r = strcmp(simple_test_sl, simple_test_sr) < 0 ? 1 : 0; + goto end; + case SIMPLE_TEST_GEQ: + if (simple_test_sl == NULL || simple_test_sr == NULL) + r = false; + else + r = strcmp(simple_test_sl, simple_test_sr) >= 0 ? 1 : 0; + goto end; + case SIMPLE_TEST_LEQ: + if (simple_test_sl == NULL || simple_test_sr == NULL) + r = false; + else + r = strcmp(simple_test_sl, simple_test_sr) <= 0 ? 1 : 0; + goto end; + } + + case SIMPLE_TEST_POINTER: + simple_test_pl = va_arg(ap, void *); + if (two) simple_test_pr = va_arg(ap, void *); + switch (c) { + case SIMPLE_TEST_TRUE: + r = simple_test_pl != NULL; + goto end; + case SIMPLE_TEST_FALSE: + r = simple_test_pl == NULL; + goto end; + case SIMPLE_TEST_EQ: + r = simple_test_pl == simple_test_pr; + goto end; + case SIMPLE_TEST_NEQ: + r = simple_test_pl != simple_test_pr; + goto end; + case SIMPLE_TEST_GT: + r = simple_test_pl > simple_test_pr; + goto end; + case SIMPLE_TEST_LT: + r = simple_test_pl < simple_test_pr; + goto end; + case SIMPLE_TEST_GEQ: + r = simple_test_pl >= simple_test_pr; + goto end; + case SIMPLE_TEST_LEQ: + r = simple_test_pl <= simple_test_pr; + goto end; + } + + default: + r = -1; + } + +end: + va_end(ap); + return r; +} + +static enum simple_test_type simple_test_type_resolve(enum simple_test_type t1, + enum simple_test_type t2) +{ + if (t1 != t2) { + if ((t1 == SIMPLE_TEST_INT && t2 == SIMPLE_TEST_UNSIGNED) + || (t1 == SIMPLE_TEST_UNSIGNED && t2 == SIMPLE_TEST_INT) + || (t1 == SIMPLE_TEST_BOOL && t2 == SIMPLE_TEST_UNSIGNED) + || (t1 == SIMPLE_TEST_UNSIGNED && t2 == SIMPLE_TEST_BOOL)) { + return SIMPLE_TEST_UNSIGNED; + } else if ((t1 == SIMPLE_TEST_BOOL && t2 == SIMPLE_TEST_INT) + || (t1 == SIMPLE_TEST_INT && t2 == SIMPLE_TEST_BOOL)) { + return SIMPLE_TEST_INT; + } else if ((t1 == SIMPLE_TEST_INT && t2 == SIMPLE_TEST_CHAR) + || (t1 == SIMPLE_TEST_CHAR && t2 == SIMPLE_TEST_INT)) { + return SIMPLE_TEST_CHAR; + } else if ((t1 == SIMPLE_TEST_CHAR && t2 == SIMPLE_TEST_UNSIGNED) + || (t1 == SIMPLE_TEST_UNSIGNED && t2 == SIMPLE_TEST_CHAR)) { + return SIMPLE_TEST_UNSIGNED; + } else if ((t1 == SIMPLE_TEST_POINTER && t2 == SIMPLE_TEST_STRING) + || (t1 == SIMPLE_TEST_STRING && t2 == SIMPLE_TEST_POINTER)) { + return SIMPLE_TEST_POINTER; + } else { + return SIMPLE_TEST_MISMATCH; + } + } + + return t1; +} + +#define SIMPLE_TEST_TYPE(a) \ + _Generic((a), \ + bool: SIMPLE_TEST_BOOL, \ + char: SIMPLE_TEST_CHAR, \ + int8_t: SIMPLE_TEST_INT, \ + int16_t: SIMPLE_TEST_INT, \ + int32_t: SIMPLE_TEST_INT, \ + int64_t: SIMPLE_TEST_INT, \ + uint8_t: SIMPLE_TEST_UNSIGNED, \ + uint16_t: SIMPLE_TEST_UNSIGNED, \ + uint32_t: SIMPLE_TEST_UNSIGNED, \ + uint64_t: SIMPLE_TEST_UNSIGNED, \ + char *: SIMPLE_TEST_STRING, \ + void *: SIMPLE_TEST_POINTER, \ + default: SIMPLE_TEST_UNKNOWN) + +#define SIMPLE_TEST_FAIL1(...) \ + do { \ + printf("\e[1m%*c :: at line %d, \e[m\e[1;31mfail: \e[m", \ + simple_test_pad_width, ' ', __LINE__); \ + printf(__VA_ARGS__); \ + printf("\n"); \ + } while (0) + +#define SIMPLE_TEST_PRINT_VAL(w, s, t) \ + do { \ + printf("\e[1m%*c :: ", simple_test_pad_width, ' '); \ + printf("`%s` \e[m== \e[1m", s); \ + switch (t) { \ + case SIMPLE_TEST_BOOL: \ + printf("%s", (w ? simple_test_il : simple_test_ir) \ + ? "true" : "false"); \ + break; \ + case SIMPLE_TEST_CHAR: \ + printf("%c", w ? (char)simple_test_il : (char)simple_test_ir); \ + break; \ + case SIMPLE_TEST_INT: \ + printf("%" PRIdMAX, w ? simple_test_il : simple_test_ir); \ + break; \ + case SIMPLE_TEST_UNSIGNED: \ + printf("%" PRIuMAX, w ? simple_test_ul : simple_test_ur); \ + break; \ + case SIMPLE_TEST_STRING: \ + printf(((w ? simple_test_sl : simple_test_sr) \ + ? "\"%s\"" : "%s"), w \ + ? simple_test_sl : simple_test_sr); \ + break; \ + case SIMPLE_TEST_POINTER: \ + printf("%p", w ? simple_test_pl : simple_test_pr); \ + break; \ + default: \ + break; \ + } \ + printf("\e[m\n"); \ + } while (0) + +#define SIMPLE_TEST_FAIL2 \ + do { \ + simple_test_fail_count++; \ + goto simple_test_loop_end; \ + } while (0) + +#define SIMPLE_TEST_ERR(...) \ + do { \ + printf("\e[1m%*c :: at line %d, \e[m\e[1;31merr: \e[m", \ + simple_test_pad_width, ' ', __LINE__); \ + printf(__VA_ARGS__); \ + printf("\n"); \ + printf("\e[1;31mtesting aborted\e[m\n"); \ + exit(1); \ + } while (0) + +#define SIMPLE_TEST_PRINT_BUF_WIDTH 512 + +#define SIMPLE_TEST_ASSERT1(t, c, s, a) \ + do { \ + switch ( simple_test_assert(t, c, (a)) ) { \ + case 1: break; \ + case 0: \ + SIMPLE_TEST_FAIL1(s " failed"); \ + SIMPLE_TEST_PRINT_VAL(0, #a, t); \ + SIMPLE_TEST_FAIL2; \ + break; \ + default: \ + SIMPLE_TEST_ERR("unrecognised type in assertion"); \ + } \ + } while (0) + +#define SIMPLE_TEST_ASSERT2(t1, t2, c, s, a, b) \ + do { \ + switch ( simple_test_assert(simple_test_type_resolve(t1, t2), \ + c, (a), (b)) ) { \ + case 1: break; \ + case 0: \ + SIMPLE_TEST_FAIL1(s " failed"); \ + SIMPLE_TEST_PRINT_VAL(0, #a, simple_test_type_resolve(t1, t2)); \ + SIMPLE_TEST_PRINT_VAL(1, #b, simple_test_type_resolve(t1, t2)); \ + SIMPLE_TEST_FAIL2; \ + break; \ + case -2: \ + SIMPLE_TEST_ERR("type mismatch in assertion"); \ + default: \ + SIMPLE_TEST_ERR("unrecognised type in assertion"); \ + } \ + } while (0) + + +/****************** + * BASIC MACROS * + ******************/ + +#define REGISTER_TEARDOWN(f) \ + do { \ + if (simple_test_teardown != NULL) \ + SIMPLE_TEST_ERR("teardown function already defined"); \ + simple_test_teardown = _Generic((f), \ + void(*)(void): (f), default: NULL); \ + if (simple_test_teardown == NULL) { \ + SIMPLE_TEST_ERR( \ + "wrongly-typed function passed to REGISTER_TEARDOWN"); \ + } \ + } while (0) + + +#define USE_TEARDOWN \ + do { \ + if (simple_test_teardown == NULL) \ + SIMPLE_TEST_ERR("teardown function undefined"); \ + simple_test_do_teardown = true; \ + } while (0) + +/* must appear before all tests */ +#define BEGIN_TEST \ + int main(int argc, char **argv) \ + { \ + int simple_test_iterator; \ + int simple_test_pad_width = 0; \ + int simple_test_fail_count = 0; \ + char simple_test_print_buf[SIMPLE_TEST_PRINT_BUF_WIDTH]; \ + int simple_test_test_count = 0; \ + int simple_test_test_current = 1; \ + int simple_test_test_current_at; \ + int simple_test_pass_number = 0; \ + bool simple_test_do_teardown = false; \ + void (*simple_test_teardown)(void) = NULL; \ + do { \ + simple_test_test_current_at = 0; \ + if (simple_test_pass_number == 0) { \ + printf("\e[1mstarting tests in " __FILE__ "...\n"); \ + } else { \ + simple_test_pad_width = sprintf(simple_test_print_buf, \ + "%d", simple_test_test_count) + 1; \ + } \ + for (simple_test_iterator = 0; simple_test_pass_number == 0 && \ + simple_test_iterator < 1; simple_test_iterator++) { \ + (void)0; \ + + +#define TEST(description) \ + } \ + if (simple_test_do_teardown) { \ + simple_test_do_teardown = false; \ + simple_test_teardown(); \ + } \ + simple_test_test_current_at++; \ + if (simple_test_pass_number == 0) { \ + simple_test_test_count++; \ + } else if (simple_test_pass_number \ + == simple_test_test_current_at) { \ + printf("\e[m%*d \e[1m:: \e[m\e[33m%s\e[m\n", simple_test_pad_width, \ + simple_test_test_current++, description); \ + +/* must appear after all tests */ +#define END_TEST \ + } \ + if (simple_test_do_teardown) { \ + simple_test_do_teardown = false; \ + simple_test_teardown(); \ + } \ + if (simple_test_test_count == 0) { \ + SIMPLE_TEST_ERR("no tests defined"); \ + } \ +simple_test_loop_end: \ + (void)0; \ + } while (simple_test_pass_number++ < simple_test_test_count); \ + if (simple_test_fail_count) { \ + printf("\e[1;31m%d of %d tests failed\e[m\n", \ + simple_test_fail_count, simple_test_test_count); \ + return 1; \ + } else { \ + printf("\e[1;32mall tests passed!\e[m\n"); \ + return 0; \ + } \ + } + +#define ECHO(...) \ + do { \ + printf("\e[1m%*c :: \e[m\e[34m", simple_test_pad_width, ' '); \ + printf(__VA_ARGS__); \ + printf("...\e[m\n"); \ + } while (0) + + +/********************** + * ASSERTION MACROS * + **********************/ + +#define ASSERT(a) \ + SIMPLE_TEST_ASSERT1(SIMPLE_TEST_TYPE((a)), SIMPLE_TEST_TRUE, "ASSERT", a) + +#define ASSERT_NOT(a) \ + SIMPLE_TEST_ASSERT1(SIMPLE_TEST_TYPE((a)), SIMPLE_TEST_FALSE, \ + "ASSERT_NOT", a) + +#define ASSERT_EQ(a, b) \ + SIMPLE_TEST_ASSERT2(SIMPLE_TEST_TYPE((a)), SIMPLE_TEST_TYPE((b)), \ + SIMPLE_TEST_EQ, "ASSERT_EQ", a, b) + +#define ASSERT_NEQ(a, b) \ + SIMPLE_TEST_ASSERT2(SIMPLE_TEST_TYPE((a)), SIMPLE_TEST_TYPE((b)), \ + SIMPLE_TEST_NEQ, "ASSERT_NEQ", a, b) + +#define ASSERT_GT(a, b) \ + SIMPLE_TEST_ASSERT2(SIMPLE_TEST_TYPE((a)), SIMPLE_TEST_TYPE((b)), \ + SIMPLE_TEST_GT, "ASSERT_GT", a, b) + +#define ASSERT_LT(a, b) \ + SIMPLE_TEST_ASSERT2(SIMPLE_TEST_TYPE((a)), SIMPLE_TEST_TYPE((b)), \ + SIMPLE_TEST_LT, "ASSERT_LT", a, b) + +#define ASSERT_GEQ(a, b) \ + SIMPLE_TEST_ASSERT2(SIMPLE_TEST_TYPE((a)), SIMPLE_TEST_TYPE((b)), \ + SIMPLE_TEST_GEQ, "ASSERT_GEQ", a, b) + +#define ASSERT_LEQ(a, b) \ + SIMPLE_TEST_ASSERT2(SIMPLE_TEST_TYPE((a)), SIMPLE_TEST_TYPE((b)), \ + SIMPLE_TEST_LEQ, "ASSERT_LEQ", a, b) + +#endif diff --git a/src/simple-test.h b/src/simple-test.h deleted file mode 100644 index 63da668..0000000 --- a/src/simple-test.h +++ /dev/null @@ -1,472 +0,0 @@ -#ifndef SIMPLE_TEST_H -#define SIMPLE_TEST_H - -#include -#include -#include -#include -#include -#include -#include - - -/************************************************** - * INTERNAL FUNCTIONALITY. DO NOT CALL DIRECTLY * - **************************************************/ - -enum simple_test_type { - SIMPLE_TEST_BOOL, - SIMPLE_TEST_INT, - SIMPLE_TEST_UNSIGNED, - SIMPLE_TEST_CHAR, - SIMPLE_TEST_STRING, - SIMPLE_TEST_POINTER, - SIMPLE_TEST_UNKNOWN, - SIMPLE_TEST_MISMATCH, -}; - -enum simple_test_cond { - SIMPLE_TEST_TRUE, - SIMPLE_TEST_FALSE, - SIMPLE_TEST_EQ, - SIMPLE_TEST_NEQ, - SIMPLE_TEST_GT, - SIMPLE_TEST_LT, - SIMPLE_TEST_GEQ, - SIMPLE_TEST_LEQ -}; - -static intmax_t simple_test_il, simple_test_ir; -static uintmax_t simple_test_ul, simple_test_ur; -static char *simple_test_sl, *simple_test_sr; -static void *simple_test_pl, *simple_test_pr; - -static int simple_test_assert(enum simple_test_type t, - enum simple_test_cond c, ...) -{ - va_list ap; - bool two = !(c == SIMPLE_TEST_TRUE || c == SIMPLE_TEST_FALSE); - - int r; - - va_start(ap, c); - - switch (t) { - case SIMPLE_TEST_MISMATCH: - return -2; - case SIMPLE_TEST_BOOL: - case SIMPLE_TEST_INT: - case SIMPLE_TEST_CHAR: - simple_test_il = va_arg(ap, intmax_t); - if (two) simple_test_ir = va_arg(ap, intmax_t); - switch (c) { - case SIMPLE_TEST_TRUE: - r = simple_test_il; - goto end; - case SIMPLE_TEST_FALSE: - r = !simple_test_il; - goto end; - case SIMPLE_TEST_EQ: - r = simple_test_il == simple_test_ir; - goto end; - case SIMPLE_TEST_NEQ: - r = simple_test_il != simple_test_ir; - goto end; - case SIMPLE_TEST_GT: - r = simple_test_il > simple_test_ir; - goto end; - case SIMPLE_TEST_LT: - r = simple_test_il < simple_test_ir; - goto end; - case SIMPLE_TEST_GEQ: - r = simple_test_il >= simple_test_ir; - goto end; - case SIMPLE_TEST_LEQ: - r = simple_test_il <= simple_test_ir; - goto end; - } - - case SIMPLE_TEST_UNSIGNED: - simple_test_ul = va_arg(ap, uintmax_t); - if (two) simple_test_ur = va_arg(ap, uintmax_t); - switch (c) { - case SIMPLE_TEST_TRUE: - r = simple_test_ul; - goto end; - case SIMPLE_TEST_FALSE: - r = !simple_test_ul; - goto end; - case SIMPLE_TEST_EQ: - r = simple_test_ul == simple_test_ur; - goto end; - case SIMPLE_TEST_NEQ: - r = simple_test_ul != simple_test_ur; - goto end; - case SIMPLE_TEST_GT: - r = simple_test_ul > simple_test_ur; - goto end; - case SIMPLE_TEST_LT: - r = simple_test_ul < simple_test_ur; - goto end; - case SIMPLE_TEST_GEQ: - r = simple_test_ul >= simple_test_ur; - goto end; - case SIMPLE_TEST_LEQ: - r = simple_test_ul <= simple_test_ur; - goto end; - } - - case SIMPLE_TEST_STRING: - simple_test_sl = va_arg(ap, char *); - if (two) simple_test_sr = va_arg(ap, char *); - switch (c) { - case SIMPLE_TEST_TRUE: - r = simple_test_sl != NULL; - goto end; - case SIMPLE_TEST_FALSE: - r = simple_test_sl == NULL; - goto end; - case SIMPLE_TEST_EQ: - if (simple_test_sl == NULL || simple_test_sr == NULL) - r = simple_test_sl == simple_test_sr; - else - r = strcmp(simple_test_sl, simple_test_sr) ? 0 : 1; - goto end; - case SIMPLE_TEST_NEQ: - if (simple_test_sl == NULL || simple_test_sr == NULL) - r = simple_test_sl != simple_test_sr; - else - r = strcmp(simple_test_sl, simple_test_sr) ? 1 : 0; - goto end; - case SIMPLE_TEST_GT: - if (simple_test_sl == NULL || simple_test_sr == NULL) - r = false; - else - r = strcmp(simple_test_sl, simple_test_sr) > 0 ? 1 : 0; - goto end; - case SIMPLE_TEST_LT: - if (simple_test_sl == NULL || simple_test_sr == NULL) - r = false; - else - r = strcmp(simple_test_sl, simple_test_sr) < 0 ? 1 : 0; - goto end; - case SIMPLE_TEST_GEQ: - if (simple_test_sl == NULL || simple_test_sr == NULL) - r = false; - else - r = strcmp(simple_test_sl, simple_test_sr) >= 0 ? 1 : 0; - goto end; - case SIMPLE_TEST_LEQ: - if (simple_test_sl == NULL || simple_test_sr == NULL) - r = false; - else - r = strcmp(simple_test_sl, simple_test_sr) <= 0 ? 1 : 0; - goto end; - } - - case SIMPLE_TEST_POINTER: - simple_test_pl = va_arg(ap, void *); - if (two) simple_test_pr = va_arg(ap, void *); - switch (c) { - case SIMPLE_TEST_TRUE: - r = simple_test_pl != NULL; - goto end; - case SIMPLE_TEST_FALSE: - r = simple_test_pl == NULL; - goto end; - case SIMPLE_TEST_EQ: - r = simple_test_pl == simple_test_pr; - goto end; - case SIMPLE_TEST_NEQ: - r = simple_test_pl != simple_test_pr; - goto end; - case SIMPLE_TEST_GT: - r = simple_test_pl > simple_test_pr; - goto end; - case SIMPLE_TEST_LT: - r = simple_test_pl < simple_test_pr; - goto end; - case SIMPLE_TEST_GEQ: - r = simple_test_pl >= simple_test_pr; - goto end; - case SIMPLE_TEST_LEQ: - r = simple_test_pl <= simple_test_pr; - goto end; - } - - default: - r = -1; - } - -end: - va_end(ap); - return r; -} - -static enum simple_test_type simple_test_type_resolve(enum simple_test_type t1, - enum simple_test_type t2) -{ - if (t1 != t2) { - if ((t1 == SIMPLE_TEST_INT && t2 == SIMPLE_TEST_UNSIGNED) - || (t1 == SIMPLE_TEST_UNSIGNED && t2 == SIMPLE_TEST_INT) - || (t1 == SIMPLE_TEST_BOOL && t2 == SIMPLE_TEST_UNSIGNED) - || (t1 == SIMPLE_TEST_UNSIGNED && t2 == SIMPLE_TEST_BOOL)) { - return SIMPLE_TEST_UNSIGNED; - } else if ((t1 == SIMPLE_TEST_BOOL && t2 == SIMPLE_TEST_INT) - || (t1 == SIMPLE_TEST_INT && t2 == SIMPLE_TEST_BOOL)) { - return SIMPLE_TEST_INT; - } else if ((t1 == SIMPLE_TEST_INT && t2 == SIMPLE_TEST_CHAR) - || (t1 == SIMPLE_TEST_CHAR && t2 == SIMPLE_TEST_INT)) { - return SIMPLE_TEST_CHAR; - } else if ((t1 == SIMPLE_TEST_CHAR && t2 == SIMPLE_TEST_UNSIGNED) - || (t1 == SIMPLE_TEST_UNSIGNED && t2 == SIMPLE_TEST_CHAR)) { - return SIMPLE_TEST_UNSIGNED; - } else if ((t1 == SIMPLE_TEST_POINTER && t2 == SIMPLE_TEST_STRING) - || (t1 == SIMPLE_TEST_STRING && t2 == SIMPLE_TEST_POINTER)) { - return SIMPLE_TEST_POINTER; - } else { - return SIMPLE_TEST_MISMATCH; - } - } - - return t1; -} - -#define SIMPLE_TEST_TYPE(a) \ - _Generic((a), \ - bool: SIMPLE_TEST_BOOL, \ - char: SIMPLE_TEST_CHAR, \ - int8_t: SIMPLE_TEST_INT, \ - int16_t: SIMPLE_TEST_INT, \ - int32_t: SIMPLE_TEST_INT, \ - int64_t: SIMPLE_TEST_INT, \ - uint8_t: SIMPLE_TEST_UNSIGNED, \ - uint16_t: SIMPLE_TEST_UNSIGNED, \ - uint32_t: SIMPLE_TEST_UNSIGNED, \ - uint64_t: SIMPLE_TEST_UNSIGNED, \ - char *: SIMPLE_TEST_STRING, \ - void *: SIMPLE_TEST_POINTER, \ - default: SIMPLE_TEST_UNKNOWN) - -#define SIMPLE_TEST_FAIL1(...) \ - do { \ - printf("\e[1m%*c :: at line %d, \e[m\e[1;31mfail: \e[m", \ - simple_test_pad_width, ' ', __LINE__); \ - printf(__VA_ARGS__); \ - printf("\n"); \ - } while (0) - -#define SIMPLE_TEST_PRINT_VAL(w, s, t) \ - do { \ - printf("\e[1m%*c :: ", simple_test_pad_width, ' '); \ - printf("`%s` \e[m== \e[1m", s); \ - switch (t) { \ - case SIMPLE_TEST_BOOL: \ - printf("%s", (w ? simple_test_il : simple_test_ir) \ - ? "true" : "false"); \ - break; \ - case SIMPLE_TEST_CHAR: \ - printf("%c", w ? (char)simple_test_il : (char)simple_test_ir); \ - break; \ - case SIMPLE_TEST_INT: \ - printf("%" PRIdMAX, w ? simple_test_il : simple_test_ir); \ - break; \ - case SIMPLE_TEST_UNSIGNED: \ - printf("%" PRIuMAX, w ? simple_test_ul : simple_test_ur); \ - break; \ - case SIMPLE_TEST_STRING: \ - printf(((w ? simple_test_sl : simple_test_sr) \ - ? "\"%s\"" : "%s"), w \ - ? simple_test_sl : simple_test_sr); \ - break; \ - case SIMPLE_TEST_POINTER: \ - printf("%p", w ? simple_test_pl : simple_test_pr); \ - break; \ - default: \ - break; \ - } \ - printf("\e[m\n"); \ - } while (0) - -#define SIMPLE_TEST_FAIL2 \ - do { \ - simple_test_fail_count++; \ - goto simple_test_loop_end; \ - } while (0) - -#define SIMPLE_TEST_ERR(...) \ - do { \ - printf("\e[1m%*c :: at line %d, \e[m\e[1;31merr: \e[m", \ - simple_test_pad_width, ' ', __LINE__); \ - printf(__VA_ARGS__); \ - printf("\n"); \ - exit(1); \ - } while (0) - -#define SIMPLE_TEST_PRINT_BUF_WIDTH 512 - -#define SIMPLE_TEST_ASSERT1(t, c, s, a) \ - do { \ - switch ( simple_test_assert(t, c, (a)) ) { \ - case 1: break; \ - case 0: \ - SIMPLE_TEST_FAIL1(s " failed"); \ - SIMPLE_TEST_PRINT_VAL(0, #a, t); \ - SIMPLE_TEST_FAIL2; \ - break; \ - default: \ - SIMPLE_TEST_ERR("unrecognised type in assertion"); \ - } \ - } while (0) - -#define SIMPLE_TEST_ASSERT2(t1, t2, c, s, a, b) \ - do { \ - switch ( simple_test_assert(simple_test_type_resolve(t1, t2), \ - c, (a), (b)) ) { \ - case 1: break; \ - case 0: \ - SIMPLE_TEST_FAIL1(s " failed"); \ - SIMPLE_TEST_PRINT_VAL(0, #a, simple_test_type_resolve(t1, t2)); \ - SIMPLE_TEST_PRINT_VAL(1, #b, simple_test_type_resolve(t1, t2)); \ - SIMPLE_TEST_FAIL2; \ - break; \ - case -2: \ - SIMPLE_TEST_ERR("type mismatch in assertion"); \ - default: \ - SIMPLE_TEST_ERR("unrecognised type in assertion"); \ - } \ - } while (0) - - -/****************** - * BASIC MACROS * - ******************/ - -#define REGISTER_TEARDOWN(f) \ - do { \ - if (simple_test_teardown != NULL) \ - SIMPLE_TEST_ERR("teardown function already defined"); \ - simple_test_teardown = _Generic((f), \ - void(*)(void): (f), default: NULL); \ - if (simple_test_teardown == NULL) { \ - SIMPLE_TEST_ERR( \ - "wrongly-typed function passed to REGISTER_TEARDOWN"); \ - } \ - } while (0) - - -#define USE_TEARDOWN \ - do { \ - if (simple_test_teardown == NULL) \ - SIMPLE_TEST_ERR("teardown function undefined"); \ - simple_test_do_teardown = true; \ - } while (0) - -/* must appear before all tests */ -#define BEGIN_TEST \ - int main(int argc, char **argv) \ - { \ - int simple_test_iterator; \ - int simple_test_pad_width = 0; \ - int simple_test_fail_count = 0; \ - char simple_test_print_buf[SIMPLE_TEST_PRINT_BUF_WIDTH]; \ - int simple_test_test_count = 0; \ - int simple_test_test_current = 1; \ - int simple_test_test_current_at; \ - int simple_test_pass_number = 0; \ - bool simple_test_do_teardown = false; \ - void (*simple_test_teardown)(void) = NULL; \ - do { \ - simple_test_test_current_at = 0; \ - if (simple_test_pass_number == 0) { \ - printf("\e[1mstarting tests in " __FILE__ "...\n"); \ - } else { \ - simple_test_pad_width = sprintf(simple_test_print_buf, \ - "%d", simple_test_test_count) + 1; \ - } \ - for (simple_test_iterator = 0; simple_test_pass_number == 0 && \ - simple_test_iterator < 1; simple_test_iterator++) { \ - (void)0; \ - - -#define TEST(description) \ - } \ - if (simple_test_do_teardown) { \ - simple_test_do_teardown = false; \ - simple_test_teardown(); \ - } \ - simple_test_test_current_at++; \ - if (simple_test_pass_number == 0) { \ - simple_test_test_count++; \ - } else if (simple_test_pass_number \ - == simple_test_test_current_at) { \ - printf("\e[m%*d \e[1m:: \e[m\e[33m%s\e[m\n", simple_test_pad_width, \ - simple_test_test_current++, description); \ - -/* must appear after all tests */ -#define END_TEST \ - } \ - if (simple_test_do_teardown) { \ - simple_test_do_teardown = false; \ - simple_test_teardown(); \ - } \ - if (simple_test_test_count == 0) { \ - SIMPLE_TEST_ERR("no tests defined"); \ - } \ -simple_test_loop_end: \ - (void)0; \ - } while (simple_test_pass_number++ < simple_test_test_count); \ - if (simple_test_fail_count) { \ - printf("\e[1;31m%d of %d tests failed\e[m\n", \ - simple_test_fail_count, simple_test_test_count); \ - return 1; \ - } else { \ - printf("\e[1;32mall tests passed!\e[m\n"); \ - return 0; \ - } \ - } - -#define ECHO(...) \ - do { \ - printf("\e[1m%*c :: \e[m\e[34m", simple_test_pad_width, ' '); \ - printf(__VA_ARGS__); \ - printf("...\e[m\n"); \ - } while (0) - - -/********************** - * ASSERTION MACROS * - **********************/ - -#define ASSERT(a) \ - SIMPLE_TEST_ASSERT1(SIMPLE_TEST_TYPE((a)), SIMPLE_TEST_TRUE, "ASSERT", a) - -#define ASSERT_NOT(a) \ - SIMPLE_TEST_ASSERT1(SIMPLE_TEST_TYPE((a)), SIMPLE_TEST_FALSE, \ - "ASSERT_NOT", a) - -#define ASSERT_EQ(a, b) \ - SIMPLE_TEST_ASSERT2(SIMPLE_TEST_TYPE((a)), SIMPLE_TEST_TYPE((b)), \ - SIMPLE_TEST_EQ, "ASSERT_EQ", a, b) - -#define ASSERT_NEQ(a, b) \ - SIMPLE_TEST_ASSERT2(SIMPLE_TEST_TYPE((a)), SIMPLE_TEST_TYPE((b)), \ - SIMPLE_TEST_NEQ, "ASSERT_NEQ", a, b) - -#define ASSERT_GT(a, b) \ - SIMPLE_TEST_ASSERT2(SIMPLE_TEST_TYPE((a)), SIMPLE_TEST_TYPE((b)), \ - SIMPLE_TEST_GT, "ASSERT_GT", a, b) - -#define ASSERT_LT(a, b) \ - SIMPLE_TEST_ASSERT2(SIMPLE_TEST_TYPE((a)), SIMPLE_TEST_TYPE((b)), \ - SIMPLE_TEST_LT, "ASSERT_LT", a, b) - -#define ASSERT_GEQ(a, b) \ - SIMPLE_TEST_ASSERT2(SIMPLE_TEST_TYPE((a)), SIMPLE_TEST_TYPE((b)), \ - SIMPLE_TEST_GEQ, "ASSERT_GEQ", a, b) - -#define ASSERT_LEQ(a, b) \ - SIMPLE_TEST_ASSERT2(SIMPLE_TEST_TYPE((a)), SIMPLE_TEST_TYPE((b)), \ - SIMPLE_TEST_LEQ, "ASSERT_LEQ", a, b) - -#endif -- cgit v1.2.3