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 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 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 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); 167 ATF_TC_HEAD(inv, tc) 168 { 169 atf_tc_set_md_var(tc, "descr", "Tests the INV macro"); 170 } 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); 180 ATF_TC_HEAD(pre, tc) 181 { 182 atf_tc_set_md_var(tc, "descr", "Tests the PRE macro"); 183 } 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); 193 ATF_TC_HEAD(post, tc) 194 { 195 atf_tc_set_md_var(tc, "descr", "Tests the POST macro"); 196 } 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); 206 ATF_TC_HEAD(unreachable, tc) 207 { 208 atf_tc_set_md_var(tc, "descr", "Tests the UNREACHABLE macro"); 209 } 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 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