Raw
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 */
7
8 #define _BSD_SOURCE
9 #define _DARWIN_C_SOURCE
10 #define _DEFAULT_SOURCE
11
12 #include <errno.h>
13 #include <setjmp.h>
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <math.h>
18 #include <stdarg.h>
19 #include <wchar.h>
20 #include <time.h>
21 #include <inttypes.h>
22
23 /* required for sandboxing */
24 #include <sys/types.h>
25 #include <sys/stat.h>
26
27 #ifndef va_copy
28 # ifdef __va_copy
29 # define va_copy(dst, src) __va_copy(dst, src)
30 # else
31 # define va_copy(dst, src) ((dst) = (src))
32 # endif
33 #endif
34
35 #if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_WCHAR__)
36 /*
37 * uClibc can optionally be built without wchar support, in which case
38 * the installed <wchar.h> is a stub that only defines the `whar_t`
39 * type but none of the functions typically declared by it.
40 */
41 #else
42 # define CLAR_HAVE_WCHAR
43 #endif
44
45 #ifdef _WIN32
46 # define WIN32_LEAN_AND_MEAN
47 # include <windows.h>
48 # include <io.h>
49 # include <direct.h>
50
51 # define _MAIN_CC __cdecl
52
53 # ifndef stat
54 # define stat(path, st) _stat(path, st)
55 typedef struct _stat STAT_T;
56 # else
57 typedef struct stat STAT_T;
58 # endif
59 # ifndef mkdir
60 # define mkdir(path, mode) _mkdir(path)
61 # endif
62 # ifndef chdir
63 # define chdir(path) _chdir(path)
64 # endif
65 # ifndef access
66 # define access(path, mode) _access(path, mode)
67 # endif
68 # ifndef strdup
69 # define strdup(str) _strdup(str)
70 # endif
71 # ifndef strcasecmp
72 # define strcasecmp(a,b) _stricmp(a,b)
73 # endif
74
75 # ifndef __MINGW32__
76 # pragma comment(lib, "shell32")
77 # ifndef strncpy
78 # define strncpy(to, from, to_size) strncpy_s(to, to_size, from, _TRUNCATE)
79 # endif
80 # ifndef W_OK
81 # define W_OK 02
82 # endif
83 # ifndef S_ISDIR
84 # define S_ISDIR(x) ((x & _S_IFDIR) != 0)
85 # endif
86 # define p_snprintf(buf,sz,fmt,...) _snprintf_s(buf,sz,_TRUNCATE,fmt,__VA_ARGS__)
87 # define p_vsnprintf _vsnprintf
88 # else
89 # define p_snprintf snprintf
90 # define p_vsnprintf vsnprintf
91 # endif
92
93 # define localtime_r(timer, buf) (localtime_s(buf, timer) == 0 ? buf : NULL)
94 #else
95 # include <sys/wait.h> /* waitpid(2) */
96 # include <unistd.h>
97 # define _MAIN_CC
98 # define p_snprintf snprintf
99 # define p_vsnprintf vsnprintf
100 typedef struct stat STAT_T;
101 #endif
102
103 #define MAX(x, y) (((x) > (y)) ? (x) : (y))
104
105 #include "clar.h"
106
107 static void fs_rm(const char *_source);
108 static void fs_copy(const char *_source, const char *dest);
109
110 #ifdef CLAR_FIXTURE_PATH
111 static const char *
112 fixture_path(const char *base, const char *fixture_name);
113 #endif
114
115 struct clar_error {
116 const char *file;
117 const char *function;
118 uintmax_t line_number;
119 const char *error_msg;
120 char *description;
121
122 struct clar_error *next;
123 };
124
125 struct clar_explicit {
126 size_t suite_idx;
127 const char *filter;
128
129 struct clar_explicit *next;
130 };
131
132 struct clar_report {
133 const char *test;
134 int test_number;
135 const char *suite;
136
137 enum cl_test_status status;
138 time_t start;
139 double elapsed;
140
141 struct clar_error *errors;
142 struct clar_error *last_error;
143
144 struct clar_report *next;
145 };
146
147 struct clar_summary {
148 const char *filename;
149 FILE *fp;
150 };
151
152 static struct {
153 enum cl_test_status test_status;
154
155 const char *active_test;
156 const char *active_suite;
157
158 int total_skipped;
159 int total_errors;
160
161 int tests_ran;
162 int suites_ran;
163
164 enum cl_output_format output_format;
165
166 int exit_on_error;
167 int verbosity;
168
169 int write_summary;
170 char *summary_filename;
171 struct clar_summary *summary;
172
173 struct clar_explicit *explicit;
174 struct clar_explicit *last_explicit;
175
176 struct clar_report *reports;
177 struct clar_report *last_report;
178
179 const char *invoke_file;
180 const char *invoke_func;
181 size_t invoke_line;
182
183 void (*local_cleanup)(void *);
184 void *local_cleanup_payload;
185
186 jmp_buf trampoline;
187 int trampoline_enabled;
188
189 cl_trace_cb *pfn_trace_cb;
190 void *trace_payload;
191
192 } _clar;
193
194 struct clar_func {
195 const char *name;
196 void (*ptr)(void);
197 };
198
199 struct clar_suite {
200 const char *name;
201 struct clar_func initialize;
202 struct clar_func cleanup;
203 const struct clar_func *tests;
204 size_t test_count;
205 int enabled;
206 };
207
208 /* From clar_print_*.c */
209 static void clar_print_init(int test_count, int suite_count);
210 static void clar_print_shutdown(int test_count, int suite_count, int error_count);
211 static void clar_print_error(int num, const struct clar_report *report, const struct clar_error *error);
212 static void clar_print_ontest(const char *suite_name, const char *test_name, int test_number, enum cl_test_status failed);
213 static void clar_print_onsuite(const char *suite_name, int suite_index);
214 static void clar_print_onabortv(const char *msg, va_list argp);
215 static void clar_print_onabort(const char *msg, ...);
216
217 /* From clar_sandbox.c */
218 static void clar_tempdir_init(void);
219 static void clar_tempdir_shutdown(void);
220 static int clar_sandbox_create(const char *suite_name, const char *test_name);
221 static int clar_sandbox_cleanup(void);
222
223 /* From summary.h */
224 static struct clar_summary *clar_summary_init(const char *filename);
225 static int clar_summary_shutdown(struct clar_summary *fp);
226
227 /* Load the declarations for the test suite */
228 #include "clar.suite"
229
230
231 #define CL_TRACE(ev) \
232 do { \
233 if (_clar.pfn_trace_cb) \
234 _clar.pfn_trace_cb(ev, \
235 _clar.active_suite, \
236 _clar.active_test, \
237 _clar.trace_payload); \
238 } while (0)
239
240 static void clar_abort(const char *msg, ...)
241 {
242 va_list argp;
243 va_start(argp, msg);
244 clar_print_onabortv(msg, argp);
245 va_end(argp);
246 exit(-1);
247 }
248
249 void cl_trace_register(cl_trace_cb *cb, void *payload)
250 {
251 _clar.pfn_trace_cb = cb;
252 _clar.trace_payload = payload;
253 }
254
255
256 /* Core test functions */
257 static void
258 clar_report_errors(struct clar_report *report)
259 {
260 struct clar_error *error;
261 int i = 1;
262
263 for (error = report->errors; error; error = error->next)
264 clar_print_error(i++, _clar.last_report, error);
265 }
266
267 static void
268 clar_report_all(void)
269 {
270 struct clar_report *report;
271 struct clar_error *error;
272 int i = 1;
273
274 for (report = _clar.reports; report; report = report->next) {
275 if (report->status != CL_TEST_FAILURE)
276 continue;
277
278 for (error = report->errors; error; error = error->next)
279 clar_print_error(i++, report, error);
280 }
281 }
282
283 #ifdef WIN32
284 # define clar_time DWORD
285
286 static void clar_time_now(clar_time *out)
287 {
288 *out = GetTickCount();
289 }
290
291 static double clar_time_diff(clar_time *start, clar_time *end)
292 {
293 return ((double)*end - (double)*start) / 1000;
294 }
295 #else
296 # include <sys/time.h>
297
298 # define clar_time struct timeval
299
300 static void clar_time_now(clar_time *out)
301 {
302 gettimeofday(out, NULL);
303 }
304
305 static double clar_time_diff(clar_time *start, clar_time *end)
306 {
307 return ((double)end->tv_sec + (double)end->tv_usec / 1.0E6) -
308 ((double)start->tv_sec + (double)start->tv_usec / 1.0E6);
309 }
310 #endif
311
312 static void
313 clar_run_test(
314 const struct clar_suite *suite,
315 const struct clar_func *test,
316 const struct clar_func *initialize,
317 const struct clar_func *cleanup)
318 {
319 clar_time start, end;
320
321 _clar.trampoline_enabled = 1;
322
323 CL_TRACE(CL_TRACE__TEST__BEGIN);
324
325 clar_sandbox_create(suite->name, test->name);
326
327 _clar.last_report->start = time(NULL);
328 clar_time_now(&start);
329
330 if (setjmp(_clar.trampoline) == 0) {
331 if (initialize->ptr != NULL)
332 initialize->ptr();
333
334 CL_TRACE(CL_TRACE__TEST__RUN_BEGIN);
335 test->ptr();
336 CL_TRACE(CL_TRACE__TEST__RUN_END);
337 }
338
339 clar_time_now(&end);
340
341 _clar.trampoline_enabled = 0;
342
343 if (_clar.last_report->status == CL_TEST_NOTRUN)
344 _clar.last_report->status = CL_TEST_OK;
345
346 _clar.last_report->elapsed = clar_time_diff(&start, &end);
347
348 if (_clar.local_cleanup != NULL)
349 _clar.local_cleanup(_clar.local_cleanup_payload);
350
351 clar__clear_invokepoint();
352
353 if (cleanup->ptr != NULL)
354 cleanup->ptr();
355
356 clar_sandbox_cleanup();
357
358 CL_TRACE(CL_TRACE__TEST__END);
359
360 _clar.tests_ran++;
361
362 /* remove any local-set cleanup methods */
363 _clar.local_cleanup = NULL;
364 _clar.local_cleanup_payload = NULL;
365
366 clar_print_ontest(suite->name, test->name, _clar.tests_ran, _clar.last_report->status);
367 }
368
369 static void
370 clar_run_suite(const struct clar_suite *suite, const char *filter)
371 {
372 const struct clar_func *test = suite->tests;
373 size_t i, matchlen = 0;
374 struct clar_report *report;
375 int exact = 0;
376
377 if (!suite->enabled)
378 return;
379
380 if (_clar.exit_on_error && _clar.total_errors)
381 return;
382
383 clar_print_onsuite(suite->name, ++_clar.suites_ran);
384
385 _clar.active_suite = suite->name;
386 _clar.active_test = NULL;
387 CL_TRACE(CL_TRACE__SUITE_BEGIN);
388
389 if (filter) {
390 size_t suitelen = strlen(suite->name);
391 matchlen = strlen(filter);
392 if (matchlen <= suitelen) {
393 filter = NULL;
394 } else {
395 filter += suitelen;
396 while (*filter == ':')
397 ++filter;
398 matchlen = strlen(filter);
399
400 if (matchlen && filter[matchlen - 1] == '$') {
401 exact = 1;
402 matchlen--;
403 }
404 }
405 }
406
407 for (i = 0; i < suite->test_count; ++i) {
408 if (filter && strncmp(test[i].name, filter, matchlen))
409 continue;
410
411 if (exact && strlen(test[i].name) != matchlen)
412 continue;
413
414 _clar.active_test = test[i].name;
415
416 if ((report = calloc(1, sizeof(*report))) == NULL)
417 clar_abort("Failed to allocate report.\n");
418 report->suite = _clar.active_suite;
419 report->test = _clar.active_test;
420 report->test_number = _clar.tests_ran;
421 report->status = CL_TEST_NOTRUN;
422
423 if (_clar.reports == NULL)
424 _clar.reports = report;
425
426 if (_clar.last_report != NULL)
427 _clar.last_report->next = report;
428
429 _clar.last_report = report;
430
431 clar_run_test(suite, &test[i], &suite->initialize, &suite->cleanup);
432
433 if (_clar.exit_on_error && _clar.total_errors)
434 return;
435 }
436
437 _clar.active_test = NULL;
438 CL_TRACE(CL_TRACE__SUITE_END);
439 }
440
441 static void
442 clar_usage(const char *arg)
443 {
444 printf("Usage: %s [options]\n\n", arg);
445 printf("Options:\n");
446 printf(" -sname Run only the suite with `name` (can go to individual test name)\n");
447 printf(" -iname Include the suite with `name`\n");
448 printf(" -xname Exclude the suite with `name`\n");
449 printf(" -v Increase verbosity (show suite names)\n");
450 printf(" -q Decrease verbosity, inverse to -v\n");
451 printf(" -Q Quit as soon as a test fails\n");
452 printf(" -t Display results in tap format\n");
453 printf(" -l Print suite names\n");
454 printf(" -r[filename] Write summary file (to the optional filename)\n");
455 exit(1);
456 }
457
458 static void
459 clar_parse_args(int argc, char **argv)
460 {
461 int i;
462
463 for (i = 1; i < argc; ++i) {
464 char *argument = argv[i];
465
466 if (argument[0] != '-' || argument[1] == '\0')
467 clar_usage(argv[0]);
468
469 switch (argument[1]) {
470 case 's':
471 case 'i':
472 case 'x': { /* given suite name */
473 int offset = (argument[2] == '=') ? 3 : 2, found = 0;
474 char action = argument[1];
475 size_t j, arglen, suitelen, cmplen;
476
477 argument += offset;
478 arglen = strlen(argument);
479
480 if (arglen == 0) {
481 if (i + 1 == argc)
482 clar_usage(argv[0]);
483
484 argument = argv[++i];
485 arglen = strlen(argument);
486 }
487
488 for (j = 0; j < _clar_suite_count; ++j) {
489 suitelen = strlen(_clar_suites[j].name);
490 cmplen = (arglen < suitelen) ? arglen : suitelen;
491
492 if (strncmp(argument, _clar_suites[j].name, cmplen) == 0) {
493 int exact = (arglen >= suitelen);
494
495 /* Do we have a real suite prefix separated by a
496 * trailing '::' or just a matching substring? */
497 if (arglen > suitelen && (argument[suitelen] != ':'
498 || argument[suitelen + 1] != ':'))
499 continue;
500
501 ++found;
502
503 switch (action) {
504 case 's': {
505 struct clar_explicit *explicit;
506
507 if ((explicit = calloc(1, sizeof(*explicit))) == NULL)
508 clar_abort("Failed to allocate explicit test.\n");
509
510 explicit->suite_idx = j;
511 explicit->filter = argument;
512
513 if (_clar.explicit == NULL)
514 _clar.explicit = explicit;
515
516 if (_clar.last_explicit != NULL)
517 _clar.last_explicit->next = explicit;
518
519 _clar_suites[j].enabled = 1;
520 _clar.last_explicit = explicit;
521 break;
522 }
523 case 'i': _clar_suites[j].enabled = 1; break;
524 case 'x': _clar_suites[j].enabled = 0; break;
525 }
526
527 if (exact)
528 break;
529 }
530 }
531
532 if (!found)
533 clar_abort("No suite matching '%s' found.\n", argument);
534
535 break;
536 }
537
538 case 'q':
539 if (argument[2] != '\0')
540 clar_usage(argv[0]);
541
542 _clar.verbosity--;
543 break;
544
545 case 'Q':
546 if (argument[2] != '\0')
547 clar_usage(argv[0]);
548
549 _clar.exit_on_error = 1;
550 break;
551
552 case 't':
553 if (argument[2] != '\0')
554 clar_usage(argv[0]);
555
556 _clar.output_format = CL_OUTPUT_TAP;
557 break;
558
559 case 'l': {
560 size_t j;
561
562 if (argument[2] != '\0')
563 clar_usage(argv[0]);
564
565 printf("Test suites (use -s<name> to run just one):\n");
566 for (j = 0; j < _clar_suite_count; ++j)
567 printf(" %3d: %s\n", (int)j, _clar_suites[j].name);
568
569 exit(0);
570 }
571
572 case 'v':
573 if (argument[2] != '\0')
574 clar_usage(argv[0]);
575
576 _clar.verbosity++;
577 break;
578
579 case 'r':
580 _clar.write_summary = 1;
581 free(_clar.summary_filename);
582
583 if (*(argument + 2)) {
584 if ((_clar.summary_filename = strdup(argument + 2)) == NULL)
585 clar_abort("Failed to allocate summary filename.\n");
586 } else {
587 _clar.summary_filename = NULL;
588 }
589
590 break;
591
592 default:
593 clar_usage(argv[0]);
594 }
595 }
596 }
597
598 void
599 clar_test_init(int argc, char **argv)
600 {
601 const char *summary_env;
602
603 if (argc > 1)
604 clar_parse_args(argc, argv);
605
606 clar_print_init((int)_clar_callback_count, (int)_clar_suite_count);
607
608 if (!_clar.summary_filename &&
609 (summary_env = getenv("CLAR_SUMMARY")) != NULL) {
610 _clar.write_summary = 1;
611 if ((_clar.summary_filename = strdup(summary_env)) == NULL)
612 clar_abort("Failed to allocate summary filename.\n");
613 }
614
615 if (_clar.write_summary && !_clar.summary_filename)
616 if ((_clar.summary_filename = strdup("summary.xml")) == NULL)
617 clar_abort("Failed to allocate summary filename.\n");
618
619 if (_clar.write_summary)
620 _clar.summary = clar_summary_init(_clar.summary_filename);
621
622 clar_tempdir_init();
623 }
624
625 int
626 clar_test_run(void)
627 {
628 size_t i;
629 struct clar_explicit *explicit;
630
631 if (_clar.explicit) {
632 for (explicit = _clar.explicit; explicit; explicit = explicit->next)
633 clar_run_suite(&_clar_suites[explicit->suite_idx], explicit->filter);
634 } else {
635 for (i = 0; i < _clar_suite_count; ++i)
636 clar_run_suite(&_clar_suites[i], NULL);
637 }
638
639 return _clar.total_errors;
640 }
641
642 void
643 clar_test_shutdown(void)
644 {
645 struct clar_explicit *explicit, *explicit_next;
646 struct clar_report *report, *report_next;
647
648 clar_print_shutdown(
649 _clar.tests_ran,
650 (int)_clar_suite_count,
651 _clar.total_errors
652 );
653
654 clar_tempdir_shutdown();
655
656 if (_clar.write_summary && clar_summary_shutdown(_clar.summary) < 0)
657 clar_abort("Failed to write the summary file '%s: %s.\n",
658 _clar.summary_filename, strerror(errno));
659
660 for (explicit = _clar.explicit; explicit; explicit = explicit_next) {
661 explicit_next = explicit->next;
662 free(explicit);
663 }
664
665 for (report = _clar.reports; report; report = report_next) {
666 struct clar_error *error, *error_next;
667
668 for (error = report->errors; error; error = error_next) {
669 free(error->description);
670 error_next = error->next;
671 free(error);
672 }
673
674 report_next = report->next;
675 free(report);
676 }
677
678 free(_clar.summary_filename);
679 }
680
681 int
682 clar_test(int argc, char **argv)
683 {
684 int errors;
685
686 clar_test_init(argc, argv);
687 errors = clar_test_run();
688 clar_test_shutdown();
689
690 return errors;
691 }
692
693 static void abort_test(void)
694 {
695 if (!_clar.trampoline_enabled) {
696 clar_print_onabort(
697 "Fatal error: a cleanup method raised an exception.\n");
698 clar_report_errors(_clar.last_report);
699 exit(1);
700 }
701
702 CL_TRACE(CL_TRACE__TEST__LONGJMP);
703 longjmp(_clar.trampoline, -1);
704 }
705
706 void clar__skip(void)
707 {
708 _clar.last_report->status = CL_TEST_SKIP;
709 _clar.total_skipped++;
710 abort_test();
711 }
712
713 static void clar__failv(
714 const char *file,
715 const char *function,
716 size_t line,
717 int should_abort,
718 const char *error_msg,
719 const char *description,
720 va_list args)
721 {
722 struct clar_error *error;
723
724 if ((error = calloc(1, sizeof(*error))) == NULL)
725 clar_abort("Failed to allocate error.\n");
726
727 if (_clar.last_report->errors == NULL)
728 _clar.last_report->errors = error;
729
730 if (_clar.last_report->last_error != NULL)
731 _clar.last_report->last_error->next = error;
732
733 _clar.last_report->last_error = error;
734
735 error->file = _clar.invoke_file ? _clar.invoke_file : file;
736 error->function = _clar.invoke_func ? _clar.invoke_func : function;
737 error->line_number = _clar.invoke_line ? _clar.invoke_line : line;
738 error->error_msg = error_msg;
739
740 if (description != NULL) {
741 va_list args_copy;
742 int len;
743
744 va_copy(args_copy, args);
745 if ((len = p_vsnprintf(NULL, 0, description, args_copy)) < 0)
746 clar_abort("Failed to compute description.");
747 va_end(args_copy);
748
749 if ((error->description = calloc(1, len + 1)) == NULL)
750 clar_abort("Failed to allocate buffer.");
751 p_vsnprintf(error->description, len + 1, description, args);
752 }
753
754 _clar.total_errors++;
755 _clar.last_report->status = CL_TEST_FAILURE;
756
757 if (should_abort)
758 abort_test();
759 }
760
761 void clar__failf(
762 const char *file,
763 const char *function,
764 size_t line,
765 int should_abort,
766 const char *error_msg,
767 const char *description,
768 ...)
769 {
770 va_list args;
771 va_start(args, description);
772 clar__failv(file, function, line, should_abort, error_msg,
773 description, args);
774 va_end(args);
775 }
776
777 void clar__fail(
778 const char *file,
779 const char *function,
780 size_t line,
781 const char *error_msg,
782 const char *description,
783 int should_abort)
784 {
785 clar__failf(file, function, line, should_abort, error_msg,
786 description ? "%s" : NULL, description);
787 }
788
789 void clar__assert(
790 int condition,
791 const char *file,
792 const char *function,
793 size_t line,
794 const char *error_msg,
795 const char *description,
796 int should_abort)
797 {
798 if (condition)
799 return;
800
801 clar__fail(file, function, line, error_msg, description, should_abort);
802 }
803
804 void clar__assert_equal(
805 const char *file,
806 const char *function,
807 size_t line,
808 const char *err,
809 int should_abort,
810 const char *fmt,
811 ...)
812 {
813 va_list args;
814 char buf[4096];
815 int is_equal = 1;
816
817 va_start(args, fmt);
818
819 if (!strcmp("%s", fmt)) {
820 const char *s1 = va_arg(args, const char *);
821 const char *s2 = va_arg(args, const char *);
822 is_equal = (!s1 || !s2) ? (s1 == s2) : !strcmp(s1, s2);
823
824 if (!is_equal) {
825 if (s1 && s2) {
826 int pos;
827 for (pos = 0; s1[pos] == s2[pos] && s1[pos] && s2[pos]; ++pos)
828 /* find differing byte offset */;
829 p_snprintf(buf, sizeof(buf), "'%s' != '%s' (at byte %d)",
830 s1, s2, pos);
831 } else {
832 const char *q1 = s1 ? "'" : "";
833 const char *q2 = s2 ? "'" : "";
834 s1 = s1 ? s1 : "NULL";
835 s2 = s2 ? s2 : "NULL";
836 p_snprintf(buf, sizeof(buf), "%s%s%s != %s%s%s",
837 q1, s1, q1, q2, s2, q2);
838 }
839 }
840 }
841 else if(!strcmp("%.*s", fmt)) {
842 const char *s1 = va_arg(args, const char *);
843 const char *s2 = va_arg(args, const char *);
844 int len = va_arg(args, int);
845 is_equal = (!s1 || !s2) ? (s1 == s2) : !strncmp(s1, s2, len);
846
847 if (!is_equal) {
848 if (s1 && s2) {
849 int pos;
850 for (pos = 0; pos < len && s1[pos] == s2[pos]; ++pos)
851 /* find differing byte offset */;
852 p_snprintf(buf, sizeof(buf), "'%.*s' != '%.*s' (at byte %d)",
853 len, s1, len, s2, pos);
854 } else {
855 const char *q1 = s1 ? "'" : "";
856 const char *q2 = s2 ? "'" : "";
857 s1 = s1 ? s1 : "NULL";
858 s2 = s2 ? s2 : "NULL";
859 p_snprintf(buf, sizeof(buf), "%s%.*s%s != %s%.*s%s",
860 q1, len, s1, q1, q2, len, s2, q2);
861 }
862 }
863 }
864 #ifdef CLAR_HAVE_WCHAR
865 else if (!strcmp("%ls", fmt)) {
866 const wchar_t *wcs1 = va_arg(args, const wchar_t *);
867 const wchar_t *wcs2 = va_arg(args, const wchar_t *);
868 is_equal = (!wcs1 || !wcs2) ? (wcs1 == wcs2) : !wcscmp(wcs1, wcs2);
869
870 if (!is_equal) {
871 if (wcs1 && wcs2) {
872 int pos;
873 for (pos = 0; wcs1[pos] == wcs2[pos] && wcs1[pos] && wcs2[pos]; ++pos)
874 /* find differing byte offset */;
875 p_snprintf(buf, sizeof(buf), "'%ls' != '%ls' (at byte %d)",
876 wcs1, wcs2, pos);
877 } else {
878 const char *q1 = wcs1 ? "'" : "";
879 const char *q2 = wcs2 ? "'" : "";
880 wcs1 = wcs1 ? wcs1 : L"NULL";
881 wcs2 = wcs2 ? wcs2 : L"NULL";
882 p_snprintf(buf, sizeof(buf), "%s%ls%s != %s%ls%s",
883 q1, wcs1, q1, q2, wcs2, q2);
884 }
885 }
886 }
887 else if(!strcmp("%.*ls", fmt)) {
888 const wchar_t *wcs1 = va_arg(args, const wchar_t *);
889 const wchar_t *wcs2 = va_arg(args, const wchar_t *);
890 int len = va_arg(args, int);
891 is_equal = (!wcs1 || !wcs2) ? (wcs1 == wcs2) : !wcsncmp(wcs1, wcs2, len);
892
893 if (!is_equal) {
894 if (wcs1 && wcs2) {
895 int pos;
896 for (pos = 0; pos < len && wcs1[pos] == wcs2[pos]; ++pos)
897 /* find differing byte offset */;
898 p_snprintf(buf, sizeof(buf), "'%.*ls' != '%.*ls' (at byte %d)",
899 len, wcs1, len, wcs2, pos);
900 } else {
901 const char *q1 = wcs1 ? "'" : "";
902 const char *q2 = wcs2 ? "'" : "";
903 wcs1 = wcs1 ? wcs1 : L"NULL";
904 wcs2 = wcs2 ? wcs2 : L"NULL";
905 p_snprintf(buf, sizeof(buf), "%s%.*ls%s != %s%.*ls%s",
906 q1, len, wcs1, q1, q2, len, wcs2, q2);
907 }
908 }
909 }
910 #endif /* CLAR_HAVE_WCHAR */
911 else if (!strcmp("%"PRIuMAX, fmt) || !strcmp("%"PRIxMAX, fmt)) {
912 uintmax_t sz1 = va_arg(args, uintmax_t), sz2 = va_arg(args, uintmax_t);
913 is_equal = (sz1 == sz2);
914 if (!is_equal) {
915 int offset = p_snprintf(buf, sizeof(buf), fmt, sz1);
916 strncat(buf, " != ", sizeof(buf) - offset);
917 p_snprintf(buf + offset + 4, sizeof(buf) - offset - 4, fmt, sz2);
918 }
919 }
920 else if (!strcmp("%p", fmt)) {
921 void *p1 = va_arg(args, void *), *p2 = va_arg(args, void *);
922 is_equal = (p1 == p2);
923 if (!is_equal)
924 p_snprintf(buf, sizeof(buf), "%p != %p", p1, p2);
925 }
926 else {
927 int i1 = va_arg(args, int), i2 = va_arg(args, int);
928 is_equal = (i1 == i2);
929 if (!is_equal) {
930 int offset = p_snprintf(buf, sizeof(buf), fmt, i1);
931 strncat(buf, " != ", sizeof(buf) - offset);
932 p_snprintf(buf + offset + 4, sizeof(buf) - offset - 4, fmt, i2);
933 }
934 }
935
936 va_end(args);
937
938 if (!is_equal)
939 clar__fail(file, function, line, err, buf, should_abort);
940 }
941
942 void clar__assert_compare_i(
943 const char *file,
944 const char *func,
945 size_t line,
946 int should_abort,
947 enum clar_comparison cmp,
948 intmax_t value1,
949 intmax_t value2,
950 const char *error,
951 const char *description,
952 ...)
953 {
954 int fulfilled;
955 switch (cmp) {
956 case CLAR_COMPARISON_EQ:
957 fulfilled = value1 == value2;
958 break;
959 case CLAR_COMPARISON_LT:
960 fulfilled = value1 < value2;
961 break;
962 case CLAR_COMPARISON_LE:
963 fulfilled = value1 <= value2;
964 break;
965 case CLAR_COMPARISON_GT:
966 fulfilled = value1 > value2;
967 break;
968 case CLAR_COMPARISON_GE:
969 fulfilled = value1 >= value2;
970 break;
971 default:
972 cl_assert(0);
973 return;
974 }
975
976 if (!fulfilled) {
977 va_list args;
978 va_start(args, description);
979 clar__failv(file, func, line, should_abort, error,
980 description, args);
981 va_end(args);
982 }
983 }
984
985 void clar__assert_compare_u(
986 const char *file,
987 const char *func,
988 size_t line,
989 int should_abort,
990 enum clar_comparison cmp,
991 uintmax_t value1,
992 uintmax_t value2,
993 const char *error,
994 const char *description,
995 ...)
996 {
997 int fulfilled;
998 switch (cmp) {
999 case CLAR_COMPARISON_EQ:
1000 fulfilled = value1 == value2;
1001 break;
1002 case CLAR_COMPARISON_LT:
1003 fulfilled = value1 < value2;
1004 break;
1005 case CLAR_COMPARISON_LE:
1006 fulfilled = value1 <= value2;
1007 break;
1008 case CLAR_COMPARISON_GT:
1009 fulfilled = value1 > value2;
1010 break;
1011 case CLAR_COMPARISON_GE:
1012 fulfilled = value1 >= value2;
1013 break;
1014 default:
1015 cl_assert(0);
1016 return;
1017 }
1018
1019 if (!fulfilled) {
1020 va_list args;
1021 va_start(args, description);
1022 clar__failv(file, func, line, should_abort, error,
1023 description, args);
1024 va_end(args);
1025 }
1026 }
1027
1028 void cl_set_cleanup(void (*cleanup)(void *), void *opaque)
1029 {
1030 _clar.local_cleanup = cleanup;
1031 _clar.local_cleanup_payload = opaque;
1032 }
1033
1034 void clar__set_invokepoint(
1035 const char *file,
1036 const char *func,
1037 size_t line)
1038 {
1039 _clar.invoke_file = file;
1040 _clar.invoke_func = func;
1041 _clar.invoke_line = line;
1042 }
1043
1044 void clar__clear_invokepoint(void)
1045 {
1046 _clar.invoke_file = NULL;
1047 _clar.invoke_func = NULL;
1048 _clar.invoke_line = 0;
1049 }
1050
1051 #include "clar/sandbox.h"
1052 #include "clar/fixtures.h"
1053 #include "clar/fs.h"
1054 #include "clar/print.h"
1055 #include "clar/summary.h"