123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354 |
- /*
- libtap - Write tests in C
- Copyright 2012 Jake Gelbman <gelbman@gmail.com>
- This file is licensed under the LGPL
- */
- #define _DEFAULT_SOURCE 1
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdarg.h>
- #include <string.h>
- #include "tap.h"
- static int expected_tests = NO_PLAN;
- static int failed_tests;
- static int current_test;
- static char *todo_mesg;
- static char *
- vstrdupf (const char *fmt, va_list args) {
- char *str;
- int size;
- va_list args2;
- va_copy(args2, args);
- if (!fmt)
- fmt = "";
- size = vsnprintf(NULL, 0, fmt, args2) + 2;
- str = malloc(size);
- if (!str) {
- perror("malloc error");
- exit(1);
- }
- vsprintf(str, fmt, args);
- va_end(args2);
- return str;
- }
- void
- tap_plan (int tests, const char *fmt, ...) {
- expected_tests = tests;
- if (tests == SKIP_ALL) {
- char *why;
- va_list args;
- va_start(args, fmt);
- why = vstrdupf(fmt, args);
- va_end(args);
- printf("1..0 ");
- diag("SKIP %s\n", why);
- exit(0);
- }
- if (tests != NO_PLAN) {
- printf("1..%d\n", tests);
- }
- }
- int
- vok_at_loc (const char *file, int line, int test, const char *fmt,
- va_list args)
- {
- char *name = vstrdupf(fmt, args);
- if (!test) {
- printf("not ");
- }
- printf("ok %d", ++current_test);
- if (*name)
- printf(" - %s", name);
- if (todo_mesg) {
- printf(" # TODO");
- if (*todo_mesg)
- printf(" %s", todo_mesg);
- }
- printf("\n");
- if (!test) {
- printf("# Failed ");
- if (todo_mesg)
- printf("(TODO) ");
- printf("test ");
- if (*name)
- printf("'%s'\n# ", name);
- printf("at %s line %d.\n", file, line);
- if (!todo_mesg)
- failed_tests++;
- }
- free(name);
- return test;
- }
- int
- ok_at_loc (const char *file, int line, int test, const char *fmt, ...) {
- va_list args;
- va_start(args, fmt);
- vok_at_loc(file, line, test, fmt, args);
- va_end(args);
- return test;
- }
- static int
- mystrcmp (const char *a, const char *b) {
- return a == b ? 0 : !a ? -1 : !b ? 1 : strcmp(a, b);
- }
- #define eq(a, b) (!mystrcmp(a, b))
- #define ne(a, b) (mystrcmp(a, b))
- int
- is_at_loc (const char *file, int line, const char *got, const char *expected,
- const char *fmt, ...)
- {
- int test = eq(got, expected);
- va_list args;
- va_start(args, fmt);
- vok_at_loc(file, line, test, fmt, args);
- va_end(args);
- if (!test) {
- diag(" got: '%s'", got);
- diag(" expected: '%s'", expected);
- }
- return test;
- }
- int
- isnt_at_loc (const char *file, int line, const char *got, const char *expected,
- const char *fmt, ...)
- {
- int test = ne(got, expected);
- va_list args;
- va_start(args, fmt);
- vok_at_loc(file, line, test, fmt, args);
- va_end(args);
- if (!test) {
- diag(" got: '%s'", got);
- diag(" expected: anything else");
- }
- return test;
- }
- int
- cmp_ok_at_loc (const char *file, int line, int a, const char *op, int b,
- const char *fmt, ...)
- {
- int test = eq(op, "||") ? a || b
- : eq(op, "&&") ? a && b
- : eq(op, "|") ? a | b
- : eq(op, "^") ? a ^ b
- : eq(op, "&") ? a & b
- : eq(op, "==") ? a == b
- : eq(op, "!=") ? a != b
- : eq(op, "<") ? a < b
- : eq(op, ">") ? a > b
- : eq(op, "<=") ? a <= b
- : eq(op, ">=") ? a >= b
- : eq(op, "<<") ? a << b
- : eq(op, ">>") ? a >> b
- : eq(op, "+") ? a + b
- : eq(op, "-") ? a - b
- : eq(op, "*") ? a * b
- : eq(op, "/") ? a / b
- : eq(op, "%") ? a % b
- : diag("unrecognized operator '%s'", op);
- va_list args;
- va_start(args, fmt);
- vok_at_loc(file, line, test, fmt, args);
- va_end(args);
- if (!test) {
- diag(" %d", a);
- diag(" %s", op);
- diag(" %d", b);
- }
- return test;
- }
- static int
- find_mem_diff (const char *a, const char *b, size_t n, size_t *offset) {
- size_t i;
- if (a == b)
- return 0;
- if (!a || !b)
- return 2;
- for (i = 0; i < n; i++) {
- if (a[i] != b[i]) {
- *offset = i;
- return 1;
- }
- }
- return 0;
- }
- int
- cmp_mem_at_loc (const char *file, int line, const void *got,
- const void *expected, size_t n, const char *fmt, ...)
- {
- size_t offset;
- int diff = find_mem_diff(got, expected, n, &offset);
- va_list args;
- va_start(args, fmt);
- vok_at_loc(file, line, !diff, fmt, args);
- va_end(args);
- if (diff == 1) {
- diag(" Difference starts at offset %d", offset);
- diag(" got: 0x%02x", ((unsigned char *)got)[offset]);
- diag(" expected: 0x%02x", ((unsigned char *)expected)[offset]);
- }
- else if (diff == 2) {
- diag(" got: %s", got ? "not NULL" : "NULL");
- diag(" expected: %s", expected ? "not NULL" : "NULL");
- }
- return !diff;
- }
- int
- diag (const char *fmt, ...) {
- va_list args;
- char *mesg, *line;
- int i;
- va_start(args, fmt);
- if (!fmt)
- return 0;
- mesg = vstrdupf(fmt, args);
- line = mesg;
- for (i = 0; *line; i++) {
- char c = mesg[i];
- if (!c || c == '\n') {
- mesg[i] = '\0';
- printf("# %s\n", line);
- if (!c)
- break;
- mesg[i] = c;
- line = mesg + i + 1;
- }
- }
- free(mesg);
- va_end(args);
- return 0;
- }
- int
- exit_status () {
- int retval = 0;
- if (expected_tests == NO_PLAN) {
- printf("1..%d\n", current_test);
- }
- else if (current_test != expected_tests) {
- diag("Looks like you planned %d test%s but ran %d.",
- expected_tests, expected_tests > 1 ? "s" : "", current_test);
- retval = 2;
- }
- if (failed_tests) {
- diag("Looks like you failed %d test%s of %d run.",
- failed_tests, failed_tests > 1 ? "s" : "", current_test);
- retval = 1;
- }
- return retval;
- }
- int
- bail_out (int ignore, const char *fmt, ...) {
- va_list args;
- va_start(args, fmt);
- printf("Bail out! ");
- vprintf(fmt, args);
- printf("\n");
- va_end(args);
- exit(255);
- return 0;
- }
- void
- tap_skip (int n, const char *fmt, ...) {
- char *why;
- va_list args;
- va_start(args, fmt);
- why = vstrdupf(fmt, args);
- va_end(args);
- while (n --> 0) {
- printf("ok %d ", ++current_test);
- diag("skip %s\n", why);
- }
- free(why);
- }
- void
- tap_todo (int ignore, const char *fmt, ...) {
- va_list args;
- va_start(args, fmt);
- todo_mesg = vstrdupf(fmt, args);
- va_end(args);
- }
- void
- tap_end_todo () {
- free(todo_mesg);
- todo_mesg = NULL;
- }
- #ifndef _WIN32
- #include <sys/mman.h>
- #include <sys/param.h>
- #include <regex.h>
- #if defined __APPLE__ || defined BSD
- #define MAP_ANONYMOUS MAP_ANON
- #endif
- /* Create a shared memory int to keep track of whether a piece of code executed
- dies. to be used in the dies_ok and lives_ok macros. */
- int
- tap_test_died (int status) {
- static int *test_died = NULL;
- int prev;
- if (!test_died) {
- test_died = mmap(0, sizeof (int), PROT_READ | PROT_WRITE,
- MAP_SHARED | MAP_ANONYMOUS, -1, 0);
- *test_died = 0;
- }
- prev = *test_died;
- *test_died = status;
- return prev;
- }
- int
- like_at_loc (int for_match, const char *file, int line, const char *got,
- const char *expected, const char *fmt, ...)
- {
- int test;
- regex_t re;
- va_list args;
- int err = regcomp(&re, expected, REG_EXTENDED);
- if (err) {
- char errbuf[256];
- regerror(err, &re, errbuf, sizeof errbuf);
- fprintf(stderr, "Unable to compile regex '%s': %s at %s line %d\n",
- expected, errbuf, file, line);
- exit(255);
- }
- err = regexec(&re, got, 0, NULL, 0);
- regfree(&re);
- test = for_match ? !err : err;
- va_start(args, fmt);
- vok_at_loc(file, line, test, fmt, args);
- va_end(args);
- if (!test) {
- if (for_match) {
- diag(" '%s'", got);
- diag(" doesn't match: '%s'", expected);
- }
- else {
- diag(" '%s'", got);
- diag(" matches: '%s'", expected);
- }
- }
- return test;
- }
- #endif
|