clar.c 17.4 KB
Newer Older
Russell Belfer committed
1 2 3 4 5 6
/*
 * Copyright (c) Vicent Marti. All rights reserved.
 *
 * This file is part of clar, distributed under the ISC license.
 * For full terms see the included COPYING file.
 */
Vicent Marti committed
7 8 9 10 11 12 13
#include <assert.h>
#include <setjmp.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdarg.h>
14
#include <wchar.h>
Vicent Marti committed
15 16 17 18 19 20 21 22 23 24 25 26 27

/* required for sandboxing */
#include <sys/types.h>
#include <sys/stat.h>

#ifdef _WIN32
#	include <windows.h>
#	include <io.h>
#	include <shellapi.h>
#	include <direct.h>

#	define _MAIN_CC __cdecl

Russell Belfer committed
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
#	ifndef stat
#		define stat(path, st) _stat(path, st)
#	endif
#	ifndef mkdir
#		define mkdir(path, mode) _mkdir(path)
#	endif
#	ifndef chdir
#		define chdir(path) _chdir(path)
#	endif
#	ifndef access
#		define access(path, mode) _access(path, mode)
#	endif
#	ifndef strdup
#		define strdup(str) _strdup(str)
#	endif
#	ifndef strcasecmp
#		define strcasecmp(a,b) _stricmp(a,b)
#	endif
Vicent Marti committed
46 47 48

#	ifndef __MINGW32__
#		pragma comment(lib, "shell32")
Russell Belfer committed
49 50 51 52 53 54 55 56 57 58
#		ifndef strncpy
#			define strncpy(to, from, to_size) strncpy_s(to, to_size, from, _TRUNCATE)
#		endif
#		ifndef W_OK
#			define W_OK 02
#		endif
#		ifndef S_ISDIR
#			define S_ISDIR(x) ((x & _S_IFDIR) != 0)
#		endif
#		define p_snprintf(buf,sz,fmt,...) _snprintf_s(buf,sz,_TRUNCATE,fmt,__VA_ARGS__)
Vicent Marti committed
59
#	else
Russell Belfer committed
60 61 62 63 64 65 66 67
#		define p_snprintf snprintf
#	endif

#	ifndef PRIuZ
#		define PRIuZ "Iu"
#	endif
#	ifndef PRIxZ
#		define PRIxZ "Ix"
Vicent Marti committed
68
#	endif
Edward Thomson committed
69

70
#	if defined(_MSC_VER) || defined(__MINGW32__)
Edward Thomson committed
71 72
	typedef struct stat STAT_T;
#	else
Vicent Marti committed
73
	typedef struct _stat STAT_T;
Edward Thomson committed
74
#	endif
Vicent Marti committed
75 76 77 78
#else
#	include <sys/wait.h> /* waitpid(2) */
#	include <unistd.h>
#	define _MAIN_CC
Russell Belfer committed
79 80 81 82 83 84 85
#	define p_snprintf snprintf
#	ifndef PRIuZ
#		define PRIuZ "zu"
#	endif
#	ifndef PRIxZ
#		define PRIxZ "zx"
#	endif
Vicent Marti committed
86 87 88 89 90 91 92 93 94 95 96 97 98
	typedef struct stat STAT_T;
#endif

#include "clar.h"

static void fs_rm(const char *_source);
static void fs_copy(const char *_source, const char *dest);

static const char *
fixture_path(const char *base, const char *fixture_name);

struct clar_error {
	const char *file;
99
	const char *function;
100
	size_t line_number;
Vicent Marti committed
101 102 103 104 105 106
	const char *error_msg;
	char *description;

	struct clar_error *next;
};

107 108 109 110 111 112
struct clar_explicit {
	size_t suite_idx;
	const char *filter;

	struct clar_explicit *next;
};
Edward Thomson committed
113

Etienne Samson committed
114 115 116 117 118 119 120 121 122 123 124 125 126
struct clar_report {
	const char *test;
	int test_number;
	const char *suite;

	enum cl_test_status status;

	struct clar_error *errors;
	struct clar_error *last_error;

	struct clar_report *next;
};

