CCL
ctest.h
Go to the documentation of this file.
1 /* Copyright 2011-2016 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 #if defined _WIN32 || defined __CYGWIN__
20 #ifndef WIN32
21 #define WIN32
22 #endif
23 #endif
24 
25 #ifndef WIN32
26 #define WEAK __attribute__ ((weak))
27 #else
28 #define WEAK
29 #endif
30 
31 #include <inttypes.h> /* intmax_t, uintmax_t, PRI* */
32 #include <stddef.h> /* size_t */
33 
34 typedef void (*SetupFunc)(void*);
35 typedef void (*TearDownFunc)(void*);
36 
37 struct ctest {
38  const char* ssname; // suite name
39  const char* ttname; // test name
40  void (*run)();
41  int skip;
42 
43  void* data;
46 
47  unsigned int magic;
48 };
49 
50 #define __FNAME(sname, tname) __ctest_##sname##_##tname##_run
51 #define __TNAME(sname, tname) __ctest_##sname##_##tname
52 
53 #define __CTEST_MAGIC (0xdeadbeef)
54 #ifdef __APPLE__
55 #define __Test_Section __attribute__ ((used, section ("__DATA, .ctest")))
56 #else
57 #define __Test_Section __attribute__ ((used, section (".ctest")))
58 #endif
59 
60 #define __CTEST_STRUCT(sname, tname, _skip, __data, __setup, __teardown) \
61  static struct ctest __TNAME(sname, tname) __Test_Section = { \
62  .ssname=#sname, \
63  .ttname=#tname, \
64  .run = __FNAME(sname, tname), \
65  .skip = _skip, \
66  .data = __data, \
67  .setup = (SetupFunc)__setup, \
68  .teardown = (TearDownFunc)__teardown, \
69  .magic = __CTEST_MAGIC };
70 
71 #define CTEST_DATA(sname) struct sname##_data
72 
73 #define CTEST_SETUP(sname) \
74  void WEAK sname##_setup(struct sname##_data* data)
75 
76 #define CTEST_TEARDOWN(sname) \
77  void WEAK sname##_teardown(struct sname##_data* data)
78 
79 #define __CTEST_INTERNAL(sname, tname, _skip) \
80  void __FNAME(sname, tname)(); \
81  __CTEST_STRUCT(sname, tname, _skip, NULL, NULL, NULL) \
82  void __FNAME(sname, tname)()
83 
84 #ifdef __APPLE__
85 #define SETUP_FNAME(sname) NULL
86 #define TEARDOWN_FNAME(sname) NULL
87 #else
88 #define SETUP_FNAME(sname) sname##_setup
89 #define TEARDOWN_FNAME(sname) sname##_teardown
90 #endif
91 
92 #define __CTEST2_INTERNAL(sname, tname, _skip) \
93  static struct sname##_data __ctest_##sname##_data; \
94  CTEST_SETUP(sname); \
95  CTEST_TEARDOWN(sname); \
96  void __FNAME(sname, tname)(struct sname##_data* data); \
97  __CTEST_STRUCT(sname, tname, _skip, &__ctest_##sname##_data, SETUP_FNAME(sname), TEARDOWN_FNAME(sname)) \
98  void __FNAME(sname, tname)(struct sname##_data* data)
99 
100 
101 void CTEST_LOG(const char* fmt, ...);
102 void CTEST_ERR(const char* fmt, ...); // doesn't return
103 
104 #define CTEST(sname, tname) __CTEST_INTERNAL(sname, tname, 0)
105 #define CTEST_SKIP(sname, tname) __CTEST_INTERNAL(sname, tname, 1)
106 
107 #define CTEST2(sname, tname) __CTEST2_INTERNAL(sname, tname, 0)
108 #define CTEST2_SKIP(sname, tname) __CTEST2_INTERNAL(sname, tname, 1)
109 
110 
111 void assert_str(const char* exp, const char* real, const char* caller, int line);
112 #define ASSERT_STR(exp, real) assert_str(exp, real, __FILE__, __LINE__)
113 
114 void assert_data(const unsigned char* exp, size_t expsize,
115  const unsigned char* real, size_t realsize,
116  const char* caller, int line);
117 #define ASSERT_DATA(exp, expsize, real, realsize) \
118  assert_data(exp, expsize, real, realsize, __FILE__, __LINE__)
119 
120 void assert_equal(intmax_t exp, intmax_t real, const char* caller, int line);
121 #define ASSERT_EQUAL(exp, real) assert_equal(exp, real, __FILE__, __LINE__)
122 
123 void assert_equal_u(uintmax_t exp, uintmax_t real, const char* caller, int line);
124 #define ASSERT_EQUAL_U(exp, real) assert_equal_u(exp, real, __FILE__, __LINE__)
125 
126 void assert_not_equal(intmax_t exp, intmax_t real, const char* caller, int line);
127 #define ASSERT_NOT_EQUAL(exp, real) assert_not_equal(exp, real, __FILE__, __LINE__)
128 
129 void assert_not_equal_u(uintmax_t exp, uintmax_t real, const char* caller, int line);
130 #define ASSERT_NOT_EQUAL_U(exp, real) assert_not_equal_u(exp, real, __FILE__, __LINE__)
131 
132 void assert_interval(intmax_t exp1, intmax_t exp2, intmax_t real, const char* caller, int line);
133 #define ASSERT_INTERVAL(exp1, exp2, real) assert_interval(exp1, exp2, real, __FILE__, __LINE__)
134 
135 void assert_null(void* real, const char* caller, int line);
136 #define ASSERT_NULL(real) assert_null((void*)real, __FILE__, __LINE__)
137 
138 void assert_not_null(const void* real, const char* caller, int line);
139 #define ASSERT_NOT_NULL(real) assert_not_null(real, __FILE__, __LINE__)
140 
141 void assert_true(int real, const char* caller, int line);
142 #define ASSERT_TRUE(real) assert_true(real, __FILE__, __LINE__)
143 
144 void assert_false(int real, const char* caller, int line);
145 #define ASSERT_FALSE(real) assert_false(real, __FILE__, __LINE__)
146 
147 void assert_fail(const char* caller, int line);
148 #define ASSERT_FAIL() assert_fail(__FILE__, __LINE__)
149 
150 void assert_dbl_near(double exp, double real, double tol, const char* caller, int line);
151 #define ASSERT_DBL_NEAR(exp, real) assert_dbl_near(exp, real, 1e-4, __FILE__, __LINE__)
152 #define ASSERT_DBL_NEAR_TOL(exp, real, tol) assert_dbl_near(exp, real, tol, __FILE__, __LINE__)
153 
154 void assert_dbl_far(double exp, double real, double tol, const char* caller, int line);
155 #define ASSERT_DBL_FAR(exp, real) assert_dbl_far(exp, real, 1e-4, __FILE__, __LINE__)
156 #define ASSERT_DBL_FAR_TOL(exp, real, tol) assert_dbl_far(exp, real, tol, __FILE__, __LINE__)
157 
158 #ifdef CTEST_MAIN
159 
160 #include <setjmp.h>
161 #include <stdarg.h>
162 #include <stdio.h>
163 #include <string.h>
164 #include <sys/time.h>
165 #include <unistd.h>
166 #include <stdint.h>
167 #include <stdlib.h>
168 
169 #ifdef __APPLE__
170 #include <dlfcn.h>
171 #endif
172 
173 static size_t ctest_errorsize;
174 static char* ctest_errormsg;
175 #define MSG_SIZE 4096
176 static char ctest_errorbuffer[MSG_SIZE];
177 static jmp_buf ctest_err;
178 static int color_output = 1;
179 static const char* suite_name;
180 
181 typedef int (*filter_func)(struct ctest*);
182 
183 #define ANSI_BLACK "\033[0;30m"
184 #define ANSI_RED "\033[0;31m"
185 #define ANSI_GREEN "\033[0;32m"
186 #define ANSI_YELLOW "\033[0;33m"
187 #define ANSI_BLUE "\033[0;34m"
188 #define ANSI_MAGENTA "\033[0;35m"
189 #define ANSI_CYAN "\033[0;36m"
190 #define ANSI_GREY "\033[0;37m"
191 #define ANSI_DARKGREY "\033[01;30m"
192 #define ANSI_BRED "\033[01;31m"
193 #define ANSI_BGREEN "\033[01;32m"
194 #define ANSI_BYELLOW "\033[01;33m"
195 #define ANSI_BBLUE "\033[01;34m"
196 #define ANSI_BMAGENTA "\033[01;35m"
197 #define ANSI_BCYAN "\033[01;36m"
198 #define ANSI_WHITE "\033[01;37m"
199 #define ANSI_NORMAL "\033[0m"
200 
201 static CTEST(suite, test) { }
202 
203 inline static void vprint_errormsg(const char* const fmt, va_list ap) {
204  // (v)snprintf returns the number that would have been written
205  const int ret = vsnprintf(ctest_errormsg, ctest_errorsize, fmt, ap);
206  if (ret < 0) {
207  ctest_errormsg[0] = 0x00;
208  } else {
209  const size_t size = (size_t) ret;
210  const size_t s = (ctest_errorsize <= size ? size -ctest_errorsize : size);
211  // ctest_errorsize may overflow at this point
212  ctest_errorsize -= s;
213  ctest_errormsg += s;
214  }
215 }
216 
217 inline static void print_errormsg(const char* const fmt, ...) {
218  va_list argp;
219  va_start(argp, fmt);
220  vprint_errormsg(fmt, argp);
221  va_end(argp);
222 }
223 
224 static void msg_start(const char* color, const char* title) {
225  if (color_output) {
226  print_errormsg("%s", color);
227  }
228  print_errormsg(" %s: ", title);
229 }
230 
231 static void msg_end() {
232  if (color_output) {
233  print_errormsg(ANSI_NORMAL);
234  }
235  print_errormsg("\n");
236 }
237 
238 void CTEST_LOG(const char* fmt, ...)
239 {
240  va_list argp;
241  msg_start(ANSI_BLUE, "LOG");
242 
243  va_start(argp, fmt);
244  vprint_errormsg(fmt, argp);
245  va_end(argp);
246 
247  msg_end();
248 }
249 
250 void CTEST_ERR(const char* fmt, ...)
251 {
252  va_list argp;
253  msg_start(ANSI_YELLOW, "ERR");
254 
255  va_start(argp, fmt);
256  vprint_errormsg(fmt, argp);
257  va_end(argp);
258 
259  msg_end();
260  longjmp(ctest_err, 1);
261 }
262 
263 void assert_str(const char* exp, const char* real, const char* caller, int line) {
264  if ((exp == NULL && real != NULL) ||
265  (exp != NULL && real == NULL) ||
266  (exp && real && strcmp(exp, real) != 0)) {
267  CTEST_ERR("%s:%d expected '%s', got '%s'", caller, line, exp, real);
268  }
269 }
270 
271 void assert_data(const unsigned char* exp, size_t expsize,
272  const unsigned char* real, size_t realsize,
273  const char* caller, int line) {
274  size_t i;
275  if (expsize != realsize) {
276  CTEST_ERR("%s:%d expected %" PRIuMAX " bytes, got %" PRIuMAX, caller, line, (uintmax_t) expsize, (uintmax_t) realsize);
277  }
278  for (i=0; i<expsize; i++) {
279  if (exp[i] != real[i]) {
280  CTEST_ERR("%s:%d expected 0x%02x at offset %" PRIuMAX " got 0x%02x",
281  caller, line, exp[i], (uintmax_t) i, real[i]);
282  }
283  }
284 }
285 
286 void assert_equal(intmax_t exp, intmax_t real, const char* caller, int line) {
287  if (exp != real) {
288  CTEST_ERR("%s:%d expected %" PRIdMAX ", got %" PRIdMAX, caller, line, exp, real);
289  }
290 }
291 
292 void assert_equal_u(uintmax_t exp, uintmax_t real, const char* caller, int line) {
293  if (exp != real) {
294  CTEST_ERR("%s:%d expected %" PRIuMAX ", got %" PRIuMAX, caller, line, exp, real);
295  }
296 }
297 
298 void assert_not_equal(intmax_t exp, intmax_t real, const char* caller, int line) {
299  if ((exp) == (real)) {
300  CTEST_ERR("%s:%d should not be %" PRIdMAX, caller, line, real);
301  }
302 }
303 
304 void assert_not_equal_u(uintmax_t exp, uintmax_t real, const char* caller, int line) {
305  if ((exp) == (real)) {
306  CTEST_ERR("%s:%d should not be %" PRIuMAX, caller, line, real);
307  }
308 }
309 
310 void assert_interval(intmax_t exp1, intmax_t exp2, intmax_t real, const char* caller, int line) {
311  if (real < exp1 || real > exp2) {
312  CTEST_ERR("%s:%d expected %" PRIdMAX "-%" PRIdMAX ", got %" PRIdMAX, caller, line, exp1, exp2, real);
313  }
314 }
315 
316 void assert_dbl_near(double exp, double real, double tol, const char* caller, int line) {
317  double diff = exp - real;
318  double absdiff = diff;
319  /* avoid using fabs and linking with a math lib */
320  if(diff < 0) {
321  absdiff *= -1;
322  }
323  if (absdiff > tol) {
324  CTEST_ERR("%s:%d expected %0.6e, got %0.6e (diff %0.6e, tol %0.6e)", caller, line, exp, real, diff, tol);
325  }
326 }
327 
328 void assert_dbl_far(double exp, double real, double tol, const char* caller, int line) {
329  double diff = exp - real;
330  double absdiff = diff;
331  /* avoid using fabs and linking with a math lib */
332  if(diff < 0) {
333  absdiff *= -1;
334  }
335  if (absdiff <= tol) {
336  CTEST_ERR("%s:%d expected %0.6e, got %0.6e (diff %0.6e, tol %0.6e)", caller, line, exp, real, diff, tol);
337  }
338 }
339 
340 void assert_null(void* real, const char* caller, int line) {
341  if ((real) != NULL) {
342  CTEST_ERR("%s:%d should be NULL", caller, line);
343  }
344 }
345 
346 void assert_not_null(const void* real, const char* caller, int line) {
347  if (real == NULL) {
348  CTEST_ERR("%s:%d should not be NULL", caller, line);
349  }
350 }
351 
352 void assert_true(int real, const char* caller, int line) {
353  if ((real) == 0) {
354  CTEST_ERR("%s:%d should be true", caller, line);
355  }
356 }
357 
358 void assert_false(int real, const char* caller, int line) {
359  if ((real) != 0) {
360  CTEST_ERR("%s:%d should be false", caller, line);
361  }
362 }
363 
364 void assert_fail(const char* caller, int line) {
365  CTEST_ERR("%s:%d shouldn't come here", caller, line);
366 }
367 
368 
369 static int suite_all(struct ctest* t) {
370  (void) t; // fix unused parameter warning
371  return 1;
372 }
373 
374 static int suite_filter(struct ctest* t) {
375  return strncmp(suite_name, t->ssname, strlen(suite_name)) == 0;
376 }
377 
378 static uint64_t getCurrentTime() {
379  struct timeval now;
380  gettimeofday(&now, NULL);
381  uint64_t now64 = (uint64_t) now.tv_sec;
382  now64 *= 1000000;
383  now64 += ((uint64_t) now.tv_usec);
384  return now64;
385 }
386 
387 static void color_print(const char* color, const char* text) {
388  if (color_output)
389  printf("%s%s"ANSI_NORMAL"\n", color, text);
390  else
391  printf("%s\n", text);
392 }
393 
394 #ifdef __APPLE__
395 static void *find_symbol(struct ctest *test, const char *fname)
396 {
397  size_t len = strlen(test->ssname) + 1 + strlen(fname);
398  char *symbol_name = (char *) malloc(len + 1);
399  memset(symbol_name, 0, len + 1);
400  snprintf(symbol_name, len + 1, "%s_%s", test->ssname, fname);
401 
402  //fprintf(stderr, ">>>> dlsym: loading %s\n", symbol_name);
403  void *symbol = dlsym(RTLD_DEFAULT, symbol_name);
404  if (!symbol) {
405  //fprintf(stderr, ">>>> ERROR: %s\n", dlerror());
406  }
407  // returns NULL on error
408 
409  free(symbol_name);
410  return symbol;
411 }
412 #endif
413 
414 #ifdef CTEST_SEGFAULT
415 #include <signal.h>
416 static void sighandler(int signum)
417 {
418  char msg[128];
419  sprintf(msg, "[SIGNAL %d: %s]", signum, sys_siglist[signum]);
420  color_print(ANSI_BRED, msg);
421  fflush(stdout);
422 
423  /* "Unregister" the signal handler and send the signal back to the process
424  * so it can terminate as expected */
425  signal(signum, SIG_DFL);
426  kill(getpid(), signum);
427 }
428 #endif
429 
430 int ctest_main(int argc, const char *argv[])
431 {
432  static int total = 0;
433  static int num_ok = 0;
434  static int num_fail = 0;
435  static int num_skip = 0;
436  static int index = 1;
437  static filter_func filter = suite_all;
438 
439 #ifdef CTEST_SEGFAULT
440  signal(SIGSEGV, sighandler);
441 #endif
442 
443  if (argc == 2) {
444  suite_name = argv[1];
445  filter = suite_filter;
446  }
447 #ifdef CTEST_NO_COLORS
448  color_output = 0;
449 #else
450  color_output = isatty(1);
451 #endif
452  uint64_t t1 = getCurrentTime();
453 
454  struct ctest* ctest_begin = &__TNAME(suite, test);
455  struct ctest* ctest_end = &__TNAME(suite, test);
456  // find begin and end of section by comparing magics
457  while (1) {
458  struct ctest* t = ctest_begin-1;
459  if (t->magic != __CTEST_MAGIC) break;
460  ctest_begin--;
461  }
462  while (1) {
463  struct ctest* t = ctest_end+1;
464  if (t->magic != __CTEST_MAGIC) break;
465  ctest_end++;
466  }
467  ctest_end++; // end after last one
468 
469  static struct ctest* test;
470  for (test = ctest_begin; test != ctest_end; test++) {
471  if (test == &__TNAME(suite, test)) continue;
472  if (filter(test)) total++;
473  }
474 
475  for (test = ctest_begin; test != ctest_end; test++) {
476  if (test == &__TNAME(suite, test)) continue;
477  if (filter(test)) {
478  ctest_errorbuffer[0] = 0;
479  ctest_errorsize = MSG_SIZE-1;
480  ctest_errormsg = ctest_errorbuffer;
481  printf("TEST %d/%d %s:%s ", index, total, test->ssname, test->ttname);
482  fflush(stdout);
483  if (test->skip) {
484  color_print(ANSI_BYELLOW, "[SKIPPED]");
485  num_skip++;
486  } else {
487  int result = setjmp(ctest_err);
488  if (result == 0) {
489 #ifdef __APPLE__
490  if (!test->setup) {
491  test->setup = (SetupFunc) find_symbol(test, "setup");
492  }
493  if (!test->teardown) {
494  test->teardown = (TearDownFunc) find_symbol(test, "teardown");
495  }
496 #endif
497 
498  if (test->setup) test->setup(test->data);
499  if (test->data)
500  test->run(test->data);
501  else
502  test->run();
503  if (test->teardown) test->teardown(test->data);
504  // if we got here it's ok
505 #ifdef CTEST_COLOR_OK
506  color_print(ANSI_BGREEN, "[OK]");
507 #else
508  printf("[OK]\n");
509 #endif
510  num_ok++;
511  } else {
512  color_print(ANSI_BRED, "[FAIL]");
513  num_fail++;
514  }
515  if (ctest_errorsize != MSG_SIZE-1) printf("%s", ctest_errorbuffer);
516  }
517  index++;
518  }
519  }
520  uint64_t t2 = getCurrentTime();
521 
522  const char* color = (num_fail) ? ANSI_BRED : ANSI_GREEN;
523  char results[80];
524  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);
525  color_print(color, results);
526  return num_fail;
527 }
528 
529 #endif
530 
531 #endif
532 
void(* run)()
Definition: ctest.h:40
void assert_equal(intmax_t exp, intmax_t real, const char *caller, int line)
#define CTEST(sname, tname)
Definition: ctest.h:104
void assert_dbl_near(double exp, double real, double tol, const char *caller, int line)
void CTEST_LOG(const char *fmt,...)
void assert_data(const unsigned char *exp, size_t expsize, const unsigned char *real, size_t realsize, const char *caller, int line)
void assert_not_equal(intmax_t exp, intmax_t real, const char *caller, int line)
void assert_null(void *real, const char *caller, int line)
void assert_dbl_far(double exp, double real, double tol, const char *caller, int line)
#define __TNAME(sname, tname)
Definition: ctest.h:51
void(* TearDownFunc)(void *)
Definition: ctest.h:35
Definition: ctest.h:37
void assert_interval(intmax_t exp1, intmax_t exp2, intmax_t real, const char *caller, int line)
TearDownFunc teardown
Definition: ctest.h:45
void assert_equal_u(uintmax_t exp, uintmax_t real, const char *caller, int line)
unsigned int magic
Definition: ctest.h:47
void assert_str(const char *exp, const char *real, const char *caller, int line)
#define __CTEST_MAGIC
Definition: ctest.h:53
void assert_false(int real, const char *caller, int line)
void * data
Definition: ctest.h:43
void assert_not_equal_u(uintmax_t exp, uintmax_t real, const char *caller, int line)
void assert_true(int real, const char *caller, int line)
SetupFunc setup
Definition: ctest.h:44
const char * ssname
Definition: ctest.h:38
const char * ttname
Definition: ctest.h:39
void assert_fail(const char *caller, int line)
int skip
Definition: ctest.h:41
void CTEST_ERR(const char *fmt,...)
void assert_not_null(const void *real, const char *caller, int line)
void(* SetupFunc)(void *)
Definition: ctest.h:34