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
53 enum expect_type {
54 EXPECT_PASS,
55 EXPECT_FAIL,
56 EXPECT_EXIT,
57 EXPECT_SIGNAL,
58 EXPECT_DEATH,
59 EXPECT_TIMEOUT,
60 };
61
62 struct 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
75 static void context_init(struct context *, const atf_tc_t *, const char *);
76 static void check_fatal_error(atf_error_t);
77 static void report_fatal_error(const char *, ...)
78 ATF_DEFS_ATTRIBUTE_NORETURN;
79 static atf_error_t write_resfile(const int, const char *, const int,
80 const atf_dynstr_t *);
81 static void create_resfile(const char *, const char *, const int,
82 atf_dynstr_t *);
83 static void error_in_expect(struct context *, const char *, ...)
84 ATF_DEFS_ATTRIBUTE_NORETURN;
85 static void validate_expect(struct context *);
86 static void expected_failure(struct context *, atf_dynstr_t *)
87 ATF_DEFS_ATTRIBUTE_NORETURN;
88 static void fail_requirement(struct context *, atf_dynstr_t *)
89 ATF_DEFS_ATTRIBUTE_NORETURN;
90 static void fail_check(struct context *, atf_dynstr_t *);
91 static void pass(struct context *)
92 ATF_DEFS_ATTRIBUTE_NORETURN;
93 static void skip(struct context *, atf_dynstr_t *)
94 ATF_DEFS_ATTRIBUTE_NORETURN;
95 static void format_reason_ap(atf_dynstr_t *, const char *, const size_t,
96 const char *, va_list);
97 static void format_reason_fmt(atf_dynstr_t *, const char *, const size_t,
98 const char *, ...);
99 static void errno_test(struct context *, const char *, const size_t,
100 const int, const char *, const bool,
101 void (*)(struct context *, atf_dynstr_t *));
102 static atf_error_t check_prog_in_dir(const char *, void *);
103 static atf_error_t check_prog(struct context *, const char *);
104
105 static void
context_init(struct context * ctx,const atf_tc_t * tc,const char * resfile)106 context_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
119 static void
check_fatal_error(atf_error_t err)120 check_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
131 static void
report_fatal_error(const char * msg,...)132 report_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 */
152 static atf_error_t
write_resfile(const int fd,const char * result,const int arg,const atf_dynstr_t * reason)153 write_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 */
204 static void
create_resfile(const char * resfile,const char * result,const int arg,atf_dynstr_t * reason)205 create_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. */
233 static void
error_in_expect(struct context * ctx,const char * fmt,...)234 error_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 */
251 static void
validate_expect(struct context * ctx)252 validate_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
278 static void
expected_failure(struct context * ctx,atf_dynstr_t * reason)279 expected_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
287 static void
fail_requirement(struct context * ctx,atf_dynstr_t * reason)288 fail_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
302 static void
fail_check(struct context * ctx,atf_dynstr_t * reason)303 fail_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
321 static void
pass(struct context * ctx)322 pass(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
337 static void
skip(struct context * ctx,atf_dynstr_t * reason)338 skip(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 */
362 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)363 format_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
387 static void
format_reason_fmt(atf_dynstr_t * out_reason,const char * source_file,const size_t source_line,const char * reason,...)388 format_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
399 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 *))400 errno_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
424 struct prog_found_pair {
425 const char *prog;
426 bool found;
427 };
428
429 static atf_error_t
check_prog_in_dir(const char * dir,void * data)430 check_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
453 out_p:
454 atf_fs_path_fini(&p);
455 }
456
457 return err;
458 }
459
460 static atf_error_t
check_prog(struct context * ctx,const char * prog)461 check_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
515 out_bp:
516 atf_fs_path_fini(&bp);
517 }
518
519 out_p:
520 atf_fs_path_fini(&p);
521 out:
522 return err;
523 }
524
525 /* ---------------------------------------------------------------------
526 * The "atf_tc" type.
527 * --------------------------------------------------------------------- */
528
529 struct 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
544 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)545 atf_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
593 err_map:
594 atf_map_fini(&tc->pimpl->m_vars);
595 err_vars:
596 atf_map_fini(&tc->pimpl->m_config);
597 err:
598 return err;
599 }
600
601 atf_error_t
atf_tc_init_pack(atf_tc_t * tc,const atf_tc_pack_t * pack,const char * const * config)602 atf_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
609 void
atf_tc_fini(atf_tc_t * tc)610 atf_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
620 const char *
atf_tc_get_ident(const atf_tc_t * tc)621 atf_tc_get_ident(const atf_tc_t *tc)
622 {
623 return tc->pimpl->m_ident;
624 }
625
626 const char *
atf_tc_get_config_var(const atf_tc_t * tc,const char * name)627 atf_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
640 const char *
atf_tc_get_config_var_wd(const atf_tc_t * tc,const char * name,const char * defval)641 atf_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
654 bool
atf_tc_get_config_var_as_bool(const atf_tc_t * tc,const char * name)655 atf_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
672 bool
atf_tc_get_config_var_as_bool_wd(const atf_tc_t * tc,const char * name,const bool defval)673 atf_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
686 long
atf_tc_get_config_var_as_long(const atf_tc_t * tc,const char * name)687 atf_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
704 long
atf_tc_get_config_var_as_long_wd(const atf_tc_t * tc,const char * name,const long defval)705 atf_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
718 const char *
atf_tc_get_md_var(const atf_tc_t * tc,const char * name)719 atf_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
732 char **
atf_tc_get_md_vars(const atf_tc_t * tc)733 atf_tc_get_md_vars(const atf_tc_t *tc)
734 {
735 return atf_map_to_charpp(&tc->pimpl->m_vars);
736 }
737
738 bool
atf_tc_has_config_var(const atf_tc_t * tc,const char * name)739 atf_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
748 bool
atf_tc_has_md_var(const atf_tc_t * tc,const char * name)749 atf_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
762 atf_error_t
atf_tc_set_md_var(atf_tc_t * tc,const char * name,const char * fmt,...)763 atf_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
785 static void _atf_tc_fail(struct context *, const char *, va_list)
786 ATF_DEFS_ATTRIBUTE_NORETURN;
787 static void _atf_tc_fail_nonfatal(struct context *, const char *, va_list);
788 static void _atf_tc_fail_check(struct context *, const char *, const size_t,
789 const char *, va_list);
790 static void _atf_tc_fail_requirement(struct context *, const char *,
791 const size_t, const char *, va_list) ATF_DEFS_ATTRIBUTE_NORETURN;
792 static void _atf_tc_pass(struct context *) ATF_DEFS_ATTRIBUTE_NORETURN;
793 static void _atf_tc_require_prog(struct context *, const char *);
794 static void _atf_tc_skip(struct context *, const char *, va_list)
795 ATF_DEFS_ATTRIBUTE_NORETURN;
796 static void _atf_tc_check_errno(struct context *, const char *, const size_t,
797 const int, const char *, const bool);
798 static void _atf_tc_require_errno(struct context *, const char *, const size_t,
799 const int, const char *, const bool);
800 static void _atf_tc_expect_pass(struct context *);
801 static void _atf_tc_expect_fail(struct context *, const char *, va_list);
802 static void _atf_tc_expect_exit(struct context *, const int, const char *,
803 va_list);
804 static void _atf_tc_expect_signal(struct context *, const int, const char *,
805 va_list);
806 static void _atf_tc_expect_death(struct context *, const char *,
807 va_list);
808
809 static void
_atf_tc_fail(struct context * ctx,const char * fmt,va_list ap)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
823 static void
_atf_tc_fail_nonfatal(struct context * ctx,const char * fmt,va_list ap)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
836 static void
_atf_tc_fail_check(struct context * ctx,const char * file,const size_t line,const char * fmt,va_list ap)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
850 static void
_atf_tc_fail_requirement(struct context * ctx,const char * file,const size_t line,const char * fmt,va_list ap)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
865 static void
_atf_tc_pass(struct context * ctx)866 _atf_tc_pass(struct context *ctx)
867 {
868 pass(ctx);
869 UNREACHABLE;
870 }
871
872 static void
_atf_tc_require_prog(struct context * ctx,const char * prog)873 _atf_tc_require_prog(struct context *ctx, const char *prog)
874 {
875 check_fatal_error(check_prog(ctx, prog));
876 }
877
878 static void
_atf_tc_skip(struct context * ctx,const char * fmt,va_list ap)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
891 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)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
899 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)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
908 static void
_atf_tc_expect_pass(struct context * ctx)909 _atf_tc_expect_pass(struct context *ctx)
910 {
911 validate_expect(ctx);
912
913 ctx->expect = EXPECT_PASS;
914 }
915
916 static void
_atf_tc_expect_fail(struct context * ctx,const char * reason,va_list ap)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
931 static void
_atf_tc_expect_exit(struct context * ctx,const int exitcode,const char * reason,va_list ap)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
948 static void
_atf_tc_expect_signal(struct context * ctx,const int signo,const char * reason,va_list ap)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
965 static void
_atf_tc_expect_death(struct context * ctx,const char * reason,va_list ap)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
981 static void
_atf_tc_expect_timeout(struct context * ctx,const char * reason,va_list ap)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
1001 static struct context Current;
1002
1003 atf_error_t
atf_tc_run(const atf_tc_t * tc,const char * resfile)1004 atf_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
1031 atf_error_t
atf_tc_cleanup(const atf_tc_t * tc)1032 atf_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
1054 void
atf_tc_fail(const char * fmt,...)1055 atf_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
1066 void
atf_tc_fail_nonfatal(const char * fmt,...)1067 atf_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
1078 void
atf_tc_fail_check(const char * file,const size_t line,const char * fmt,...)1079 atf_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
1090 void
atf_tc_fail_requirement(const char * file,const size_t line,const char * fmt,...)1091 atf_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
1103 void
atf_tc_pass(void)1104 atf_tc_pass(void)
1105 {
1106 PRE(Current.tc != NULL);
1107
1108 _atf_tc_pass(&Current);
1109 }
1110
1111 void
atf_tc_require_prog(const char * prog)1112 atf_tc_require_prog(const char *prog)
1113 {
1114 PRE(Current.tc != NULL);
1115
1116 _atf_tc_require_prog(&Current, prog);
1117 }
1118
1119 void
atf_tc_skip(const char * fmt,...)1120 atf_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
1131 void
atf_tc_check_errno(const char * file,const size_t line,const int exp_errno,const char * expr_str,const bool expr_result)1132 atf_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
1141 void
atf_tc_require_errno(const char * file,const size_t line,const int exp_errno,const char * expr_str,const bool expr_result)1142 atf_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
1151 void
atf_tc_expect_pass(void)1152 atf_tc_expect_pass(void)
1153 {
1154 PRE(Current.tc != NULL);
1155
1156 _atf_tc_expect_pass(&Current);
1157 }
1158
1159 void
atf_tc_expect_fail(const char * reason,...)1160 atf_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
1171 void
atf_tc_expect_exit(const int exitcode,const char * reason,...)1172 atf_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
1183 void
atf_tc_expect_signal(const int signo,const char * reason,...)1184 atf_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
1195 void
atf_tc_expect_death(const char * reason,...)1196 atf_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
1207 void
atf_tc_expect_timeout(const char * reason,...)1208 atf_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