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