127 128 129 130 131
struct clar_summary {
	const char *filename;
	FILE *fp;
};

132
static struct {
Vicent Marti committed
133
	enum cl_test_status test_status;
Etienne Samson committed
134

Vicent Marti committed
135 136 137
	const char *active_test;
	const char *active_suite;

Vicent Marti committed
138
	int total_skipped;
Vicent Marti committed
139 140 141 142 143
	int total_errors;

	int tests_ran;
	int suites_ran;

144 145
	enum cl_output_format output_format;

Vicent Marti committed
146 147
	int report_errors_only;
	int exit_on_error;
Russell Belfer committed
148
	int report_suite_names;
149

150
	int write_summary;
151
	char *summary_filename;
152
	struct clar_summary *summary;
Vicent Marti committed
153

154 155 156
	struct clar_explicit *explicit;
	struct clar_explicit *last_explicit;

Etienne Samson committed
157 158
	struct clar_report *reports;
	struct clar_report *last_report;
Vicent Marti committed
159 160 161 162 163 164

	void (*local_cleanup)(void *);
	void *local_cleanup_payload;

	jmp_buf trampoline;
	int trampoline_enabled;
165 166 167 168

	cl_trace_cb *pfn_trace_cb;
	void *trace_payload;

Vicent Marti committed
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
} _clar;

struct clar_func {
	const char *name;
	void (*ptr)(void);
};

struct clar_suite {
	const char *name;
	struct clar_func initialize;
	struct clar_func cleanup;
	const struct clar_func *tests;
	size_t test_count;
	int enabled;
};

/* From clar_print_*.c */
static void clar_print_init(int test_count, int suite_count, const char *suite_names);
static void clar_print_shutdown(int test_count, int suite_count, int error_count);
Etienne Samson committed
188
static void clar_print_error(int num, const struct clar_report *report, const struct clar_error *error);
Vicent Marti committed
189
static void clar_print_ontest(const char *test_name, int test_number, enum cl_test_status failed);
Vicent Marti committed
190 191 192 193 194 195 196
static void clar_print_onsuite(const char *suite_name, int suite_index);
static void clar_print_onabort(const char *msg, ...);

/* From clar_sandbox.c */
static void clar_unsandbox(void);
static int clar_sandbox(void);

197
/* From summary.h */
198 199
static struct clar_summary *clar_summary_init(const char *filename);
static int clar_summary_shutdown(struct clar_summary *fp);
200

Vicent Marti committed
201 202 203
/* Load the declarations for the test suite */
#include "clar.suite"

204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220

#define CL_TRACE(ev)													\
	do {																\
		if (_clar.pfn_trace_cb)											\
			_clar.pfn_trace_cb(ev,										\
							   _clar.active_suite,						\
							   _clar.active_test,						\
							   _clar.trace_payload);					\
	} while (0)

void cl_trace_register(cl_trace_cb *cb, void *payload)
{
	_clar.pfn_trace_cb = cb;
	_clar.trace_payload = payload;
}


Vicent Marti committed
221 222
/* Core test functions */
static void
223
clar_report_errors(struct clar_report *report)
Etienne Samson committed
224
{
225
	struct clar_error *error;
Etienne Samson committed
226
	int i = 1;
227 228 229

	for (error = report->errors; error; error = error->next)
		clar_print_error(i++, _clar.last_report, error);
Etienne Samson committed
230 231 232 233 234 235
}

static void
clar_report_all(void)
{
	struct clar_report *report;
236 237 238 239 240 241
	struct clar_error *error;
	int i = 1;

	for (report = _clar.reports; report; report = report->next) {
		if (report->status != CL_TEST_FAILURE)
			continue;
Etienne Samson committed
242

243 244
		for (error = report->errors; error; error = error->next)
			clar_print_error(i++, report, error);
Etienne Samson committed
245
	}
Vicent Marti committed
246 247 248 249 250 251 252 253 254 255
}

