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