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