1*640235e2SEnji Cooper# $NetBSD: t_set_e.sh,v 1.4 2016/03/31 16:22:27 christos Exp $ 257718be8SEnji Cooper# 357718be8SEnji Cooper# Copyright (c) 2007 The NetBSD Foundation, Inc. 457718be8SEnji Cooper# All rights reserved. 557718be8SEnji Cooper# 657718be8SEnji Cooper# Redistribution and use in source and binary forms, with or without 757718be8SEnji Cooper# modification, are permitted provided that the following conditions 857718be8SEnji Cooper# are met: 957718be8SEnji Cooper# 1. Redistributions of source code must retain the above copyright 1057718be8SEnji Cooper# notice, this list of conditions and the following disclaimer. 1157718be8SEnji Cooper# 2. Redistributions in binary form must reproduce the above copyright 1257718be8SEnji Cooper# notice, this list of conditions and the following disclaimer in the 1357718be8SEnji Cooper# documentation and/or other materials provided with the distribution. 1457718be8SEnji Cooper# 1557718be8SEnji Cooper# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 1657718be8SEnji Cooper# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 1757718be8SEnji Cooper# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 1857718be8SEnji Cooper# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 1957718be8SEnji Cooper# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2057718be8SEnji Cooper# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2157718be8SEnji Cooper# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2257718be8SEnji Cooper# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2357718be8SEnji Cooper# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2457718be8SEnji Cooper# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2557718be8SEnji Cooper# POSSIBILITY OF SUCH DAMAGE. 2657718be8SEnji Cooper# 2757718be8SEnji Cooper 2857718be8SEnji Cooper# references: 2957718be8SEnji Cooper# http://www.opengroup.org/onlinepubs/009695399/utilities/set.html 3057718be8SEnji Cooper# http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html 3157718be8SEnji Cooper 3257718be8SEnji Cooper# the implementation of "sh" to test 33*640235e2SEnji Cooper: ${TEST_SH:="/bin/sh"} 3457718be8SEnji Cooper 3557718be8SEnji Cooperfailwith() 3657718be8SEnji Cooper{ 3757718be8SEnji Cooper case "$SH_FAILS" in 3857718be8SEnji Cooper "") SH_FAILS=`echo "$1"`;; 3957718be8SEnji Cooper *) SH_FAILS="$SH_FAILS"`echo; echo "$1"`;; 4057718be8SEnji Cooper esac 4157718be8SEnji Cooper} 4257718be8SEnji Cooper 4357718be8SEnji Coopercheck1() 4457718be8SEnji Cooper{ 4557718be8SEnji Cooper #echo "$TEST_SH -c $1" 4657718be8SEnji Cooper result=`$TEST_SH -c "$1" 2>/dev/null | tr '\n' ' ' | sed 's/ *$//'` 4757718be8SEnji Cooper if [ "$result" != "$2" ]; then 4857718be8SEnji Cooper MSG=`printf "%-56s %-8s %s" "$3" "$result" "$2"` 4957718be8SEnji Cooper failwith "$MSG" 5057718be8SEnji Cooper failcount=`expr $failcount + 1` 5157718be8SEnji Cooper fi 5257718be8SEnji Cooper count=`expr $count + 1` 5357718be8SEnji Cooper} 5457718be8SEnji Cooper 5557718be8SEnji Cooper# direct check: try the given expression. 5657718be8SEnji Cooperdcheck() 5757718be8SEnji Cooper{ 5857718be8SEnji Cooper check1 "$1" "$2" "$1" 5957718be8SEnji Cooper} 6057718be8SEnji Cooper 6157718be8SEnji Cooper# eval check: indirect through eval. 6257718be8SEnji Cooper# as of this writing, this changes the behavior pretty drastically and 6357718be8SEnji Cooper# is thus important to test. (PR bin/29861) 6457718be8SEnji Cooperecheck() 6557718be8SEnji Cooper{ 6657718be8SEnji Cooper check1 'eval '"'( $1 )'" "$2" "eval '($1)'" 6757718be8SEnji Cooper} 6857718be8SEnji Cooper 6957718be8SEnji Cooperatf_test_case all 7057718be8SEnji Cooperall_head() { 7157718be8SEnji Cooper atf_set "descr" "Tests that 'set -e' works correctly" 7257718be8SEnji Cooper} 7357718be8SEnji Cooperall_body() { 7457718be8SEnji Cooper count=0 7557718be8SEnji Cooper failcount=0 7657718be8SEnji Cooper 7757718be8SEnji Cooper # make sure exiting from a subshell behaves as expected 7857718be8SEnji Cooper dcheck '(set -e; exit 1; echo ERR$?); echo OK$?' 'OK1' 7957718be8SEnji Cooper echeck '(set -e; exit 1; echo ERR$?); echo OK$?' 'OK1' 8057718be8SEnji Cooper 8157718be8SEnji Cooper # first, check basic functioning. 8257718be8SEnji Cooper # The ERR shouldn't print; the result of the () should be 1. 8357718be8SEnji Cooper # Henceforth we'll assume that we don't need to check $?. 84*640235e2SEnji Cooper dcheck '(set -e; false; echo ERR$?); echo OK$?' 'OK1' 85*640235e2SEnji Cooper echeck '(set -e; false; echo ERR$?); echo OK$?' 'OK1' 8657718be8SEnji Cooper 8757718be8SEnji Cooper # these cases should be equivalent to the preceding. 8857718be8SEnji Cooper dcheck '(set -e; /nonexistent; echo ERR); echo OK' 'OK' 8957718be8SEnji Cooper echeck '(set -e; /nonexistent; echo ERR); echo OK' 'OK' 9057718be8SEnji Cooper dcheck '(set -e; nonexistent-program-on-path; echo ERR); echo OK' 'OK' 9157718be8SEnji Cooper echeck '(set -e; nonexistent-program-on-path; echo ERR); echo OK' 'OK' 9257718be8SEnji Cooper dcheck 'f() { false; }; (set -e; f; echo ERR); echo OK' 'OK' 9357718be8SEnji Cooper echeck 'f() { false; }; (set -e; f; echo ERR); echo OK' 'OK' 9457718be8SEnji Cooper dcheck 'f() { return 1; }; (set -e; f; echo ERR); echo OK' 'OK' 9557718be8SEnji Cooper echeck 'f() { return 1; }; (set -e; f; echo ERR); echo OK' 'OK' 9657718be8SEnji Cooper 9757718be8SEnji Cooper # but! with set -e, the false should cause an *immediate* exit. 9857718be8SEnji Cooper # The return form should not, as such, but there's no way to 9957718be8SEnji Cooper # distinguish it. 10057718be8SEnji Cooper dcheck 'f() { false; echo ERR; }; (set -e; f); echo OK' 'OK' 10157718be8SEnji Cooper echeck 'f() { false; echo ERR; }; (set -e; f); echo OK' 'OK' 10257718be8SEnji Cooper 10357718be8SEnji Cooper # set is not scoped, so these should not exit at all. 10457718be8SEnji Cooper dcheck 'f() { set +e; false; echo OK; }; (set -e; f); echo OK' 'OK OK' 10557718be8SEnji Cooper echeck 'f() { set +e; false; echo OK; }; (set -e; f); echo OK' 'OK OK' 10657718be8SEnji Cooper 10757718be8SEnji Cooper # according to the standard, only failing *simple* commands 10857718be8SEnji Cooper # cause an exit under -e. () is not a simple command. 10957718be8SEnji Cooper # Correct (per POSIX): 11057718be8SEnji Cooper #dcheck '(set -e; (set +e; false; echo OK; false); echo OK)' 'OK OK' 11157718be8SEnji Cooper #echeck '(set -e; (set +e; false; echo OK; false); echo OK)' 'OK OK' 11257718be8SEnji Cooper # Wrong current behavior: 11357718be8SEnji Cooper dcheck '(set -e; (set +e; false; echo OK; false); echo OK)' 'OK' 11457718be8SEnji Cooper echeck '(set -e; (set +e; false; echo OK; false); echo OK)' 'OK' 11557718be8SEnji Cooper 11657718be8SEnji Cooper # make sure an inner nested shell does exit though. 11757718be8SEnji Cooper dcheck '(set -e; (false; echo ERR)); echo OK' 'OK' 11857718be8SEnji Cooper 11957718be8SEnji Cooper # The left hand side of an || or && is explicitly tested and 12057718be8SEnji Cooper # thus should not cause an exit. Furthermore, because a || or 12157718be8SEnji Cooper # && expression is not a simple command, there should be no 12257718be8SEnji Cooper # exit even if the overall result is false. 12357718be8SEnji Cooper dcheck '(set -e; false || true; echo OK); echo OK' 'OK OK' 12457718be8SEnji Cooper echeck '(set -e; false || true; echo OK); echo OK' 'OK OK' 12557718be8SEnji Cooper dcheck '(set -e; false && true; echo OK); echo OK' 'OK OK' 12657718be8SEnji Cooper echeck '(set -e; false && true; echo OK); echo OK' 'OK OK' 12757718be8SEnji Cooper 12857718be8SEnji Cooper # However, the right hand side is not tested, so a failure 12957718be8SEnji Cooper # there *should* cause an exit, regardless of whether it 13057718be8SEnji Cooper # appears inside a non-simple command. 13157718be8SEnji Cooper # 13257718be8SEnji Cooper # Note that in at least one place the standard does not 13357718be8SEnji Cooper # distinguish between the left and right hand sides of 13457718be8SEnji Cooper # logical operators. It is possible that for strict 13557718be8SEnji Cooper # compliance these need to not exit; however, if so that 13657718be8SEnji Cooper # should probably be limited to when some strict-posix setting 13757718be8SEnji Cooper # is in effect and tested accordingly. 13857718be8SEnji Cooper # 13957718be8SEnji Cooper dcheck '(set -e; false || false; echo ERR); echo OK' 'OK' 14057718be8SEnji Cooper dcheck '(set -e; true && false; echo ERR); echo OK' 'OK' 14157718be8SEnji Cooper echeck '(set -e; false || false; echo ERR); echo OK' 'OK' 14257718be8SEnji Cooper echeck '(set -e; true && false; echo ERR); echo OK' 'OK' 14357718be8SEnji Cooper 14457718be8SEnji Cooper # correct: 14557718be8SEnji Cooper #dcheck '(set -e; false && false; echo ERR); echo OK' 'OK' 14657718be8SEnji Cooper #echeck '(set -e; false && false; echo ERR); echo OK' 'OK' 14757718be8SEnji Cooper 14857718be8SEnji Cooper # wrong current behavior: 14957718be8SEnji Cooper dcheck '(set -e; false && false; echo ERR); echo OK' 'ERR OK' 15057718be8SEnji Cooper echeck '(set -e; false && false; echo ERR); echo OK' 'ERR OK' 15157718be8SEnji Cooper 15257718be8SEnji Cooper # A failure that is not reached because of short-circuit 15357718be8SEnji Cooper # evaluation should not cause an exit, however. 15457718be8SEnji Cooper dcheck '(set -e; true || false; echo OK); echo OK' 'OK OK' 15557718be8SEnji Cooper echeck '(set -e; true || false; echo OK); echo OK' 'OK OK' 15657718be8SEnji Cooper 15757718be8SEnji Cooper # For completeness, test the other two combinations. 15857718be8SEnji Cooper dcheck '(set -e; true || true; echo OK); echo OK' 'OK OK' 15957718be8SEnji Cooper dcheck '(set -e; true && true; echo OK); echo OK' 'OK OK' 16057718be8SEnji Cooper echeck '(set -e; true || true; echo OK); echo OK' 'OK OK' 16157718be8SEnji Cooper echeck '(set -e; true && true; echo OK); echo OK' 'OK OK' 16257718be8SEnji Cooper 16357718be8SEnji Cooper # likewise, none of these should exit. 16457718be8SEnji Cooper dcheck '(set -e; while false; do :; done; echo OK); echo OK' 'OK OK' 16557718be8SEnji Cooper dcheck '(set -e; if false; then :; fi; echo OK); echo OK' 'OK OK' 16657718be8SEnji Cooper # problematic :-) 16757718be8SEnji Cooper #dcheck '(set -e; until false; do :; done; echo OK); echo OK' 'OK OK' 16857718be8SEnji Cooper dcheck '(set -e; until [ "$t" = 1 ]; do t=1; done; echo OK); echo OK' \ 16957718be8SEnji Cooper 'OK OK' 17057718be8SEnji Cooper echeck '(set -e; while false; do :; done; echo OK); echo OK' 'OK OK' 17157718be8SEnji Cooper echeck '(set -e; if false; then :; fi; echo OK); echo OK' 'OK OK' 17257718be8SEnji Cooper echeck '(set -e; until [ "$t" = 1 ]; do t=1; done; echo OK); echo OK' \ 17357718be8SEnji Cooper 'OK OK' 17457718be8SEnji Cooper 17557718be8SEnji Cooper # the bang operator tests its argument and thus the argument 17657718be8SEnji Cooper # should not cause an exit. it is also not a simple command (I 17757718be8SEnji Cooper # believe) so it also shouldn't exit even if it yields a false 17857718be8SEnji Cooper # result. 17957718be8SEnji Cooper dcheck '(set -e; ! false; echo OK); echo OK' 'OK OK' 18057718be8SEnji Cooper dcheck '(set -e; ! true; echo OK); echo OK' 'OK OK' 18157718be8SEnji Cooper echeck '(set -e; ! false; echo OK); echo OK' 'OK OK' 18257718be8SEnji Cooper echeck '(set -e; ! true; echo OK); echo OK' 'OK OK' 18357718be8SEnji Cooper 18457718be8SEnji Cooper # combined case with () and &&; the inner expression is false 18557718be8SEnji Cooper # but does not itself exit, and the () should not cause an 18657718be8SEnji Cooper # exit even when failing. 18757718be8SEnji Cooper # correct: 18857718be8SEnji Cooper #dcheck '(set -e; (false && true); echo OK); echo OK' 'OK OK' 18957718be8SEnji Cooper #echeck '(set -e; (false && true); echo OK); echo OK' 'OK OK' 19057718be8SEnji Cooper # wrong current behavior: 19157718be8SEnji Cooper dcheck '(set -e; (false && true); echo OK); echo OK' 'OK' 19257718be8SEnji Cooper echeck '(set -e; (false && true); echo OK); echo OK' 'OK' 19357718be8SEnji Cooper 19457718be8SEnji Cooper # pipelines. only the right-hand end is significant. 19557718be8SEnji Cooper dcheck '(set -e; false | true; echo OK); echo OK' 'OK OK' 19657718be8SEnji Cooper echeck '(set -e; false | true; echo OK); echo OK' 'OK OK' 19757718be8SEnji Cooper dcheck '(set -e; true | false; echo ERR); echo OK' 'OK' 19857718be8SEnji Cooper echeck '(set -e; true | false; echo ERR); echo OK' 'OK' 19957718be8SEnji Cooper 20057718be8SEnji Cooper dcheck '(set -e; while true | false; do :; done; echo OK); echo OK' \ 20157718be8SEnji Cooper 'OK OK' 20257718be8SEnji Cooper dcheck '(set -e; if true | false; then :; fi; echo OK); echo OK' \ 20357718be8SEnji Cooper 'OK OK' 20457718be8SEnji Cooper 20557718be8SEnji Cooper 20657718be8SEnji Cooper # According to dsl@ in PR bin/32282, () is not defined as a 20757718be8SEnji Cooper # subshell, only as a grouping operator [and a scope, I guess] 208*640235e2SEnji Cooper 209*640235e2SEnji Cooper # (This is incorrect. () is definitely a sub-shell) 210*640235e2SEnji Cooper 21157718be8SEnji Cooper # so the nested false ought to cause the whole shell to exit, 21257718be8SEnji Cooper # not just the subshell. dholland@ would like to see C&V, 21357718be8SEnji Cooper # because that seems like a bad idea. (Among other things, it 21457718be8SEnji Cooper # would break all the above test logic, which relies on being 21557718be8SEnji Cooper # able to isolate set -e behavior inside ().) However, I'm 21657718be8SEnji Cooper # going to put these tests here to make sure the issue gets 21757718be8SEnji Cooper # dealt with sometime. 21857718be8SEnji Cooper # 21957718be8SEnji Cooper # XXX: the second set has been disabled in the name of making 22057718be8SEnji Cooper # all tests "pass". 221*640235e2SEnji Cooper # 222*640235e2SEnji Cooper # As they should be, they are utter nonsense. 22357718be8SEnji Cooper 224*640235e2SEnji Cooper # 1. error if the whole shell exits (current correct behavior) 22557718be8SEnji Cooper dcheck 'echo OK; (set -e; false); echo OK' 'OK OK' 22657718be8SEnji Cooper echeck 'echo OK; (set -e; false); echo OK' 'OK OK' 22757718be8SEnji Cooper # 2. error if the whole shell does not exit (dsl's suggested behavior) 22857718be8SEnji Cooper #dcheck 'echo OK; (set -e; false); echo ERR' 'OK' 22957718be8SEnji Cooper #echeck 'echo OK; (set -e; false); echo ERR' 'OK' 23057718be8SEnji Cooper 23157718be8SEnji Cooper # The current behavior of the shell is that it exits out as 23257718be8SEnji Cooper # far as -e is set and then stops. This is probably a 23357718be8SEnji Cooper # consequence of it handling () wrong, but it's a somewhat 23457718be8SEnji Cooper # curious compromise position between 1. and 2. above. 23557718be8SEnji Cooper dcheck '(set -e; (false; echo ERR); echo ERR); echo OK' 'OK' 23657718be8SEnji Cooper echeck '(set -e; (false; echo ERR); echo ERR); echo OK' 'OK' 23757718be8SEnji Cooper 23857718be8SEnji Cooper # backquote expansion (PR bin/17514) 23957718be8SEnji Cooper 240*640235e2SEnji Cooper # (in-)correct 24157718be8SEnji Cooper #dcheck '(set -e; echo ERR `false`; echo ERR); echo OK' 'OK' 24257718be8SEnji Cooper #dcheck '(set -e; echo ERR $(false); echo ERR); echo OK' 'OK' 24357718be8SEnji Cooper #dcheck '(set -e; echo ERR `exit 3`; echo ERR); echo OK' 'OK' 24457718be8SEnji Cooper #dcheck '(set -e; echo ERR $(exit 3); echo ERR); echo OK' 'OK' 245*640235e2SEnji Cooper # Not-wrong current behavior 246*640235e2SEnji Cooper # the exit status of ommand substitution is ignored in most cases 247*640235e2SEnji Cooper # None of these should be causing the shell to exit. 24857718be8SEnji Cooper dcheck '(set -e; echo ERR `false`; echo ERR); echo OK' 'ERR ERR OK' 24957718be8SEnji Cooper dcheck '(set -e; echo ERR $(false); echo ERR); echo OK' 'ERR ERR OK' 25057718be8SEnji Cooper dcheck '(set -e; echo ERR `exit 3`; echo ERR); echo OK' 'ERR ERR OK' 25157718be8SEnji Cooper dcheck '(set -e; echo ERR $(exit 3); echo ERR); echo OK' 'ERR ERR OK' 25257718be8SEnji Cooper 253*640235e2SEnji Cooper # This is testing one case (the case?) where the exit status is used 25457718be8SEnji Cooper dcheck '(set -e; x=`false`; echo ERR); echo OK' 'OK' 25557718be8SEnji Cooper dcheck '(set -e; x=$(false); echo ERR); echo OK' 'OK' 25657718be8SEnji Cooper dcheck '(set -e; x=`exit 3`; echo ERR); echo OK' 'OK' 25757718be8SEnji Cooper dcheck '(set -e; x=$(exit 3); echo ERR); echo OK' 'OK' 25857718be8SEnji Cooper 259*640235e2SEnji Cooper # correct (really just commented out incorrect nonsense) 26057718be8SEnji Cooper #echeck '(set -e; echo ERR `false`; echo ERR); echo OK' 'OK' 26157718be8SEnji Cooper #echeck '(set -e; echo ERR $(false); echo ERR); echo OK' 'OK' 26257718be8SEnji Cooper #echeck '(set -e; echo ERR `exit 3`; echo ERR); echo OK' 'OK' 26357718be8SEnji Cooper #echeck '(set -e; echo ERR $(exit 3); echo ERR); echo OK' 'OK' 26457718be8SEnji Cooper 265*640235e2SEnji Cooper # not-wrong current behavior (as above) 26657718be8SEnji Cooper echeck '(set -e; echo ERR `false`; echo ERR); echo OK' 'ERR ERR OK' 26757718be8SEnji Cooper echeck '(set -e; echo ERR $(false); echo ERR); echo OK' 'ERR ERR OK' 26857718be8SEnji Cooper echeck '(set -e; echo ERR `exit 3`; echo ERR); echo OK' 'ERR ERR OK' 26957718be8SEnji Cooper echeck '(set -e; echo ERR $(exit 3); echo ERR); echo OK' 'ERR ERR OK' 27057718be8SEnji Cooper 27157718be8SEnji Cooper echeck '(set -e; x=`false`; echo ERR); echo OK' 'OK' 27257718be8SEnji Cooper echeck '(set -e; x=$(false); echo ERR); echo OK' 'OK' 27357718be8SEnji Cooper echeck '(set -e; x=`exit 3`; echo ERR); echo OK' 'OK' 27457718be8SEnji Cooper echeck '(set -e; x=$(exit 3); echo ERR); echo OK' 'OK' 27557718be8SEnji Cooper 27657718be8SEnji Cooper # shift (PR bin/37493) 27757718be8SEnji Cooper # correct 278*640235e2SEnji Cooper # Actually, both ways are correct, both are permitted 27957718be8SEnji Cooper #dcheck '(set -e; shift || true; echo OK); echo OK' 'OK OK' 28057718be8SEnji Cooper #echeck '(set -e; shift || true; echo OK); echo OK' 'OK OK' 281*640235e2SEnji Cooper # (not-) wrong current behavior 282*640235e2SEnji Cooper #dcheck '(set -e; shift || true; echo OK); echo OK' 'OK' 283*640235e2SEnji Cooper #echeck '(set -e; shift || true; echo OK); echo OK' 'OK' 284*640235e2SEnji Cooper 285*640235e2SEnji Cooper # what is wrong is this test assuming one behaviour or the other 286*640235e2SEnji Cooper # (and incidentally this has nothing whatever to do with "-e", 287*640235e2SEnji Cooper # the test should really be moved elsewhere...) 288*640235e2SEnji Cooper # But for now, leave it here, and correct it: 289*640235e2SEnji Cooper dcheck '(set -e; shift && echo OK); echo OK' 'OK' 290*640235e2SEnji Cooper echeck '(set -e; shift && echo OK); echo OK' 'OK' 29157718be8SEnji Cooper 29257718be8SEnji Cooper # Done. 29357718be8SEnji Cooper 29457718be8SEnji Cooper if [ "x$SH_FAILS" != x ]; then 29557718be8SEnji Cooper printf '%-56s %-8s %s\n' "Expression" "Result" "Should be" 29657718be8SEnji Cooper echo "$SH_FAILS" 29757718be8SEnji Cooper atf_fail "$failcount of $count failed cases" 29857718be8SEnji Cooper else 29957718be8SEnji Cooper atf_pass 30057718be8SEnji Cooper fi 30157718be8SEnji Cooper} 30257718be8SEnji Cooper 30357718be8SEnji Cooperatf_init_test_cases() { 30457718be8SEnji Cooper atf_add_test_case all 30557718be8SEnji Cooper} 306