tools/llvm: Do not build with symbols
[minix3.git] / external / bsd / atf / dist / atf-c / tc.c
blobcbdd00c4e0b0f92414d638317aaaff0a56b89947
1 /*
2 * Automated Testing Framework (atf)
4 * Copyright (c) 2008 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
17 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
18 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <sys/uio.h>
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <stdarg.h>
37 #include <stdbool.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
43 #include "atf-c/defs.h"
44 #include "atf-c/error.h"
45 #include "atf-c/tc.h"
47 #include "detail/env.h"
48 #include "detail/fs.h"
49 #include "detail/map.h"
50 #include "detail/sanity.h"
51 #include "detail/text.h"
53 /* ---------------------------------------------------------------------
54 * Auxiliary functions.
55 * --------------------------------------------------------------------- */
57 enum expect_type {
58 EXPECT_PASS,
59 EXPECT_FAIL,
60 EXPECT_EXIT,
61 EXPECT_SIGNAL,
62 EXPECT_DEATH,
63 EXPECT_TIMEOUT,
66 struct context {
67 const atf_tc_t *tc;
68 const char *resfile;
69 size_t fail_count;
71 enum expect_type expect;
72 atf_dynstr_t expect_reason;
73 size_t expect_previous_fail_count;
74 size_t expect_fail_count;
75 int expect_exitcode;
76 int expect_signo;
79 static void context_init(struct context *, const atf_tc_t *, const char *);
80 static void check_fatal_error(atf_error_t);
81 static void report_fatal_error(const char *, ...)
82 ATF_DEFS_ATTRIBUTE_NORETURN;
83 static atf_error_t write_resfile(const int, const char *, const int,
84 const atf_dynstr_t *);
85 static void create_resfile(const char *, const char *, const int,
86 atf_dynstr_t *);
87 static void error_in_expect(struct context *, const char *, ...)
88 ATF_DEFS_ATTRIBUTE_NORETURN;
89 static void validate_expect(struct context *);
90 static void expected_failure(struct context *, atf_dynstr_t *)
91 ATF_DEFS_ATTRIBUTE_NORETURN;
92 static void fail_requirement(struct context *, atf_dynstr_t *)
93 ATF_DEFS_ATTRIBUTE_NORETURN;
94 static void fail_check(struct context *, atf_dynstr_t *);
95 static void pass(struct context *)
96 ATF_DEFS_ATTRIBUTE_NORETURN;
97 static void skip(struct context *, atf_dynstr_t *)
98 ATF_DEFS_ATTRIBUTE_NORETURN;
99 static void format_reason_ap(atf_dynstr_t *, const char *, const size_t,
100 const char *, va_list);
101 static void format_reason_fmt(atf_dynstr_t *, const char *, const size_t,
102 const char *, ...);
103 static void errno_test(struct context *, const char *, const size_t,
104 const int, const char *, const bool,
105 void (*)(struct context *, atf_dynstr_t *));
106 static atf_error_t check_prog_in_dir(const char *, void *);
107 static atf_error_t check_prog(struct context *, const char *);
109 static void
110 context_init(struct context *ctx, const atf_tc_t *tc, const char *resfile)
112 ctx->tc = tc;
113 ctx->resfile = resfile;
114 ctx->fail_count = 0;
115 ctx->expect = EXPECT_PASS;
116 check_fatal_error(atf_dynstr_init(&ctx->expect_reason));
117 ctx->expect_previous_fail_count = 0;
118 ctx->expect_fail_count = 0;
119 ctx->expect_exitcode = 0;
120 ctx->expect_signo = 0;
123 static void
124 check_fatal_error(atf_error_t err)
126 if (atf_is_error(err)) {
127 char buf[1024];
128 atf_error_format(err, buf, sizeof(buf));
129 fprintf(stderr, "FATAL ERROR: %s\n", buf);
130 atf_error_free(err);
131 abort();
135 static void
136 report_fatal_error(const char *msg, ...)
138 va_list ap;
139 fprintf(stderr, "FATAL ERROR: ");
141 va_start(ap, msg);
142 vfprintf(stderr, msg, ap);
143 va_end(ap);
145 fprintf(stderr, "\n");
146 abort();
149 /** Writes to a results file.
151 * The results file is supposed to be already open.
153 * This function returns an error code instead of exiting in case of error
154 * because the caller needs to clean up the reason object before terminating.
156 static atf_error_t
157 write_resfile(const int fd, const char *result, const int arg,
158 const atf_dynstr_t *reason)
160 static char NL[] = "\n", CS[] = ": ";
161 char buf[64];
162 const char *r;
163 struct iovec iov[5];
164 ssize_t ret;
165 int count = 0;
167 INV(arg == -1 || reason != NULL);
169 #define UNCONST(a) ((void *)(unsigned long)(const void *)(a))
170 iov[count].iov_base = UNCONST(result);
171 iov[count++].iov_len = strlen(result);
173 if (reason != NULL) {
174 if (arg != -1) {
175 iov[count].iov_base = buf;
176 iov[count++].iov_len = snprintf(buf, sizeof(buf), "(%d)", arg);
179 iov[count].iov_base = CS;
180 iov[count++].iov_len = sizeof(CS) - 1;
182 r = atf_dynstr_cstring(reason);
183 iov[count].iov_base = UNCONST(r);
184 iov[count++].iov_len = strlen(r);
186 #undef UNCONST
188 iov[count].iov_base = NL;
189 iov[count++].iov_len = sizeof(NL) - 1;
191 while ((ret = writev(fd, iov, count)) == -1 && errno == EINTR)
192 continue; /* Retry. */
193 if (ret != -1)
194 return atf_no_error();
196 return atf_libc_error(
197 errno, "Failed to write results file; result %s, reason %s", result,
198 reason == NULL ? "null" : atf_dynstr_cstring(reason));
201 /** Creates a results file.
203 * The input reason is released in all cases.
205 * An error in this function is considered to be fatal, hence why it does
206 * not return any error code.
208 static void
209 create_resfile(const char *resfile, const char *result, const int arg,
210 atf_dynstr_t *reason)
212 atf_error_t err;
214 if (strcmp("/dev/stdout", resfile) == 0) {
215 err = write_resfile(STDOUT_FILENO, result, arg, reason);
216 } else if (strcmp("/dev/stderr", resfile) == 0) {
217 err = write_resfile(STDERR_FILENO, result, arg, reason);
218 } else {
219 const int fd = open(resfile, O_WRONLY | O_CREAT | O_TRUNC,
220 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
221 if (fd == -1) {
222 err = atf_libc_error(errno, "Cannot create results file '%s'",
223 resfile);
224 } else {
225 err = write_resfile(fd, result, arg, reason);
226 close(fd);
230 if (reason != NULL)
231 atf_dynstr_fini(reason);
233 check_fatal_error(err);
236 /** Fails a test case if validate_expect fails. */
237 static void
238 error_in_expect(struct context *ctx, const char *fmt, ...)
240 atf_dynstr_t reason;
241 va_list ap;
243 va_start(ap, fmt);
244 format_reason_ap(&reason, NULL, 0, fmt, ap);
245 va_end(ap);
247 ctx->expect = EXPECT_PASS; /* Ensure fail_requirement really fails. */
248 fail_requirement(ctx, &reason);
251 /** Ensures that the "expect" state is correct.
253 * Call this function before modifying the current value of expect.
255 static void
256 validate_expect(struct context *ctx)
258 if (ctx->expect == EXPECT_DEATH) {
259 error_in_expect(ctx, "Test case was expected to terminate abruptly "
260 "but it continued execution");
261 } else if (ctx->expect == EXPECT_EXIT) {
262 error_in_expect(ctx, "Test case was expected to exit cleanly but it "
263 "continued execution");
264 } else if (ctx->expect == EXPECT_FAIL) {
265 if (ctx->expect_fail_count == ctx->expect_previous_fail_count)
266 error_in_expect(ctx, "Test case was expecting a failure but none "
267 "were raised");
268 else
269 INV(ctx->expect_fail_count > ctx->expect_previous_fail_count);
270 } else if (ctx->expect == EXPECT_PASS) {
271 /* Nothing to validate. */
272 } else if (ctx->expect == EXPECT_SIGNAL) {
273 error_in_expect(ctx, "Test case was expected to receive a termination "
274 "signal but it continued execution");
275 } else if (ctx->expect == EXPECT_TIMEOUT) {
276 error_in_expect(ctx, "Test case was expected to hang but it continued "
277 "execution");
278 } else
279 UNREACHABLE;
282 static void
283 expected_failure(struct context *ctx, atf_dynstr_t *reason)
285 check_fatal_error(atf_dynstr_prepend_fmt(reason, "%s: ",
286 atf_dynstr_cstring(&ctx->expect_reason)));
287 create_resfile(ctx->resfile, "expected_failure", -1, reason);
288 exit(EXIT_SUCCESS);
291 static void
292 fail_requirement(struct context *ctx, atf_dynstr_t *reason)
294 if (ctx->expect == EXPECT_FAIL) {
295 expected_failure(ctx, reason);
296 } else if (ctx->expect == EXPECT_PASS) {
297 create_resfile(ctx->resfile, "failed", -1, reason);
298 exit(EXIT_FAILURE);
299 } else {
300 error_in_expect(ctx, "Test case raised a failure but was not "
301 "expecting one; reason was %s", atf_dynstr_cstring(reason));
303 UNREACHABLE;
306 static void
307 fail_check(struct context *ctx, atf_dynstr_t *reason)
309 if (ctx->expect == EXPECT_FAIL) {
310 fprintf(stderr, "*** Expected check failure: %s: %s\n",
311 atf_dynstr_cstring(&ctx->expect_reason),
312 atf_dynstr_cstring(reason));
313 ctx->expect_fail_count++;
314 } else if (ctx->expect == EXPECT_PASS) {
315 fprintf(stderr, "*** Check failed: %s\n", atf_dynstr_cstring(reason));
316 ctx->fail_count++;
317 } else {
318 error_in_expect(ctx, "Test case raised a failure but was not "
319 "expecting one; reason was %s", atf_dynstr_cstring(reason));
322 atf_dynstr_fini(reason);
325 static void
326 pass(struct context *ctx)
328 if (ctx->expect == EXPECT_FAIL) {
329 error_in_expect(ctx, "Test case was expecting a failure but got "
330 "a pass instead");
331 } else if (ctx->expect == EXPECT_PASS) {
332 create_resfile(ctx->resfile, "passed", -1, NULL);
333 exit(EXIT_SUCCESS);
334 } else {
335 error_in_expect(ctx, "Test case asked to explicitly pass but was "
336 "not expecting such condition");
338 UNREACHABLE;
341 static void
342 skip(struct context *ctx, atf_dynstr_t *reason)
344 if (ctx->expect == EXPECT_PASS) {
345 create_resfile(ctx->resfile, "skipped", -1, reason);
346 exit(EXIT_SUCCESS);
347 } else {
348 error_in_expect(ctx, "Can only skip a test case when running in "
349 "expect pass mode");
351 UNREACHABLE;
354 /** Formats a failure/skip reason message.
356 * The formatted reason is stored in out_reason. out_reason is initialized
357 * in this function and is supposed to be released by the caller. In general,
358 * the reason will eventually be fed to create_resfile, which will release
359 * it.
361 * Errors in this function are fatal. Rationale being: reasons are used to
362 * create results files; if we can't format the reason correctly, the result
363 * of the test program will be bogus. So it's better to just exit with a
364 * fatal error.
366 static void
367 format_reason_ap(atf_dynstr_t *out_reason,
368 const char *source_file, const size_t source_line,
369 const char *reason, va_list ap)
371 atf_error_t err;
373 if (source_file != NULL) {
374 err = atf_dynstr_init_fmt(out_reason, "%s:%zd: ", source_file,
375 source_line);
376 } else {
377 PRE(source_line == 0);
378 err = atf_dynstr_init(out_reason);
381 if (!atf_is_error(err)) {
382 va_list ap2;
383 va_copy(ap2, ap);
384 err = atf_dynstr_append_ap(out_reason, reason, ap2);
385 va_end(ap2);
388 check_fatal_error(err);
391 static void
392 format_reason_fmt(atf_dynstr_t *out_reason,
393 const char *source_file, const size_t source_line,
394 const char *reason, ...)
396 va_list ap;
398 va_start(ap, reason);
399 format_reason_ap(out_reason, source_file, source_line, reason, ap);
400 va_end(ap);
403 static void
404 errno_test(struct context *ctx, const char *file, const size_t line,
405 const int exp_errno, const char *expr_str,
406 const bool expr_result,
407 void (*fail_func)(struct context *, atf_dynstr_t *))
409 const int actual_errno = errno;
411 if (expr_result) {
412 if (exp_errno != actual_errno) {
413 atf_dynstr_t reason;
415 format_reason_fmt(&reason, file, line, "Expected errno %d, got %d, "
416 "in %s", exp_errno, actual_errno, expr_str);
417 fail_func(ctx, &reason);
419 } else {
420 atf_dynstr_t reason;
422 format_reason_fmt(&reason, file, line, "Expected true value in %s",
423 expr_str);
424 fail_func(ctx, &reason);
428 struct prog_found_pair {
429 const char *prog;
430 bool found;
433 static atf_error_t
434 check_prog_in_dir(const char *dir, void *data)
436 struct prog_found_pair *pf = data;
437 atf_error_t err;
439 if (pf->found)
440 err = atf_no_error();
441 else {
442 atf_fs_path_t p;
444 err = atf_fs_path_init_fmt(&p, "%s/%s", dir, pf->prog);
445 if (atf_is_error(err))
446 goto out_p;
448 err = atf_fs_eaccess(&p, atf_fs_access_x);
449 if (!atf_is_error(err))
450 pf->found = true;
451 else {
452 atf_error_free(err);
453 INV(!pf->found);
454 err = atf_no_error();
457 out_p:
458 atf_fs_path_fini(&p);
461 return err;
464 static atf_error_t
465 check_prog(struct context *ctx, const char *prog)
467 atf_error_t err;
468 atf_fs_path_t p;
470 err = atf_fs_path_init_fmt(&p, "%s", prog);
471 if (atf_is_error(err))
472 goto out;
474 if (atf_fs_path_is_absolute(&p)) {
475 err = atf_fs_eaccess(&p, atf_fs_access_x);
476 if (atf_is_error(err)) {
477 atf_dynstr_t reason;
479 atf_error_free(err);
480 atf_fs_path_fini(&p);
481 format_reason_fmt(&reason, NULL, 0, "The required program %s could "
482 "not be found", prog);
483 skip(ctx, &reason);
485 } else {
486 const char *path = atf_env_get("PATH");
487 struct prog_found_pair pf;
488 atf_fs_path_t bp;
490 err = atf_fs_path_branch_path(&p, &bp);
491 if (atf_is_error(err))
492 goto out_p;
494 if (strcmp(atf_fs_path_cstring(&bp), ".") != 0) {
495 atf_fs_path_fini(&bp);
496 atf_fs_path_fini(&p);
498 report_fatal_error("Relative paths are not allowed when searching "
499 "for a program (%s)", prog);
500 UNREACHABLE;
503 pf.prog = prog;
504 pf.found = false;
505 err = atf_text_for_each_word(path, ":", check_prog_in_dir, &pf);
506 if (atf_is_error(err))
507 goto out_bp;
509 if (!pf.found) {
510 atf_dynstr_t reason;
512 atf_fs_path_fini(&bp);
513 atf_fs_path_fini(&p);
514 format_reason_fmt(&reason, NULL, 0, "The required program %s could "
515 "not be found in the PATH", prog);
516 fail_requirement(ctx, &reason);
519 out_bp:
520 atf_fs_path_fini(&bp);
523 out_p:
524 atf_fs_path_fini(&p);
525 out:
526 return err;
529 /* ---------------------------------------------------------------------
530 * The "atf_tc" type.
531 * --------------------------------------------------------------------- */
533 struct atf_tc_impl {
534 const char *m_ident;
536 atf_map_t m_vars;
537 atf_map_t m_config;
539 atf_tc_head_t m_head;
540 atf_tc_body_t m_body;
541 atf_tc_cleanup_t m_cleanup;
545 * Constructors/destructors.
548 atf_error_t
549 atf_tc_init(atf_tc_t *tc, const char *ident, atf_tc_head_t head,
550 atf_tc_body_t body, atf_tc_cleanup_t cleanup,
551 const char *const *config)
553 atf_error_t err;
555 tc->pimpl = malloc(sizeof(struct atf_tc_impl));
556 if (tc->pimpl == NULL) {
557 err = atf_no_memory_error();
558 goto err;
561 tc->pimpl->m_ident = ident;
562 tc->pimpl->m_head = head;
563 tc->pimpl->m_body = body;
564 tc->pimpl->m_cleanup = cleanup;
566 err = atf_map_init_charpp(&tc->pimpl->m_config, config);
567 if (atf_is_error(err))
568 goto err;
570 err = atf_map_init(&tc->pimpl->m_vars);
571 if (atf_is_error(err))
572 goto err_vars;
574 err = atf_tc_set_md_var(tc, "ident", ident);
575 if (atf_is_error(err))
576 goto err_map;
578 if (cleanup != NULL) {
579 err = atf_tc_set_md_var(tc, "has.cleanup", "true");
580 if (atf_is_error(err))
581 goto err_map;
584 /* XXX Should the head be able to return error codes? */
585 if (tc->pimpl->m_head != NULL)
586 tc->pimpl->m_head(tc);
588 if (strcmp(atf_tc_get_md_var(tc, "ident"), ident) != 0) {
589 report_fatal_error("Test case head modified the read-only 'ident' "
590 "property");
591 UNREACHABLE;
594 INV(!atf_is_error(err));
595 return err;
597 err_map:
598 atf_map_fini(&tc->pimpl->m_vars);
599 err_vars:
600 atf_map_fini(&tc->pimpl->m_config);
601 err:
602 return err;
605 atf_error_t
606 atf_tc_init_pack(atf_tc_t *tc, const atf_tc_pack_t *pack,
607 const char *const *config)
609 return atf_tc_init(tc, pack->m_ident, pack->m_head, pack->m_body,
610 pack->m_cleanup, config);
613 void
614 atf_tc_fini(atf_tc_t *tc)
616 atf_map_fini(&tc->pimpl->m_vars);
617 free(tc->pimpl);
621 * Getters.
624 const char *
625 atf_tc_get_ident(const atf_tc_t *tc)
627 return tc->pimpl->m_ident;
630 const char *
631 atf_tc_get_config_var(const atf_tc_t *tc, const char *name)
633 const char *val;
634 atf_map_citer_t iter;
636 PRE(atf_tc_has_config_var(tc, name));
637 iter = atf_map_find_c(&tc->pimpl->m_config, name);
638 val = atf_map_citer_data(iter);
639 INV(val != NULL);
641 return val;
644 const char *
645 atf_tc_get_config_var_wd(const atf_tc_t *tc, const char *name,
646 const char *defval)
648 const char *val;
650 if (!atf_tc_has_config_var(tc, name))
651 val = defval;
652 else
653 val = atf_tc_get_config_var(tc, name);
655 return val;
658 bool
659 atf_tc_get_config_var_as_bool(const atf_tc_t *tc, const char *name)
661 bool val;
662 const char *strval;
663 atf_error_t err;
665 strval = atf_tc_get_config_var(tc, name);
666 err = atf_text_to_bool(strval, &val);
667 if (atf_is_error(err)) {
668 atf_error_free(err);
669 atf_tc_fail("Configuration variable %s does not have a valid "
670 "boolean value; found %s", name, strval);
673 return val;
676 bool
677 atf_tc_get_config_var_as_bool_wd(const atf_tc_t *tc, const char *name,
678 const bool defval)
680 bool val;
682 if (!atf_tc_has_config_var(tc, name))
683 val = defval;
684 else
685 val = atf_tc_get_config_var_as_bool(tc, name);
687 return val;
690 long
691 atf_tc_get_config_var_as_long(const atf_tc_t *tc, const char *name)
693 long val;
694 const char *strval;
695 atf_error_t err;
697 strval = atf_tc_get_config_var(tc, name);
698 err = atf_text_to_long(strval, &val);
699 if (atf_is_error(err)) {
700 atf_error_free(err);
701 atf_tc_fail("Configuration variable %s does not have a valid "
702 "long value; found %s", name, strval);
705 return val;
708 long
709 atf_tc_get_config_var_as_long_wd(const atf_tc_t *tc, const char *name,
710 const long defval)
712 long val;
714 if (!atf_tc_has_config_var(tc, name))
715 val = defval;
716 else
717 val = atf_tc_get_config_var_as_long(tc, name);
719 return val;
722 const char *
723 atf_tc_get_md_var(const atf_tc_t *tc, const char *name)
725 const char *val;
726 atf_map_citer_t iter;
728 PRE(atf_tc_has_md_var(tc, name));
729 iter = atf_map_find_c(&tc->pimpl->m_vars, name);
730 val = atf_map_citer_data(iter);
731 INV(val != NULL);
733 return val;
736 char **
737 atf_tc_get_md_vars(const atf_tc_t *tc)
739 return atf_map_to_charpp(&tc->pimpl->m_vars);
742 bool
743 atf_tc_has_config_var(const atf_tc_t *tc, const char *name)
745 atf_map_citer_t end, iter;
747 iter = atf_map_find_c(&tc->pimpl->m_config, name);
748 end = atf_map_end_c(&tc->pimpl->m_config);
749 return !atf_equal_map_citer_map_citer(iter, end);
752 bool
753 atf_tc_has_md_var(const atf_tc_t *tc, const char *name)
755 atf_map_citer_t end, iter;
757 iter = atf_map_find_c(&tc->pimpl->m_vars, name);
758 end = atf_map_end_c(&tc->pimpl->m_vars);
759 return !atf_equal_map_citer_map_citer(iter, end);
763 * Modifiers.
766 atf_error_t
767 atf_tc_set_md_var(atf_tc_t *tc, const char *name, const char *fmt, ...)
769 atf_error_t err;
770 char *value;
771 va_list ap;
773 va_start(ap, fmt);
774 err = atf_text_format_ap(&value, fmt, ap);
775 va_end(ap);
777 if (!atf_is_error(err))
778 err = atf_map_insert(&tc->pimpl->m_vars, name, value, true);
779 else
780 free(value);
782 return err;
785 /* ---------------------------------------------------------------------
786 * Free functions, as they should be publicly but they can't.
787 * --------------------------------------------------------------------- */
789 static void _atf_tc_fail(struct context *, const char *, va_list)
790 ATF_DEFS_ATTRIBUTE_NORETURN;
791 static void _atf_tc_fail_nonfatal(struct context *, const char *, va_list);
792 static void _atf_tc_fail_check(struct context *, const char *, const size_t,
793 const char *, va_list);
794 static void _atf_tc_fail_requirement(struct context *, const char *,
795 const size_t, const char *, va_list) ATF_DEFS_ATTRIBUTE_NORETURN;
796 static void _atf_tc_pass(struct context *) ATF_DEFS_ATTRIBUTE_NORETURN;
797 static void _atf_tc_require_prog(struct context *, const char *);
798 static void _atf_tc_skip(struct context *, const char *, va_list)
799 ATF_DEFS_ATTRIBUTE_NORETURN;
800 static void _atf_tc_check_errno(struct context *, const char *, const size_t,
801 const int, const char *, const bool);
802 static void _atf_tc_require_errno(struct context *, const char *, const size_t,
803 const int, const char *, const bool);
804 static void _atf_tc_expect_pass(struct context *);
805 static void _atf_tc_expect_fail(struct context *, const char *, va_list);
806 static void _atf_tc_expect_exit(struct context *, const int, const char *,
807 va_list);
808 static void _atf_tc_expect_signal(struct context *, const int, const char *,
809 va_list);
810 static void _atf_tc_expect_death(struct context *, const char *,
811 va_list);
813 static void
814 _atf_tc_fail(struct context *ctx, const char *fmt, va_list ap)
816 va_list ap2;
817 atf_dynstr_t reason;
819 va_copy(ap2, ap);
820 format_reason_ap(&reason, NULL, 0, fmt, ap2);
821 va_end(ap2);
823 fail_requirement(ctx, &reason);
824 UNREACHABLE;
827 static void
828 _atf_tc_fail_nonfatal(struct context *ctx, const char *fmt, va_list ap)
830 va_list ap2;
831 atf_dynstr_t reason;
833 va_copy(ap2, ap);
834 format_reason_ap(&reason, NULL, 0, fmt, ap2);
835 va_end(ap2);
837 fail_check(ctx, &reason);
840 static void
841 _atf_tc_fail_check(struct context *ctx, const char *file, const size_t line,
842 const char *fmt, va_list ap)
844 va_list ap2;
845 atf_dynstr_t reason;
847 va_copy(ap2, ap);
848 format_reason_ap(&reason, file, line, fmt, ap2);
849 va_end(ap2);
851 fail_check(ctx, &reason);
854 static void
855 _atf_tc_fail_requirement(struct context *ctx, const char *file,
856 const size_t line, const char *fmt, va_list ap)
858 va_list ap2;
859 atf_dynstr_t reason;
861 va_copy(ap2, ap);
862 format_reason_ap(&reason, file, line, fmt, ap2);
863 va_end(ap2);
865 fail_requirement(ctx, &reason);
866 UNREACHABLE;
869 static void
870 _atf_tc_pass(struct context *ctx)
872 pass(ctx);
873 UNREACHABLE;
876 static void
877 _atf_tc_require_prog(struct context *ctx, const char *prog)
879 check_fatal_error(check_prog(ctx, prog));
882 static void
883 _atf_tc_skip(struct context *ctx, const char *fmt, va_list ap)
885 atf_dynstr_t reason;
886 va_list ap2;
888 va_copy(ap2, ap);
889 format_reason_ap(&reason, NULL, 0, fmt, ap2);
890 va_end(ap2);
892 skip(ctx, &reason);
895 static void
896 _atf_tc_check_errno(struct context *ctx, const char *file, const size_t line,
897 const int exp_errno, const char *expr_str,
898 const bool expr_result)
900 errno_test(ctx, file, line, exp_errno, expr_str, expr_result, fail_check);
903 static void
904 _atf_tc_require_errno(struct context *ctx, const char *file, const size_t line,
905 const int exp_errno, const char *expr_str,
906 const bool expr_result)
908 errno_test(ctx, file, line, exp_errno, expr_str, expr_result,
909 fail_requirement);
912 static void
913 _atf_tc_expect_pass(struct context *ctx)
915 validate_expect(ctx);
917 ctx->expect = EXPECT_PASS;
920 static void
921 _atf_tc_expect_fail(struct context *ctx, const char *reason, va_list ap)
923 va_list ap2;
925 validate_expect(ctx);
927 ctx->expect = EXPECT_FAIL;
928 atf_dynstr_fini(&ctx->expect_reason);
929 va_copy(ap2, ap);
930 check_fatal_error(atf_dynstr_init_ap(&ctx->expect_reason, reason, ap2));
931 va_end(ap2);
932 ctx->expect_previous_fail_count = ctx->expect_fail_count;
935 static void
936 _atf_tc_expect_exit(struct context *ctx, const int exitcode, const char *reason,
937 va_list ap)
939 va_list ap2;
940 atf_dynstr_t formatted;
942 validate_expect(ctx);
944 ctx->expect = EXPECT_EXIT;
945 va_copy(ap2, ap);
946 check_fatal_error(atf_dynstr_init_ap(&formatted, reason, ap2));
947 va_end(ap2);
949 create_resfile(ctx->resfile, "expected_exit", exitcode, &formatted);
952 static void
953 _atf_tc_expect_signal(struct context *ctx, const int signo, const char *reason,
954 va_list ap)
956 va_list ap2;
957 atf_dynstr_t formatted;
959 validate_expect(ctx);
961 ctx->expect = EXPECT_SIGNAL;
962 va_copy(ap2, ap);
963 check_fatal_error(atf_dynstr_init_ap(&formatted, reason, ap2));
964 va_end(ap2);
966 create_resfile(ctx->resfile, "expected_signal", signo, &formatted);
969 static void
970 _atf_tc_expect_death(struct context *ctx, const char *reason, va_list ap)
972 va_list ap2;
973 atf_dynstr_t formatted;
975 validate_expect(ctx);
977 ctx->expect = EXPECT_DEATH;
978 va_copy(ap2, ap);
979 check_fatal_error(atf_dynstr_init_ap(&formatted, reason, ap2));
980 va_end(ap2);
982 create_resfile(ctx->resfile, "expected_death", -1, &formatted);
985 static void
986 _atf_tc_expect_timeout(struct context *ctx, const char *reason, va_list ap)
988 va_list ap2;
989 atf_dynstr_t formatted;
991 validate_expect(ctx);
993 ctx->expect = EXPECT_TIMEOUT;
994 va_copy(ap2, ap);
995 check_fatal_error(atf_dynstr_init_ap(&formatted, reason, ap2));
996 va_end(ap2);
998 create_resfile(ctx->resfile, "expected_timeout", -1, &formatted);
1001 /* ---------------------------------------------------------------------
1002 * Free functions.
1003 * --------------------------------------------------------------------- */
1005 static struct context Current;
1007 atf_error_t
1008 atf_tc_run(const atf_tc_t *tc, const char *resfile)
1010 context_init(&Current, tc, resfile);
1012 tc->pimpl->m_body(tc);
1014 validate_expect(&Current);
1016 if (Current.fail_count > 0) {
1017 atf_dynstr_t reason;
1019 format_reason_fmt(&reason, NULL, 0, "%d checks failed; see output for "
1020 "more details", Current.fail_count);
1021 fail_requirement(&Current, &reason);
1022 } else if (Current.expect_fail_count > 0) {
1023 atf_dynstr_t reason;
1025 format_reason_fmt(&reason, NULL, 0, "%d checks failed as expected; "
1026 "see output for more details", Current.expect_fail_count);
1027 expected_failure(&Current, &reason);
1028 } else {
1029 pass(&Current);
1031 UNREACHABLE;
1032 return atf_no_error();
1035 atf_error_t
1036 atf_tc_cleanup(const atf_tc_t *tc)
1038 if (tc->pimpl->m_cleanup != NULL)
1039 tc->pimpl->m_cleanup(tc);
1040 return atf_no_error(); /* XXX */
1043 /* ---------------------------------------------------------------------
1044 * Free functions that depend on Current.
1045 * --------------------------------------------------------------------- */
1048 * All the functions below provide delegates to other internal functions
1049 * (prefixed by _) that take the current test case as an argument to
1050 * prevent them from accessing global state. This is to keep the side-
1051 * effects of the internal functions clearer and easier to understand.
1053 * The public API should never have hid the fact that it needs access to
1054 * the current test case (other than maybe in the macros), but changing it
1055 * is hard. TODO: Revisit in the future.
1058 void
1059 atf_tc_fail(const char *fmt, ...)
1061 va_list ap;
1063 PRE(Current.tc != NULL);
1065 va_start(ap, fmt);
1066 _atf_tc_fail(&Current, fmt, ap);
1067 va_end(ap);
1070 void
1071 atf_tc_fail_nonfatal(const char *fmt, ...)
1073 va_list ap;
1075 PRE(Current.tc != NULL);
1077 va_start(ap, fmt);
1078 _atf_tc_fail_nonfatal(&Current, fmt, ap);
1079 va_end(ap);
1082 void
1083 atf_tc_fail_check(const char *file, const size_t line, const char *fmt, ...)
1085 va_list ap;
1087 PRE(Current.tc != NULL);
1089 va_start(ap, fmt);
1090 _atf_tc_fail_check(&Current, file, line, fmt, ap);
1091 va_end(ap);
1094 void
1095 atf_tc_fail_requirement(const char *file, const size_t line,
1096 const char *fmt, ...)
1098 va_list ap;
1100 PRE(Current.tc != NULL);
1102 va_start(ap, fmt);
1103 _atf_tc_fail_requirement(&Current, file, line, fmt, ap);
1104 va_end(ap);
1107 void
1108 atf_tc_pass(void)
1110 PRE(Current.tc != NULL);
1112 _atf_tc_pass(&Current);
1115 void
1116 atf_tc_require_prog(const char *prog)
1118 PRE(Current.tc != NULL);
1120 _atf_tc_require_prog(&Current, prog);
1123 void
1124 atf_tc_skip(const char *fmt, ...)
1126 va_list ap;
1128 PRE(Current.tc != NULL);
1130 va_start(ap, fmt);
1131 _atf_tc_skip(&Current, fmt, ap);
1132 va_end(ap);
1135 void
1136 atf_tc_check_errno(const char *file, const size_t line, const int exp_errno,
1137 const char *expr_str, const bool expr_result)
1139 PRE(Current.tc != NULL);
1141 _atf_tc_check_errno(&Current, file, line, exp_errno, expr_str,
1142 expr_result);
1145 void
1146 atf_tc_require_errno(const char *file, const size_t line, const int exp_errno,
1147 const char *expr_str, const bool expr_result)
1149 PRE(Current.tc != NULL);
1151 _atf_tc_require_errno(&Current, file, line, exp_errno, expr_str,
1152 expr_result);
1155 void
1156 atf_tc_expect_pass(void)
1158 PRE(Current.tc != NULL);
1160 _atf_tc_expect_pass(&Current);
1163 void
1164 atf_tc_expect_fail(const char *reason, ...)
1166 va_list ap;
1168 PRE(Current.tc != NULL);
1170 va_start(ap, reason);
1171 _atf_tc_expect_fail(&Current, reason, ap);
1172 va_end(ap);
1175 void
1176 atf_tc_expect_exit(const int exitcode, const char *reason, ...)
1178 va_list ap;
1180 PRE(Current.tc != NULL);
1182 va_start(ap, reason);
1183 _atf_tc_expect_exit(&Current, exitcode, reason, ap);
1184 va_end(ap);
1187 void
1188 atf_tc_expect_signal(const int signo, const char *reason, ...)
1190 va_list ap;
1192 PRE(Current.tc != NULL);
1194 va_start(ap, reason);
1195 _atf_tc_expect_signal(&Current, signo, reason, ap);
1196 va_end(ap);
1199 void
1200 atf_tc_expect_death(const char *reason, ...)
1202 va_list ap;
1204 PRE(Current.tc != NULL);
1206 va_start(ap, reason);
1207 _atf_tc_expect_death(&Current, reason, ap);
1208 va_end(ap);
1211 void
1212 atf_tc_expect_timeout(const char *reason, ...)
1214 va_list ap;
1216 PRE(Current.tc != NULL);
1218 va_start(ap, reason);
1219 _atf_tc_expect_timeout(&Current, reason, ap);
1220 va_end(ap);