xref: /minix3/external/bsd/atf/dist/atf-c/tc.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
111be35a1SLionel Sambuc /*
211be35a1SLionel Sambuc  * Automated Testing Framework (atf)
311be35a1SLionel Sambuc  *
411be35a1SLionel Sambuc  * Copyright (c) 2008 The NetBSD Foundation, Inc.
511be35a1SLionel Sambuc  * All rights reserved.
611be35a1SLionel Sambuc  *
711be35a1SLionel Sambuc  * Redistribution and use in source and binary forms, with or without
811be35a1SLionel Sambuc  * modification, are permitted provided that the following conditions
911be35a1SLionel Sambuc  * are met:
1011be35a1SLionel Sambuc  * 1. Redistributions of source code must retain the above copyright
1111be35a1SLionel Sambuc  *    notice, this list of conditions and the following disclaimer.
1211be35a1SLionel Sambuc  * 2. Redistributions in binary form must reproduce the above copyright
1311be35a1SLionel Sambuc  *    notice, this list of conditions and the following disclaimer in the
1411be35a1SLionel Sambuc  *    documentation and/or other materials provided with the distribution.
1511be35a1SLionel Sambuc  *
1611be35a1SLionel Sambuc  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
1711be35a1SLionel Sambuc  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
1811be35a1SLionel Sambuc  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
1911be35a1SLionel Sambuc  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2011be35a1SLionel Sambuc  * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
2111be35a1SLionel Sambuc  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2211be35a1SLionel Sambuc  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
2311be35a1SLionel Sambuc  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2411be35a1SLionel Sambuc  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
2511be35a1SLionel Sambuc  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
2611be35a1SLionel Sambuc  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
2711be35a1SLionel Sambuc  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2811be35a1SLionel Sambuc  */
2911be35a1SLionel Sambuc 
3011be35a1SLionel Sambuc #include <sys/types.h>
3111be35a1SLionel Sambuc #include <sys/stat.h>
3211be35a1SLionel Sambuc #include <sys/uio.h>
3311be35a1SLionel Sambuc 
3411be35a1SLionel Sambuc #include <errno.h>
3511be35a1SLionel Sambuc #include <fcntl.h>
3611be35a1SLionel Sambuc #include <stdarg.h>
3711be35a1SLionel Sambuc #include <stdbool.h>
3811be35a1SLionel Sambuc #include <stdio.h>
3911be35a1SLionel Sambuc #include <stdlib.h>
4011be35a1SLionel Sambuc #include <string.h>
4111be35a1SLionel Sambuc #include <unistd.h>
4211be35a1SLionel Sambuc 
4311be35a1SLionel Sambuc #include "atf-c/defs.h"
4411be35a1SLionel Sambuc #include "atf-c/error.h"
4511be35a1SLionel Sambuc #include "atf-c/tc.h"
4611be35a1SLionel Sambuc 
4711be35a1SLionel Sambuc #include "detail/env.h"
4811be35a1SLionel Sambuc #include "detail/fs.h"
4911be35a1SLionel Sambuc #include "detail/map.h"
5011be35a1SLionel Sambuc #include "detail/sanity.h"
5111be35a1SLionel Sambuc #include "detail/text.h"
5211be35a1SLionel Sambuc 
5311be35a1SLionel Sambuc /* ---------------------------------------------------------------------
5411be35a1SLionel Sambuc  * Auxiliary functions.
5511be35a1SLionel Sambuc  * --------------------------------------------------------------------- */
5611be35a1SLionel Sambuc 
5711be35a1SLionel Sambuc enum expect_type {
5811be35a1SLionel Sambuc     EXPECT_PASS,
5911be35a1SLionel Sambuc     EXPECT_FAIL,
6011be35a1SLionel Sambuc     EXPECT_EXIT,
6111be35a1SLionel Sambuc     EXPECT_SIGNAL,
6211be35a1SLionel Sambuc     EXPECT_DEATH,
6311be35a1SLionel Sambuc     EXPECT_TIMEOUT,
6411be35a1SLionel Sambuc };
6511be35a1SLionel Sambuc 
6611be35a1SLionel Sambuc struct context {
6711be35a1SLionel Sambuc     const atf_tc_t *tc;
6811be35a1SLionel Sambuc     const char *resfile;
6911be35a1SLionel Sambuc     size_t fail_count;
7011be35a1SLionel Sambuc 
7111be35a1SLionel Sambuc     enum expect_type expect;
7211be35a1SLionel Sambuc     atf_dynstr_t expect_reason;
7311be35a1SLionel Sambuc     size_t expect_previous_fail_count;
7411be35a1SLionel Sambuc     size_t expect_fail_count;
7511be35a1SLionel Sambuc     int expect_exitcode;
7611be35a1SLionel Sambuc     int expect_signo;
7711be35a1SLionel Sambuc };
7811be35a1SLionel Sambuc 
7911be35a1SLionel Sambuc static void context_init(struct context *, const atf_tc_t *, const char *);
8011be35a1SLionel Sambuc static void check_fatal_error(atf_error_t);
8111be35a1SLionel Sambuc static void report_fatal_error(const char *, ...)
82*0a6a1f1dSLionel Sambuc     ATF_DEFS_ATTRIBUTE_FORMAT_PRINTF(1, 2)
8311be35a1SLionel Sambuc     ATF_DEFS_ATTRIBUTE_NORETURN;
8411be35a1SLionel Sambuc static atf_error_t write_resfile(const int, const char *, const int,
8511be35a1SLionel Sambuc                                  const atf_dynstr_t *);
8611be35a1SLionel Sambuc static void create_resfile(const char *, const char *, const int,
8711be35a1SLionel Sambuc                            atf_dynstr_t *);
8811be35a1SLionel Sambuc static void error_in_expect(struct context *, const char *, ...)
89*0a6a1f1dSLionel Sambuc     ATF_DEFS_ATTRIBUTE_FORMAT_PRINTF(2, 3)
9011be35a1SLionel Sambuc     ATF_DEFS_ATTRIBUTE_NORETURN;
9111be35a1SLionel Sambuc static void validate_expect(struct context *);
9211be35a1SLionel Sambuc static void expected_failure(struct context *, atf_dynstr_t *)
9311be35a1SLionel Sambuc     ATF_DEFS_ATTRIBUTE_NORETURN;
9411be35a1SLionel Sambuc static void fail_requirement(struct context *, atf_dynstr_t *)
9511be35a1SLionel Sambuc     ATF_DEFS_ATTRIBUTE_NORETURN;
9611be35a1SLionel Sambuc static void fail_check(struct context *, atf_dynstr_t *);
9711be35a1SLionel Sambuc static void pass(struct context *)
9811be35a1SLionel Sambuc     ATF_DEFS_ATTRIBUTE_NORETURN;
9911be35a1SLionel Sambuc static void skip(struct context *, atf_dynstr_t *)
10011be35a1SLionel Sambuc     ATF_DEFS_ATTRIBUTE_NORETURN;
10111be35a1SLionel Sambuc static void format_reason_ap(atf_dynstr_t *, const char *, const size_t,
102*0a6a1f1dSLionel Sambuc                              const char *, va_list)
103*0a6a1f1dSLionel Sambuc     ATF_DEFS_ATTRIBUTE_FORMAT_PRINTF(4, 0);
10411be35a1SLionel Sambuc static void format_reason_fmt(atf_dynstr_t *, const char *, const size_t,
105*0a6a1f1dSLionel Sambuc                               const char *, ...)
106*0a6a1f1dSLionel Sambuc     ATF_DEFS_ATTRIBUTE_FORMAT_PRINTF(4, 5);
10711be35a1SLionel Sambuc static void errno_test(struct context *, const char *, const size_t,
10811be35a1SLionel Sambuc                        const int, const char *, const bool,
10911be35a1SLionel Sambuc                        void (*)(struct context *, atf_dynstr_t *));
11011be35a1SLionel Sambuc static atf_error_t check_prog_in_dir(const char *, void *);
11111be35a1SLionel Sambuc static atf_error_t check_prog(struct context *, const char *);
11211be35a1SLionel Sambuc 
11311be35a1SLionel Sambuc static void
context_init(struct context * ctx,const atf_tc_t * tc,const char * resfile)11411be35a1SLionel Sambuc context_init(struct context *ctx, const atf_tc_t *tc, const char *resfile)
11511be35a1SLionel Sambuc {
11611be35a1SLionel Sambuc     ctx->tc = tc;
11711be35a1SLionel Sambuc     ctx->resfile = resfile;
11811be35a1SLionel Sambuc     ctx->fail_count = 0;
11911be35a1SLionel Sambuc     ctx->expect = EXPECT_PASS;
12011be35a1SLionel Sambuc     check_fatal_error(atf_dynstr_init(&ctx->expect_reason));
12111be35a1SLionel Sambuc     ctx->expect_previous_fail_count = 0;
12211be35a1SLionel Sambuc     ctx->expect_fail_count = 0;
12311be35a1SLionel Sambuc     ctx->expect_exitcode = 0;
12411be35a1SLionel Sambuc     ctx->expect_signo = 0;
12511be35a1SLionel Sambuc }
12611be35a1SLionel Sambuc 
12711be35a1SLionel Sambuc static void
check_fatal_error(atf_error_t err)12811be35a1SLionel Sambuc check_fatal_error(atf_error_t err)
12911be35a1SLionel Sambuc {
13011be35a1SLionel Sambuc     if (atf_is_error(err)) {
13111be35a1SLionel Sambuc         char buf[1024];
13211be35a1SLionel Sambuc         atf_error_format(err, buf, sizeof(buf));
13311be35a1SLionel Sambuc         fprintf(stderr, "FATAL ERROR: %s\n", buf);
13411be35a1SLionel Sambuc         atf_error_free(err);
13511be35a1SLionel Sambuc         abort();
13611be35a1SLionel Sambuc     }
13711be35a1SLionel Sambuc }
13811be35a1SLionel Sambuc 
13911be35a1SLionel Sambuc static void
report_fatal_error(const char * msg,...)14011be35a1SLionel Sambuc report_fatal_error(const char *msg, ...)
14111be35a1SLionel Sambuc {
14211be35a1SLionel Sambuc     va_list ap;
14311be35a1SLionel Sambuc     fprintf(stderr, "FATAL ERROR: ");
14411be35a1SLionel Sambuc 
14511be35a1SLionel Sambuc     va_start(ap, msg);
14611be35a1SLionel Sambuc     vfprintf(stderr, msg, ap);
14711be35a1SLionel Sambuc     va_end(ap);
14811be35a1SLionel Sambuc 
14911be35a1SLionel Sambuc     fprintf(stderr, "\n");
15011be35a1SLionel Sambuc     abort();
15111be35a1SLionel Sambuc }
15211be35a1SLionel Sambuc 
15311be35a1SLionel Sambuc /** Writes to a results file.
15411be35a1SLionel Sambuc  *
15511be35a1SLionel Sambuc  * The results file is supposed to be already open.
15611be35a1SLionel Sambuc  *
15711be35a1SLionel Sambuc  * This function returns an error code instead of exiting in case of error
15811be35a1SLionel Sambuc  * because the caller needs to clean up the reason object before terminating.
15911be35a1SLionel Sambuc  */
16011be35a1SLionel Sambuc static atf_error_t
write_resfile(const int fd,const char * result,const int arg,const atf_dynstr_t * reason)16111be35a1SLionel Sambuc write_resfile(const int fd, const char *result, const int arg,
16211be35a1SLionel Sambuc               const atf_dynstr_t *reason)
16311be35a1SLionel Sambuc {
16411be35a1SLionel Sambuc     static char NL[] = "\n", CS[] = ": ";
16511be35a1SLionel Sambuc     char buf[64];
16611be35a1SLionel Sambuc     const char *r;
16711be35a1SLionel Sambuc     struct iovec iov[5];
16811be35a1SLionel Sambuc     ssize_t ret;
16911be35a1SLionel Sambuc     int count = 0;
17011be35a1SLionel Sambuc 
17111be35a1SLionel Sambuc     INV(arg == -1 || reason != NULL);
17211be35a1SLionel Sambuc 
17311be35a1SLionel Sambuc #define UNCONST(a) ((void *)(unsigned long)(const void *)(a))
17411be35a1SLionel Sambuc     iov[count].iov_base = UNCONST(result);
17511be35a1SLionel Sambuc     iov[count++].iov_len = strlen(result);
17611be35a1SLionel Sambuc 
17711be35a1SLionel Sambuc     if (reason != NULL) {
17811be35a1SLionel Sambuc         if (arg != -1) {
17911be35a1SLionel Sambuc             iov[count].iov_base = buf;
18011be35a1SLionel Sambuc             iov[count++].iov_len = snprintf(buf, sizeof(buf), "(%d)", arg);
18111be35a1SLionel Sambuc         }
18211be35a1SLionel Sambuc 
18311be35a1SLionel Sambuc         iov[count].iov_base = CS;
18411be35a1SLionel Sambuc         iov[count++].iov_len = sizeof(CS) - 1;
18511be35a1SLionel Sambuc 
18611be35a1SLionel Sambuc         r = atf_dynstr_cstring(reason);
18711be35a1SLionel Sambuc         iov[count].iov_base = UNCONST(r);
18811be35a1SLionel Sambuc         iov[count++].iov_len = strlen(r);
18911be35a1SLionel Sambuc     }
19011be35a1SLionel Sambuc #undef UNCONST
19111be35a1SLionel Sambuc 
19211be35a1SLionel Sambuc     iov[count].iov_base = NL;
19311be35a1SLionel Sambuc     iov[count++].iov_len = sizeof(NL) - 1;
19411be35a1SLionel Sambuc 
19511be35a1SLionel Sambuc     while ((ret = writev(fd, iov, count)) == -1 && errno == EINTR)
19611be35a1SLionel Sambuc         continue; /* Retry. */
19711be35a1SLionel Sambuc     if (ret != -1)
19811be35a1SLionel Sambuc         return atf_no_error();
19911be35a1SLionel Sambuc 
20011be35a1SLionel Sambuc     return atf_libc_error(
20111be35a1SLionel Sambuc         errno, "Failed to write results file; result %s, reason %s", result,
20211be35a1SLionel Sambuc         reason == NULL ? "null" : atf_dynstr_cstring(reason));
20311be35a1SLionel Sambuc }
20411be35a1SLionel Sambuc 
20511be35a1SLionel Sambuc /** Creates a results file.
20611be35a1SLionel Sambuc  *
20711be35a1SLionel Sambuc  * The input reason is released in all cases.
20811be35a1SLionel Sambuc  *
20911be35a1SLionel Sambuc  * An error in this function is considered to be fatal, hence why it does
21011be35a1SLionel Sambuc  * not return any error code.
21111be35a1SLionel Sambuc  */
21211be35a1SLionel Sambuc static void
create_resfile(const char * resfile,const char * result,const int arg,atf_dynstr_t * reason)21311be35a1SLionel Sambuc create_resfile(const char *resfile, const char *result, const int arg,
21411be35a1SLionel Sambuc                atf_dynstr_t *reason)
21511be35a1SLionel Sambuc {
21611be35a1SLionel Sambuc     atf_error_t err;
21711be35a1SLionel Sambuc 
21811be35a1SLionel Sambuc     if (strcmp("/dev/stdout", resfile) == 0) {
21911be35a1SLionel Sambuc         err = write_resfile(STDOUT_FILENO, result, arg, reason);
22011be35a1SLionel Sambuc     } else if (strcmp("/dev/stderr", resfile) == 0) {
22111be35a1SLionel Sambuc         err = write_resfile(STDERR_FILENO, result, arg, reason);
22211be35a1SLionel Sambuc     } else {
22311be35a1SLionel Sambuc         const int fd = open(resfile, O_WRONLY | O_CREAT | O_TRUNC,
22411be35a1SLionel Sambuc             S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
22511be35a1SLionel Sambuc         if (fd == -1) {
22611be35a1SLionel Sambuc             err = atf_libc_error(errno, "Cannot create results file '%s'",
22711be35a1SLionel Sambuc                                  resfile);
22811be35a1SLionel Sambuc         } else {
22911be35a1SLionel Sambuc             err = write_resfile(fd, result, arg, reason);
23011be35a1SLionel Sambuc             close(fd);
23111be35a1SLionel Sambuc         }
23211be35a1SLionel Sambuc     }
23311be35a1SLionel Sambuc 
23411be35a1SLionel Sambuc     if (reason != NULL)
23511be35a1SLionel Sambuc         atf_dynstr_fini(reason);
23611be35a1SLionel Sambuc 
23711be35a1SLionel Sambuc     check_fatal_error(err);
23811be35a1SLionel Sambuc }
23911be35a1SLionel Sambuc 
24011be35a1SLionel Sambuc /** Fails a test case if validate_expect fails. */
24111be35a1SLionel Sambuc static void
error_in_expect(struct context * ctx,const char * fmt,...)24211be35a1SLionel Sambuc error_in_expect(struct context *ctx, const char *fmt, ...)
24311be35a1SLionel Sambuc {
24411be35a1SLionel Sambuc     atf_dynstr_t reason;
24511be35a1SLionel Sambuc     va_list ap;
24611be35a1SLionel Sambuc 
24711be35a1SLionel Sambuc     va_start(ap, fmt);
24811be35a1SLionel Sambuc     format_reason_ap(&reason, NULL, 0, fmt, ap);
24911be35a1SLionel Sambuc     va_end(ap);
25011be35a1SLionel Sambuc 
25111be35a1SLionel Sambuc     ctx->expect = EXPECT_PASS;  /* Ensure fail_requirement really fails. */
25211be35a1SLionel Sambuc     fail_requirement(ctx, &reason);
25311be35a1SLionel Sambuc }
25411be35a1SLionel Sambuc 
25511be35a1SLionel Sambuc /** Ensures that the "expect" state is correct.
25611be35a1SLionel Sambuc  *
25711be35a1SLionel Sambuc  * Call this function before modifying the current value of expect.
25811be35a1SLionel Sambuc  */
25911be35a1SLionel Sambuc static void
validate_expect(struct context * ctx)26011be35a1SLionel Sambuc validate_expect(struct context *ctx)
26111be35a1SLionel Sambuc {
26211be35a1SLionel Sambuc     if (ctx->expect == EXPECT_DEATH) {
26311be35a1SLionel Sambuc         error_in_expect(ctx, "Test case was expected to terminate abruptly "
26411be35a1SLionel Sambuc             "but it continued execution");
26511be35a1SLionel Sambuc     } else if (ctx->expect == EXPECT_EXIT) {
26611be35a1SLionel Sambuc         error_in_expect(ctx, "Test case was expected to exit cleanly but it "
26711be35a1SLionel Sambuc             "continued execution");
26811be35a1SLionel Sambuc     } else if (ctx->expect == EXPECT_FAIL) {
26911be35a1SLionel Sambuc         if (ctx->expect_fail_count == ctx->expect_previous_fail_count)
27011be35a1SLionel Sambuc             error_in_expect(ctx, "Test case was expecting a failure but none "
27111be35a1SLionel Sambuc                 "were raised");
27211be35a1SLionel Sambuc         else
27311be35a1SLionel Sambuc             INV(ctx->expect_fail_count > ctx->expect_previous_fail_count);
27411be35a1SLionel Sambuc     } else if (ctx->expect == EXPECT_PASS) {
27511be35a1SLionel Sambuc         /* Nothing to validate. */
27611be35a1SLionel Sambuc     } else if (ctx->expect == EXPECT_SIGNAL) {
27711be35a1SLionel Sambuc         error_in_expect(ctx, "Test case was expected to receive a termination "
27811be35a1SLionel Sambuc             "signal but it continued execution");
27911be35a1SLionel Sambuc     } else if (ctx->expect == EXPECT_TIMEOUT) {
28011be35a1SLionel Sambuc         error_in_expect(ctx, "Test case was expected to hang but it continued "
28111be35a1SLionel Sambuc             "execution");
28211be35a1SLionel Sambuc     } else
28311be35a1SLionel Sambuc         UNREACHABLE;
28411be35a1SLionel Sambuc }
28511be35a1SLionel Sambuc 
28611be35a1SLionel Sambuc static void
expected_failure(struct context * ctx,atf_dynstr_t * reason)28711be35a1SLionel Sambuc expected_failure(struct context *ctx, atf_dynstr_t *reason)
28811be35a1SLionel Sambuc {
28911be35a1SLionel Sambuc     check_fatal_error(atf_dynstr_prepend_fmt(reason, "%s: ",
29011be35a1SLionel Sambuc         atf_dynstr_cstring(&ctx->expect_reason)));
29111be35a1SLionel Sambuc     create_resfile(ctx->resfile, "expected_failure", -1, reason);
29211be35a1SLionel Sambuc     exit(EXIT_SUCCESS);
29311be35a1SLionel Sambuc }
29411be35a1SLionel Sambuc 
29511be35a1SLionel Sambuc static void
fail_requirement(struct context * ctx,atf_dynstr_t * reason)29611be35a1SLionel Sambuc fail_requirement(struct context *ctx, atf_dynstr_t *reason)
29711be35a1SLionel Sambuc {
29811be35a1SLionel Sambuc     if (ctx->expect == EXPECT_FAIL) {
29911be35a1SLionel Sambuc         expected_failure(ctx, reason);
30011be35a1SLionel Sambuc     } else if (ctx->expect == EXPECT_PASS) {
30111be35a1SLionel Sambuc         create_resfile(ctx->resfile, "failed", -1, reason);
30211be35a1SLionel Sambuc         exit(EXIT_FAILURE);
30311be35a1SLionel Sambuc     } else {
30411be35a1SLionel Sambuc         error_in_expect(ctx, "Test case raised a failure but was not "
30511be35a1SLionel Sambuc             "expecting one; reason was %s", atf_dynstr_cstring(reason));
30611be35a1SLionel Sambuc     }
30711be35a1SLionel Sambuc     UNREACHABLE;
30811be35a1SLionel Sambuc }
30911be35a1SLionel Sambuc 
31011be35a1SLionel Sambuc static void
fail_check(struct context * ctx,atf_dynstr_t * reason)31111be35a1SLionel Sambuc fail_check(struct context *ctx, atf_dynstr_t *reason)
31211be35a1SLionel Sambuc {
31311be35a1SLionel Sambuc     if (ctx->expect == EXPECT_FAIL) {
31411be35a1SLionel Sambuc         fprintf(stderr, "*** Expected check failure: %s: %s\n",
31511be35a1SLionel Sambuc             atf_dynstr_cstring(&ctx->expect_reason),
31611be35a1SLionel Sambuc             atf_dynstr_cstring(reason));
31711be35a1SLionel Sambuc         ctx->expect_fail_count++;
31811be35a1SLionel Sambuc     } else if (ctx->expect == EXPECT_PASS) {
31911be35a1SLionel Sambuc         fprintf(stderr, "*** Check failed: %s\n", atf_dynstr_cstring(reason));
32011be35a1SLionel Sambuc         ctx->fail_count++;
32111be35a1SLionel Sambuc     } else {
32211be35a1SLionel Sambuc         error_in_expect(ctx, "Test case raised a failure but was not "
32311be35a1SLionel Sambuc             "expecting one; reason was %s", atf_dynstr_cstring(reason));
32411be35a1SLionel Sambuc     }
32511be35a1SLionel Sambuc 
32611be35a1SLionel Sambuc     atf_dynstr_fini(reason);
32711be35a1SLionel Sambuc }
32811be35a1SLionel Sambuc 
32911be35a1SLionel Sambuc static void
pass(struct context * ctx)33011be35a1SLionel Sambuc pass(struct context *ctx)
33111be35a1SLionel Sambuc {
33211be35a1SLionel Sambuc     if (ctx->expect == EXPECT_FAIL) {
33311be35a1SLionel Sambuc         error_in_expect(ctx, "Test case was expecting a failure but got "
33411be35a1SLionel Sambuc             "a pass instead");
33511be35a1SLionel Sambuc     } else if (ctx->expect == EXPECT_PASS) {
33611be35a1SLionel Sambuc         create_resfile(ctx->resfile, "passed", -1, NULL);
33711be35a1SLionel Sambuc         exit(EXIT_SUCCESS);
33811be35a1SLionel Sambuc     } else {
33911be35a1SLionel Sambuc         error_in_expect(ctx, "Test case asked to explicitly pass but was "
34011be35a1SLionel Sambuc             "not expecting such condition");
34111be35a1SLionel Sambuc     }
34211be35a1SLionel Sambuc     UNREACHABLE;
34311be35a1SLionel Sambuc }
34411be35a1SLionel Sambuc 
34511be35a1SLionel Sambuc static void
skip(struct context * ctx,atf_dynstr_t * reason)34611be35a1SLionel Sambuc skip(struct context *ctx, atf_dynstr_t *reason)
34711be35a1SLionel Sambuc {
34811be35a1SLionel Sambuc     if (ctx->expect == EXPECT_PASS) {
34911be35a1SLionel Sambuc         create_resfile(ctx->resfile, "skipped", -1, reason);
35011be35a1SLionel Sambuc         exit(EXIT_SUCCESS);
35111be35a1SLionel Sambuc     } else {
35211be35a1SLionel Sambuc         error_in_expect(ctx, "Can only skip a test case when running in "
35311be35a1SLionel Sambuc             "expect pass mode");
35411be35a1SLionel Sambuc     }
35511be35a1SLionel Sambuc     UNREACHABLE;
35611be35a1SLionel Sambuc }
35711be35a1SLionel Sambuc 
35811be35a1SLionel Sambuc /** Formats a failure/skip reason message.
35911be35a1SLionel Sambuc  *
36011be35a1SLionel Sambuc  * The formatted reason is stored in out_reason.  out_reason is initialized
36111be35a1SLionel Sambuc  * in this function and is supposed to be released by the caller.  In general,
36211be35a1SLionel Sambuc  * the reason will eventually be fed to create_resfile, which will release
36311be35a1SLionel Sambuc  * it.
36411be35a1SLionel Sambuc  *
36511be35a1SLionel Sambuc  * Errors in this function are fatal.  Rationale being: reasons are used to
36611be35a1SLionel Sambuc  * create results files; if we can't format the reason correctly, the result
36711be35a1SLionel Sambuc  * of the test program will be bogus.  So it's better to just exit with a
36811be35a1SLionel Sambuc  * fatal error.
36911be35a1SLionel Sambuc  */
37011be35a1SLionel Sambuc static void
format_reason_ap(atf_dynstr_t * out_reason,const char * source_file,const size_t source_line,const char * reason,va_list ap)37111be35a1SLionel Sambuc format_reason_ap(atf_dynstr_t *out_reason,
37211be35a1SLionel Sambuc                  const char *source_file, const size_t source_line,
37311be35a1SLionel Sambuc                  const char *reason, va_list ap)
37411be35a1SLionel Sambuc {
37511be35a1SLionel Sambuc     atf_error_t err;
37611be35a1SLionel Sambuc 
37711be35a1SLionel Sambuc     if (source_file != NULL) {
37811be35a1SLionel Sambuc         err = atf_dynstr_init_fmt(out_reason, "%s:%zd: ", source_file,
37911be35a1SLionel Sambuc                                   source_line);
38011be35a1SLionel Sambuc     } else {
38111be35a1SLionel Sambuc         PRE(source_line == 0);
38211be35a1SLionel Sambuc         err = atf_dynstr_init(out_reason);
38311be35a1SLionel Sambuc     }
38411be35a1SLionel Sambuc 
38511be35a1SLionel Sambuc     if (!atf_is_error(err)) {
38611be35a1SLionel Sambuc         va_list ap2;
38711be35a1SLionel Sambuc         va_copy(ap2, ap);
38811be35a1SLionel Sambuc         err = atf_dynstr_append_ap(out_reason, reason, ap2);
38911be35a1SLionel Sambuc         va_end(ap2);
39011be35a1SLionel Sambuc     }
39111be35a1SLionel Sambuc 
39211be35a1SLionel Sambuc     check_fatal_error(err);
39311be35a1SLionel Sambuc }
39411be35a1SLionel Sambuc 
39511be35a1SLionel Sambuc static void
format_reason_fmt(atf_dynstr_t * out_reason,const char * source_file,const size_t source_line,const char * reason,...)39611be35a1SLionel Sambuc format_reason_fmt(atf_dynstr_t *out_reason,
39711be35a1SLionel Sambuc                   const char *source_file, const size_t source_line,
39811be35a1SLionel Sambuc                   const char *reason, ...)
39911be35a1SLionel Sambuc {
40011be35a1SLionel Sambuc     va_list ap;
40111be35a1SLionel Sambuc 
40211be35a1SLionel Sambuc     va_start(ap, reason);
40311be35a1SLionel Sambuc     format_reason_ap(out_reason, source_file, source_line, reason, ap);
40411be35a1SLionel Sambuc     va_end(ap);
40511be35a1SLionel Sambuc }
40611be35a1SLionel Sambuc 
40711be35a1SLionel Sambuc static void
errno_test(struct context * ctx,const char * file,const size_t line,const int exp_errno,const char * expr_str,const bool expr_result,void (* fail_func)(struct context *,atf_dynstr_t *))40811be35a1SLionel Sambuc errno_test(struct context *ctx, const char *file, const size_t line,
40911be35a1SLionel Sambuc            const int exp_errno, const char *expr_str,
41011be35a1SLionel Sambuc            const bool expr_result,
41111be35a1SLionel Sambuc            void (*fail_func)(struct context *, atf_dynstr_t *))
41211be35a1SLionel Sambuc {
41311be35a1SLionel Sambuc     const int actual_errno = errno;
41411be35a1SLionel Sambuc 
41511be35a1SLionel Sambuc     if (expr_result) {
41611be35a1SLionel Sambuc         if (exp_errno != actual_errno) {
41711be35a1SLionel Sambuc             atf_dynstr_t reason;
41811be35a1SLionel Sambuc 
41911be35a1SLionel Sambuc             format_reason_fmt(&reason, file, line, "Expected errno %d, got %d, "
42011be35a1SLionel Sambuc                 "in %s", exp_errno, actual_errno, expr_str);
42111be35a1SLionel Sambuc             fail_func(ctx, &reason);
42211be35a1SLionel Sambuc         }
42311be35a1SLionel Sambuc     } else {
42411be35a1SLionel Sambuc         atf_dynstr_t reason;
42511be35a1SLionel Sambuc 
42611be35a1SLionel Sambuc         format_reason_fmt(&reason, file, line, "Expected true value in %s",
42711be35a1SLionel Sambuc             expr_str);
42811be35a1SLionel Sambuc         fail_func(ctx, &reason);
42911be35a1SLionel Sambuc     }
43011be35a1SLionel Sambuc }
43111be35a1SLionel Sambuc 
43211be35a1SLionel Sambuc struct prog_found_pair {
43311be35a1SLionel Sambuc     const char *prog;
43411be35a1SLionel Sambuc     bool found;
43511be35a1SLionel Sambuc };
43611be35a1SLionel Sambuc 
43711be35a1SLionel Sambuc static atf_error_t
check_prog_in_dir(const char * dir,void * data)43811be35a1SLionel Sambuc check_prog_in_dir(const char *dir, void *data)
43911be35a1SLionel Sambuc {
44011be35a1SLionel Sambuc     struct prog_found_pair *pf = data;
44111be35a1SLionel Sambuc     atf_error_t err;
44211be35a1SLionel Sambuc 
44311be35a1SLionel Sambuc     if (pf->found)
44411be35a1SLionel Sambuc         err = atf_no_error();
44511be35a1SLionel Sambuc     else {
44611be35a1SLionel Sambuc         atf_fs_path_t p;
44711be35a1SLionel Sambuc 
44811be35a1SLionel Sambuc         err = atf_fs_path_init_fmt(&p, "%s/%s", dir, pf->prog);
44911be35a1SLionel Sambuc         if (atf_is_error(err))
45011be35a1SLionel Sambuc             goto out_p;
45111be35a1SLionel Sambuc 
45211be35a1SLionel Sambuc         err = atf_fs_eaccess(&p, atf_fs_access_x);
45311be35a1SLionel Sambuc         if (!atf_is_error(err))
45411be35a1SLionel Sambuc             pf->found = true;
45511be35a1SLionel Sambuc         else {
45611be35a1SLionel Sambuc             atf_error_free(err);
45711be35a1SLionel Sambuc             INV(!pf->found);
45811be35a1SLionel Sambuc             err = atf_no_error();
45911be35a1SLionel Sambuc         }
46011be35a1SLionel Sambuc 
46111be35a1SLionel Sambuc out_p:
46211be35a1SLionel Sambuc         atf_fs_path_fini(&p);
46311be35a1SLionel Sambuc     }
46411be35a1SLionel Sambuc 
46511be35a1SLionel Sambuc     return err;
46611be35a1SLionel Sambuc }
46711be35a1SLionel Sambuc 
46811be35a1SLionel Sambuc static atf_error_t
check_prog(struct context * ctx,const char * prog)46911be35a1SLionel Sambuc check_prog(struct context *ctx, const char *prog)
47011be35a1SLionel Sambuc {
47111be35a1SLionel Sambuc     atf_error_t err;
47211be35a1SLionel Sambuc     atf_fs_path_t p;
47311be35a1SLionel Sambuc 
47411be35a1SLionel Sambuc     err = atf_fs_path_init_fmt(&p, "%s", prog);
47511be35a1SLionel Sambuc     if (atf_is_error(err))
47611be35a1SLionel Sambuc         goto out;
47711be35a1SLionel Sambuc 
47811be35a1SLionel Sambuc     if (atf_fs_path_is_absolute(&p)) {
47911be35a1SLionel Sambuc         err = atf_fs_eaccess(&p, atf_fs_access_x);
48011be35a1SLionel Sambuc         if (atf_is_error(err)) {
48111be35a1SLionel Sambuc             atf_dynstr_t reason;
48211be35a1SLionel Sambuc 
48311be35a1SLionel Sambuc             atf_error_free(err);
48411be35a1SLionel Sambuc             atf_fs_path_fini(&p);
48511be35a1SLionel Sambuc             format_reason_fmt(&reason, NULL, 0, "The required program %s could "
48611be35a1SLionel Sambuc                 "not be found", prog);
48711be35a1SLionel Sambuc             skip(ctx, &reason);
48811be35a1SLionel Sambuc         }
48911be35a1SLionel Sambuc     } else {
49011be35a1SLionel Sambuc         const char *path = atf_env_get("PATH");
49111be35a1SLionel Sambuc         struct prog_found_pair pf;
49211be35a1SLionel Sambuc         atf_fs_path_t bp;
49311be35a1SLionel Sambuc 
49411be35a1SLionel Sambuc         err = atf_fs_path_branch_path(&p, &bp);
49511be35a1SLionel Sambuc         if (atf_is_error(err))
49611be35a1SLionel Sambuc             goto out_p;
49711be35a1SLionel Sambuc 
49811be35a1SLionel Sambuc         if (strcmp(atf_fs_path_cstring(&bp), ".") != 0) {
49911be35a1SLionel Sambuc             atf_fs_path_fini(&bp);
50011be35a1SLionel Sambuc             atf_fs_path_fini(&p);
50111be35a1SLionel Sambuc 
50211be35a1SLionel Sambuc             report_fatal_error("Relative paths are not allowed when searching "
50311be35a1SLionel Sambuc                 "for a program (%s)", prog);
50411be35a1SLionel Sambuc             UNREACHABLE;
50511be35a1SLionel Sambuc         }
50611be35a1SLionel Sambuc 
50711be35a1SLionel Sambuc         pf.prog = prog;
50811be35a1SLionel Sambuc         pf.found = false;
50911be35a1SLionel Sambuc         err = atf_text_for_each_word(path, ":", check_prog_in_dir, &pf);
51011be35a1SLionel Sambuc         if (atf_is_error(err))
51111be35a1SLionel Sambuc             goto out_bp;
51211be35a1SLionel Sambuc 
51311be35a1SLionel Sambuc         if (!pf.found) {
51411be35a1SLionel Sambuc             atf_dynstr_t reason;
51511be35a1SLionel Sambuc 
51611be35a1SLionel Sambuc             atf_fs_path_fini(&bp);
51711be35a1SLionel Sambuc             atf_fs_path_fini(&p);
51811be35a1SLionel Sambuc             format_reason_fmt(&reason, NULL, 0, "The required program %s could "
51911be35a1SLionel Sambuc                 "not be found in the PATH", prog);
52011be35a1SLionel Sambuc             fail_requirement(ctx, &reason);
52111be35a1SLionel Sambuc         }
52211be35a1SLionel Sambuc 
52311be35a1SLionel Sambuc out_bp:
52411be35a1SLionel Sambuc         atf_fs_path_fini(&bp);
52511be35a1SLionel Sambuc     }
52611be35a1SLionel Sambuc 
52711be35a1SLionel Sambuc out_p:
52811be35a1SLionel Sambuc     atf_fs_path_fini(&p);
52911be35a1SLionel Sambuc out:
53011be35a1SLionel Sambuc     return err;
53111be35a1SLionel Sambuc }
53211be35a1SLionel Sambuc 
53311be35a1SLionel Sambuc /* ---------------------------------------------------------------------
53411be35a1SLionel Sambuc  * The "atf_tc" type.
53511be35a1SLionel Sambuc  * --------------------------------------------------------------------- */
53611be35a1SLionel Sambuc 
53711be35a1SLionel Sambuc struct atf_tc_impl {
53811be35a1SLionel Sambuc     const char *m_ident;
53911be35a1SLionel Sambuc 
54011be35a1SLionel Sambuc     atf_map_t m_vars;
54111be35a1SLionel Sambuc     atf_map_t m_config;
54211be35a1SLionel Sambuc 
54311be35a1SLionel Sambuc     atf_tc_head_t m_head;
54411be35a1SLionel Sambuc     atf_tc_body_t m_body;
54511be35a1SLionel Sambuc     atf_tc_cleanup_t m_cleanup;
54611be35a1SLionel Sambuc };
54711be35a1SLionel Sambuc 
54811be35a1SLionel Sambuc /*
54911be35a1SLionel Sambuc  * Constructors/destructors.
55011be35a1SLionel Sambuc  */
55111be35a1SLionel Sambuc 
55211be35a1SLionel Sambuc atf_error_t
atf_tc_init(atf_tc_t * tc,const char * ident,atf_tc_head_t head,atf_tc_body_t body,atf_tc_cleanup_t cleanup,const char * const * config)55311be35a1SLionel Sambuc atf_tc_init(atf_tc_t *tc, const char *ident, atf_tc_head_t head,
55411be35a1SLionel Sambuc             atf_tc_body_t body, atf_tc_cleanup_t cleanup,
55511be35a1SLionel Sambuc             const char *const *config)
55611be35a1SLionel Sambuc {
55711be35a1SLionel Sambuc     atf_error_t err;
55811be35a1SLionel Sambuc 
55911be35a1SLionel Sambuc     tc->pimpl = malloc(sizeof(struct atf_tc_impl));
56011be35a1SLionel Sambuc     if (tc->pimpl == NULL) {
56111be35a1SLionel Sambuc         err = atf_no_memory_error();
56211be35a1SLionel Sambuc         goto err;
56311be35a1SLionel Sambuc     }
56411be35a1SLionel Sambuc 
56511be35a1SLionel Sambuc     tc->pimpl->m_ident = ident;
56611be35a1SLionel Sambuc     tc->pimpl->m_head = head;
56711be35a1SLionel Sambuc     tc->pimpl->m_body = body;
56811be35a1SLionel Sambuc     tc->pimpl->m_cleanup = cleanup;
56911be35a1SLionel Sambuc 
57011be35a1SLionel Sambuc     err = atf_map_init_charpp(&tc->pimpl->m_config, config);
57111be35a1SLionel Sambuc     if (atf_is_error(err))
57211be35a1SLionel Sambuc         goto err;
57311be35a1SLionel Sambuc 
57411be35a1SLionel Sambuc     err = atf_map_init(&tc->pimpl->m_vars);
57511be35a1SLionel Sambuc     if (atf_is_error(err))
57611be35a1SLionel Sambuc         goto err_vars;
57711be35a1SLionel Sambuc 
578*0a6a1f1dSLionel Sambuc     err = atf_tc_set_md_var(tc, "ident", "%s", ident);
57911be35a1SLionel Sambuc     if (atf_is_error(err))
58011be35a1SLionel Sambuc         goto err_map;
58111be35a1SLionel Sambuc 
58211be35a1SLionel Sambuc     if (cleanup != NULL) {
58311be35a1SLionel Sambuc         err = atf_tc_set_md_var(tc, "has.cleanup", "true");
58411be35a1SLionel Sambuc         if (atf_is_error(err))
58511be35a1SLionel Sambuc             goto err_map;
58611be35a1SLionel Sambuc     }
58711be35a1SLionel Sambuc 
58811be35a1SLionel Sambuc     /* XXX Should the head be able to return error codes? */
58911be35a1SLionel Sambuc     if (tc->pimpl->m_head != NULL)
59011be35a1SLionel Sambuc         tc->pimpl->m_head(tc);
59111be35a1SLionel Sambuc 
59211be35a1SLionel Sambuc     if (strcmp(atf_tc_get_md_var(tc, "ident"), ident) != 0) {
59311be35a1SLionel Sambuc         report_fatal_error("Test case head modified the read-only 'ident' "
59411be35a1SLionel Sambuc             "property");
59511be35a1SLionel Sambuc         UNREACHABLE;
59611be35a1SLionel Sambuc     }
59711be35a1SLionel Sambuc 
59811be35a1SLionel Sambuc     INV(!atf_is_error(err));
59911be35a1SLionel Sambuc     return err;
60011be35a1SLionel Sambuc 
60111be35a1SLionel Sambuc err_map:
60211be35a1SLionel Sambuc     atf_map_fini(&tc->pimpl->m_vars);
60311be35a1SLionel Sambuc err_vars:
60411be35a1SLionel Sambuc     atf_map_fini(&tc->pimpl->m_config);
60511be35a1SLionel Sambuc err:
60611be35a1SLionel Sambuc     return err;
60711be35a1SLionel Sambuc }
60811be35a1SLionel Sambuc 
60911be35a1SLionel Sambuc atf_error_t
atf_tc_init_pack(atf_tc_t * tc,const atf_tc_pack_t * pack,const char * const * config)61011be35a1SLionel Sambuc atf_tc_init_pack(atf_tc_t *tc, const atf_tc_pack_t *pack,
61111be35a1SLionel Sambuc                  const char *const *config)
61211be35a1SLionel Sambuc {
61311be35a1SLionel Sambuc     return atf_tc_init(tc, pack->m_ident, pack->m_head, pack->m_body,
61411be35a1SLionel Sambuc                        pack->m_cleanup, config);
61511be35a1SLionel Sambuc }
61611be35a1SLionel Sambuc 
61711be35a1SLionel Sambuc void
atf_tc_fini(atf_tc_t * tc)61811be35a1SLionel Sambuc atf_tc_fini(atf_tc_t *tc)
61911be35a1SLionel Sambuc {
62011be35a1SLionel Sambuc     atf_map_fini(&tc->pimpl->m_vars);
62111be35a1SLionel Sambuc     free(tc->pimpl);
62211be35a1SLionel Sambuc }
62311be35a1SLionel Sambuc 
62411be35a1SLionel Sambuc /*
62511be35a1SLionel Sambuc  * Getters.
62611be35a1SLionel Sambuc  */
62711be35a1SLionel Sambuc 
62811be35a1SLionel Sambuc const char *
atf_tc_get_ident(const atf_tc_t * tc)62911be35a1SLionel Sambuc atf_tc_get_ident(const atf_tc_t *tc)
63011be35a1SLionel Sambuc {
63111be35a1SLionel Sambuc     return tc->pimpl->m_ident;
63211be35a1SLionel Sambuc }
63311be35a1SLionel Sambuc 
63411be35a1SLionel Sambuc const char *
atf_tc_get_config_var(const atf_tc_t * tc,const char * name)63511be35a1SLionel Sambuc atf_tc_get_config_var(const atf_tc_t *tc, const char *name)
63611be35a1SLionel Sambuc {
63711be35a1SLionel Sambuc     const char *val;
63811be35a1SLionel Sambuc     atf_map_citer_t iter;
63911be35a1SLionel Sambuc 
64011be35a1SLionel Sambuc     PRE(atf_tc_has_config_var(tc, name));
64111be35a1SLionel Sambuc     iter = atf_map_find_c(&tc->pimpl->m_config, name);
64211be35a1SLionel Sambuc     val = atf_map_citer_data(iter);
64311be35a1SLionel Sambuc     INV(val != NULL);
64411be35a1SLionel Sambuc 
64511be35a1SLionel Sambuc     return val;
64611be35a1SLionel Sambuc }
64711be35a1SLionel Sambuc 
64811be35a1SLionel Sambuc const char *
atf_tc_get_config_var_wd(const atf_tc_t * tc,const char * name,const char * defval)64911be35a1SLionel Sambuc atf_tc_get_config_var_wd(const atf_tc_t *tc, const char *name,
65011be35a1SLionel Sambuc                          const char *defval)
65111be35a1SLionel Sambuc {
65211be35a1SLionel Sambuc     const char *val;
65311be35a1SLionel Sambuc 
65411be35a1SLionel Sambuc     if (!atf_tc_has_config_var(tc, name))
65511be35a1SLionel Sambuc         val = defval;
65611be35a1SLionel Sambuc     else
65711be35a1SLionel Sambuc         val = atf_tc_get_config_var(tc, name);
65811be35a1SLionel Sambuc 
65911be35a1SLionel Sambuc     return val;
66011be35a1SLionel Sambuc }
66111be35a1SLionel Sambuc 
66211be35a1SLionel Sambuc bool
atf_tc_get_config_var_as_bool(const atf_tc_t * tc,const char * name)66311be35a1SLionel Sambuc atf_tc_get_config_var_as_bool(const atf_tc_t *tc, const char *name)
66411be35a1SLionel Sambuc {
66511be35a1SLionel Sambuc     bool val;
66611be35a1SLionel Sambuc     const char *strval;
66711be35a1SLionel Sambuc     atf_error_t err;
66811be35a1SLionel Sambuc 
66911be35a1SLionel Sambuc     strval = atf_tc_get_config_var(tc, name);
67011be35a1SLionel Sambuc     err = atf_text_to_bool(strval, &val);
67111be35a1SLionel Sambuc     if (atf_is_error(err)) {
67211be35a1SLionel Sambuc         atf_error_free(err);
67311be35a1SLionel Sambuc         atf_tc_fail("Configuration variable %s does not have a valid "
67411be35a1SLionel Sambuc                     "boolean value; found %s", name, strval);
67511be35a1SLionel Sambuc     }
67611be35a1SLionel Sambuc 
67711be35a1SLionel Sambuc     return val;
67811be35a1SLionel Sambuc }
67911be35a1SLionel Sambuc 
68011be35a1SLionel Sambuc bool
atf_tc_get_config_var_as_bool_wd(const atf_tc_t * tc,const char * name,const bool defval)68111be35a1SLionel Sambuc atf_tc_get_config_var_as_bool_wd(const atf_tc_t *tc, const char *name,
68211be35a1SLionel Sambuc                                  const bool defval)
68311be35a1SLionel Sambuc {
68411be35a1SLionel Sambuc     bool val;
68511be35a1SLionel Sambuc 
68611be35a1SLionel Sambuc     if (!atf_tc_has_config_var(tc, name))
68711be35a1SLionel Sambuc         val = defval;
68811be35a1SLionel Sambuc     else
68911be35a1SLionel Sambuc         val = atf_tc_get_config_var_as_bool(tc, name);
69011be35a1SLionel Sambuc 
69111be35a1SLionel Sambuc     return val;
69211be35a1SLionel Sambuc }
69311be35a1SLionel Sambuc 
69411be35a1SLionel Sambuc long
atf_tc_get_config_var_as_long(const atf_tc_t * tc,const char * name)69511be35a1SLionel Sambuc atf_tc_get_config_var_as_long(const atf_tc_t *tc, const char *name)
69611be35a1SLionel Sambuc {
69711be35a1SLionel Sambuc     long val;
69811be35a1SLionel Sambuc     const char *strval;
69911be35a1SLionel Sambuc     atf_error_t err;
70011be35a1SLionel Sambuc 
70111be35a1SLionel Sambuc     strval = atf_tc_get_config_var(tc, name);
70211be35a1SLionel Sambuc     err = atf_text_to_long(strval, &val);
70311be35a1SLionel Sambuc     if (atf_is_error(err)) {
70411be35a1SLionel Sambuc         atf_error_free(err);
70511be35a1SLionel Sambuc         atf_tc_fail("Configuration variable %s does not have a valid "
70611be35a1SLionel Sambuc                     "long value; found %s", name, strval);
70711be35a1SLionel Sambuc     }
70811be35a1SLionel Sambuc 
70911be35a1SLionel Sambuc     return val;
71011be35a1SLionel Sambuc }
71111be35a1SLionel Sambuc 
71211be35a1SLionel Sambuc long
atf_tc_get_config_var_as_long_wd(const atf_tc_t * tc,const char * name,const long defval)71311be35a1SLionel Sambuc atf_tc_get_config_var_as_long_wd(const atf_tc_t *tc, const char *name,
71411be35a1SLionel Sambuc                                  const long defval)
71511be35a1SLionel Sambuc {
71611be35a1SLionel Sambuc     long val;
71711be35a1SLionel Sambuc 
71811be35a1SLionel Sambuc     if (!atf_tc_has_config_var(tc, name))
71911be35a1SLionel Sambuc         val = defval;
72011be35a1SLionel Sambuc     else
72111be35a1SLionel Sambuc         val = atf_tc_get_config_var_as_long(tc, name);
72211be35a1SLionel Sambuc 
72311be35a1SLionel Sambuc     return val;
72411be35a1SLionel Sambuc }
72511be35a1SLionel Sambuc 
72611be35a1SLionel Sambuc const char *
atf_tc_get_md_var(const atf_tc_t * tc,const char * name)72711be35a1SLionel Sambuc atf_tc_get_md_var(const atf_tc_t *tc, const char *name)
72811be35a1SLionel Sambuc {
72911be35a1SLionel Sambuc     const char *val;
73011be35a1SLionel Sambuc     atf_map_citer_t iter;
73111be35a1SLionel Sambuc 
73211be35a1SLionel Sambuc     PRE(atf_tc_has_md_var(tc, name));
73311be35a1SLionel Sambuc     iter = atf_map_find_c(&tc->pimpl->m_vars, name);
73411be35a1SLionel Sambuc     val = atf_map_citer_data(iter);
73511be35a1SLionel Sambuc     INV(val != NULL);
73611be35a1SLionel Sambuc 
73711be35a1SLionel Sambuc     return val;
73811be35a1SLionel Sambuc }
73911be35a1SLionel Sambuc 
74011be35a1SLionel Sambuc char **
atf_tc_get_md_vars(const atf_tc_t * tc)74111be35a1SLionel Sambuc atf_tc_get_md_vars(const atf_tc_t *tc)
74211be35a1SLionel Sambuc {
74311be35a1SLionel Sambuc     return atf_map_to_charpp(&tc->pimpl->m_vars);
74411be35a1SLionel Sambuc }
74511be35a1SLionel Sambuc 
74611be35a1SLionel Sambuc bool
atf_tc_has_config_var(const atf_tc_t * tc,const char * name)74711be35a1SLionel Sambuc atf_tc_has_config_var(const atf_tc_t *tc, const char *name)
74811be35a1SLionel Sambuc {
74911be35a1SLionel Sambuc     atf_map_citer_t end, iter;
75011be35a1SLionel Sambuc 
75111be35a1SLionel Sambuc     iter = atf_map_find_c(&tc->pimpl->m_config, name);
75211be35a1SLionel Sambuc     end = atf_map_end_c(&tc->pimpl->m_config);
75311be35a1SLionel Sambuc     return !atf_equal_map_citer_map_citer(iter, end);
75411be35a1SLionel Sambuc }
75511be35a1SLionel Sambuc 
75611be35a1SLionel Sambuc bool
atf_tc_has_md_var(const atf_tc_t * tc,const char * name)75711be35a1SLionel Sambuc atf_tc_has_md_var(const atf_tc_t *tc, const char *name)
75811be35a1SLionel Sambuc {
75911be35a1SLionel Sambuc     atf_map_citer_t end, iter;
76011be35a1SLionel Sambuc 
76111be35a1SLionel Sambuc     iter = atf_map_find_c(&tc->pimpl->m_vars, name);
76211be35a1SLionel Sambuc     end = atf_map_end_c(&tc->pimpl->m_vars);
76311be35a1SLionel Sambuc     return !atf_equal_map_citer_map_citer(iter, end);
76411be35a1SLionel Sambuc }
76511be35a1SLionel Sambuc 
76611be35a1SLionel Sambuc /*
76711be35a1SLionel Sambuc  * Modifiers.
76811be35a1SLionel Sambuc  */
76911be35a1SLionel Sambuc 
77011be35a1SLionel Sambuc atf_error_t
atf_tc_set_md_var(atf_tc_t * tc,const char * name,const char * fmt,...)77111be35a1SLionel Sambuc atf_tc_set_md_var(atf_tc_t *tc, const char *name, const char *fmt, ...)
77211be35a1SLionel Sambuc {
77311be35a1SLionel Sambuc     atf_error_t err;
77411be35a1SLionel Sambuc     char *value;
77511be35a1SLionel Sambuc     va_list ap;
77611be35a1SLionel Sambuc 
77711be35a1SLionel Sambuc     va_start(ap, fmt);
77811be35a1SLionel Sambuc     err = atf_text_format_ap(&value, fmt, ap);
77911be35a1SLionel Sambuc     va_end(ap);
78011be35a1SLionel Sambuc 
78111be35a1SLionel Sambuc     if (!atf_is_error(err))
78211be35a1SLionel Sambuc         err = atf_map_insert(&tc->pimpl->m_vars, name, value, true);
78311be35a1SLionel Sambuc     else
78411be35a1SLionel Sambuc         free(value);
78511be35a1SLionel Sambuc 
78611be35a1SLionel Sambuc     return err;
78711be35a1SLionel Sambuc }
78811be35a1SLionel Sambuc 
78911be35a1SLionel Sambuc /* ---------------------------------------------------------------------
79011be35a1SLionel Sambuc  * Free functions, as they should be publicly but they can't.
79111be35a1SLionel Sambuc  * --------------------------------------------------------------------- */
79211be35a1SLionel Sambuc 
79311be35a1SLionel Sambuc static void _atf_tc_fail(struct context *, const char *, va_list)
794*0a6a1f1dSLionel Sambuc     ATF_DEFS_ATTRIBUTE_FORMAT_PRINTF(2, 0)
79511be35a1SLionel Sambuc     ATF_DEFS_ATTRIBUTE_NORETURN;
796*0a6a1f1dSLionel Sambuc static void _atf_tc_fail_nonfatal(struct context *, const char *, va_list)
797*0a6a1f1dSLionel Sambuc     ATF_DEFS_ATTRIBUTE_FORMAT_PRINTF(2, 0);
79811be35a1SLionel Sambuc static void _atf_tc_fail_check(struct context *, const char *, const size_t,
799*0a6a1f1dSLionel Sambuc     const char *, va_list)
800*0a6a1f1dSLionel Sambuc     ATF_DEFS_ATTRIBUTE_FORMAT_PRINTF(4, 0);
80111be35a1SLionel Sambuc static void _atf_tc_fail_requirement(struct context *, const char *,
802*0a6a1f1dSLionel Sambuc     const size_t, const char *, va_list)
803*0a6a1f1dSLionel Sambuc     ATF_DEFS_ATTRIBUTE_NORETURN
804*0a6a1f1dSLionel Sambuc     ATF_DEFS_ATTRIBUTE_FORMAT_PRINTF(4, 0);
80511be35a1SLionel Sambuc static void _atf_tc_pass(struct context *) ATF_DEFS_ATTRIBUTE_NORETURN;
80611be35a1SLionel Sambuc static void _atf_tc_require_prog(struct context *, const char *);
80711be35a1SLionel Sambuc static void _atf_tc_skip(struct context *, const char *, va_list)
808*0a6a1f1dSLionel Sambuc     ATF_DEFS_ATTRIBUTE_FORMAT_PRINTF(2, 0)
80911be35a1SLionel Sambuc     ATF_DEFS_ATTRIBUTE_NORETURN;
81011be35a1SLionel Sambuc static void _atf_tc_check_errno(struct context *, const char *, const size_t,
81111be35a1SLionel Sambuc     const int, const char *, const bool);
81211be35a1SLionel Sambuc static void _atf_tc_require_errno(struct context *, const char *, const size_t,
81311be35a1SLionel Sambuc     const int, const char *, const bool);
81411be35a1SLionel Sambuc static void _atf_tc_expect_pass(struct context *);
815*0a6a1f1dSLionel Sambuc static void _atf_tc_expect_fail(struct context *, const char *, va_list)
816*0a6a1f1dSLionel Sambuc     ATF_DEFS_ATTRIBUTE_FORMAT_PRINTF(2, 0);
81711be35a1SLionel Sambuc static void _atf_tc_expect_exit(struct context *, const int, const char *,
818*0a6a1f1dSLionel Sambuc     va_list) ATF_DEFS_ATTRIBUTE_FORMAT_PRINTF(3, 0);
81911be35a1SLionel Sambuc static void _atf_tc_expect_signal(struct context *, const int, const char *,
820*0a6a1f1dSLionel Sambuc     va_list) ATF_DEFS_ATTRIBUTE_FORMAT_PRINTF(3, 0);
82111be35a1SLionel Sambuc static void _atf_tc_expect_death(struct context *, const char *,
822*0a6a1f1dSLionel Sambuc     va_list) ATF_DEFS_ATTRIBUTE_FORMAT_PRINTF(2, 0);
82311be35a1SLionel Sambuc 
82411be35a1SLionel Sambuc static void
_atf_tc_fail(struct context * ctx,const char * fmt,va_list ap)82511be35a1SLionel Sambuc _atf_tc_fail(struct context *ctx, const char *fmt, va_list ap)
82611be35a1SLionel Sambuc {
82711be35a1SLionel Sambuc     va_list ap2;
82811be35a1SLionel Sambuc     atf_dynstr_t reason;
82911be35a1SLionel Sambuc 
83011be35a1SLionel Sambuc     va_copy(ap2, ap);
83111be35a1SLionel Sambuc     format_reason_ap(&reason, NULL, 0, fmt, ap2);
83211be35a1SLionel Sambuc     va_end(ap2);
83311be35a1SLionel Sambuc 
83411be35a1SLionel Sambuc     fail_requirement(ctx, &reason);
83511be35a1SLionel Sambuc     UNREACHABLE;
83611be35a1SLionel Sambuc }
83711be35a1SLionel Sambuc 
83811be35a1SLionel Sambuc static void
_atf_tc_fail_nonfatal(struct context * ctx,const char * fmt,va_list ap)83911be35a1SLionel Sambuc _atf_tc_fail_nonfatal(struct context *ctx, const char *fmt, va_list ap)
84011be35a1SLionel Sambuc {
84111be35a1SLionel Sambuc     va_list ap2;
84211be35a1SLionel Sambuc     atf_dynstr_t reason;
84311be35a1SLionel Sambuc 
84411be35a1SLionel Sambuc     va_copy(ap2, ap);
84511be35a1SLionel Sambuc     format_reason_ap(&reason, NULL, 0, fmt, ap2);
84611be35a1SLionel Sambuc     va_end(ap2);
84711be35a1SLionel Sambuc 
84811be35a1SLionel Sambuc     fail_check(ctx, &reason);
84911be35a1SLionel Sambuc }
85011be35a1SLionel Sambuc 
85111be35a1SLionel Sambuc static void
_atf_tc_fail_check(struct context * ctx,const char * file,const size_t line,const char * fmt,va_list ap)85211be35a1SLionel Sambuc _atf_tc_fail_check(struct context *ctx, const char *file, const size_t line,
85311be35a1SLionel Sambuc                    const char *fmt, va_list ap)
85411be35a1SLionel Sambuc {
85511be35a1SLionel Sambuc     va_list ap2;
85611be35a1SLionel Sambuc     atf_dynstr_t reason;
85711be35a1SLionel Sambuc 
85811be35a1SLionel Sambuc     va_copy(ap2, ap);
85911be35a1SLionel Sambuc     format_reason_ap(&reason, file, line, fmt, ap2);
86011be35a1SLionel Sambuc     va_end(ap2);
86111be35a1SLionel Sambuc 
86211be35a1SLionel Sambuc     fail_check(ctx, &reason);
86311be35a1SLionel Sambuc }
86411be35a1SLionel Sambuc 
86511be35a1SLionel Sambuc static void
_atf_tc_fail_requirement(struct context * ctx,const char * file,const size_t line,const char * fmt,va_list ap)86611be35a1SLionel Sambuc _atf_tc_fail_requirement(struct context *ctx, const char *file,
86711be35a1SLionel Sambuc                          const size_t line, const char *fmt, va_list ap)
86811be35a1SLionel Sambuc {
86911be35a1SLionel Sambuc     va_list ap2;
87011be35a1SLionel Sambuc     atf_dynstr_t reason;
87111be35a1SLionel Sambuc 
87211be35a1SLionel Sambuc     va_copy(ap2, ap);
87311be35a1SLionel Sambuc     format_reason_ap(&reason, file, line, fmt, ap2);
87411be35a1SLionel Sambuc     va_end(ap2);
87511be35a1SLionel Sambuc 
87611be35a1SLionel Sambuc     fail_requirement(ctx, &reason);
87711be35a1SLionel Sambuc     UNREACHABLE;
87811be35a1SLionel Sambuc }
87911be35a1SLionel Sambuc 
88011be35a1SLionel Sambuc static void
_atf_tc_pass(struct context * ctx)88111be35a1SLionel Sambuc _atf_tc_pass(struct context *ctx)
88211be35a1SLionel Sambuc {
88311be35a1SLionel Sambuc     pass(ctx);
88411be35a1SLionel Sambuc     UNREACHABLE;
88511be35a1SLionel Sambuc }
88611be35a1SLionel Sambuc 
88711be35a1SLionel Sambuc static void
_atf_tc_require_prog(struct context * ctx,const char * prog)88811be35a1SLionel Sambuc _atf_tc_require_prog(struct context *ctx, const char *prog)
88911be35a1SLionel Sambuc {
89011be35a1SLionel Sambuc     check_fatal_error(check_prog(ctx, prog));
89111be35a1SLionel Sambuc }
89211be35a1SLionel Sambuc 
89311be35a1SLionel Sambuc static void
_atf_tc_skip(struct context * ctx,const char * fmt,va_list ap)89411be35a1SLionel Sambuc _atf_tc_skip(struct context *ctx, const char *fmt, va_list ap)
89511be35a1SLionel Sambuc {
89611be35a1SLionel Sambuc     atf_dynstr_t reason;
89711be35a1SLionel Sambuc     va_list ap2;
89811be35a1SLionel Sambuc 
89911be35a1SLionel Sambuc     va_copy(ap2, ap);
90011be35a1SLionel Sambuc     format_reason_ap(&reason, NULL, 0, fmt, ap2);
90111be35a1SLionel Sambuc     va_end(ap2);
90211be35a1SLionel Sambuc 
90311be35a1SLionel Sambuc     skip(ctx, &reason);
90411be35a1SLionel Sambuc }
90511be35a1SLionel Sambuc 
90611be35a1SLionel Sambuc static void
_atf_tc_check_errno(struct context * ctx,const char * file,const size_t line,const int exp_errno,const char * expr_str,const bool expr_result)90711be35a1SLionel Sambuc _atf_tc_check_errno(struct context *ctx, const char *file, const size_t line,
90811be35a1SLionel Sambuc                     const int exp_errno, const char *expr_str,
90911be35a1SLionel Sambuc                     const bool expr_result)
91011be35a1SLionel Sambuc {
91111be35a1SLionel Sambuc     errno_test(ctx, file, line, exp_errno, expr_str, expr_result, fail_check);
91211be35a1SLionel Sambuc }
91311be35a1SLionel Sambuc 
91411be35a1SLionel Sambuc static void
_atf_tc_require_errno(struct context * ctx,const char * file,const size_t line,const int exp_errno,const char * expr_str,const bool expr_result)91511be35a1SLionel Sambuc _atf_tc_require_errno(struct context *ctx, const char *file, const size_t line,
91611be35a1SLionel Sambuc                       const int exp_errno, const char *expr_str,
91711be35a1SLionel Sambuc                       const bool expr_result)
91811be35a1SLionel Sambuc {
91911be35a1SLionel Sambuc     errno_test(ctx, file, line, exp_errno, expr_str, expr_result,
92011be35a1SLionel Sambuc         fail_requirement);
92111be35a1SLionel Sambuc }
92211be35a1SLionel Sambuc 
92311be35a1SLionel Sambuc static void
_atf_tc_expect_pass(struct context * ctx)92411be35a1SLionel Sambuc _atf_tc_expect_pass(struct context *ctx)
92511be35a1SLionel Sambuc {
92611be35a1SLionel Sambuc     validate_expect(ctx);
92711be35a1SLionel Sambuc 
92811be35a1SLionel Sambuc     ctx->expect = EXPECT_PASS;
92911be35a1SLionel Sambuc }
93011be35a1SLionel Sambuc 
93111be35a1SLionel Sambuc static void
_atf_tc_expect_fail(struct context * ctx,const char * reason,va_list ap)93211be35a1SLionel Sambuc _atf_tc_expect_fail(struct context *ctx, const char *reason, va_list ap)
93311be35a1SLionel Sambuc {
93411be35a1SLionel Sambuc     va_list ap2;
93511be35a1SLionel Sambuc 
93611be35a1SLionel Sambuc     validate_expect(ctx);
93711be35a1SLionel Sambuc 
93811be35a1SLionel Sambuc     ctx->expect = EXPECT_FAIL;
93911be35a1SLionel Sambuc     atf_dynstr_fini(&ctx->expect_reason);
94011be35a1SLionel Sambuc     va_copy(ap2, ap);
94111be35a1SLionel Sambuc     check_fatal_error(atf_dynstr_init_ap(&ctx->expect_reason, reason, ap2));
94211be35a1SLionel Sambuc     va_end(ap2);
94311be35a1SLionel Sambuc     ctx->expect_previous_fail_count = ctx->expect_fail_count;
94411be35a1SLionel Sambuc }
94511be35a1SLionel Sambuc 
94611be35a1SLionel Sambuc static void
_atf_tc_expect_exit(struct context * ctx,const int exitcode,const char * reason,va_list ap)94711be35a1SLionel Sambuc _atf_tc_expect_exit(struct context *ctx, const int exitcode, const char *reason,
94811be35a1SLionel Sambuc                     va_list ap)
94911be35a1SLionel Sambuc {
95011be35a1SLionel Sambuc     va_list ap2;
95111be35a1SLionel Sambuc     atf_dynstr_t formatted;
95211be35a1SLionel Sambuc 
95311be35a1SLionel Sambuc     validate_expect(ctx);
95411be35a1SLionel Sambuc 
95511be35a1SLionel Sambuc     ctx->expect = EXPECT_EXIT;
95611be35a1SLionel Sambuc     va_copy(ap2, ap);
95711be35a1SLionel Sambuc     check_fatal_error(atf_dynstr_init_ap(&formatted, reason, ap2));
95811be35a1SLionel Sambuc     va_end(ap2);
95911be35a1SLionel Sambuc 
96011be35a1SLionel Sambuc     create_resfile(ctx->resfile, "expected_exit", exitcode, &formatted);
96111be35a1SLionel Sambuc }
96211be35a1SLionel Sambuc 
96311be35a1SLionel Sambuc static void
_atf_tc_expect_signal(struct context * ctx,const int signo,const char * reason,va_list ap)96411be35a1SLionel Sambuc _atf_tc_expect_signal(struct context *ctx, const int signo, const char *reason,
96511be35a1SLionel Sambuc                       va_list ap)
96611be35a1SLionel Sambuc {
96711be35a1SLionel Sambuc     va_list ap2;
96811be35a1SLionel Sambuc     atf_dynstr_t formatted;
96911be35a1SLionel Sambuc 
97011be35a1SLionel Sambuc     validate_expect(ctx);
97111be35a1SLionel Sambuc 
97211be35a1SLionel Sambuc     ctx->expect = EXPECT_SIGNAL;
97311be35a1SLionel Sambuc     va_copy(ap2, ap);
97411be35a1SLionel Sambuc     check_fatal_error(atf_dynstr_init_ap(&formatted, reason, ap2));
97511be35a1SLionel Sambuc     va_end(ap2);
97611be35a1SLionel Sambuc 
97711be35a1SLionel Sambuc     create_resfile(ctx->resfile, "expected_signal", signo, &formatted);
97811be35a1SLionel Sambuc }
97911be35a1SLionel Sambuc 
98011be35a1SLionel Sambuc static void
_atf_tc_expect_death(struct context * ctx,const char * reason,va_list ap)98111be35a1SLionel Sambuc _atf_tc_expect_death(struct context *ctx, const char *reason, va_list ap)
98211be35a1SLionel Sambuc {
98311be35a1SLionel Sambuc     va_list ap2;
98411be35a1SLionel Sambuc     atf_dynstr_t formatted;
98511be35a1SLionel Sambuc 
98611be35a1SLionel Sambuc     validate_expect(ctx);
98711be35a1SLionel Sambuc 
98811be35a1SLionel Sambuc     ctx->expect = EXPECT_DEATH;
98911be35a1SLionel Sambuc     va_copy(ap2, ap);
99011be35a1SLionel Sambuc     check_fatal_error(atf_dynstr_init_ap(&formatted, reason, ap2));
99111be35a1SLionel Sambuc     va_end(ap2);
99211be35a1SLionel Sambuc 
99311be35a1SLionel Sambuc     create_resfile(ctx->resfile, "expected_death", -1, &formatted);
99411be35a1SLionel Sambuc }
99511be35a1SLionel Sambuc 
996*0a6a1f1dSLionel Sambuc ATF_DEFS_ATTRIBUTE_FORMAT_PRINTF(2, 0)
99711be35a1SLionel Sambuc static void
_atf_tc_expect_timeout(struct context * ctx,const char * reason,va_list ap)99811be35a1SLionel Sambuc _atf_tc_expect_timeout(struct context *ctx, const char *reason, va_list ap)
99911be35a1SLionel Sambuc {
100011be35a1SLionel Sambuc     va_list ap2;
100111be35a1SLionel Sambuc     atf_dynstr_t formatted;
100211be35a1SLionel Sambuc 
100311be35a1SLionel Sambuc     validate_expect(ctx);
100411be35a1SLionel Sambuc 
100511be35a1SLionel Sambuc     ctx->expect = EXPECT_TIMEOUT;
100611be35a1SLionel Sambuc     va_copy(ap2, ap);
100711be35a1SLionel Sambuc     check_fatal_error(atf_dynstr_init_ap(&formatted, reason, ap2));
100811be35a1SLionel Sambuc     va_end(ap2);
100911be35a1SLionel Sambuc 
101011be35a1SLionel Sambuc     create_resfile(ctx->resfile, "expected_timeout", -1, &formatted);
101111be35a1SLionel Sambuc }
101211be35a1SLionel Sambuc 
101311be35a1SLionel Sambuc /* ---------------------------------------------------------------------
101411be35a1SLionel Sambuc  * Free functions.
101511be35a1SLionel Sambuc  * --------------------------------------------------------------------- */
101611be35a1SLionel Sambuc 
101711be35a1SLionel Sambuc static struct context Current;
101811be35a1SLionel Sambuc 
101911be35a1SLionel Sambuc atf_error_t
atf_tc_run(const atf_tc_t * tc,const char * resfile)102011be35a1SLionel Sambuc atf_tc_run(const atf_tc_t *tc, const char *resfile)
102111be35a1SLionel Sambuc {
102211be35a1SLionel Sambuc     context_init(&Current, tc, resfile);
102311be35a1SLionel Sambuc 
102411be35a1SLionel Sambuc     tc->pimpl->m_body(tc);
102511be35a1SLionel Sambuc 
102611be35a1SLionel Sambuc     validate_expect(&Current);
102711be35a1SLionel Sambuc 
102811be35a1SLionel Sambuc     if (Current.fail_count > 0) {
102911be35a1SLionel Sambuc         atf_dynstr_t reason;
103011be35a1SLionel Sambuc 
1031*0a6a1f1dSLionel Sambuc         format_reason_fmt(&reason, NULL, 0, "%zu checks failed; see output for "
103211be35a1SLionel Sambuc             "more details", Current.fail_count);
103311be35a1SLionel Sambuc         fail_requirement(&Current, &reason);
103411be35a1SLionel Sambuc     } else if (Current.expect_fail_count > 0) {
103511be35a1SLionel Sambuc         atf_dynstr_t reason;
103611be35a1SLionel Sambuc 
1037*0a6a1f1dSLionel Sambuc         format_reason_fmt(&reason, NULL, 0, "%zu checks failed as expected; "
103811be35a1SLionel Sambuc             "see output for more details", Current.expect_fail_count);
103911be35a1SLionel Sambuc         expected_failure(&Current, &reason);
104011be35a1SLionel Sambuc     } else {
104111be35a1SLionel Sambuc         pass(&Current);
104211be35a1SLionel Sambuc     }
104311be35a1SLionel Sambuc     UNREACHABLE;
104411be35a1SLionel Sambuc     return atf_no_error();
104511be35a1SLionel Sambuc }
104611be35a1SLionel Sambuc 
104711be35a1SLionel Sambuc atf_error_t
atf_tc_cleanup(const atf_tc_t * tc)104811be35a1SLionel Sambuc atf_tc_cleanup(const atf_tc_t *tc)
104911be35a1SLionel Sambuc {
105011be35a1SLionel Sambuc     if (tc->pimpl->m_cleanup != NULL)
105111be35a1SLionel Sambuc         tc->pimpl->m_cleanup(tc);
105211be35a1SLionel Sambuc     return atf_no_error(); /* XXX */
105311be35a1SLionel Sambuc }
105411be35a1SLionel Sambuc 
105511be35a1SLionel Sambuc /* ---------------------------------------------------------------------
105611be35a1SLionel Sambuc  * Free functions that depend on Current.
105711be35a1SLionel Sambuc  * --------------------------------------------------------------------- */
105811be35a1SLionel Sambuc 
105911be35a1SLionel Sambuc /*
106011be35a1SLionel Sambuc  * All the functions below provide delegates to other internal functions
106111be35a1SLionel Sambuc  * (prefixed by _) that take the current test case as an argument to
106211be35a1SLionel Sambuc  * prevent them from accessing global state.  This is to keep the side-
106311be35a1SLionel Sambuc  * effects of the internal functions clearer and easier to understand.
106411be35a1SLionel Sambuc  *
106511be35a1SLionel Sambuc  * The public API should never have hid the fact that it needs access to
106611be35a1SLionel Sambuc  * the current test case (other than maybe in the macros), but changing it
106711be35a1SLionel Sambuc  * is hard.  TODO: Revisit in the future.
106811be35a1SLionel Sambuc  */
106911be35a1SLionel Sambuc 
107011be35a1SLionel Sambuc void
atf_tc_fail(const char * fmt,...)107111be35a1SLionel Sambuc atf_tc_fail(const char *fmt, ...)
107211be35a1SLionel Sambuc {
107311be35a1SLionel Sambuc     va_list ap;
107411be35a1SLionel Sambuc 
107511be35a1SLionel Sambuc     PRE(Current.tc != NULL);
107611be35a1SLionel Sambuc 
107711be35a1SLionel Sambuc     va_start(ap, fmt);
107811be35a1SLionel Sambuc     _atf_tc_fail(&Current, fmt, ap);
107911be35a1SLionel Sambuc     va_end(ap);
108011be35a1SLionel Sambuc }
108111be35a1SLionel Sambuc 
108211be35a1SLionel Sambuc void
atf_tc_fail_nonfatal(const char * fmt,...)108311be35a1SLionel Sambuc atf_tc_fail_nonfatal(const char *fmt, ...)
108411be35a1SLionel Sambuc {
108511be35a1SLionel Sambuc     va_list ap;
108611be35a1SLionel Sambuc 
108711be35a1SLionel Sambuc     PRE(Current.tc != NULL);
108811be35a1SLionel Sambuc 
108911be35a1SLionel Sambuc     va_start(ap, fmt);
109011be35a1SLionel Sambuc     _atf_tc_fail_nonfatal(&Current, fmt, ap);
109111be35a1SLionel Sambuc     va_end(ap);
109211be35a1SLionel Sambuc }
109311be35a1SLionel Sambuc 
109411be35a1SLionel Sambuc void
atf_tc_fail_check(const char * file,const size_t line,const char * fmt,...)109511be35a1SLionel Sambuc atf_tc_fail_check(const char *file, const size_t line, const char *fmt, ...)
109611be35a1SLionel Sambuc {
109711be35a1SLionel Sambuc     va_list ap;
109811be35a1SLionel Sambuc 
109911be35a1SLionel Sambuc     PRE(Current.tc != NULL);
110011be35a1SLionel Sambuc 
110111be35a1SLionel Sambuc     va_start(ap, fmt);
110211be35a1SLionel Sambuc     _atf_tc_fail_check(&Current, file, line, fmt, ap);
110311be35a1SLionel Sambuc     va_end(ap);
110411be35a1SLionel Sambuc }
110511be35a1SLionel Sambuc 
110611be35a1SLionel Sambuc void
atf_tc_fail_requirement(const char * file,const size_t line,const char * fmt,...)110711be35a1SLionel Sambuc atf_tc_fail_requirement(const char *file, const size_t line,
110811be35a1SLionel Sambuc                         const char *fmt, ...)
110911be35a1SLionel Sambuc {
111011be35a1SLionel Sambuc     va_list ap;
111111be35a1SLionel Sambuc 
111211be35a1SLionel Sambuc     PRE(Current.tc != NULL);
111311be35a1SLionel Sambuc 
111411be35a1SLionel Sambuc     va_start(ap, fmt);
111511be35a1SLionel Sambuc     _atf_tc_fail_requirement(&Current, file, line, fmt, ap);
111611be35a1SLionel Sambuc     va_end(ap);
111711be35a1SLionel Sambuc }
111811be35a1SLionel Sambuc 
111911be35a1SLionel Sambuc void
atf_tc_pass(void)112011be35a1SLionel Sambuc atf_tc_pass(void)
112111be35a1SLionel Sambuc {
112211be35a1SLionel Sambuc     PRE(Current.tc != NULL);
112311be35a1SLionel Sambuc 
112411be35a1SLionel Sambuc     _atf_tc_pass(&Current);
112511be35a1SLionel Sambuc }
112611be35a1SLionel Sambuc 
112711be35a1SLionel Sambuc void
atf_tc_require_prog(const char * prog)112811be35a1SLionel Sambuc atf_tc_require_prog(const char *prog)
112911be35a1SLionel Sambuc {
113011be35a1SLionel Sambuc     PRE(Current.tc != NULL);
113111be35a1SLionel Sambuc 
113211be35a1SLionel Sambuc     _atf_tc_require_prog(&Current, prog);
113311be35a1SLionel Sambuc }
113411be35a1SLionel Sambuc 
113511be35a1SLionel Sambuc void
atf_tc_skip(const char * fmt,...)113611be35a1SLionel Sambuc atf_tc_skip(const char *fmt, ...)
113711be35a1SLionel Sambuc {
113811be35a1SLionel Sambuc     va_list ap;
113911be35a1SLionel Sambuc 
114011be35a1SLionel Sambuc     PRE(Current.tc != NULL);
114111be35a1SLionel Sambuc 
114211be35a1SLionel Sambuc     va_start(ap, fmt);
114311be35a1SLionel Sambuc     _atf_tc_skip(&Current, fmt, ap);
114411be35a1SLionel Sambuc     va_end(ap);
114511be35a1SLionel Sambuc }
114611be35a1SLionel Sambuc 
114711be35a1SLionel Sambuc void
atf_tc_check_errno(const char * file,const size_t line,const int exp_errno,const char * expr_str,const bool expr_result)114811be35a1SLionel Sambuc atf_tc_check_errno(const char *file, const size_t line, const int exp_errno,
114911be35a1SLionel Sambuc                    const char *expr_str, const bool expr_result)
115011be35a1SLionel Sambuc {
115111be35a1SLionel Sambuc     PRE(Current.tc != NULL);
115211be35a1SLionel Sambuc 
115311be35a1SLionel Sambuc     _atf_tc_check_errno(&Current, file, line, exp_errno, expr_str,
115411be35a1SLionel Sambuc                         expr_result);
115511be35a1SLionel Sambuc }
115611be35a1SLionel Sambuc 
115711be35a1SLionel Sambuc void
atf_tc_require_errno(const char * file,const size_t line,const int exp_errno,const char * expr_str,const bool expr_result)115811be35a1SLionel Sambuc atf_tc_require_errno(const char *file, const size_t line, const int exp_errno,
115911be35a1SLionel Sambuc                      const char *expr_str, const bool expr_result)
116011be35a1SLionel Sambuc {
116111be35a1SLionel Sambuc     PRE(Current.tc != NULL);
116211be35a1SLionel Sambuc 
116311be35a1SLionel Sambuc     _atf_tc_require_errno(&Current, file, line, exp_errno, expr_str,
116411be35a1SLionel Sambuc                           expr_result);
116511be35a1SLionel Sambuc }
116611be35a1SLionel Sambuc 
116711be35a1SLionel Sambuc void
atf_tc_expect_pass(void)116811be35a1SLionel Sambuc atf_tc_expect_pass(void)
116911be35a1SLionel Sambuc {
117011be35a1SLionel Sambuc     PRE(Current.tc != NULL);
117111be35a1SLionel Sambuc 
117211be35a1SLionel Sambuc     _atf_tc_expect_pass(&Current);
117311be35a1SLionel Sambuc }
117411be35a1SLionel Sambuc 
117511be35a1SLionel Sambuc void
atf_tc_expect_fail(const char * reason,...)117611be35a1SLionel Sambuc atf_tc_expect_fail(const char *reason, ...)
117711be35a1SLionel Sambuc {
117811be35a1SLionel Sambuc     va_list ap;
117911be35a1SLionel Sambuc 
118011be35a1SLionel Sambuc     PRE(Current.tc != NULL);
118111be35a1SLionel Sambuc 
118211be35a1SLionel Sambuc     va_start(ap, reason);
118311be35a1SLionel Sambuc     _atf_tc_expect_fail(&Current, reason, ap);
118411be35a1SLionel Sambuc     va_end(ap);
118511be35a1SLionel Sambuc }
118611be35a1SLionel Sambuc 
118711be35a1SLionel Sambuc void
atf_tc_expect_exit(const int exitcode,const char * reason,...)118811be35a1SLionel Sambuc atf_tc_expect_exit(const int exitcode, const char *reason, ...)
118911be35a1SLionel Sambuc {
119011be35a1SLionel Sambuc     va_list ap;
119111be35a1SLionel Sambuc 
119211be35a1SLionel Sambuc     PRE(Current.tc != NULL);
119311be35a1SLionel Sambuc 
119411be35a1SLionel Sambuc     va_start(ap, reason);
119511be35a1SLionel Sambuc     _atf_tc_expect_exit(&Current, exitcode, reason, ap);
119611be35a1SLionel Sambuc     va_end(ap);
119711be35a1SLionel Sambuc }
119811be35a1SLionel Sambuc 
119911be35a1SLionel Sambuc void
atf_tc_expect_signal(const int signo,const char * reason,...)120011be35a1SLionel Sambuc atf_tc_expect_signal(const int signo, const char *reason, ...)
120111be35a1SLionel Sambuc {
120211be35a1SLionel Sambuc     va_list ap;
120311be35a1SLionel Sambuc 
120411be35a1SLionel Sambuc     PRE(Current.tc != NULL);
120511be35a1SLionel Sambuc 
120611be35a1SLionel Sambuc     va_start(ap, reason);
120711be35a1SLionel Sambuc     _atf_tc_expect_signal(&Current, signo, reason, ap);
120811be35a1SLionel Sambuc     va_end(ap);
120911be35a1SLionel Sambuc }
121011be35a1SLionel Sambuc 
121111be35a1SLionel Sambuc void
atf_tc_expect_death(const char * reason,...)121211be35a1SLionel Sambuc atf_tc_expect_death(const char *reason, ...)
121311be35a1SLionel Sambuc {
121411be35a1SLionel Sambuc     va_list ap;
121511be35a1SLionel Sambuc 
121611be35a1SLionel Sambuc     PRE(Current.tc != NULL);
121711be35a1SLionel Sambuc 
121811be35a1SLionel Sambuc     va_start(ap, reason);
121911be35a1SLionel Sambuc     _atf_tc_expect_death(&Current, reason, ap);
122011be35a1SLionel Sambuc     va_end(ap);
122111be35a1SLionel Sambuc }
122211be35a1SLionel Sambuc 
122311be35a1SLionel Sambuc void
atf_tc_expect_timeout(const char * reason,...)122411be35a1SLionel Sambuc atf_tc_expect_timeout(const char *reason, ...)
122511be35a1SLionel Sambuc {
122611be35a1SLionel Sambuc     va_list ap;
122711be35a1SLionel Sambuc 
122811be35a1SLionel Sambuc     PRE(Current.tc != NULL);
122911be35a1SLionel Sambuc 
123011be35a1SLionel Sambuc     va_start(ap, reason);
123111be35a1SLionel Sambuc     _atf_tc_expect_timeout(&Current, reason, ap);
123211be35a1SLionel Sambuc     va_end(ap);
123311be35a1SLionel Sambuc }
1234