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