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