static void
clar_run_test(
	const struct clar_func *test,
	const struct clar_func *initialize,
	const struct clar_func *cleanup)
{
	_clar.trampoline_enabled = 1;

256 257
	CL_TRACE(CL_TRACE__TEST__BEGIN);

Vicent Marti committed
258 259 260 261
	if (setjmp(_clar.trampoline) == 0) {
		if (initialize->ptr != NULL)
			initialize->ptr();

262
		CL_TRACE(CL_TRACE__TEST__RUN_BEGIN);
Vicent Marti committed
263
		test->ptr();
264
		CL_TRACE(CL_TRACE__TEST__RUN_END);
Vicent Marti committed
265 266 267 268
	}

	_clar.trampoline_enabled = 0;

Etienne Samson committed
269 270 271
	if (_clar.last_report->status == CL_TEST_NOTRUN)
		_clar.last_report->status = CL_TEST_OK;

Vicent Marti committed
272 273 274 275 276 277
	if (_clar.local_cleanup != NULL)
		_clar.local_cleanup(_clar.local_cleanup_payload);

	if (cleanup->ptr != NULL)
		cleanup->ptr();

278 279
	CL_TRACE(CL_TRACE__TEST__END);

Vicent Marti committed
280 281 282 283 284 285
	_clar.tests_ran++;

	/* remove any local-set cleanup methods */
	_clar.local_cleanup = NULL;
	_clar.local_cleanup_payload = NULL;

Vicent Marti committed
286
	if (_clar.report_errors_only) {
287
		clar_report_errors(_clar.last_report);
Vicent Marti committed
288
	} else {
Etienne Samson committed
289
		clar_print_ontest(test->name, _clar.tests_ran, _clar.last_report->status);
Vicent Marti committed
290
	}
Vicent Marti committed
291 292 293
}

static void
294
clar_run_suite(const struct clar_suite *suite, const char *filter)
Vicent Marti committed
295 296
{
	const struct clar_func *test = suite->tests;
297
	size_t i, matchlen;
Etienne Samson committed
298
	struct clar_report *report;
299
	int exact = 0;
Vicent Marti committed
300 301 302 303 304 305 306 307 308 309 310

	if (!suite->enabled)
		return;

	if (_clar.exit_on_error && _clar.total_errors)
		return;

	if (!_clar.report_errors_only)
		clar_print_onsuite(suite->name, ++_clar.suites_ran);

	_clar.active_suite = suite->name;
311 312
	_clar.active_test = NULL;
	CL_TRACE(CL_TRACE__SUITE_BEGIN);
Vicent Marti committed
313

314
	if (filter) {
315
		size_t suitelen = strlen(suite->name);
316 317 318
		matchlen = strlen(filter);
		if (matchlen <= suitelen) {
			filter = NULL;
319
		} else {
320 321 322 323
			filter += suitelen;
			while (*filter == ':')
				++filter;
			matchlen = strlen(filter);
324 325 326 327 328

			if (matchlen && filter[matchlen - 1] == '$') {
				exact = 1;
				matchlen--;
			}
329 330 331
		}
	}

Vicent Marti committed
332
	for (i = 0; i < suite->test_count; ++i) {
333
		if (filter && strncmp(test[i].name, filter, matchlen))
334 335
			continue;

336 337 338
		if (exact && strlen(test[i].name) != matchlen)
			continue;

Vicent Marti committed
339
		_clar.active_test = test[i].name;
Etienne Samson committed
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354

		report = calloc(1, sizeof(struct clar_report));
		report->suite = _clar.active_suite;
		report->test = _clar.active_test;
		report->test_number = _clar.tests_ran;
		report->status = CL_TEST_NOTRUN;

		if (_clar.reports == NULL)
			_clar.reports = report;

		if (_clar.last_report != NULL)
			_clar.last_report->next = report;

		_clar.last_report = report;

Vicent Marti committed
355 356 357 358 359
		clar_run_test(&test[i], &suite->initialize, &suite->cleanup);

		if (_clar.exit_on_error && _clar.total_errors)
			return;
	}
360 361 362

	_clar.active_test = NULL;
	CL_TRACE(CL_TRACE__SUITE_END);
Vicent Marti committed
363 364 365 366 367 368 369
}

