Home | History | Annotate | Download | only in test
      1 /* Copyright 2011,2012 Bas van den Berg
      2  *
      3  * Licensed under the Apache License, Version 2.0 (the "License");
      4  * you may not use this file except in compliance with the License.
      5  * You may obtain a copy of the License at
      6  *
      7  *     http://www.apache.org/licenses/LICENSE-2.0
      8  *
      9  * Unless required by applicable law or agreed to in writing, software
     10  * distributed under the License is distributed on an "AS IS" BASIS,
     11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12  * See the License for the specific language governing permissions and
     13  * limitations under the License.
     14  */
     15 
     16 #ifndef CTEST_H
     17 #define CTEST_H
     18 
     19 #ifndef UNUSED_PARAM
     20   /**
     21    * \def UNUSED_PARAM(p);
     22    *
     23    * A macro for quelling compiler warnings about unused variables.
     24    */
     25 #  define UNUSED_PARAM(p) ((void)&(p))
     26 #endif /* UNUSED_PARM */
     27 
     28 typedef void (*SetupFunc)(void*);
     29 typedef void (*TearDownFunc)(void*);
     30 
     31 struct ctest {
     32     const char* ssname;  // suite name
     33     const char* ttname;  // test name
     34     void (*run)();
     35     int skip;
     36 
     37     void* data;
     38     SetupFunc setup;
     39     TearDownFunc teardown;
     40 
     41     unsigned int magic;
     42 };
     43 
     44 #define __FNAME(sname, tname) __ctest_##sname##_##tname##_run
     45 #define __TNAME(sname, tname) __ctest_##sname##_##tname
     46 
     47 #define __CTEST_MAGIC (0xdeadbeef)
     48 #ifdef __APPLE__
     49 #define __Test_Section __attribute__ ((unused,section ("__DATA, .ctest")))
     50 #else
     51 #define __Test_Section __attribute__ ((unused,section (".ctest")))
     52 #endif
     53 
     54 #define __CTEST_STRUCT(sname, tname, _skip, __data, __setup, __teardown) \
     55     struct ctest __TNAME(sname, tname) __Test_Section = { \
     56         .ssname=#sname, \
     57         .ttname=#tname, \
     58         .run = __FNAME(sname, tname), \
     59         .skip = _skip, \
     60         .data = __data, \
     61         .setup = (SetupFunc)__setup,					\
     62         .teardown = (TearDownFunc)__teardown,				\
     63         .magic = __CTEST_MAGIC };
     64 
     65 #define CTEST_DATA(sname) struct sname##_data
     66 
     67 #define CTEST_SETUP(sname) \
     68     void __attribute__ ((weak)) sname##_setup(struct sname##_data* data)
     69 
     70 #define CTEST_TEARDOWN(sname) \
     71     void __attribute__ ((weak)) sname##_teardown(struct sname##_data* data)
     72 
     73 #define __CTEST_INTERNAL(sname, tname, _skip) \
     74     void __FNAME(sname, tname)(); \
     75     __CTEST_STRUCT(sname, tname, _skip, NULL, NULL, NULL) \
     76     void __FNAME(sname, tname)()
     77 
     78 #ifdef __APPLE__
     79 #define SETUP_FNAME(sname) NULL
     80 #define TEARDOWN_FNAME(sname) NULL
     81 #else
     82 #define SETUP_FNAME(sname) sname##_setup
     83 #define TEARDOWN_FNAME(sname) sname##_teardown
     84 #endif
     85 
     86 #define __CTEST2_INTERNAL(sname, tname, _skip) \
     87     static struct sname##_data  __ctest_##sname##_data; \
     88     CTEST_SETUP(sname); \
     89     CTEST_TEARDOWN(sname); \
     90     void __FNAME(sname, tname)(struct sname##_data* data); \
     91     __CTEST_STRUCT(sname, tname, _skip, &__ctest_##sname##_data, SETUP_FNAME(sname), TEARDOWN_FNAME(sname)) \
     92     void __FNAME(sname, tname)(struct sname##_data* data)
     93 
     94 
     95 void CTEST_LOG(char *fmt, ...);
     96 void CTEST_ERR(char *fmt, ...);  // doesn't return
     97 
     98 #define CTEST(sname, tname) __CTEST_INTERNAL(sname, tname, 0)
     99 #define CTEST_SKIP(sname, tname) __CTEST_INTERNAL(sname, tname, 1)
    100 
    101 #define CTEST2(sname, tname) __CTEST2_INTERNAL(sname, tname, 0)
    102 #define CTEST2_SKIP(sname, tname) __CTEST2_INTERNAL(sname, tname, 1)
    103 
    104 
    105 void assert_str(const char* exp, const char* real, const char* caller, int line);
    106 #define ASSERT_STR(exp, real) assert_str(exp, real, __FILE__, __LINE__)
    107 
    108 void assert_data(const unsigned char* exp, int expsize,
    109                  const unsigned char* real, int realsize,
    110                  const char* caller, int line);
    111 #define ASSERT_DATA(exp, expsize, real, realsize) \
    112     assert_data(exp, expsize, real, realsize, __FILE__, __LINE__)
    113 
    114 void assert_equal(long exp, long real, const char* caller, int line);
    115 #define ASSERT_EQUAL(exp, real) assert_equal(exp, real, __FILE__, __LINE__)
    116 
    117 void assert_not_equal(long exp, long real, const char* caller, int line);
    118 #define ASSERT_NOT_EQUAL(exp, real) assert_not_equal(exp, real, __FILE__, __LINE__)
    119 
    120 void assert_null(void* real, const char* caller, int line);
    121 #define ASSERT_NULL(real) assert_null((void*)real, __FILE__, __LINE__)
    122 
    123 void assert_not_null(const void* real, const char* caller, int line);
    124 #define ASSERT_NOT_NULL(real) assert_not_null(real, __FILE__, __LINE__)
    125 
    126 void assert_true(int real, const char* caller, int line);
    127 #define ASSERT_TRUE(real) assert_true(real, __FILE__, __LINE__)
    128 
    129 void assert_false(int real, const char* caller, int line);
    130 #define ASSERT_FALSE(real) assert_false(real, __FILE__, __LINE__)
    131 
    132 void assert_fail(const char* caller, int line);
    133 #define ASSERT_FAIL() assert_fail(__FILE__, __LINE__)
    134 
    135 #ifdef CTEST_MAIN
    136 
    137 #include <setjmp.h>
    138 #include <stdarg.h>
    139 #include <stdio.h>
    140 #include <string.h>
    141 #include <sys/time.h>
    142 #include <inttypes.h>
    143 #include <unistd.h>
    144 #include <stdint.h>
    145 #include <stdlib.h>
    146 
    147 #ifdef __APPLE__
    148 #include <dlfcn.h>
    149 #endif
    150 
    151 //#define COLOR_OK
    152 
    153 static size_t ctest_errorsize;
    154 static char* ctest_errormsg;
    155 #define MSG_SIZE 4096
    156 static char ctest_errorbuffer[MSG_SIZE];
    157 static jmp_buf ctest_err;
    158 static int color_output = 1;
    159 static const char* suite_name;
    160 
    161 typedef int (*filter_func)(struct ctest*);
    162 
    163 #define ANSI_BLACK    "\033[0;30m"
    164 #define ANSI_RED      "\033[0;31m"
    165 #define ANSI_GREEN    "\033[0;32m"
    166 #define ANSI_YELLOW   "\033[0;33m"
    167 #define ANSI_BLUE     "\033[0;34m"
    168 #define ANSI_MAGENTA  "\033[0;35m"
    169 #define ANSI_CYAN     "\033[0;36m"
    170 #define ANSI_GREY     "\033[0;37m"
    171 #define ANSI_DARKGREY "\033[01;30m"
    172 #define ANSI_BRED     "\033[01;31m"
    173 #define ANSI_BGREEN   "\033[01;32m"
    174 #define ANSI_BYELLOW  "\033[01;33m"
    175 #define ANSI_BBLUE    "\033[01;34m"
    176 #define ANSI_BMAGENTA "\033[01;35m"
    177 #define ANSI_BCYAN    "\033[01;36m"
    178 #define ANSI_WHITE    "\033[01;37m"
    179 #define ANSI_NORMAL   "\033[0m"
    180 
    181 static CTEST(suite, test) { }
    182 
    183 static void msg_start(const char* color, const char* title) {
    184     int size;
    185     if (color_output) {
    186         size = snprintf(ctest_errormsg, ctest_errorsize, "%s", color);
    187         ctest_errorsize -= size;
    188         ctest_errormsg += size;
    189     }
    190     size = snprintf(ctest_errormsg, ctest_errorsize, "  %s: ", title);
    191     ctest_errorsize -= size;
    192     ctest_errormsg += size;
    193 }
    194 
    195 static void msg_end() {
    196     int size;
    197     if (color_output) {
    198         size = snprintf(ctest_errormsg, ctest_errorsize, ANSI_NORMAL);
    199         ctest_errorsize -= size;
    200         ctest_errormsg += size;
    201     }
    202     size = snprintf(ctest_errormsg, ctest_errorsize, "\n");
    203     ctest_errorsize -= size;
    204     ctest_errormsg += size;
    205 }
    206 
    207 void CTEST_LOG(char *fmt, ...)
    208 {
    209     va_list argp;
    210     msg_start(ANSI_BLUE, "LOG");
    211 
    212     va_start(argp, fmt);
    213     int size = vsnprintf(ctest_errormsg, ctest_errorsize, fmt, argp);
    214     ctest_errorsize -= size;
    215     ctest_errormsg += size;
    216     va_end(argp);
    217 
    218     msg_end();
    219 }
    220 
    221 void CTEST_ERR(char *fmt, ...)
    222 {
    223     va_list argp;
    224     msg_start(ANSI_YELLOW, "ERR");
    225 
    226     va_start(argp, fmt);
    227     int size = vsnprintf(ctest_errormsg, ctest_errorsize, fmt, argp);
    228     ctest_errorsize -= size;
    229     ctest_errormsg += size;
    230     va_end(argp);
    231 
    232     msg_end();
    233     longjmp(ctest_err, 1);
    234 }
    235 
    236 void assert_str(const char* exp, const char*  real, const char* caller, int line) {
    237     if ((exp == NULL && real != NULL) ||
    238         (exp != NULL && real == NULL) ||
    239         (exp && real && strcmp(exp, real) != 0)) {
    240         CTEST_ERR("%s:%d  expected '%s', got '%s'", caller, line, exp, real);
    241     }
    242 }
    243 
    244 void assert_data(const unsigned char* exp, int expsize,
    245                  const unsigned char* real, int realsize,
    246                  const char* caller, int line) {
    247     int i;
    248     if (expsize != realsize) {
    249         CTEST_ERR("%s:%d  expected %d bytes, got %d", caller, line, expsize, realsize);
    250     }
    251     for (i=0; i<expsize; i++) {
    252         if (exp[i] != real[i]) {
    253             CTEST_ERR("%s:%d expected 0x%02x at offset %d got 0x%02x",
    254                 caller, line, exp[i], i, real[i]);
    255         }
    256     }
    257 }
    258 
    259 void assert_equal(long exp, long real, const char* caller, int line) {
    260     if (exp != real) {
    261         CTEST_ERR("%s:%d  expected %ld, got %ld", caller, line, exp, real);
    262     }
    263 }
    264 
    265 void assert_not_equal(long exp, long real, const char* caller, int line) {
    266     if ((exp) == (real)) {
    267         CTEST_ERR("%s:%d  should not be %ld", caller, line, real);
    268     }
    269 }
    270 
    271 void assert_null(void* real, const char* caller, int line) {
    272     if ((real) != NULL) {
    273         CTEST_ERR("%s:%d  should be NULL", caller, line);
    274     }
    275 }
    276 
    277 void assert_not_null(const void* real, const char* caller, int line) {
    278     if (real == NULL) {
    279         CTEST_ERR("%s:%d  should not be NULL", caller, line);
    280     }
    281 }
    282 
    283 void assert_true(int real, const char* caller, int line) {
    284     if ((real) == 0) {
    285         CTEST_ERR("%s:%d  should be true", caller, line);
    286     }
    287 }
    288 
    289 void assert_false(int real, const char* caller, int line) {
    290     if ((real) != 0) {
    291         CTEST_ERR("%s:%d  should be false", caller, line);
    292     }
    293 }
    294 
    295 void assert_fail(const char* caller, int line) {
    296     CTEST_ERR("%s:%d  shouldn't come here", caller, line);
    297 }
    298 
    299 
    300 static int suite_all(struct ctest* t) {
    301     UNUSED_PARAM(t);
    302     return 1;
    303 }
    304 
    305 static int suite_filter(struct ctest* t) {
    306     return strncmp(suite_name, t->ssname, strlen(suite_name)) == 0;
    307 }
    308 
    309 static uint64_t getCurrentTime() {
    310     struct timeval now;
    311     gettimeofday(&now, NULL);
    312     uint64_t now64 = now.tv_sec;
    313     now64 *= 1000000;
    314     now64 += (now.tv_usec);
    315     return now64;
    316 }
    317 
    318 static void color_print(const char* color, const char* text) {
    319     if (color_output)
    320         printf("%s%s"ANSI_NORMAL"\n", color, text);
    321     else
    322         printf("%s\n", text);
    323 }
    324 
    325 #ifdef __APPLE__
    326 static void *find_symbol(struct ctest *test, const char *fname)
    327 {
    328     size_t len = strlen(test->ssname) + 1 + strlen(fname);
    329     char *symbol_name = (char *) malloc(len + 1);
    330     memset(symbol_name, 0, len + 1);
    331     snprintf(symbol_name, len + 1, "%s_%s", test->ssname, fname);
    332 
    333     //fprintf(stderr, ">>>> dlsym: loading %s\n", symbol_name);
    334     void *symbol = dlsym(RTLD_DEFAULT, symbol_name);
    335     if (!symbol) {
    336         //fprintf(stderr, ">>>> ERROR: %s\n", dlerror());
    337     }
    338     // returns NULL on error
    339 
    340     free(symbol_name);
    341     return symbol;
    342 }
    343 #endif
    344 
    345 #ifdef CTEST_SEGFAULT
    346 #include <signal.h>
    347 static void sighandler(int signum)
    348 {
    349     char msg[128];
    350     sprintf(msg, "[SIGNAL %d: %s]", signum, sys_siglist[signum]);
    351     color_print(ANSI_BRED, msg);
    352     fflush(stdout);
    353 
    354     /* "Unregister" the signal handler and send the signal back to the process
    355      * so it can terminate as expected */
    356     signal(signum, SIG_DFL);
    357     kill(getpid(), signum);
    358 }
    359 #endif
    360 
    361 int ctest_main(int argc, const char *argv[])
    362 {
    363     static int total = 0;
    364     static int num_ok = 0;
    365     static int num_fail = 0;
    366     static int num_skip = 0;
    367     static int index = 1;
    368     static filter_func filter = suite_all;
    369 
    370 #ifdef CTEST_SEGFAULT
    371     signal(SIGSEGV, sighandler);
    372 #endif
    373 
    374     if (argc == 2) {
    375         suite_name = argv[1];
    376         filter = suite_filter;
    377     }
    378 
    379     color_output = isatty(1);
    380     uint64_t t1 = getCurrentTime();
    381 
    382     struct ctest* ctest_begin = &__TNAME(suite, test);
    383     struct ctest* ctest_end = &__TNAME(suite, test);
    384     // find begin and end of section by comparing magics
    385     while (1) {
    386         struct ctest* t = ctest_begin-1;
    387         if (t->magic != __CTEST_MAGIC) break;
    388         ctest_begin--;
    389     }
    390     while (1) {
    391         struct ctest* t = ctest_end+1;
    392         if (t->magic != __CTEST_MAGIC) break;
    393         ctest_end++;
    394     }
    395     ctest_end++;    // end after last one
    396 
    397     static struct ctest* test;
    398     for (test = ctest_begin; test != ctest_end; test++) {
    399         if (test == &__ctest_suite_test) continue;
    400         if (filter(test)) total++;
    401     }
    402 
    403     for (test = ctest_begin; test != ctest_end; test++) {
    404         if (test == &__ctest_suite_test) continue;
    405         if (filter(test)) {
    406             ctest_errorbuffer[0] = 0;
    407             ctest_errorsize = MSG_SIZE-1;
    408             ctest_errormsg = ctest_errorbuffer;
    409             printf("TEST %d/%d %s:%s ", index, total, test->ssname, test->ttname);
    410             fflush(stdout);
    411             if (test->skip) {
    412                 color_print(ANSI_BYELLOW, "[SKIPPED]");
    413                 num_skip++;
    414             } else {
    415                 int result = setjmp(ctest_err);
    416                 if (result == 0) {
    417 #ifdef __APPLE__
    418                     if (!test->setup) {
    419                         test->setup = (SetupFunc)find_symbol(test, "setup");
    420                     }
    421                     if (!test->teardown) {
    422                         test->teardown = (SetupFunc)find_symbol(test, "teardown");
    423                     }
    424 #endif
    425 
    426                     if (test->setup) test->setup(test->data);
    427                     if (test->data)
    428                       test->run(test->data);
    429                     else
    430                       test->run();
    431                     if (test->teardown) test->teardown(test->data);
    432                     // if we got here it's ok
    433 #ifdef COLOR_OK
    434                     color_print(ANSI_BGREEN, "[OK]");
    435 #else
    436                     printf("[OK]\n");
    437 #endif
    438                     num_ok++;
    439                 } else {
    440                     color_print(ANSI_BRED, "[FAIL]");
    441                     num_fail++;
    442                 }
    443                 if (ctest_errorsize != MSG_SIZE-1) printf("%s", ctest_errorbuffer);
    444             }
    445             index++;
    446         }
    447     }
    448     uint64_t t2 = getCurrentTime();
    449 
    450     const char* color = (num_fail) ? ANSI_BRED : ANSI_GREEN;
    451     char results[80];
    452     sprintf(results, "RESULTS: %d tests (%d ok, %d failed, %d skipped) ran in %"PRIu64" ms", total, num_ok, num_fail, num_skip, (t2 - t1)/1000);
    453     color_print(color, results);
    454     return num_fail;
    455 }
    456 
    457 #endif
    458 
    459 #endif
    460