From 7f8d3a898169eabb1f515e3206c762812ea4b475 Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Fri, 18 Aug 2017 14:38:06 -0700 Subject: Updated convey test framework, and self tests for it. --- tests/CMakeLists.txt | 10 ++ tests/convey.c | 329 +++++++++++++++++++++++---------------------------- tests/convey.h | 194 +++++++++++++++--------------- tests/convey_test.c | 145 +++++++++++++++++++++++ 4 files changed, 397 insertions(+), 281 deletions(-) create mode 100644 tests/convey_test.c diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 7dd74d8a..357ea402 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -35,6 +35,16 @@ if (NNG_TESTS) add_definitions (-pthread) endif() + # convey tests -- verify the test framework works! + add_executable(convey_test convey_test.c convey.c) + if (CMAKE_THREAD_LIBS_INIT) + target_link_libraries (convey_test "${CMAKE_THREAD_LIBS_INIT}") + endif() + add_test (NAME convey_test COMMAND convey_test + -v -d -p ENV_TEST=ON -p ANOTHERNAME -p AGAIN=yes extra) + set_tests_properties( convey_test PROPERTIES TIMEOUT 2) + list (APPEND all_tests convey_test) + set (TEST_PORT 12100) macro (add_nng_test NAME TIMEOUT) list (APPEND all_tests ${NAME}) diff --git a/tests/convey.c b/tests/convey.c index 2d2b1f03..2cb4e367 100644 --- a/tests/convey.c +++ b/tests/convey.c @@ -1,5 +1,5 @@ /* - * Copyright 2016 Garrett D'Amore + * Copyright 2017 Garrett D'Amore * * This software is supplied under the terms of the MIT License, a * copy of which should be located in the distribution where this @@ -29,12 +29,12 @@ * only added late -- like in 2010. Specifically uint32_t and uint64_t). */ -#include -#include -#include -#include #include #include +#include +#include +#include +#include #include #ifdef _WIN32 @@ -42,11 +42,11 @@ #else -#include -#include #include -#include +#include #include +#include +#include #ifndef CONVEY_NO_THREADS #include @@ -76,81 +76,81 @@ * a scope not expressed to user code, these rules are relaxed. */ -static const char *convey_sym_pass = "."; -static const char *convey_sym_skip = "?"; -static const char *convey_sym_fail = "X"; +static const char *convey_sym_pass = "."; +static const char *convey_sym_skip = "?"; +static const char *convey_sym_fail = "X"; static const char *convey_sym_fatal = "!"; -static const char *convey_nocolor = ""; -static const char *convey_green = ""; -static const char *convey_red = ""; -static const char *convey_yellow = ""; - -static int convey_debug = 0; -static int convey_verbose = 0; -static int convey_nassert = 0; -static int convey_nskip = 0; +static const char *convey_nocolor = ""; +static const char *convey_green = ""; +static const char *convey_red = ""; +static const char *convey_yellow = ""; + +static int convey_debug = 0; +static int convey_verbose = 0; +static int convey_nassert = 0; +static int convey_nskip = 0; static const char *convey_assert_color = ""; #if defined(_WIN32) -static WORD convey_defattr; +static WORD convey_defattr; static HANDLE convey_console; #endif -#define CONVEY_EXIT_OK 0 -#define CONVEY_EXIT_USAGE 1 -#define CONVEY_EXIT_FAIL 2 -#define CONVEY_EXIT_FATAL 3 -#define CONVEY_EXIT_NOMEM 4 +#define CONVEY_EXIT_OK 0 +#define CONVEY_EXIT_USAGE 1 +#define CONVEY_EXIT_FAIL 2 +#define CONVEY_EXIT_FATAL 3 +#define CONVEY_EXIT_NOMEM 4 struct convey_timer { - uint64_t timer_base; - uint64_t timer_count; - uint64_t timer_rate; - int timer_running; + uint64_t timer_base; + uint64_t timer_count; + uint64_t timer_rate; + int timer_running; }; struct convey_log { - char * log_buf; - size_t log_size; - size_t log_length; + char * log_buf; + size_t log_size; + size_t log_length; }; struct convey_ctx { - char ctx_name[256]; - struct convey_ctx * ctx_parent; - struct convey_ctx * ctx_root; /* the root node on the list */ - struct convey_ctx * ctx_next; /* root list only, cleanup */ - int ctx_level; - int ctx_done; - int ctx_started; - jmp_buf * ctx_jmp; - int ctx_fatal; - int ctx_fail; - int ctx_skip; - int ctx_printed; - struct convey_timer ctx_timer; - struct convey_log * ctx_errlog; - struct convey_log * ctx_faillog; - struct convey_log * ctx_dbglog; + char ctx_name[256]; + struct convey_ctx * ctx_parent; + struct convey_ctx * ctx_root; /* the root node on the list */ + struct convey_ctx * ctx_next; /* root list only, cleanup */ + int ctx_level; + int ctx_done; + int ctx_started; + jmp_buf * ctx_jmp; + int ctx_fatal; + int ctx_fail; + int ctx_skip; + int ctx_printed; + struct convey_timer ctx_timer; + struct convey_log * ctx_errlog; + struct convey_log * ctx_faillog; + struct convey_log * ctx_dbglog; }; -static void convey_print_result(struct convey_ctx *); -static void convey_init_timer(struct convey_timer *); -static void convey_start_timer(struct convey_timer *); -static void convey_stop_timer(struct convey_timer *); -static void convey_read_timer(struct convey_timer *, int *, int *); -static void convey_init_term(void); -static int convey_tls_init(void); +static void convey_print_result(struct convey_ctx *); +static void convey_init_timer(struct convey_timer *); +static void convey_start_timer(struct convey_timer *); +static void convey_stop_timer(struct convey_timer *); +static void convey_read_timer(struct convey_timer *, int *, int *); +static void convey_init_term(void); +static int convey_tls_init(void); static void *convey_tls_get(void); -static int convey_tls_set(void *); +static int convey_tls_set(void *); static struct convey_ctx *convey_get_ctx(void); static void convey_vlogf(struct convey_log *, const char *, va_list, int); static void convey_logf(struct convey_log *, const char *, ...); static void convey_log_emit(struct convey_log *, const char *, const char *); static void convey_log_free(struct convey_log *); static struct convey_log *convey_log_alloc(void); -static char *convey_nextline(char **); -static void convey_emit_color(const char *); +static char * convey_nextline(char **); +static void convey_emit_color(const char *); /* * convey_emit_color just changes the output text to the color @@ -165,8 +165,8 @@ convey_emit_color(const char *color) WORD attr; attr = convey_defattr & - ~(FOREGROUND_BLUE|FOREGROUND_GREEN|FOREGROUND_RED| - FOREGROUND_INTENSITY); + ~(FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | + FOREGROUND_INTENSITY); if (color == convey_nocolor) { attr = convey_defattr; @@ -190,7 +190,6 @@ convey_emit_color(const char *color) #endif } - /* * convey_print_result prints the test results. It prints more information * in convey_verbose mode. Note that its possible for assertion checks done at @@ -207,15 +206,16 @@ convey_print_result(struct convey_ctx *t) int secs, usecs; if (t->ctx_root == t) { - convey_stop_timer(&t->ctx_timer); /* This is idempotent */ + convey_stop_timer(&t->ctx_timer); /* This is idempotent */ convey_read_timer(&t->ctx_timer, &secs, &usecs); (void) convey_logf(t->ctx_dbglog, "Test %s: %s (%d.%02ds)\n", - t->ctx_fatal ? "FATAL" : - t->ctx_fail ? "FAIL" : - t->ctx_skip ? "PASS (with SKIPs)" : - "PASS", t->ctx_name, secs, usecs / 10000); + t->ctx_fatal ? "FATAL" + : t->ctx_fail + ? "FAIL" + : t->ctx_skip ? "PASS (with SKIPs)" : "PASS", + t->ctx_name, secs, usecs / 10000); if (convey_verbose) { (void) puts(""); @@ -229,20 +229,21 @@ convey_print_result(struct convey_ctx *t) (void) puts(""); (void) puts(""); convey_emit_color(convey_assert_color); - (void) printf("%d assertions thus far", convey_nassert); + (void) printf( + "%d assertions thus far", convey_nassert); convey_emit_color(convey_nocolor); if (convey_nskip) { (void) fputs(" ", stdout); convey_emit_color(convey_yellow); - (void) fputs("(one or more sections skipped)", - stdout); + (void) fputs( + "(one or more sections skipped)", stdout); convey_emit_color(convey_nocolor); } (void) printf("\n\n--- %s: %s (%d.%02ds)\n", - t->ctx_fatal ? "FATAL" : - t->ctx_fail ? "FAIL" : - "PASS", t->ctx_name, secs, usecs / 10000); + t->ctx_fatal ? "FATAL" + : t->ctx_fail ? "FAIL" : "PASS", + t->ctx_name, secs, usecs / 10000); } /* Remove the context, because we cannot reenter here */ @@ -256,13 +257,12 @@ convey_print_result(struct convey_ctx *t) convey_log_free(t->ctx_errlog); } t = t->ctx_next; - memset(freeit, 0, sizeof (*freeit)); + memset(freeit, 0, sizeof(*freeit)); free(freeit); } } } - /* * conveyStart is called when the context starts, before any call to * setjmp is made. If the context isn't initialized already, that is @@ -282,37 +282,37 @@ conveyStart(conveyScope *scope, const char *name) if ((t = scope->cs_data) != NULL) { if (t->ctx_done) { convey_print_result(t); - return (1); /* all done, skip */ + return (1); /* all done, skip */ } - return (0); /* continue onward */ + return (0); /* continue onward */ } - scope->cs_data = (t = calloc(1, sizeof (struct convey_ctx))); + scope->cs_data = (t = calloc(1, sizeof(struct convey_ctx))); if (t == NULL) { goto allocfail; } t->ctx_jmp = &scope->cs_jmp; - (void) snprintf(t->ctx_name, sizeof (t->ctx_name)-1, "%s", name); + (void) snprintf(t->ctx_name, sizeof(t->ctx_name) - 1, "%s", name); + if (parent != NULL) { t->ctx_parent = parent; - t->ctx_root = t->ctx_parent->ctx_root; - t->ctx_level = t->ctx_parent->ctx_level + 1; + t->ctx_root = t->ctx_parent->ctx_root; + t->ctx_level = t->ctx_parent->ctx_level + 1; /* unified logging against the root context */ - t->ctx_dbglog = t->ctx_root->ctx_dbglog; - t->ctx_faillog = t->ctx_root->ctx_faillog; - t->ctx_errlog = t->ctx_root->ctx_errlog; - t->ctx_next = t->ctx_root->ctx_next; + t->ctx_dbglog = t->ctx_root->ctx_dbglog; + t->ctx_faillog = t->ctx_root->ctx_faillog; + t->ctx_errlog = t->ctx_root->ctx_errlog; + t->ctx_next = t->ctx_root->ctx_next; t->ctx_root->ctx_next = t; } else { t->ctx_parent = t; - t->ctx_root = t; + t->ctx_root = t; if (((t->ctx_errlog = convey_log_alloc()) == NULL) || ((t->ctx_faillog = convey_log_alloc()) == NULL) || ((t->ctx_dbglog = convey_log_alloc()) == NULL)) { goto allocfail; } - convey_logf(t->ctx_dbglog, - "Test Started: %s\n", t->ctx_name); + convey_logf(t->ctx_dbglog, "Test Started: %s\n", t->ctx_name); } return (0); @@ -330,7 +330,6 @@ allocfail: return (1); } - /* * conveyLoop is called right after setjmp. If unwind is true it indicates * that setjmp returned true, and we are unwinding the stack. In that case @@ -344,7 +343,7 @@ int conveyLoop(conveyScope *scope, int unwind) { struct convey_ctx *t; - int i; + int i; if ((t = scope->cs_data) == NULL) { return (1); @@ -382,7 +381,6 @@ conveyLoop(conveyScope *scope, int unwind) return (0); } - void conveyFinish(conveyScope *scope, int *rvp) { @@ -407,12 +405,11 @@ conveyFinish(conveyScope *scope, int *rvp) longjmp(*t->ctx_jmp, 1); } - void conveySkip(const char *file, int line, const char *fmt, ...) { - va_list ap; - struct convey_ctx *t = convey_get_ctx(); + va_list ap; + struct convey_ctx *t = convey_get_ctx(); struct convey_log *dlog = t->ctx_dbglog; if (convey_verbose) { @@ -420,17 +417,15 @@ conveySkip(const char *file, int line, const char *fmt, ...) (void) fputs(convey_sym_skip, stdout); convey_emit_color(convey_nocolor); } - convey_logf(dlog, "* %s (%s:%d) (Skip): ", - t->ctx_name, file, line); + convey_logf(dlog, "* %s (%s:%d) (Skip): ", t->ctx_name, file, line); va_start(ap, fmt); convey_vlogf(dlog, fmt, ap, 1); va_end(ap); - t->ctx_done = 1; /* This forces an end */ + t->ctx_done = 1; /* This forces an end */ convey_nskip++; longjmp(*t->ctx_jmp, 1); } - void conveyAssertFail(const char *cond, const char *file, int line) { @@ -447,18 +442,16 @@ conveyAssertFail(const char *cond, const char *file, int line) } convey_assert_color = convey_yellow; t->ctx_fail++; - t->ctx_done = 1; /* This forces an end */ - convey_logf(t->ctx_faillog, "* %s (Assertion Failed)\n", - t->ctx_name); + t->ctx_done = 1; /* This forces an end */ + convey_logf(t->ctx_faillog, "* Assertion Failed (%s)\n", t->ctx_name); convey_logf(t->ctx_faillog, "File: %s\n", file); convey_logf(t->ctx_faillog, "Line: %d\n", line); convey_logf(t->ctx_faillog, "Test: %s\n\n", cond); - convey_logf(t->ctx_dbglog, "* %s (%s:%d) (FAILED): %s\n", - t->ctx_name, file, line, cond); + convey_logf(t->ctx_dbglog, "* %s (%s:%d) (FAILED): %s\n", t->ctx_name, + file, line, cond); longjmp(*t->ctx_jmp, 1); } - void conveyAssertPass(const char *cond, const char *file, int line) { @@ -470,11 +463,10 @@ conveyAssertPass(const char *cond, const char *file, int line) (void) fputs(convey_sym_pass, stdout); convey_emit_color(convey_nocolor); } - convey_logf(t->ctx_dbglog, "* %s (%s:%d) (Passed): %s\n", - t->ctx_name, file, line, cond); + convey_logf(t->ctx_dbglog, "* %s (%s:%d) (Passed): %s\n", t->ctx_name, + file, line, cond); } - void conveyAssertSkip(const char *cond, const char *file, int line) { @@ -486,11 +478,10 @@ conveyAssertSkip(const char *cond, const char *file, int line) (void) fputs(convey_sym_pass, stdout); convey_emit_color(convey_nocolor); } - convey_logf(t->ctx_dbglog, "* %s (%s:%d) (Skip): %s\n", - t->ctx_name, file, line, cond); + convey_logf(t->ctx_dbglog, "* %s (%s:%d) (Skip): %s\n", t->ctx_name, + file, line, cond); } - /* * Performance counters. Really we just want to start and stop timers, to * measure elapsed time in usec. @@ -498,10 +489,9 @@ conveyAssertSkip(const char *cond, const char *file, int line) static void convey_init_timer(struct convey_timer *pc) { - memset(pc, 0, sizeof (*pc)); + memset(pc, 0, sizeof(*pc)); } - static void convey_start_timer(struct convey_timer *pc) { @@ -515,7 +505,7 @@ convey_start_timer(struct convey_timer *pc) pc->timer_base = pcnt.QuadPart; pc->timer_rate = pfreq.QuadPart; #elif defined(CLOCK_MONOTONIC) && !defined(CONVEY_USE_GETTIMEOFDAY) - uint64_t usecs; + uint64_t usecs; struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); @@ -533,7 +523,6 @@ convey_start_timer(struct convey_timer *pc) pc->timer_running = 1; } - static void convey_stop_timer(struct convey_timer *pc) { @@ -546,7 +535,7 @@ convey_stop_timer(struct convey_timer *pc) QueryPerformanceCounter(&pcnt); pc->timer_count += (pcnt.QuadPart - pc->timer_base); #elif defined(CLOCK_MONOTONIC) && !defined(CONVEY_USE_GETTIMEOFDAY) - uint64_t ns; + uint64_t ns; struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); @@ -554,7 +543,7 @@ convey_stop_timer(struct convey_timer *pc) ns += ts.tv_nsec; pc->timer_count += (ns - pc->timer_base); #else - uint64_t us; + uint64_t us; struct timeval tv; gettimeofday(&tv, NULL); @@ -565,14 +554,13 @@ convey_stop_timer(struct convey_timer *pc) } while (0); } - static void convey_read_timer(struct convey_timer *pc, int *secp, int *usecp) { uint64_t delta, rate, sec, usec; delta = pc->timer_count; - rate = pc->timer_rate; + rate = pc->timer_rate; sec = delta / rate; delta -= (sec * rate); @@ -591,10 +579,10 @@ convey_read_timer(struct convey_timer *pc, int *secp, int *usecp) } } - /* * Thread-specific data. Pthreads uses one way, Win32 another. If you - * lack threads, just #define CONVEY_NO_THREADS. C11 thread support is pending. + * lack threads, just #define CONVEY_NO_THREADS. C11 thread support is + * pending. */ #ifdef CONVEY_NO_THREADS @@ -606,7 +594,6 @@ convey_tls_init(void) return (0); } - static int convey_tls_set(void *v) { @@ -614,14 +601,12 @@ convey_tls_set(void *v) return (0); } - static void * convey_tls_get(void) { return (convey_tls_key); } - #elif defined(_WIN32) static DWORD convey_tls_key; @@ -635,7 +620,6 @@ convey_tls_init(void) return (0); } - static int convey_tls_set(void *v) { @@ -645,14 +629,12 @@ convey_tls_set(void *v) return (0); } - static void * convey_tls_get(void) { return ((void *) TlsGetValue(convey_tls_key)); } - #else pthread_key_t convey_tls_key; @@ -666,7 +648,6 @@ convey_tls_init(void) return (0); } - static int convey_tls_set(void *v) { @@ -676,14 +657,12 @@ convey_tls_set(void *v) return (0); } - static void * convey_tls_get(void) { return (pthread_getspecific(convey_tls_key)); } - #endif static struct convey_ctx * @@ -692,7 +671,6 @@ convey_get_ctx(void) return (convey_tls_get()); } - /* * Log stuff. */ @@ -702,14 +680,14 @@ convey_vlogf(struct convey_log *log, const char *fmt, va_list va, int addnl) /* Grow the log buffer if we need to */ while ((log->log_size - log->log_length) < 256) { size_t newsz = log->log_size + 2000; - char *ptr = malloc(newsz); + char * ptr = malloc(newsz); if (ptr == NULL) { return; } memcpy(ptr, log->log_buf, log->log_length); memset(ptr + log->log_length, 0, newsz - log->log_length); free(log->log_buf); - log->log_buf = ptr; + log->log_buf = ptr; log->log_size = newsz; } @@ -717,12 +695,11 @@ convey_vlogf(struct convey_log *log, const char *fmt, va_list va, int addnl) (void) vsnprintf(log->log_buf + log->log_length, log->log_size - (log->log_length + 2), fmt, va); log->log_length += strlen(log->log_buf + log->log_length); - if (addnl && (log->log_buf[log->log_length-1] != '\n')) { + if (addnl && (log->log_buf[log->log_length - 1] != '\n')) { log->log_buf[log->log_length++] = '\n'; } } - static void convey_logf(struct convey_log *log, const char *fmt, ...) { @@ -733,7 +710,6 @@ convey_logf(struct convey_log *log, const char *fmt, ...) va_end(va); } - static void convey_log_emit(struct convey_log *log, const char *header, const char *color) { @@ -758,7 +734,6 @@ convey_log_emit(struct convey_log *log, const char *header, const char *color) } } - static void convey_log_free(struct convey_log *log) { @@ -770,14 +745,12 @@ convey_log_free(struct convey_log *log) } } - static struct convey_log * convey_log_alloc(void) { - return (calloc(1, sizeof (struct convey_log))); + return (calloc(1, sizeof(struct convey_log))); } - /* * ConveyInit initializes some common global stuff. Call it from main(), * if you don't use the framework provided main. @@ -797,21 +770,19 @@ ConveyInit(void) return (0); } - void ConveySetVerbose(void) { convey_verbose = 1; } - void conveyFail(const char *file, int line, const char *fmt, ...) { - struct convey_ctx *t = convey_get_ctx(); + struct convey_ctx *t = convey_get_ctx(); struct convey_log *flog = t->ctx_faillog; struct convey_log *dlog = t->ctx_dbglog; - va_list ap; + va_list ap; convey_logf(dlog, "* %s (%s:%d) (Failed): ", t->ctx_name, file, line); va_start(ap, fmt); @@ -831,18 +802,17 @@ conveyFail(const char *file, int line, const char *fmt, ...) } convey_assert_color = convey_yellow; t->ctx_fail++; - t->ctx_done = 1; /* This forces an end */ + t->ctx_done = 1; /* This forces an end */ longjmp(*t->ctx_jmp, 1); } - void conveyError(const char *file, int line, const char *fmt, ...) { - struct convey_ctx *t = convey_get_ctx(); + struct convey_ctx *t = convey_get_ctx(); struct convey_log *flog = t->ctx_errlog; struct convey_log *dlog = t->ctx_dbglog; - va_list ap; + va_list ap; convey_logf(dlog, "* %s (%s:%d) (Error): ", t->ctx_name, file, line); va_start(ap, fmt); @@ -862,16 +832,15 @@ conveyError(const char *file, int line, const char *fmt, ...) } convey_assert_color = convey_red; t->ctx_fail++; - t->ctx_done = 1; /* This forces an end */ + t->ctx_done = 1; /* This forces an end */ longjmp(*t->ctx_jmp, 1); } - void conveyPrintf(const char *file, int line, const char *fmt, ...) { - va_list ap; - struct convey_ctx *t = convey_get_ctx(); + va_list ap; + struct convey_ctx *t = convey_get_ctx(); struct convey_log *dlog = t->ctx_dbglog; convey_logf(dlog, "* %s (%s:%d) (Debug): ", t->ctx_name, file, line); @@ -880,7 +849,6 @@ conveyPrintf(const char *file, int line, const char *fmt, ...) va_end(ap); } - extern int conveyMainImpl(void); static void @@ -895,10 +863,10 @@ convey_init_term(void) (void) setlocale(LC_ALL, ""); codeset = nl_langinfo(CODESET); if ((codeset != NULL) && (strcmp(codeset, "UTF-8") == 0)) { - convey_sym_pass = "✔"; - convey_sym_fail = "✘"; + convey_sym_pass = "✔"; + convey_sym_fail = "✘"; convey_sym_fatal = "🔥"; - convey_sym_skip = "⚠"; + convey_sym_skip = "⚠"; } term = getenv("TERM"); if (!isatty(fileno(stdin))) { @@ -916,28 +884,26 @@ convey_init_term(void) // Values probably don't matter, just need to be // different! convey_nocolor = "\033[0m"; - convey_green = "\033[32m"; - convey_yellow = "\033[33m"; - convey_red = "\033[31m"; + convey_green = "\033[32m"; + convey_yellow = "\033[33m"; + convey_red = "\033[31m"; } term = getenv("TERM"); #endif - if (term != NULL) { if ((strstr(term, "xterm") != NULL) || (strstr(term, "ansi") != NULL) || (strstr(term, "color") != NULL)) { convey_nocolor = "\033[0m"; - convey_green = "\033[32m"; - convey_yellow = "\033[33m"; - convey_red = "\033[31m"; + convey_green = "\033[32m"; + convey_yellow = "\033[33m"; + convey_red = "\033[31m"; } } convey_assert_color = convey_green; } - /* * This function exists because strtok isn't safe, and strtok_r and * strsep are not universally available. Its like strsep, but only does @@ -949,14 +915,14 @@ convey_nextline(char **next) { char *line = *next; char *nl; - char c; + char c; if (line == NULL) { return (NULL); } for (nl = line; (c = (*nl)) != '\0'; nl++) { if (c == '\n') { - *nl = '\0'; + *nl = '\0'; *next = nl + 1; return (line); } @@ -975,9 +941,9 @@ convey_nextline(char **next) static struct convey_env { struct convey_env *next; - const char *name; - char *value; -} *convey_environment; + const char * name; + char * value; +} * convey_environment; static struct convey_env * conveyFindEnv(const char *name) @@ -1008,14 +974,14 @@ conveyPutEnv(const char *name, char *value) struct convey_env *env; if ((env = conveyFindEnv(name)) == NULL) { - env = malloc(sizeof (*env)); + env = malloc(sizeof(*env)); if (env == NULL) { return (-1); } - env->next = convey_environment; + env->next = convey_environment; convey_environment = env; } - env->name = name; + env->name = name; env->value = value; return (0); } @@ -1023,17 +989,15 @@ conveyPutEnv(const char *name, char *value) int conveyMain(int argc, char **argv) { - int i; - const char *status; - const char *prog; + int i; + const char * status; + const char * prog = ""; struct convey_timer pc; - int secs, usecs; - struct convey_env *env; + int secs, usecs; + struct convey_env * env; if ((argc > 0) && (argv[0] != NULL)) { prog = argv[0]; - } else { - prog = ""; } /* @@ -1054,11 +1018,11 @@ conveyMain(int argc, char **argv) } if ((strcmp(argv[i], "-p") == 0) && ((i + 1) < argc)) { char *delim; - if ((delim = strchr(argv[i+1], '=')) != NULL) { + if ((delim = strchr(argv[i + 1], '=')) != NULL) { *delim = '\0'; - conveyPutEnv(argv[i+1], delim+1); + conveyPutEnv(argv[i + 1], delim + 1); } else { - conveyPutEnv(argv[i+1], ""); + conveyPutEnv(argv[i + 1], ""); } i++; continue; @@ -1099,7 +1063,8 @@ conveyMain(int argc, char **argv) } convey_read_timer(&pc, &secs, &usecs); - (void) printf("%-8s%-52s%4d.%03ds\n", status, prog, secs, usecs / 1000); + (void) printf( + "%-8s%-52s%4d.%03ds\n", status, prog, secs, usecs / 1000); while ((env = convey_environment) != NULL) { convey_environment = env->next; free(env); diff --git a/tests/convey.h b/tests/convey.h index d367cfcc..59445059 100644 --- a/tests/convey.h +++ b/tests/convey.h @@ -1,5 +1,5 @@ /* - * Copyright 2016 Garrett D'Amore + * Copyright 2017 Garrett D'Amore * * This software is supplied under the terms of the MIT License, a * copy of which should be located in the distribution where this @@ -9,13 +9,13 @@ #ifndef CONVEY_H -#define CONVEY_H +#define CONVEY_H -#include -#include -#include #include #include +#include +#include +#include /* * This test framework allows one to write tests as a form of assertion, @@ -72,16 +72,16 @@ */ typedef struct { jmp_buf cs_jmp; - void *cs_data; + void * cs_data; } conveyScope; /* These functions are not for use by tests -- they are used internally. */ -extern int conveyStart(conveyScope *, const char *); -extern int conveyLoop(conveyScope *, int); -extern void conveyFinish(conveyScope *, int *); -extern int conveyMain(int, char **); +extern int conveyStart(conveyScope *, const char *); +extern int conveyLoop(conveyScope *, int); +extern void conveyFinish(conveyScope *, int *); +extern int conveyMain(int, char **); extern char *conveyGetEnv(const char *); -extern int conveyPutEnv(const char *, char *); +extern int conveyPutEnv(const char *, char *); extern void conveyAssertPass(const char *, const char *, int); extern void conveyAssertSkip(const char *, const char *, int); @@ -97,29 +97,29 @@ extern void conveyPrintf(const char *, int, const char *, ...); * and for the code block to be inlined. Becuase this inlines user * code, we have to be *very* careful with symbol names. */ -#define conveyRun(convey_name, convey_code, convey_resultp) \ - do { \ - static conveyScope convey_scope; \ - int convey_unwind; \ - int convey_break = 0; \ - if (conveyStart(&convey_scope, convey_name) != 0) { \ - break; \ - } \ - convey_unwind = setjmp(convey_scope.cs_jmp); \ - if (conveyLoop(&convey_scope, convey_unwind) != 0) { \ - break; \ - } \ - do { \ - convey_code \ - } while (0); \ - if (convey_break) { \ - break; \ - } \ - conveyFinish(&convey_scope, convey_resultp); \ +#define conveyRun(convey_name, convey_code, convey_resultp) \ + do { \ + static conveyScope convey_scope; \ + int convey_unwind; \ + int convey_break = 0; \ + if (conveyStart(&convey_scope, convey_name) != 0) { \ + break; \ + } \ + convey_unwind = setjmp(convey_scope.cs_jmp); \ + if (conveyLoop(&convey_scope, convey_unwind) != 0) { \ + break; \ + } \ + do { \ + convey_code \ + } while (0); \ + if (convey_break) { \ + break; \ + } \ + conveyFinish(&convey_scope, convey_resultp); \ } while (0); /* - * ConveyRset establishes a reset for the current scope. This code will + * ConveyReset establishes a reset for the current scope. This code will * be executed every time the current scope is unwinding. This means that * the code will be executed each time a child convey exits. It is also * going to be executed once more, for the final pass, which doesn't actually @@ -139,16 +139,16 @@ extern void conveyPrintf(const char *, int, const char *, ...); * override a prior reset. Normally you should avoid this, and just * use lower level convey blocks. */ -#define ConveyReset(convey_reset_code) \ - convey_unwind = setjmp(convey_scope.cs_jmp); \ - if (convey_unwind) { \ - do { \ - convey_reset_code \ - } while (0); \ - } \ - if (conveyLoop(&convey_scope, convey_unwind) != 0) { \ - convey_break = 1; \ - break; \ +#define ConveyReset(convey_reset_code) \ + convey_unwind = setjmp(convey_scope.cs_jmp); \ + if (convey_unwind) { \ + do { \ + convey_reset_code \ + } while (0); \ + } \ + if (conveyLoop(&convey_scope, convey_unwind) != 0) { \ + convey_break = 1; \ + break; \ } /* @@ -157,17 +157,16 @@ extern void conveyPrintf(const char *, int, const char *, ...); * sets up the program, parses options, and then executes the tests nested * within it. */ -#define ConveyMain(code) \ - static int convey_main_rv; \ - int conveyMainImpl(void) { \ - do { \ - code \ - } while (0); \ - return (convey_main_rv); \ - } \ - int main(int argc, char **argv) { \ - return (conveyMain(argc, argv)); \ - } +#define ConveyMain(code) \ + static int convey_main_rv; \ + int conveyMainImpl(void) \ + { \ + do { \ + code \ + } while (0); \ + return (convey_main_rv); \ + } \ + int main(int argc, char **argv) { return (conveyMain(argc, argv)); } /* * ConveyGetEnv is used to get environment variables, which can be @@ -177,20 +176,20 @@ extern void conveyPrintf(const char *, int, const char *, ...); /* * ConveyPutEnv is used to change environment variables. This is not - * thread safe! + * thread safe! */ #define ConveyPutEnv(name, value) conveyPutEnv(name, value) /* * ConveyTest creates a top-level test instance, which can contain multiple * Convey blocks. */ -#define ConveyTest(name, code) \ - do { \ - int convey_rv; \ - conveyRun(name, code, &convey_rv); \ - if (convey_rv > convey_main_rv) { \ - convey_main_rv = convey_rv; \ - }; \ +#define ConveyTest(name, code) \ + do { \ + int convey_rv; \ + conveyRun(name, code, &convey_rv); \ + if (convey_rv > convey_main_rv) { \ + convey_main_rv = convey_rv; \ + }; \ } while (0); /* @@ -200,8 +199,7 @@ extern void conveyPrintf(const char *, int, const char *, ...); * is the same as using Main with just a single Test embedded, but saves * some typing and probably a level of indentation. */ -#define ConveyTestMain(name, code) \ - ConveyMain(ConveyTest(name, code)) +#define ConveyTestMain(name, code) ConveyMain(ConveyTest(name, code)) /* * EXPERIMENTAL: @@ -220,28 +218,28 @@ extern void conveyPrintf(const char *, int, const char *, ...); * Block takes the place of both Main() and Test(). It is to be hoped * that you will not need this. */ -#define ConveyBlock(name, code, resultp) conveyRun(name, code, resultp) +#define ConveyBlock(name, code, resultp) conveyRun(name, code, resultp) /* * ConveyAssert and ConveySo allow you to run assertions. */ -#define ConveyAssert(truth) \ - do { \ - if (!(truth)) { \ - conveyAssertFail(#truth, __FILE__, __LINE__); \ - } else { \ - conveyAssertPass(#truth, __FILE__, __LINE__); \ - } \ +#define ConveyAssert(truth) \ + do { \ + if (!(truth)) { \ + conveyAssertFail(#truth, __FILE__, __LINE__); \ + } else { \ + conveyAssertPass(#truth, __FILE__, __LINE__); \ + } \ } while (0) -#define ConveySo(truth) ConveyAssert(truth) +#define ConveySo(truth) ConveyAssert(truth) /* * Convey(name, ) starts a convey context, with as * the body. The is its scope, and may be called repeatedly * within the body of a loop. */ -#define Convey(name, code) conveyRun(name, code, NULL) +#define Convey(name, code) conveyRun(name, code, NULL) /* * ConveySkip() just stops processing of the rest of the current context, @@ -254,33 +252,31 @@ extern void conveyPrintf(const char *, int, const char *, ...); * format specifiers. */ #ifdef CONVEY_NO_VARIADICS -#define ConveySkip(reason) conveySkip(__FILE__, __LINE__, reason) -#define ConveyFail(reason) conveyFail(__FILE__, __LINE__, reason) -#define ConveyError(reason) conveyError(__FILE__, __LINE__, reason) -#define ConveyPrintf(reason) conveyPrintf(__FILE__, __LINE__, reason) +#define ConveySkip(reason) conveySkip(__FILE__, __LINE__, reason) +#define ConveyFail(reason) conveyFail(__FILE__, __LINE__, reason) +#define ConveyError(reason) conveyError(__FILE__, __LINE__, reason) +#define ConveyPrintf(reason) conveyPrintf(__FILE__, __LINE__, reason) #else -#define ConveySkip(...) conveySkip(__FILE__, __LINE__, __VA_ARGS__) -#define ConveyFail(...) conveyFail(__FILE__, __LINE__, __VA_ARGS__) -#define ConveyError(...) conveyError(__FILE__, __LINE__, __VA_ARGS__) -#define ConveyPrintf(...) conveyPrintf(__FILE__, __LINE__, __VA_ARGS__) +#define ConveySkip(...) conveySkip(__FILE__, __LINE__, __VA_ARGS__) +#define ConveyFail(...) conveyFail(__FILE__, __LINE__, __VA_ARGS__) +#define ConveyError(...) conveyError(__FILE__, __LINE__, __VA_ARGS__) +#define ConveyPrintf(...) conveyPrintf(__FILE__, __LINE__, __VA_ARGS__) #endif /* * ConveySkipSo() is used to skip processing of a single assertion. * Further processing in the same context continues. */ -#define ConveySkipAssert(truth) \ - conveyAssertSkip(truth, __FILE__, __LINE__) -#define ConveySkipSo(truth) ConveySkipAssert(truth) +#define ConveySkipAssert(truth) conveyAssertSkip(#truth, __FILE__, __LINE__) +#define ConveySkipSo(truth) ConveySkipAssert(truth) /* * ConveySkipConvey() is used to skip a convey context. This is intended * to permit changing "Convey", to "SkipConvey". This is logged, * and the current convey context continues processing. */ -#define ConveySkipConvey(name, code) \ - Convey(name, ConveySkip("Skipped")) - +#define ConveySkipConvey(name, code) \ + conveyRun(name, ConveySkip("Skipped");, NULL) /* * ConveyInit sets up initial things required for testing. If you don't @@ -313,18 +309,18 @@ extern void ConveySetVerbose(void); */ #ifndef CONVEY_NAMESPACE_CLEAN -#define TestMain ConveyTestMain -#define Test ConveyTest -#define Main ConveyMain -#define So ConveySo -#define Skip ConveySkip -#define Fail ConveyFail -#define Error ConveyError -#define SkipConvey ConveySkipConvey -#define SkipSo ConveySkipSo -#define Reset ConveyReset -#define Printf ConveyPrintf +#define TestMain ConveyTestMain +#define Test ConveyTest +#define Main ConveyMain +#define So ConveySo +#define Skip ConveySkip +#define Fail ConveyFail +#define Error ConveyError +#define SkipConvey ConveySkipConvey +#define SkipSo ConveySkipSo +#define Reset ConveyReset +#define Printf ConveyPrintf -#endif /* CONVEY_NAMESPACE_CLEAN */ +#endif /* CONVEY_NAMESPACE_CLEAN */ -#endif /* CONVEY_H */ +#endif /* CONVEY_H */ diff --git a/tests/convey_test.c b/tests/convey_test.c new file mode 100644 index 00000000..0970e664 --- /dev/null +++ b/tests/convey_test.c @@ -0,0 +1,145 @@ +/* + * Copyright 2017 Garrett D'Amore + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +/* + * This file is intended to test the framework. It also demonstrates + * some of the capabilities. + */ + +#include "convey.h" + +#include +#include + +Main({ + + /* + * The ordering test demonstrates the execution order. + * At the end of each inner Convey, we roll back up the stack + * to the root, and then start over, bypassing Convey blocks + * that have already completed. Note that if a Convey block + * is the last thing in an enclosing Convey, we will make + * one more pass all the way through until we bypass that last + * item and can close the outer Convey. + */ + Test("Ordering", { + /* + * The buffer has to be static because don't want to clear + * it with each new pass -- that would defeat our tests! + * Note that it starts zeroed (C standard). + */ + static char buffer[32]; + static int bufidx; + + Convey("A runs first", { buffer[bufidx++] = 'A'; }); + Printf("Bufidx is now %d", 1); + buffer[bufidx++] = '1'; + + Convey("B runs after A", { + + So(strlen(buffer) > 0); + So(buffer[bufidx - 1] == '1'); + buffer[bufidx++] = 'B'; + + Convey("C runs inside B", { + So(buffer[bufidx - 1] == 'B'); + buffer[bufidx++] = 'C'; + }); + }); + + Convey("D runs afer A, B, C.", { + So(buffer[bufidx - 1] == '1'); + buffer[bufidx++] = 'D'; + }); + + buffer[bufidx++] = '2'; + + Convey("E is last", { + So(buffer[bufidx - 1] == '2'); + buffer[bufidx++] = 'E'; + }); + + So(strcmp(buffer, "A1BC1B1D12E12") == 0); + }); + + Test("Skipping works", { + int skipped = 0; + SkipConvey("ConveySkip works.", { So(skipped = 0); }); + Convey("Assertion skipping works.", { SkipSo(skipped == 1); }); + }); + + Test("Reset", { + static int x; + + Convey("Initialize X to a non-zero value", { + So(x == 0); + x = 1; + So(x == 1); + }); + + Reset({ x = 20; }); + + Convey("Verify that reset did not get called", { + So(x == 1); + x = 5; + So(x == 5); + }); + + Convey("But now it did", { So(x == 20); }); + }); + + /* save the current status so we can override */ + int oldrv = convey_main_rv; + Test("Failures work", { + Convey("Assertion failure works", + { Convey("Injected failure", { So(1 == 0); }); }); + + Convey("ConveyFail works", { ConveyFail("forced failure"); }); + + Convey("ConveyError works", { ConveyError("forced error"); }); + }); + + /* Override the result variable to reset failure. */ + convey_main_rv = oldrv; + + Test("Environment works", { + Convey("PATH environment", { + So(ConveyGetEnv("PATH") != NULL); + So(strlen(ConveyGetEnv("PATH")) != 0); + }); + Convey("Command line args work", { + char *v1 = ConveyGetEnv("ANOTHERNAME"); + char *v2 = ConveyGetEnv("AGAIN"); + if (ConveyGetEnv("NAMETEST") == NULL) { + SkipSo(v1 != NULL); + SkipSo(v2 != NULL); + SkipSo(strcmp(v1, "") == 0); + SkipSo(strcmp(v2, "YES") == 0); + } else { + So(v1 != NULL); + So(v2 != NULL); + So(strcmp(v1, "") == 0); + So(strcmp(v2, "YES") == 0); + } + }) + }); +}) -- cgit v1.2.3-70-g09d2