static void
clar_usage(const char *arg)
{
	printf("Usage: %s [options]\n\n", arg);
	printf("Options:\n");
370 371 372 373 374 375
	printf("  -sname        Run only the suite with `name` (can go to individual test name)\n");
	printf("  -iname        Include the suite with `name`\n");
	printf("  -xname        Exclude the suite with `name`\n");
	printf("  -v            Increase verbosity (show suite names)\n");
	printf("  -q            Only report tests that had an error\n");
	printf("  -Q            Quit as soon as a test fails\n");
Edward Thomson committed
376
	printf("  -t            Display results in tap format\n");
377 378
	printf("  -l            Print suite names\n");
	printf("  -r[filename]  Write summary file (to the optional filename)\n");
Vicent Marti committed
379 380 381 382 383 384 385 386
	exit(-1);
}

static void
clar_parse_args(int argc, char **argv)
{
	int i;

387
	/* Verify options before execute */
Vicent Marti committed
388 389 390
	for (i = 1; i < argc; ++i) {
		char *argument = argv[i];

391
		if (argument[0] != '-' || argument[1] == '\0'
Edward Thomson committed
392
		    || strchr("sixvqQtlr", argument[1]) == NULL) {
Vicent Marti committed
393
			clar_usage(argv[0]);
394 395 396 397 398
		}
	}

	for (i = 1; i < argc; ++i) {
		char *argument = argv[i];
Vicent Marti committed
399 400 401 402 403

		switch (argument[1]) {
		case 's':
		case 'i':
		case 'x': { /* given suite name */
Russell Belfer committed
404
			int offset = (argument[2] == '=') ? 3 : 2, found = 0;
Vicent Marti committed
405
			char action = argument[1];
406
			size_t j, arglen, suitelen, cmplen;
Vicent Marti committed
407 408

			argument += offset;
409
			arglen = strlen(argument);
Vicent Marti committed
410

411
			if (arglen == 0)
Vicent Marti committed
412 413 414
				clar_usage(argv[0]);

			for (j = 0; j < _clar_suite_count; ++j) {
415 416
				suitelen = strlen(_clar_suites[j].name);
				cmplen = (arglen < suitelen) ? arglen : suitelen;
417 418

				if (strncmp(argument, _clar_suites[j].name, cmplen) == 0) {
419
					int exact = (arglen >= suitelen);
Russell Belfer committed
420

421 422 423 424 425 426
					/* Do we have a real suite prefix separated by a
					 * trailing '::' or just a matching substring? */
					if (arglen > suitelen && (argument[suitelen] != ':'
						    || argument[suitelen + 1] != ':'))
					    continue;

Russell Belfer committed
427 428 429 430 431
					++found;

					if (!exact)
						_clar.report_suite_names = 1;

Vicent Marti committed
432
					switch (action) {
433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450
					case 's': {
						struct clar_explicit *explicit =
							calloc(1, sizeof(struct clar_explicit));
						assert(explicit);

						explicit->suite_idx = j;
						explicit->filter = argument;

						if (_clar.explicit == NULL)
							_clar.explicit = explicit;

						if (_clar.last_explicit != NULL)
							_clar.last_explicit->next = explicit;

						_clar_suites[j].enabled = 1;
						_clar.last_explicit = explicit;
						break;
					}
451 452
					case 'i': _clar_suites[j].enabled = 1; break;
					case 'x': _clar_suites[j].enabled = 0; break;
Vicent Marti committed
453
					}
Russell Belfer committed
454 455 456

					if (exact)
						break;
Vicent Marti committed
457 458 459
				}
			}

Russell Belfer committed
460
			if (!found) {
Vicent Marti committed
461 462 463 464 465 466 467 468 469 470 471 472 473 474
				clar_print_onabort("No suite matching '%s' found.\n", argument);
				exit(-1);
			}
			break;
		}

		case 'q':
			_clar.report_errors_only = 1;
			break;

		case 'Q':
			_clar.exit_on_error = 1;
			break;

Edward Thomson committed
475 476 477
		case 't':
			_clar.output_format = CL_OUTPUT_TAP;
			break;
Vicent Marti committed
478 479 480 481 482 483 484 485 486 487

		case 'l': {
			size_t j;
			printf("Test suites (use -s<name> to run just one):\n");
			for (j = 0; j < _clar_suite_count; ++j)
				printf(" %3d: %s\n", (int)j, _clar_suites[j].name);

			exit(0);
		}

Edward Thomson committed
488 489 490 491
		case 'v':
			_clar.report_suite_names = 1;
			break;

492 493
		case 'r':
			_clar.write_summary = 1;
494 495
			free(_clar.summary_filename);
			_clar.summary_filename = strdup(*(argument + 2) ? (argument + 2) : "summary.xml");
496 497
			break;

Vicent Marti committed
498
		default:
499
			assert(!"Unexpected commandline argument!");
Vicent Marti committed
500 501 502 503
		}
	}
}

