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