• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2015 Samsung Electronics Co., Ltd
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files (the
6  * "Software"), to deal in the Software without restriction, including
7  * without limitation the rights to use, copy, modify, merge, publish,
8  * distribute, sublicense, and/or sell copies of the Software, and to
9  * permit persons to whom the Software is furnished to do so, subject to
10  * the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the
13  * next paragraph) shall be included in all copies or substantial
14  * portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24  */
25 
26 #include "config.h"
27 
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <stdarg.h>
31 #include <stdbool.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <sys/types.h>
36 #include <sys/wait.h>
37 #include <time.h>
38 #include <unistd.h>
39 
40 #include "zunitc/zunitc_impl.h"
41 #include "zunitc/zunitc.h"
42 
43 #include "zuc_base_logger.h"
44 #include "zuc_collector.h"
45 #include "zuc_context.h"
46 #include "zuc_event_listener.h"
47 #include "zuc_junit_reporter.h"
48 
49 #include <libweston/config-parser.h>
50 #include "shared/helpers.h"
51 #include <libweston/zalloc.h>
52 
53 /*
54  * If CLOCK_MONOTONIC is present on the system it will give us reliable
55  * results under certain edge conditions that normally require manual
56  * admin actions to trigger. If not, CLOCK_REALTIME is a reasonable
57  * fallback.
58  */
59 #if _POSIX_MONOTONIC_CLOCK
60 static const clockid_t TARGET_TIMER = CLOCK_MONOTONIC;
61 #else
62 static const clockid_t TARGET_TIMER = CLOCK_REALTIME;
63 #endif
64 
65 static char const DISABLED_PREFIX[] = "DISABLED_";
66 
67 #define MS_PER_SEC 1000L
68 #define NANO_PER_MS 1000000L
69 
70 /**
71  * Simple single-linked list structure.
72  */
73 struct zuc_slinked {
74 	void *data;
75 	struct zuc_slinked *next;
76 };
77 
78 static struct zuc_context g_ctx = {
79 	.case_count = 0,
80 	.cases = NULL,
81 
82 	.fatal = false,
83 	.repeat = 0,
84 	.random = 0,
85 	.spawn = true,
86 	.break_on_failure = false,
87 	.fds = {-1, -1},
88 
89 	.listeners = NULL,
90 
91 	.curr_case = NULL,
92 	.curr_test = NULL,
93 };
94 
95 static char *g_progname = NULL;
96 static char *g_progbasename = NULL;
97 
98 typedef int (*comp_pred2)(intptr_t lhs, intptr_t rhs);
99 
100 static bool
test_has_skip(struct zuc_test * test)101 test_has_skip(struct zuc_test *test)
102 {
103 	return test->skipped;
104 }
105 
106 static bool
test_has_failure(struct zuc_test * test)107 test_has_failure(struct zuc_test *test)
108 {
109 	return test->fatal || test->failed;
110 }
111 
112 bool
zuc_has_skip(void)113 zuc_has_skip(void)
114 {
115 	return g_ctx.curr_test ?
116 		test_has_skip(g_ctx.curr_test) : false;
117 }
118 
119 bool
zuc_has_failure(void)120 zuc_has_failure(void)
121 {
122 	return g_ctx.curr_test ?
123 		test_has_failure(g_ctx.curr_test) : false;
124 }
125 
126 void
zuc_set_filter(const char * filter)127 zuc_set_filter(const char *filter)
128 {
129 	g_ctx.filter = strdup(filter);
130 }
131 
132 void
zuc_set_repeat(int repeat)133 zuc_set_repeat(int repeat)
134 {
135 	g_ctx.repeat = repeat;
136 }
137 
138 void
zuc_set_random(int random)139 zuc_set_random(int random)
140 {
141 	g_ctx.random = random;
142 }
143 
144 void
zuc_set_spawn(bool spawn)145 zuc_set_spawn(bool spawn)
146 {
147 	g_ctx.spawn = spawn;
148 }
149 
150 void
zuc_set_break_on_failure(bool break_on_failure)151 zuc_set_break_on_failure(bool break_on_failure)
152 {
153 	g_ctx.break_on_failure = break_on_failure;
154 }
155 
156 void
zuc_set_output_junit(bool enable)157 zuc_set_output_junit(bool enable)
158 {
159 	g_ctx.output_junit = enable;
160 }
161 
162 const char *
zuc_get_program_name(void)163 zuc_get_program_name(void)
164 {
165 	return g_progname;
166 }
167 
168 const char *
zuc_get_program_basename(void)169 zuc_get_program_basename(void)
170 {
171 	return g_progbasename;
172 }
173 
174 static struct zuc_test *
create_test(int order,zucimpl_test_fn fn,zucimpl_test_fn_f fn_f,char const * case_name,char const * test_name,struct zuc_case * parent)175 create_test(int order, zucimpl_test_fn fn, zucimpl_test_fn_f fn_f,
176 	    char const *case_name, char const *test_name,
177 	    struct zuc_case *parent)
178 {
179 	struct zuc_test *test = zalloc(sizeof(struct zuc_test));
180 	ZUC_ASSERTG_NOT_NULL(test, out);
181 	test->order = order;
182 	test->fn = fn;
183 	test->fn_f = fn_f;
184 	test->name = strdup(test_name);
185 	if ((!fn && !fn_f) ||
186 	    (strncmp(DISABLED_PREFIX,
187 		     test_name, sizeof(DISABLED_PREFIX) - 1) == 0))
188 		test->disabled = 1;
189 
190 	test->test_case = parent;
191 
192 out:
193 	return test;
194 }
195 
196 static int
compare_regs(const void * lhs,const void * rhs)197 compare_regs(const void *lhs, const void *rhs)
198 {
199 	int rc = strcmp((*(struct zuc_registration **)lhs)->tcase,
200 		      (*(struct zuc_registration **)rhs)->tcase);
201 	if (rc == 0)
202 		rc = strcmp((*(struct zuc_registration **)lhs)->test,
203 		      (*(struct zuc_registration **)rhs)->test);
204 
205 	return rc;
206 }
207 
208 /* gcc-specific markers for auto test case registration: */
209 extern const struct zuc_registration __start_zuc_tsect;
210 extern const struct zuc_registration __stop_zuc_tsect;
211 
212 static void
register_tests(void)213 register_tests(void)
214 {
215 	size_t case_count = 0;
216 	size_t count = &__stop_zuc_tsect - &__start_zuc_tsect;
217 	size_t i;
218 	int idx = 0;
219 	const char *last_name = NULL;
220 	void **array = zalloc(sizeof(void *) * count);
221 	ZUC_ASSERT_NOT_NULL(array);
222 	for (i = 0; i < count; ++i)
223 		array[i] = (void *)(&__start_zuc_tsect + i);
224 
225 	qsort(array, count, sizeof(array[0]), compare_regs);
226 
227 	/* Count transitions to get number of test cases. */
228 	last_name = NULL;
229 	for (i = 0; i < count; ++i) {
230 		const struct zuc_registration *reg =
231 			(const struct zuc_registration *)array[i];
232 		if (!last_name || (strcmp(last_name, reg->tcase))) {
233 			last_name = reg->tcase;
234 			case_count++;
235 		}
236 	}
237 
238 	/* Create test case data items. */
239 	struct zuc_case **case_array =
240 		zalloc(sizeof(struct zuc_case *) * case_count);
241 	ZUC_ASSERT_NOT_NULL(case_array);
242 	struct zuc_case *last_case = NULL;
243 	size_t case_num = 0;
244 	for (i = 0; i < count; ++i) {
245 		const struct zuc_registration *reg =
246 			(const struct zuc_registration *)array[i];
247 		if (!last_case || (strcmp(last_case->name, reg->tcase))) {
248 			last_case = zalloc(sizeof(struct zuc_case));
249 			ZUC_ASSERT_NOT_NULL(last_case);
250 			last_case->order = count;
251 			last_case->name = strdup(reg->tcase);
252 			last_case->fxt = reg->fxt;
253 			last_case->test_count = i;
254 			if (case_num > 0) {
255 				int tcount = i
256 					- case_array[case_num - 1]->test_count;
257 				case_array[case_num - 1]->test_count = tcount;
258 			}
259 			case_array[case_num++] = last_case;
260 		}
261 	}
262 	case_array[case_count - 1]->test_count = count
263 		- case_array[case_count - 1]->test_count;
264 
265 	/* Reserve space for tests per test case. */
266 	for (case_num = 0; case_num < case_count; ++case_num) {
267 		case_array[case_num]->tests =
268 			zalloc(case_array[case_num]->test_count
269 			       * sizeof(struct zuc_test *));
270 		ZUC_ASSERT_NOT_NULL(case_array[case_num]->tests);
271 	}
272 
273 	last_name = NULL;
274 	case_num = -1;
275 	for (i = 0; i < count; ++i) {
276 		const struct zuc_registration *reg =
277 			(const struct zuc_registration *)array[i];
278 		int order = count - (1 + (reg - &__start_zuc_tsect));
279 
280 		if (!last_name || (strcmp(last_name, reg->tcase))) {
281 			last_name = reg->tcase;
282 			case_num++;
283 			idx = 0;
284 		}
285 		if (order < case_array[case_num]->order)
286 			case_array[case_num]->order = order;
287 		case_array[case_num]->tests[idx] =
288 			create_test(order, reg->fn, reg->fn_f,
289 				    reg->tcase, reg->test,
290 				    case_array[case_num]);
291 
292 		if (case_array[case_num]->fxt != reg->fxt)
293 			printf("%s:%d: error: Mismatched fixtures for '%s'\n",
294 			       __FILE__, __LINE__, case_array[case_num]->name);
295 
296 		idx++;
297 	}
298 	free(array);
299 
300 	g_ctx.case_count = case_count;
301 	g_ctx.cases = case_array;
302 }
303 
304 static int
compare_case_order(const void * lhs,const void * rhs)305 compare_case_order(const void *lhs, const void *rhs)
306 {
307 	return (*(struct zuc_case **)lhs)->order
308 		- (*(struct zuc_case **)rhs)->order;
309 }
310 
311 static int
compare_test_order(const void * lhs,const void * rhs)312 compare_test_order(const void *lhs, const void *rhs)
313 {
314 	return (*(struct zuc_test **)lhs)->order
315 		- (*(struct zuc_test **)rhs)->order;
316 }
317 
318 static void
order_cases(int count,struct zuc_case ** cases)319 order_cases(int count, struct zuc_case **cases)
320 {
321 	int i;
322 	qsort(cases, count, sizeof(*cases), compare_case_order);
323 	for (i = 0; i < count; ++i) {
324 		qsort(cases[i]->tests, cases[i]->test_count,
325 		      sizeof(*cases[i]->tests), compare_test_order);
326 	}
327 }
328 
329 static void
free_events(struct zuc_event ** events)330 free_events(struct zuc_event **events)
331 {
332 	struct zuc_event *evt = *events;
333 	*events = NULL;
334 	while (evt) {
335 		struct zuc_event *old = evt;
336 		evt = evt->next;
337 		free(old->file);
338 		if (old->valtype == ZUC_VAL_CSTR) {
339 			free((void *)old->val1);
340 			free((void *)old->val2);
341 		}
342 		free(old->expr1);
343 		free(old->expr2);
344 		free(old);
345 	}
346 }
347 
348 static void
free_test(struct zuc_test * test)349 free_test(struct zuc_test *test)
350 {
351 	free(test->name);
352 	free_events(&test->events);
353 	free_events(&test->deferred);
354 	free(test);
355 }
356 
357 static void
free_test_case(struct zuc_case * test_case)358 free_test_case(struct zuc_case *test_case)
359 {
360 	int i;
361 	free(test_case->name);
362 	for (i = test_case->test_count - 1; i >= 0; --i) {
363 		free_test(test_case->tests[i]);
364 		test_case->tests[i] = NULL;
365 	}
366 	free(test_case->tests);
367 	free(test_case);
368 }
369 
370 /**
371  * A very simple matching that is compatible with the algorithm used in
372  * Google Test.
373  *
374  * @param wildcard sequence of '?', '*' or normal characters to match.
375  * @param str string to check for matching.
376  * @return true if the wildcard matches the entire string, false otherwise.
377  */
378 static bool
wildcard_matches(char const * wildcard,char const * str)379 wildcard_matches(char const *wildcard, char const *str)
380 {
381 	switch (*wildcard) {
382 	case '\0':
383 		return !*str;
384 	case '?':
385 		return *str && wildcard_matches(wildcard + 1, str + 1);
386 	case '*':
387 		return (*str && wildcard_matches(wildcard, str + 1))
388 			|| wildcard_matches(wildcard + 1, str);
389 	default:
390 		return (*wildcard == *str)
391 			&& wildcard_matches(wildcard + 1, str + 1);
392 	};
393 }
394 
395 static char**
segment_str(char * str)396 segment_str(char *str)
397 {
398 	int count = 1;
399 	char **parts = NULL;
400 	char *saved = NULL;
401 	char *tok = NULL;
402 	int i = 0;
403 	for (i = 0; str[i]; ++i)
404 		if (str[i] == ':')
405 			count++;
406 	parts = zalloc(sizeof(char*) * (count + 1));
407 	ZUC_ASSERTG_NOT_NULL(parts, out);
408 	tok = strtok_r(str, ":", &saved);
409 	i = 0;
410 	parts[i++] = tok;
411 	while (tok) {
412 		tok = strtok_r(NULL, ":", &saved);
413 		parts[i++] = tok;
414 	}
415 out:
416 	return parts;
417 }
418 
419 static void
filter_cases(int * count,struct zuc_case ** cases,char const * filter)420 filter_cases(int *count, struct zuc_case **cases, char const *filter)
421 {
422 	int i = 0;
423 	int j = 0;
424 	int num_pos = 0;
425 	int negative = -1;
426 	char *buf = strdup(filter);
427 	char **parts = segment_str(buf);
428 
429 	for (i = 0; parts[i]; ++i) {
430 		if (parts[i][0] == '-') {
431 			parts[i]++;
432 			negative = i;
433 			break;
434 		}
435 		num_pos++;
436 	}
437 
438 	for (i = 0; i < *count; ++i) {
439 		/* Walk backwards for easier pruning. */
440 		for (j = cases[i]->test_count - 1; j >= 0; --j) {
441 			int x;
442 			bool keep = num_pos == 0;
443 			char *name = NULL;
444 			struct zuc_test *test = cases[i]->tests[j];
445 			if (asprintf(&name, "%s.%s", cases[i]->name,
446 				     test->name) < 0) {
447 				printf("%s:%d: error: %d\n", __FILE__, __LINE__,
448 				       errno);
449 				exit(EXIT_FAILURE);
450 			}
451 			for (x = 0; (x < num_pos) && !keep; ++x)
452 				keep = wildcard_matches(parts[x], name);
453 			if (keep && (negative >= 0))
454 				for (x = negative; parts[x] && keep; ++x)
455 					keep &= !wildcard_matches(parts[x],
456 								  name);
457 			if (!keep) {
458 				int w;
459 				free_test(test);
460 				for (w = j + 1; w < cases[i]->test_count; w++)
461 					cases[i]->tests[w - 1] =
462 						cases[i]->tests[w];
463 				cases[i]->test_count--;
464 			}
465 
466 			free(name);
467 		}
468 	}
469 	free(parts);
470 	parts = NULL;
471 	free(buf);
472 	buf = NULL;
473 
474 	/* Prune any cases with no more tests. */
475 	for (i = *count - 1; i >= 0; --i) {
476 		if (cases[i]->test_count < 1) {
477 			free_test_case(cases[i]);
478 			for (j = i + 1; j < *count; ++j)
479 				cases[j - 1] = cases[j];
480 			cases[*count - 1] = NULL;
481 			(*count)--;
482 		}
483 	}
484 }
485 
486 static unsigned int
get_seed_from_time(void)487 get_seed_from_time(void)
488 {
489 	time_t sec = time(NULL);
490 	unsigned int seed = (unsigned int) sec % 100000;
491 	if (seed < 2)
492 		seed = 2;
493 
494 	return seed;
495 }
496 
497 static void
initialize(void)498 initialize(void)
499 {
500 	static bool init = false;
501 	if (init)
502 		return;
503 
504 	init = true;
505 	register_tests();
506 	if (g_ctx.fatal)
507 		return;
508 
509 	if (g_ctx.random > 1) {
510 		g_ctx.seed = g_ctx.random;
511 	} else if (g_ctx.random == 1) {
512 		g_ctx.seed = get_seed_from_time();
513 	}
514 
515 	if (g_ctx.case_count) {
516 		order_cases(g_ctx.case_count, g_ctx.cases);
517 		if (g_ctx.filter && g_ctx.filter[0])
518 			filter_cases(&g_ctx.case_count, g_ctx.cases,
519 				     g_ctx.filter);
520 	}
521 }
522 
523 int
zuc_initialize(int * argc,char * argv[],bool * help_flagged)524 zuc_initialize(int *argc, char *argv[], bool *help_flagged)
525 {
526 	int rc = EXIT_FAILURE;
527 	bool opt_help = false;
528 	bool opt_nofork = false;
529 	bool opt_list = false;
530 	int opt_repeat = 0;
531 	int opt_random = 0;
532 	bool opt_break_on_failure = false;
533 	bool opt_junit = false;
534 	char *opt_filter = NULL;
535 
536 	char *help_param = NULL;
537 	int argc_in = *argc;
538 
539 	const struct weston_option options[] = {
540 		{ WESTON_OPTION_BOOLEAN, "zuc-nofork", 0, &opt_nofork },
541 		{ WESTON_OPTION_BOOLEAN, "zuc-list-tests", 0, &opt_list },
542 		{ WESTON_OPTION_INTEGER, "zuc-repeat", 0, &opt_repeat },
543 		{ WESTON_OPTION_INTEGER, "zuc-random", 0, &opt_random },
544 		{ WESTON_OPTION_BOOLEAN, "zuc-break-on-failure", 0,
545 		  &opt_break_on_failure },
546 #if ENABLE_JUNIT_XML
547 		{ WESTON_OPTION_BOOLEAN, "zuc-output-xml", 0, &opt_junit },
548 #endif
549 		{ WESTON_OPTION_STRING, "zuc-filter", 0, &opt_filter },
550 	};
551 
552 	/*
553 	 *If a test binary is linked to our libzunitcmain it might want
554 	 * to access the program 'name' from argv[0]
555 	 */
556 	free(g_progname);
557 	g_progname = NULL;
558 	free(g_progbasename);
559 	g_progbasename = NULL;
560 	if ((*argc > 0) && argv) {
561 		char *path = NULL;
562 		char *base = NULL;
563 
564 		g_progname = strdup(argv[0]);
565 
566 		/* basename() might modify the input, so needs a writeable
567 		 * string.
568 		 * It also may return a statically allocated buffer subject to
569 		 * being overwritten so needs to be dup'd.
570 		 */
571 		path = strdup(g_progname);
572 		base = basename(path);
573 		g_progbasename = strdup(base);
574 		free(path);
575 	} else {
576 		g_progname = strdup("");
577 		printf("%s:%d: warning: No valid argv[0] for initialization\n",
578 		       __FILE__, __LINE__);
579 	}
580 
581 
582 	initialize();
583 	if (g_ctx.fatal)
584 		return EXIT_FAILURE;
585 
586 	if (help_flagged)
587 		*help_flagged = false;
588 
589 	{
590 		/* Help param will be a special case and need restoring. */
591 		int i = 0;
592 		char **argv_in = NULL;
593 		const struct weston_option help_options[] = {
594 			{ WESTON_OPTION_BOOLEAN, "help", 'h', &opt_help },
595 		};
596 		argv_in = zalloc(sizeof(char *) * argc_in);
597 		if (!argv_in) {
598 			printf("%s:%d: error: alloc failed.\n",
599 			       __FILE__, __LINE__);
600 			return EXIT_FAILURE;
601 		}
602 		for (i = 0; i < argc_in; ++i)
603 			argv_in[i] = argv[i];
604 
605 		parse_options(help_options, ARRAY_LENGTH(help_options),
606 			      argc, argv);
607 		if (*argc < argc_in) {
608 			for (i = 1; (i < argc_in) && !help_param; ++i) {
609 				bool found = false;
610 				int j = 0;
611 				for (j = 0; (j < *argc) && !found; ++j)
612 					found = (argv[j] == argv_in[i]);
613 
614 				if (!found)
615 					help_param = argv_in[i];
616 			}
617 		}
618 		free(argv_in);
619 	}
620 
621 	parse_options(options, ARRAY_LENGTH(options), argc, argv);
622 
623 	if (help_param && (*argc < argc_in))
624 		argv[(*argc)++] = help_param;
625 
626 	if (opt_filter) {
627 		zuc_set_filter(opt_filter);
628 		free(opt_filter);
629 	}
630 
631 	if (opt_help) {
632 		printf("Usage: %s [OPTIONS]\n"
633 		       "  --zuc-break-on-failure\n"
634 		       "  --zuc-filter=FILTER\n"
635 		       "  --zuc-list-tests\n"
636 		       "  --zuc-nofork\n"
637 #if ENABLE_JUNIT_XML
638 		       "  --zuc-output-xml\n"
639 #endif
640 		       "  --zuc-random=N            [0|1|<seed number>]\n"
641 		       "  --zuc-repeat=N\n"
642 		       "  --help\n",
643 		       argv[0]);
644 		if (help_flagged)
645 			*help_flagged = true;
646 		rc = EXIT_SUCCESS;
647 	} else if (opt_list) {
648 		zuc_list_tests();
649 		rc = EXIT_FAILURE;
650 	} else {
651 		zuc_set_repeat(opt_repeat);
652 		zuc_set_random(opt_random);
653 		zuc_set_spawn(!opt_nofork);
654 		zuc_set_break_on_failure(opt_break_on_failure);
655 		zuc_set_output_junit(opt_junit);
656 		rc = EXIT_SUCCESS;
657 	}
658 
659 	return rc;
660 }
661 
662 static void
dispatch_pre_run(struct zuc_context * ctx,int pass_count,int pass_num,int seed,const char * filter)663 dispatch_pre_run(struct zuc_context *ctx, int pass_count, int pass_num,
664 		 int seed, const char *filter)
665 {
666 	struct zuc_slinked *curr;
667 	for (curr = ctx->listeners; curr; curr = curr->next) {
668 		struct zuc_event_listener *listener = curr->data;
669 		if (listener->pre_run)
670 			listener->pre_run(listener->data,
671 					  pass_count,
672 					  pass_num,
673 					  seed,
674 					  filter);
675 	}
676 }
677 
678 static void
dispatch_run_started(struct zuc_context * ctx,int live_case_count,int live_test_count,int disabled_count)679 dispatch_run_started(struct zuc_context *ctx, int live_case_count,
680 		     int live_test_count, int disabled_count)
681 {
682 	struct zuc_slinked *curr;
683 	for (curr = ctx->listeners; curr; curr = curr->next) {
684 		struct zuc_event_listener *listener = curr->data;
685 		if (listener->run_started)
686 			listener->run_started(listener->data,
687 					      live_case_count,
688 					      live_test_count,
689 					      disabled_count);
690 	}
691 }
692 
693 static void
dispatch_run_ended(struct zuc_context * ctx,int live_case_count,int live_test_count,int total_passed,int total_failed,int total_disabled,long total_elapsed)694 dispatch_run_ended(struct zuc_context *ctx,
695 		   int live_case_count, int live_test_count, int total_passed,
696 		   int total_failed, int total_disabled, long total_elapsed)
697 {
698 	struct zuc_slinked *curr;
699 	for (curr = ctx->listeners; curr; curr = curr->next) {
700 		struct zuc_event_listener *listener = curr->data;
701 		if (listener->run_ended)
702 			listener->run_ended(listener->data,
703 					    ctx->case_count,
704 					    ctx->cases,
705 					    live_case_count,
706 					    live_test_count,
707 					    total_passed,
708 					    total_failed,
709 					    total_disabled,
710 					    total_elapsed);
711 	}
712 }
713 
714 static void
dispatch_case_started(struct zuc_context * ctx,struct zuc_case * test_case,int live_test_count,int disabled_count)715 dispatch_case_started(struct zuc_context *ctx,struct zuc_case *test_case,
716 		      int live_test_count, int disabled_count)
717 {
718 	struct zuc_slinked *curr;
719 	for (curr = ctx->listeners; curr; curr = curr->next) {
720 		struct zuc_event_listener *listener = curr->data;
721 		if (listener->case_started)
722 			listener->case_started(listener->data,
723 					       test_case,
724 					       live_test_count,
725 					       disabled_count);
726 	}
727 }
728 
729 static void
dispatch_case_ended(struct zuc_context * ctx,struct zuc_case * test_case)730 dispatch_case_ended(struct zuc_context *ctx, struct zuc_case *test_case)
731 {
732 	struct zuc_slinked *curr;
733 	for (curr = ctx->listeners; curr; curr = curr->next) {
734 		struct zuc_event_listener *listener = curr->data;
735 		if (listener->case_ended)
736 			listener->case_ended(listener->data, test_case);
737 	}
738 }
739 
740 static void
dispatch_test_started(struct zuc_context * ctx,struct zuc_test * test)741 dispatch_test_started(struct zuc_context *ctx, struct zuc_test *test)
742 {
743 	struct zuc_slinked *curr;
744 	for (curr = ctx->listeners; curr; curr = curr->next) {
745 		struct zuc_event_listener *listener = curr->data;
746 		if (listener->test_started)
747 			listener->test_started(listener->data, test);
748 	}
749 }
750 
751 static void
dispatch_test_ended(struct zuc_context * ctx,struct zuc_test * test)752 dispatch_test_ended(struct zuc_context *ctx, struct zuc_test *test)
753 {
754 	struct zuc_slinked *curr;
755 	for (curr = ctx->listeners; curr; curr = curr->next) {
756 		struct zuc_event_listener *listener = curr->data;
757 		if (listener->test_ended)
758 			listener->test_ended(listener->data, test);
759 	}
760 }
761 
762 static void
dispatch_test_disabled(struct zuc_context * ctx,struct zuc_test * test)763 dispatch_test_disabled(struct zuc_context *ctx, struct zuc_test *test)
764 {
765 	struct zuc_slinked *curr;
766 	for (curr = ctx->listeners; curr; curr = curr->next) {
767 		struct zuc_event_listener *listener = curr->data;
768 		if (listener->test_disabled)
769 			listener->test_disabled(listener->data, test);
770 	}
771 }
772 
773 static void
dispatch_check_triggered(struct zuc_context * ctx,char const * file,int line,enum zuc_fail_state state,enum zuc_check_op op,enum zuc_check_valtype valtype,intptr_t val1,intptr_t val2,const char * expr1,const char * expr2)774 dispatch_check_triggered(struct zuc_context *ctx, char const *file, int line,
775 			 enum zuc_fail_state state, enum zuc_check_op op,
776 			 enum zuc_check_valtype valtype,
777 			 intptr_t val1, intptr_t val2,
778 			 const char *expr1, const char *expr2)
779 {
780 	struct zuc_slinked *curr;
781 	for (curr = ctx->listeners; curr; curr = curr->next) {
782 		struct zuc_event_listener *listener = curr->data;
783 		if (listener->check_triggered)
784 			listener->check_triggered(listener->data,
785 						  file, line,
786 						  state, op, valtype,
787 						  val1, val2,
788 						  expr1, expr2);
789 	}
790 }
791 
792 static void
dispatch_collect_event(struct zuc_context * ctx,char const * file,int line,const char * expr1)793 dispatch_collect_event(struct zuc_context *ctx, char const *file, int line,
794 		       const char *expr1)
795 {
796 	struct zuc_slinked *curr;
797 	for (curr = ctx->listeners; curr; curr = curr->next) {
798 		struct zuc_event_listener *listener = curr->data;
799 		if (listener->collect_event)
800 			listener->collect_event(listener->data,
801 						file, line, expr1);
802 	}
803 }
804 
805 static void
migrate_deferred_events(struct zuc_test * test,bool transferred)806 migrate_deferred_events(struct zuc_test *test, bool transferred)
807 {
808 	struct zuc_event *evt = test->deferred;
809 	if (!evt)
810 		return;
811 
812 	test->deferred = NULL;
813 	if (test->events) {
814 		struct zuc_event *old = test->events;
815 		while (old->next)
816 			old = old->next;
817 		old->next = evt;
818 	} else {
819 		test->events = evt;
820 	}
821 	while (evt && !transferred) {
822 		dispatch_check_triggered(&g_ctx,
823 					 evt->file, evt->line,
824 					 evt->state, evt->op,
825 					 evt->valtype,
826 					 evt->val1, evt->val2,
827 					 evt->expr1, evt->expr2);
828 		evt = evt->next;
829 	}
830 }
831 
832 static void
mark_single_failed(struct zuc_test * test,enum zuc_fail_state state)833 mark_single_failed(struct zuc_test *test, enum zuc_fail_state state)
834 {
835 	switch (state) {
836 	case ZUC_CHECK_OK:
837 		/* no internal state to change */
838 		break;
839 	case ZUC_CHECK_SKIP:
840 		if (test)
841 			test->skipped = 1;
842 		break;
843 	case ZUC_CHECK_FAIL:
844 		if (test)
845 			test->failed = 1;
846 		break;
847 	case ZUC_CHECK_ERROR:
848 	case ZUC_CHECK_FATAL:
849 		if (test)
850 			test->fatal = 1;
851 		break;
852 	}
853 
854 	if (g_ctx.break_on_failure)
855 		raise(SIGABRT);
856 
857 }
858 
859 static void
mark_failed(struct zuc_test * test,enum zuc_fail_state state)860 mark_failed(struct zuc_test *test, enum zuc_fail_state state)
861 {
862 	if (!test && g_ctx.curr_test)
863 		test = g_ctx.curr_test;
864 
865 	if (test) {
866 		mark_single_failed(test, state);
867 	} else if (g_ctx.curr_case) {
868 		/* In setup or tear-down of test suite */
869 		int i;
870 		for (i = 0; i < g_ctx.curr_case->test_count; ++i)
871 			mark_single_failed(g_ctx.curr_case->tests[i], state);
872 	}
873 	if ((state == ZUC_CHECK_FATAL) || (state == ZUC_CHECK_ERROR))
874 		g_ctx.fatal = true;
875 }
876 
877 void
zuc_attach_event(struct zuc_test * test,struct zuc_event * event,enum zuc_event_type event_type,bool transferred)878 zuc_attach_event(struct zuc_test *test, struct zuc_event *event,
879 		 enum zuc_event_type event_type, bool transferred)
880 {
881 	if (!test) {
882 		/*
883 		 * consider adding events directly to the case.
884 		 * would be for use during per-suite setup and teardown.
885 		 */
886 		printf("%s:%d: error: No current test.\n", __FILE__, __LINE__);
887 	} else if (event_type == ZUC_EVENT_DEFERRED) {
888 		if (test->deferred) {
889 			struct zuc_event *curr = test->deferred;
890 			while (curr->next)
891 				curr = curr->next;
892 			curr->next = event;
893 		} else {
894 			test->deferred = event;
895 		}
896 	} else {
897 		if (test)
898 			migrate_deferred_events(test, transferred);
899 
900 		if (test->events) {
901 			struct zuc_event *curr = test->events;
902 			while (curr->next)
903 				curr = curr->next;
904 			curr->next = event;
905 		} else {
906 			test->events = event;
907 		}
908 		mark_failed(test, event->state);
909 	}
910 }
911 
912 void
zuc_add_event_listener(struct zuc_event_listener * event_listener)913 zuc_add_event_listener(struct zuc_event_listener *event_listener)
914 {
915 	if (!event_listener) /* ensure null entries are not added */
916 		return;
917 
918 	if (!g_ctx.listeners) {
919 		g_ctx.listeners = zalloc(sizeof(struct zuc_slinked));
920 		ZUC_ASSERT_NOT_NULL(g_ctx.listeners);
921 		g_ctx.listeners->data = event_listener;
922 	} else {
923 		struct zuc_slinked *curr = g_ctx.listeners;
924 		while (curr->next)
925 			curr = curr->next;
926 		curr->next = zalloc(sizeof(struct zuc_slinked));
927 		ZUC_ASSERT_NOT_NULL(curr->next);
928 		curr->next->data = event_listener;
929 	}
930 }
931 
932 
933 void
zuc_cleanup(void)934 zuc_cleanup(void)
935 {
936 	int i;
937 
938 	free(g_ctx.filter);
939 	g_ctx.filter = 0;
940 	for (i = 0; i < 2; ++i)
941 		if (g_ctx.fds[i] != -1) {
942 			close(g_ctx.fds[i]);
943 			g_ctx.fds[i] = -1;
944 		}
945 
946 	if (g_ctx.listeners) {
947 		struct zuc_slinked *curr = g_ctx.listeners;
948 		while (curr) {
949 			struct zuc_slinked *old = curr;
950 			struct zuc_event_listener *listener = curr->data;
951 			if (listener->destroy)
952 				listener->destroy(listener->data);
953 			free(listener);
954 			curr = curr->next;
955 			free(old);
956 		}
957 		g_ctx.listeners = NULL;
958 	}
959 
960 	for (i = g_ctx.case_count - 1; i >= 0; --i) {
961 		free_test_case(g_ctx.cases[i]);
962 		g_ctx.cases[i] = NULL;
963 	}
964 	free(g_ctx.cases);
965 	g_ctx.cases = NULL;
966 
967 	free(g_progname);
968 	g_progname = NULL;
969 	free(g_progbasename);
970 	g_progbasename = NULL;
971 }
972 
973 static void
shuffle_cases(int count,struct zuc_case ** cases,unsigned int seed)974 shuffle_cases(int count, struct zuc_case **cases,
975 		   unsigned int seed)
976 {
977 	int i;
978 	unsigned int rseed = seed;
979 	for (i = 0; i < count; ++i) {
980 		int j;
981 		for (j = cases[i]->test_count - 1; j > 0 ; --j) {
982 			int val = rand_r(&rseed);
983 			int b = ((val / (double)RAND_MAX) * j + 0.5);
984 			if (j != b) {
985 				struct zuc_test *tmp = cases[i]->tests[j];
986 				cases[i]->tests[j] = cases[i]->tests[b];
987 				cases[i]->tests[b] = tmp;
988 			}
989 		}
990 	}
991 
992 	for (i = count - 1; i > 0; --i) {
993 		int val = rand_r(&rseed);
994 		int j = ((val / (double)RAND_MAX) * i + 0.5);
995 
996 		if (i != j) {
997 			struct zuc_case *tmp = cases[i];
998 			cases[i] = cases[j];
999 			cases[j] = tmp;
1000 		}
1001 	}
1002 }
1003 
1004 void
zuc_list_tests(void)1005 zuc_list_tests(void)
1006 {
1007 	int i;
1008 	int j;
1009 	initialize();
1010 	if (g_ctx.fatal)
1011 		return;
1012 	for (i = 0; i < g_ctx.case_count; ++i) {
1013 		printf("%s.\n", g_ctx.cases[i]->name);
1014 		for (j = 0; j < g_ctx.cases[i]->test_count; ++j) {
1015 			printf("  %s\n", g_ctx.cases[i]->tests[j]->name);
1016 		}
1017 	}
1018 }
1019 
1020 static void
spawn_test(struct zuc_test * test,void * test_data,void (* cleanup_fn)(void * data),void * cleanup_data)1021 spawn_test(struct zuc_test *test, void *test_data,
1022 	   void (*cleanup_fn)(void *data), void *cleanup_data)
1023 {
1024 	pid_t pid = -1;
1025 
1026 	if (!test || (!test->fn && !test->fn_f))
1027 		return;
1028 
1029 	if (pipe2(g_ctx.fds, O_CLOEXEC)) {
1030 		printf("%s:%d: error: Unable to create pipe: %d\n",
1031 		       __FILE__, __LINE__, errno);
1032 		mark_failed(test, ZUC_CHECK_ERROR);
1033 		return;
1034 	}
1035 
1036 	fflush(NULL); /* important. avoid duplication of output */
1037 	pid = fork();
1038 	switch (pid) {
1039 	case -1: /* Error forking */
1040 		printf("%s:%d: error: Problem with fork: %d\n",
1041 		       __FILE__, __LINE__, errno);
1042 		mark_failed(test, ZUC_CHECK_ERROR);
1043 		close(g_ctx.fds[0]);
1044 		g_ctx.fds[0] = -1;
1045 		close(g_ctx.fds[1]);
1046 		g_ctx.fds[1] = -1;
1047 		break;
1048 	case 0: { /* child */
1049 		int rc = EXIT_SUCCESS;
1050 		close(g_ctx.fds[0]);
1051 		g_ctx.fds[0] = -1;
1052 
1053 		if (test->fn_f)
1054 			test->fn_f(test_data);
1055 		else
1056 			test->fn();
1057 
1058 		if (test_has_failure(test))
1059 			rc = EXIT_FAILURE;
1060 		else if (test_has_skip(test))
1061 			rc = ZUC_EXIT_SKIP;
1062 
1063 		/* Avoid confusing memory tools like valgrind */
1064 		if (cleanup_fn)
1065 			cleanup_fn(cleanup_data);
1066 
1067 		zuc_cleanup();
1068 		exit(rc);
1069 	}
1070 	default: { /* parent */
1071 		ssize_t rc = 0;
1072 		siginfo_t info = {};
1073 
1074 		close(g_ctx.fds[1]);
1075 		g_ctx.fds[1] = -1;
1076 
1077 		do {
1078 			rc = zuc_process_message(g_ctx.curr_test,
1079 						 g_ctx.fds[0]);
1080 		} while (rc > 0);
1081 		close(g_ctx.fds[0]);
1082 		g_ctx.fds[0] = -1;
1083 
1084 		if (waitid(P_ALL, 0, &info, WEXITED)) {
1085 			printf("%s:%d: error: waitid failed. (%d)\n",
1086 			       __FILE__, __LINE__, errno);
1087 			mark_failed(test, ZUC_CHECK_ERROR);
1088 		} else {
1089 			switch (info.si_code) {
1090 			case CLD_EXITED: {
1091 				int exit_code = info.si_status;
1092 				switch(exit_code) {
1093 				case EXIT_SUCCESS:
1094 					break;
1095 				case ZUC_EXIT_SKIP:
1096 					if (!test_has_skip(g_ctx.curr_test) &&
1097 					    !test_has_failure(g_ctx.curr_test))
1098 						ZUC_SKIP("Child exited SKIP");
1099 					break;
1100 				default:
1101 					/* unexpected failure */
1102 					if (!test_has_failure(g_ctx.curr_test))
1103 						ZUC_ASSERT_EQ(0, exit_code);
1104 				}
1105 				break;
1106 			}
1107 			case CLD_KILLED:
1108 			case CLD_DUMPED:
1109 				printf("%s:%d: error: signaled: %d\n",
1110 				       __FILE__, __LINE__, info.si_status);
1111 				mark_failed(test, ZUC_CHECK_ERROR);
1112 				break;
1113 			}
1114 		}
1115 	}
1116 	}
1117 }
1118 
1119 static void
run_single_test(struct zuc_test * test,const struct zuc_fixture * fxt,void * case_data,bool spawn)1120 run_single_test(struct zuc_test *test,const struct zuc_fixture *fxt,
1121 		void *case_data, bool spawn)
1122 {
1123 	long elapsed = 0;
1124 	struct timespec begin;
1125 	struct timespec end;
1126 	void *test_data = NULL;
1127 	void *cleanup_data = NULL;
1128 	void (*cleanup_fn)(void *data) = NULL;
1129 	memset(&begin, 0, sizeof(begin));
1130 	memset(&end, 0, sizeof(end));
1131 
1132 	g_ctx.curr_test = test;
1133 	dispatch_test_started(&g_ctx, test);
1134 
1135 	cleanup_fn = fxt ? fxt->tear_down : NULL;
1136 	cleanup_data = NULL;
1137 
1138 	if (fxt && fxt->set_up) {
1139 		test_data = fxt->set_up(case_data);
1140 		cleanup_data = test_data;
1141 	} else {
1142 		test_data = case_data;
1143 	}
1144 
1145 	clock_gettime(TARGET_TIMER, &begin);
1146 
1147 	/* Need to re-check these, as fixtures might have changed test state. */
1148 	if (!test->fatal && !test->skipped) {
1149 		if (spawn) {
1150 			spawn_test(test, test_data,
1151 				   cleanup_fn, cleanup_data);
1152 		} else {
1153 			if (test->fn_f)
1154 				test->fn_f(test_data);
1155 			else
1156 				test->fn();
1157 		}
1158 	}
1159 
1160 	clock_gettime(TARGET_TIMER, &end);
1161 
1162 	elapsed = (end.tv_sec - begin.tv_sec) * MS_PER_SEC;
1163 	if (end.tv_sec != begin.tv_sec) {
1164 		elapsed -= (begin.tv_nsec) / NANO_PER_MS;
1165 		elapsed += (end.tv_nsec) / NANO_PER_MS;
1166 	} else {
1167 		elapsed += (end.tv_nsec - begin.tv_nsec) / NANO_PER_MS;
1168 	}
1169 	test->elapsed = elapsed;
1170 
1171 	if (cleanup_fn)
1172 		cleanup_fn(cleanup_data);
1173 
1174 	if (test->deferred) {
1175 		if (test_has_failure(test))
1176 			migrate_deferred_events(test, false);
1177 		else
1178 			free_events(&test->deferred);
1179 	}
1180 
1181 	dispatch_test_ended(&g_ctx, test);
1182 
1183 	g_ctx.curr_test = NULL;
1184 }
1185 
1186 static void
run_single_case(struct zuc_case * test_case)1187 run_single_case(struct zuc_case *test_case)
1188 {
1189 	int count_live = test_case->test_count - test_case->disabled;
1190 	g_ctx.curr_case = test_case;
1191 	if (count_live) {
1192 		int i = 0;
1193 		const struct zuc_fixture *fxt = test_case->fxt;
1194 		void *case_data = fxt ? (void *)fxt->data : NULL;
1195 
1196 		dispatch_case_started(&g_ctx, test_case,
1197 				      count_live, test_case->disabled);
1198 
1199 		if (fxt && fxt->set_up_test_case)
1200 			case_data = fxt->set_up_test_case(fxt->data);
1201 
1202 		for (i = 0; i < test_case->test_count; ++i) {
1203 			struct zuc_test *curr = test_case->tests[i];
1204 			if (curr->disabled) {
1205 				dispatch_test_disabled(&g_ctx, curr);
1206 			} else {
1207 				run_single_test(curr, fxt, case_data,
1208 						g_ctx.spawn);
1209 				if (curr->skipped)
1210 					test_case->skipped++;
1211 				if (curr->failed)
1212 					test_case->failed++;
1213 				if (curr->fatal)
1214 					test_case->fatal++;
1215 				if (!curr->failed && !curr->fatal)
1216 					test_case->passed++;
1217 				test_case->elapsed += curr->elapsed;
1218 			}
1219 		}
1220 
1221 		if (fxt && fxt->tear_down_test_case)
1222 			fxt->tear_down_test_case(case_data);
1223 
1224 		dispatch_case_ended(&g_ctx, test_case);
1225 	}
1226 	g_ctx.curr_case = NULL;
1227 }
1228 
1229 static void
reset_test_values(struct zuc_case ** cases,int case_count)1230 reset_test_values(struct zuc_case **cases, int case_count)
1231 {
1232 	int i;
1233 	for (i = 0; i < case_count; ++i) {
1234 		int j;
1235 		cases[i]->disabled = 0;
1236 		cases[i]->skipped = 0;
1237 		cases[i]->failed = 0;
1238 		cases[i]->fatal = 0;
1239 		cases[i]->passed = 0;
1240 		cases[i]->elapsed = 0;
1241 		for (j = 0; j < cases[i]->test_count; ++j) {
1242 			struct zuc_test *test = cases[i]->tests[j];
1243 			if (test->disabled)
1244 				cases[i]->disabled++;
1245 			test->skipped = 0;
1246 			test->failed = 0;
1247 			test->fatal = 0;
1248 			test->elapsed = 0;
1249 
1250 			free_events(&test->events);
1251 			free_events(&test->deferred);
1252 		}
1253 	}
1254 }
1255 
1256 static int
run_single_pass(void)1257 run_single_pass(void)
1258 {
1259 	long total_elapsed = 0;
1260 	int total_passed = 0;
1261 	int total_failed = 0;
1262 	int total_skipped = 0;
1263 	int live_case_count = 0;
1264 	int live_test_count = 0;
1265 	int disabled_test_count = 0;
1266 	int i;
1267 
1268 	reset_test_values(g_ctx.cases, g_ctx.case_count);
1269 	for (i = 0; i <  g_ctx.case_count; ++i) {
1270 		int live = g_ctx.cases[i]->test_count
1271 			- g_ctx.cases[i]->disabled;
1272 		if (live) {
1273 			live_test_count += live;
1274 			live_case_count++;
1275 		}
1276 		if (g_ctx.cases[i]->disabled)
1277 			disabled_test_count++;
1278 	}
1279 
1280 	dispatch_run_started(&g_ctx, live_case_count, live_test_count,
1281 			     disabled_test_count);
1282 
1283 	for (i = 0; i <  g_ctx.case_count; ++i) {
1284 		run_single_case(g_ctx.cases[i]);
1285 		total_failed += g_ctx.cases[i]->test_count
1286 			- (g_ctx.cases[i]->passed + g_ctx.cases[i]->disabled);
1287 		total_passed += g_ctx.cases[i]->passed;
1288 		total_elapsed += g_ctx.cases[i]->elapsed;
1289 		total_skipped += g_ctx.cases[i]->skipped;
1290 	}
1291 
1292 	dispatch_run_ended(&g_ctx, live_case_count, live_test_count,
1293 			   total_passed, total_failed, disabled_test_count,
1294 			   total_elapsed);
1295 
1296 	if (total_failed)
1297 		return EXIT_FAILURE;
1298 	else if (total_skipped)
1299 		return ZUC_EXIT_SKIP;
1300 	else
1301 		return EXIT_SUCCESS;
1302 }
1303 
1304 int
zucimpl_run_tests(void)1305 zucimpl_run_tests(void)
1306 {
1307 	int rc = EXIT_SUCCESS;
1308 	int i;
1309 	int limit = g_ctx.repeat > 0 ? g_ctx.repeat : 1;
1310 
1311 	initialize();
1312 	if (g_ctx.fatal)
1313 		return EXIT_FAILURE;
1314 
1315 	if (g_ctx.listeners == NULL) {
1316 		zuc_add_event_listener(zuc_collector_create(&(g_ctx.fds[1])));
1317 		zuc_add_event_listener(zuc_base_logger_create());
1318 		if (g_ctx.output_junit)
1319 			zuc_add_event_listener(zuc_junit_reporter_create());
1320 	}
1321 
1322 	if (g_ctx.case_count < 1) {
1323 		printf("%s:%d: error: Setup error: test tree is empty\n",
1324 		       __FILE__, __LINE__);
1325 		rc = EXIT_FAILURE;
1326 	}
1327 
1328 	for (i = 0; (i < limit) && (g_ctx.case_count > 0); ++i) {
1329 		int pass_code = EXIT_SUCCESS;
1330 		dispatch_pre_run(&g_ctx, limit, i + 1,
1331 				 (g_ctx.random > 0) ? g_ctx.seed : 0,
1332 				 g_ctx.filter);
1333 
1334 		order_cases(g_ctx.case_count, g_ctx.cases);
1335 		if (g_ctx.random > 0)
1336 			shuffle_cases(g_ctx.case_count, g_ctx.cases,
1337 				      g_ctx.seed);
1338 
1339 		pass_code = run_single_pass();
1340 		if (pass_code == EXIT_FAILURE)
1341 			rc = EXIT_FAILURE;
1342 		else if ((pass_code == ZUC_EXIT_SKIP) && (rc == EXIT_SUCCESS))
1343 			rc = ZUC_EXIT_SKIP;
1344 
1345 		g_ctx.seed++;
1346 	}
1347 
1348 	return rc;
1349 }
1350 
1351 int
zucimpl_tracepoint(char const * file,int line,char const * fmt,...)1352 zucimpl_tracepoint(char const *file, int line, char const *fmt, ...)
1353 {
1354 	int rc = -1;
1355 	va_list argp;
1356 	char *msg = NULL;
1357 
1358 
1359 	va_start(argp, fmt);
1360 	rc = vasprintf(&msg, fmt, argp);
1361 	if (rc == -1) {
1362 		msg = NULL;
1363 	}
1364 	va_end(argp);
1365 
1366 	dispatch_collect_event(&g_ctx,
1367 			       file, line,
1368 			       msg);
1369 
1370 	free(msg);
1371 
1372 	return rc;
1373 }
1374 
1375 void
zucimpl_terminate(char const * file,int line,bool fail,bool fatal,const char * msg)1376 zucimpl_terminate(char const *file, int line,
1377 		  bool fail, bool fatal, const char *msg)
1378 {
1379 	enum zuc_fail_state state = ZUC_CHECK_SKIP;
1380 	int level = 2;
1381 	if (fail && fatal) {
1382 		state =  ZUC_CHECK_FATAL;
1383 		level = 0;
1384 	} else if (fail && !fatal) {
1385 		state = ZUC_CHECK_FAIL;
1386 		level = 0;
1387 	}
1388 
1389 	mark_failed(g_ctx.curr_test, state);
1390 
1391 	if ((state != ZUC_CHECK_OK) && g_ctx.curr_test)
1392 		migrate_deferred_events(g_ctx.curr_test, false);
1393 
1394 	dispatch_check_triggered(&g_ctx,
1395 				 file, line,
1396 				 state,
1397 				 ZUC_OP_TERMINATE, ZUC_VAL_INT,
1398 				 level, 0,
1399 				 msg, "");
1400 }
1401 
1402 static void
validate_types(enum zuc_check_op op,enum zuc_check_valtype valtype)1403 validate_types(enum zuc_check_op op, enum zuc_check_valtype valtype)
1404 {
1405 	bool is_valid = true;
1406 
1407 	switch (op) {
1408 	case ZUC_OP_NULL:
1409 	case ZUC_OP_NOT_NULL:
1410 		is_valid = is_valid && (valtype == ZUC_VAL_PTR);
1411 		break;
1412 	default:
1413 		; /* all rest OK */
1414 	}
1415 
1416 	switch (valtype) {
1417 	case ZUC_VAL_CSTR:
1418 		is_valid = is_valid && ((op == ZUC_OP_EQ) || (op == ZUC_OP_NE));
1419 		break;
1420 	default:
1421 		; /* all rest OK */
1422 	}
1423 
1424 	if (!is_valid)
1425 		printf("%s:%d: warning: Unexpected op+type %d/%d.\n",
1426 		       __FILE__, __LINE__, op, valtype);
1427 }
1428 
1429 static int
pred2_unknown(intptr_t lhs,intptr_t rhs)1430 pred2_unknown(intptr_t lhs, intptr_t rhs)
1431 {
1432 	return 0;
1433 }
1434 
1435 static int
pred2_true(intptr_t lhs,intptr_t rhs)1436 pred2_true(intptr_t lhs, intptr_t rhs)
1437 {
1438 	return lhs;
1439 }
1440 
1441 static int
pred2_false(intptr_t lhs,intptr_t rhs)1442 pred2_false(intptr_t lhs, intptr_t rhs)
1443 {
1444 	return !lhs;
1445 }
1446 
1447 static int
pred2_eq(intptr_t lhs,intptr_t rhs)1448 pred2_eq(intptr_t lhs, intptr_t rhs)
1449 {
1450 	return lhs == rhs;
1451 }
1452 
1453 static int
pred2_streq(intptr_t lhs,intptr_t rhs)1454 pred2_streq(intptr_t lhs, intptr_t rhs)
1455 {
1456 	int status = 0;
1457 	const char *lhptr = (const char *)lhs;
1458 	const char *rhptr = (const char *)rhs;
1459 
1460 	if (!lhptr && !rhptr)
1461 		status = 1;
1462 	else if (lhptr && rhptr)
1463 		status = strcmp(lhptr, rhptr) == 0;
1464 
1465 	return status;
1466 }
1467 
1468 static int
pred2_ne(intptr_t lhs,intptr_t rhs)1469 pred2_ne(intptr_t lhs, intptr_t rhs)
1470 {
1471 	return lhs != rhs;
1472 }
1473 
1474 static int
pred2_strne(intptr_t lhs,intptr_t rhs)1475 pred2_strne(intptr_t lhs, intptr_t rhs)
1476 {
1477 	int status = 0;
1478 	const char *lhptr = (const char *)lhs;
1479 	const char *rhptr = (const char *)rhs;
1480 
1481 	if (lhptr != rhptr) {
1482 		if (!lhptr || !rhptr)
1483 			status = 1;
1484 		else
1485 			status = strcmp(lhptr, rhptr) != 0;
1486 	}
1487 
1488 	return status;
1489 }
1490 
1491 static int
pred2_ge(intptr_t lhs,intptr_t rhs)1492 pred2_ge(intptr_t lhs, intptr_t rhs)
1493 {
1494 	return lhs >= rhs;
1495 }
1496 
1497 static int
pred2_gt(intptr_t lhs,intptr_t rhs)1498 pred2_gt(intptr_t lhs, intptr_t rhs)
1499 {
1500 	return lhs > rhs;
1501 }
1502 
1503 static int
pred2_le(intptr_t lhs,intptr_t rhs)1504 pred2_le(intptr_t lhs, intptr_t rhs)
1505 {
1506 	return lhs <= rhs;
1507 }
1508 
1509 static int
pred2_lt(intptr_t lhs,intptr_t rhs)1510 pred2_lt(intptr_t lhs, intptr_t rhs)
1511 {
1512 	return lhs < rhs;
1513 }
1514 
1515 static comp_pred2
get_pred2(enum zuc_check_op op,enum zuc_check_valtype valtype)1516 get_pred2(enum zuc_check_op op, enum zuc_check_valtype valtype)
1517 {
1518 	switch (op) {
1519 	case ZUC_OP_TRUE:
1520 		return pred2_true;
1521 	case ZUC_OP_FALSE:
1522 		return pred2_false;
1523 	case ZUC_OP_NULL:
1524 		return pred2_false;
1525 	case ZUC_OP_NOT_NULL:
1526 		return pred2_true;
1527 	case ZUC_OP_EQ:
1528 		if (valtype == ZUC_VAL_CSTR)
1529 			return pred2_streq;
1530 		else
1531 			return pred2_eq;
1532 	case ZUC_OP_NE:
1533 		if (valtype == ZUC_VAL_CSTR)
1534 			return pred2_strne;
1535 		else
1536 			return pred2_ne;
1537 	case ZUC_OP_GE:
1538 		return pred2_ge;
1539 	case ZUC_OP_GT:
1540 		return pred2_gt;
1541 	case ZUC_OP_LE:
1542 		return pred2_le;
1543 	case ZUC_OP_LT:
1544 		return pred2_lt;
1545 	default:
1546 		return pred2_unknown;
1547 	}
1548 }
1549 
1550 int
zucimpl_expect_pred2(char const * file,int line,enum zuc_check_op op,enum zuc_check_valtype valtype,bool fatal,intptr_t lhs,intptr_t rhs,const char * lhs_str,const char * rhs_str)1551 zucimpl_expect_pred2(char const *file, int line,
1552 		     enum zuc_check_op op, enum zuc_check_valtype valtype,
1553 		     bool fatal,
1554 		     intptr_t lhs, intptr_t rhs,
1555 		     const char *lhs_str, const char* rhs_str)
1556 {
1557 	enum zuc_fail_state state = fatal ?  ZUC_CHECK_FATAL : ZUC_CHECK_FAIL;
1558 	comp_pred2 pred = get_pred2(op, valtype);
1559 	int failed = !pred(lhs, rhs);
1560 
1561 	validate_types(op, valtype);
1562 
1563 	if (failed) {
1564 		mark_failed(g_ctx.curr_test, state);
1565 
1566 		if (g_ctx.curr_test)
1567 			migrate_deferred_events(g_ctx.curr_test, false);
1568 
1569 		dispatch_check_triggered(&g_ctx,
1570 					 file, line,
1571 					 fatal ? ZUC_CHECK_FATAL
1572 					 : ZUC_CHECK_FAIL,
1573 					 op, valtype,
1574 					 lhs, rhs,
1575 					 lhs_str, rhs_str);
1576 	}
1577 	return failed;
1578 }
1579