xref: /netbsd/external/bsd/atf/dist/atf-c/tc.c (revision 6550d01e)
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 bool
646 atf_tc_get_config_var_as_bool(const atf_tc_t *tc, const char *name)
647 {
648     bool val;
649     const char *strval;
650     atf_error_t err;
651 
652     strval = atf_tc_get_config_var(tc, name);
653     err = atf_text_to_bool(strval, &val);
654     if (atf_is_error(err)) {
655         atf_error_free(err);
656         atf_tc_fail("Configuration variable %s does not have a valid "
657                     "boolean value; found %s", name, strval);
658     }
659 
660     return val;
661 }
662 
663 bool
664 atf_tc_get_config_var_as_bool_wd(const atf_tc_t *tc, const char *name,
665                                  const bool defval)
666 {
667     bool val;
668 
669     if (!atf_tc_has_config_var(tc, name))
670         val = defval;
671     else
672         val = atf_tc_get_config_var_as_bool(tc, name);
673 
674     return val;
675 }
676 
677 long
678 atf_tc_get_config_var_as_long(const atf_tc_t *tc, const char *name)
679 {
680     long val;
681     const char *strval;
682     atf_error_t err;
683 
684     strval = atf_tc_get_config_var(tc, name);
685     err = atf_text_to_long(strval, &val);
686     if (atf_is_error(err)) {
687         atf_error_free(err);
688         atf_tc_fail("Configuration variable %s does not have a valid "
689                     "long value; found %s", name, strval);
690     }
691 
692     return val;
693 }
694 
695 long
696 atf_tc_get_config_var_as_long_wd(const atf_tc_t *tc, const char *name,
697                                  const long defval)
698 {
699     long val;
700 
701     if (!atf_tc_has_config_var(tc, name))
702         val = defval;
703     else
704         val = atf_tc_get_config_var_as_long(tc, name);
705 
706     return val;
707 }
708 
709 const char *
710 atf_tc_get_md_var(const atf_tc_t *tc, const char *name)
711 {
712     const char *val;
713     atf_map_citer_t iter;
714 
715     PRE(atf_tc_has_md_var(tc, name));
716     iter = atf_map_find_c(&tc->pimpl->m_vars, name);
717     val = atf_map_citer_data(iter);
718     INV(val != NULL);
719 
720     return val;
721 }
722 
723 char **
724 atf_tc_get_md_vars(const atf_tc_t *tc)
725 {
726     return atf_map_to_charpp(&tc->pimpl->m_vars);
727 }
728 
729 bool
730 atf_tc_has_config_var(const atf_tc_t *tc, const char *name)
731 {
732     atf_map_citer_t end, iter;
733 
734     iter = atf_map_find_c(&tc->pimpl->m_config, name);
735     end = atf_map_end_c(&tc->pimpl->m_config);
736     return !atf_equal_map_citer_map_citer(iter, end);
737 }
738 
739 bool
740 atf_tc_has_md_var(const atf_tc_t *tc, const char *name)
741 {
742     atf_map_citer_t end, iter;
743 
744     iter = atf_map_find_c(&tc->pimpl->m_vars, name);
745     end = atf_map_end_c(&tc->pimpl->m_vars);
746     return !atf_equal_map_citer_map_citer(iter, end);
747 }
748 
749 /*
750  * Modifiers.
751  */
752 
753 atf_error_t
754 atf_tc_set_md_var(atf_tc_t *tc, const char *name, const char *fmt, ...)
755 {
756     atf_error_t err;
757     char *value;
758     va_list ap;
759 
760     va_start(ap, fmt);
761     err = atf_text_format_ap(&value, fmt, ap);
762     va_end(ap);
763 
764     if (!atf_is_error(err))
765         err = atf_map_insert(&tc->pimpl->m_vars, name, value, true);
766     else
767         free(value);
768 
769     return err;
770 }
771 
772 /* ---------------------------------------------------------------------
773  * Free functions, as they should be publicly but they can't.
774  * --------------------------------------------------------------------- */
775 
776 static void _atf_tc_fail(struct context *, const char *, va_list)
777     ATF_DEFS_ATTRIBUTE_NORETURN;
778 static void _atf_tc_fail_nonfatal(struct context *, const char *, va_list);
779 static void _atf_tc_fail_check(struct context *, const char *, const size_t,
780     const char *, va_list);
781 static void _atf_tc_fail_requirement(struct context *, const char *,
782     const size_t, const char *, va_list) ATF_DEFS_ATTRIBUTE_NORETURN;
783 static void _atf_tc_pass(struct context *) ATF_DEFS_ATTRIBUTE_NORETURN;
784 static void _atf_tc_require_prog(struct context *, const char *);
785 static void _atf_tc_skip(struct context *, const char *, va_list)
786     ATF_DEFS_ATTRIBUTE_NORETURN;
787 static void _atf_tc_check_errno(struct context *, const char *, const size_t,
788     const int, const char *, const bool);
789 static void _atf_tc_require_errno(struct context *, const char *, const size_t,
790     const int, const char *, const bool);
791 static void _atf_tc_expect_pass(struct context *);
792 static void _atf_tc_expect_fail(struct context *, const char *, va_list);
793 static void _atf_tc_expect_exit(struct context *, const int, const char *,
794     va_list);
795 static void _atf_tc_expect_signal(struct context *, const int, const char *,
796     va_list);
797 static void _atf_tc_expect_death(struct context *, const char *,
798     va_list);
799 
800 static void
801 _atf_tc_fail(struct context *ctx, const char *fmt, va_list ap)
802 {
803     va_list ap2;
804     atf_dynstr_t reason;
805 
806     va_copy(ap2, ap);
807     format_reason_ap(&reason, NULL, 0, fmt, ap2);
808     va_end(ap2);
809 
810     fail_requirement(ctx, &reason);
811     UNREACHABLE;
812 }
813 
814 static void
815 _atf_tc_fail_nonfatal(struct context *ctx, const char *fmt, va_list ap)
816 {
817     va_list ap2;
818     atf_dynstr_t reason;
819 
820     va_copy(ap2, ap);
821     format_reason_ap(&reason, NULL, 0, fmt, ap2);
822     va_end(ap2);
823 
824     fail_check(ctx, &reason);
825 }
826 
827 static void
828 _atf_tc_fail_check(struct context *ctx, const char *file, const size_t line,
829                    const char *fmt, va_list ap)
830 {
831     va_list ap2;
832     atf_dynstr_t reason;
833 
834     va_copy(ap2, ap);
835     format_reason_ap(&reason, file, line, fmt, ap2);
836     va_end(ap2);
837 
838     fail_check(ctx, &reason);
839 }
840 
841 static void
842 _atf_tc_fail_requirement(struct context *ctx, const char *file,
843                          const size_t line, const char *fmt, va_list ap)
844 {
845     va_list ap2;
846     atf_dynstr_t reason;
847 
848     va_copy(ap2, ap);
849     format_reason_ap(&reason, file, line, fmt, ap2);
850     va_end(ap2);
851 
852     fail_requirement(ctx, &reason);
853     UNREACHABLE;
854 }
855 
856 static void
857 _atf_tc_pass(struct context *ctx)
858 {
859     pass(ctx);
860     UNREACHABLE;
861 }
862 
863 static void
864 _atf_tc_require_prog(struct context *ctx, const char *prog)
865 {
866     check_fatal_error(check_prog(ctx, prog, NULL));
867 }
868 
869 static void
870 _atf_tc_skip(struct context *ctx, const char *fmt, va_list ap)
871 {
872     atf_dynstr_t reason;
873     va_list ap2;
874 
875     va_copy(ap2, ap);
876     format_reason_ap(&reason, NULL, 0, fmt, ap2);
877     va_end(ap2);
878 
879     skip(ctx, &reason);
880 }
881 
882 static void
883 _atf_tc_check_errno(struct context *ctx, const char *file, const size_t line,
884                     const int exp_errno, const char *expr_str,
885                     const bool expr_result)
886 {
887     errno_test(ctx, file, line, exp_errno, expr_str, expr_result, fail_check);
888 }
889 
890 static void
891 _atf_tc_require_errno(struct context *ctx, const char *file, const size_t line,
892                       const int exp_errno, const char *expr_str,
893                       const bool expr_result)
894 {
895     errno_test(ctx, file, line, exp_errno, expr_str, expr_result,
896         fail_requirement);
897 }
898 
899 static void
900 _atf_tc_expect_pass(struct context *ctx)
901 {
902     validate_expect(ctx);
903 
904     ctx->expect = EXPECT_PASS;
905 }
906 
907 static void
908 _atf_tc_expect_fail(struct context *ctx, const char *reason, va_list ap)
909 {
910     va_list ap2;
911 
912     validate_expect(ctx);
913 
914     ctx->expect = EXPECT_FAIL;
915     atf_dynstr_fini(&ctx->expect_reason);
916     va_copy(ap2, ap);
917     check_fatal_error(atf_dynstr_init_ap(&ctx->expect_reason, reason, ap2));
918     va_end(ap2);
919     ctx->expect_previous_fail_count = ctx->expect_fail_count;
920 }
921 
922 static void
923 _atf_tc_expect_exit(struct context *ctx, const int exitcode, const char *reason,
924                     va_list ap)
925 {
926     va_list ap2;
927     atf_dynstr_t formatted;
928 
929     validate_expect(ctx);
930 
931     ctx->expect = EXPECT_EXIT;
932     va_copy(ap2, ap);
933     check_fatal_error(atf_dynstr_init_ap(&formatted, reason, ap2));
934     va_end(ap2);
935 
936     create_resfile(ctx->resfile, "expected_exit", exitcode, &formatted);
937 }
938 
939 static void
940 _atf_tc_expect_signal(struct context *ctx, const int signo, const char *reason,
941                       va_list ap)
942 {
943     va_list ap2;
944     atf_dynstr_t formatted;
945 
946     validate_expect(ctx);
947 
948     ctx->expect = EXPECT_SIGNAL;
949     va_copy(ap2, ap);
950     check_fatal_error(atf_dynstr_init_ap(&formatted, reason, ap2));
951     va_end(ap2);
952 
953     create_resfile(ctx->resfile, "expected_signal", signo, &formatted);
954 }
955 
956 static void
957 _atf_tc_expect_death(struct context *ctx, const char *reason, va_list ap)
958 {
959     va_list ap2;
960     atf_dynstr_t formatted;
961 
962     validate_expect(ctx);
963 
964     ctx->expect = EXPECT_DEATH;
965     va_copy(ap2, ap);
966     check_fatal_error(atf_dynstr_init_ap(&formatted, reason, ap2));
967     va_end(ap2);
968 
969     create_resfile(ctx->resfile, "expected_death", -1, &formatted);
970 }
971 
972 static void
973 _atf_tc_expect_timeout(struct context *ctx, const char *reason, va_list ap)
974 {
975     va_list ap2;
976     atf_dynstr_t formatted;
977 
978     validate_expect(ctx);
979 
980     ctx->expect = EXPECT_TIMEOUT;
981     va_copy(ap2, ap);
982     check_fatal_error(atf_dynstr_init_ap(&formatted, reason, ap2));
983     va_end(ap2);
984 
985     create_resfile(ctx->resfile, "expected_timeout", -1, &formatted);
986 }
987 
988 /* ---------------------------------------------------------------------
989  * Free functions.
990  * --------------------------------------------------------------------- */
991 
992 static struct context Current;
993 
994 atf_error_t
995 atf_tc_run(const atf_tc_t *tc, const char *resfile)
996 {
997     context_init(&Current, tc, resfile);
998 
999     tc->pimpl->m_body(tc);
1000 
1001     validate_expect(&Current);
1002 
1003     if (Current.fail_count > 0) {
1004         atf_dynstr_t reason;
1005 
1006         format_reason_fmt(&reason, NULL, 0, "%d checks failed; see output for "
1007             "more details", Current.fail_count);
1008         fail_requirement(&Current, &reason);
1009     } else if (Current.expect_fail_count > 0) {
1010         atf_dynstr_t reason;
1011 
1012         format_reason_fmt(&reason, NULL, 0, "%d checks failed as expected; "
1013             "see output for more details", Current.expect_fail_count);
1014         expected_failure(&Current, &reason);
1015     } else {
1016         pass(&Current);
1017     }
1018     UNREACHABLE;
1019     return atf_no_error();
1020 }
1021 
1022 atf_error_t
1023 atf_tc_cleanup(const atf_tc_t *tc)
1024 {
1025     if (tc->pimpl->m_cleanup != NULL)
1026         tc->pimpl->m_cleanup(tc);
1027     return atf_no_error(); /* XXX */
1028 }
1029 
1030 /* ---------------------------------------------------------------------
1031  * Free functions that depend on Current.
1032  * --------------------------------------------------------------------- */
1033 
1034 /*
1035  * All the functions below provide delegates to other internal functions
1036  * (prefixed by _) that take the current test case as an argument to
1037  * prevent them from accessing global state.  This is to keep the side-
1038  * effects of the internal functions clearer and easier to understand.
1039  *
1040  * The public API should never have hid the fact that it needs access to
1041  * the current test case (other than maybe in the macros), but changing it
1042  * is hard.  TODO: Revisit in the future.
1043  */
1044 
1045 void
1046 atf_tc_fail(const char *fmt, ...)
1047 {
1048     va_list ap;
1049 
1050     PRE(Current.tc != NULL);
1051 
1052     va_start(ap, fmt);
1053     _atf_tc_fail(&Current, fmt, ap);
1054     va_end(ap);
1055 }
1056 
1057 void
1058 atf_tc_fail_nonfatal(const char *fmt, ...)
1059 {
1060     va_list ap;
1061 
1062     PRE(Current.tc != NULL);
1063 
1064     va_start(ap, fmt);
1065     _atf_tc_fail_nonfatal(&Current, fmt, ap);
1066     va_end(ap);
1067 }
1068 
1069 void
1070 atf_tc_fail_check(const char *file, const size_t line, const char *fmt, ...)
1071 {
1072     va_list ap;
1073 
1074     PRE(Current.tc != NULL);
1075 
1076     va_start(ap, fmt);
1077     _atf_tc_fail_check(&Current, file, line, fmt, ap);
1078     va_end(ap);
1079 }
1080 
1081 void
1082 atf_tc_fail_requirement(const char *file, const size_t line,
1083                         const char *fmt, ...)
1084 {
1085     va_list ap;
1086 
1087     PRE(Current.tc != NULL);
1088 
1089     va_start(ap, fmt);
1090     _atf_tc_fail_requirement(&Current, file, line, fmt, ap);
1091     va_end(ap);
1092 }
1093 
1094 void
1095 atf_tc_pass(void)
1096 {
1097     PRE(Current.tc != NULL);
1098 
1099     _atf_tc_pass(&Current);
1100 }
1101 
1102 void
1103 atf_tc_require_prog(const char *prog)
1104 {
1105     PRE(Current.tc != NULL);
1106 
1107     _atf_tc_require_prog(&Current, prog);
1108 }
1109 
1110 void
1111 atf_tc_skip(const char *fmt, ...)
1112 {
1113     va_list ap;
1114 
1115     PRE(Current.tc != NULL);
1116 
1117     va_start(ap, fmt);
1118     _atf_tc_skip(&Current, fmt, ap);
1119     va_end(ap);
1120 }
1121 
1122 void
1123 atf_tc_check_errno(const char *file, const size_t line, const int exp_errno,
1124                    const char *expr_str, const bool expr_result)
1125 {
1126     PRE(Current.tc != NULL);
1127 
1128     _atf_tc_check_errno(&Current, file, line, exp_errno, expr_str,
1129                         expr_result);
1130 }
1131 
1132 void
1133 atf_tc_require_errno(const char *file, const size_t line, const int exp_errno,
1134                      const char *expr_str, const bool expr_result)
1135 {
1136     PRE(Current.tc != NULL);
1137 
1138     _atf_tc_require_errno(&Current, file, line, exp_errno, expr_str,
1139                           expr_result);
1140 }
1141 
1142 void
1143 atf_tc_expect_pass(void)
1144 {
1145     PRE(Current.tc != NULL);
1146 
1147     _atf_tc_expect_pass(&Current);
1148 }
1149 
1150 void
1151 atf_tc_expect_fail(const char *reason, ...)
1152 {
1153     va_list ap;
1154 
1155     PRE(Current.tc != NULL);
1156 
1157     va_start(ap, reason);
1158     _atf_tc_expect_fail(&Current, reason, ap);
1159     va_end(ap);
1160 }
1161 
1162 void
1163 atf_tc_expect_exit(const int exitcode, const char *reason, ...)
1164 {
1165     va_list ap;
1166 
1167     PRE(Current.tc != NULL);
1168 
1169     va_start(ap, reason);
1170     _atf_tc_expect_exit(&Current, exitcode, reason, ap);
1171     va_end(ap);
1172 }
1173 
1174 void
1175 atf_tc_expect_signal(const int signo, const char *reason, ...)
1176 {
1177     va_list ap;
1178 
1179     PRE(Current.tc != NULL);
1180 
1181     va_start(ap, reason);
1182     _atf_tc_expect_signal(&Current, signo, reason, ap);
1183     va_end(ap);
1184 }
1185 
1186 void
1187 atf_tc_expect_death(const char *reason, ...)
1188 {
1189     va_list ap;
1190 
1191     PRE(Current.tc != NULL);
1192 
1193     va_start(ap, reason);
1194     _atf_tc_expect_death(&Current, reason, ap);
1195     va_end(ap);
1196 }
1197 
1198 void
1199 atf_tc_expect_timeout(const char *reason, ...)
1200 {
1201     va_list ap;
1202 
1203     PRE(Current.tc != NULL);
1204 
1205     va_start(ap, reason);
1206     _atf_tc_expect_timeout(&Current, reason, ap);
1207     va_end(ap);
1208 }
1209