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