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