xref: /netbsd-src/external/bsd/kyua-cli/dist/utils/sanity_test.cpp (revision 6b3a42af15b5e090c339512c790dd68f3d11a9d8)
1 // Copyright 2010 Google 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 are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 //   notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright
11 //   notice, this list of conditions and the following disclaimer in the
12 //   documentation and/or other materials provided with the distribution.
13 // * Neither the name of Google Inc. nor the names of its contributors
14 //   may be used to endorse or promote products derived from this software
15 //   without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 
29 #include "utils/sanity.hpp"
30 
31 extern "C" {
32 #include <signal.h>
33 #include <unistd.h>
34 }
35 
36 #include <cstdlib>
37 #include <iostream>
38 
39 #include <atf-c++.hpp>
40 
41 #include "utils/format/macros.hpp"
42 #include "utils/fs/path.hpp"
43 #include "utils/process/child.ipp"
44 #include "utils/process/status.hpp"
45 
46 namespace fs = utils::fs;
47 namespace process = utils::process;
48 
49 
50 #define FILE_REGEXP __FILE__ ":[0-9]+: "
51 
52 
53 static const fs::path Stdout_File("stdout.txt");
54 static const fs::path Stderr_File("stderr.txt");
55 
56 
57 #if NDEBUG
58 static bool NDebug = true;
59 #else
60 static bool NDebug = false;
61 #endif
62 
63 
64 template< typename Function >
65 static process::status
run_test(Function function)66 run_test(Function function)
67 {
68     const process::status status = process::child::fork_files(
69         function, Stdout_File, Stderr_File)->wait();
70     atf::utils::cat_file(Stdout_File.str(), "Helper stdout: ");
71     atf::utils::cat_file(Stderr_File.str(), "Helper stderr: ");
72     return status;
73 }
74 
75 
76 static void
verify_success(const process::status & status)77 verify_success(const process::status& status)
78 {
79     ATF_REQUIRE(status.exited());
80     ATF_REQUIRE_EQ(EXIT_SUCCESS, status.exitstatus());
81     ATF_REQUIRE(atf::utils::grep_file("Before test", Stdout_File.str()));
82     ATF_REQUIRE(atf::utils::grep_file("After test", Stdout_File.str()));
83 }
84 
85 
86 static void
verify_failed(const process::status & status,const char * type,const char * exp_message,const bool check_ndebug)87 verify_failed(const process::status& status, const char* type,
88               const char* exp_message, const bool check_ndebug)
89 {
90     if (check_ndebug && NDebug) {
91         std::cout << "Built with NDEBUG; skipping verification\n";
92         verify_success(status);
93     } else {
94         ATF_REQUIRE(status.signaled());
95         ATF_REQUIRE_EQ(SIGABRT, status.termsig());
96         ATF_REQUIRE(atf::utils::grep_file("Before test", Stdout_File.str()));
97         ATF_REQUIRE(!atf::utils::grep_file("After test", Stdout_File.str()));
98         if (exp_message != NULL)
99             ATF_REQUIRE(atf::utils::grep_file(F(FILE_REGEXP "%s: %s") %
100                                               type % exp_message,
101                                               Stderr_File.str()));
102         else
103             ATF_REQUIRE(atf::utils::grep_file(F(FILE_REGEXP "%s") % type,
104                                               Stderr_File.str()));
105     }
106 }
107 
108 
109 template< bool Expression, bool WithMessage >
110 static void
do_inv_test(void)111 do_inv_test(void)
112 {
113     std::cout << "Before test\n";
114     if (WithMessage)
115         INV_MSG(Expression, "Custom message");
116     else
117         INV(Expression);
118     std::cout << "After test\n";
119     std::exit(EXIT_SUCCESS);
120 }
121 
122 
123 ATF_TEST_CASE_WITHOUT_HEAD(inv__holds);
ATF_TEST_CASE_BODY(inv__holds)124 ATF_TEST_CASE_BODY(inv__holds)
125 {
126     const process::status status = run_test(do_inv_test< true, false >);
127     verify_success(status);
128 }
129 
130 
131 ATF_TEST_CASE_WITHOUT_HEAD(inv__triggers_default_message);
ATF_TEST_CASE_BODY(inv__triggers_default_message)132 ATF_TEST_CASE_BODY(inv__triggers_default_message)
133 {
134     const process::status status = run_test(do_inv_test< false, false >);
135     verify_failed(status, "Invariant check failed", "Expression", true);
136 }
137 
138 
139 ATF_TEST_CASE_WITHOUT_HEAD(inv__triggers_custom_message);
ATF_TEST_CASE_BODY(inv__triggers_custom_message)140 ATF_TEST_CASE_BODY(inv__triggers_custom_message)
141 {
142     const process::status status = run_test(do_inv_test< false, true >);
143     verify_failed(status, "Invariant check failed", "Custom", true);
144 }
145 
146 
147 template< bool Expression, bool WithMessage >
148 static void
do_pre_test(void)149 do_pre_test(void)
150 {
151     std::cout << "Before test\n";
152     if (WithMessage)
153         PRE_MSG(Expression, "Custom message");
154     else
155         PRE(Expression);
156     std::cout << "After test\n";
157     std::exit(EXIT_SUCCESS);
158 }
159 
160 
161 ATF_TEST_CASE_WITHOUT_HEAD(pre__holds);
ATF_TEST_CASE_BODY(pre__holds)162 ATF_TEST_CASE_BODY(pre__holds)
163 {
164     const process::status status = run_test(do_pre_test< true, false >);
165     verify_success(status);
166 }
167 
168 
169 ATF_TEST_CASE_WITHOUT_HEAD(pre__triggers_default_message);
ATF_TEST_CASE_BODY(pre__triggers_default_message)170 ATF_TEST_CASE_BODY(pre__triggers_default_message)
171 {
172     const process::status status = run_test(do_pre_test< false, false >);
173     verify_failed(status, "Precondition check failed", "Expression", true);
174 }
175 
176 
177 ATF_TEST_CASE_WITHOUT_HEAD(pre__triggers_custom_message);
ATF_TEST_CASE_BODY(pre__triggers_custom_message)178 ATF_TEST_CASE_BODY(pre__triggers_custom_message)
179 {
180     const process::status status = run_test(do_pre_test< false, true >);
181     verify_failed(status, "Precondition check failed", "Custom", true);
182 }
183 
184 
185 template< bool Expression, bool WithMessage >
186 static void
do_post_test(void)187 do_post_test(void)
188 {
189     std::cout << "Before test\n";
190     if (WithMessage)
191         POST_MSG(Expression, "Custom message");
192     else
193         POST(Expression);
194     std::cout << "After test\n";
195     std::exit(EXIT_SUCCESS);
196 }
197 
198 
199 ATF_TEST_CASE_WITHOUT_HEAD(post__holds);
ATF_TEST_CASE_BODY(post__holds)200 ATF_TEST_CASE_BODY(post__holds)
201 {
202     const process::status status = run_test(do_post_test< true, false >);
203     verify_success(status);
204 }
205 
206 
207 ATF_TEST_CASE_WITHOUT_HEAD(post__triggers_default_message);
ATF_TEST_CASE_BODY(post__triggers_default_message)208 ATF_TEST_CASE_BODY(post__triggers_default_message)
209 {
210     const process::status status = run_test(do_post_test< false, false >);
211     verify_failed(status, "Postcondition check failed", "Expression", true);
212 }
213 
214 
215 ATF_TEST_CASE_WITHOUT_HEAD(post__triggers_custom_message);
ATF_TEST_CASE_BODY(post__triggers_custom_message)216 ATF_TEST_CASE_BODY(post__triggers_custom_message)
217 {
218     const process::status status = run_test(do_post_test< false, true >);
219     verify_failed(status, "Postcondition check failed", "Custom", true);
220 }
221 
222 
223 template< bool WithMessage >
224 static void
do_unreachable_test(void)225 do_unreachable_test(void)
226 {
227     std::cout << "Before test\n";
228     if (WithMessage)
229         UNREACHABLE_MSG("Custom message");
230     else
231         UNREACHABLE;
232     std::cout << "After test\n";
233     std::exit(EXIT_SUCCESS);
234 }
235 
236 
237 ATF_TEST_CASE_WITHOUT_HEAD(unreachable__default_message);
ATF_TEST_CASE_BODY(unreachable__default_message)238 ATF_TEST_CASE_BODY(unreachable__default_message)
239 {
240     const process::status status = run_test(do_unreachable_test< false >);
241     verify_failed(status, "Unreachable point reached", NULL, false);
242 }
243 
244 
245 ATF_TEST_CASE_WITHOUT_HEAD(unreachable__custom_message);
ATF_TEST_CASE_BODY(unreachable__custom_message)246 ATF_TEST_CASE_BODY(unreachable__custom_message)
247 {
248     const process::status status = run_test(do_unreachable_test< true >);
249     verify_failed(status, "Unreachable point reached", "Custom", false);
250 }
251 
252 
253 template< int Signo >
254 static void
do_crash_handler_test(void)255 do_crash_handler_test(void)
256 {
257     utils::install_crash_handlers("test-log.txt");
258     ::kill(::getpid(), Signo);
259     std::cout << "After signal\n";
260     std::exit(EXIT_FAILURE);
261 }
262 
263 
264 template< int Signo >
265 static void
crash_handler_test(void)266 crash_handler_test(void)
267 {
268     const process::status status = run_test(do_crash_handler_test< Signo >);
269     ATF_REQUIRE(status.signaled());
270     ATF_REQUIRE_EQ(Signo, status.termsig());
271     ATF_REQUIRE(atf::utils::grep_file(F("Fatal signal %s") % Signo,
272                                       Stderr_File.str()));
273     ATF_REQUIRE(atf::utils::grep_file("Log file is test-log.txt",
274                                       Stderr_File.str()));
275     ATF_REQUIRE(!atf::utils::grep_file("After signal", Stdout_File.str()));
276 }
277 
278 
279 ATF_TEST_CASE_WITHOUT_HEAD(install_crash_handlers__sigabrt);
ATF_TEST_CASE_BODY(install_crash_handlers__sigabrt)280 ATF_TEST_CASE_BODY(install_crash_handlers__sigabrt)
281 {
282     crash_handler_test< SIGABRT >();
283 }
284 
285 
286 ATF_TEST_CASE_WITHOUT_HEAD(install_crash_handlers__sigbus);
ATF_TEST_CASE_BODY(install_crash_handlers__sigbus)287 ATF_TEST_CASE_BODY(install_crash_handlers__sigbus)
288 {
289     crash_handler_test< SIGBUS >();
290 }
291 
292 
293 ATF_TEST_CASE_WITHOUT_HEAD(install_crash_handlers__sigsegv);
ATF_TEST_CASE_BODY(install_crash_handlers__sigsegv)294 ATF_TEST_CASE_BODY(install_crash_handlers__sigsegv)
295 {
296     crash_handler_test< SIGSEGV >();
297 }
298 
299 
ATF_INIT_TEST_CASES(tcs)300 ATF_INIT_TEST_CASES(tcs)
301 {
302     ATF_ADD_TEST_CASE(tcs, inv__holds);
303     ATF_ADD_TEST_CASE(tcs, inv__triggers_default_message);
304     ATF_ADD_TEST_CASE(tcs, inv__triggers_custom_message);
305     ATF_ADD_TEST_CASE(tcs, pre__holds);
306     ATF_ADD_TEST_CASE(tcs, pre__triggers_default_message);
307     ATF_ADD_TEST_CASE(tcs, pre__triggers_custom_message);
308     ATF_ADD_TEST_CASE(tcs, post__holds);
309     ATF_ADD_TEST_CASE(tcs, post__triggers_default_message);
310     ATF_ADD_TEST_CASE(tcs, post__triggers_custom_message);
311     ATF_ADD_TEST_CASE(tcs, unreachable__default_message);
312     ATF_ADD_TEST_CASE(tcs, unreachable__custom_message);
313 
314     ATF_ADD_TEST_CASE(tcs, install_crash_handlers__sigabrt);
315     ATF_ADD_TEST_CASE(tcs, install_crash_handlers__sigbus);
316     ATF_ADD_TEST_CASE(tcs, install_crash_handlers__sigsegv);
317 }
318