13b6cf63jmmv/* Copyright (c) 2008 The NetBSD Foundation, Inc.
245147a9marcel * All rights reserved.
345147a9marcel *
445147a9marcel * Redistribution and use in source and binary forms, with or without
545147a9marcel * modification, are permitted provided that the following conditions
645147a9marcel * are met:
745147a9marcel * 1. Redistributions of source code must retain the above copyright
845147a9marcel *    notice, this list of conditions and the following disclaimer.
945147a9marcel * 2. Redistributions in binary form must reproduce the above copyright
1045147a9marcel *    notice, this list of conditions and the following disclaimer in the
1145147a9marcel *    documentation and/or other materials provided with the distribution.
1245147a9marcel *
1345147a9marcel * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
1445147a9marcel * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
1545147a9marcel * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
1645147a9marcel * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1745147a9marcel * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
1845147a9marcel * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1945147a9marcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
2045147a9marcel * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2145147a9marcel * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
2245147a9marcel * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
2345147a9marcel * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
243b6cf63jmmv * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  */
253b6cf63jmmv
263b6cf63jmmv#include "atf-c/tc.h"
2745147a9marcel
2845147a9marcel#include <sys/types.h>
2945147a9marcel#include <sys/stat.h>
3045147a9marcel#include <sys/uio.h>
3145147a9marcel
3245147a9marcel#include <errno.h>
3345147a9marcel#include <fcntl.h>
3445147a9marcel#include <stdarg.h>
3545147a9marcel#include <stdbool.h>
3645147a9marcel#include <stdio.h>
3745147a9marcel#include <stdlib.h>
3845147a9marcel#include <string.h>
3945147a9marcel#include <unistd.h>
4045147a9marcel
4145147a9marcel#include "atf-c/defs.h"
423b6cf63jmmv#include "atf-c/detail/env.h"
433b6cf63jmmv#include "atf-c/detail/fs.h"
443b6cf63jmmv#include "atf-c/detail/map.h"
453b6cf63jmmv#include "atf-c/detail/sanity.h"
463b6cf63jmmv#include "atf-c/detail/text.h"
4745147a9marcel#include "atf-c/error.h"
4845147a9marcel
4945147a9marcel/* ---------------------------------------------------------------------
5045147a9marcel * Auxiliary functions.
5145147a9marcel * --------------------------------------------------------------------- */
5245147a9marcel
5345147a9marcelenum expect_type {
5445147a9marcel    EXPECT_PASS,
5545147a9marcel    EXPECT_FAIL,
5645147a9marcel    EXPECT_EXIT,
5745147a9marcel    EXPECT_SIGNAL,
5845147a9marcel    EXPECT_DEATH,
5945147a9marcel    EXPECT_TIMEOUT,
6045147a9marcel};
6145147a9marcel
6245147a9marcelstruct context {
6345147a9marcel    const atf_tc_t *tc;
6445147a9marcel    const char *resfile;
6545147a9marcel    size_t fail_count;
6645147a9marcel
6745147a9marcel    enum expect_type expect;
6845147a9marcel    atf_dynstr_t expect_reason;
6945147a9marcel    size_t expect_previous_fail_count;
7045147a9marcel    size_t expect_fail_count;
7145147a9marcel    int expect_exitcode;
7245147a9marcel    int expect_signo;
7345147a9marcel};
7445147a9marcel
7545147a9marcelstatic void context_init(struct context *, const atf_tc_t *, const char *);
7645147a9marcelstatic void check_fatal_error(atf_error_t);
7745147a9marcelstatic void report_fatal_error(const char *, ...)
7845147a9marcel    ATF_DEFS_ATTRIBUTE_NORETURN;
7945147a9marcelstatic atf_error_t write_resfile(const int, const char *, const int,
8045147a9marcel                                 const atf_dynstr_t *);
8145147a9marcelstatic void create_resfile(const char *, const char *, const int,
8245147a9marcel                           atf_dynstr_t *);
8345147a9marcelstatic void error_in_expect(struct context *, const char *, ...)
8445147a9marcel    ATF_DEFS_ATTRIBUTE_NORETURN;
8545147a9marcelstatic void validate_expect(struct context *);
8645147a9marcelstatic void expected_failure(struct context *, atf_dynstr_t *)
8745147a9marcel    ATF_DEFS_ATTRIBUTE_NORETURN;
8845147a9marcelstatic void fail_requirement(struct context *, atf_dynstr_t *)
8945147a9marcel    ATF_DEFS_ATTRIBUTE_NORETURN;
9045147a9marcelstatic void fail_check(struct context *, atf_dynstr_t *);
9145147a9marcelstatic void pass(struct context *)
9245147a9marcel    ATF_DEFS_ATTRIBUTE_NORETURN;
9345147a9marcelstatic void skip(struct context *, atf_dynstr_t *)
9445147a9marcel    ATF_DEFS_ATTRIBUTE_NORETURN;
9545147a9marcelstatic void format_reason_ap(atf_dynstr_t *, const char *, const size_t,
9645147a9marcel                             const char *, va_list);
9745147a9marcelstatic void format_reason_fmt(atf_dynstr_t *, const char *, const size_t,
9845147a9marcel                              const char *, ...);
9945147a9marcelstatic void errno_test(struct context *, const char *, const size_t,
10045147a9marcel                       const int, const char *, const bool,
10145147a9marcel                       void (*)(struct context *, atf_dynstr_t *));
10245147a9marcelstatic atf_error_t check_prog_in_dir(const char *, void *);
10345147a9marcelstatic atf_error_t check_prog(struct context *, const char *);
10445147a9marcel
10545147a9marcelstatic void
10645147a9marcelcontext_init(struct context *ctx, const atf_tc_t *tc, const char *resfile)
10745147a9marcel{
10845147a9marcel    ctx->tc = tc;
10945147a9marcel    ctx->resfile = resfile;
11045147a9marcel    ctx->fail_count = 0;
11145147a9marcel    ctx->expect = EXPECT_PASS;
11245147a9marcel    check_fatal_error(atf_dynstr_init(&ctx->expect_reason));
11345147a9marcel    ctx->expect_previous_fail_count = 0;
11445147a9marcel    ctx->expect_fail_count = 0;
11545147a9marcel    ctx->expect_exitcode = 0;
11645147a9marcel    ctx->expect_signo = 0;
11745147a9marcel}
11845147a9marcel
11945147a9marcelstatic void
12045147a9marcelcheck_fatal_error(atf_error_t err)
12145147a9marcel{
12245147a9marcel    if (atf_is_error(err)) {
12345147a9marcel        char buf[1024];
12445147a9marcel        atf_error_format(err, buf, sizeof(buf));
12545147a9marcel        fprintf(stderr, "FATAL ERROR: %s\n", buf);
12645147a9marcel        atf_error_free(err);
12745147a9marcel        abort();
12845147a9marcel    }
12945147a9marcel}
13045147a9marcel
13145147a9marcelstatic void
13245147a9marcelreport_fatal_error(const char *msg, ...)
13345147a9marcel{
13445147a9marcel    va_list ap;
13545147a9marcel    fprintf(stderr, "FATAL ERROR: ");
13645147a9marcel
13745147a9marcel    va_start(ap, msg);
13845147a9marcel    vfprintf(stderr, msg, ap);
13945147a9marcel    va_end(ap);
14045147a9marcel
14145147a9marcel    fprintf(stderr, "\n");
14245147a9marcel    abort();
14345147a9marcel}
14445147a9marcel
14545147a9marcel/** Writes to a results file.
14645147a9marcel *
14745147a9marcel * The results file is supposed to be already open.
14845147a9marcel *
14945147a9marcel * This function returns an error code instead of exiting in case of error
15045147a9marcel * because the caller needs to clean up the reason object before terminating.
15145147a9marcel */
15245147a9marcelstatic atf_error_t
15345147a9marcelwrite_resfile(const int fd, const char *result, const int arg,
15445147a9marcel              const atf_dynstr_t *reason)
15545147a9marcel{
15645147a9marcel    static char NL[] = "\n", CS[] = ": ";
15745147a9marcel    char buf[64];
15845147a9marcel    const char *r;
15945147a9marcel    struct iovec iov[5];
16045147a9marcel    ssize_t ret;
16145147a9marcel    int count = 0;
16245147a9marcel
16345147a9marcel    INV(arg == -1 || reason != NULL);
16445147a9marcel
16545147a9marcel#define UNCONST(a) ((void *)(unsigned long)(const void *)(a))
16645147a9marcel    iov[count].iov_base = UNCONST(result);
16745147a9marcel    iov[count++].iov_len = strlen(result);
16845147a9marcel
16945147a9marcel    if (reason != NULL) {
17045147a9marcel        if (arg != -1) {
17145147a9marcel            iov[count].iov_base = buf;
17245147a9marcel            iov[count++].iov_len = snprintf(buf, sizeof(buf), "(%d)", arg);
17345147a9marcel        }
17445147a9marcel
17545147a9marcel        iov[count].iov_base = CS;
17645147a9marcel        iov[count++].iov_len = sizeof(CS) - 1;
17745147a9marcel
17845147a9marcel        r = atf_dynstr_cstring(reason);
17945147a9marcel        iov[count].iov_base = UNCONST(r);
18045147a9marcel        iov[count++].iov_len = strlen(r);
18145147a9marcel    }
18245147a9marcel#undef UNCONST
18345147a9marcel
18445147a9marcel    iov[count].iov_base = NL;
18545147a9marcel    iov[count++].iov_len = sizeof(NL) - 1;
18645147a9marcel
18745147a9marcel    while ((ret = writev(fd, iov, count)) == -1 && errno == EINTR)
18845147a9marcel        continue; /* Retry. */
18945147a9marcel    if (ret != -1)
19045147a9marcel        return atf_no_error();
19145147a9marcel
19245147a9marcel    return atf_libc_error(
19345147a9marcel        errno, "Failed to write results file; result %s, reason %s", result,
19445147a9marcel        reason == NULL ? "null" : atf_dynstr_cstring(reason));
19545147a9marcel}
19645147a9marcel
19745147a9marcel/** Creates a results file.
19845147a9marcel *
19945147a9marcel * The input reason is released in all cases.
20045147a9marcel *
20145147a9marcel * An error in this function is considered to be fatal, hence why it does
20245147a9marcel * not return any error code.
20345147a9marcel */
20445147a9marcelstatic void
20545147a9marcelcreate_resfile(const char *resfile, const char *result, const int arg,
20645147a9marcel               atf_dynstr_t *reason)
20745147a9marcel{
20845147a9marcel    atf_error_t err;
20945147a9marcel
21045147a9marcel    if (strcmp("/dev/stdout", resfile) == 0) {
21145147a9marcel        err = write_resfile(STDOUT_FILENO, result, arg, reason);
21245147a9marcel    } else if (strcmp("/dev/stderr", resfile) == 0) {
21345147a9marcel        err = write_resfile(STDERR_FILENO, result, arg, reason);
21445147a9marcel    } else {
21545147a9marcel        const int fd = open(resfile, O_WRONLY | O_CREAT | O_TRUNC,
21645147a9marcel            S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
21745147a9marcel        if (fd == -1) {
21845147a9marcel            err = atf_libc_error(errno, "Cannot create results file '%s'",
21945147a9marcel                                 resfile);
22045147a9marcel        } else {
22145147a9marcel            err = write_resfile(fd, result, arg, reason);
22245147a9marcel            close(fd);
22345147a9marcel        }
22445147a9marcel    }
22545147a9marcel
22645147a9marcel    if (reason != NULL)
22745147a9marcel        atf_dynstr_fini(reason);
22845147a9marcel
22945147a9marcel    check_fatal_error(err);
23045147a9marcel}
23145147a9marcel
23245147a9marcel/** Fails a test case if validate_expect fails. */
23345147a9marcelstatic void
23445147a9marcelerror_in_expect(struct context *ctx, const char *fmt, ...)
23545147a9marcel{
23645147a9marcel    atf_dynstr_t reason;
23745147a9marcel    va_list ap;
23845147a9marcel
23945147a9marcel    va_start(ap, fmt);
24045147a9marcel    format_reason_ap(&reason, NULL, 0, fmt, ap);
24145147a9marcel    va_end(ap);
24245147a9marcel
24345147a9marcel    ctx->expect = EXPECT_PASS;  /* Ensure fail_requirement really fails. */
24445147a9marcel    fail_requirement(ctx, &reason);
24545147a9marcel}
24645147a9marcel
24745147a9marcel/** Ensures that the "expect" state is correct.
24845147a9marcel *
24945147a9marcel * Call this function before modifying the current value of expect.
25045147a9marcel */
25145147a9marcelstatic void
25245147a9marcelvalidate_expect(struct context *ctx)
25345147a9marcel{
25445147a9marcel    if (ctx->expect == EXPECT_DEATH) {
25545147a9marcel        error_in_expect(ctx, "Test case was expected to terminate abruptly "
25645147a9marcel            "but it continued execution");
25745147a9marcel    } else if (ctx->expect == EXPECT_EXIT) {
25845147a9marcel        error_in_expect(ctx, "Test case was expected to exit cleanly but it "
25945147a9marcel            "continued execution");
26045147a9marcel    } else if (ctx->expect == EXPECT_FAIL) {
26145147a9marcel        if (ctx->expect_fail_count == ctx->expect_previous_fail_count)
26245147a9marcel            error_in_expect(ctx, "Test case was expecting a failure but none "
26345147a9marcel                "were raised");
26445147a9marcel        else
26545147a9marcel            INV(ctx->expect_fail_count > ctx->expect_previous_fail_count);
26645147a9marcel    } else if (ctx->expect == EXPECT_PASS) {
26745147a9marcel        /* Nothing to validate. */
26845147a9marcel    } else if (ctx->expect == EXPECT_SIGNAL) {
26945147a9marcel        error_in_expect(ctx, "Test case was expected to receive a termination "
27045147a9marcel            "signal but it continued execution");
27145147a9marcel    } else if (ctx->expect == EXPECT_TIMEOUT) {
27245147a9marcel        error_in_expect(ctx, "Test case was expected to hang but it continued "
27345147a9marcel            "execution");
27445147a9marcel    } else
27545147a9marcel        UNREACHABLE;
27645147a9marcel}
27745147a9marcel
27845147a9marcelstatic void
27945147a9marcelexpected_failure(struct context *ctx, atf_dynstr_t *reason)
28045147a9marcel{
28145147a9marcel    check_fatal_error(atf_dynstr_prepend_fmt(reason, "%s: ",
28245147a9marcel        atf_dynstr_cstring(&ctx->expect_reason)));
28345147a9marcel    create_resfile(ctx->resfile, "expected_failure", -1, reason);
28445147a9marcel    exit(EXIT_SUCCESS);
28545147a9marcel}
28645147a9marcel
28745147a9marcelstatic void
28845147a9marcelfail_requirement(struct context *ctx, atf_dynstr_t *reason)
28945147a9marcel{
29045147a9marcel    if (ctx->expect == EXPECT_FAIL) {
29145147a9marcel        expected_failure(ctx, reason);
29245147a9marcel    } else if (ctx->expect == EXPECT_PASS) {
29345147a9marcel        create_resfile(ctx->resfile, "failed", -1, reason);
29445147a9marcel        exit(EXIT_FAILURE);
29545147a9marcel    } else {
29645147a9marcel        error_in_expect(ctx, "Test case raised a failure but was not "
29745147a9marcel            "expecting one; reason was %s", atf_dynstr_cstring(reason));
29845147a9marcel    }
29945147a9marcel    UNREACHABLE;
30045147a9marcel}
30145147a9marcel
30245147a9marcelstatic void
30345147a9marcelfail_check(struct context *ctx, atf_dynstr_t *reason)
30445147a9marcel{
30545147a9marcel    if (ctx->expect == EXPECT_FAIL) {
30645147a9marcel        fprintf(stderr, "*** Expected check failure: %s: %s\n",
30745147a9marcel            atf_dynstr_cstring(&ctx->expect_reason),
30845147a9marcel            atf_dynstr_cstring(reason));
30945147a9marcel        ctx->expect_fail_count++;
31045147a9marcel    } else if (ctx->expect == EXPECT_PASS) {
31145147a9marcel        fprintf(stderr, "*** Check failed: %s\n", atf_dynstr_cstring(reason));
31245147a9marcel        ctx->fail_count++;
31345147a9marcel    } else {
31445147a9marcel        error_in_expect(ctx, "Test case raised a failure but was not "
31545147a9marcel            "expecting one; reason was %s", atf_dynstr_cstring(reason));
31645147a9marcel    }
31745147a9marcel
31845147a9marcel    atf_dynstr_fini(reason);
31945147a9marcel}
32045147a9marcel
32145147a9marcelstatic void
32245147a9marcelpass(struct context *ctx)
32345147a9marcel{
32445147a9marcel    if (ctx->expect == EXPECT_FAIL) {
32545147a9marcel        error_in_expect(ctx, "Test case was expecting a failure but got "
32645147a9marcel            "a pass instead");
32745147a9marcel    } else if (ctx->expect == EXPECT_PASS) {
32845147a9marcel        create_resfile(ctx->resfile, "passed", -1, NULL);
32945147a9marcel        exit(EXIT_SUCCESS);
33045147a9marcel    } else {
33145147a9marcel        error_in_expect(ctx, "Test case asked to explicitly pass but was "
33245147a9marcel            "not expecting such condition");
33345147a9marcel    }
33445147a9marcel    UNREACHABLE;
33545147a9marcel}
33645147a9marcel
33745147a9marcelstatic void
33845147a9marcelskip(struct context *ctx, atf_dynstr_t *reason)
33945147a9marcel{
34045147a9marcel    if (ctx->expect == EXPECT_PASS) {
34145147a9marcel        create_resfile(ctx->resfile, "skipped", -1, reason);
34245147a9marcel        exit(EXIT_SUCCESS);
34345147a9marcel    } else {
34445147a9marcel        error_in_expect(ctx, "Can only skip a test case when running in "
34545147a9marcel            "expect pass mode");
34645147a9marcel    }
34745147a9marcel    UNREACHABLE;
34845147a9marcel}
34945147a9marcel
35045147a9marcel/** Formats a failure/skip reason message.
35145147a9marcel *
35245147a9marcel * The formatted reason is stored in out_reason.  out_reason is initialized
35345147a9marcel * in this function and is supposed to be released by the caller.  In general,
35445147a9marcel * the reason will eventually be fed to create_resfile, which will release
35545147a9marcel * it.
35645147a9marcel *
35745147a9marcel * Errors in this function are fatal.  Rationale being: reasons are used to
35845147a9marcel * create results files; if we can't format the reason correctly, the result
35945147a9marcel * of the test program will be bogus.  So it's better to just exit with a
36045147a9marcel * fatal error.
36145147a9marcel */
36245147a9marcelstatic void
36345147a9marcelformat_reason_ap(atf_dynstr_t *out_reason,
36445147a9marcel                 const char *source_file, const size_t source_line,
36545147a9marcel                 const char *reason, va_list ap)
36645147a9marcel{
36745147a9marcel    atf_error_t err;
36845147a9marcel
36945147a9marcel    if (source_file != NULL) {
37045147a9marcel        err = atf_dynstr_init_fmt(out_reason, "%s:%zd: ", source_file,
37145147a9marcel                                  source_line);
37245147a9marcel    } else {
37345147a9marcel        PRE(source_line == 0);
37445147a9marcel        err = atf_dynstr_init(out_reason);
37545147a9marcel    }
37645147a9marcel
37745147a9marcel    if (!atf_is_error(err)) {
37845147a9marcel        va_list ap2;
37945147a9marcel        va_copy(ap2, ap);
38045147a9marcel        err = atf_dynstr_append_ap(out_reason, reason, ap2);
38145147a9marcel        va_end(ap2);
38245147a9marcel    }
38345147a9marcel
38445147a9marcel    check_fatal_error(err);
38545147a9marcel}
38645147a9marcel
38745147a9marcelstatic void
38845147a9marcelformat_reason_fmt(atf_dynstr_t *out_reason,
38945147a9marcel                  const char *source_file, const size_t source_line,
39045147a9marcel                  const char *reason, ...)
39145147a9marcel{
39245147a9marcel    va_list ap;
39345147a9marcel
39445147a9marcel    va_start(ap, reason);
39545147a9marcel    format_reason_ap(out_reason, source_file, source_line, reason, ap);
39645147a9marcel    va_end(ap);
39745147a9marcel}
39845147a9marcel
39945147a9marcelstatic void
40045147a9marcelerrno_test(struct context *ctx, const char *file, const size_t line,
40145147a9marcel           const int exp_errno, const char *expr_str,
40245147a9marcel           const bool expr_result,
40345147a9marcel           void (*fail_func)(struct context *, atf_dynstr_t *))
40445147a9marcel{
40545147a9marcel    const int actual_errno = errno;
40645147a9marcel
40745147a9marcel    if (expr_result) {
40845147a9marcel        if (exp_errno != actual_errno) {
40945147a9marcel            atf_dynstr_t reason;
41045147a9marcel
41145147a9marcel            format_reason_fmt(&reason, file, line, "Expected errno %d, got %d, "
41245147a9marcel                "in %s", exp_errno, actual_errno, expr_str);
41345147a9marcel            fail_func(ctx, &reason);
41445147a9marcel        }
41545147a9marcel    } else {
41645147a9marcel        atf_dynstr_t reason;
41745147a9marcel
41845147a9marcel        format_reason_fmt(&reason, file, line, "Expected true value in %s",
41945147a9marcel            expr_str);
42045147a9marcel        fail_func(ctx, &reason);
42145147a9marcel    }
42245147a9marcel}
42345147a9marcel
42445147a9marcelstruct prog_found_pair {
42545147a9marcel    const char *prog;
42645147a9marcel    bool found;
42745147a9marcel};
42845147a9marcel
42945147a9marcelstatic atf_error_t
43045147a9marcelcheck_prog_in_dir(const char *dir, void *data)
43145147a9marcel{
43245147a9marcel    struct prog_found_pair *pf = data;
43345147a9marcel    atf_error_t err;
43445147a9marcel
43545147a9marcel    if (pf->found)
43645147a9marcel        err = atf_no_error();
43745147a9marcel    else {
43845147a9marcel        atf_fs_path_t p;
43945147a9marcel
44045147a9marcel        err = atf_fs_path_init_fmt(&p, "%s/%s", dir, pf->prog);
44145147a9marcel        if (atf_is_error(err))
44245147a9marcel            goto out_p;
44345147a9marcel
44445147a9marcel        err = atf_fs_eaccess(&p, atf_fs_access_x);
44545147a9marcel        if (!atf_is_error(err))
44645147a9marcel            pf->found = true;
44745147a9marcel        else {
44845147a9marcel            atf_error_free(err);
44945147a9marcel            INV(!pf->found);
45045147a9marcel            err = atf_no_error();
45145147a9marcel        }
45245147a9marcel
45345147a9marcelout_p:
45445147a9marcel        atf_fs_path_fini(&p);
45545147a9marcel    }
45645147a9marcel
45745147a9marcel    return err;
45845147a9marcel}
45945147a9marcel
46045147a9marcelstatic atf_error_t
46145147a9marcelcheck_prog(struct context *ctx, const char *prog)
46245147a9marcel{
46345147a9marcel    atf_error_t err;
46445147a9marcel    atf_fs_path_t p;
46545147a9marcel
46645147a9marcel    err = atf_fs_path_init_fmt(&p, "%s", prog);
46745147a9marcel    if (atf_is_error(err))
46845147a9marcel        goto out;
46945147a9marcel
47045147a9marcel    if (atf_fs_path_is_absolute(&p)) {
47145147a9marcel        err = atf_fs_eaccess(&p, atf_fs_access_x);
47245147a9marcel        if (atf_is_error(err)) {
47345147a9marcel            atf_dynstr_t reason;
47445147a9marcel
47545147a9marcel            atf_error_free(err);
47645147a9marcel            atf_fs_path_fini(&p);
47745147a9marcel            format_reason_fmt(&reason, NULL, 0, "The required program %s could "
47845147a9marcel                "not be found", prog);
47945147a9marcel            skip(ctx, &reason);
48045147a9marcel        }
48145147a9marcel    } else {
48245147a9marcel        const char *path = atf_env_get("PATH");
48345147a9marcel        struct prog_found_pair pf;
48445147a9marcel        atf_fs_path_t bp;
48545147a9marcel
48645147a9marcel        err = atf_fs_path_branch_path(&p, &bp);
48745147a9marcel        if (atf_is_error(err))
48845147a9marcel            goto out_p;
48945147a9marcel
49045147a9marcel        if (strcmp(atf_fs_path_cstring(&bp), ".") != 0) {
49145147a9marcel            atf_fs_path_fini(&bp);
49245147a9marcel            atf_fs_path_fini(&p);
49345147a9marcel
49445147a9marcel            report_fatal_error("Relative paths are not allowed when searching "
49545147a9marcel                "for a program (%s)", prog);
49645147a9marcel            UNREACHABLE;
49745147a9marcel        }
49845147a9marcel
49945147a9marcel        pf.prog = prog;
50045147a9marcel        pf.found = false;
50145147a9marcel        err = atf_text_for_each_word(path, ":", check_prog_in_dir, &pf);
50245147a9marcel        if (atf_is_error(err))
50345147a9marcel            goto out_bp;
50445147a9marcel
50545147a9marcel        if (!pf.found) {
50645147a9marcel            atf_dynstr_t reason;
50745147a9marcel
50845147a9marcel            atf_fs_path_fini(&bp);
50945147a9marcel            atf_fs_path_fini(&p);
51045147a9marcel            format_reason_fmt(&reason, NULL, 0, "The required program %s could "
51145147a9marcel                "not be found in the PATH", prog);
51245147a9marcel            fail_requirement(ctx, &reason);
51345147a9marcel        }
51445147a9marcel
51545147a9marcelout_bp:
51645147a9marcel        atf_fs_path_fini(&bp);
51745147a9marcel    }
51845147a9marcel
51945147a9marcelout_p:
52045147a9marcel    atf_fs_path_fini(&p);
52145147a9marcelout:
52245147a9marcel    return err;
52345147a9marcel}
52445147a9marcel
52545147a9marcel/* ---------------------------------------------------------------------
52645147a9marcel * The "atf_tc" type.
52745147a9marcel * --------------------------------------------------------------------- */
52845147a9marcel
52945147a9marcelstruct atf_tc_impl {
53045147a9marcel    const char *m_ident;
53145147a9marcel
53245147a9marcel    atf_map_t m_vars;
53345147a9marcel    atf_map_t m_config;
53445147a9marcel
53545147a9marcel    atf_tc_head_t m_head;
53645147a9marcel    atf_tc_body_t m_body;
53745147a9marcel    atf_tc_cleanup_t m_cleanup;
53845147a9marcel};
53945147a9marcel
54045147a9marcel/*
54145147a9marcel * Constructors/destructors.
54245147a9marcel */
54345147a9marcel
54445147a9marcelatf_error_t
54545147a9marcelatf_tc_init(atf_tc_t *tc, const char *ident, atf_tc_head_t head,
54645147a9marcel            atf_tc_body_t body, atf_tc_cleanup_t cleanup,
54745147a9marcel            const char *const *config)
54845147a9marcel{
54945147a9marcel    atf_error_t err;
55045147a9marcel
55145147a9marcel    tc->pimpl = malloc(sizeof(struct atf_tc_impl));
55245147a9marcel    if (tc->pimpl == NULL) {
55345147a9marcel        err = atf_no_memory_error();
55445147a9marcel        goto err;
55545147a9marcel    }
55645147a9marcel
55745147a9marcel    tc->pimpl->m_ident = ident;
55845147a9marcel    tc->pimpl->m_head = head;
55945147a9marcel    tc->pimpl->m_body = body;
56045147a9marcel    tc->pimpl->m_cleanup = cleanup;
56145147a9marcel
56245147a9marcel    err = atf_map_init_charpp(&tc->pimpl->m_config, config);
56345147a9marcel    if (atf_is_error(err))
56445147a9marcel        goto err;
56545147a9marcel
56645147a9marcel    err = atf_map_init(&tc->pimpl->m_vars);
56745147a9marcel    if (atf_is_error(err))
56845147a9marcel        goto err_vars;
56945147a9marcel
57045147a9marcel    err = atf_tc_set_md_var(tc, "ident", ident);
57145147a9marcel    if (atf_is_error(err))
57245147a9marcel        goto err_map;
57345147a9marcel
57445147a9marcel    if (cleanup != NULL) {
57545147a9marcel        err = atf_tc_set_md_var(tc, "has.cleanup", "true");
57645147a9marcel        if (atf_is_error(err))
57745147a9marcel            goto err_map;
57845147a9marcel    }
57945147a9marcel
58045147a9marcel    /* XXX Should the head be able to return error codes? */
58145147a9marcel    if (tc->pimpl->m_head != NULL)
58245147a9marcel        tc->pimpl->m_head(tc);
58345147a9marcel
58445147a9marcel    if (strcmp(atf_tc_get_md_var(tc, "ident"), ident) != 0) {
58545147a9marcel        report_fatal_error("Test case head modified the read-only 'ident' "
58645147a9marcel            "property");
58745147a9marcel        UNREACHABLE;
58845147a9marcel    }
58945147a9marcel
59045147a9marcel    INV(!atf_is_error(err));
59145147a9marcel    return err;
59245147a9marcel
59345147a9marcelerr_map:
59445147a9marcel    atf_map_fini(&tc->pimpl->m_vars);
59545147a9marcelerr_vars:
59645147a9marcel    atf_map_fini(&tc->pimpl->m_config);
59745147a9marcelerr:
59845147a9marcel    return err;
59945147a9marcel}
60045147a9marcel
60145147a9marcelatf_error_t
60245147a9marcelatf_tc_init_pack(atf_tc_t *tc, const atf_tc_pack_t *pack,
60345147a9marcel                 const char *const *config)
60445147a9marcel{
60545147a9marcel    return atf_tc_init(tc, pack->m_ident, pack->m_head, pack->m_body,
60645147a9marcel                       pack->m_cleanup, config);
60745147a9marcel}
60845147a9marcel
60945147a9marcelvoid
61045147a9marcelatf_tc_fini(atf_tc_t *tc)
61145147a9marcel{
61245147a9marcel    atf_map_fini(&tc->pimpl->m_vars);
61345147a9marcel    free(tc->pimpl);
61445147a9marcel}
61545147a9marcel
61645147a9marcel/*
61745147a9marcel * Getters.
61845147a9marcel */
61945147a9marcel
62045147a9marcelconst char *
62145147a9marcelatf_tc_get_ident(const atf_tc_t *tc)
62245147a9marcel{
62345147a9marcel    return tc->pimpl->m_ident;
62445147a9marcel}
62545147a9marcel
62645147a9marcelconst char *
62745147a9marcelatf_tc_get_config_var(const atf_tc_t *tc, const char *name)
62845147a9marcel{
62945147a9marcel    const char *val;
63045147a9marcel    atf_map_citer_t iter;
63145147a9marcel
63245147a9marcel    PRE(atf_tc_has_config_var(tc, name));
63345147a9marcel    iter = atf_map_find_c(&tc->pimpl->m_config, name);
63445147a9marcel    val = atf_map_citer_data(iter);
63545147a9marcel    INV(val != NULL);
63645147a9marcel
63745147a9marcel    return val;
63845147a9marcel}
63945147a9marcel
64045147a9marcelconst char *
64145147a9marcelatf_tc_get_config_var_wd(const atf_tc_t *tc, const char *name,
64245147a9marcel                         const char *defval)
64345147a9marcel{
64445147a9marcel    const char *val;
64545147a9marcel
64645147a9marcel    if (!atf_tc_has_config_var(tc, name))
64745147a9marcel        val = defval;
64845147a9marcel    else
64945147a9marcel        val = atf_tc_get_config_var(tc, name);
65045147a9marcel
65145147a9marcel    return val;
65245147a9marcel}
65345147a9marcel
65445147a9marcelbool
65545147a9marcelatf_tc_get_config_var_as_bool(const atf_tc_t *tc, const char *name)
65645147a9marcel{
65745147a9marcel    bool val;
65845147a9marcel    const char *strval;
65945147a9marcel    atf_error_t err;
66045147a9marcel
66145147a9marcel    strval = atf_tc_get_config_var(tc, name);
66245147a9marcel    err = atf_text_to_bool(strval, &val);
66345147a9marcel    if (atf_is_error(err)) {
66445147a9marcel        atf_error_free(err);
66545147a9marcel        atf_tc_fail("Configuration variable %s does not have a valid "
66645147a9marcel                    "boolean value; found %s", name, strval);
66745147a9marcel    }
66845147a9marcel
66945147a9marcel    return val;
67045147a9marcel}
67145147a9marcel
67245147a9marcelbool
67345147a9marcelatf_tc_get_config_var_as_bool_wd(const atf_tc_t *tc, const char *name,
67445147a9marcel                                 const bool defval)
67545147a9marcel{
67645147a9marcel    bool val;
67745147a9marcel
67845147a9marcel    if (!atf_tc_has_config_var(tc, name))
67945147a9marcel        val = defval;
68045147a9marcel    else
68145147a9marcel        val = atf_tc_get_config_var_as_bool(tc, name);
68245147a9marcel
68345147a9marcel    return val;
68445147a9marcel}
68545147a9marcel
68645147a9marcellong
68745147a9marcelatf_tc_get_config_var_as_long(const atf_tc_t *tc, const char *name)
68845147a9marcel{
68945147a9marcel    long val;
69045147a9marcel    const char *strval;
69145147a9marcel    atf_error_t err;
69245147a9marcel
69345147a9marcel    strval = atf_tc_get_config_var(tc, name);
69445147a9marcel    err = atf_text_to_long(strval, &val);
69545147a9marcel    if (atf_is_error(err)) {
69645147a9marcel        atf_error_free(err);
69745147a9marcel        atf_tc_fail("Configuration variable %s does not have a valid "
69845147a9marcel                    "long value; found %s", name, strval);
69945147a9marcel    }
70045147a9marcel
70145147a9marcel    return val;
70245147a9marcel}
70345147a9marcel
70445147a9marcellong
70545147a9marcelatf_tc_get_config_var_as_long_wd(const atf_tc_t *tc, const char *name,
70645147a9marcel                                 const long defval)
70745147a9marcel{
70845147a9marcel    long val;
70945147a9marcel
71045147a9marcel    if (!atf_tc_has_config_var(tc, name))
71145147a9marcel        val = defval;
71245147a9marcel    else
71345147a9marcel        val = atf_tc_get_config_var_as_long(tc, name);
71445147a9marcel
71545147a9marcel    return val;
71645147a9marcel}
71745147a9marcel
71845147a9marcelconst char *
71945147a9marcelatf_tc_get_md_var(const atf_tc_t *tc, const char *name)
72045147a9marcel{
72145147a9marcel    const char *val;
72245147a9marcel    atf_map_citer_t iter;
72345147a9marcel
72445147a9marcel    PRE(atf_tc_has_md_var(tc, name));
72545147a9marcel    iter = atf_map_find_c(&tc->pimpl->m_vars, name);
72645147a9marcel    val = atf_map_citer_data(iter);
72745147a9marcel    INV(val != NULL);
72845147a9marcel
72945147a9marcel    return val;
73045147a9marcel}
73145147a9marcel
73245147a9marcelchar **
73345147a9marcelatf_tc_get_md_vars(const atf_tc_t *tc)
73445147a9marcel{
73545147a9marcel    return atf_map_to_charpp(&tc->pimpl->m_vars);
73645147a9marcel}
73745147a9marcel
73845147a9marcelbool
73945147a9marcelatf_tc_has_config_var(const atf_tc_t *tc, const char *name)
74045147a9marcel{
74145147a9marcel    atf_map_citer_t end, iter;
74245147a9marcel
74345147a9marcel    iter = atf_map_find_c(&tc->pimpl->m_config, name);
74445147a9marcel    end = atf_map_end_c(&tc->pimpl->m_config);
74545147a9marcel    return !atf_equal_map_citer_map_citer(iter, end);
74645147a9marcel}
74745147a9marcel
74845147a9marcelbool
74945147a9marcelatf_tc_has_md_var(const atf_tc_t *tc, const char *name)
75045147a9marcel{
75145147a9marcel    atf_map_citer_t end, iter;
75245147a9marcel
75345147a9marcel    iter = atf_map_find_c(&tc->pimpl->m_vars, name);
75445147a9marcel    end = atf_map_end_c(&tc->pimpl->m_vars);
75545147a9marcel    return !atf_equal_map_citer_map_citer(iter, end);
75645147a9marcel}
75745147a9marcel
75845147a9marcel/*
75945147a9marcel * Modifiers.
76045147a9marcel */
76145147a9marcel
76245147a9marcelatf_error_t
76345147a9marcelatf_tc_set_md_var(atf_tc_t *tc, const char *name, const char *fmt, ...)
76445147a9marcel{
76545147a9marcel    atf_error_t err;
76645147a9marcel    char *value;
76745147a9marcel    va_list ap;
76845147a9marcel
76945147a9marcel    va_start(ap, fmt);
77045147a9marcel    err = atf_text_format_ap(&value, fmt, ap);
77145147a9marcel    va_end(ap);
77245147a9marcel
77345147a9marcel    if (!atf_is_error(err))
77445147a9marcel        err = atf_map_insert(&tc->pimpl->m_vars, name, value, true);
77545147a9marcel    else
77645147a9marcel        free(value);
77745147a9marcel
77845147a9marcel    return err;
77945147a9marcel}
78045147a9marcel
78145147a9marcel/* ---------------------------------------------------------------------
78245147a9marcel * Free functions, as they should be publicly but they can't.
78345147a9marcel * --------------------------------------------------------------------- */
78445147a9marcel
78545147a9marcelstatic void _atf_tc_fail(struct context *, const char *, va_list)
78645147a9marcel    ATF_DEFS_ATTRIBUTE_NORETURN;
78745147a9marcelstatic void _atf_tc_fail_nonfatal(struct context *, const char *, va_list);
78845147a9marcelstatic void _atf_tc_fail_check(struct context *, const char *, const size_t,
78945147a9marcel    const char *, va_list);
79045147a9marcelstatic void _atf_tc_fail_requirement(struct context *, const char *,
79145147a9marcel    const size_t, const char *, va_list) ATF_DEFS_ATTRIBUTE_NORETURN;
79245147a9marcelstatic void _atf_tc_pass(struct context *) ATF_DEFS_ATTRIBUTE_NORETURN;
79345147a9marcelstatic void _atf_tc_require_prog(struct context *, const char *);
79445147a9marcelstatic void _atf_tc_skip(struct context *, const char *, va_list)
79545147a9marcel    ATF_DEFS_ATTRIBUTE_NORETURN;
79645147a9marcelstatic void _atf_tc_check_errno(struct context *, const char *, const size_t,
79745147a9marcel    const int, const char *, const bool);
79845147a9marcelstatic void _atf_tc_require_errno(struct context *, const char *, const size_t,
79945147a9marcel    const int, const char *, const bool);
80045147a9marcelstatic void _atf_tc_expect_pass(struct context *);
80145147a9marcelstatic void _atf_tc_expect_fail(struct context *, const char *, va_list);
80245147a9marcelstatic void _atf_tc_expect_exit(struct context *, const int, const char *,
80345147a9marcel    va_list);
80445147a9marcelstatic void _atf_tc_expect_signal(struct context *, const int, const char *,
80545147a9marcel    va_list);
80645147a9marcelstatic void _atf_tc_expect_death(struct context *, const char *,
80745147a9marcel    va_list);
80845147a9marcel
80945147a9marcelstatic void
81045147a9marcel_atf_tc_fail(struct context *ctx, const char *fmt, va_list ap)
81145147a9marcel{
81245147a9marcel    va_list ap2;
81345147a9marcel    atf_dynstr_t reason;
81445147a9marcel
81545147a9marcel    va_copy(ap2, ap);
81645147a9marcel    format_reason_ap(&reason, NULL, 0, fmt, ap2);
81745147a9marcel    va_end(ap2);
81845147a9marcel
81945147a9marcel    fail_requirement(ctx, &reason);
82045147a9marcel    UNREACHABLE;
82145147a9marcel}
82245147a9marcel
82345147a9marcelstatic void
82445147a9marcel_atf_tc_fail_nonfatal(struct context *ctx, const char *fmt, va_list ap)
82545147a9marcel{
82645147a9marcel    va_list ap2;
82745147a9marcel    atf_dynstr_t reason;
82845147a9marcel
82945147a9marcel    va_copy(ap2, ap);
83045147a9marcel    format_reason_ap(&reason, NULL, 0, fmt, ap2);
83145147a9marcel    va_end(ap2);
83245147a9marcel
83345147a9marcel    fail_check(ctx, &reason);
83445147a9marcel}
83545147a9marcel
83645147a9marcelstatic void
83745147a9marcel_atf_tc_fail_check(struct context *ctx, const char *file, const size_t line,
83845147a9marcel                   const char *fmt, va_list ap)
83945147a9marcel{
84045147a9marcel    va_list ap2;
84145147a9marcel    atf_dynstr_t reason;
84245147a9marcel
84345147a9marcel    va_copy(ap2, ap);
84445147a9marcel    format_reason_ap(&reason, file, line, fmt, ap2);
84545147a9marcel    va_end(ap2);
84645147a9marcel
84745147a9marcel    fail_check(ctx, &reason);
84845147a9marcel}
84945147a9marcel
85045147a9marcelstatic void
85145147a9marcel_atf_tc_fail_requirement(struct context *ctx, const char *file,
85245147a9marcel                         const size_t line, const char *fmt, va_list ap)
85345147a9marcel{
85445147a9marcel    va_list ap2;
85545147a9marcel    atf_dynstr_t reason;
85645147a9marcel
85745147a9marcel    va_copy(ap2, ap);
85845147a9marcel    format_reason_ap(&reason, file, line, fmt, ap2);
85945147a9marcel    va_end(ap2);
86045147a9marcel
86145147a9marcel    fail_requirement(ctx, &reason);
86245147a9marcel    UNREACHABLE;
86345147a9marcel}
86445147a9marcel
86545147a9marcelstatic void
86645147a9marcel_atf_tc_pass(struct context *ctx)
86745147a9marcel{
86845147a9marcel    pass(ctx);
86945147a9marcel    UNREACHABLE;
87045147a9marcel}
87145147a9marcel
87245147a9marcelstatic void
87345147a9marcel_atf_tc_require_prog(struct context *ctx, const char *prog)
87445147a9marcel{
87545147a9marcel    check_fatal_error(check_prog(ctx, prog));
87645147a9marcel}
87745147a9marcel
87845147a9marcelstatic void
87945147a9marcel_atf_tc_skip(struct context *ctx, const char *fmt, va_list ap)
88045147a9marcel{
88145147a9marcel    atf_dynstr_t reason;
88245147a9marcel    va_list ap2;
88345147a9marcel
88445147a9marcel    va_copy(ap2, ap);
88545147a9marcel    format_reason_ap(&reason, NULL, 0, fmt, ap2);
88645147a9marcel    va_end(ap2);
88745147a9marcel
88845147a9marcel    skip(ctx, &reason);
88945147a9marcel}
89045147a9marcel
89145147a9marcelstatic void
89245147a9marcel_atf_tc_check_errno(struct context *ctx, const char *file, const size_t line,
89345147a9marcel                    const int exp_errno, const char *expr_str,
89445147a9marcel                    const bool expr_result)
89545147a9marcel{
89645147a9marcel    errno_test(ctx, file, line, exp_errno, expr_str, expr_result, fail_check);
89745147a9marcel}
89845147a9marcel
89945147a9marcelstatic void
90045147a9marcel_atf_tc_require_errno(struct context *ctx, const char *file, const size_t line,
90145147a9marcel                      const int exp_errno, const char *expr_str,
90245147a9marcel                      const bool expr_result)
90345147a9marcel{
90445147a9marcel    errno_test(ctx, file, line, exp_errno, expr_str, expr_result,
90545147a9marcel        fail_requirement);
90645147a9marcel}
90745147a9marcel
90845147a9marcelstatic void
90945147a9marcel_atf_tc_expect_pass(struct context *ctx)
91045147a9marcel{
91145147a9marcel    validate_expect(ctx);
91245147a9marcel
91345147a9marcel    ctx->expect = EXPECT_PASS;
91445147a9marcel}
91545147a9marcel
91645147a9marcelstatic void
91745147a9marcel_atf_tc_expect_fail(struct context *ctx, const char *reason, va_list ap)
91845147a9marcel{
91945147a9marcel    va_list ap2;
92045147a9marcel
92145147a9marcel    validate_expect(ctx);
92245147a9marcel
92345147a9marcel    ctx->expect = EXPECT_FAIL;
92445147a9marcel    atf_dynstr_fini(&ctx->expect_reason);
92545147a9marcel    va_copy(ap2, ap);
92645147a9marcel    check_fatal_error(atf_dynstr_init_ap(&ctx->expect_reason, reason, ap2));
92745147a9marcel    va_end(ap2);
92845147a9marcel    ctx->expect_previous_fail_count = ctx->expect_fail_count;
92945147a9marcel}
93045147a9marcel
93145147a9marcelstatic void
93245147a9marcel_atf_tc_expect_exit(struct context *ctx, const int exitcode, const char *reason,
93345147a9marcel                    va_list ap)
93445147a9marcel{
93545147a9marcel    va_list ap2;
93645147a9marcel    atf_dynstr_t formatted;
93745147a9marcel
93845147a9marcel    validate_expect(ctx);
93945147a9marcel
94045147a9marcel    ctx->expect = EXPECT_EXIT;
94145147a9marcel    va_copy(ap2, ap);
94245147a9marcel    check_fatal_error(atf_dynstr_init_ap(&formatted, reason, ap2));
94345147a9marcel    va_end(ap2);
94445147a9marcel
94545147a9marcel    create_resfile(ctx->resfile, "expected_exit", exitcode, &formatted);
94645147a9marcel}
94745147a9marcel
94845147a9marcelstatic void
94945147a9marcel_atf_tc_expect_signal(struct context *ctx, const int signo, const char *reason,
95045147a9marcel                      va_list ap)
95145147a9marcel{
95245147a9marcel    va_list ap2;
95345147a9marcel    atf_dynstr_t formatted;
95445147a9marcel
95545147a9marcel    validate_expect(ctx);
95645147a9marcel
95745147a9marcel    ctx->expect = EXPECT_SIGNAL;
95845147a9marcel    va_copy(ap2, ap);
95945147a9marcel    check_fatal_error(atf_dynstr_init_ap(&formatted, reason, ap2));
96045147a9marcel    va_end(ap2);
96145147a9marcel
96245147a9marcel    create_resfile(ctx->resfile, "expected_signal", signo, &formatted);
96345147a9marcel}
96445147a9marcel
96545147a9marcelstatic void
96645147a9marcel_atf_tc_expect_death(struct context *ctx, const char *reason, va_list ap)
96745147a9marcel{
96845147a9marcel    va_list ap2;
96945147a9marcel    atf_dynstr_t formatted;
97045147a9marcel
97145147a9marcel    validate_expect(ctx);
97245147a9marcel
97345147a9marcel    ctx->expect = EXPECT_DEATH;
97445147a9marcel    va_copy(ap2, ap);
97545147a9marcel    check_fatal_error(atf_dynstr_init_ap(&formatted, reason, ap2));
97645147a9marcel    va_end(ap2);
97745147a9marcel
97845147a9marcel    create_resfile(ctx->resfile, "expected_death", -1, &formatted);
97945147a9marcel}
98045147a9marcel
98145147a9marcelstatic void
98245147a9marcel_atf_tc_expect_timeout(struct context *ctx, const char *reason, va_list ap)
98345147a9marcel{
98445147a9marcel    va_list ap2;
98545147a9marcel    atf_dynstr_t formatted;
98645147a9marcel
98745147a9marcel    validate_expect(ctx);
98845147a9marcel
98945147a9marcel    ctx->expect = EXPECT_TIMEOUT;
99045147a9marcel    va_copy(ap2, ap);
99145147a9marcel    check_fatal_error(atf_dynstr_init_ap(&formatted, reason, ap2));
99245147a9marcel    va_end(ap2);
99345147a9marcel
99445147a9marcel    create_resfile(ctx->resfile, "expected_timeout", -1, &formatted);
99545147a9marcel}
99645147a9marcel
99745147a9marcel/* ---------------------------------------------------------------------
99845147a9marcel * Free functions.
99945147a9marcel * --------------------------------------------------------------------- */
100045147a9marcel
100145147a9marcelstatic struct context Current;
100245147a9marcel
100345147a9marcelatf_error_t
100445147a9marcelatf_tc_run(const atf_tc_t *tc, const char *resfile)
100545147a9marcel{
100645147a9marcel    context_init(&Current, tc, resfile);
100745147a9marcel
100845147a9marcel    tc->pimpl->m_body(tc);
100945147a9marcel
101045147a9marcel    validate_expect(&Current);
101145147a9marcel
101245147a9marcel    if (Current.fail_count > 0) {
101345147a9marcel        atf_dynstr_t reason;
101445147a9marcel
101545147a9marcel        format_reason_fmt(&reason, NULL, 0, "%d checks failed; see output for "
101645147a9marcel            "more details", Current.fail_count);
101745147a9marcel        fail_requirement(&Current, &reason);
101845147a9marcel    } else if (Current.expect_fail_count > 0) {
101945147a9marcel        atf_dynstr_t reason;
102045147a9marcel
102145147a9marcel        format_reason_fmt(&reason, NULL, 0, "%d checks failed as expected; "
102245147a9marcel            "see output for more details", Current.expect_fail_count);
102345147a9marcel        expected_failure(&Current, &reason);
102445147a9marcel    } else {
102545147a9marcel        pass(&Current);
102645147a9marcel    }
102745147a9marcel    UNREACHABLE;
102845147a9marcel    return atf_no_error();
102945147a9marcel}
103045147a9marcel
103145147a9marcelatf_error_t
103245147a9marcelatf_tc_cleanup(const atf_tc_t *tc)
103345147a9marcel{
103445147a9marcel    if (tc->pimpl->m_cleanup != NULL)
103545147a9marcel        tc->pimpl->m_cleanup(tc);
103645147a9marcel    return atf_no_error(); /* XXX */
103745147a9marcel}
103845147a9marcel
103945147a9marcel/* ---------------------------------------------------------------------
104045147a9marcel * Free functions that depend on Current.
104145147a9marcel * --------------------------------------------------------------------- */
104245147a9marcel
104345147a9marcel/*
104445147a9marcel * All the functions below provide delegates to other internal functions
104545147a9marcel * (prefixed by _) that take the current test case as an argument to
104645147a9marcel * prevent them from accessing global state.  This is to keep the side-
104745147a9marcel * effects of the internal functions clearer and easier to understand.
104845147a9marcel *
104945147a9marcel * The public API should never have hid the fact that it needs access to
105045147a9marcel * the current test case (other than maybe in the macros), but changing it
105145147a9marcel * is hard.  TODO: Revisit in the future.
105245147a9marcel */
105345147a9marcel
105445147a9marcelvoid
105545147a9marcelatf_tc_fail(const char *fmt, ...)
105645147a9marcel{
105745147a9marcel    va_list ap;
105845147a9marcel
105945147a9marcel    PRE(Current.tc != NULL);
106045147a9marcel
106145147a9marcel    va_start(ap, fmt);
106245147a9marcel    _atf_tc_fail(&Current, fmt, ap);
106345147a9marcel    va_end(ap);
106445147a9marcel}
106545147a9marcel
106645147a9marcelvoid
106745147a9marcelatf_tc_fail_nonfatal(const char *fmt, ...)
106845147a9marcel{
106945147a9marcel    va_list ap;
107045147a9marcel
107145147a9marcel    PRE(Current.tc != NULL);
107245147a9marcel
107345147a9marcel    va_start(ap, fmt);
107445147a9marcel    _atf_tc_fail_nonfatal(&Current, fmt, ap);
107545147a9marcel    va_end(ap);
107645147a9marcel}
107745147a9marcel
107845147a9marcelvoid
107945147a9marcelatf_tc_fail_check(const char *file, const size_t line, const char *fmt, ...)
108045147a9marcel{
108145147a9marcel    va_list ap;
108245147a9marcel
108345147a9marcel    PRE(Current.tc != NULL);
108445147a9marcel
108545147a9marcel    va_start(ap, fmt);
108645147a9marcel    _atf_tc_fail_check(&Current, file, line, fmt, ap);
108745147a9marcel    va_end(ap);
108845147a9marcel}
108945147a9marcel
109045147a9marcelvoid
109145147a9marcelatf_tc_fail_requirement(const char *file, const size_t line,
109245147a9marcel                        const char *fmt, ...)
109345147a9marcel{
109445147a9marcel    va_list ap;
109545147a9marcel
109645147a9marcel    PRE(Current.tc != NULL);
109745147a9marcel
109845147a9marcel    va_start(ap, fmt);
109945147a9marcel    _atf_tc_fail_requirement(&Current, file, line, fmt, ap);
110045147a9marcel    va_end(ap);
110145147a9marcel}
110245147a9marcel
110345147a9marcelvoid
110445147a9marcelatf_tc_pass(void)
110545147a9marcel{
110645147a9marcel    PRE(Current.tc != NULL);
110745147a9marcel
110845147a9marcel    _atf_tc_pass(&Current);
110945147a9marcel}
111045147a9marcel
111145147a9marcelvoid
111245147a9marcelatf_tc_require_prog(const char *prog)
111345147a9marcel{
111445147a9marcel    PRE(Current.tc != NULL);
111545147a9marcel
111645147a9marcel    _atf_tc_require_prog(&Current, prog);
111745147a9marcel}
111845147a9marcel
111945147a9marcelvoid
112045147a9marcelatf_tc_skip(const char *fmt, ...)
112145147a9marcel{
112245147a9marcel    va_list ap;
112345147a9marcel
112445147a9marcel    PRE(Current.tc != NULL);
112545147a9marcel
112645147a9marcel    va_start(ap, fmt);
112745147a9marcel    _atf_tc_skip(&Current, fmt, ap);
112845147a9marcel    va_end(ap);
112945147a9marcel}
113045147a9marcel
113145147a9marcelvoid
113245147a9marcelatf_tc_check_errno(const char *file, const size_t line, const int exp_errno,
113345147a9marcel                   const char *expr_str, const bool expr_result)
113445147a9marcel{
113545147a9marcel    PRE(Current.tc != NULL);
113645147a9marcel
113745147a9marcel    _atf_tc_check_errno(&Current, file, line, exp_errno, expr_str,
113845147a9marcel                        expr_result);
113945147a9marcel}
114045147a9marcel
114145147a9marcelvoid
114245147a9marcelatf_tc_require_errno(const char *file, const size_t line, const int exp_errno,
114345147a9marcel                     const char *expr_str, const bool expr_result)
114445147a9marcel{
114545147a9marcel    PRE(Current.tc != NULL);
114645147a9marcel
114745147a9marcel    _atf_tc_require_errno(&Current, file, line, exp_errno, expr_str,
114845147a9marcel                          expr_result);
114945147a9marcel}
115045147a9marcel
115145147a9marcelvoid
115245147a9marcelatf_tc_expect_pass(void)
115345147a9marcel{
115445147a9marcel    PRE(Current.tc != NULL);
115545147a9marcel
115645147a9marcel    _atf_tc_expect_pass(&Current);
115745147a9marcel}
115845147a9marcel
115945147a9marcelvoid
116045147a9marcelatf_tc_expect_fail(const char *reason, ...)
116145147a9marcel{
116245147a9marcel    va_list ap;
116345147a9marcel
116445147a9marcel    PRE(Current.tc != NULL);
116545147a9marcel
116645147a9marcel    va_start(ap, reason);
116745147a9marcel    _atf_tc_expect_fail(&Current, reason, ap);
116845147a9marcel    va_end(ap);
116945147a9marcel}
117045147a9marcel
117145147a9marcelvoid
117245147a9marcelatf_tc_expect_exit(const int exitcode, const char *reason, ...)
117345147a9marcel{
117445147a9marcel    va_list ap;
117545147a9marcel
117645147a9marcel    PRE(Current.tc != NULL);
117745147a9marcel
117845147a9marcel    va_start(ap, reason);
117945147a9marcel    _atf_tc_expect_exit(&Current, exitcode, reason, ap);
118045147a9marcel    va_end(ap);
118145147a9marcel}
118245147a9marcel
118345147a9marcelvoid
118445147a9marcelatf_tc_expect_signal(const int signo, const char *reason, ...)
118545147a9marcel{
118645147a9marcel    va_list ap;
118745147a9marcel
118845147a9marcel    PRE(Current.tc != NULL);
118945147a9marcel
119045147a9marcel    va_start(ap, reason);
119145147a9marcel    _atf_tc_expect_signal(&Current, signo, reason, ap);
119245147a9marcel    va_end(ap);
119345147a9marcel}
119445147a9marcel
119545147a9marcelvoid
119645147a9marcelatf_tc_expect_death(const char *reason, ...)
119745147a9marcel{
119845147a9marcel    va_list ap;
119945147a9marcel
120045147a9marcel    PRE(Current.tc != NULL);
120145147a9marcel
120245147a9marcel    va_start(ap, reason);
120345147a9marcel    _atf_tc_expect_death(&Current, reason, ap);
120445147a9marcel    va_end(ap);
120545147a9marcel}
120645147a9marcel
120745147a9marcelvoid
120845147a9marcelatf_tc_expect_timeout(const char *reason, ...)
120945147a9marcel{
121045147a9marcel    va_list ap;
121145147a9marcel
121245147a9marcel    PRE(Current.tc != NULL);
121345147a9marcel
121445147a9marcel    va_start(ap, reason);
121545147a9marcel    _atf_tc_expect_timeout(&Current, reason, ap);
121645147a9marcel    va_end(ap);
121745147a9marcel}
1218