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 --- simple-test.h | 473 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 473 insertions(+) create mode 100644 simple-test.h (limited to 'simple-test.h') 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 -- cgit v1.2.3