btcs

bitcoin script parser/evaluator/compiler/decompiler
git clone git://jb55.com/btcs
Log | Files | Refs | README | LICENSE

tap.c (7837B)


      1 /*
      2 libtap - Write tests in C
      3 Copyright 2012 Jake Gelbman <gelbman@gmail.com>
      4 This file is licensed under the GPLv2
      5 */
      6 
      7 #define _DEFAULT_SOURCE 1
      8 
      9 #include <stdio.h>
     10 #include <stdlib.h>
     11 #include <stdarg.h>
     12 #include <string.h>
     13 #include "tap.h"
     14 
     15 static int expected_tests = NO_PLAN;
     16 static int failed_tests;
     17 static int current_test;
     18 static char *todo_mesg;
     19 
     20 static char *
     21 vstrdupf (const char *fmt, va_list args) {
     22     char *str;
     23     int size;
     24     va_list args2;
     25     va_copy(args2, args);
     26     if (!fmt)
     27         fmt = "";
     28     size = vsnprintf(NULL, 0, fmt, args2) + 2;
     29     str = malloc(size);
     30     if (!str) {
     31         perror("malloc error");
     32         exit(1);
     33     }
     34     vsprintf(str, fmt, args);
     35     va_end(args2);
     36     return str;
     37 }
     38 
     39 void
     40 tap_plan (int tests, const char *fmt, ...) {
     41     expected_tests = tests;
     42     if (tests == SKIP_ALL) {
     43         char *why;
     44         va_list args;
     45         va_start(args, fmt);
     46         why = vstrdupf(fmt, args);
     47         va_end(args);
     48         printf("1..0 ");
     49         note("SKIP %s\n", why);
     50         exit(0);
     51     }
     52     if (tests != NO_PLAN) {
     53         printf("1..%d\n", tests);
     54     }
     55 }
     56 
     57 int
     58 vok_at_loc (const char *file, int line, int test, const char *fmt,
     59             va_list args)
     60 {
     61     char *name = vstrdupf(fmt, args);
     62     printf("%sok %d", test ? "" : "not ", ++current_test);
     63     if (*name)
     64         printf(" - %s", name);
     65     if (todo_mesg) {
     66         printf(" # TODO");
     67         if (*todo_mesg)
     68             printf(" %s", todo_mesg);
     69     }
     70     printf("\n");
     71     if (!test) {
     72         if (*name)
     73             diag("  Failed%s test '%s'\n  at %s line %d.",
     74                 todo_mesg ? " (TODO)" : "", name, file, line);
     75         else
     76             diag("  Failed%s test at %s line %d.",
     77                 todo_mesg ? " (TODO)" : "", file, line);
     78         if (!todo_mesg)
     79             failed_tests++;
     80     }
     81     free(name);
     82     return test;
     83 }
     84 
     85 int
     86 ok_at_loc (const char *file, int line, int test, const char *fmt, ...) {
     87     va_list args;
     88     va_start(args, fmt);
     89     vok_at_loc(file, line, test, fmt, args);
     90     va_end(args);
     91     return test;
     92 }
     93 
     94 static int
     95 mystrcmp (const char *a, const char *b) {
     96     return a == b ? 0 : !a ? -1 : !b ? 1 : strcmp(a, b);
     97 }
     98 
     99 #define eq(a, b) (!mystrcmp(a, b))
    100 #define ne(a, b) (mystrcmp(a, b))
    101 
    102 int
    103 is_at_loc (const char *file, int line, const char *got, const char *expected,
    104            const char *fmt, ...)
    105 {
    106     int test = eq(got, expected);
    107     va_list args;
    108     va_start(args, fmt);
    109     vok_at_loc(file, line, test, fmt, args);
    110     va_end(args);
    111     if (!test) {
    112         diag("         got: '%s'", got);
    113         diag("    expected: '%s'", expected);
    114     }
    115     return test;
    116 }
    117 
    118 int
    119 isnt_at_loc (const char *file, int line, const char *got, const char *expected,
    120              const char *fmt, ...)
    121 {
    122     int test = ne(got, expected);
    123     va_list args;
    124     va_start(args, fmt);
    125     vok_at_loc(file, line, test, fmt, args);
    126     va_end(args);
    127     if (!test) {
    128         diag("         got: '%s'", got);
    129         diag("    expected: anything else");
    130     }
    131     return test;
    132 }
    133 
    134 int
    135 cmp_ok_at_loc (const char *file, int line, int a, const char *op, int b,
    136                const char *fmt, ...)
    137 {
    138     int test = eq(op, "||") ? a || b
    139              : eq(op, "&&") ? a && b
    140              : eq(op, "|")  ? a |  b
    141              : eq(op, "^")  ? a ^  b
    142              : eq(op, "&")  ? a &  b
    143              : eq(op, "==") ? a == b
    144              : eq(op, "!=") ? a != b
    145              : eq(op, "<")  ? a <  b
    146              : eq(op, ">")  ? a >  b
    147              : eq(op, "<=") ? a <= b
    148              : eq(op, ">=") ? a >= b
    149              : eq(op, "<<") ? a << b
    150              : eq(op, ">>") ? a >> b
    151              : eq(op, "+")  ? a +  b
    152              : eq(op, "-")  ? a -  b
    153              : eq(op, "*")  ? a *  b
    154              : eq(op, "/")  ? a /  b
    155              : eq(op, "%")  ? a %  b
    156              : diag("unrecognized operator '%s'", op);
    157     va_list args;
    158     va_start(args, fmt);
    159     vok_at_loc(file, line, test, fmt, args);
    160     va_end(args);
    161     if (!test) {
    162         diag("    %d", a);
    163         diag("        %s", op);
    164         diag("    %d", b);
    165     }
    166     return test;
    167 }
    168 
    169 static void
    170 vdiag_to_fh (FILE *fh, const char *fmt, va_list args) {
    171     char *mesg, *line;
    172     int i;
    173     if (!fmt)
    174         return;
    175     mesg = vstrdupf(fmt, args);
    176     line = mesg;
    177     for (i = 0; *line; i++) {
    178         char c = mesg[i];
    179         if (!c || c == '\n') {
    180             mesg[i] = '\0';
    181             fprintf(fh, "# %s\n", line);
    182             if (!c)
    183                 break;
    184             mesg[i] = c;
    185             line = mesg + i + 1;
    186         }
    187     }
    188     free(mesg);
    189     return;
    190 }
    191 
    192 int
    193 diag (const char *fmt, ...) {
    194     va_list args;
    195     va_start(args, fmt);
    196     vdiag_to_fh(stderr, fmt, args);
    197     va_end(args);
    198     return 0;
    199 }
    200 
    201 int
    202 note (const char *fmt, ...) {
    203     va_list args;
    204     va_start(args, fmt);
    205     vdiag_to_fh(stdout, fmt, args);
    206     va_end(args);
    207     return 0;
    208 }
    209 
    210 int
    211 exit_status () {
    212     int retval = 0;
    213     if (expected_tests == NO_PLAN) {
    214         printf("1..%d\n", current_test);
    215     }
    216     else if (current_test != expected_tests) {
    217         diag("Looks like you planned %d test%s but ran %d.",
    218             expected_tests, expected_tests > 1 ? "s" : "", current_test);
    219         retval = 255;
    220     }
    221     if (failed_tests) {
    222         diag("Looks like you failed %d test%s of %d run.",
    223             failed_tests, failed_tests > 1 ? "s" : "", current_test);
    224         if (expected_tests == NO_PLAN)
    225             retval = failed_tests;
    226         else
    227             retval = expected_tests - current_test + failed_tests;
    228     }
    229     return retval;
    230 }
    231 
    232 int bail_out (const char *fmt, ...) {
    233     va_list args;
    234     va_start(args, fmt);
    235     printf("Bail out!  ");
    236     vprintf(fmt, args);
    237     printf("\n");
    238     va_end(args);
    239     exit(255);
    240     return 0;
    241 }
    242 
    243 void tap_skip (int n, const char *fmt, ...) {
    244     char *why;
    245     va_list args;
    246     va_start(args, fmt);
    247     why = vstrdupf(fmt, args);
    248     va_end(args);
    249     while (n --> 0) {
    250         printf("ok %d ", ++current_test);
    251         note("skip %s\n", why);
    252     }
    253     free(why);
    254 }
    255 
    256 void tap_todo (const char *fmt, ...) {
    257     va_list args;
    258     va_start(args, fmt);
    259     todo_mesg = vstrdupf(fmt, args);
    260     va_end(args);
    261 }
    262 
    263 void
    264 tap_end_todo () {
    265     free(todo_mesg);
    266     todo_mesg = NULL;
    267 }
    268 
    269 #ifndef _WIN32
    270 #include <sys/mman.h>
    271 #include <sys/param.h>
    272 #include <regex.h>
    273 
    274 #if defined __APPLE__ || defined BSD
    275 #define MAP_ANONYMOUS MAP_ANON
    276 #endif
    277 
    278 /* Create a shared memory int to keep track of whether a piece of code executed
    279 dies. to be used in the dies_ok and lives_ok macros.  */
    280 int
    281 tap_test_died (int status) {
    282     static int *test_died = NULL;
    283     int prev;
    284     if (!test_died) {
    285         test_died = mmap(0, sizeof (int), PROT_READ | PROT_WRITE,
    286                          MAP_SHARED | MAP_ANONYMOUS, -1, 0);
    287         *test_died = 0;
    288     }
    289     prev = *test_died;
    290     *test_died = status;
    291     return prev;
    292 }
    293 
    294 int
    295 like_at_loc (int for_match, const char *file, int line, const char *got,
    296              const char *expected, const char *fmt, ...)
    297 {
    298     int test;
    299     regex_t re;
    300     va_list args;
    301     int err = regcomp(&re, expected, REG_EXTENDED);
    302     if (err) {
    303         char errbuf[256];
    304         regerror(err, &re, errbuf, sizeof errbuf);
    305         fprintf(stderr, "Unable to compile regex '%s': %s at %s line %d\n",
    306                         expected, errbuf, file, line);
    307         exit(255);
    308     }
    309     err = regexec(&re, got, 0, NULL, 0);
    310     regfree(&re);
    311     test = for_match ? !err : err;
    312     va_start(args, fmt);
    313     vok_at_loc(file, line, test, fmt, args);
    314     va_end(args);
    315     if (!test) {
    316         if (for_match) {
    317             diag("                   '%s'", got);
    318             diag("    doesn't match: '%s'", expected);
    319         }
    320         else {
    321             diag("                   '%s'", got);
    322             diag("          matches: '%s'", expected);
    323         }
    324     }
    325     return test;
    326 }
    327 #endif
    328