1275988Sngie/* Copyright (c) 2008 The NetBSD Foundation, Inc.
2240116Smarcel * All rights reserved.
3240116Smarcel *
4240116Smarcel * Redistribution and use in source and binary forms, with or without
5240116Smarcel * modification, are permitted provided that the following conditions
6240116Smarcel * are met:
7240116Smarcel * 1. Redistributions of source code must retain the above copyright
8240116Smarcel *    notice, this list of conditions and the following disclaimer.
9240116Smarcel * 2. Redistributions in binary form must reproduce the above copyright
10240116Smarcel *    notice, this list of conditions and the following disclaimer in the
11240116Smarcel *    documentation and/or other materials provided with the distribution.
12240116Smarcel *
13240116Smarcel * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
14240116Smarcel * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
15240116Smarcel * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16240116Smarcel * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17240116Smarcel * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
18240116Smarcel * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19240116Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
20240116Smarcel * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21240116Smarcel * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
22240116Smarcel * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23240116Smarcel * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
24275988Sngie * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  */
25240116Smarcel
26275988Sngie#include "atf-c/tc.h"
27275988Sngie
28240116Smarcel#include <sys/types.h>
29240116Smarcel#include <sys/stat.h>
30240116Smarcel#include <sys/uio.h>
31240116Smarcel
32240116Smarcel#include <errno.h>
33240116Smarcel#include <fcntl.h>
34240116Smarcel#include <stdarg.h>
35240116Smarcel#include <stdbool.h>
36240116Smarcel#include <stdio.h>
37240116Smarcel#include <stdlib.h>
38240116Smarcel#include <string.h>
39240116Smarcel#include <unistd.h>
40240116Smarcel
41240116Smarcel#include "atf-c/defs.h"
42275988Sngie#include "atf-c/detail/env.h"
43275988Sngie#include "atf-c/detail/fs.h"
44275988Sngie#include "atf-c/detail/map.h"
45275988Sngie#include "atf-c/detail/sanity.h"
46275988Sngie#include "atf-c/detail/text.h"
47240116Smarcel#include "atf-c/error.h"
48240116Smarcel
49240116Smarcel/* ---------------------------------------------------------------------
50240116Smarcel * Auxiliary functions.
51240116Smarcel * --------------------------------------------------------------------- */
52240116Smarcel
53240116Smarcelenum expect_type {
54240116Smarcel    EXPECT_PASS,
55240116Smarcel    EXPECT_FAIL,
56240116Smarcel    EXPECT_EXIT,
57240116Smarcel    EXPECT_SIGNAL,
58240116Smarcel    EXPECT_DEATH,
59240116Smarcel    EXPECT_TIMEOUT,
60240116Smarcel};
61240116Smarcel
62240116Smarcelstruct context {
63240116Smarcel    const atf_tc_t *tc;
64240116Smarcel    const char *resfile;
65240116Smarcel    size_t fail_count;
66240116Smarcel
67240116Smarcel    enum expect_type expect;
68240116Smarcel    atf_dynstr_t expect_reason;
69240116Smarcel    size_t expect_previous_fail_count;
70240116Smarcel    size_t expect_fail_count;
71240116Smarcel    int expect_exitcode;
72240116Smarcel    int expect_signo;
73240116Smarcel};
74240116Smarcel
75240116Smarcelstatic void context_init(struct context *, const atf_tc_t *, const char *);
76240116Smarcelstatic void check_fatal_error(atf_error_t);
77240116Smarcelstatic void report_fatal_error(const char *, ...)
78240116Smarcel    ATF_DEFS_ATTRIBUTE_NORETURN;
79240116Smarcelstatic atf_error_t write_resfile(const int, const char *, const int,
80240116Smarcel                                 const atf_dynstr_t *);
81240116Smarcelstatic void create_resfile(const char *, const char *, const int,
82240116Smarcel                           atf_dynstr_t *);
83240116Smarcelstatic void error_in_expect(struct context *, const char *, ...)
84240116Smarcel    ATF_DEFS_ATTRIBUTE_NORETURN;
85240116Smarcelstatic void validate_expect(struct context *);
86240116Smarcelstatic void expected_failure(struct context *, atf_dynstr_t *)
87240116Smarcel    ATF_DEFS_ATTRIBUTE_NORETURN;
88240116Smarcelstatic void fail_requirement(struct context *, atf_dynstr_t *)
89240116Smarcel    ATF_DEFS_ATTRIBUTE_NORETURN;
90240116Smarcelstatic void fail_check(struct context *, atf_dynstr_t *);
91240116Smarcelstatic void pass(struct context *)
92240116Smarcel    ATF_DEFS_ATTRIBUTE_NORETURN;
93240116Smarcelstatic void skip(struct context *, atf_dynstr_t *)
94240116Smarcel    ATF_DEFS_ATTRIBUTE_NORETURN;
95240116Smarcelstatic void format_reason_ap(atf_dynstr_t *, const char *, const size_t,
96240116Smarcel                             const char *, va_list);
97240116Smarcelstatic void format_reason_fmt(atf_dynstr_t *, const char *, const size_t,
98240116Smarcel                              const char *, ...);
99240116Smarcelstatic void errno_test(struct context *, const char *, const size_t,
100240116Smarcel                       const int, const char *, const bool,
101240116Smarcel                       void (*)(struct context *, atf_dynstr_t *));
102240116Smarcelstatic atf_error_t check_prog_in_dir(const char *, void *);
103240116Smarcelstatic atf_error_t check_prog(struct context *, const char *);
104240116Smarcel
105240116Smarcelstatic void
106240116Smarcelcontext_init(struct context *ctx, const atf_tc_t *tc, const char *resfile)
107240116Smarcel{
108240116Smarcel    ctx->tc = tc;
109240116Smarcel    ctx->resfile = resfile;
110240116Smarcel    ctx->fail_count = 0;
111240116Smarcel    ctx->expect = EXPECT_PASS;
112240116Smarcel    check_fatal_error(atf_dynstr_init(&ctx->expect_reason));
113240116Smarcel    ctx->expect_previous_fail_count = 0;
114240116Smarcel    ctx->expect_fail_count = 0;
115240116Smarcel    ctx->expect_exitcode = 0;
116240116Smarcel    ctx->expect_signo = 0;
117240116Smarcel}
118240116Smarcel
119240116Smarcelstatic void
120240116Smarcelcheck_fatal_error(atf_error_t err)
121240116Smarcel{
122240116Smarcel    if (atf_is_error(err)) {
123240116Smarcel        char buf[1024];
124240116Smarcel        atf_error_format(err, buf, sizeof(buf));
125240116Smarcel        fprintf(stderr, "FATAL ERROR: %s\n", buf);
126240116Smarcel        atf_error_free(err);
127240116Smarcel        abort();
128240116Smarcel    }
129240116Smarcel}
130240116Smarcel
131240116Smarcelstatic void
132240116Smarcelreport_fatal_error(const char *msg, ...)
133240116Smarcel{
134240116Smarcel    va_list ap;
135240116Smarcel    fprintf(stderr, "FATAL ERROR: ");
136240116Smarcel
137240116Smarcel    va_start(ap, msg);
138240116Smarcel    vfprintf(stderr, msg, ap);
139240116Smarcel    va_end(ap);
140240116Smarcel
141240116Smarcel    fprintf(stderr, "\n");
142240116Smarcel    abort();
143240116Smarcel}
144240116Smarcel
145240116Smarcel/** Writes to a results file.
146240116Smarcel *
147240116Smarcel * The results file is supposed to be already open.
148240116Smarcel *
149240116Smarcel * This function returns an error code instead of exiting in case of error
150240116Smarcel * because the caller needs to clean up the reason object before terminating.
151240116Smarcel */
152240116Smarcelstatic atf_error_t
153240116Smarcelwrite_resfile(const int fd, const char *result, const int arg,
154240116Smarcel              const atf_dynstr_t *reason)
155240116Smarcel{
156240116Smarcel    static char NL[] = "\n", CS[] = ": ";
157240116Smarcel    char buf[64];
158240116Smarcel    const char *r;
159240116Smarcel    struct iovec iov[5];
160240116Smarcel    ssize_t ret;
161240116Smarcel    int count = 0;
162240116Smarcel
163240116Smarcel    INV(arg == -1 || reason != NULL);
164240116Smarcel
165240116Smarcel#define UNCONST(a) ((void *)(unsigned long)(const void *)(a))
166240116Smarcel    iov[count].iov_base = UNCONST(result);
167240116Smarcel    iov[count++].iov_len = strlen(result);
168240116Smarcel
169240116Smarcel    if (reason != NULL) {
170240116Smarcel        if (arg != -1) {
171240116Smarcel            iov[count].iov_base = buf;
172240116Smarcel            iov[count++].iov_len = snprintf(buf, sizeof(buf), "(%d)", arg);
173240116Smarcel        }
174240116Smarcel
175240116Smarcel        iov[count].iov_base = CS;
176240116Smarcel        iov[count++].iov_len = sizeof(CS) - 1;
177240116Smarcel
178240116Smarcel        r = atf_dynstr_cstring(reason);
179240116Smarcel        iov[count].iov_base = UNCONST(r);
180240116Smarcel        iov[count++].iov_len = strlen(r);
181240116Smarcel    }
182240116Smarcel#undef UNCONST
183240116Smarcel
184240116Smarcel    iov[count].iov_base = NL;
185240116Smarcel    iov[count++].iov_len = sizeof(NL) - 1;
186240116Smarcel
187240116Smarcel    while ((ret = writev(fd, iov, count)) == -1 && errno == EINTR)
188240116Smarcel        continue; /* Retry. */
189240116Smarcel    if (ret != -1)
190240116Smarcel        return atf_no_error();
191240116Smarcel
192240116Smarcel    return atf_libc_error(
193240116Smarcel        errno, "Failed to write results file; result %s, reason %s", result,
194240116Smarcel        reason == NULL ? "null" : atf_dynstr_cstring(reason));
195240116Smarcel}
196240116Smarcel
197240116Smarcel/** Creates a results file.
198240116Smarcel *
199240116Smarcel * The input reason is released in all cases.
200240116Smarcel *
201240116Smarcel * An error in this function is considered to be fatal, hence why it does
202240116Smarcel * not return any error code.
203240116Smarcel */
204240116Smarcelstatic void
205240116Smarcelcreate_resfile(const char *resfile, const char *result, const int arg,
206240116Smarcel               atf_dynstr_t *reason)
207240116Smarcel{
208240116Smarcel    atf_error_t err;
209240116Smarcel
210240116Smarcel    if (strcmp("/dev/stdout", resfile) == 0) {
211240116Smarcel        err = write_resfile(STDOUT_FILENO, result, arg, reason);
212240116Smarcel    } else if (strcmp("/dev/stderr", resfile) == 0) {
213240116Smarcel        err = write_resfile(STDERR_FILENO, result, arg, reason);
214240116Smarcel    } else {
215240116Smarcel        const int fd = open(resfile, O_WRONLY | O_CREAT | O_TRUNC,
216240116Smarcel            S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
217240116Smarcel        if (fd == -1) {
218240116Smarcel            err = atf_libc_error(errno, "Cannot create results file '%s'",
219240116Smarcel                                 resfile);
220240116Smarcel        } else {
221240116Smarcel            err = write_resfile(fd, result, arg, reason);
222240116Smarcel            close(fd);
223240116Smarcel        }
224240116Smarcel    }
225240116Smarcel
226240116Smarcel    if (reason != NULL)
227240116Smarcel        atf_dynstr_fini(reason);
228240116Smarcel
229240116Smarcel    check_fatal_error(err);
230240116Smarcel}
231240116Smarcel
232240116Smarcel/** Fails a test case if validate_expect fails. */
233240116Smarcelstatic void
234240116Smarcelerror_in_expect(struct context *ctx, const char *fmt, ...)
235240116Smarcel{
236240116Smarcel    atf_dynstr_t reason;
237240116Smarcel    va_list ap;
238240116Smarcel
239240116Smarcel    va_start(ap, fmt);
240240116Smarcel    format_reason_ap(&reason, NULL, 0, fmt, ap);
241240116Smarcel    va_end(ap);
242240116Smarcel
243240116Smarcel    ctx->expect = EXPECT_PASS;  /* Ensure fail_requirement really fails. */
244240116Smarcel    fail_requirement(ctx, &reason);
245240116Smarcel}
246240116Smarcel
247240116Smarcel/** Ensures that the "expect" state is correct.
248240116Smarcel *
249240116Smarcel * Call this function before modifying the current value of expect.
250240116Smarcel */
251240116Smarcelstatic void
252240116Smarcelvalidate_expect(struct context *ctx)
253240116Smarcel{
254240116Smarcel    if (ctx->expect == EXPECT_DEATH) {
255240116Smarcel        error_in_expect(ctx, "Test case was expected to terminate abruptly "
256240116Smarcel            "but it continued execution");
257240116Smarcel    } else if (ctx->expect == EXPECT_EXIT) {
258240116Smarcel        error_in_expect(ctx, "Test case was expected to exit cleanly but it "
259240116Smarcel            "continued execution");
260240116Smarcel    } else if (ctx->expect == EXPECT_FAIL) {
261240116Smarcel        if (ctx->expect_fail_count == ctx->expect_previous_fail_count)
262240116Smarcel            error_in_expect(ctx, "Test case was expecting a failure but none "
263240116Smarcel                "were raised");
264240116Smarcel        else
265240116Smarcel            INV(ctx->expect_fail_count > ctx->expect_previous_fail_count);
266240116Smarcel    } else if (ctx->expect == EXPECT_PASS) {
267240116Smarcel        /* Nothing to validate. */
268240116Smarcel    } else if (ctx->expect == EXPECT_SIGNAL) {
269240116Smarcel        error_in_expect(ctx, "Test case was expected to receive a termination "
270240116Smarcel            "signal but it continued execution");
271240116Smarcel    } else if (ctx->expect == EXPECT_TIMEOUT) {
272240116Smarcel        error_in_expect(ctx, "Test case was expected to hang but it continued "
273240116Smarcel            "execution");
274240116Smarcel    } else
275240116Smarcel        UNREACHABLE;
276240116Smarcel}
277240116Smarcel
278240116Smarcelstatic void
279240116Smarcelexpected_failure(struct context *ctx, atf_dynstr_t *reason)
280240116Smarcel{
281240116Smarcel    check_fatal_error(atf_dynstr_prepend_fmt(reason, "%s: ",
282240116Smarcel        atf_dynstr_cstring(&ctx->expect_reason)));
283240116Smarcel    create_resfile(ctx->resfile, "expected_failure", -1, reason);
284240116Smarcel    exit(EXIT_SUCCESS);
285240116Smarcel}
286240116Smarcel
287240116Smarcelstatic void
288240116Smarcelfail_requirement(struct context *ctx, atf_dynstr_t *reason)
289240116Smarcel{
290240116Smarcel    if (ctx->expect == EXPECT_FAIL) {
291240116Smarcel        expected_failure(ctx, reason);
292240116Smarcel    } else if (ctx->expect == EXPECT_PASS) {
293240116Smarcel        create_resfile(ctx->resfile, "failed", -1, reason);
294240116Smarcel        exit(EXIT_FAILURE);
295240116Smarcel    } else {
296240116Smarcel        error_in_expect(ctx, "Test case raised a failure but was not "
297240116Smarcel            "expecting one; reason was %s", atf_dynstr_cstring(reason));
298240116Smarcel    }
299240116Smarcel    UNREACHABLE;
300240116Smarcel}
301240116Smarcel
302240116Smarcelstatic void
303240116Smarcelfail_check(struct context *ctx, atf_dynstr_t *reason)
304240116Smarcel{
305240116Smarcel    if (ctx->expect == EXPECT_FAIL) {
306240116Smarcel        fprintf(stderr, "*** Expected check failure: %s: %s\n",
307240116Smarcel            atf_dynstr_cstring(&ctx->expect_reason),
308240116Smarcel            atf_dynstr_cstring(reason));
309240116Smarcel        ctx->expect_fail_count++;
310240116Smarcel    } else if (ctx->expect == EXPECT_PASS) {
311240116Smarcel        fprintf(stderr, "*** Check failed: %s\n", atf_dynstr_cstring(reason));
312240116Smarcel        ctx->fail_count++;
313240116Smarcel    } else {
314240116Smarcel        error_in_expect(ctx, "Test case raised a failure but was not "
315240116Smarcel            "expecting one; reason was %s", atf_dynstr_cstring(reason));
316240116Smarcel    }
317240116Smarcel
318240116Smarcel    atf_dynstr_fini(reason);
319240116Smarcel}
320240116Smarcel
321240116Smarcelstatic void
322240116Smarcelpass(struct context *ctx)
323240116Smarcel{
324240116Smarcel    if (ctx->expect == EXPECT_FAIL) {
325240116Smarcel        error_in_expect(ctx, "Test case was expecting a failure but got "
326240116Smarcel            "a pass instead");
327240116Smarcel    } else if (ctx->expect == EXPECT_PASS) {
328240116Smarcel        create_resfile(ctx->resfile, "passed", -1, NULL);
329240116Smarcel        exit(EXIT_SUCCESS);
330240116Smarcel    } else {
331240116Smarcel        error_in_expect(ctx, "Test case asked to explicitly pass but was "
332240116Smarcel            "not expecting such condition");
333240116Smarcel    }
334240116Smarcel    UNREACHABLE;
335240116Smarcel}
336240116Smarcel
337240116Smarcelstatic void
338240116Smarcelskip(struct context *ctx, atf_dynstr_t *reason)
339240116Smarcel{
340240116Smarcel    if (ctx->expect == EXPECT_PASS) {
341240116Smarcel        create_resfile(ctx->resfile, "skipped", -1, reason);
342240116Smarcel        exit(EXIT_SUCCESS);
343240116Smarcel    } else {
344240116Smarcel        error_in_expect(ctx, "Can only skip a test case when running in "
345240116Smarcel            "expect pass mode");
346240116Smarcel    }
347240116Smarcel    UNREACHABLE;
348240116Smarcel}
349240116Smarcel
350240116Smarcel/** Formats a failure/skip reason message.
351240116Smarcel *
352240116Smarcel * The formatted reason is stored in out_reason.  out_reason is initialized
353240116Smarcel * in this function and is supposed to be released by the caller.  In general,
354240116Smarcel * the reason will eventually be fed to create_resfile, which will release
355240116Smarcel * it.
356240116Smarcel *
357240116Smarcel * Errors in this function are fatal.  Rationale being: reasons are used to
358240116Smarcel * create results files; if we can't format the reason correctly, the result
359240116Smarcel * of the test program will be bogus.  So it's better to just exit with a
360240116Smarcel * fatal error.
361240116Smarcel */
362240116Smarcelstatic void
363240116Smarcelformat_reason_ap(atf_dynstr_t *out_reason,
364240116Smarcel                 const char *source_file, const size_t source_line,
365240116Smarcel                 const char *reason, va_list ap)
366240116Smarcel{
367240116Smarcel    atf_error_t err;
368240116Smarcel
369240116Smarcel    if (source_file != NULL) {
370240116Smarcel        err = atf_dynstr_init_fmt(out_reason, "%s:%zd: ", source_file,
371240116Smarcel                                  source_line);
372240116Smarcel    } else {
373240116Smarcel        PRE(source_line == 0);
374240116Smarcel        err = atf_dynstr_init(out_reason);
375240116Smarcel    }
376240116Smarcel
377240116Smarcel    if (!atf_is_error(err)) {
378240116Smarcel        va_list ap2;
379240116Smarcel        va_copy(ap2, ap);
380240116Smarcel        err = atf_dynstr_append_ap(out_reason, reason, ap2);
381240116Smarcel        va_end(ap2);
382240116Smarcel    }
383240116Smarcel
384240116Smarcel    check_fatal_error(err);
385240116Smarcel}
386240116Smarcel
387240116Smarcelstatic void
388240116Smarcelformat_reason_fmt(atf_dynstr_t *out_reason,
389240116Smarcel                  const char *source_file, const size_t source_line,
390240116Smarcel                  const char *reason, ...)
391240116Smarcel{
392240116Smarcel    va_list ap;
393240116Smarcel
394240116Smarcel    va_start(ap, reason);
395240116Smarcel    format_reason_ap(out_reason, source_file, source_line, reason, ap);
396240116Smarcel    va_end(ap);
397240116Smarcel}
398240116Smarcel
399240116Smarcelstatic void
400240116Smarcelerrno_test(struct context *ctx, const char *file, const size_t line,
401240116Smarcel           const int exp_errno, const char *expr_str,
402240116Smarcel           const bool expr_result,
403240116Smarcel           void (*fail_func)(struct context *, atf_dynstr_t *))
404240116Smarcel{
405240116Smarcel    const int actual_errno = errno;
406240116Smarcel
407240116Smarcel    if (expr_result) {
408240116Smarcel        if (exp_errno != actual_errno) {
409240116Smarcel            atf_dynstr_t reason;
410240116Smarcel
411240116Smarcel            format_reason_fmt(&reason, file, line, "Expected errno %d, got %d, "
412240116Smarcel                "in %s", exp_errno, actual_errno, expr_str);
413240116Smarcel            fail_func(ctx, &reason);
414240116Smarcel        }
415240116Smarcel    } else {
416240116Smarcel        atf_dynstr_t reason;
417240116Smarcel
418240116Smarcel        format_reason_fmt(&reason, file, line, "Expected true value in %s",
419240116Smarcel            expr_str);
420240116Smarcel        fail_func(ctx, &reason);
421240116Smarcel    }
422240116Smarcel}
423240116Smarcel
424240116Smarcelstruct prog_found_pair {
425240116Smarcel    const char *prog;
426240116Smarcel    bool found;
427240116Smarcel};
428240116Smarcel
429240116Smarcelstatic atf_error_t
430240116Smarcelcheck_prog_in_dir(const char *dir, void *data)
431240116Smarcel{
432240116Smarcel    struct prog_found_pair *pf = data;
433240116Smarcel    atf_error_t err;
434240116Smarcel
435240116Smarcel    if (pf->found)
436240116Smarcel        err = atf_no_error();
437240116Smarcel    else {
438240116Smarcel        atf_fs_path_t p;
439240116Smarcel
440240116Smarcel        err = atf_fs_path_init_fmt(&p, "%s/%s", dir, pf->prog);
441240116Smarcel        if (atf_is_error(err))
442240116Smarcel            goto out_p;
443240116Smarcel
444240116Smarcel        err = atf_fs_eaccess(&p, atf_fs_access_x);
445240116Smarcel        if (!atf_is_error(err))
446240116Smarcel            pf->found = true;
447240116Smarcel        else {
448240116Smarcel            atf_error_free(err);
449240116Smarcel            INV(!pf->found);
450240116Smarcel            err = atf_no_error();
451240116Smarcel        }
452240116Smarcel
453240116Smarcelout_p:
454240116Smarcel        atf_fs_path_fini(&p);
455240116Smarcel    }
456240116Smarcel
457240116Smarcel    return err;
458240116Smarcel}
459240116Smarcel
460240116Smarcelstatic atf_error_t
461240116Smarcelcheck_prog(struct context *ctx, const char *prog)
462240116Smarcel{
463240116Smarcel    atf_error_t err;
464240116Smarcel    atf_fs_path_t p;
465240116Smarcel
466240116Smarcel    err = atf_fs_path_init_fmt(&p, "%s", prog);
467240116Smarcel    if (atf_is_error(err))
468240116Smarcel        goto out;
469240116Smarcel
470240116Smarcel    if (atf_fs_path_is_absolute(&p)) {
471240116Smarcel        err = atf_fs_eaccess(&p, atf_fs_access_x);
472240116Smarcel        if (atf_is_error(err)) {
473240116Smarcel            atf_dynstr_t reason;
474240116Smarcel
475240116Smarcel            atf_error_free(err);
476240116Smarcel            atf_fs_path_fini(&p);
477240116Smarcel            format_reason_fmt(&reason, NULL, 0, "The required program %s could "
478240116Smarcel                "not be found", prog);
479240116Smarcel            skip(ctx, &reason);
480240116Smarcel        }
481240116Smarcel    } else {
482240116Smarcel        const char *path = atf_env_get("PATH");
483240116Smarcel        struct prog_found_pair pf;
484240116Smarcel        atf_fs_path_t bp;
485240116Smarcel
486240116Smarcel        err = atf_fs_path_branch_path(&p, &bp);
487240116Smarcel        if (atf_is_error(err))
488240116Smarcel            goto out_p;
489240116Smarcel
490240116Smarcel        if (strcmp(atf_fs_path_cstring(&bp), ".") != 0) {
491240116Smarcel            atf_fs_path_fini(&bp);
492240116Smarcel            atf_fs_path_fini(&p);
493240116Smarcel
494240116Smarcel            report_fatal_error("Relative paths are not allowed when searching "
495240116Smarcel                "for a program (%s)", prog);
496240116Smarcel            UNREACHABLE;
497240116Smarcel        }
498240116Smarcel
499240116Smarcel        pf.prog = prog;
500240116Smarcel        pf.found = false;
501240116Smarcel        err = atf_text_for_each_word(path, ":", check_prog_in_dir, &pf);
502240116Smarcel        if (atf_is_error(err))
503240116Smarcel            goto out_bp;
504240116Smarcel
505240116Smarcel        if (!pf.found) {
506240116Smarcel            atf_dynstr_t reason;
507240116Smarcel
508240116Smarcel            atf_fs_path_fini(&bp);
509240116Smarcel            atf_fs_path_fini(&p);
510240116Smarcel            format_reason_fmt(&reason, NULL, 0, "The required program %s could "
511240116Smarcel                "not be found in the PATH", prog);
512240116Smarcel            fail_requirement(ctx, &reason);
513240116Smarcel        }
514240116Smarcel
515240116Smarcelout_bp:
516240116Smarcel        atf_fs_path_fini(&bp);
517240116Smarcel    }
518240116Smarcel
519240116Smarcelout_p:
520240116Smarcel    atf_fs_path_fini(&p);
521240116Smarcelout:
522240116Smarcel    return err;
523240116Smarcel}
524240116Smarcel
525240116Smarcel/* ---------------------------------------------------------------------
526240116Smarcel * The "atf_tc" type.
527240116Smarcel * --------------------------------------------------------------------- */
528240116Smarcel
529240116Smarcelstruct atf_tc_impl {
530240116Smarcel    const char *m_ident;
531240116Smarcel
532240116Smarcel    atf_map_t m_vars;
533240116Smarcel    atf_map_t m_config;
534240116Smarcel
535240116Smarcel    atf_tc_head_t m_head;
536240116Smarcel    atf_tc_body_t m_body;
537240116Smarcel    atf_tc_cleanup_t m_cleanup;
538240116Smarcel};
539240116Smarcel
540240116Smarcel/*
541240116Smarcel * Constructors/destructors.
542240116Smarcel */
543240116Smarcel
544240116Smarcelatf_error_t
545240116Smarcelatf_tc_init(atf_tc_t *tc, const char *ident, atf_tc_head_t head,
546240116Smarcel            atf_tc_body_t body, atf_tc_cleanup_t cleanup,
547240116Smarcel            const char *const *config)
548240116Smarcel{
549240116Smarcel    atf_error_t err;
550240116Smarcel
551240116Smarcel    tc->pimpl = malloc(sizeof(struct atf_tc_impl));
552240116Smarcel    if (tc->pimpl == NULL) {
553240116Smarcel        err = atf_no_memory_error();
554240116Smarcel        goto err;
555240116Smarcel    }
556240116Smarcel
557240116Smarcel    tc->pimpl->m_ident = ident;
558240116Smarcel    tc->pimpl->m_head = head;
559240116Smarcel    tc->pimpl->m_body = body;
560240116Smarcel    tc->pimpl->m_cleanup = cleanup;
561240116Smarcel
562240116Smarcel    err = atf_map_init_charpp(&tc->pimpl->m_config, config);
563240116Smarcel    if (atf_is_error(err))
564240116Smarcel        goto err;
565240116Smarcel
566240116Smarcel    err = atf_map_init(&tc->pimpl->m_vars);
567240116Smarcel    if (atf_is_error(err))
568240116Smarcel        goto err_vars;
569240116Smarcel
570240116Smarcel    err = atf_tc_set_md_var(tc, "ident", ident);
571240116Smarcel    if (atf_is_error(err))
572240116Smarcel        goto err_map;
573240116Smarcel
574240116Smarcel    if (cleanup != NULL) {
575240116Smarcel        err = atf_tc_set_md_var(tc, "has.cleanup", "true");
576240116Smarcel        if (atf_is_error(err))
577240116Smarcel            goto err_map;
578240116Smarcel    }
579240116Smarcel
580240116Smarcel    /* XXX Should the head be able to return error codes? */
581240116Smarcel    if (tc->pimpl->m_head != NULL)
582240116Smarcel        tc->pimpl->m_head(tc);
583240116Smarcel
584240116Smarcel    if (strcmp(atf_tc_get_md_var(tc, "ident"), ident) != 0) {
585240116Smarcel        report_fatal_error("Test case head modified the read-only 'ident' "
586240116Smarcel            "property");
587240116Smarcel        UNREACHABLE;
588240116Smarcel    }
589240116Smarcel
590240116Smarcel    INV(!atf_is_error(err));
591240116Smarcel    return err;
592240116Smarcel
593240116Smarcelerr_map:
594240116Smarcel    atf_map_fini(&tc->pimpl->m_vars);
595240116Smarcelerr_vars:
596240116Smarcel    atf_map_fini(&tc->pimpl->m_config);
597240116Smarcelerr:
598240116Smarcel    return err;
599240116Smarcel}
600240116Smarcel
601240116Smarcelatf_error_t
602240116Smarcelatf_tc_init_pack(atf_tc_t *tc, const atf_tc_pack_t *pack,
603240116Smarcel                 const char *const *config)
604240116Smarcel{
605240116Smarcel    return atf_tc_init(tc, pack->m_ident, pack->m_head, pack->m_body,
606240116Smarcel                       pack->m_cleanup, config);
607240116Smarcel}
608240116Smarcel
609240116Smarcelvoid
610240116Smarcelatf_tc_fini(atf_tc_t *tc)
611240116Smarcel{
612240116Smarcel    atf_map_fini(&tc->pimpl->m_vars);
613240116Smarcel    free(tc->pimpl);
614240116Smarcel}
615240116Smarcel
616240116Smarcel/*
617240116Smarcel * Getters.
618240116Smarcel */
619240116Smarcel
620240116Smarcelconst char *
621240116Smarcelatf_tc_get_ident(const atf_tc_t *tc)
622240116Smarcel{
623240116Smarcel    return tc->pimpl->m_ident;
624240116Smarcel}
625240116Smarcel
626240116Smarcelconst char *
627240116Smarcelatf_tc_get_config_var(const atf_tc_t *tc, const char *name)
628240116Smarcel{
629240116Smarcel    const char *val;
630240116Smarcel    atf_map_citer_t iter;
631240116Smarcel
632240116Smarcel    PRE(atf_tc_has_config_var(tc, name));
633240116Smarcel    iter = atf_map_find_c(&tc->pimpl->m_config, name);
634240116Smarcel    val = atf_map_citer_data(iter);
635240116Smarcel    INV(val != NULL);
636240116Smarcel
637240116Smarcel    return val;
638240116Smarcel}
639240116Smarcel
640240116Smarcelconst char *
641240116Smarcelatf_tc_get_config_var_wd(const atf_tc_t *tc, const char *name,
642240116Smarcel                         const char *defval)
643240116Smarcel{
644240116Smarcel    const char *val;
645240116Smarcel
646240116Smarcel    if (!atf_tc_has_config_var(tc, name))
647240116Smarcel        val = defval;
648240116Smarcel    else
649240116Smarcel        val = atf_tc_get_config_var(tc, name);
650240116Smarcel
651240116Smarcel    return val;
652240116Smarcel}
653240116Smarcel
654240116Smarcelbool
655240116Smarcelatf_tc_get_config_var_as_bool(const atf_tc_t *tc, const char *name)
656240116Smarcel{
657240116Smarcel    bool val;
658240116Smarcel    const char *strval;
659240116Smarcel    atf_error_t err;
660240116Smarcel
661240116Smarcel    strval = atf_tc_get_config_var(tc, name);
662240116Smarcel    err = atf_text_to_bool(strval, &val);
663240116Smarcel    if (atf_is_error(err)) {
664240116Smarcel        atf_error_free(err);
665240116Smarcel        atf_tc_fail("Configuration variable %s does not have a valid "
666240116Smarcel                    "boolean value; found %s", name, strval);
667240116Smarcel    }
668240116Smarcel
669240116Smarcel    return val;
670240116Smarcel}
671240116Smarcel
672240116Smarcelbool
673240116Smarcelatf_tc_get_config_var_as_bool_wd(const atf_tc_t *tc, const char *name,
674240116Smarcel                                 const bool defval)
675240116Smarcel{
676240116Smarcel    bool val;
677240116Smarcel
678240116Smarcel    if (!atf_tc_has_config_var(tc, name))
679240116Smarcel        val = defval;
680240116Smarcel    else
681240116Smarcel        val = atf_tc_get_config_var_as_bool(tc, name);
682240116Smarcel
683240116Smarcel    return val;
684240116Smarcel}
685240116Smarcel
686240116Smarcellong
687240116Smarcelatf_tc_get_config_var_as_long(const atf_tc_t *tc, const char *name)
688240116Smarcel{
689240116Smarcel    long val;
690240116Smarcel    const char *strval;
691240116Smarcel    atf_error_t err;
692240116Smarcel
693240116Smarcel    strval = atf_tc_get_config_var(tc, name);
694240116Smarcel    err = atf_text_to_long(strval, &val);
695240116Smarcel    if (atf_is_error(err)) {
696240116Smarcel        atf_error_free(err);
697240116Smarcel        atf_tc_fail("Configuration variable %s does not have a valid "
698240116Smarcel                    "long value; found %s", name, strval);
699240116Smarcel    }
700240116Smarcel
701240116Smarcel    return val;
702240116Smarcel}
703240116Smarcel
704240116Smarcellong
705240116Smarcelatf_tc_get_config_var_as_long_wd(const atf_tc_t *tc, const char *name,
706240116Smarcel                                 const long defval)
707240116Smarcel{
708240116Smarcel    long val;
709240116Smarcel
710240116Smarcel    if (!atf_tc_has_config_var(tc, name))
711240116Smarcel        val = defval;
712240116Smarcel    else
713240116Smarcel        val = atf_tc_get_config_var_as_long(tc, name);
714240116Smarcel
715240116Smarcel    return val;
716240116Smarcel}
717240116Smarcel
718240116Smarcelconst char *
719240116Smarcelatf_tc_get_md_var(const atf_tc_t *tc, const char *name)
720240116Smarcel{
721240116Smarcel    const char *val;
722240116Smarcel    atf_map_citer_t iter;
723240116Smarcel
724240116Smarcel    PRE(atf_tc_has_md_var(tc, name));
725240116Smarcel    iter = atf_map_find_c(&tc->pimpl->m_vars, name);
726240116Smarcel    val = atf_map_citer_data(iter);
727240116Smarcel    INV(val != NULL);
728240116Smarcel
729240116Smarcel    return val;
730240116Smarcel}
731240116Smarcel
732240116Smarcelchar **
733240116Smarcelatf_tc_get_md_vars(const atf_tc_t *tc)
734240116Smarcel{
735240116Smarcel    return atf_map_to_charpp(&tc->pimpl->m_vars);
736240116Smarcel}
737240116Smarcel
738240116Smarcelbool
739240116Smarcelatf_tc_has_config_var(const atf_tc_t *tc, const char *name)
740240116Smarcel{
741240116Smarcel    atf_map_citer_t end, iter;
742240116Smarcel
743240116Smarcel    iter = atf_map_find_c(&tc->pimpl->m_config, name);
744240116Smarcel    end = atf_map_end_c(&tc->pimpl->m_config);
745240116Smarcel    return !atf_equal_map_citer_map_citer(iter, end);
746240116Smarcel}
747240116Smarcel
748240116Smarcelbool
749240116Smarcelatf_tc_has_md_var(const atf_tc_t *tc, const char *name)
750240116Smarcel{
751240116Smarcel    atf_map_citer_t end, iter;
752240116Smarcel
753240116Smarcel    iter = atf_map_find_c(&tc->pimpl->m_vars, name);
754240116Smarcel    end = atf_map_end_c(&tc->pimpl->m_vars);
755240116Smarcel    return !atf_equal_map_citer_map_citer(iter, end);
756240116Smarcel}
757240116Smarcel
758240116Smarcel/*
759240116Smarcel * Modifiers.
760240116Smarcel */
761240116Smarcel
762240116Smarcelatf_error_t
763240116Smarcelatf_tc_set_md_var(atf_tc_t *tc, const char *name, const char *fmt, ...)
764240116Smarcel{
765240116Smarcel    atf_error_t err;
766240116Smarcel    char *value;
767240116Smarcel    va_list ap;
768240116Smarcel
769240116Smarcel    va_start(ap, fmt);
770240116Smarcel    err = atf_text_format_ap(&value, fmt, ap);
771240116Smarcel    va_end(ap);
772240116Smarcel
773240116Smarcel    if (!atf_is_error(err))
774240116Smarcel        err = atf_map_insert(&tc->pimpl->m_vars, name, value, true);
775240116Smarcel    else
776240116Smarcel        free(value);
777240116Smarcel
778240116Smarcel    return err;
779240116Smarcel}
780240116Smarcel
781240116Smarcel/* ---------------------------------------------------------------------
782240116Smarcel * Free functions, as they should be publicly but they can't.
783240116Smarcel * --------------------------------------------------------------------- */
784240116Smarcel
785240116Smarcelstatic void _atf_tc_fail(struct context *, const char *, va_list)
786240116Smarcel    ATF_DEFS_ATTRIBUTE_NORETURN;
787240116Smarcelstatic void _atf_tc_fail_nonfatal(struct context *, const char *, va_list);
788240116Smarcelstatic void _atf_tc_fail_check(struct context *, const char *, const size_t,
789240116Smarcel    const char *, va_list);
790240116Smarcelstatic void _atf_tc_fail_requirement(struct context *, const char *,
791240116Smarcel    const size_t, const char *, va_list) ATF_DEFS_ATTRIBUTE_NORETURN;
792240116Smarcelstatic void _atf_tc_pass(struct context *) ATF_DEFS_ATTRIBUTE_NORETURN;
793240116Smarcelstatic void _atf_tc_require_prog(struct context *, const char *);
794240116Smarcelstatic void _atf_tc_skip(struct context *, const char *, va_list)
795240116Smarcel    ATF_DEFS_ATTRIBUTE_NORETURN;
796240116Smarcelstatic void _atf_tc_check_errno(struct context *, const char *, const size_t,
797240116Smarcel    const int, const char *, const bool);
798240116Smarcelstatic void _atf_tc_require_errno(struct context *, const char *, const size_t,
799240116Smarcel    const int, const char *, const bool);
800240116Smarcelstatic void _atf_tc_expect_pass(struct context *);
801240116Smarcelstatic void _atf_tc_expect_fail(struct context *, const char *, va_list);
802240116Smarcelstatic void _atf_tc_expect_exit(struct context *, const int, const char *,
803240116Smarcel    va_list);
804240116Smarcelstatic void _atf_tc_expect_signal(struct context *, const int, const char *,
805240116Smarcel    va_list);
806240116Smarcelstatic void _atf_tc_expect_death(struct context *, const char *,
807240116Smarcel    va_list);
808240116Smarcel
809240116Smarcelstatic void
810240116Smarcel_atf_tc_fail(struct context *ctx, const char *fmt, va_list ap)
811240116Smarcel{
812240116Smarcel    va_list ap2;
813240116Smarcel    atf_dynstr_t reason;
814240116Smarcel
815240116Smarcel    va_copy(ap2, ap);
816240116Smarcel    format_reason_ap(&reason, NULL, 0, fmt, ap2);
817240116Smarcel    va_end(ap2);
818240116Smarcel
819240116Smarcel    fail_requirement(ctx, &reason);
820240116Smarcel    UNREACHABLE;
821240116Smarcel}
822240116Smarcel
823240116Smarcelstatic void
824240116Smarcel_atf_tc_fail_nonfatal(struct context *ctx, const char *fmt, va_list ap)
825240116Smarcel{
826240116Smarcel    va_list ap2;
827240116Smarcel    atf_dynstr_t reason;
828240116Smarcel
829240116Smarcel    va_copy(ap2, ap);
830240116Smarcel    format_reason_ap(&reason, NULL, 0, fmt, ap2);
831240116Smarcel    va_end(ap2);
832240116Smarcel
833240116Smarcel    fail_check(ctx, &reason);
834240116Smarcel}
835240116Smarcel
836240116Smarcelstatic void
837240116Smarcel_atf_tc_fail_check(struct context *ctx, const char *file, const size_t line,
838240116Smarcel                   const char *fmt, va_list ap)
839240116Smarcel{
840240116Smarcel    va_list ap2;
841240116Smarcel    atf_dynstr_t reason;
842240116Smarcel
843240116Smarcel    va_copy(ap2, ap);
844240116Smarcel    format_reason_ap(&reason, file, line, fmt, ap2);
845240116Smarcel    va_end(ap2);
846240116Smarcel
847240116Smarcel    fail_check(ctx, &reason);
848240116Smarcel}
849240116Smarcel
850240116Smarcelstatic void
851240116Smarcel_atf_tc_fail_requirement(struct context *ctx, const char *file,
852240116Smarcel                         const size_t line, const char *fmt, va_list ap)
853240116Smarcel{
854240116Smarcel    va_list ap2;
855240116Smarcel    atf_dynstr_t reason;
856240116Smarcel
857240116Smarcel    va_copy(ap2, ap);
858240116Smarcel    format_reason_ap(&reason, file, line, fmt, ap2);
859240116Smarcel    va_end(ap2);
860240116Smarcel
861240116Smarcel    fail_requirement(ctx, &reason);
862240116Smarcel    UNREACHABLE;
863240116Smarcel}
864240116Smarcel
865240116Smarcelstatic void
866240116Smarcel_atf_tc_pass(struct context *ctx)
867240116Smarcel{
868240116Smarcel    pass(ctx);
869240116Smarcel    UNREACHABLE;
870240116Smarcel}
871240116Smarcel
872240116Smarcelstatic void
873240116Smarcel_atf_tc_require_prog(struct context *ctx, const char *prog)
874240116Smarcel{
875240116Smarcel    check_fatal_error(check_prog(ctx, prog));
876240116Smarcel}
877240116Smarcel
878240116Smarcelstatic void
879240116Smarcel_atf_tc_skip(struct context *ctx, const char *fmt, va_list ap)
880240116Smarcel{
881240116Smarcel    atf_dynstr_t reason;
882240116Smarcel    va_list ap2;
883240116Smarcel
884240116Smarcel    va_copy(ap2, ap);
885240116Smarcel    format_reason_ap(&reason, NULL, 0, fmt, ap2);
886240116Smarcel    va_end(ap2);
887240116Smarcel
888240116Smarcel    skip(ctx, &reason);
889240116Smarcel}
890240116Smarcel
891240116Smarcelstatic void
892240116Smarcel_atf_tc_check_errno(struct context *ctx, const char *file, const size_t line,
893240116Smarcel                    const int exp_errno, const char *expr_str,
894240116Smarcel                    const bool expr_result)
895240116Smarcel{
896240116Smarcel    errno_test(ctx, file, line, exp_errno, expr_str, expr_result, fail_check);
897240116Smarcel}
898240116Smarcel
899240116Smarcelstatic void
900240116Smarcel_atf_tc_require_errno(struct context *ctx, const char *file, const size_t line,
901240116Smarcel                      const int exp_errno, const char *expr_str,
902240116Smarcel                      const bool expr_result)
903240116Smarcel{
904240116Smarcel    errno_test(ctx, file, line, exp_errno, expr_str, expr_result,
905240116Smarcel        fail_requirement);
906240116Smarcel}
907240116Smarcel
908240116Smarcelstatic void
909240116Smarcel_atf_tc_expect_pass(struct context *ctx)
910240116Smarcel{
911240116Smarcel    validate_expect(ctx);
912240116Smarcel
913240116Smarcel    ctx->expect = EXPECT_PASS;
914240116Smarcel}
915240116Smarcel
916240116Smarcelstatic void
917240116Smarcel_atf_tc_expect_fail(struct context *ctx, const char *reason, va_list ap)
918240116Smarcel{
919240116Smarcel    va_list ap2;
920240116Smarcel
921240116Smarcel    validate_expect(ctx);
922240116Smarcel
923240116Smarcel    ctx->expect = EXPECT_FAIL;
924240116Smarcel    atf_dynstr_fini(&ctx->expect_reason);
925240116Smarcel    va_copy(ap2, ap);
926240116Smarcel    check_fatal_error(atf_dynstr_init_ap(&ctx->expect_reason, reason, ap2));
927240116Smarcel    va_end(ap2);
928240116Smarcel    ctx->expect_previous_fail_count = ctx->expect_fail_count;
929240116Smarcel}
930240116Smarcel
931240116Smarcelstatic void
932240116Smarcel_atf_tc_expect_exit(struct context *ctx, const int exitcode, const char *reason,
933240116Smarcel                    va_list ap)
934240116Smarcel{
935240116Smarcel    va_list ap2;
936240116Smarcel    atf_dynstr_t formatted;
937240116Smarcel
938240116Smarcel    validate_expect(ctx);
939240116Smarcel
940240116Smarcel    ctx->expect = EXPECT_EXIT;
941240116Smarcel    va_copy(ap2, ap);
942240116Smarcel    check_fatal_error(atf_dynstr_init_ap(&formatted, reason, ap2));
943240116Smarcel    va_end(ap2);
944240116Smarcel
945240116Smarcel    create_resfile(ctx->resfile, "expected_exit", exitcode, &formatted);
946240116Smarcel}
947240116Smarcel
948240116Smarcelstatic void
949240116Smarcel_atf_tc_expect_signal(struct context *ctx, const int signo, const char *reason,
950240116Smarcel                      va_list ap)
951240116Smarcel{
952240116Smarcel    va_list ap2;
953240116Smarcel    atf_dynstr_t formatted;
954240116Smarcel
955240116Smarcel    validate_expect(ctx);
956240116Smarcel
957240116Smarcel    ctx->expect = EXPECT_SIGNAL;
958240116Smarcel    va_copy(ap2, ap);
959240116Smarcel    check_fatal_error(atf_dynstr_init_ap(&formatted, reason, ap2));
960240116Smarcel    va_end(ap2);
961240116Smarcel
962240116Smarcel    create_resfile(ctx->resfile, "expected_signal", signo, &formatted);
963240116Smarcel}
964240116Smarcel
965240116Smarcelstatic void
966240116Smarcel_atf_tc_expect_death(struct context *ctx, const char *reason, va_list ap)
967240116Smarcel{
968240116Smarcel    va_list ap2;
969240116Smarcel    atf_dynstr_t formatted;
970240116Smarcel
971240116Smarcel    validate_expect(ctx);
972240116Smarcel
973240116Smarcel    ctx->expect = EXPECT_DEATH;
974240116Smarcel    va_copy(ap2, ap);
975240116Smarcel    check_fatal_error(atf_dynstr_init_ap(&formatted, reason, ap2));
976240116Smarcel    va_end(ap2);
977240116Smarcel
978240116Smarcel    create_resfile(ctx->resfile, "expected_death", -1, &formatted);
979240116Smarcel}
980240116Smarcel
981240116Smarcelstatic void
982240116Smarcel_atf_tc_expect_timeout(struct context *ctx, const char *reason, va_list ap)
983240116Smarcel{
984240116Smarcel    va_list ap2;
985240116Smarcel    atf_dynstr_t formatted;
986240116Smarcel
987240116Smarcel    validate_expect(ctx);
988240116Smarcel
989240116Smarcel    ctx->expect = EXPECT_TIMEOUT;
990240116Smarcel    va_copy(ap2, ap);
991240116Smarcel    check_fatal_error(atf_dynstr_init_ap(&formatted, reason, ap2));
992240116Smarcel    va_end(ap2);
993240116Smarcel
994240116Smarcel    create_resfile(ctx->resfile, "expected_timeout", -1, &formatted);
995240116Smarcel}
996240116Smarcel
997240116Smarcel/* ---------------------------------------------------------------------
998240116Smarcel * Free functions.
999240116Smarcel * --------------------------------------------------------------------- */
1000240116Smarcel
1001240116Smarcelstatic struct context Current;
1002240116Smarcel
1003240116Smarcelatf_error_t
1004240116Smarcelatf_tc_run(const atf_tc_t *tc, const char *resfile)
1005240116Smarcel{
1006240116Smarcel    context_init(&Current, tc, resfile);
1007240116Smarcel
1008240116Smarcel    tc->pimpl->m_body(tc);
1009240116Smarcel
1010240116Smarcel    validate_expect(&Current);
1011240116Smarcel
1012240116Smarcel    if (Current.fail_count > 0) {
1013240116Smarcel        atf_dynstr_t reason;
1014240116Smarcel
1015240116Smarcel        format_reason_fmt(&reason, NULL, 0, "%d checks failed; see output for "
1016240116Smarcel            "more details", Current.fail_count);
1017240116Smarcel        fail_requirement(&Current, &reason);
1018240116Smarcel    } else if (Current.expect_fail_count > 0) {
1019240116Smarcel        atf_dynstr_t reason;
1020240116Smarcel
1021240116Smarcel        format_reason_fmt(&reason, NULL, 0, "%d checks failed as expected; "
1022240116Smarcel            "see output for more details", Current.expect_fail_count);
1023240116Smarcel        expected_failure(&Current, &reason);
1024240116Smarcel    } else {
1025240116Smarcel        pass(&Current);
1026240116Smarcel    }
1027240116Smarcel    UNREACHABLE;
1028240116Smarcel    return atf_no_error();
1029240116Smarcel}
1030240116Smarcel
1031240116Smarcelatf_error_t
1032240116Smarcelatf_tc_cleanup(const atf_tc_t *tc)
1033240116Smarcel{
1034240116Smarcel    if (tc->pimpl->m_cleanup != NULL)
1035240116Smarcel        tc->pimpl->m_cleanup(tc);
1036240116Smarcel    return atf_no_error(); /* XXX */
1037240116Smarcel}
1038240116Smarcel
1039240116Smarcel/* ---------------------------------------------------------------------
1040240116Smarcel * Free functions that depend on Current.
1041240116Smarcel * --------------------------------------------------------------------- */
1042240116Smarcel
1043240116Smarcel/*
1044240116Smarcel * All the functions below provide delegates to other internal functions
1045240116Smarcel * (prefixed by _) that take the current test case as an argument to
1046240116Smarcel * prevent them from accessing global state.  This is to keep the side-
1047240116Smarcel * effects of the internal functions clearer and easier to understand.
1048240116Smarcel *
1049240116Smarcel * The public API should never have hid the fact that it needs access to
1050240116Smarcel * the current test case (other than maybe in the macros), but changing it
1051240116Smarcel * is hard.  TODO: Revisit in the future.
1052240116Smarcel */
1053240116Smarcel
1054240116Smarcelvoid
1055240116Smarcelatf_tc_fail(const char *fmt, ...)
1056240116Smarcel{
1057240116Smarcel    va_list ap;
1058240116Smarcel
1059240116Smarcel    PRE(Current.tc != NULL);
1060240116Smarcel
1061240116Smarcel    va_start(ap, fmt);
1062240116Smarcel    _atf_tc_fail(&Current, fmt, ap);
1063240116Smarcel    va_end(ap);
1064240116Smarcel}
1065240116Smarcel
1066240116Smarcelvoid
1067240116Smarcelatf_tc_fail_nonfatal(const char *fmt, ...)
1068240116Smarcel{
1069240116Smarcel    va_list ap;
1070240116Smarcel
1071240116Smarcel    PRE(Current.tc != NULL);
1072240116Smarcel
1073240116Smarcel    va_start(ap, fmt);
1074240116Smarcel    _atf_tc_fail_nonfatal(&Current, fmt, ap);
1075240116Smarcel    va_end(ap);
1076240116Smarcel}
1077240116Smarcel
1078240116Smarcelvoid
1079240116Smarcelatf_tc_fail_check(const char *file, const size_t line, const char *fmt, ...)
1080240116Smarcel{
1081240116Smarcel    va_list ap;
1082240116Smarcel
1083240116Smarcel    PRE(Current.tc != NULL);
1084240116Smarcel
1085240116Smarcel    va_start(ap, fmt);
1086240116Smarcel    _atf_tc_fail_check(&Current, file, line, fmt, ap);
1087240116Smarcel    va_end(ap);
1088240116Smarcel}
1089240116Smarcel
1090240116Smarcelvoid
1091240116Smarcelatf_tc_fail_requirement(const char *file, const size_t line,
1092240116Smarcel                        const char *fmt, ...)
1093240116Smarcel{
1094240116Smarcel    va_list ap;
1095240116Smarcel
1096240116Smarcel    PRE(Current.tc != NULL);
1097240116Smarcel
1098240116Smarcel    va_start(ap, fmt);
1099240116Smarcel    _atf_tc_fail_requirement(&Current, file, line, fmt, ap);
1100240116Smarcel    va_end(ap);
1101240116Smarcel}
1102240116Smarcel
1103240116Smarcelvoid
1104240116Smarcelatf_tc_pass(void)
1105240116Smarcel{
1106240116Smarcel    PRE(Current.tc != NULL);
1107240116Smarcel
1108240116Smarcel    _atf_tc_pass(&Current);
1109240116Smarcel}
1110240116Smarcel
1111240116Smarcelvoid
1112240116Smarcelatf_tc_require_prog(const char *prog)
1113240116Smarcel{
1114240116Smarcel    PRE(Current.tc != NULL);
1115240116Smarcel
1116240116Smarcel    _atf_tc_require_prog(&Current, prog);
1117240116Smarcel}
1118240116Smarcel
1119240116Smarcelvoid
1120240116Smarcelatf_tc_skip(const char *fmt, ...)
1121240116Smarcel{
1122240116Smarcel    va_list ap;
1123240116Smarcel
1124240116Smarcel    PRE(Current.tc != NULL);
1125240116Smarcel
1126240116Smarcel    va_start(ap, fmt);
1127240116Smarcel    _atf_tc_skip(&Current, fmt, ap);
1128240116Smarcel    va_end(ap);
1129240116Smarcel}
1130240116Smarcel
1131240116Smarcelvoid
1132240116Smarcelatf_tc_check_errno(const char *file, const size_t line, const int exp_errno,
1133240116Smarcel                   const char *expr_str, const bool expr_result)
1134240116Smarcel{
1135240116Smarcel    PRE(Current.tc != NULL);
1136240116Smarcel
1137240116Smarcel    _atf_tc_check_errno(&Current, file, line, exp_errno, expr_str,
1138240116Smarcel                        expr_result);
1139240116Smarcel}
1140240116Smarcel
1141240116Smarcelvoid
1142240116Smarcelatf_tc_require_errno(const char *file, const size_t line, const int exp_errno,
1143240116Smarcel                     const char *expr_str, const bool expr_result)
1144240116Smarcel{
1145240116Smarcel    PRE(Current.tc != NULL);
1146240116Smarcel
1147240116Smarcel    _atf_tc_require_errno(&Current, file, line, exp_errno, expr_str,
1148240116Smarcel                          expr_result);
1149240116Smarcel}
1150240116Smarcel
1151240116Smarcelvoid
1152240116Smarcelatf_tc_expect_pass(void)
1153240116Smarcel{
1154240116Smarcel    PRE(Current.tc != NULL);
1155240116Smarcel
1156240116Smarcel    _atf_tc_expect_pass(&Current);
1157240116Smarcel}
1158240116Smarcel
1159240116Smarcelvoid
1160240116Smarcelatf_tc_expect_fail(const char *reason, ...)
1161240116Smarcel{
1162240116Smarcel    va_list ap;
1163240116Smarcel
1164240116Smarcel    PRE(Current.tc != NULL);
1165240116Smarcel
1166240116Smarcel    va_start(ap, reason);
1167240116Smarcel    _atf_tc_expect_fail(&Current, reason, ap);
1168240116Smarcel    va_end(ap);
1169240116Smarcel}
1170240116Smarcel
1171240116Smarcelvoid
1172240116Smarcelatf_tc_expect_exit(const int exitcode, const char *reason, ...)
1173240116Smarcel{
1174240116Smarcel    va_list ap;
1175240116Smarcel
1176240116Smarcel    PRE(Current.tc != NULL);
1177240116Smarcel
1178240116Smarcel    va_start(ap, reason);
1179240116Smarcel    _atf_tc_expect_exit(&Current, exitcode, reason, ap);
1180240116Smarcel    va_end(ap);
1181240116Smarcel}
1182240116Smarcel
1183240116Smarcelvoid
1184240116Smarcelatf_tc_expect_signal(const int signo, const char *reason, ...)
1185240116Smarcel{
1186240116Smarcel    va_list ap;
1187240116Smarcel
1188240116Smarcel    PRE(Current.tc != NULL);
1189240116Smarcel
1190240116Smarcel    va_start(ap, reason);
1191240116Smarcel    _atf_tc_expect_signal(&Current, signo, reason, ap);
1192240116Smarcel    va_end(ap);
1193240116Smarcel}
1194240116Smarcel
1195240116Smarcelvoid
1196240116Smarcelatf_tc_expect_death(const char *reason, ...)
1197240116Smarcel{
1198240116Smarcel    va_list ap;
1199240116Smarcel
1200240116Smarcel    PRE(Current.tc != NULL);
1201240116Smarcel
1202240116Smarcel    va_start(ap, reason);
1203240116Smarcel    _atf_tc_expect_death(&Current, reason, ap);
1204240116Smarcel    va_end(ap);
1205240116Smarcel}
1206240116Smarcel
1207240116Smarcelvoid
1208240116Smarcelatf_tc_expect_timeout(const char *reason, ...)
1209240116Smarcel{
1210240116Smarcel    va_list ap;
1211240116Smarcel
1212240116Smarcel    PRE(Current.tc != NULL);
1213240116Smarcel
1214240116Smarcel    va_start(ap, reason);
1215240116Smarcel    _atf_tc_expect_timeout(&Current, reason, ap);
1216240116Smarcel    va_end(ap);
1217240116Smarcel}
1218