Edward Thomson committed
504 505
void
clar_test_init(int argc, char **argv)
Vicent Marti committed
506
{
507 508 509
	if (argc > 1)
		clar_parse_args(argc, argv);

Vicent Marti committed
510 511 512 513 514 515
	clar_print_init(
		(int)_clar_callback_count,
		(int)_clar_suite_count,
		""
	);

516 517 518 519 520
	if ((_clar.summary_filename = getenv("CLAR_SUMMARY")) != NULL) {
		_clar.write_summary = 1;
		_clar.summary_filename = strdup(_clar.summary_filename);
	}

521 522 523
	if (_clar.write_summary &&
	    !(_clar.summary = clar_summary_init(_clar.summary_filename))) {
		clar_print_onabort("Failed to open the summary file\n");
524 525 526
		exit(-1);
	}

Vicent Marti committed
527 528 529 530
	if (clar_sandbox() < 0) {
		clar_print_onabort("Failed to sandbox the test runner.\n");
		exit(-1);
	}
Edward Thomson committed
531
}
Vicent Marti committed
532

Edward Thomson committed
533
int
534
clar_test_run(void)
Edward Thomson committed
535
{
536 537
	size_t i;
	struct clar_explicit *explicit;
Edward Thomson committed
538

539 540 541 542
	if (_clar.explicit) {
		for (explicit = _clar.explicit; explicit; explicit = explicit->next)
			clar_run_suite(&_clar_suites[explicit->suite_idx], explicit->filter);
	} else {
Vicent Marti committed
543
		for (i = 0; i < _clar_suite_count; ++i)
544
			clar_run_suite(&_clar_suites[i], NULL);
Vicent Marti committed
545 546
	}

Edward Thomson committed
547 548 549 550
	return _clar.total_errors;
}

void
551
clar_test_shutdown(void)
Edward Thomson committed
552
{
553
	struct clar_explicit *explicit, *explicit_next;
Etienne Samson committed
554
	struct clar_report *report, *report_next;
555

Vicent Marti committed
556 557 558 559 560 561 562
	clar_print_shutdown(
		_clar.tests_ran,
		(int)_clar_suite_count,
		_clar.total_errors
	);

	clar_unsandbox();
563

564 565 566 567
	if (_clar.write_summary && clar_summary_shutdown(_clar.summary) < 0) {
		clar_print_onabort("Failed to write the summary file\n");
		exit(-1);
	}
568

569 570 571 572
	for (explicit = _clar.explicit; explicit; explicit = explicit_next) {
		explicit_next = explicit->next;
		free(explicit);
	}
Etienne Samson committed
573 574 575 576 577

	for (report = _clar.reports; report; report = report_next) {
		report_next = report->next;
		free(report);
	}
578 579

	free(_clar.summary_filename);
Edward Thomson committed
580 581 582 583 584 585 586 587 588 589 590 591
}

int
clar_test(int argc, char **argv)
{
	int errors;

	clar_test_init(argc, argv);
	errors = clar_test_run();
	clar_test_shutdown();

	return errors;
Vicent Marti committed
592 593
}

