• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
CTEST(suite,test)181 static CTEST(suite, test) { }
182 
msg_start(const char * color,const char * title)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 
msg_end()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 
CTEST_LOG(char * fmt,...)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 
CTEST_ERR(char * fmt,...)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 
assert_str(const char * exp,const char * real,const char * caller,int line)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 
assert_data(const unsigned char * exp,int expsize,const unsigned char * real,int realsize,const char * caller,int line)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 
assert_equal(long exp,long real,const char * caller,int line)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 
assert_not_equal(long exp,long real,const char * caller,int line)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 
assert_null(void * real,const char * caller,int line)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 
assert_not_null(const void * real,const char * caller,int line)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 
assert_true(int real,const char * caller,int line)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 
assert_false(int real,const char * caller,int line)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 
assert_fail(const char * caller,int line)295 void assert_fail(const char* caller, int line) {
296     CTEST_ERR("%s:%d  shouldn't come here", caller, line);
297 }
298 
299 
suite_all(struct ctest * t)300 static int suite_all(struct ctest* t) {
301     UNUSED_PARAM(t);
302     return 1;
303 }
304 
suite_filter(struct ctest * t)305 static int suite_filter(struct ctest* t) {
306     return strncmp(suite_name, t->ssname, strlen(suite_name)) == 0;
307 }
308 
getCurrentTime()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 
color_print(const char * color,const char * text)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__
find_symbol(struct ctest * test,const char * fname)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>
sighandler(int signum)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 
ctest_main(int argc,const char * argv[])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