Home | History | Annotate | Line # | Download | only in atf-c
tc.c revision 1.12
      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 
     57 enum expect_type {
     58     EXPECT_PASS,
     59     EXPECT_FAIL,
     60     EXPECT_EXIT,
     61     EXPECT_SIGNAL,
     62     EXPECT_DEATH,
     63     EXPECT_TIMEOUT,
     64 };
     65 
     66 struct 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 
     79 static void context_init(struct context *, const atf_tc_t *, const char *);
     80 static void check_fatal_error(atf_error_t);
     81 static void report_fatal_error(const char *, ...)
     82     ATF_DEFS_ATTRIBUTE_NORETURN;
     83 static atf_error_t write_resfile(const int, const char *, const int,
     84                                  const atf_dynstr_t *);
     85 static void create_resfile(const char *, const char *, const int,
     86                            atf_dynstr_t *);
     87 static void error_in_expect(struct context *, const char *, ...)
     88     ATF_DEFS_ATTRIBUTE_NORETURN;
     89 static void validate_expect(struct context *);
     90 static void expected_failure(struct context *, atf_dynstr_t *)
     91     ATF_DEFS_ATTRIBUTE_NORETURN;
     92 static void fail_requirement(struct context *, atf_dynstr_t *)
     93     ATF_DEFS_ATTRIBUTE_NORETURN;
     94 static void fail_check(struct context *, atf_dynstr_t *);
     95 static void pass(struct context *)
     96     ATF_DEFS_ATTRIBUTE_NORETURN;
     97 static void skip(struct context *, atf_dynstr_t *)
     98     ATF_DEFS_ATTRIBUTE_NORETURN;
     99 static void format_reason_ap(atf_dynstr_t *, const char *, const size_t,
    100                              const char *, va_list);
    101 static void format_reason_fmt(atf_dynstr_t *, const char *, const size_t,
    102                               const char *, ...);
    103 static void errno_test(struct context *, const char *, const size_t,
    104                        const int, const char *, const bool,
    105                        void (*)(struct context *, atf_dynstr_t *));
    106 static atf_error_t check_prog_in_dir(const char *, void *);
    107 static atf_error_t check_prog(struct context *, const char *);
    108 
    109 static void
    110 context_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 
    123 static void
    124 check_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 
    135 static void
    136 report_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  */
    156 static atf_error_t
    157 write_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  */
    208 static void
    209 create_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. */
    237 static void
    238 error_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  */
    255 static void
    256 validate_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 
    282 static void
    283 expected_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 
    291 static void
    292 fail_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 
    306 static void
    307 fail_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 
    325 static void
    326 pass(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 
    341 static void
    342 skip(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  */
    366 static void
    367 format_reason_ap(atf_dynstr_t *out_reason,
    368                  const char *source_file, const size_t source_line,
    369                  const char *reason, va_list ap)
    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 
    391 static void
    392 format_reason_fmt(atf_dynstr_t *out_reason,
    393                   const char *source_file, const size_t source_line,
    394                   const char *reason, ...)
    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 
    403 static void
    404 errno_test(struct context *ctx, const char *file, const size_t line,
    405            const int exp_errno, const char *expr_str,
    406            const bool expr_result,
    407            void (*fail_func)(struct context *, atf_dynstr_t *))
    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 
    428 struct prog_found_pair {
    429     const char *prog;
    430     bool found;
    431 };
    432 
    433 static atf_error_t
    434 check_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 
    457 out_p:
    458         atf_fs_path_fini(&p);
    459     }
    460 
    461     return err;
    462 }
    463 
    464 static atf_error_t
    465 check_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 
    519 out_bp:
    520         atf_fs_path_fini(&bp);
    521     }
    522 
    523 out_p:
    524     atf_fs_path_fini(&p);
    525 out:
    526     return err;
    527 }
    528 
    529 /* ---------------------------------------------------------------------
    530  * The "atf_tc" type.
    531  * --------------------------------------------------------------------- */
    532 
    533 struct 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 
    548 atf_error_t
    549 atf_tc_init(atf_tc_t *tc, const char *ident, atf_tc_head_t head,
    550             atf_tc_body_t body, atf_tc_cleanup_t cleanup,
    551             const char *const *config)
    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 
    597 err_map:
    598     atf_map_fini(&tc->pimpl->m_vars);
    599 err_vars:
    600     atf_map_fini(&tc->pimpl->m_config);
    601 err:
    602     return err;
    603 }
    604 
    605 atf_error_t
    606 atf_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 
    613 void
    614 atf_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 
    624 const char *
    625 atf_tc_get_ident(const atf_tc_t *tc)
    626 {
    627     return tc->pimpl->m_ident;
    628 }
    629 
    630 const char *
    631 atf_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 
    644 const char *
    645 atf_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 
    658 bool
    659 atf_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 
    676 bool
    677 atf_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 
    690 long
    691 atf_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 
    708 long
    709 atf_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 
    722 const char *
    723 atf_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 
    736 char **
    737 atf_tc_get_md_vars(const atf_tc_t *tc)
    738 {
    739     return atf_map_to_charpp(&tc->pimpl->m_vars);
    740 }
    741 
    742 bool
    743 atf_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 
    752 bool
    753 atf_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 
    766 atf_error_t
    767 atf_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 
    789 static void _atf_tc_fail(struct context *, const char *, va_list)
    790     ATF_DEFS_ATTRIBUTE_NORETURN;
    791 static void _atf_tc_fail_nonfatal(struct context *, const char *, va_list);
    792 static void _atf_tc_fail_check(struct context *, const char *, const size_t,
    793     const char *, va_list);
    794 static void _atf_tc_fail_requirement(struct context *, const char *,
    795     const size_t, const char *, va_list) ATF_DEFS_ATTRIBUTE_NORETURN;
    796 static void _atf_tc_pass(struct context *) ATF_DEFS_ATTRIBUTE_NORETURN;
    797 static void _atf_tc_require_prog(struct context *, const char *);
    798 static void _atf_tc_skip(struct context *, const char *, va_list)
    799     ATF_DEFS_ATTRIBUTE_NORETURN;
    800 static void _atf_tc_check_errno(struct context *, const char *, const size_t,
    801     const int, const char *, const bool);
    802 static void _atf_tc_require_errno(struct context *, const char *, const size_t,
    803     const int, const char *, const bool);
    804 static void _atf_tc_expect_pass(struct context *);
    805 static void _atf_tc_expect_fail(struct context *, const char *, va_list);
    806 static void _atf_tc_expect_exit(struct context *, const int, const char *,
    807     va_list);
    808 static void _atf_tc_expect_signal(struct context *, const int, const char *,
    809     va_list);
    810 static void _atf_tc_expect_death(struct context *, const char *,
    811     va_list);
    812 
    813 static 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 
    827 static 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 
    840 static void
    841 _atf_tc_fail_check(struct context *ctx, const char *file, const size_t line,
    842                    const char *fmt, va_list ap)
    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 
    854 static void
    855 _atf_tc_fail_requirement(struct context *ctx, const char *file,
    856                          const size_t line, const char *fmt, va_list ap)
    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 
    869 static void
    870 _atf_tc_pass(struct context *ctx)
    871 {
    872     pass(ctx);
    873     UNREACHABLE;
    874 }
    875 
    876 static void
    877 _atf_tc_require_prog(struct context *ctx, const char *prog)
    878 {
    879     check_fatal_error(check_prog(ctx, prog));
    880 }
    881 
    882 static 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 
    895 static void
    896 _atf_tc_check_errno(struct context *ctx, const char *file, const size_t line,
    897                     const int exp_errno, const char *expr_str,
    898                     const bool expr_result)
    899 {
    900     errno_test(ctx, file, line, exp_errno, expr_str, expr_result, fail_check);
    901 }
    902 
    903 static void
    904 _atf_tc_require_errno(struct context *ctx, const char *file, const size_t line,
    905                       const int exp_errno, const char *expr_str,
    906                       const bool expr_result)
    907 {
    908     errno_test(ctx, file, line, exp_errno, expr_str, expr_result,
    909         fail_requirement);
    910 }
    911 
    912 static void
    913 _atf_tc_expect_pass(struct context *ctx)
    914 {
    915     validate_expect(ctx);
    916 
    917     ctx->expect = EXPECT_PASS;
    918 }
    919 
    920 static 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 
    935 static 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 
    952 static 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 
    969 static 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 
    985 static 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 
   1005 static struct context Current;
   1006 
   1007 atf_error_t
   1008 atf_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 
   1035 atf_error_t
   1036 atf_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 
   1058 void
   1059 atf_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 
   1070 void
   1071 atf_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 
   1082 void
   1083 atf_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 
   1094 void
   1095 atf_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 
   1107 void
   1108 atf_tc_pass(void)
   1109 {
   1110     PRE(Current.tc != NULL);
   1111 
   1112     _atf_tc_pass(&Current);
   1113 }
   1114 
   1115 void
   1116 atf_tc_require_prog(const char *prog)
   1117 {
   1118     PRE(Current.tc != NULL);
   1119 
   1120     _atf_tc_require_prog(&Current, prog);
   1121 }
   1122 
   1123 void
   1124 atf_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 
   1135 void
   1136 atf_tc_check_errno(const char *file, const size_t line, const int exp_errno,
   1137                    const char *expr_str, const bool expr_result)
   1138 {
   1139     PRE(Current.tc != NULL);
   1140 
   1141     _atf_tc_check_errno(&Current, file, line, exp_errno, expr_str,
   1142                         expr_result);
   1143 }
   1144 
   1145 void
   1146 atf_tc_require_errno(const char *file, const size_t line, const int exp_errno,
   1147                      const char *expr_str, const bool expr_result)
   1148 {
   1149     PRE(Current.tc != NULL);
   1150 
   1151     _atf_tc_require_errno(&Current, file, line, exp_errno, expr_str,
   1152                           expr_result);
   1153 }
   1154 
   1155 void
   1156 atf_tc_expect_pass(void)
   1157 {
   1158     PRE(Current.tc != NULL);
   1159 
   1160     _atf_tc_expect_pass(&Current);
   1161 }
   1162 
   1163 void
   1164 atf_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 
   1175 void
   1176 atf_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 
   1187 void
   1188 atf_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 
   1199 void
   1200 atf_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 
   1211 void
   1212 atf_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