Vicent Marti committed
594 595 596 597 598
static void abort_test(void)
{
	if (!_clar.trampoline_enabled) {
		clar_print_onabort(
				"Fatal error: a cleanup method raised an exception.");
599
		clar_report_errors(_clar.last_report);
Vicent Marti committed
600 601 602
		exit(-1);
	}

603
	CL_TRACE(CL_TRACE__TEST__LONGJMP);
Vicent Marti committed
604 605 606 607 608
	longjmp(_clar.trampoline, -1);
}

void clar__skip(void)
{
Etienne Samson committed
609
	_clar.last_report->status = CL_TEST_SKIP;
Vicent Marti committed
610 611 612 613
	_clar.total_skipped++;
	abort_test();
}

Russell Belfer committed
614
void clar__fail(
Vicent Marti committed
615
	const char *file,
616
	const char *function,
617
	size_t line,
Vicent Marti committed
618 619 620 621
	const char *error_msg,
	const char *description,
	int should_abort)
{
Russell Belfer committed
622
	struct clar_error *error = calloc(1, sizeof(struct clar_error));
Vicent Marti committed
623

Etienne Samson committed
624 625
	if (_clar.last_report->errors == NULL)
		_clar.last_report->errors = error;
Vicent Marti committed
626

Etienne Samson committed
627 628
	if (_clar.last_report->last_error != NULL)
		_clar.last_report->last_error->next = error;
Vicent Marti committed
629

Etienne Samson committed
630
	_clar.last_report->last_error = error;
Vicent Marti committed
631 632

	error->file = file;
633
	error->function = function;
Vicent Marti committed
634 635 636 637 638 639 640
	error->line_number = line;
	error->error_msg = error_msg;

	if (description != NULL)
		error->description = strdup(description);

	_clar.total_errors++;
Etienne Samson committed
641
	_clar.last_report->status = CL_TEST_FAILURE;
Vicent Marti committed
642

Vicent Marti committed
643 644
	if (should_abort)
		abort_test();
Vicent Marti committed
645 646
}

Russell Belfer committed
647 648 649
void clar__assert(
	int condition,
	const char *file,
650
	const char *function,
651
	size_t line,
Russell Belfer committed
652 653 654 655 656 657 658
	const char *error_msg,
	const char *description,
	int should_abort)
{
	if (condition)
		return;

659
	clar__fail(file, function, line, error_msg, description, should_abort);
Russell Belfer committed
660 661
}

Russell Belfer committed
662
void clar__assert_equal(
Vicent Marti committed
663
	const char *file,
664
	const char *function,
665
	size_t line,
Vicent Marti committed
666
	const char *err,
Russell Belfer committed
667 668 669
	int should_abort,
	const char *fmt,
	...)
