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