xref: /freebsd/contrib/atf/atf-c/detail/sanity_test.c (revision c6ec7d31830ab1c80edae95ad5e4b9dba10c47ac)
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 
54 enum type { inv, pre, post, unreachable };
55 
56 static
57 bool
58 grep(const atf_dynstr_t *line, const char *text)
59 {
60     const char *l = atf_dynstr_cstring(line);
61     bool found;
62 
63     found = false;
64 
65     if (strstr(l, text) != NULL)
66         found = true;
67 
68     return found;
69 }
70 
71 struct test_data {
72     enum type m_type;
73     bool m_cond;
74 };
75 
76 static void do_test_child(void *) ATF_DEFS_ATTRIBUTE_NORETURN;
77 
78 static
79 void
80 do_test_child(void *v)
81 {
82     struct test_data *td = v;
83 
84     switch (td->m_type) {
85     case inv:
86         INV(td->m_cond);
87         break;
88 
89     case pre:
90         PRE(td->m_cond);
91         break;
92 
93     case post:
94         POST(td->m_cond);
95         break;
96 
97     case unreachable:
98         if (!td->m_cond)
99             UNREACHABLE;
100         break;
101     }
102 
103     exit(EXIT_SUCCESS);
104 }
105 
106 static
107 void
108 do_test(enum type t, bool cond)
109 {
110     atf_process_child_t child;
111     atf_process_status_t status;
112     bool eof;
113     int nlines;
114     atf_dynstr_t lines[3];
115 
116     {
117         atf_process_stream_t outsb, errsb;
118         struct test_data td = { t, cond };
119 
120         RE(atf_process_stream_init_inherit(&outsb));
121         RE(atf_process_stream_init_capture(&errsb));
122         RE(atf_process_fork(&child, do_test_child, &outsb, &errsb, &td));
123         atf_process_stream_fini(&errsb);
124         atf_process_stream_fini(&outsb);
125     }
126 
127     nlines = 0;
128     eof = false;
129     do {
130         RE(atf_dynstr_init(&lines[nlines]));
131         if (!eof)
132             eof = read_line(atf_process_child_stderr(&child), &lines[nlines]);
133         nlines++;
134     } while (nlines < 3);
135     ATF_REQUIRE(nlines == 0 || nlines == 3);
136 
137     RE(atf_process_child_wait(&child, &status));
138     if (!cond) {
139         ATF_REQUIRE(atf_process_status_signaled(&status));
140         ATF_REQUIRE(atf_process_status_termsig(&status) == SIGABRT);
141     } else {
142         ATF_REQUIRE(atf_process_status_exited(&status));
143         ATF_REQUIRE(atf_process_status_exitstatus(&status) == EXIT_SUCCESS);
144     }
145     atf_process_status_fini(&status);
146 
147     if (!cond) {
148         switch (t) {
149         case inv:
150             ATF_REQUIRE(grep(&lines[0], "Invariant"));
151             break;
152 
153         case pre:
154             ATF_REQUIRE(grep(&lines[0], "Precondition"));
155             break;
156 
157         case post:
158             ATF_REQUIRE(grep(&lines[0], "Postcondition"));
159             break;
160 
161         case unreachable:
162             ATF_REQUIRE(grep(&lines[0], "Invariant"));
163             break;
164         }
165 
166         ATF_REQUIRE(grep(&lines[0], __FILE__));
167         ATF_REQUIRE(grep(&lines[2], PACKAGE_BUGREPORT));
168     }
169 
170     while (nlines > 0) {
171         nlines--;
172         atf_dynstr_fini(&lines[nlines]);
173     }
174 }
175 
176 static
177 void
178 require_ndebug(void)
179 {
180 #if defined(NDEBUG)
181     atf_tc_skip("Sanity checks not available; code built with -DNDEBUG");
182 #endif
183 }
184 
185 /* ---------------------------------------------------------------------
186  * Test cases for the free functions.
187  * --------------------------------------------------------------------- */
188 
189 ATF_TC(inv);
190 ATF_TC_HEAD(inv, tc)
191 {
192     atf_tc_set_md_var(tc, "descr", "Tests the INV macro");
193 }
194 ATF_TC_BODY(inv, tc)
195 {
196     require_ndebug();
197 
198     do_test(inv, false);
199     do_test(inv, true);
200 }
201 
202 ATF_TC(pre);
203 ATF_TC_HEAD(pre, tc)
204 {
205     atf_tc_set_md_var(tc, "descr", "Tests the PRE macro");
206 }
207 ATF_TC_BODY(pre, tc)
208 {
209     require_ndebug();
210 
211     do_test(pre, false);
212     do_test(pre, true);
213 }
214 
215 ATF_TC(post);
216 ATF_TC_HEAD(post, tc)
217 {
218     atf_tc_set_md_var(tc, "descr", "Tests the POST macro");
219 }
220 ATF_TC_BODY(post, tc)
221 {
222     require_ndebug();
223 
224     do_test(post, false);
225     do_test(post, true);
226 }
227 
228 ATF_TC(unreachable);
229 ATF_TC_HEAD(unreachable, tc)
230 {
231     atf_tc_set_md_var(tc, "descr", "Tests the UNREACHABLE macro");
232 }
233 ATF_TC_BODY(unreachable, tc)
234 {
235     require_ndebug();
236 
237     do_test(unreachable, false);
238     do_test(unreachable, true);
239 }
240 
241 /* ---------------------------------------------------------------------
242  * Main.
243  * --------------------------------------------------------------------- */
244 
245 ATF_TP_ADD_TCS(tp)
246 {
247     ATF_TP_ADD_TC(tp, inv);
248     ATF_TP_ADD_TC(tp, pre);
249     ATF_TP_ADD_TC(tp, post);
250     ATF_TP_ADD_TC(tp, unreachable);
251 
252     return atf_no_error();
253 }
254