]>
Commit | Line | Data |
---|---|---|
e8a92fe1 RB |
1 | /* |
2 | * Copyright (c) Vicent Marti. All rights reserved. | |
3 | * | |
4 | * This file is part of clar, distributed under the ISC license. | |
5 | * For full terms see the included COPYING file. | |
6 | */ | |
2e6f06a8 VM |
7 | #include <assert.h> |
8 | #include <setjmp.h> | |
9 | #include <stdlib.h> | |
10 | #include <stdio.h> | |
11 | #include <string.h> | |
12 | #include <math.h> | |
13 | #include <stdarg.h> | |
09debe12 | 14 | #include <wchar.h> |
2e6f06a8 VM |
15 | |
16 | /* required for sandboxing */ | |
17 | #include <sys/types.h> | |
18 | #include <sys/stat.h> | |
19 | ||
20 | #ifdef _WIN32 | |
21 | # include <windows.h> | |
22 | # include <io.h> | |
23 | # include <shellapi.h> | |
24 | # include <direct.h> | |
25 | ||
26 | # define _MAIN_CC __cdecl | |
27 | ||
cf94024c RB |
28 | # ifndef stat |
29 | # define stat(path, st) _stat(path, st) | |
30 | # endif | |
31 | # ifndef mkdir | |
32 | # define mkdir(path, mode) _mkdir(path) | |
33 | # endif | |
34 | # ifndef chdir | |
35 | # define chdir(path) _chdir(path) | |
36 | # endif | |
37 | # ifndef access | |
38 | # define access(path, mode) _access(path, mode) | |
39 | # endif | |
40 | # ifndef strdup | |
41 | # define strdup(str) _strdup(str) | |
42 | # endif | |
43 | # ifndef strcasecmp | |
44 | # define strcasecmp(a,b) _stricmp(a,b) | |
45 | # endif | |
2e6f06a8 VM |
46 | |
47 | # ifndef __MINGW32__ | |
48 | # pragma comment(lib, "shell32") | |
cf94024c RB |
49 | # ifndef strncpy |
50 | # define strncpy(to, from, to_size) strncpy_s(to, to_size, from, _TRUNCATE) | |
51 | # endif | |
52 | # ifndef W_OK | |
53 | # define W_OK 02 | |
54 | # endif | |
55 | # ifndef S_ISDIR | |
56 | # define S_ISDIR(x) ((x & _S_IFDIR) != 0) | |
57 | # endif | |
58 | # define p_snprintf(buf,sz,fmt,...) _snprintf_s(buf,sz,_TRUNCATE,fmt,__VA_ARGS__) | |
2e6f06a8 | 59 | # else |
cf94024c RB |
60 | # define p_snprintf snprintf |
61 | # endif | |
62 | ||
63 | # ifndef PRIuZ | |
64 | # define PRIuZ "Iu" | |
65 | # endif | |
66 | # ifndef PRIxZ | |
67 | # define PRIxZ "Ix" | |
2e6f06a8 | 68 | # endif |
806571f3 | 69 | |
22a2d3d5 | 70 | # if defined(_MSC_VER) || defined(__MINGW32__) |
806571f3 ET |
71 | typedef struct stat STAT_T; |
72 | # else | |
2e6f06a8 | 73 | typedef struct _stat STAT_T; |
806571f3 | 74 | # endif |
2e6f06a8 VM |
75 | #else |
76 | # include <sys/wait.h> /* waitpid(2) */ | |
77 | # include <unistd.h> | |
78 | # define _MAIN_CC | |
cf94024c RB |
79 | # define p_snprintf snprintf |
80 | # ifndef PRIuZ | |
81 | # define PRIuZ "zu" | |
82 | # endif | |
83 | # ifndef PRIxZ | |
84 | # define PRIxZ "zx" | |
85 | # endif | |
2e6f06a8 VM |
86 | typedef struct stat STAT_T; |
87 | #endif | |
88 | ||
89 | #include "clar.h" | |
90 | ||
91 | static void fs_rm(const char *_source); | |
92 | static void fs_copy(const char *_source, const char *dest); | |
93 | ||
94 | static const char * | |
95 | fixture_path(const char *base, const char *fixture_name); | |
96 | ||
97 | struct clar_error { | |
2e6f06a8 | 98 | const char *file; |
22a2d3d5 UG |
99 | const char *function; |
100 | size_t line_number; | |
2e6f06a8 VM |
101 | const char *error_msg; |
102 | char *description; | |
103 | ||
104 | struct clar_error *next; | |
105 | }; | |
106 | ||
6c7cee42 RD |
107 | struct clar_explicit { |
108 | size_t suite_idx; | |
109 | const char *filter; | |
110 | ||
111 | struct clar_explicit *next; | |
112 | }; | |
113 | ||
114 | struct clar_report { | |
115 | const char *test; | |
116 | int test_number; | |
117 | const char *suite; | |
118 | ||
119 | enum cl_test_status status; | |
120 | ||
121 | struct clar_error *errors; | |
122 | struct clar_error *last_error; | |
123 | ||
124 | struct clar_report *next; | |
125 | }; | |
ed38bff1 | 126 | |
6c7cee42 RD |
127 | struct clar_summary { |
128 | const char *filename; | |
129 | FILE *fp; | |
130 | }; | |
131 | ||
132 | static struct { | |
0f65733b | 133 | enum cl_test_status test_status; |
6c7cee42 | 134 | |
2e6f06a8 VM |
135 | const char *active_test; |
136 | const char *active_suite; | |
137 | ||
0f65733b | 138 | int total_skipped; |
2e6f06a8 VM |
139 | int total_errors; |
140 | ||
141 | int tests_ran; | |
142 | int suites_ran; | |
143 | ||
22a2d3d5 UG |
144 | enum cl_output_format output_format; |
145 | ||
2e6f06a8 VM |
146 | int report_errors_only; |
147 | int exit_on_error; | |
e8a92fe1 | 148 | int report_suite_names; |
2e6f06a8 | 149 | |
6c7cee42 | 150 | int write_summary; |
22a2d3d5 | 151 | char *summary_filename; |
6c7cee42 RD |
152 | struct clar_summary *summary; |
153 | ||
154 | struct clar_explicit *explicit; | |
155 | struct clar_explicit *last_explicit; | |
156 | ||
157 | struct clar_report *reports; | |
158 | struct clar_report *last_report; | |
2e6f06a8 VM |
159 | |
160 | void (*local_cleanup)(void *); | |
161 | void *local_cleanup_payload; | |
162 | ||
163 | jmp_buf trampoline; | |
164 | int trampoline_enabled; | |
cfcb346d ET |
165 | |
166 | cl_trace_cb *pfn_trace_cb; | |
167 | void *trace_payload; | |
168 | ||
2e6f06a8 VM |
169 | } _clar; |
170 | ||
171 | struct clar_func { | |
172 | const char *name; | |
173 | void (*ptr)(void); | |
174 | }; | |
175 | ||
176 | struct clar_suite { | |
177 | const char *name; | |
178 | struct clar_func initialize; | |
179 | struct clar_func cleanup; | |
180 | const struct clar_func *tests; | |
181 | size_t test_count; | |
182 | int enabled; | |
183 | }; | |
184 | ||
185 | /* From clar_print_*.c */ | |
186 | static void clar_print_init(int test_count, int suite_count, const char *suite_names); | |
187 | static void clar_print_shutdown(int test_count, int suite_count, int error_count); | |
6c7cee42 | 188 | static void clar_print_error(int num, const struct clar_report *report, const struct clar_error *error); |
0f65733b | 189 | static void clar_print_ontest(const char *test_name, int test_number, enum cl_test_status failed); |
2e6f06a8 VM |
190 | static void clar_print_onsuite(const char *suite_name, int suite_index); |
191 | static void clar_print_onabort(const char *msg, ...); | |
192 | ||
193 | /* From clar_sandbox.c */ | |
194 | static void clar_unsandbox(void); | |
195 | static int clar_sandbox(void); | |
196 | ||
6c7cee42 RD |
197 | /* From summary.h */ |
198 | static struct clar_summary *clar_summary_init(const char *filename); | |
199 | static int clar_summary_shutdown(struct clar_summary *fp); | |
200 | ||
2e6f06a8 VM |
201 | /* Load the declarations for the test suite */ |
202 | #include "clar.suite" | |
203 | ||
cfcb346d ET |
204 | |
205 | #define CL_TRACE(ev) \ | |
206 | do { \ | |
207 | if (_clar.pfn_trace_cb) \ | |
208 | _clar.pfn_trace_cb(ev, \ | |
209 | _clar.active_suite, \ | |
210 | _clar.active_test, \ | |
211 | _clar.trace_payload); \ | |
212 | } while (0) | |
213 | ||
214 | void cl_trace_register(cl_trace_cb *cb, void *payload) | |
215 | { | |
216 | _clar.pfn_trace_cb = cb; | |
217 | _clar.trace_payload = payload; | |
218 | } | |
219 | ||
220 | ||
2e6f06a8 VM |
221 | /* Core test functions */ |
222 | static void | |
6c7cee42 | 223 | clar_report_errors(struct clar_report *report) |
2e6f06a8 | 224 | { |
6c7cee42 | 225 | struct clar_error *error; |
2e6f06a8 | 226 | int i = 1; |
2e6f06a8 | 227 | |
6c7cee42 RD |
228 | for (error = report->errors; error; error = error->next) |
229 | clar_print_error(i++, _clar.last_report, error); | |
230 | } | |
231 | ||
232 | static void | |
233 | clar_report_all(void) | |
234 | { | |
235 | struct clar_report *report; | |
236 | struct clar_error *error; | |
237 | int i = 1; | |
238 | ||
239 | for (report = _clar.reports; report; report = report->next) { | |
240 | if (report->status != CL_TEST_FAILURE) | |
241 | continue; | |
242 | ||
243 | for (error = report->errors; error; error = error->next) | |
244 | clar_print_error(i++, report, error); | |
245 | } | |
2e6f06a8 VM |
246 | } |
247 | ||
248 | static void | |
249 | clar_run_test( | |
250 | const struct clar_func *test, | |
251 | const struct clar_func *initialize, | |
252 | const struct clar_func *cleanup) | |
253 | { | |
2e6f06a8 VM |
254 | _clar.trampoline_enabled = 1; |
255 | ||
cfcb346d ET |
256 | CL_TRACE(CL_TRACE__TEST__BEGIN); |
257 | ||
2e6f06a8 VM |
258 | if (setjmp(_clar.trampoline) == 0) { |
259 | if (initialize->ptr != NULL) | |
260 | initialize->ptr(); | |
261 | ||
cfcb346d | 262 | CL_TRACE(CL_TRACE__TEST__RUN_BEGIN); |
2e6f06a8 | 263 | test->ptr(); |
cfcb346d | 264 | CL_TRACE(CL_TRACE__TEST__RUN_END); |
2e6f06a8 VM |
265 | } |
266 | ||
267 | _clar.trampoline_enabled = 0; | |
268 | ||
6c7cee42 RD |
269 | if (_clar.last_report->status == CL_TEST_NOTRUN) |
270 | _clar.last_report->status = CL_TEST_OK; | |
271 | ||
2e6f06a8 VM |
272 | if (_clar.local_cleanup != NULL) |
273 | _clar.local_cleanup(_clar.local_cleanup_payload); | |
274 | ||
275 | if (cleanup->ptr != NULL) | |
276 | cleanup->ptr(); | |
277 | ||
cfcb346d ET |
278 | CL_TRACE(CL_TRACE__TEST__END); |
279 | ||
2e6f06a8 VM |
280 | _clar.tests_ran++; |
281 | ||
282 | /* remove any local-set cleanup methods */ | |
283 | _clar.local_cleanup = NULL; | |
284 | _clar.local_cleanup_payload = NULL; | |
285 | ||
0f65733b | 286 | if (_clar.report_errors_only) { |
6c7cee42 | 287 | clar_report_errors(_clar.last_report); |
0f65733b | 288 | } else { |
6c7cee42 | 289 | clar_print_ontest(test->name, _clar.tests_ran, _clar.last_report->status); |
0f65733b | 290 | } |
2e6f06a8 VM |
291 | } |
292 | ||
293 | static void | |
f4183347 | 294 | clar_run_suite(const struct clar_suite *suite, const char *filter) |
2e6f06a8 VM |
295 | { |
296 | const struct clar_func *test = suite->tests; | |
f4183347 | 297 | size_t i, matchlen; |
6c7cee42 | 298 | struct clar_report *report; |
22a2d3d5 | 299 | int exact = 0; |
2e6f06a8 VM |
300 | |
301 | if (!suite->enabled) | |
302 | return; | |
303 | ||
304 | if (_clar.exit_on_error && _clar.total_errors) | |
305 | return; | |
306 | ||
307 | if (!_clar.report_errors_only) | |
308 | clar_print_onsuite(suite->name, ++_clar.suites_ran); | |
309 | ||
310 | _clar.active_suite = suite->name; | |
cfcb346d ET |
311 | _clar.active_test = NULL; |
312 | CL_TRACE(CL_TRACE__SUITE_BEGIN); | |
2e6f06a8 | 313 | |
f4183347 | 314 | if (filter) { |
114f5a6c | 315 | size_t suitelen = strlen(suite->name); |
f4183347 RB |
316 | matchlen = strlen(filter); |
317 | if (matchlen <= suitelen) { | |
318 | filter = NULL; | |
114f5a6c | 319 | } else { |
f4183347 RB |
320 | filter += suitelen; |
321 | while (*filter == ':') | |
322 | ++filter; | |
323 | matchlen = strlen(filter); | |
22a2d3d5 UG |
324 | |
325 | if (matchlen && filter[matchlen - 1] == '$') { | |
326 | exact = 1; | |
327 | matchlen--; | |
328 | } | |
114f5a6c RB |
329 | } |
330 | } | |
331 | ||
2e6f06a8 | 332 | for (i = 0; i < suite->test_count; ++i) { |
f4183347 | 333 | if (filter && strncmp(test[i].name, filter, matchlen)) |
114f5a6c RB |
334 | continue; |
335 | ||
22a2d3d5 UG |
336 | if (exact && strlen(test[i].name) != matchlen) |
337 | continue; | |
338 | ||
2e6f06a8 | 339 | _clar.active_test = test[i].name; |
6c7cee42 RD |
340 | |
341 | report = calloc(1, sizeof(struct clar_report)); | |
342 | report->suite = _clar.active_suite; | |
343 | report->test = _clar.active_test; | |
344 | report->test_number = _clar.tests_ran; | |
345 | report->status = CL_TEST_NOTRUN; | |
346 | ||
347 | if (_clar.reports == NULL) | |
348 | _clar.reports = report; | |
349 | ||
350 | if (_clar.last_report != NULL) | |
351 | _clar.last_report->next = report; | |
352 | ||
353 | _clar.last_report = report; | |
354 | ||
2e6f06a8 VM |
355 | clar_run_test(&test[i], &suite->initialize, &suite->cleanup); |
356 | ||
357 | if (_clar.exit_on_error && _clar.total_errors) | |
358 | return; | |
359 | } | |
cfcb346d ET |
360 | |
361 | _clar.active_test = NULL; | |
362 | CL_TRACE(CL_TRACE__SUITE_END); | |
2e6f06a8 VM |
363 | } |
364 | ||
365 | static void | |
366 | clar_usage(const char *arg) | |
367 | { | |
368 | printf("Usage: %s [options]\n\n", arg); | |
369 | printf("Options:\n"); | |
6c7cee42 RD |
370 | printf(" -sname Run only the suite with `name` (can go to individual test name)\n"); |
371 | printf(" -iname Include the suite with `name`\n"); | |
372 | printf(" -xname Exclude the suite with `name`\n"); | |
373 | printf(" -v Increase verbosity (show suite names)\n"); | |
374 | printf(" -q Only report tests that had an error\n"); | |
375 | printf(" -Q Quit as soon as a test fails\n"); | |
22a2d3d5 | 376 | printf(" -t Display results in tap format\n"); |
6c7cee42 RD |
377 | printf(" -l Print suite names\n"); |
378 | printf(" -r[filename] Write summary file (to the optional filename)\n"); | |
2e6f06a8 VM |
379 | exit(-1); |
380 | } | |
381 | ||
382 | static void | |
383 | clar_parse_args(int argc, char **argv) | |
384 | { | |
385 | int i; | |
386 | ||
eae0bfdc | 387 | /* Verify options before execute */ |
2e6f06a8 VM |
388 | for (i = 1; i < argc; ++i) { |
389 | char *argument = argv[i]; | |
390 | ||
eae0bfdc | 391 | if (argument[0] != '-' || argument[1] == '\0' |
22a2d3d5 | 392 | || strchr("sixvqQtlr", argument[1]) == NULL) { |
2e6f06a8 | 393 | clar_usage(argv[0]); |
eae0bfdc PP |
394 | } |
395 | } | |
396 | ||
397 | for (i = 1; i < argc; ++i) { | |
398 | char *argument = argv[i]; | |
2e6f06a8 VM |
399 | |
400 | switch (argument[1]) { | |
401 | case 's': | |
402 | case 'i': | |
403 | case 'x': { /* given suite name */ | |
e8a92fe1 | 404 | int offset = (argument[2] == '=') ? 3 : 2, found = 0; |
2e6f06a8 | 405 | char action = argument[1]; |
f4183347 | 406 | size_t j, arglen, suitelen, cmplen; |
2e6f06a8 VM |
407 | |
408 | argument += offset; | |
f4183347 | 409 | arglen = strlen(argument); |
2e6f06a8 | 410 | |
f4183347 | 411 | if (arglen == 0) |
2e6f06a8 VM |
412 | clar_usage(argv[0]); |
413 | ||
414 | for (j = 0; j < _clar_suite_count; ++j) { | |
f4183347 RB |
415 | suitelen = strlen(_clar_suites[j].name); |
416 | cmplen = (arglen < suitelen) ? arglen : suitelen; | |
114f5a6c RB |
417 | |
418 | if (strncmp(argument, _clar_suites[j].name, cmplen) == 0) { | |
f4183347 | 419 | int exact = (arglen >= suitelen); |
e8a92fe1 | 420 | |
f2cab0a6 PS |
421 | /* Do we have a real suite prefix separated by a |
422 | * trailing '::' or just a matching substring? */ | |
423 | if (arglen > suitelen && (argument[suitelen] != ':' | |
424 | || argument[suitelen + 1] != ':')) | |
425 | continue; | |
426 | ||
e8a92fe1 RB |
427 | ++found; |
428 | ||
429 | if (!exact) | |
430 | _clar.report_suite_names = 1; | |
431 | ||
2e6f06a8 | 432 | switch (action) { |
6c7cee42 RD |
433 | case 's': { |
434 | struct clar_explicit *explicit = | |
435 | calloc(1, sizeof(struct clar_explicit)); | |
436 | assert(explicit); | |
437 | ||
438 | explicit->suite_idx = j; | |
439 | explicit->filter = argument; | |
440 | ||
441 | if (_clar.explicit == NULL) | |
442 | _clar.explicit = explicit; | |
443 | ||
444 | if (_clar.last_explicit != NULL) | |
445 | _clar.last_explicit->next = explicit; | |
446 | ||
447 | _clar_suites[j].enabled = 1; | |
448 | _clar.last_explicit = explicit; | |
449 | break; | |
450 | } | |
114f5a6c RB |
451 | case 'i': _clar_suites[j].enabled = 1; break; |
452 | case 'x': _clar_suites[j].enabled = 0; break; | |
2e6f06a8 | 453 | } |
e8a92fe1 RB |
454 | |
455 | if (exact) | |
456 | break; | |
2e6f06a8 VM |
457 | } |
458 | } | |
459 | ||
e8a92fe1 | 460 | if (!found) { |
2e6f06a8 VM |
461 | clar_print_onabort("No suite matching '%s' found.\n", argument); |
462 | exit(-1); | |
463 | } | |
464 | break; | |
465 | } | |
466 | ||
467 | case 'q': | |
468 | _clar.report_errors_only = 1; | |
469 | break; | |
470 | ||
471 | case 'Q': | |
472 | _clar.exit_on_error = 1; | |
473 | break; | |
474 | ||
22a2d3d5 UG |
475 | case 't': |
476 | _clar.output_format = CL_OUTPUT_TAP; | |
477 | break; | |
478 | ||
2e6f06a8 VM |
479 | case 'l': { |
480 | size_t j; | |
481 | printf("Test suites (use -s<name> to run just one):\n"); | |
482 | for (j = 0; j < _clar_suite_count; ++j) | |
483 | printf(" %3d: %s\n", (int)j, _clar_suites[j].name); | |
484 | ||
485 | exit(0); | |
486 | } | |
487 | ||
83276dcc ET |
488 | case 'v': |
489 | _clar.report_suite_names = 1; | |
490 | break; | |
491 | ||
6c7cee42 RD |
492 | case 'r': |
493 | _clar.write_summary = 1; | |
22a2d3d5 UG |
494 | free(_clar.summary_filename); |
495 | _clar.summary_filename = strdup(*(argument + 2) ? (argument + 2) : "summary.xml"); | |
6c7cee42 RD |
496 | break; |
497 | ||
2e6f06a8 | 498 | default: |
eae0bfdc | 499 | assert(!"Unexpected commandline argument!"); |
2e6f06a8 VM |
500 | } |
501 | } | |
502 | } | |
503 | ||
10be94e9 ET |
504 | void |
505 | clar_test_init(int argc, char **argv) | |
2e6f06a8 | 506 | { |
22a2d3d5 UG |
507 | if (argc > 1) |
508 | clar_parse_args(argc, argv); | |
509 | ||
2e6f06a8 VM |
510 | clar_print_init( |
511 | (int)_clar_callback_count, | |
512 | (int)_clar_suite_count, | |
513 | "" | |
514 | ); | |
515 | ||
22a2d3d5 UG |
516 | if ((_clar.summary_filename = getenv("CLAR_SUMMARY")) != NULL) { |
517 | _clar.write_summary = 1; | |
518 | _clar.summary_filename = strdup(_clar.summary_filename); | |
519 | } | |
6c7cee42 RD |
520 | |
521 | if (_clar.write_summary && | |
522 | !(_clar.summary = clar_summary_init(_clar.summary_filename))) { | |
523 | clar_print_onabort("Failed to open the summary file\n"); | |
524 | exit(-1); | |
525 | } | |
526 | ||
2e6f06a8 VM |
527 | if (clar_sandbox() < 0) { |
528 | clar_print_onabort("Failed to sandbox the test runner.\n"); | |
529 | exit(-1); | |
530 | } | |
10be94e9 | 531 | } |
2e6f06a8 | 532 | |
10be94e9 | 533 | int |
8fd74c08 | 534 | clar_test_run(void) |
10be94e9 | 535 | { |
6c7cee42 RD |
536 | size_t i; |
537 | struct clar_explicit *explicit; | |
ed38bff1 | 538 | |
6c7cee42 RD |
539 | if (_clar.explicit) { |
540 | for (explicit = _clar.explicit; explicit; explicit = explicit->next) | |
541 | clar_run_suite(&_clar_suites[explicit->suite_idx], explicit->filter); | |
542 | } else { | |
2e6f06a8 | 543 | for (i = 0; i < _clar_suite_count; ++i) |
114f5a6c | 544 | clar_run_suite(&_clar_suites[i], NULL); |
2e6f06a8 VM |
545 | } |
546 | ||
10be94e9 ET |
547 | return _clar.total_errors; |
548 | } | |
549 | ||
550 | void | |
8fd74c08 | 551 | clar_test_shutdown(void) |
10be94e9 | 552 | { |
6c7cee42 RD |
553 | struct clar_explicit *explicit, *explicit_next; |
554 | struct clar_report *report, *report_next; | |
555 | ||
2e6f06a8 VM |
556 | clar_print_shutdown( |
557 | _clar.tests_ran, | |
558 | (int)_clar_suite_count, | |
559 | _clar.total_errors | |
560 | ); | |
561 | ||
562 | clar_unsandbox(); | |
6c7cee42 RD |
563 | |
564 | if (_clar.write_summary && clar_summary_shutdown(_clar.summary) < 0) { | |
565 | clar_print_onabort("Failed to write the summary file\n"); | |
566 | exit(-1); | |
567 | } | |
568 | ||
569 | for (explicit = _clar.explicit; explicit; explicit = explicit_next) { | |
570 | explicit_next = explicit->next; | |
571 | free(explicit); | |
572 | } | |
573 | ||
574 | for (report = _clar.reports; report; report = report_next) { | |
575 | report_next = report->next; | |
576 | free(report); | |
577 | } | |
22a2d3d5 UG |
578 | |
579 | free(_clar.summary_filename); | |
10be94e9 ET |
580 | } |
581 | ||
582 | int | |
583 | clar_test(int argc, char **argv) | |
584 | { | |
585 | int errors; | |
586 | ||
587 | clar_test_init(argc, argv); | |
588 | errors = clar_test_run(); | |
589 | clar_test_shutdown(); | |
590 | ||
591 | return errors; | |
2e6f06a8 VM |
592 | } |
593 | ||
0f65733b VM |
594 | static void abort_test(void) |
595 | { | |
596 | if (!_clar.trampoline_enabled) { | |
597 | clar_print_onabort( | |
598 | "Fatal error: a cleanup method raised an exception."); | |
6c7cee42 | 599 | clar_report_errors(_clar.last_report); |
0f65733b VM |
600 | exit(-1); |
601 | } | |
602 | ||
cfcb346d | 603 | CL_TRACE(CL_TRACE__TEST__LONGJMP); |
0f65733b VM |
604 | longjmp(_clar.trampoline, -1); |
605 | } | |
606 | ||
607 | void clar__skip(void) | |
608 | { | |
6c7cee42 | 609 | _clar.last_report->status = CL_TEST_SKIP; |
0f65733b VM |
610 | _clar.total_skipped++; |
611 | abort_test(); | |
612 | } | |
613 | ||
7202ec29 | 614 | void clar__fail( |
2e6f06a8 | 615 | const char *file, |
22a2d3d5 UG |
616 | const char *function, |
617 | size_t line, | |
2e6f06a8 VM |
618 | const char *error_msg, |
619 | const char *description, | |
620 | int should_abort) | |
621 | { | |
7202ec29 | 622 | struct clar_error *error = calloc(1, sizeof(struct clar_error)); |
2e6f06a8 | 623 | |
6c7cee42 RD |
624 | if (_clar.last_report->errors == NULL) |
625 | _clar.last_report->errors = error; | |
2e6f06a8 | 626 | |
6c7cee42 RD |
627 | if (_clar.last_report->last_error != NULL) |
628 | _clar.last_report->last_error->next = error; | |
2e6f06a8 | 629 | |
6c7cee42 | 630 | _clar.last_report->last_error = error; |
2e6f06a8 | 631 | |
2e6f06a8 | 632 | error->file = file; |
22a2d3d5 | 633 | error->function = function; |
2e6f06a8 VM |
634 | error->line_number = line; |
635 | error->error_msg = error_msg; | |
636 | ||
637 | if (description != NULL) | |
638 | error->description = strdup(description); | |
639 | ||
2e6f06a8 | 640 | _clar.total_errors++; |
6c7cee42 | 641 | _clar.last_report->status = CL_TEST_FAILURE; |
2e6f06a8 | 642 | |
0f65733b VM |
643 | if (should_abort) |
644 | abort_test(); | |
2e6f06a8 VM |
645 | } |
646 | ||
7202ec29 RB |
647 | void clar__assert( |
648 | int condition, | |
649 | const char *file, | |
22a2d3d5 UG |
650 | const char *function, |
651 | size_t line, | |
7202ec29 RB |
652 | const char *error_msg, |
653 | const char *description, | |
654 | int should_abort) | |
655 | { | |
656 | if (condition) | |
657 | return; | |
658 | ||
22a2d3d5 | 659 | clar__fail(file, function, line, error_msg, description, should_abort); |
7202ec29 RB |
660 | } |
661 | ||
cf94024c | 662 | void clar__assert_equal( |
2e6f06a8 | 663 | const char *file, |
22a2d3d5 UG |
664 | const char *function, |
665 | size_t line, | |
2e6f06a8 | 666 | const char *err, |
cf94024c RB |
667 | int should_abort, |
668 | const char *fmt, | |
669 | ...) | |
2e6f06a8 | 670 | { |
cf94024c RB |
671 | va_list args; |
672 | char buf[4096]; | |
673 | int is_equal = 1; | |
674 | ||
675 | va_start(args, fmt); | |
676 | ||
677 | if (!strcmp("%s", fmt)) { | |
678 | const char *s1 = va_arg(args, const char *); | |
679 | const char *s2 = va_arg(args, const char *); | |
680 | is_equal = (!s1 || !s2) ? (s1 == s2) : !strcmp(s1, s2); | |
681 | ||
682 | if (!is_equal) { | |
683 | if (s1 && s2) { | |
684 | int pos; | |
685 | for (pos = 0; s1[pos] == s2[pos] && s1[pos] && s2[pos]; ++pos) | |
686 | /* find differing byte offset */; | |
687 | p_snprintf(buf, sizeof(buf), "'%s' != '%s' (at byte %d)", | |
688 | s1, s2, pos); | |
689 | } else { | |
690 | p_snprintf(buf, sizeof(buf), "'%s' != '%s'", s1, s2); | |
691 | } | |
692 | } | |
693 | } | |
806571f3 ET |
694 | else if(!strcmp("%.*s", fmt)) { |
695 | const char *s1 = va_arg(args, const char *); | |
696 | const char *s2 = va_arg(args, const char *); | |
dd954a37 | 697 | int len = va_arg(args, int); |
806571f3 ET |
698 | is_equal = (!s1 || !s2) ? (s1 == s2) : !strncmp(s1, s2, len); |
699 | ||
700 | if (!is_equal) { | |
701 | if (s1 && s2) { | |
dd954a37 | 702 | int pos; |
806571f3 ET |
703 | for (pos = 0; s1[pos] == s2[pos] && pos < len; ++pos) |
704 | /* find differing byte offset */; | |
705 | p_snprintf(buf, sizeof(buf), "'%.*s' != '%.*s' (at byte %d)", | |
706 | len, s1, len, s2, pos); | |
707 | } else { | |
708 | p_snprintf(buf, sizeof(buf), "'%.*s' != '%.*s'", len, s1, len, s2); | |
709 | } | |
710 | } | |
711 | } | |
09debe12 ET |
712 | else if (!strcmp("%ls", fmt)) { |
713 | const wchar_t *wcs1 = va_arg(args, const wchar_t *); | |
714 | const wchar_t *wcs2 = va_arg(args, const wchar_t *); | |
715 | is_equal = (!wcs1 || !wcs2) ? (wcs1 == wcs2) : !wcscmp(wcs1, wcs2); | |
716 | ||
717 | if (!is_equal) { | |
718 | if (wcs1 && wcs2) { | |
719 | int pos; | |
720 | for (pos = 0; wcs1[pos] == wcs2[pos] && wcs1[pos] && wcs2[pos]; ++pos) | |
721 | /* find differing byte offset */; | |
722 | p_snprintf(buf, sizeof(buf), "'%ls' != '%ls' (at byte %d)", | |
723 | wcs1, wcs2, pos); | |
724 | } else { | |
725 | p_snprintf(buf, sizeof(buf), "'%ls' != '%ls'", wcs1, wcs2); | |
726 | } | |
727 | } | |
728 | } | |
729 | else if(!strcmp("%.*ls", fmt)) { | |
730 | const wchar_t *wcs1 = va_arg(args, const wchar_t *); | |
731 | const wchar_t *wcs2 = va_arg(args, const wchar_t *); | |
732 | int len = va_arg(args, int); | |
733 | is_equal = (!wcs1 || !wcs2) ? (wcs1 == wcs2) : !wcsncmp(wcs1, wcs2, len); | |
734 | ||
735 | if (!is_equal) { | |
736 | if (wcs1 && wcs2) { | |
737 | int pos; | |
738 | for (pos = 0; wcs1[pos] == wcs2[pos] && pos < len; ++pos) | |
739 | /* find differing byte offset */; | |
740 | p_snprintf(buf, sizeof(buf), "'%.*ls' != '%.*ls' (at byte %d)", | |
741 | len, wcs1, len, wcs2, pos); | |
742 | } else { | |
743 | p_snprintf(buf, sizeof(buf), "'%.*ls' != '%.*ls'", len, wcs1, len, wcs2); | |
744 | } | |
745 | } | |
746 | } | |
273ddc54 | 747 | else if (!strcmp("%"PRIuZ, fmt) || !strcmp("%"PRIxZ, fmt)) { |
cf94024c RB |
748 | size_t sz1 = va_arg(args, size_t), sz2 = va_arg(args, size_t); |
749 | is_equal = (sz1 == sz2); | |
750 | if (!is_equal) { | |
751 | int offset = p_snprintf(buf, sizeof(buf), fmt, sz1); | |
752 | strncat(buf, " != ", sizeof(buf) - offset); | |
753 | p_snprintf(buf + offset + 4, sizeof(buf) - offset - 4, fmt, sz2); | |
754 | } | |
755 | } | |
756 | else if (!strcmp("%p", fmt)) { | |
757 | void *p1 = va_arg(args, void *), *p2 = va_arg(args, void *); | |
758 | is_equal = (p1 == p2); | |
759 | if (!is_equal) | |
760 | p_snprintf(buf, sizeof(buf), "%p != %p", p1, p2); | |
761 | } | |
762 | else { | |
763 | int i1 = va_arg(args, int), i2 = va_arg(args, int); | |
764 | is_equal = (i1 == i2); | |
765 | if (!is_equal) { | |
766 | int offset = p_snprintf(buf, sizeof(buf), fmt, i1); | |
767 | strncat(buf, " != ", sizeof(buf) - offset); | |
768 | p_snprintf(buf + offset + 4, sizeof(buf) - offset - 4, fmt, i2); | |
f4183347 | 769 | } |
2e6f06a8 | 770 | } |
2e6f06a8 | 771 | |
cf94024c RB |
772 | va_end(args); |
773 | ||
774 | if (!is_equal) | |
22a2d3d5 | 775 | clar__fail(file, function, line, err, buf, should_abort); |
2e6f06a8 VM |
776 | } |
777 | ||
778 | void cl_set_cleanup(void (*cleanup)(void *), void *opaque) | |
779 | { | |
780 | _clar.local_cleanup = cleanup; | |
781 | _clar.local_cleanup_payload = opaque; | |
782 | } | |
783 | ||
784 | #include "clar/sandbox.h" | |
785 | #include "clar/fixtures.h" | |
786 | #include "clar/fs.h" | |
787 | #include "clar/print.h" | |
6c7cee42 | 788 | #include "clar/summary.h" |