1/*
2 * Automated Testing Framework (atf)
3 *
4 * Copyright (c) 2008 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#if defined(HAVE_CONFIG_H)
31#include "bconfig.h"
32#endif
33
34#include <sys/types.h>
35#include <sys/wait.h>
36
37#include <signal.h>
38#include <stdbool.h>
39#include <stdlib.h>
40#include <string.h>
41#include <unistd.h>
42
43#include <atf-c.h>
44
45#include "dynstr.h"
46#include "process.h"
47#include "sanity.h"
48#include "test_helpers.h"
49
50/* ---------------------------------------------------------------------
51 * Auxiliary functions.
52 * --------------------------------------------------------------------- */
53
54enum type { inv, pre, post, unreachable };
55
56struct test_data {
57    enum type m_type;
58    bool m_cond;
59};
60
61static void do_test_child(void *) ATF_DEFS_ATTRIBUTE_NORETURN;
62
63static
64void
65do_test_child(void *v)
66{
67    struct test_data *td = v;
68
69    switch (td->m_type) {
70    case inv:
71        INV(td->m_cond);
72        break;
73
74    case pre:
75        PRE(td->m_cond);
76        break;
77
78    case post:
79        POST(td->m_cond);
80        break;
81
82    case unreachable:
83        if (!td->m_cond)
84            UNREACHABLE;
85        break;
86    }
87
88    exit(EXIT_SUCCESS);
89}
90
91static
92void
93do_test(enum type t, bool cond)
94{
95    atf_process_child_t child;
96    atf_process_status_t status;
97    int nlines;
98    char *lines[3];
99
100    {
101        atf_process_stream_t outsb, errsb;
102        struct test_data td = { t, cond };
103
104        RE(atf_process_stream_init_inherit(&outsb));
105        RE(atf_process_stream_init_capture(&errsb));
106        RE(atf_process_fork(&child, do_test_child, &outsb, &errsb, &td));
107        atf_process_stream_fini(&errsb);
108        atf_process_stream_fini(&outsb);
109    }
110
111    nlines = 0;
112    while (nlines < 3 && (lines[nlines] =
113           atf_utils_readline(atf_process_child_stderr(&child))) != NULL)
114        nlines++;
115    ATF_REQUIRE(nlines == 0 || nlines == 3);
116
117    RE(atf_process_child_wait(&child, &status));
118    if (!cond) {
119        ATF_REQUIRE(atf_process_status_signaled(&status));
120        ATF_REQUIRE(atf_process_status_termsig(&status) == SIGABRT);
121    } else {
122        ATF_REQUIRE(atf_process_status_exited(&status));
123        ATF_REQUIRE(atf_process_status_exitstatus(&status) == EXIT_SUCCESS);
124    }
125    atf_process_status_fini(&status);
126
127    if (!cond) {
128        switch (t) {
129        case inv:
130            ATF_REQUIRE(atf_utils_grep_string("Invariant", lines[0]));
131            break;
132
133        case pre:
134            ATF_REQUIRE(atf_utils_grep_string("Precondition", lines[0]));
135            break;
136
137        case post:
138            ATF_REQUIRE(atf_utils_grep_string("Postcondition", lines[0]));
139            break;
140
141        case unreachable:
142            ATF_REQUIRE(atf_utils_grep_string("Invariant", lines[0]));
143            break;
144        }
145
146        ATF_REQUIRE(atf_utils_grep_string(__FILE__, lines[0]));
147        ATF_REQUIRE(atf_utils_grep_string(PACKAGE_BUGREPORT, lines[2]));
148    }
149
150    while (nlines > 0) {
151        nlines--;
152        free(lines[nlines]);
153    }
154}
155
156static
157void
158require_ndebug(void)
159{
160#if defined(NDEBUG)
161    atf_tc_skip("Sanity checks not available; code built with -DNDEBUG");
162#endif
163}
164
165/* ---------------------------------------------------------------------
166 * Test cases for the free functions.
167 * --------------------------------------------------------------------- */
168
169ATF_TC(inv);
170ATF_TC_HEAD(inv, tc)
171{
172    atf_tc_set_md_var(tc, "descr", "Tests the INV macro");
173}
174ATF_TC_BODY(inv, tc)
175{
176    require_ndebug();
177
178    do_test(inv, false);
179    do_test(inv, true);
180}
181
182ATF_TC(pre);
183ATF_TC_HEAD(pre, tc)
184{
185    atf_tc_set_md_var(tc, "descr", "Tests the PRE macro");
186}
187ATF_TC_BODY(pre, tc)
188{
189    require_ndebug();
190
191    do_test(pre, false);
192    do_test(pre, true);
193}
194
195ATF_TC(post);
196ATF_TC_HEAD(post, tc)
197{
198    atf_tc_set_md_var(tc, "descr", "Tests the POST macro");
199}
200ATF_TC_BODY(post, tc)
201{
202    require_ndebug();
203
204    do_test(post, false);
205    do_test(post, true);
206}
207
208ATF_TC(unreachable);
209ATF_TC_HEAD(unreachable, tc)
210{
211    atf_tc_set_md_var(tc, "descr", "Tests the UNREACHABLE macro");
212}
213ATF_TC_BODY(unreachable, tc)
214{
215    require_ndebug();
216
217    do_test(unreachable, false);
218    do_test(unreachable, true);
219}
220
221/* ---------------------------------------------------------------------
222 * Main.
223 * --------------------------------------------------------------------- */
224
225ATF_TP_ADD_TCS(tp)
226{
227    ATF_TP_ADD_TC(tp, inv);
228    ATF_TP_ADD_TC(tp, pre);
229    ATF_TP_ADD_TC(tp, post);
230    ATF_TP_ADD_TC(tp, unreachable);
231
232    return atf_no_error();
233}
234