1 // Copyright 2010 The Kyua Authors. 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 #include "utils/test_utils.ipp" 46 47 namespace fs = utils::fs; 48 namespace process = utils::process; 49 50 51 #define FILE_REGEXP __FILE__ ":[0-9]+: " 52 53 54 static const fs::path Stdout_File("stdout.txt"); 55 static const fs::path Stderr_File("stderr.txt"); 56 57 58 #if NDEBUG 59 static bool NDebug = true; 60 #else 61 static bool NDebug = false; 62 #endif 63 64 65 template< typename Function > 66 static process::status 67 run_test(Function function) 68 { 69 utils::avoid_coredump_on_crash(); 70 71 const process::status status = process::child::fork_files( 72 function, Stdout_File, Stderr_File)->wait(); 73 atf::utils::cat_file(Stdout_File.str(), "Helper stdout: "); 74 atf::utils::cat_file(Stderr_File.str(), "Helper stderr: "); 75 return status; 76 } 77 78 79 static void 80 verify_success(const process::status& status) 81 { 82 ATF_REQUIRE(status.exited()); 83 ATF_REQUIRE_EQ(EXIT_SUCCESS, status.exitstatus()); 84 ATF_REQUIRE(atf::utils::grep_file("Before test", Stdout_File.str())); 85 ATF_REQUIRE(atf::utils::grep_file("After test", Stdout_File.str())); 86 } 87 88 89 static void 90 verify_failed(const process::status& status, const char* type, 91 const char* exp_message, const bool check_ndebug) 92 { 93 if (check_ndebug && NDebug) { 94 std::cout << "Built with NDEBUG; skipping verification\n"; 95 verify_success(status); 96 } else { 97 ATF_REQUIRE(status.signaled()); 98 ATF_REQUIRE_EQ(SIGABRT, status.termsig()); 99 ATF_REQUIRE(atf::utils::grep_file("Before test", Stdout_File.str())); 100 ATF_REQUIRE(!atf::utils::grep_file("After test", Stdout_File.str())); 101 if (exp_message != NULL) 102 ATF_REQUIRE(atf::utils::grep_file(F(FILE_REGEXP "%s: %s") % 103 type % exp_message, 104 Stderr_File.str())); 105 else 106 ATF_REQUIRE(atf::utils::grep_file(F(FILE_REGEXP "%s") % type, 107 Stderr_File.str())); 108 } 109 } 110 111 112 template< bool Expression, bool WithMessage > 113 static void 114 do_inv_test(void) 115 { 116 std::cout << "Before test\n"; 117 if (WithMessage) 118 INV_MSG(Expression, "Custom message"); 119 else 120 INV(Expression); 121 std::cout << "After test\n"; 122 std::exit(EXIT_SUCCESS); 123 } 124 125 126 ATF_TEST_CASE_WITHOUT_HEAD(inv__holds); 127 ATF_TEST_CASE_BODY(inv__holds) 128 { 129 const process::status status = run_test(do_inv_test< true, false >); 130 verify_success(status); 131 } 132 133 134 ATF_TEST_CASE_WITHOUT_HEAD(inv__triggers_default_message); 135 ATF_TEST_CASE_BODY(inv__triggers_default_message) 136 { 137 const process::status status = run_test(do_inv_test< false, false >); 138 verify_failed(status, "Invariant check failed", "Expression", true); 139 } 140 141 142 ATF_TEST_CASE_WITHOUT_HEAD(inv__triggers_custom_message); 143 ATF_TEST_CASE_BODY(inv__triggers_custom_message) 144 { 145 const process::status status = run_test(do_inv_test< false, true >); 146 verify_failed(status, "Invariant check failed", "Custom", true); 147 } 148 149 150 template< bool Expression, bool WithMessage > 151 static void 152 do_pre_test(void) 153 { 154 std::cout << "Before test\n"; 155 if (WithMessage) 156 PRE_MSG(Expression, "Custom message"); 157 else 158 PRE(Expression); 159 std::cout << "After test\n"; 160 std::exit(EXIT_SUCCESS); 161 } 162 163 164 ATF_TEST_CASE_WITHOUT_HEAD(pre__holds); 165 ATF_TEST_CASE_BODY(pre__holds) 166 { 167 const process::status status = run_test(do_pre_test< true, false >); 168 verify_success(status); 169 } 170 171 172 ATF_TEST_CASE_WITHOUT_HEAD(pre__triggers_default_message); 173 ATF_TEST_CASE_BODY(pre__triggers_default_message) 174 { 175 const process::status status = run_test(do_pre_test< false, false >); 176 verify_failed(status, "Precondition check failed", "Expression", true); 177 } 178 179 180 ATF_TEST_CASE_WITHOUT_HEAD(pre__triggers_custom_message); 181 ATF_TEST_CASE_BODY(pre__triggers_custom_message) 182 { 183 const process::status status = run_test(do_pre_test< false, true >); 184 verify_failed(status, "Precondition check failed", "Custom", true); 185 } 186 187 188 template< bool Expression, bool WithMessage > 189 static void 190 do_post_test(void) 191 { 192 std::cout << "Before test\n"; 193 if (WithMessage) 194 POST_MSG(Expression, "Custom message"); 195 else 196 POST(Expression); 197 std::cout << "After test\n"; 198 std::exit(EXIT_SUCCESS); 199 } 200 201 202 ATF_TEST_CASE_WITHOUT_HEAD(post__holds); 203 ATF_TEST_CASE_BODY(post__holds) 204 { 205 const process::status status = run_test(do_post_test< true, false >); 206 verify_success(status); 207 } 208 209 210 ATF_TEST_CASE_WITHOUT_HEAD(post__triggers_default_message); 211 ATF_TEST_CASE_BODY(post__triggers_default_message) 212 { 213 const process::status status = run_test(do_post_test< false, false >); 214 verify_failed(status, "Postcondition check failed", "Expression", true); 215 } 216 217 218 ATF_TEST_CASE_WITHOUT_HEAD(post__triggers_custom_message); 219 ATF_TEST_CASE_BODY(post__triggers_custom_message) 220 { 221 const process::status status = run_test(do_post_test< false, true >); 222 verify_failed(status, "Postcondition check failed", "Custom", true); 223 } 224 225 226 template< bool WithMessage > 227 static void 228 do_unreachable_test(void) 229 { 230 std::cout << "Before test\n"; 231 if (WithMessage) 232 UNREACHABLE_MSG("Custom message"); 233 else 234 UNREACHABLE; 235 std::cout << "After test\n"; 236 std::exit(EXIT_SUCCESS); 237 } 238 239 240 ATF_TEST_CASE_WITHOUT_HEAD(unreachable__default_message); 241 ATF_TEST_CASE_BODY(unreachable__default_message) 242 { 243 const process::status status = run_test(do_unreachable_test< false >); 244 verify_failed(status, "Unreachable point reached", NULL, false); 245 } 246 247 248 ATF_TEST_CASE_WITHOUT_HEAD(unreachable__custom_message); 249 ATF_TEST_CASE_BODY(unreachable__custom_message) 250 { 251 const process::status status = run_test(do_unreachable_test< true >); 252 verify_failed(status, "Unreachable point reached", "Custom", false); 253 } 254 255 256 template< int Signo > 257 static void 258 do_crash_handler_test(void) 259 { 260 utils::install_crash_handlers("test-log.txt"); 261 ::kill(::getpid(), Signo); 262 std::cout << "After signal\n"; 263 std::exit(EXIT_FAILURE); 264 } 265 266 267 template< int Signo > 268 static void 269 crash_handler_test(void) 270 { 271 utils::avoid_coredump_on_crash(); 272 273 const process::status status = run_test(do_crash_handler_test< Signo >); 274 ATF_REQUIRE(status.signaled()); 275 ATF_REQUIRE_EQ(Signo, status.termsig()); 276 ATF_REQUIRE(atf::utils::grep_file(F("Fatal signal %s") % Signo, 277 Stderr_File.str())); 278 ATF_REQUIRE(atf::utils::grep_file("Log file is test-log.txt", 279 Stderr_File.str())); 280 ATF_REQUIRE(!atf::utils::grep_file("After signal", Stdout_File.str())); 281 } 282 283 284 ATF_TEST_CASE_WITHOUT_HEAD(install_crash_handlers__sigabrt); 285 ATF_TEST_CASE_BODY(install_crash_handlers__sigabrt) 286 { 287 crash_handler_test< SIGABRT >(); 288 } 289 290 291 ATF_TEST_CASE_WITHOUT_HEAD(install_crash_handlers__sigbus); 292 ATF_TEST_CASE_BODY(install_crash_handlers__sigbus) 293 { 294 crash_handler_test< SIGBUS >(); 295 } 296 297 298 ATF_TEST_CASE_WITHOUT_HEAD(install_crash_handlers__sigsegv); 299 ATF_TEST_CASE_BODY(install_crash_handlers__sigsegv) 300 { 301 crash_handler_test< SIGSEGV >(); 302 } 303 304 305 ATF_INIT_TEST_CASES(tcs) 306 { 307 ATF_ADD_TEST_CASE(tcs, inv__holds); 308 ATF_ADD_TEST_CASE(tcs, inv__triggers_default_message); 309 ATF_ADD_TEST_CASE(tcs, inv__triggers_custom_message); 310 ATF_ADD_TEST_CASE(tcs, pre__holds); 311 ATF_ADD_TEST_CASE(tcs, pre__triggers_default_message); 312 ATF_ADD_TEST_CASE(tcs, pre__triggers_custom_message); 313 ATF_ADD_TEST_CASE(tcs, post__holds); 314 ATF_ADD_TEST_CASE(tcs, post__triggers_default_message); 315 ATF_ADD_TEST_CASE(tcs, post__triggers_custom_message); 316 ATF_ADD_TEST_CASE(tcs, unreachable__default_message); 317 ATF_ADD_TEST_CASE(tcs, unreachable__custom_message); 318 319 ATF_ADD_TEST_CASE(tcs, install_crash_handlers__sigabrt); 320 ATF_ADD_TEST_CASE(tcs, install_crash_handlers__sigbus); 321 ATF_ADD_TEST_CASE(tcs, install_crash_handlers__sigsegv); 322 } 323