Vicent Marti committed
670
{
Russell Belfer committed
671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693
	va_list args;
	char buf[4096];
	int is_equal = 1;

	va_start(args, fmt);

	if (!strcmp("%s", fmt)) {
		const char *s1 = va_arg(args, const char *);
		const char *s2 = va_arg(args, const char *);
		is_equal = (!s1 || !s2) ? (s1 == s2) : !strcmp(s1, s2);

		if (!is_equal) {
			if (s1 && s2) {
				int pos;
				for (pos = 0; s1[pos] == s2[pos] && s1[pos] && s2[pos]; ++pos)
					/* find differing byte offset */;
				p_snprintf(buf, sizeof(buf), "'%s' != '%s' (at byte %d)",
					s1, s2, pos);
			} else {
				p_snprintf(buf, sizeof(buf), "'%s' != '%s'", s1, s2);
			}
		}
	}
Edward Thomson committed
694 695 696
	else if(!strcmp("%.*s", fmt)) {
		const char *s1 = va_arg(args, const char *);
		const char *s2 = va_arg(args, const char *);
Edward Thomson committed
697
		int len = va_arg(args, int);
Edward Thomson committed
698 699 700 701
		is_equal = (!s1 || !s2) ? (s1 == s2) : !strncmp(s1, s2, len);

		if (!is_equal) {
			if (s1 && s2) {
Edward Thomson committed
702
				int pos;
Edward Thomson committed
703 704 705 706 707 708 709 710 711
				for (pos = 0; s1[pos] == s2[pos] && pos < len; ++pos)
					/* find differing byte offset */;
				p_snprintf(buf, sizeof(buf), "'%.*s' != '%.*s' (at byte %d)",
					len, s1, len, s2, pos);
			} else {
				p_snprintf(buf, sizeof(buf), "'%.*s' != '%.*s'", len, s1, len, s2);
			}
		}
	}
712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746
	else if (!strcmp("%ls", fmt)) {
		const wchar_t *wcs1 = va_arg(args, const wchar_t *);
		const wchar_t *wcs2 = va_arg(args, const wchar_t *);
		is_equal = (!wcs1 || !wcs2) ? (wcs1 == wcs2) : !wcscmp(wcs1, wcs2);

		if (!is_equal) {
			if (wcs1 && wcs2) {
				int pos;
				for (pos = 0; wcs1[pos] == wcs2[pos] && wcs1[pos] && wcs2[pos]; ++pos)
					/* find differing byte offset */;
				p_snprintf(buf, sizeof(buf), "'%ls' != '%ls' (at byte %d)",
					wcs1, wcs2, pos);
			} else {
				p_snprintf(buf, sizeof(buf), "'%ls' != '%ls'", wcs1, wcs2);
			}
		}
	}
	else if(!strcmp("%.*ls", fmt)) {
		const wchar_t *wcs1 = va_arg(args, const wchar_t *);
		const wchar_t *wcs2 = va_arg(args, const wchar_t *);
		int len = va_arg(args, int);
		is_equal = (!wcs1 || !wcs2) ? (wcs1 == wcs2) : !wcsncmp(wcs1, wcs2, len);

		if (!is_equal) {
			if (wcs1 && wcs2) {
				int pos;
				for (pos = 0; wcs1[pos] == wcs2[pos] && pos < len; ++pos)
					/* find differing byte offset */;
				p_snprintf(buf, sizeof(buf), "'%.*ls' != '%.*ls' (at byte %d)",
					len, wcs1, len, wcs2, pos);
			} else {
				p_snprintf(buf, sizeof(buf), "'%.*ls' != '%.*ls'", len, wcs1, len, wcs2);
			}
		}
	}
747
	else if (!strcmp("%"PRIuZ, fmt) || !strcmp("%"PRIxZ, fmt)) {
Russell Belfer committed
748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768
		size_t sz1 = va_arg(args, size_t), sz2 = va_arg(args, size_t);
		is_equal = (sz1 == sz2);
		if (!is_equal) {
			int offset = p_snprintf(buf, sizeof(buf), fmt, sz1);
			strncat(buf, " != ", sizeof(buf) - offset);
			p_snprintf(buf + offset + 4, sizeof(buf) - offset - 4, fmt, sz2);
		}
	}
	else if (!strcmp("%p", fmt)) {
		void *p1 = va_arg(args, void *), *p2 = va_arg(args, void *);
		is_equal = (p1 == p2);
		if (!is_equal)
			p_snprintf(buf, sizeof(buf), "%p != %p", p1, p2);
	}
	else {
		int i1 = va_arg(args, int), i2 = va_arg(args, int);
		is_equal = (i1 == i2);
		if (!is_equal) {
			int offset = p_snprintf(buf, sizeof(buf), fmt, i1);
			strncat(buf, " != ", sizeof(buf) - offset);
			p_snprintf(buf + offset + 4, sizeof(buf) - offset - 4, fmt, i2);
769
		}
Vicent Marti committed
770 771
	}

Russell Belfer committed
772 773 774
	va_end(args);

	if (!is_equal)
775
		clar__fail(file, function, line, err, buf, should_abort);
Vicent Marti committed
776 777 778 779 780 781 782 783 784 785 786 787
}

void cl_set_cleanup(void (*cleanup)(void *), void *opaque)
{
	_clar.local_cleanup = cleanup;
	_clar.local_cleanup_payload = opaque;
}

#include "clar/sandbox.h"
#include "clar/fixtures.h"
#include "clar/fs.h"
#include "clar/print.h"
788
#include "clar/summary.h"