1/*
2 * Automated Testing Framework (atf)
3 *
4 * Copyright (c) 2008 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
17 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
18 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include <sys/types.h>
31#include <sys/stat.h>
32#include <sys/uio.h>
33
34#include <errno.h>
35#include <fcntl.h>
36#include <stdarg.h>
37#include <stdbool.h>
38#include <stdio.h>
39#include <stdlib.h>
40#include <string.h>
41#include <unistd.h>
42
43#include "atf-c/defs.h"
44#include "atf-c/error.h"
45#include "atf-c/tc.h"
46
47#include "detail/env.h"
48#include "detail/fs.h"
49#include "detail/map.h"
50#include "detail/sanity.h"
51#include "detail/text.h"
52
53/* ---------------------------------------------------------------------
54 * Auxiliary functions.
55 * --------------------------------------------------------------------- */
56
57enum expect_type {
58    EXPECT_PASS,
59    EXPECT_FAIL,
60    EXPECT_EXIT,
61    EXPECT_SIGNAL,
62    EXPECT_DEATH,
63    EXPECT_TIMEOUT,
64};
65
66struct context {
67    const atf_tc_t *tc;
68    const char *resfile;
69    size_t fail_count;
70
71    enum expect_type expect;
72    atf_dynstr_t expect_reason;
73    size_t expect_previous_fail_count;
74    size_t expect_fail_count;
75    int expect_exitcode;
76    int expect_signo;
77};
78
79static void context_init(struct context *, const atf_tc_t *, const char *);
80static void check_fatal_error(atf_error_t);
81static void report_fatal_error(const char *, ...)
82    ATF_DEFS_ATTRIBUTE_NORETURN;
83static atf_error_t write_resfile(const int, const char *, const int,
84                                 const atf_dynstr_t *);
85static void create_resfile(const char *, const char *, const int,
86                           atf_dynstr_t *);
87static void error_in_expect(struct context *, const char *, ...)
88    ATF_DEFS_ATTRIBUTE_NORETURN;
89static void validate_expect(struct context *);
90static void expected_failure(struct context *, atf_dynstr_t *)
91    ATF_DEFS_ATTRIBUTE_NORETURN;
92static void fail_requirement(struct context *, atf_dynstr_t *)
93    ATF_DEFS_ATTRIBUTE_NORETURN;
94static void fail_check(struct context *, atf_dynstr_t *);
95static void pass(struct context *)
96    ATF_DEFS_ATTRIBUTE_NORETURN;
97static void skip(struct context *, atf_dynstr_t *)
98    ATF_DEFS_ATTRIBUTE_NORETURN;
99static void format_reason_ap(atf_dynstr_t *, const char *, const size_t,
100                             const char *, va_list);
101static void format_reason_fmt(atf_dynstr_t *, const char *, const size_t,
102                              const char *, ...);
103static void errno_test(struct context *, const char *, const size_t,
104                       const int, const char *, const bool,
105                       void (*)(struct context *, atf_dynstr_t *));
106static atf_error_t check_prog_in_dir(const char *, void *);
107static atf_error_t check_prog(struct context *, const char *);
108
109static void
110context_init(struct context *ctx, const atf_tc_t *tc, const char *resfile)
111{
112    ctx->tc = tc;
113    ctx->resfile = resfile;
114    ctx->fail_count = 0;
115    ctx->expect = EXPECT_PASS;
116    check_fatal_error(atf_dynstr_init(&ctx->expect_reason));
117    ctx->expect_previous_fail_count = 0;
118    ctx->expect_fail_count = 0;
119    ctx->expect_exitcode = 0;
120    ctx->expect_signo = 0;
121}
122
123static void
124check_fatal_error(atf_error_t err)
125{
126    if (atf_is_error(err)) {
127        char buf[1024];
128        atf_error_format(err, buf, sizeof(buf));
129        fprintf(stderr, "FATAL ERROR: %s\n", buf);
130        atf_error_free(err);
131        abort();
132    }
133}
134
135static void
136report_fatal_error(const char *msg, ...)
137{
138    va_list ap;
139    fprintf(stderr, "FATAL ERROR: ");
140
141    va_start(ap, msg);
142    vfprintf(stderr, msg, ap);
143    va_end(ap);
144
145    fprintf(stderr, "\n");
146    abort();
147}
148
149/** Writes to a results file.
150 *
151 * The results file is supposed to be already open.
152 *
153 * This function returns an error code instead of exiting in case of error
154 * because the caller needs to clean up the reason object before terminating.
155 */
156static atf_error_t
157write_resfile(const int fd, const char *result, const int arg,
158              const atf_dynstr_t *reason)
159{
160    static char NL[] = "\n", CS[] = ": ";
161    char buf[64];
162    const char *r;
163    struct iovec iov[5];
164    ssize_t ret;
165    int count = 0;
166
167    INV(arg == -1 || reason != NULL);
168
169#define UNCONST(a) ((void *)(unsigned long)(const void *)(a))
170    iov[count].iov_base = UNCONST(result);
171    iov[count++].iov_len = strlen(result);
172
173    if (reason != NULL) {
174        if (arg != -1) {
175            iov[count].iov_base = buf;
176            iov[count++].iov_len = snprintf(buf, sizeof(buf), "(%d)", arg);
177        }
178
179        iov[count].iov_base = CS;
180        iov[count++].iov_len = sizeof(CS) - 1;
181
182        r = atf_dynstr_cstring(reason);
183        iov[count].iov_base = UNCONST(r);
184        iov[count++].iov_len = strlen(r);
185    }
186#undef UNCONST
187
188    iov[count].iov_base = NL;
189    iov[count++].iov_len = sizeof(NL) - 1;
190
191    while ((ret = writev(fd, iov, count)) == -1 && errno == EINTR)
192        continue; /* Retry. */
193    if (ret != -1)
194        return atf_no_error();
195
196    return atf_libc_error(
197        errno, "Failed to write results file; result %s, reason %s", result,
198        reason == NULL ? "null" : atf_dynstr_cstring(reason));
199}
200
201/** Creates a results file.
202 *
203 * The input reason is released in all cases.
204 *
205 * An error in this function is considered to be fatal, hence why it does
206 * not return any error code.
207 */
208static void
209create_resfile(const char *resfile, const char *result, const int arg,
210               atf_dynstr_t *reason)
211{
212    atf_error_t err;
213
214    if (strcmp("/dev/stdout", resfile) == 0) {
215        err = write_resfile(STDOUT_FILENO, result, arg, reason);
216    } else if (strcmp("/dev/stderr", resfile) == 0) {
217        err = write_resfile(STDERR_FILENO, result, arg, reason);
218    } else {
219        const int fd = open(resfile, O_WRONLY | O_CREAT | O_TRUNC,
220            S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
221        if (fd == -1) {
222            err = atf_libc_error(errno, "Cannot create results file '%s'",
223                                 resfile);
224        } else {
225            err = write_resfile(fd, result, arg, reason);
226            close(fd);
227        }
228    }
229
230    if (reason != NULL)
231        atf_dynstr_fini(reason);
232
233    check_fatal_error(err);
234}
235
236/** Fails a test case if validate_expect fails. */
237static void
238error_in_expect(struct context *ctx, const char *fmt, ...)
239{
240    atf_dynstr_t reason;
241    va_list ap;
242
243    va_start(ap, fmt);
244    format_reason_ap(&reason, NULL, 0, fmt, ap);
245    va_end(ap);
246
247    ctx->expect = EXPECT_PASS;  /* Ensure fail_requirement really fails. */
248    fail_requirement(ctx, &reason);
249}
250
251/** Ensures that the "expect" state is correct.
252 *
253 * Call this function before modifying the current value of expect.
254 */
255static void
256validate_expect(struct context *ctx)
257{
258    if (ctx->expect == EXPECT_DEATH) {
259        error_in_expect(ctx, "Test case was expected to terminate abruptly "
260            "but it continued execution");
261    } else if (ctx->expect == EXPECT_EXIT) {
262        error_in_expect(ctx, "Test case was expected to exit cleanly but it "
263            "continued execution");
264    } else if (ctx->expect == EXPECT_FAIL) {
265        if (ctx->expect_fail_count == ctx->expect_previous_fail_count)
266            error_in_expect(ctx, "Test case was expecting a failure but none "
267                "were raised");
268        else
269            INV(ctx->expect_fail_count > ctx->expect_previous_fail_count);
270    } else if (ctx->expect == EXPECT_PASS) {
271        /* Nothing to validate. */
272    } else if (ctx->expect == EXPECT_SIGNAL) {
273        error_in_expect(ctx, "Test case was expected to receive a termination "
274            "signal but it continued execution");
275    } else if (ctx->expect == EXPECT_TIMEOUT) {
276        error_in_expect(ctx, "Test case was expected to hang but it continued "
277            "execution");
278    } else
279        UNREACHABLE;
280}
281
282static void
283expected_failure(struct context *ctx, atf_dynstr_t *reason)
284{
285    check_fatal_error(atf_dynstr_prepend_fmt(reason, "%s: ",
286        atf_dynstr_cstring(&ctx->expect_reason)));
287    create_resfile(ctx->resfile, "expected_failure", -1, reason);
288    exit(EXIT_SUCCESS);
289}
290
291static void
292fail_requirement(struct context *ctx, atf_dynstr_t *reason)
293{
294    if (ctx->expect == EXPECT_FAIL) {
295        expected_failure(ctx, reason);
296    } else if (ctx->expect == EXPECT_PASS) {
297        create_resfile(ctx->resfile, "failed", -1, reason);
298        exit(EXIT_FAILURE);
299    } else {
300        error_in_expect(ctx, "Test case raised a failure but was not "
301            "expecting one; reason was %s", atf_dynstr_cstring(reason));
302    }
303    UNREACHABLE;
304}
305
306static void
307fail_check(struct context *ctx, atf_dynstr_t *reason)
308{
309    if (ctx->expect == EXPECT_FAIL) {
310        fprintf(stderr, "*** Expected check failure: %s: %s\n",
311            atf_dynstr_cstring(&ctx->expect_reason),
312            atf_dynstr_cstring(reason));
313        ctx->expect_fail_count++;
314    } else if (ctx->expect == EXPECT_PASS) {
315        fprintf(stderr, "*** Check failed: %s\n", atf_dynstr_cstring(reason));
316        ctx->fail_count++;
317    } else {
318        error_in_expect(ctx, "Test case raised a failure but was not "
319            "expecting one; reason was %s", atf_dynstr_cstring(reason));
320    }
321
322    atf_dynstr_fini(reason);
323}
324
325static void
326pass(struct context *ctx)
327{
328    if (ctx->expect == EXPECT_FAIL) {
329        error_in_expect(ctx, "Test case was expecting a failure but got "
330            "a pass instead");
331    } else if (ctx->expect == EXPECT_PASS) {
332        create_resfile(ctx->resfile, "passed", -1, NULL);
333        exit(EXIT_SUCCESS);
334    } else {
335        error_in_expect(ctx, "Test case asked to explicitly pass but was "
336            "not expecting such condition");
337    }
338    UNREACHABLE;
339}
340
341static void
342skip(struct context *ctx, atf_dynstr_t *reason)
343{
344    if (ctx->expect == EXPECT_PASS) {
345        create_resfile(ctx->resfile, "skipped", -1, reason);
346        exit(EXIT_SUCCESS);
347    } else {
348        error_in_expect(ctx, "Can only skip a test case when running in "
349            "expect pass mode");
350    }
351    UNREACHABLE;
352}
353
354/** Formats a failure/skip reason message.
355 *
356 * The formatted reason is stored in out_reason.  out_reason is initialized
357 * in this function and is supposed to be released by the caller.  In general,
358 * the reason will eventually be fed to create_resfile, which will release
359 * it.
360 *
361 * Errors in this function are fatal.  Rationale being: reasons are used to
362 * create results files; if we can't format the reason correctly, the result
363 * of the test program will be bogus.  So it's better to just exit with a
364 * fatal error.
365 */
366static void
367format_reason_ap(atf_dynstr_t *out_reason,
368                 const char *source_file, const size_t source_line,
369                 const char *reason, va_list ap)
370{
371    atf_error_t err;
372
373    if (source_file != NULL) {
374        err = atf_dynstr_init_fmt(out_reason, "%s:%zd: ", source_file,
375                                  source_line);
376    } else {
377        PRE(source_line == 0);
378        err = atf_dynstr_init(out_reason);
379    }
380
381    if (!atf_is_error(err)) {
382        va_list ap2;
383        va_copy(ap2, ap);
384        err = atf_dynstr_append_ap(out_reason, reason, ap2);
385        va_end(ap2);
386    }
387
388    check_fatal_error(err);
389}
390
391static void
392format_reason_fmt(atf_dynstr_t *out_reason,
393                  const char *source_file, const size_t source_line,
394                  const char *reason, ...)
395{
396    va_list ap;
397
398    va_start(ap, reason);
399    format_reason_ap(out_reason, source_file, source_line, reason, ap);
400    va_end(ap);
401}
402
403static void
404errno_test(struct context *ctx, const char *file, const size_t line,
405           const int exp_errno, const char *expr_str,
406           const bool expr_result,
407           void (*fail_func)(struct context *, atf_dynstr_t *))
408{
409    const int actual_errno = errno;
410
411    if (expr_result) {
412        if (exp_errno != actual_errno) {
413            atf_dynstr_t reason;
414
415            format_reason_fmt(&reason, file, line, "Expected errno %d, got %d, "
416                "in %s", exp_errno, actual_errno, expr_str);
417            fail_func(ctx, &reason);
418        }
419    } else {
420        atf_dynstr_t reason;
421
422        format_reason_fmt(&reason, file, line, "Expected true value in %s",
423            expr_str);
424        fail_func(ctx, &reason);
425    }
426}
427
428struct prog_found_pair {
429    const char *prog;
430    bool found;
431};
432
433static atf_error_t
434check_prog_in_dir(const char *dir, void *data)
435{
436    struct prog_found_pair *pf = data;
437    atf_error_t err;
438
439    if (pf->found)
440        err = atf_no_error();
441    else {
442        atf_fs_path_t p;
443
444        err = atf_fs_path_init_fmt(&p, "%s/%s", dir, pf->prog);
445        if (atf_is_error(err))
446            goto out_p;
447
448        err = atf_fs_eaccess(&p, atf_fs_access_x);
449        if (!atf_is_error(err))
450            pf->found = true;
451        else {
452            atf_error_free(err);
453            INV(!pf->found);
454            err = atf_no_error();
455        }
456
457out_p:
458        atf_fs_path_fini(&p);
459    }
460
461    return err;
462}
463
464static atf_error_t
465check_prog(struct context *ctx, const char *prog)
466{
467    atf_error_t err;
468    atf_fs_path_t p;
469
470    err = atf_fs_path_init_fmt(&p, "%s", prog);
471    if (atf_is_error(err))
472        goto out;
473
474    if (atf_fs_path_is_absolute(&p)) {
475        err = atf_fs_eaccess(&p, atf_fs_access_x);
476        if (atf_is_error(err)) {
477            atf_dynstr_t reason;
478
479            atf_error_free(err);
480            atf_fs_path_fini(&p);
481            format_reason_fmt(&reason, NULL, 0, "The required program %s could "
482                "not be found", prog);
483            skip(ctx, &reason);
484        }
485    } else {
486        const char *path = atf_env_get("PATH");
487        struct prog_found_pair pf;
488        atf_fs_path_t bp;
489
490        err = atf_fs_path_branch_path(&p, &bp);
491        if (atf_is_error(err))
492            goto out_p;
493
494        if (strcmp(atf_fs_path_cstring(&bp), ".") != 0) {
495            atf_fs_path_fini(&bp);
496            atf_fs_path_fini(&p);
497
498            report_fatal_error("Relative paths are not allowed when searching "
499                "for a program (%s)", prog);
500            UNREACHABLE;
501        }
502
503        pf.prog = prog;
504        pf.found = false;
505        err = atf_text_for_each_word(path, ":", check_prog_in_dir, &pf);
506        if (atf_is_error(err))
507            goto out_bp;
508
509        if (!pf.found) {
510            atf_dynstr_t reason;
511
512            atf_fs_path_fini(&bp);
513            atf_fs_path_fini(&p);
514            format_reason_fmt(&reason, NULL, 0, "The required program %s could "
515                "not be found in the PATH", prog);
516            fail_requirement(ctx, &reason);
517        }
518
519out_bp:
520        atf_fs_path_fini(&bp);
521    }
522
523out_p:
524    atf_fs_path_fini(&p);
525out:
526    return err;
527}
528
529/* ---------------------------------------------------------------------
530 * The "atf_tc" type.
531 * --------------------------------------------------------------------- */
532
533struct atf_tc_impl {
534    const char *m_ident;
535
536    atf_map_t m_vars;
537    atf_map_t m_config;
538
539    atf_tc_head_t m_head;
540    atf_tc_body_t m_body;
541    atf_tc_cleanup_t m_cleanup;
542};
543
544/*
545 * Constructors/destructors.
546 */
547
548atf_error_t
549atf_tc_init(atf_tc_t *tc, const char *ident, atf_tc_head_t head,
550            atf_tc_body_t body, atf_tc_cleanup_t cleanup,
551            const char *const *config)
552{
553    atf_error_t err;
554
555    tc->pimpl = malloc(sizeof(struct atf_tc_impl));
556    if (tc->pimpl == NULL) {
557        err = atf_no_memory_error();
558        goto err;
559    }
560
561    tc->pimpl->m_ident = ident;
562    tc->pimpl->m_head = head;
563    tc->pimpl->m_body = body;
564    tc->pimpl->m_cleanup = cleanup;
565
566    err = atf_map_init_charpp(&tc->pimpl->m_config, config);
567    if (atf_is_error(err))
568        goto err;
569
570    err = atf_map_init(&tc->pimpl->m_vars);
571    if (atf_is_error(err))
572        goto err_vars;
573
574    err = atf_tc_set_md_var(tc, "ident", ident);
575    if (atf_is_error(err))
576        goto err_map;
577
578    if (cleanup != NULL) {
579        err = atf_tc_set_md_var(tc, "has.cleanup", "true");
580        if (atf_is_error(err))
581            goto err_map;
582    }
583
584    /* XXX Should the head be able to return error codes? */
585    if (tc->pimpl->m_head != NULL)
586        tc->pimpl->m_head(tc);
587
588    if (strcmp(atf_tc_get_md_var(tc, "ident"), ident) != 0) {
589        report_fatal_error("Test case head modified the read-only 'ident' "
590            "property");
591        UNREACHABLE;
592    }
593
594    INV(!atf_is_error(err));
595    return err;
596
597err_map:
598    atf_map_fini(&tc->pimpl->m_vars);
599err_vars:
600    atf_map_fini(&tc->pimpl->m_config);
601err:
602    return err;
603}
604
605atf_error_t
606atf_tc_init_pack(atf_tc_t *tc, const atf_tc_pack_t *pack,
607                 const char *const *config)
608{
609    return atf_tc_init(tc, pack->m_ident, pack->m_head, pack->m_body,
610                       pack->m_cleanup, config);
611}
612
613void
614atf_tc_fini(atf_tc_t *tc)
615{
616    atf_map_fini(&tc->pimpl->m_vars);
617    free(tc->pimpl);
618}
619
620/*
621 * Getters.
622 */
623
624const char *
625atf_tc_get_ident(const atf_tc_t *tc)
626{
627    return tc->pimpl->m_ident;
628}
629
630const char *
631atf_tc_get_config_var(const atf_tc_t *tc, const char *name)
632{
633    const char *val;
634    atf_map_citer_t iter;
635
636    PRE(atf_tc_has_config_var(tc, name));
637    iter = atf_map_find_c(&tc->pimpl->m_config, name);
638    val = atf_map_citer_data(iter);
639    INV(val != NULL);
640
641    return val;
642}
643
644const char *
645atf_tc_get_config_var_wd(const atf_tc_t *tc, const char *name,
646                         const char *defval)
647{
648    const char *val;
649
650    if (!atf_tc_has_config_var(tc, name))
651        val = defval;
652    else
653        val = atf_tc_get_config_var(tc, name);
654
655    return val;
656}
657
658bool
659atf_tc_get_config_var_as_bool(const atf_tc_t *tc, const char *name)
660{
661    bool val;
662    const char *strval;
663    atf_error_t err;
664
665    strval = atf_tc_get_config_var(tc, name);
666    err = atf_text_to_bool(strval, &val);
667    if (atf_is_error(err)) {
668        atf_error_free(err);
669        atf_tc_fail("Configuration variable %s does not have a valid "
670                    "boolean value; found %s", name, strval);
671    }
672
673    return val;
674}
675
676bool
677atf_tc_get_config_var_as_bool_wd(const atf_tc_t *tc, const char *name,
678                                 const bool defval)
679{
680    bool val;
681
682    if (!atf_tc_has_config_var(tc, name))
683        val = defval;
684    else
685        val = atf_tc_get_config_var_as_bool(tc, name);
686
687    return val;
688}
689
690long
691atf_tc_get_config_var_as_long(const atf_tc_t *tc, const char *name)
692{
693    long val;
694    const char *strval;
695    atf_error_t err;
696
697    strval = atf_tc_get_config_var(tc, name);
698    err = atf_text_to_long(strval, &val);
699    if (atf_is_error(err)) {
700        atf_error_free(err);
701        atf_tc_fail("Configuration variable %s does not have a valid "
702                    "long value; found %s", name, strval);
703    }
704
705    return val;
706}
707
708long
709atf_tc_get_config_var_as_long_wd(const atf_tc_t *tc, const char *name,
710                                 const long defval)
711{
712    long val;
713
714    if (!atf_tc_has_config_var(tc, name))
715        val = defval;
716    else
717        val = atf_tc_get_config_var_as_long(tc, name);
718
719    return val;
720}
721
722const char *
723atf_tc_get_md_var(const atf_tc_t *tc, const char *name)
724{
725    const char *val;
726    atf_map_citer_t iter;
727
728    PRE(atf_tc_has_md_var(tc, name));
729    iter = atf_map_find_c(&tc->pimpl->m_vars, name);
730    val = atf_map_citer_data(iter);
731    INV(val != NULL);
732
733    return val;
734}
735
736char **
737atf_tc_get_md_vars(const atf_tc_t *tc)
738{
739    return atf_map_to_charpp(&tc->pimpl->m_vars);
740}
741
742bool
743atf_tc_has_config_var(const atf_tc_t *tc, const char *name)
744{
745    atf_map_citer_t end, iter;
746
747    iter = atf_map_find_c(&tc->pimpl->m_config, name);
748    end = atf_map_end_c(&tc->pimpl->m_config);
749    return !atf_equal_map_citer_map_citer(iter, end);
750}
751
752bool
753atf_tc_has_md_var(const atf_tc_t *tc, const char *name)
754{
755    atf_map_citer_t end, iter;
756
757    iter = atf_map_find_c(&tc->pimpl->m_vars, name);
758    end = atf_map_end_c(&tc->pimpl->m_vars);
759    return !atf_equal_map_citer_map_citer(iter, end);
760}
761
762/*
763 * Modifiers.
764 */
765
766atf_error_t
767atf_tc_set_md_var(atf_tc_t *tc, const char *name, const char *fmt, ...)
768{
769    atf_error_t err;
770    char *value;
771    va_list ap;
772
773    va_start(ap, fmt);
774    err = atf_text_format_ap(&value, fmt, ap);
775    va_end(ap);
776
777    if (!atf_is_error(err))
778        err = atf_map_insert(&tc->pimpl->m_vars, name, value, true);
779    else
780        free(value);
781
782    return err;
783}
784
785/* ---------------------------------------------------------------------
786 * Free functions, as they should be publicly but they can't.
787 * --------------------------------------------------------------------- */
788
789static void _atf_tc_fail(struct context *, const char *, va_list)
790    ATF_DEFS_ATTRIBUTE_NORETURN;
791static void _atf_tc_fail_nonfatal(struct context *, const char *, va_list);
792static void _atf_tc_fail_check(struct context *, const char *, const size_t,
793    const char *, va_list);
794static void _atf_tc_fail_requirement(struct context *, const char *,
795    const size_t, const char *, va_list) ATF_DEFS_ATTRIBUTE_NORETURN;
796static void _atf_tc_pass(struct context *) ATF_DEFS_ATTRIBUTE_NORETURN;
797static void _atf_tc_require_prog(struct context *, const char *);
798static void _atf_tc_skip(struct context *, const char *, va_list)
799    ATF_DEFS_ATTRIBUTE_NORETURN;
800static void _atf_tc_check_errno(struct context *, const char *, const size_t,
801    const int, const char *, const bool);
802static void _atf_tc_require_errno(struct context *, const char *, const size_t,
803    const int, const char *, const bool);
804static void _atf_tc_expect_pass(struct context *);
805static void _atf_tc_expect_fail(struct context *, const char *, va_list);
806static void _atf_tc_expect_exit(struct context *, const int, const char *,
807    va_list);
808static void _atf_tc_expect_signal(struct context *, const int, const char *,
809    va_list);
810static void _atf_tc_expect_death(struct context *, const char *,
811    va_list);
812
813static void
814_atf_tc_fail(struct context *ctx, const char *fmt, va_list ap)
815{
816    va_list ap2;
817    atf_dynstr_t reason;
818
819    va_copy(ap2, ap);
820    format_reason_ap(&reason, NULL, 0, fmt, ap2);
821    va_end(ap2);
822
823    fail_requirement(ctx, &reason);
824    UNREACHABLE;
825}
826
827static void
828_atf_tc_fail_nonfatal(struct context *ctx, const char *fmt, va_list ap)
829{
830    va_list ap2;
831    atf_dynstr_t reason;
832
833    va_copy(ap2, ap);
834    format_reason_ap(&reason, NULL, 0, fmt, ap2);
835    va_end(ap2);
836
837    fail_check(ctx, &reason);
838}
839
840static void
841_atf_tc_fail_check(struct context *ctx, const char *file, const size_t line,
842                   const char *fmt, va_list ap)
843{
844    va_list ap2;
845    atf_dynstr_t reason;
846
847    va_copy(ap2, ap);
848    format_reason_ap(&reason, file, line, fmt, ap2);
849    va_end(ap2);
850
851    fail_check(ctx, &reason);
852}
853
854static void
855_atf_tc_fail_requirement(struct context *ctx, const char *file,
856                         const size_t line, const char *fmt, va_list ap)
857{
858    va_list ap2;
859    atf_dynstr_t reason;
860
861    va_copy(ap2, ap);
862    format_reason_ap(&reason, file, line, fmt, ap2);
863    va_end(ap2);
864
865    fail_requirement(ctx, &reason);
866    UNREACHABLE;
867}
868
869static void
870_atf_tc_pass(struct context *ctx)
871{
872    pass(ctx);
873    UNREACHABLE;
874}
875
876static void
877_atf_tc_require_prog(struct context *ctx, const char *prog)
878{
879    check_fatal_error(check_prog(ctx, prog));
880}
881
882static void
883_atf_tc_skip(struct context *ctx, const char *fmt, va_list ap)
884{
885    atf_dynstr_t reason;
886    va_list ap2;
887
888    va_copy(ap2, ap);
889    format_reason_ap(&reason, NULL, 0, fmt, ap2);
890    va_end(ap2);
891
892    skip(ctx, &reason);
893}
894
895static void
896_atf_tc_check_errno(struct context *ctx, const char *file, const size_t line,
897                    const int exp_errno, const char *expr_str,
898                    const bool expr_result)
899{
900    errno_test(ctx, file, line, exp_errno, expr_str, expr_result, fail_check);
901}
902
903static void
904_atf_tc_require_errno(struct context *ctx, const char *file, const size_t line,
905                      const int exp_errno, const char *expr_str,
906                      const bool expr_result)
907{
908    errno_test(ctx, file, line, exp_errno, expr_str, expr_result,
909        fail_requirement);
910}
911
912static void
913_atf_tc_expect_pass(struct context *ctx)
914{
915    validate_expect(ctx);
916
917    ctx->expect = EXPECT_PASS;
918}
919
920static void
921_atf_tc_expect_fail(struct context *ctx, const char *reason, va_list ap)
922{
923    va_list ap2;
924
925    validate_expect(ctx);
926
927    ctx->expect = EXPECT_FAIL;
928    atf_dynstr_fini(&ctx->expect_reason);
929    va_copy(ap2, ap);
930    check_fatal_error(atf_dynstr_init_ap(&ctx->expect_reason, reason, ap2));
931    va_end(ap2);
932    ctx->expect_previous_fail_count = ctx->expect_fail_count;
933}
934
935static void
936_atf_tc_expect_exit(struct context *ctx, const int exitcode, const char *reason,
937                    va_list ap)
938{
939    va_list ap2;
940    atf_dynstr_t formatted;
941
942    validate_expect(ctx);
943
944    ctx->expect = EXPECT_EXIT;
945    va_copy(ap2, ap);
946    check_fatal_error(atf_dynstr_init_ap(&formatted, reason, ap2));
947    va_end(ap2);
948
949    create_resfile(ctx->resfile, "expected_exit", exitcode, &formatted);
950}
951
952static void
953_atf_tc_expect_signal(struct context *ctx, const int signo, const char *reason,
954                      va_list ap)
955{
956    va_list ap2;
957    atf_dynstr_t formatted;
958
959    validate_expect(ctx);
960
961    ctx->expect = EXPECT_SIGNAL;
962    va_copy(ap2, ap);
963    check_fatal_error(atf_dynstr_init_ap(&formatted, reason, ap2));
964    va_end(ap2);
965
966    create_resfile(ctx->resfile, "expected_signal", signo, &formatted);
967}
968
969static void
970_atf_tc_expect_death(struct context *ctx, const char *reason, va_list ap)
971{
972    va_list ap2;
973    atf_dynstr_t formatted;
974
975    validate_expect(ctx);
976
977    ctx->expect = EXPECT_DEATH;
978    va_copy(ap2, ap);
979    check_fatal_error(atf_dynstr_init_ap(&formatted, reason, ap2));
980    va_end(ap2);
981
982    create_resfile(ctx->resfile, "expected_death", -1, &formatted);
983}
984
985static void
986_atf_tc_expect_timeout(struct context *ctx, const char *reason, va_list ap)
987{
988    va_list ap2;
989    atf_dynstr_t formatted;
990
991    validate_expect(ctx);
992
993    ctx->expect = EXPECT_TIMEOUT;
994    va_copy(ap2, ap);
995    check_fatal_error(atf_dynstr_init_ap(&formatted, reason, ap2));
996    va_end(ap2);
997
998    create_resfile(ctx->resfile, "expected_timeout", -1, &formatted);
999}
1000
1001/* ---------------------------------------------------------------------
1002 * Free functions.
1003 * --------------------------------------------------------------------- */
1004
1005static struct context Current;
1006
1007atf_error_t
1008atf_tc_run(const atf_tc_t *tc, const char *resfile)
1009{
1010    context_init(&Current, tc, resfile);
1011
1012    tc->pimpl->m_body(tc);
1013
1014    validate_expect(&Current);
1015
1016    if (Current.fail_count > 0) {
1017        atf_dynstr_t reason;
1018
1019        format_reason_fmt(&reason, NULL, 0, "%d checks failed; see output for "
1020            "more details", Current.fail_count);
1021        fail_requirement(&Current, &reason);
1022    } else if (Current.expect_fail_count > 0) {
1023        atf_dynstr_t reason;
1024
1025        format_reason_fmt(&reason, NULL, 0, "%d checks failed as expected; "
1026            "see output for more details", Current.expect_fail_count);
1027        expected_failure(&Current, &reason);
1028    } else {
1029        pass(&Current);
1030    }
1031    UNREACHABLE;
1032    return atf_no_error();
1033}
1034
1035atf_error_t
1036atf_tc_cleanup(const atf_tc_t *tc)
1037{
1038    if (tc->pimpl->m_cleanup != NULL)
1039        tc->pimpl->m_cleanup(tc);
1040    return atf_no_error(); /* XXX */
1041}
1042
1043/* ---------------------------------------------------------------------
1044 * Free functions that depend on Current.
1045 * --------------------------------------------------------------------- */
1046
1047/*
1048 * All the functions below provide delegates to other internal functions
1049 * (prefixed by _) that take the current test case as an argument to
1050 * prevent them from accessing global state.  This is to keep the side-
1051 * effects of the internal functions clearer and easier to understand.
1052 *
1053 * The public API should never have hid the fact that it needs access to
1054 * the current test case (other than maybe in the macros), but changing it
1055 * is hard.  TODO: Revisit in the future.
1056 */
1057
1058void
1059atf_tc_fail(const char *fmt, ...)
1060{
1061    va_list ap;
1062
1063    PRE(Current.tc != NULL);
1064
1065    va_start(ap, fmt);
1066    _atf_tc_fail(&Current, fmt, ap);
1067    va_end(ap);
1068}
1069
1070void
1071atf_tc_fail_nonfatal(const char *fmt, ...)
1072{
1073    va_list ap;
1074
1075    PRE(Current.tc != NULL);
1076
1077    va_start(ap, fmt);
1078    _atf_tc_fail_nonfatal(&Current, fmt, ap);
1079    va_end(ap);
1080}
1081
1082void
1083atf_tc_fail_check(const char *file, const size_t line, const char *fmt, ...)
1084{
1085    va_list ap;
1086
1087    PRE(Current.tc != NULL);
1088
1089    va_start(ap, fmt);
1090    _atf_tc_fail_check(&Current, file, line, fmt, ap);
1091    va_end(ap);
1092}
1093
1094void
1095atf_tc_fail_requirement(const char *file, const size_t line,
1096                        const char *fmt, ...)
1097{
1098    va_list ap;
1099
1100    PRE(Current.tc != NULL);
1101
1102    va_start(ap, fmt);
1103    _atf_tc_fail_requirement(&Current, file, line, fmt, ap);
1104    va_end(ap);
1105}
1106
1107void
1108atf_tc_pass(void)
1109{
1110    PRE(Current.tc != NULL);
1111
1112    _atf_tc_pass(&Current);
1113}
1114
1115void
1116atf_tc_require_prog(const char *prog)
1117{
1118    PRE(Current.tc != NULL);
1119
1120    _atf_tc_require_prog(&Current, prog);
1121}
1122
1123void
1124atf_tc_skip(const char *fmt, ...)
1125{
1126    va_list ap;
1127
1128    PRE(Current.tc != NULL);
1129
1130    va_start(ap, fmt);
1131    _atf_tc_skip(&Current, fmt, ap);
1132    va_end(ap);
1133}
1134
1135void
1136atf_tc_check_errno(const char *file, const size_t line, const int exp_errno,
1137                   const char *expr_str, const bool expr_result)
1138{
1139    PRE(Current.tc != NULL);
1140
1141    _atf_tc_check_errno(&Current, file, line, exp_errno, expr_str,
1142                        expr_result);
1143}
1144
1145void
1146atf_tc_require_errno(const char *file, const size_t line, const int exp_errno,
1147                     const char *expr_str, const bool expr_result)
1148{
1149    PRE(Current.tc != NULL);
1150
1151    _atf_tc_require_errno(&Current, file, line, exp_errno, expr_str,
1152                          expr_result);
1153}
1154
1155void
1156atf_tc_expect_pass(void)
1157{
1158    PRE(Current.tc != NULL);
1159
1160    _atf_tc_expect_pass(&Current);
1161}
1162
1163void
1164atf_tc_expect_fail(const char *reason, ...)
1165{
1166    va_list ap;
1167
1168    PRE(Current.tc != NULL);
1169
1170    va_start(ap, reason);
1171    _atf_tc_expect_fail(&Current, reason, ap);
1172    va_end(ap);
1173}
1174
1175void
1176atf_tc_expect_exit(const int exitcode, const char *reason, ...)
1177{
1178    va_list ap;
1179
1180    PRE(Current.tc != NULL);
1181
1182    va_start(ap, reason);
1183    _atf_tc_expect_exit(&Current, exitcode, reason, ap);
1184    va_end(ap);
1185}
1186
1187void
1188atf_tc_expect_signal(const int signo, const char *reason, ...)
1189{
1190    va_list ap;
1191
1192    PRE(Current.tc != NULL);
1193
1194    va_start(ap, reason);
1195    _atf_tc_expect_signal(&Current, signo, reason, ap);
1196    va_end(ap);
1197}
1198
1199void
1200atf_tc_expect_death(const char *reason, ...)
1201{
1202    va_list ap;
1203
1204    PRE(Current.tc != NULL);
1205
1206    va_start(ap, reason);
1207    _atf_tc_expect_death(&Current, reason, ap);
1208    va_end(ap);
1209}
1210
1211void
1212atf_tc_expect_timeout(const char *reason, ...)
1213{
1214    va_list ap;
1215
1216    PRE(Current.tc != NULL);
1217
1218    va_start(ap, reason);
1219    _atf_tc_expect_timeout(&Current, reason, ap);
1220    va_end(ap);
1221}
1222