1 1.4 christos # $NetBSD: t_set_e.sh,v 1.4 2016/03/31 16:22:27 christos Exp $ 2 1.1 jruoho # 3 1.1 jruoho # Copyright (c) 2007 The NetBSD Foundation, Inc. 4 1.1 jruoho # All rights reserved. 5 1.1 jruoho # 6 1.1 jruoho # Redistribution and use in source and binary forms, with or without 7 1.1 jruoho # modification, are permitted provided that the following conditions 8 1.1 jruoho # are met: 9 1.1 jruoho # 1. Redistributions of source code must retain the above copyright 10 1.1 jruoho # notice, this list of conditions and the following disclaimer. 11 1.1 jruoho # 2. Redistributions in binary form must reproduce the above copyright 12 1.1 jruoho # notice, this list of conditions and the following disclaimer in the 13 1.1 jruoho # documentation and/or other materials provided with the distribution. 14 1.1 jruoho # 15 1.1 jruoho # THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 16 1.1 jruoho # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 17 1.1 jruoho # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 1.1 jruoho # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 19 1.1 jruoho # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 1.1 jruoho # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 1.1 jruoho # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 1.1 jruoho # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 1.1 jruoho # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 1.1 jruoho # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 1.1 jruoho # POSSIBILITY OF SUCH DAMAGE. 26 1.1 jruoho # 27 1.1 jruoho 28 1.1 jruoho # references: 29 1.1 jruoho # http://www.opengroup.org/onlinepubs/009695399/utilities/set.html 30 1.1 jruoho # http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html 31 1.1 jruoho 32 1.1 jruoho # the implementation of "sh" to test 33 1.2 christos : ${TEST_SH:="/bin/sh"} 34 1.1 jruoho 35 1.1 jruoho failwith() 36 1.1 jruoho { 37 1.1 jruoho case "$SH_FAILS" in 38 1.1 jruoho "") SH_FAILS=`echo "$1"`;; 39 1.1 jruoho *) SH_FAILS="$SH_FAILS"`echo; echo "$1"`;; 40 1.1 jruoho esac 41 1.1 jruoho } 42 1.1 jruoho 43 1.1 jruoho check1() 44 1.1 jruoho { 45 1.1 jruoho #echo "$TEST_SH -c $1" 46 1.1 jruoho result=`$TEST_SH -c "$1" 2>/dev/null | tr '\n' ' ' | sed 's/ *$//'` 47 1.1 jruoho if [ "$result" != "$2" ]; then 48 1.1 jruoho MSG=`printf "%-56s %-8s %s" "$3" "$result" "$2"` 49 1.1 jruoho failwith "$MSG" 50 1.1 jruoho failcount=`expr $failcount + 1` 51 1.1 jruoho fi 52 1.1 jruoho count=`expr $count + 1` 53 1.1 jruoho } 54 1.1 jruoho 55 1.1 jruoho # direct check: try the given expression. 56 1.1 jruoho dcheck() 57 1.1 jruoho { 58 1.1 jruoho check1 "$1" "$2" "$1" 59 1.1 jruoho } 60 1.1 jruoho 61 1.1 jruoho # eval check: indirect through eval. 62 1.1 jruoho # as of this writing, this changes the behavior pretty drastically and 63 1.1 jruoho # is thus important to test. (PR bin/29861) 64 1.1 jruoho echeck() 65 1.1 jruoho { 66 1.4 christos check1 'eval '"'( $1 )'" "$2" "eval '($1)'" 67 1.1 jruoho } 68 1.1 jruoho 69 1.1 jruoho atf_test_case all 70 1.1 jruoho all_head() { 71 1.1 jruoho atf_set "descr" "Tests that 'set -e' works correctly" 72 1.1 jruoho } 73 1.1 jruoho all_body() { 74 1.1 jruoho count=0 75 1.1 jruoho failcount=0 76 1.1 jruoho 77 1.1 jruoho # make sure exiting from a subshell behaves as expected 78 1.1 jruoho dcheck '(set -e; exit 1; echo ERR$?); echo OK$?' 'OK1' 79 1.1 jruoho echeck '(set -e; exit 1; echo ERR$?); echo OK$?' 'OK1' 80 1.1 jruoho 81 1.1 jruoho # first, check basic functioning. 82 1.1 jruoho # The ERR shouldn't print; the result of the () should be 1. 83 1.1 jruoho # Henceforth we'll assume that we don't need to check $?. 84 1.3 christos dcheck '(set -e; false; echo ERR$?); echo OK$?' 'OK1' 85 1.3 christos echeck '(set -e; false; echo ERR$?); echo OK$?' 'OK1' 86 1.1 jruoho 87 1.1 jruoho # these cases should be equivalent to the preceding. 88 1.1 jruoho dcheck '(set -e; /nonexistent; echo ERR); echo OK' 'OK' 89 1.1 jruoho echeck '(set -e; /nonexistent; echo ERR); echo OK' 'OK' 90 1.1 jruoho dcheck '(set -e; nonexistent-program-on-path; echo ERR); echo OK' 'OK' 91 1.1 jruoho echeck '(set -e; nonexistent-program-on-path; echo ERR); echo OK' 'OK' 92 1.1 jruoho dcheck 'f() { false; }; (set -e; f; echo ERR); echo OK' 'OK' 93 1.1 jruoho echeck 'f() { false; }; (set -e; f; echo ERR); echo OK' 'OK' 94 1.1 jruoho dcheck 'f() { return 1; }; (set -e; f; echo ERR); echo OK' 'OK' 95 1.1 jruoho echeck 'f() { return 1; }; (set -e; f; echo ERR); echo OK' 'OK' 96 1.1 jruoho 97 1.1 jruoho # but! with set -e, the false should cause an *immediate* exit. 98 1.1 jruoho # The return form should not, as such, but there's no way to 99 1.1 jruoho # distinguish it. 100 1.1 jruoho dcheck 'f() { false; echo ERR; }; (set -e; f); echo OK' 'OK' 101 1.1 jruoho echeck 'f() { false; echo ERR; }; (set -e; f); echo OK' 'OK' 102 1.1 jruoho 103 1.1 jruoho # set is not scoped, so these should not exit at all. 104 1.1 jruoho dcheck 'f() { set +e; false; echo OK; }; (set -e; f); echo OK' 'OK OK' 105 1.1 jruoho echeck 'f() { set +e; false; echo OK; }; (set -e; f); echo OK' 'OK OK' 106 1.1 jruoho 107 1.1 jruoho # according to the standard, only failing *simple* commands 108 1.1 jruoho # cause an exit under -e. () is not a simple command. 109 1.1 jruoho # Correct (per POSIX): 110 1.1 jruoho #dcheck '(set -e; (set +e; false; echo OK; false); echo OK)' 'OK OK' 111 1.1 jruoho #echeck '(set -e; (set +e; false; echo OK; false); echo OK)' 'OK OK' 112 1.1 jruoho # Wrong current behavior: 113 1.1 jruoho dcheck '(set -e; (set +e; false; echo OK; false); echo OK)' 'OK' 114 1.1 jruoho echeck '(set -e; (set +e; false; echo OK; false); echo OK)' 'OK' 115 1.1 jruoho 116 1.1 jruoho # make sure an inner nested shell does exit though. 117 1.1 jruoho dcheck '(set -e; (false; echo ERR)); echo OK' 'OK' 118 1.1 jruoho 119 1.1 jruoho # The left hand side of an || or && is explicitly tested and 120 1.1 jruoho # thus should not cause an exit. Furthermore, because a || or 121 1.1 jruoho # && expression is not a simple command, there should be no 122 1.1 jruoho # exit even if the overall result is false. 123 1.1 jruoho dcheck '(set -e; false || true; echo OK); echo OK' 'OK OK' 124 1.1 jruoho echeck '(set -e; false || true; echo OK); echo OK' 'OK OK' 125 1.1 jruoho dcheck '(set -e; false && true; echo OK); echo OK' 'OK OK' 126 1.1 jruoho echeck '(set -e; false && true; echo OK); echo OK' 'OK OK' 127 1.1 jruoho 128 1.1 jruoho # However, the right hand side is not tested, so a failure 129 1.1 jruoho # there *should* cause an exit, regardless of whether it 130 1.1 jruoho # appears inside a non-simple command. 131 1.1 jruoho # 132 1.1 jruoho # Note that in at least one place the standard does not 133 1.1 jruoho # distinguish between the left and right hand sides of 134 1.1 jruoho # logical operators. It is possible that for strict 135 1.1 jruoho # compliance these need to not exit; however, if so that 136 1.1 jruoho # should probably be limited to when some strict-posix setting 137 1.1 jruoho # is in effect and tested accordingly. 138 1.1 jruoho # 139 1.1 jruoho dcheck '(set -e; false || false; echo ERR); echo OK' 'OK' 140 1.1 jruoho dcheck '(set -e; true && false; echo ERR); echo OK' 'OK' 141 1.1 jruoho echeck '(set -e; false || false; echo ERR); echo OK' 'OK' 142 1.1 jruoho echeck '(set -e; true && false; echo ERR); echo OK' 'OK' 143 1.1 jruoho 144 1.1 jruoho # correct: 145 1.1 jruoho #dcheck '(set -e; false && false; echo ERR); echo OK' 'OK' 146 1.1 jruoho #echeck '(set -e; false && false; echo ERR); echo OK' 'OK' 147 1.1 jruoho 148 1.1 jruoho # wrong current behavior: 149 1.1 jruoho dcheck '(set -e; false && false; echo ERR); echo OK' 'ERR OK' 150 1.1 jruoho echeck '(set -e; false && false; echo ERR); echo OK' 'ERR OK' 151 1.1 jruoho 152 1.1 jruoho # A failure that is not reached because of short-circuit 153 1.1 jruoho # evaluation should not cause an exit, however. 154 1.1 jruoho dcheck '(set -e; true || false; echo OK); echo OK' 'OK OK' 155 1.1 jruoho echeck '(set -e; true || false; echo OK); echo OK' 'OK OK' 156 1.1 jruoho 157 1.1 jruoho # For completeness, test the other two combinations. 158 1.1 jruoho dcheck '(set -e; true || true; echo OK); echo OK' 'OK OK' 159 1.1 jruoho dcheck '(set -e; true && true; echo OK); echo OK' 'OK OK' 160 1.1 jruoho echeck '(set -e; true || true; echo OK); echo OK' 'OK OK' 161 1.1 jruoho echeck '(set -e; true && true; echo OK); echo OK' 'OK OK' 162 1.1 jruoho 163 1.1 jruoho # likewise, none of these should exit. 164 1.1 jruoho dcheck '(set -e; while false; do :; done; echo OK); echo OK' 'OK OK' 165 1.1 jruoho dcheck '(set -e; if false; then :; fi; echo OK); echo OK' 'OK OK' 166 1.1 jruoho # problematic :-) 167 1.1 jruoho #dcheck '(set -e; until false; do :; done; echo OK); echo OK' 'OK OK' 168 1.1 jruoho dcheck '(set -e; until [ "$t" = 1 ]; do t=1; done; echo OK); echo OK' \ 169 1.1 jruoho 'OK OK' 170 1.1 jruoho echeck '(set -e; while false; do :; done; echo OK); echo OK' 'OK OK' 171 1.1 jruoho echeck '(set -e; if false; then :; fi; echo OK); echo OK' 'OK OK' 172 1.1 jruoho echeck '(set -e; until [ "$t" = 1 ]; do t=1; done; echo OK); echo OK' \ 173 1.1 jruoho 'OK OK' 174 1.1 jruoho 175 1.1 jruoho # the bang operator tests its argument and thus the argument 176 1.1 jruoho # should not cause an exit. it is also not a simple command (I 177 1.1 jruoho # believe) so it also shouldn't exit even if it yields a false 178 1.1 jruoho # result. 179 1.1 jruoho dcheck '(set -e; ! false; echo OK); echo OK' 'OK OK' 180 1.1 jruoho dcheck '(set -e; ! true; echo OK); echo OK' 'OK OK' 181 1.1 jruoho echeck '(set -e; ! false; echo OK); echo OK' 'OK OK' 182 1.1 jruoho echeck '(set -e; ! true; echo OK); echo OK' 'OK OK' 183 1.1 jruoho 184 1.1 jruoho # combined case with () and &&; the inner expression is false 185 1.1 jruoho # but does not itself exit, and the () should not cause an 186 1.1 jruoho # exit even when failing. 187 1.1 jruoho # correct: 188 1.1 jruoho #dcheck '(set -e; (false && true); echo OK); echo OK' 'OK OK' 189 1.1 jruoho #echeck '(set -e; (false && true); echo OK); echo OK' 'OK OK' 190 1.1 jruoho # wrong current behavior: 191 1.1 jruoho dcheck '(set -e; (false && true); echo OK); echo OK' 'OK' 192 1.1 jruoho echeck '(set -e; (false && true); echo OK); echo OK' 'OK' 193 1.1 jruoho 194 1.1 jruoho # pipelines. only the right-hand end is significant. 195 1.1 jruoho dcheck '(set -e; false | true; echo OK); echo OK' 'OK OK' 196 1.1 jruoho echeck '(set -e; false | true; echo OK); echo OK' 'OK OK' 197 1.1 jruoho dcheck '(set -e; true | false; echo ERR); echo OK' 'OK' 198 1.1 jruoho echeck '(set -e; true | false; echo ERR); echo OK' 'OK' 199 1.1 jruoho 200 1.1 jruoho dcheck '(set -e; while true | false; do :; done; echo OK); echo OK' \ 201 1.1 jruoho 'OK OK' 202 1.1 jruoho dcheck '(set -e; if true | false; then :; fi; echo OK); echo OK' \ 203 1.1 jruoho 'OK OK' 204 1.1 jruoho 205 1.1 jruoho 206 1.1 jruoho # According to dsl@ in PR bin/32282, () is not defined as a 207 1.1 jruoho # subshell, only as a grouping operator [and a scope, I guess] 208 1.2 christos 209 1.2 christos # (This is incorrect. () is definitely a sub-shell) 210 1.2 christos 211 1.1 jruoho # so the nested false ought to cause the whole shell to exit, 212 1.1 jruoho # not just the subshell. dholland@ would like to see C&V, 213 1.1 jruoho # because that seems like a bad idea. (Among other things, it 214 1.1 jruoho # would break all the above test logic, which relies on being 215 1.1 jruoho # able to isolate set -e behavior inside ().) However, I'm 216 1.1 jruoho # going to put these tests here to make sure the issue gets 217 1.1 jruoho # dealt with sometime. 218 1.1 jruoho # 219 1.1 jruoho # XXX: the second set has been disabled in the name of making 220 1.1 jruoho # all tests "pass". 221 1.2 christos # 222 1.2 christos # As they should be, they are utter nonsense. 223 1.1 jruoho 224 1.2 christos # 1. error if the whole shell exits (current correct behavior) 225 1.1 jruoho dcheck 'echo OK; (set -e; false); echo OK' 'OK OK' 226 1.1 jruoho echeck 'echo OK; (set -e; false); echo OK' 'OK OK' 227 1.1 jruoho # 2. error if the whole shell does not exit (dsl's suggested behavior) 228 1.1 jruoho #dcheck 'echo OK; (set -e; false); echo ERR' 'OK' 229 1.1 jruoho #echeck 'echo OK; (set -e; false); echo ERR' 'OK' 230 1.1 jruoho 231 1.1 jruoho # The current behavior of the shell is that it exits out as 232 1.1 jruoho # far as -e is set and then stops. This is probably a 233 1.1 jruoho # consequence of it handling () wrong, but it's a somewhat 234 1.1 jruoho # curious compromise position between 1. and 2. above. 235 1.1 jruoho dcheck '(set -e; (false; echo ERR); echo ERR); echo OK' 'OK' 236 1.1 jruoho echeck '(set -e; (false; echo ERR); echo ERR); echo OK' 'OK' 237 1.1 jruoho 238 1.1 jruoho # backquote expansion (PR bin/17514) 239 1.1 jruoho 240 1.2 christos # (in-)correct 241 1.1 jruoho #dcheck '(set -e; echo ERR `false`; echo ERR); echo OK' 'OK' 242 1.1 jruoho #dcheck '(set -e; echo ERR $(false); echo ERR); echo OK' 'OK' 243 1.1 jruoho #dcheck '(set -e; echo ERR `exit 3`; echo ERR); echo OK' 'OK' 244 1.1 jruoho #dcheck '(set -e; echo ERR $(exit 3); echo ERR); echo OK' 'OK' 245 1.2 christos # Not-wrong current behavior 246 1.2 christos # the exit status of ommand substitution is ignored in most cases 247 1.2 christos # None of these should be causing the shell to exit. 248 1.1 jruoho dcheck '(set -e; echo ERR `false`; echo ERR); echo OK' 'ERR ERR OK' 249 1.1 jruoho dcheck '(set -e; echo ERR $(false); echo ERR); echo OK' 'ERR ERR OK' 250 1.1 jruoho dcheck '(set -e; echo ERR `exit 3`; echo ERR); echo OK' 'ERR ERR OK' 251 1.1 jruoho dcheck '(set -e; echo ERR $(exit 3); echo ERR); echo OK' 'ERR ERR OK' 252 1.1 jruoho 253 1.2 christos # This is testing one case (the case?) where the exit status is used 254 1.1 jruoho dcheck '(set -e; x=`false`; echo ERR); echo OK' 'OK' 255 1.1 jruoho dcheck '(set -e; x=$(false); echo ERR); echo OK' 'OK' 256 1.1 jruoho dcheck '(set -e; x=`exit 3`; echo ERR); echo OK' 'OK' 257 1.1 jruoho dcheck '(set -e; x=$(exit 3); echo ERR); echo OK' 'OK' 258 1.1 jruoho 259 1.2 christos # correct (really just commented out incorrect nonsense) 260 1.1 jruoho #echeck '(set -e; echo ERR `false`; echo ERR); echo OK' 'OK' 261 1.1 jruoho #echeck '(set -e; echo ERR $(false); echo ERR); echo OK' 'OK' 262 1.1 jruoho #echeck '(set -e; echo ERR `exit 3`; echo ERR); echo OK' 'OK' 263 1.1 jruoho #echeck '(set -e; echo ERR $(exit 3); echo ERR); echo OK' 'OK' 264 1.1 jruoho 265 1.2 christos # not-wrong current behavior (as above) 266 1.1 jruoho echeck '(set -e; echo ERR `false`; echo ERR); echo OK' 'ERR ERR OK' 267 1.1 jruoho echeck '(set -e; echo ERR $(false); echo ERR); echo OK' 'ERR ERR OK' 268 1.1 jruoho echeck '(set -e; echo ERR `exit 3`; echo ERR); echo OK' 'ERR ERR OK' 269 1.1 jruoho echeck '(set -e; echo ERR $(exit 3); echo ERR); echo OK' 'ERR ERR OK' 270 1.1 jruoho 271 1.1 jruoho echeck '(set -e; x=`false`; echo ERR); echo OK' 'OK' 272 1.1 jruoho echeck '(set -e; x=$(false); echo ERR); echo OK' 'OK' 273 1.1 jruoho echeck '(set -e; x=`exit 3`; echo ERR); echo OK' 'OK' 274 1.1 jruoho echeck '(set -e; x=$(exit 3); echo ERR); echo OK' 'OK' 275 1.1 jruoho 276 1.1 jruoho # shift (PR bin/37493) 277 1.1 jruoho # correct 278 1.2 christos # Actually, both ways are correct, both are permitted 279 1.1 jruoho #dcheck '(set -e; shift || true; echo OK); echo OK' 'OK OK' 280 1.1 jruoho #echeck '(set -e; shift || true; echo OK); echo OK' 'OK OK' 281 1.2 christos # (not-) wrong current behavior 282 1.2 christos #dcheck '(set -e; shift || true; echo OK); echo OK' 'OK' 283 1.2 christos #echeck '(set -e; shift || true; echo OK); echo OK' 'OK' 284 1.2 christos 285 1.2 christos # what is wrong is this test assuming one behaviour or the other 286 1.2 christos # (and incidentally this has nothing whatever to do with "-e", 287 1.2 christos # the test should really be moved elsewhere...) 288 1.2 christos # But for now, leave it here, and correct it: 289 1.2 christos dcheck '(set -e; shift && echo OK); echo OK' 'OK' 290 1.2 christos echeck '(set -e; shift && echo OK); echo OK' 'OK' 291 1.1 jruoho 292 1.1 jruoho # Done. 293 1.1 jruoho 294 1.1 jruoho if [ "x$SH_FAILS" != x ]; then 295 1.1 jruoho printf '%-56s %-8s %s\n' "Expression" "Result" "Should be" 296 1.1 jruoho echo "$SH_FAILS" 297 1.1 jruoho atf_fail "$failcount of $count failed cases" 298 1.1 jruoho else 299 1.1 jruoho atf_pass 300 1.1 jruoho fi 301 1.1 jruoho } 302 1.1 jruoho 303 1.1 jruoho atf_init_test_cases() { 304 1.1 jruoho atf_add_test_case all 305 1.1 jruoho } 306