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