1*f42f89fdSandvar# $NetBSD: t_option.sh,v 1.9 2022/05/22 11:27:36 andvar Exp $ 2c1ce7cf3Schristos# 3c1ce7cf3Schristos# Copyright (c) 2016 The NetBSD Foundation, Inc. 4c1ce7cf3Schristos# All rights reserved. 5c1ce7cf3Schristos# 6c1ce7cf3Schristos# Redistribution and use in source and binary forms, with or without 7c1ce7cf3Schristos# modification, are permitted provided that the following conditions 8c1ce7cf3Schristos# are met: 9c1ce7cf3Schristos# 1. Redistributions of source code must retain the above copyright 10c1ce7cf3Schristos# notice, this list of conditions and the following disclaimer. 11c1ce7cf3Schristos# 2. Redistributions in binary form must reproduce the above copyright 12c1ce7cf3Schristos# notice, this list of conditions and the following disclaimer in the 13c1ce7cf3Schristos# documentation and/or other materials provided with the distribution. 14c1ce7cf3Schristos# 15c1ce7cf3Schristos# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 16c1ce7cf3Schristos# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 17c1ce7cf3Schristos# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18c1ce7cf3Schristos# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 19c1ce7cf3Schristos# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20c1ce7cf3Schristos# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21c1ce7cf3Schristos# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22c1ce7cf3Schristos# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23c1ce7cf3Schristos# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24c1ce7cf3Schristos# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25c1ce7cf3Schristos# POSSIBILITY OF SUCH DAMAGE. 26c1ce7cf3Schristos# 27c1ce7cf3Schristos# the implementation of "sh" to test 28c1ce7cf3Schristos: ${TEST_SH:="/bin/sh"} 29c1ce7cf3Schristos 30c1ce7cf3Schristos# The standard 31c1ce7cf3Schristos# http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html 32c1ce7cf3Schristos# says: 33c1ce7cf3Schristos# ...[lots] 34c1ce7cf3Schristos 35c1ce7cf3Schristostest_option_on_off() 36c1ce7cf3Schristos{ 37c1ce7cf3Schristos atf_require_prog tr 38c1ce7cf3Schristos 39c1ce7cf3Schristos for opt 40c1ce7cf3Schristos do 41c1ce7cf3Schristos # t is needed, as inside $()` $- appears to lose 42c1ce7cf3Schristos # the 'e' option if it happened to already be 43c1ce7cf3Schristos # set. Must check if that is what should 44c1ce7cf3Schristos # happen, but that is a different issue. 45c1ce7cf3Schristos 46c1ce7cf3Schristos test -z "${opt}" && continue 47c1ce7cf3Schristos 48c1ce7cf3Schristos # if we are playing with more that one option at a 49c1ce7cf3Schristos # time, the code below requires that we start with no 50c1ce7cf3Schristos # options set, or it will mis-diagnose the situation 51c1ce7cf3Schristos CLEAR='' 52c1ce7cf3Schristos test "${#opt}" -gt 1 && 53c1ce7cf3Schristos CLEAR='xx="$-" && xx=$(echo "$xx" | tr -d cs) && test -n "$xx" && set +"$xx";' 54c1ce7cf3Schristos 5506f9bef6Schristos atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \ 56c1ce7cf3Schristos "opt=${opt}"' 57c1ce7cf3Schristos x() { 58c1ce7cf3Schristos echo "ERROR: Unable to $1 option $2" >&2 59c1ce7cf3Schristos exit 1 60c1ce7cf3Schristos } 61c1ce7cf3Schristos s() { 62c1ce7cf3Schristos set -"$1" 63c1ce7cf3Schristos t="$-" 64c1ce7cf3Schristos x=$(echo "$t" | tr -d "$1") 65c1ce7cf3Schristos test "$t" = "$x" && x set "$1" 66c1ce7cf3Schristos return 0 67c1ce7cf3Schristos } 68c1ce7cf3Schristos c() { 69c1ce7cf3Schristos set +"$1" 70c1ce7cf3Schristos t="$-" 71c1ce7cf3Schristos x=$(echo "$t" | tr -d "$1") 72c1ce7cf3Schristos test "$t" != "$x" && x clear "$1" 73c1ce7cf3Schristos return 0 74c1ce7cf3Schristos } 75c1ce7cf3Schristos '"${CLEAR}"' 76c1ce7cf3Schristos 77c1ce7cf3Schristos # if we do not do this, -x tracing splatters stderr 78c1ce7cf3Schristos # for some shells, -v does as well (is that correct?) 79c1ce7cf3Schristos case "${opt}" in 80a60600e0Skre (*[xXv]*) exec 2>/dev/null;; 81c1ce7cf3Schristos esac 82c1ce7cf3Schristos 83c1ce7cf3Schristos o="$-" 84c1ce7cf3Schristos x=$(echo "$o" | tr -d "$opt") 85c1ce7cf3Schristos 86c1ce7cf3Schristos if [ "$o" = "$x" ]; then # option was off 87c1ce7cf3Schristos s "${opt}" 88c1ce7cf3Schristos c "${opt}" 89c1ce7cf3Schristos else 90c1ce7cf3Schristos c "${opt}" 91c1ce7cf3Schristos s "${opt}" 92c1ce7cf3Schristos fi 93c1ce7cf3Schristos ' 94c1ce7cf3Schristos done 95c1ce7cf3Schristos} 96c1ce7cf3Schristos 97c1ce7cf3Schristostest_optional_on_off() 98c1ce7cf3Schristos{ 99c1ce7cf3Schristos RET=0 100c1ce7cf3Schristos OPTS= 101c1ce7cf3Schristos for opt 102c1ce7cf3Schristos do 103c1ce7cf3Schristos test "${opt}" = n && continue 10406f9bef6Schristos ${TEST_SH} -c "set -${opt}" 2>/dev/null && 105c1ce7cf3Schristos OPTS="${OPTS} ${opt}" || RET=1 106c1ce7cf3Schristos done 107c1ce7cf3Schristos 108c1ce7cf3Schristos test -n "${OPTS}" && test_option_on_off ${OPTS} 109c1ce7cf3Schristos 110c1ce7cf3Schristos return "${RET}" 111c1ce7cf3Schristos} 112c1ce7cf3Schristos 113c1ce7cf3Schristosatf_test_case set_a 114c1ce7cf3Schristosset_a_head() { 115c1ce7cf3Schristos atf_set "descr" "Tests that 'set -a' turns on all var export " \ 116c1ce7cf3Schristos "and that it behaves as defined by the standard" 117c1ce7cf3Schristos} 118c1ce7cf3Schristosset_a_body() { 119c1ce7cf3Schristos atf_require_prog env 120c1ce7cf3Schristos atf_require_prog grep 121c1ce7cf3Schristos 122c1ce7cf3Schristos test_option_on_off a 123c1ce7cf3Schristos 124c1ce7cf3Schristos # without -a, new variables should not be exported (so grep "fails") 12506f9bef6Schristos atf_check -s exit:1 -o empty -e empty ${TEST_SH} -ce \ 126c1ce7cf3Schristos 'unset VAR; set +a; VAR=value; env | grep "^VAR="' 127c1ce7cf3Schristos 128c1ce7cf3Schristos # with -a, they should be 12906f9bef6Schristos atf_check -s exit:0 -o match:VAR=value -e empty ${TEST_SH} -ce \ 130c1ce7cf3Schristos 'unset VAR; set -a; VAR=value; env | grep "^VAR="' 131c1ce7cf3Schristos} 132c1ce7cf3Schristos 133c1ce7cf3Schristosatf_test_case set_C 134c1ce7cf3Schristosset_C_head() { 135c1ce7cf3Schristos atf_set "descr" "Tests that 'set -C' turns on no clobber mode " \ 136c1ce7cf3Schristos "and that it behaves as defined by the standard" 137c1ce7cf3Schristos} 138c1ce7cf3Schristosset_C_body() { 139c1ce7cf3Schristos atf_require_prog ls 140c1ce7cf3Schristos 141c1ce7cf3Schristos test_option_on_off C 142c1ce7cf3Schristos 143c1ce7cf3Schristos # Check that the environment to use for the tests is sane ... 144c1ce7cf3Schristos # we assume current dir is a new tempory directory & is empty 145c1ce7cf3Schristos 146c1ce7cf3Schristos test -z "$(ls)" || atf_skip "Test execution directory not clean" 147c1ce7cf3Schristos test -c "/dev/null" || atf_skip "Problem with /dev/null" 148c1ce7cf3Schristos 149c1ce7cf3Schristos echo Dummy_Content > Junk_File 150c1ce7cf3Schristos echo Precious_Content > Important_File 151c1ce7cf3Schristos 152c1ce7cf3Schristos # Check that we can redirect onto file when -C is not set 15306f9bef6Schristos atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \ 154c1ce7cf3Schristos ' 155c1ce7cf3Schristos D=$(ls -l Junk_File) || exit 1 156c1ce7cf3Schristos set +C 157c1ce7cf3Schristos echo "Overwrite it now" > Junk_File 158c1ce7cf3Schristos A=$(ls -l Junk_File) || exit 1 159c1ce7cf3Schristos test "${A}" != "${D}" 160c1ce7cf3Schristos ' 161c1ce7cf3Schristos 162c1ce7cf3Schristos # Check that we cannot redirect onto file when -C is set 16306f9bef6Schristos atf_check -s exit:0 -o empty -e not-empty ${TEST_SH} -c \ 164c1ce7cf3Schristos ' 165c1ce7cf3Schristos D=$(ls -l Important_File) || exit 1 166c1ce7cf3Schristos set -C 167c1ce7cf3Schristos echo "Fail to Overwrite it now" > Important_File 168c1ce7cf3Schristos A=$(ls -l Important_File) || exit 1 169c1ce7cf3Schristos test "${A}" = "${D}" 170c1ce7cf3Schristos ' 171c1ce7cf3Schristos 172c1ce7cf3Schristos # Check that we can append to file, even when -C is set 17306f9bef6Schristos atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \ 174c1ce7cf3Schristos ' 175c1ce7cf3Schristos D=$(ls -l Junk_File) || exit 1 176c1ce7cf3Schristos set -C 177c1ce7cf3Schristos echo "Append to it now" >> Junk_File 178c1ce7cf3Schristos A=$(ls -l Junk_File) || exit 1 179c1ce7cf3Schristos test "${A}" != "${D}" 180c1ce7cf3Schristos ' 181c1ce7cf3Schristos 182c1ce7cf3Schristos # Check that we abort on attempt to redirect onto file when -Ce is set 18306f9bef6Schristos atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \ 184c1ce7cf3Schristos ' 185c1ce7cf3Schristos set -Ce 186c1ce7cf3Schristos echo "Fail to Overwrite it now" > Important_File 187c1ce7cf3Schristos echo "Should not reach this point" 188c1ce7cf3Schristos ' 189c1ce7cf3Schristos 190c1ce7cf3Schristos # Last check that we can override -C for when we really need to 19106f9bef6Schristos atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \ 192c1ce7cf3Schristos ' 193c1ce7cf3Schristos D=$(ls -l Junk_File) || exit 1 194c1ce7cf3Schristos set -C 195c1ce7cf3Schristos echo "Change the poor bugger again" >| Junk_File 196c1ce7cf3Schristos A=$(ls -l Junk_File) || exit 1 197c1ce7cf3Schristos test "${A}" != "${D}" 198c1ce7cf3Schristos ' 199c1ce7cf3Schristos} 200c1ce7cf3Schristos 201c1ce7cf3Schristosatf_test_case set_e 202c1ce7cf3Schristosset_e_head() { 203c1ce7cf3Schristos atf_set "descr" "Tests that 'set -e' turns on error detection " \ 204c1ce7cf3Schristos "and that a simple case behaves as defined by the standard" 205c1ce7cf3Schristos} 206c1ce7cf3Schristosset_e_body() { 207c1ce7cf3Schristos test_option_on_off e 208c1ce7cf3Schristos 209c1ce7cf3Schristos # Check that -e does nothing if no commands fail 210c1ce7cf3Schristos atf_check -s exit:0 -o match:I_am_OK -e empty \ 21106f9bef6Schristos ${TEST_SH} -c \ 212c1ce7cf3Schristos 'false; printf "%s" I_am; set -e; true; printf "%s\n" _OK' 213c1ce7cf3Schristos 214c1ce7cf3Schristos # and that it (silently, but with exit status) aborts if cmd fails 215c1ce7cf3Schristos atf_check -s not-exit:0 -o match:I_am -o not-match:Broken -e empty \ 21606f9bef6Schristos ${TEST_SH} -c \ 217c1ce7cf3Schristos 'false; printf "%s" I_am; set -e; false; printf "%s\n" _Broken' 218c1ce7cf3Schristos 219c1ce7cf3Schristos # same, except -e this time is on from the beginning 220c1ce7cf3Schristos atf_check -s not-exit:0 -o match:I_am -o not-match:Broken -e empty \ 22106f9bef6Schristos ${TEST_SH} -ec 'printf "%s" I_am; false; printf "%s\n" _Broken' 222c1ce7cf3Schristos 223c1ce7cf3Schristos # More checking of -e in other places, there is lots to deal with. 224c1ce7cf3Schristos} 225c1ce7cf3Schristos 226c1ce7cf3Schristosatf_test_case set_f 227c1ce7cf3Schristosset_f_head() { 228c1ce7cf3Schristos atf_set "descr" "Tests that 'set -f' turns off pathname expansion " \ 229c1ce7cf3Schristos "and that it behaves as defined by the standard" 230c1ce7cf3Schristos} 231c1ce7cf3Schristosset_f_body() { 232c1ce7cf3Schristos atf_require_prog ls 233c1ce7cf3Schristos 234c1ce7cf3Schristos test_option_on_off f 235c1ce7cf3Schristos 236c1ce7cf3Schristos # Check that the environment to use for the tests is sane ... 237c1ce7cf3Schristos # we assume current dir is a new tempory directory & is empty 238c1ce7cf3Schristos 239c1ce7cf3Schristos test -z "$(ls)" || atf_skip "Test execution directory not clean" 240c1ce7cf3Schristos 241c1ce7cf3Schristos # we will assume that atf will clean up this junk directory 242c1ce7cf3Schristos # when we are done. But for testing pathname expansion 243c1ce7cf3Schristos # we need files 244c1ce7cf3Schristos 245c1ce7cf3Schristos for f in a b c d e f aa ab ac ad ae aaa aab aac aad aba abc bbb ccc 246c1ce7cf3Schristos do 247c1ce7cf3Schristos echo "$f" > "$f" 248c1ce7cf3Schristos done 249c1ce7cf3Schristos 25006f9bef6Schristos atf_check -s exit:0 -o empty -e empty ${TEST_SH} -ec \ 251c1ce7cf3Schristos 'X=$(echo b*); Y=$(echo b*); test "${X}" != "a*"; 252c1ce7cf3Schristos test "${X}" = "${Y}"' 253c1ce7cf3Schristos 254c1ce7cf3Schristos # now test expansion is different when -f is set 25506f9bef6Schristos atf_check -s exit:0 -o empty -e empty ${TEST_SH} -ec \ 256c1ce7cf3Schristos 'X=$(echo b*); Y=$(set -f; echo b*); test "${X}" != "${Y}"' 257c1ce7cf3Schristos} 258c1ce7cf3Schristos 259c1ce7cf3Schristosatf_test_case set_n 260c1ce7cf3Schristosset_n_head() { 26103e9d50aSmsaitoh atf_set "descr" "Tests that 'set -n' suppresses command execution " \ 262c1ce7cf3Schristos "and that it behaves as defined by the standard" 263c1ce7cf3Schristos} 264c1ce7cf3Schristosset_n_body() { 265c1ce7cf3Schristos # pointless to test this, if it turns on, it stays on... 266c1ce7cf3Schristos # test_option_on_off n 267c1ce7cf3Schristos # so just allow the tests below to verify it can be turned on 268c1ce7cf3Schristos 269c1ce7cf3Schristos # nothing should be executed, hence no output... 270c1ce7cf3Schristos atf_check -s exit:0 -o empty -e empty \ 27106f9bef6Schristos ${TEST_SH} -enc 'echo ABANDON HOPE; echo ALL YE; echo ...' 272c1ce7cf3Schristos 273c1ce7cf3Schristos # this is true even when the "commands" do not exist 274c1ce7cf3Schristos atf_check -s exit:0 -o empty -e empty \ 27506f9bef6Schristos ${TEST_SH} -enc 'ERR; FAIL; ABANDON HOPE' 276c1ce7cf3Schristos 27706f9bef6Schristos # but if there is a syntax error, it should be detected (w or w/o -e) 278c1ce7cf3Schristos atf_check -s not-exit:0 -o empty -e not-empty \ 27906f9bef6Schristos ${TEST_SH} -enc 'echo JUMP; for frogs swim; echo in puddles' 28006f9bef6Schristos atf_check -s not-exit:0 -o empty -e not-empty \ 28106f9bef6Schristos ${TEST_SH} -nc 'echo ABANDON HOPE; echo "ALL YE; echo ...' 28206f9bef6Schristos atf_check -s not-exit:0 -o empty -e not-empty \ 28306f9bef6Schristos ${TEST_SH} -enc 'echo ABANDON HOPE;; echo ALL YE; echo ...' 28406f9bef6Schristos atf_check -s not-exit:0 -o empty -e not-empty \ 28506f9bef6Schristos ${TEST_SH} -nc 'do YOU ABANDON HOPE; for all eternity?' 286c1ce7cf3Schristos 28706f9bef6Schristos # now test enabling -n in the middle of a script 28806f9bef6Schristos # note that once turned on, it cannot be turned off again. 28906f9bef6Schristos # 29006f9bef6Schristos # omit more complex cases, as those can send some shells 29106f9bef6Schristos # into infinite loops, and believe it or not, that might be OK! 29206f9bef6Schristos 29306f9bef6Schristos atf_check -s exit:0 -o match:first -o not-match:second -e empty \ 29406f9bef6Schristos ${TEST_SH} -c 'echo first; set -n; echo second' 29506f9bef6Schristos atf_check -s exit:0 -o match:first -o not-match:third -e empty \ 29606f9bef6Schristos ${TEST_SH} -c 'echo first; set -n; echo second; set +n; echo third' 29706f9bef6Schristos atf_check -s exit:0 -o inline:'a\nb\n' -e empty \ 29806f9bef6Schristos ${TEST_SH} -c 'for x in a b c d 29906f9bef6Schristos do 30006f9bef6Schristos case "$x" in 30106f9bef6Schristos a);; b);; c) set -n;; d);; 30206f9bef6Schristos esac 30306f9bef6Schristos printf "%s\n" "$x" 30406f9bef6Schristos done' 30506f9bef6Schristos 30606f9bef6Schristos # This last one is a bit more complex to explain, so I will not try 30706f9bef6Schristos 30806f9bef6Schristos # First, we need to know what signal number is used for SIGUSR1 on 30906f9bef6Schristos # the local (testing) system (signal number is $(( $XIT - 128 )) ) 31006f9bef6Schristos 31106f9bef6Schristos # this will take slightly over 1 second elapsed time (the sleep 1) 31206f9bef6Schristos # The "10" for the first sleep just needs to be something big enough 31306f9bef6Schristos # that the rest of the commands have time to complete, even on 31406f9bef6Schristos # very slow testing systems. 10 should be enough. Otherwise irrelevant 31506f9bef6Schristos 31606f9bef6Schristos # The shell will usually blather to stderr about the sleep 10 being 31706f9bef6Schristos # killed, but it affects nothing, so just allow it to cry. 31806f9bef6Schristos 31906f9bef6Schristos (sleep 10 & sleep 1; kill -USR1 $!; wait $!) 32006f9bef6Schristos XIT="$?" 32106f9bef6Schristos 32206f9bef6Schristos # The exit value should be an integer > 128 and < 256 (often 158) 32306f9bef6Schristos # If it is not just skip the test 32406f9bef6Schristos 32506f9bef6Schristos # If we do run the test, it should take (slightly over) either 1 or 2 32606f9bef6Schristos # seconds to complete, depending upon the shell being tested. 32706f9bef6Schristos 32806f9bef6Schristos case "${XIT}" in 32906f9bef6Schristos ( 129 | 1[3-9][0-9] | 2[0-4][0-9] | 25[0-5] ) 33006f9bef6Schristos 33106f9bef6Schristos # The script below should exit with the same code - no output 33206f9bef6Schristos 33306f9bef6Schristos # Or that is the result that seems best explanable. 33406f9bef6Schristos # "set -n" in uses like this is not exactly well defined... 33506f9bef6Schristos 33606f9bef6Schristos # This script comes from a member of the austin group 33706f9bef6Schristos # (they author changes to the posix shell spec - and more.) 33806f9bef6Schristos # The author is also an (occasional?) NetBSD user. 33906f9bef6Schristos atf_check -s exit:${XIT} -o empty -e empty ${TEST_SH} -c ' 34006f9bef6Schristos trap "set -n" USR1 34106f9bef6Schristos { sleep 1; kill -USR1 $$; sleep 1; } & 34206f9bef6Schristos false 34306f9bef6Schristos wait && echo t || echo f 34406f9bef6Schristos wait 34506f9bef6Schristos echo foo 34606f9bef6Schristos ' 34706f9bef6Schristos ;; 34806f9bef6Schristos esac 349c1ce7cf3Schristos} 350c1ce7cf3Schristos 351c1ce7cf3Schristosatf_test_case set_u 352c1ce7cf3Schristosset_u_head() { 353c1ce7cf3Schristos atf_set "descr" "Tests that 'set -u' turns on unset var detection " \ 354c1ce7cf3Schristos "and that it behaves as defined by the standard" 355c1ce7cf3Schristos} 356c1ce7cf3Schristosset_u_body() { 357c1ce7cf3Schristos test_option_on_off u 358c1ce7cf3Schristos 359bdbf3d66Skre unset ENV # make sure there is nothing there to cause problems 360bdbf3d66Skre 361c1ce7cf3Schristos # first make sure it is OK to unset an unset variable 36206f9bef6Schristos atf_check -s exit:0 -o match:OK -e empty ${TEST_SH} -ce \ 363c1ce7cf3Schristos 'unset _UNSET_VARIABLE_; echo OK' 364c1ce7cf3Schristos # even if -u is set 36506f9bef6Schristos atf_check -s exit:0 -o match:OK -e empty ${TEST_SH} -cue \ 366c1ce7cf3Schristos 'unset _UNSET_VARIABLE_; echo OK' 367c1ce7cf3Schristos 368c1ce7cf3Schristos # and that without -u accessing an unset variable is harmless 36906f9bef6Schristos atf_check -s exit:0 -o match:OK -e empty ${TEST_SH} -ce \ 370c1ce7cf3Schristos 'unset X; echo ${X}; echo OK' 371c1ce7cf3Schristos # and that the unset variable test expansion works properly 37206f9bef6Schristos atf_check -s exit:0 -o match:OKOK -e empty ${TEST_SH} -ce \ 373c1ce7cf3Schristos 'unset X; printf "%s" ${X-OK}; echo OK' 374c1ce7cf3Schristos 375c1ce7cf3Schristos # Next test that with -u set, the shell aborts on access to unset var 376c1ce7cf3Schristos # do not use -e, want to make sure it is -u that causes abort 37706f9bef6Schristos atf_check -s not-exit:0 -o not-match:ERR -e not-empty ${TEST_SH} -c \ 378c1ce7cf3Schristos 'unset X; set -u; echo ${X}; echo ERR' 379c1ce7cf3Schristos # quoting should make no difference... 38006f9bef6Schristos atf_check -s not-exit:0 -o not-match:ERR -e not-empty ${TEST_SH} -c \ 381c1ce7cf3Schristos 'unset X; set -u; echo "${X}"; echo ERR' 382c1ce7cf3Schristos 383c1ce7cf3Schristos # Now a bunch of accesses to unset vars, with -u, in ways that are OK 38406f9bef6Schristos atf_check -s exit:0 -o match:OK -e empty ${TEST_SH} -ce \ 385c1ce7cf3Schristos 'unset X; set -u; echo ${X-GOOD}; echo OK' 38606f9bef6Schristos atf_check -s exit:0 -o match:OK -e empty ${TEST_SH} -ce \ 387c1ce7cf3Schristos 'unset X; set -u; echo ${X-OK}' 388c1ce7cf3Schristos atf_check -s exit:0 -o not-match:ERR -o match:OK -e empty \ 38906f9bef6Schristos ${TEST_SH} -ce 'unset X; set -u; echo ${X+ERR}; echo OK' 390c1ce7cf3Schristos 391c1ce7cf3Schristos # and some more ways that are not OK 39206f9bef6Schristos atf_check -s not-exit:0 -o not-match:ERR -e not-empty ${TEST_SH} -c \ 393c1ce7cf3Schristos 'unset X; set -u; echo ${X#foo}; echo ERR' 39406f9bef6Schristos atf_check -s not-exit:0 -o not-match:ERR -e not-empty ${TEST_SH} -c \ 395c1ce7cf3Schristos 'unset X; set -u; echo ${X%%bar}; echo ERR' 396c1ce7cf3Schristos 397c1ce7cf3Schristos # lastly, just while we are checking unset vars, test aborts w/o -u 39806f9bef6Schristos atf_check -s not-exit:0 -o not-match:ERR -e not-empty ${TEST_SH} -c \ 399c1ce7cf3Schristos 'unset X; echo ${X?}; echo ERR' 400c1ce7cf3Schristos atf_check -s not-exit:0 -o not-match:ERR -e match:X_NOT_SET \ 40106f9bef6Schristos ${TEST_SH} -c 'unset X; echo ${X?X_NOT_SET}; echo ERR' 402c1ce7cf3Schristos} 403c1ce7cf3Schristos 404c1ce7cf3Schristosatf_test_case set_v 405c1ce7cf3Schristosset_v_head() { 406c1ce7cf3Schristos atf_set "descr" "Tests that 'set -v' turns on input read echoing " \ 407c1ce7cf3Schristos "and that it behaves as defined by the standard" 408c1ce7cf3Schristos} 409c1ce7cf3Schristosset_v_body() { 410c1ce7cf3Schristos test_option_on_off v 411c1ce7cf3Schristos 412c1ce7cf3Schristos # check that -v does nothing if no later input line is read 413c1ce7cf3Schristos atf_check -s exit:0 \ 414c1ce7cf3Schristos -o match:OKOK -o not-match:echo -o not-match:printf \ 415c1ce7cf3Schristos -e empty \ 41606f9bef6Schristos ${TEST_SH} -ec 'printf "%s" OK; set -v; echo OK; exit 0' 417c1ce7cf3Schristos 418c1ce7cf3Schristos # but that it does when there are multiple lines 419dd894f6fSchristos cat <<- 'EOF' | 420dd894f6fSchristos set -v 421dd894f6fSchristos printf %s OK 422dd894f6fSchristos echo OK 423dd894f6fSchristos exit 0 424dd894f6fSchristos EOF 425c1ce7cf3Schristos atf_check -s exit:0 \ 426c1ce7cf3Schristos -o match:OKOK -o not-match:echo -o not-match:printf \ 427c1ce7cf3Schristos -e match:printf -e match:OK -e match:echo \ 428dd894f6fSchristos -e not-match:set ${TEST_SH} 429c1ce7cf3Schristos 430c1ce7cf3Schristos # and that it can be disabled again 431dd894f6fSchristos cat <<- 'EOF' | 432dd894f6fSchristos set -v 433dd894f6fSchristos printf %s OK 434dd894f6fSchristos set +v 435dd894f6fSchristos echo OK 436dd894f6fSchristos exit 0 437dd894f6fSchristos EOF 438c1ce7cf3Schristos atf_check -s exit:0 \ 439c1ce7cf3Schristos -o match:OKOK -o not-match:echo -o not-match:printf \ 440c1ce7cf3Schristos -e match:printf -e match:OK -e not-match:echo \ 441dd894f6fSchristos ${TEST_SH} 442c1ce7cf3Schristos 443c1ce7cf3Schristos # and lastly, that shell keywords do get output when "read" 444dd894f6fSchristos cat <<- 'EOF' | 445dd894f6fSchristos set -v 446dd894f6fSchristos for i in 111 222 333 447dd894f6fSchristos do 448dd894f6fSchristos printf %s $i 449dd894f6fSchristos done 450dd894f6fSchristos exit 0 451dd894f6fSchristos EOF 452c1ce7cf3Schristos atf_check -s exit:0 \ 453c1ce7cf3Schristos -o match:111222333 -o not-match:printf \ 454c1ce7cf3Schristos -o not-match:for -o not-match:do -o not-match:done \ 455c1ce7cf3Schristos -e match:printf -e match:111 -e not-match:111222 \ 456c1ce7cf3Schristos -e match:for -e match:do -e match:done \ 457d4ae1f8bSkre ${TEST_SH} || 458d4ae1f8bSkre atf_fail '111 222 333 test failure' 459c1ce7cf3Schristos} 460c1ce7cf3Schristos 461c1ce7cf3Schristosatf_test_case set_x 462c1ce7cf3Schristosset_x_head() { 463c1ce7cf3Schristos atf_set "descr" "Tests that 'set -x' turns on command exec logging " \ 464c1ce7cf3Schristos "and that it behaves as defined by the standard" 465c1ce7cf3Schristos} 466c1ce7cf3Schristosset_x_body() { 467c1ce7cf3Schristos test_option_on_off x 468c1ce7cf3Schristos 469c1ce7cf3Schristos # check that cmd output appears after -x is enabled 470c1ce7cf3Schristos atf_check -s exit:0 \ 471c1ce7cf3Schristos -o match:OKOK -o not-match:echo -o not-match:printf \ 472c1ce7cf3Schristos -e not-match:printf -e match:OK -e match:echo \ 47306f9bef6Schristos ${TEST_SH} -ec 'printf "%s" OK; set -x; echo OK; exit 0' 474c1ce7cf3Schristos 475c1ce7cf3Schristos # and that it stops again afer -x is disabled 476c1ce7cf3Schristos atf_check -s exit:0 \ 477c1ce7cf3Schristos -o match:OKOK -o not-match:echo -o not-match:printf \ 478c1ce7cf3Schristos -e match:printf -e match:OK -e not-match:echo \ 47906f9bef6Schristos ${TEST_SH} -ec 'set -x; printf "%s" OK; set +x; echo OK; exit 0' 480c1ce7cf3Schristos 481c1ce7cf3Schristos # also check that PS4 is output correctly 482c1ce7cf3Schristos atf_check -s exit:0 \ 483c1ce7cf3Schristos -o match:OK -o not-match:echo \ 484c1ce7cf3Schristos -e match:OK -e match:Run:echo \ 48506f9bef6Schristos ${TEST_SH} -ec 'PS4=Run:; set -x; echo OK; exit 0' 486c1ce7cf3Schristos 487c1ce7cf3Schristos return 0 488c1ce7cf3Schristos 489c1ce7cf3Schristos # This one seems controversial... I suspect it is NetBSD's sh 490c1ce7cf3Schristos # that is wrong to not output "for" "while" "if" ... etc 491c1ce7cf3Schristos 492c1ce7cf3Schristos # and lastly, that shell keywords do not get output when "executed" 493c1ce7cf3Schristos atf_check -s exit:0 \ 494c1ce7cf3Schristos -o match:111222333 -o not-match:printf \ 495c1ce7cf3Schristos -o not-match:for \ 496c1ce7cf3Schristos -e match:printf -e match:111 -e not-match:111222 \ 497c1ce7cf3Schristos -e not-match:for -e not-match:do -e not-match:done \ 49806f9bef6Schristos ${TEST_SH} -ec \ 499c1ce7cf3Schristos 'set -x; for i in 111 222 333; do printf "%s" $i; done; echo; exit 0' 500c1ce7cf3Schristos} 501c1ce7cf3Schristos 502a60600e0Skreatf_test_case set_X 503a60600e0Skreset_X_head() { 504a60600e0Skre atf_set "descr" "Tests that 'set -X' turns on command exec logging " \ 505a60600e0Skre "and that it enables set -x and retains a single fd" 506a60600e0Skre} 507a60600e0Skreset_X_body() { 508a60600e0Skre 509a60600e0Skre # First we need to verify that $TEST_SH supports -X 510a60600e0Skre test_optional_on_off X || 511a60600e0Skre atf_skip "$TEST_SH does not support -X" 512a60600e0Skre 513a60600e0Skre # and that the -X it implements is the -X we expect 514a60600e0Skre $TEST_SH -c 'exec 2>/dev/null; 515a60600e0Skre set +x; set -X; 516a60600e0Skre case "$-" in (*x*) exit 0;; esac; 517a60600e0Skre exit 1' || 518a60600e0Skre atf_skip "$TEST_SH supports -X but not 'the' -X" 519a60600e0Skre 520a60600e0Skre # Above has already tested that set -X => set -x 521a60600e0Skre # Now test that set +X => set +x 522a60600e0Skre # and that set -x and set +x do not affect -X 523a60600e0Skre 524a60600e0Skre atf_check -s exit:0 -o empty -e ignore ${TEST_SH} -c \ 525a60600e0Skre 'set -x; set +X; case "$-" in (*x*) echo FAIL; exit 1;; esac' 526a60600e0Skre 527a60600e0Skre atf_check -s exit:0 -o empty -e ignore ${TEST_SH} -c \ 528a60600e0Skre 'set -X; set +x; 529a60600e0Skre case "$-" in (*x*) echo FAIL; exit 1;; esac 530a60600e0Skre case "$-" in (*X*) exit 0;; esac; echo ERROR; exit 2' 531a60600e0Skre 532a60600e0Skre atf_check -s exit:0 -o empty -e ignore ${TEST_SH} -c \ 533a60600e0Skre 'set -X; set +x; set -x; 534a60600e0Skre case "$-" in (*x*X*|*X*x*) exit 0;; esac; echo ERROR; exit 2' 535a60600e0Skre 536a60600e0Skre atf_check -s exit:0 -o empty -e ignore ${TEST_SH} -c \ 537a60600e0Skre 'set +X; set -x; 538a60600e0Skre case "$-" in (*X*) echo FAIL; exit 1;; esac 539a60600e0Skre case "$-" in (*x*) exit 0;; esac; echo ERROR; exit 2' 540a60600e0Skre 541a60600e0Skre atf_check -s exit:0 -o empty -e ignore ${TEST_SH} -c \ 542a60600e0Skre 'set +X; set -x; set +x; 543a60600e0Skre case "$-" in (*[xX]*) echo FAULT; exit 3;; esac' 544a60600e0Skre 545a60600e0Skre # The following just verify regular tracing using -X instead of -x 546a60600e0Skre # These are the same tests as the -x test (set_x) performs. 547a60600e0Skre 548a60600e0Skre # check that cmd output appears after -X is enabled 549a60600e0Skre atf_check -s exit:0 \ 550a60600e0Skre -o match:OKOK -o not-match:echo -o not-match:printf \ 551a60600e0Skre -e not-match:printf -e match:OK -e match:echo \ 552a60600e0Skre ${TEST_SH} -ec 'printf "%s" OK; set -X; echo OK; exit 0' 553a60600e0Skre 554a60600e0Skre # and that it stops again afer -X is disabled 555a60600e0Skre atf_check -s exit:0 \ 556a60600e0Skre -o match:OKOK -o not-match:echo -o not-match:printf \ 557a60600e0Skre -e match:printf -e match:OK -e not-match:echo \ 558a60600e0Skre ${TEST_SH} -ec 'set -X; printf "%s" OK; set +X; echo OK; exit 0' 559a60600e0Skre 560a60600e0Skre # also check that PS4 is output correctly 561a60600e0Skre atf_check -s exit:0 \ 562a60600e0Skre -o match:OK -o not-match:echo \ 563a60600e0Skre -e match:OK -e match:Run:echo \ 564a60600e0Skre ${TEST_SH} -ec 'PS4=Run:; set -X; echo OK; exit 0' 565a60600e0Skre 566a60600e0Skre # end copies of -x tests ... 567a60600e0Skre 568a60600e0Skre # now check that we can move stderr around without affecting -X output 569a60600e0Skre 570a60600e0Skre atf_check -s exit:0 \ 571a60600e0Skre -o match:OKOK -o not-match:echo -o not-match:printf \ 572a60600e0Skre -e match:printf -e match:OK -e match:echo \ 573a60600e0Skre ${TEST_SH} -ecX 'printf "%s" OK; exec 2>/dev/null; echo OK' 574a60600e0Skre atf_check -s exit:0 \ 575a60600e0Skre -o match:OKOK -o not-match:echo -o not-match:printf \ 576a60600e0Skre -e match:printf -e match:OK -e match:echo \ 577a60600e0Skre ${TEST_SH} -ecX 'printf "%s" OK; exec 2>&1; echo OK' 578a60600e0Skre atf_check -s exit:0 \ 579a60600e0Skre -o match:OKOK -o not-match:echo -o not-match:printf \ 580a60600e0Skre -e match:printf -e match:OK -e match:echo \ 581a60600e0Skre ${TEST_SH} -ecX 'printf "%s" OK; exec 2>&-; echo OK' 582a60600e0Skre 583a60600e0Skre # and that we can put tracing on an external file, leaving stderr alone 584a60600e0Skre 585a60600e0Skre atf_require_prog grep 586a60600e0Skre 587a60600e0Skre rm -f X-trace 588a60600e0Skre atf_check -s exit:0 \ 589a60600e0Skre -o match:OKOK -o not-match:echo -o not-match:printf \ 590a60600e0Skre -e empty \ 591a60600e0Skre ${TEST_SH} -ec 'PS4=; set -X 2>X-trace; printf "%s" OK; echo OK' 592a60600e0Skre test -s X-trace || atf_fail "T1: Failed to create trace output file" 593a60600e0Skre grep >/dev/null 2>&1 'printf.*%s.*OK' X-trace || 594a60600e0Skre atf_fail "T1: -X tracing missing printf" 595a60600e0Skre grep >/dev/null 2>&1 'echo.*OK' X-trace || 596a60600e0Skre atf_fail "T1: -X tracing missing echo" 597a60600e0Skre 598a60600e0Skre rm -f X-trace 599a60600e0Skre atf_check -s exit:0 \ 600a60600e0Skre -o match:OKOK -o not-match:echo -o not-match:printf \ 601a60600e0Skre -e empty \ 602a60600e0Skre ${TEST_SH} -ec \ 603a60600e0Skre 'PS4=; set -X 2>X-trace; 604a60600e0Skre printf "%s" OK; 605a60600e0Skre exec 2>/dev/null; 606a60600e0Skre echo OK' 607a60600e0Skre test -s X-trace || atf_fail "T2: Failed to create trace output file" 608a60600e0Skre grep >/dev/null 2>&1 'printf.*%s.*OK' X-trace || 609a60600e0Skre atf_fail "T2: -X tracing missing printf" 610a60600e0Skre grep >/dev/null 2>&1 'exec' X-trace || 611a60600e0Skre atf_fail "T2: -X tracing missing exec" 612a60600e0Skre grep >/dev/null 2>&1 'echo.*OK' X-trace || 613a60600e0Skre atf_fail "T2: -X tracing missing echo after stderr redirect" 614a60600e0Skre 615a60600e0Skre rm -f X-trace 616a60600e0Skre atf_check -s exit:0 \ 617a60600e0Skre -o match:OKOK -o not-match:echo -o not-match:printf \ 618a60600e0Skre -e empty \ 619a60600e0Skre ${TEST_SH} -ec \ 620a60600e0Skre 'PS4=; set -X 2>X-trace; 621a60600e0Skre printf "%s" OK; 622a60600e0Skre set -X 2>/dev/null; 623a60600e0Skre echo OK' 624a60600e0Skre test -s X-trace || atf_fail "T3: Failed to create trace output file" 625a60600e0Skre grep >/dev/null 2>&1 'printf.*%s.*OK' X-trace || 626a60600e0Skre atf_fail "T3: -X tracing missing printf" 627a60600e0Skre grep >/dev/null 2>&1 'set.*-X' X-trace || 628a60600e0Skre atf_fail "T3: -X tracing missing set -X" 629a60600e0Skre grep >/dev/null 2>&1 'echo.*OK' X-trace && 630a60600e0Skre atf_fail "T3: -X tracing included echo after set -X redirect" 631a60600e0Skre 632a60600e0Skre rm -f X-trace 633a60600e0Skre atf_check -s exit:0 \ 634a60600e0Skre -o match:OKOK -o not-match:echo -o not-match:printf \ 635a60600e0Skre -e match:echo -e match:OK -e not-match:printf \ 636a60600e0Skre ${TEST_SH} -ec \ 637a60600e0Skre 'PS4=; set -X 2>X-trace; 638a60600e0Skre printf "%s" OK; 639a60600e0Skre set -X; 640a60600e0Skre echo OK' 641a60600e0Skre test -s X-trace || atf_fail "T4: Failed to create trace output file" 642a60600e0Skre grep >/dev/null 2>&1 'printf.*%s.*OK' X-trace || 643a60600e0Skre atf_fail "T4: -X tracing missing printf" 644a60600e0Skre grep >/dev/null 2>&1 'set.*-X' X-trace || 645a60600e0Skre atf_fail "T4: -X tracing missing set -X" 646a60600e0Skre grep >/dev/null 2>&1 'echo.*OK' X-trace && 647a60600e0Skre atf_fail "T4: -X tracing included echo after set -X redirect" 648a60600e0Skre 649a60600e0Skre # Now check that -X and the tracing files work properly wrt functions 650a60600e0Skre 651a60600e0Skre # a shell that supports -X should support "local -" ... but verify 652a60600e0Skre 653a60600e0Skre ( ${TEST_SH} -c 'fn() { local - || exit 2; set -f; }; set +f; fn; 654a60600e0Skre case "$-" in ("*f*") exit 1;; esac; exit 0' ) 2>/dev/null || 655a60600e0Skre atf_skip "-X function test: 'local -' unsupported" 656a60600e0Skre 657a60600e0Skre rm -f X-trace X-trace-fn 658a60600e0Skre atf_check -s exit:0 \ 659a60600e0Skre -o match:OKhelloGOOD \ 660a60600e0Skre -e empty \ 661a60600e0Skre ${TEST_SH} -c ' 662a60600e0Skre say() { 663a60600e0Skre printf "%s" "$*" 664a60600e0Skre } 665a60600e0Skre funct() { 666a60600e0Skre local - 667a60600e0Skre 668a60600e0Skre set -X 2>X-trace-fn 669a60600e0Skre say hello 670a60600e0Skre } 671a60600e0Skre 672a60600e0Skre set -X 2>X-trace 673a60600e0Skre 674a60600e0Skre printf OK 675a60600e0Skre funct 676a60600e0Skre echo GOOD 677a60600e0Skre ' 678a60600e0Skre test -s X-trace || atf_fail "T5: Failed to create trace output file" 679a60600e0Skre test -s X-trace-fn || atf_fail "T5: Failed to create fn trace output" 680a60600e0Skre grep >/dev/null 2>&1 'printf.*OK' X-trace || 681a60600e0Skre atf_fail "T5: -X tracing missing printf" 682a60600e0Skre grep >/dev/null 2>&1 funct X-trace || 683a60600e0Skre atf_fail "T5: -X tracing missing funct" 684a60600e0Skre grep >/dev/null 2>&1 'set.*-X' X-trace || 685a60600e0Skre atf_fail "T5: -X tracing missing set -X from in funct" 686a60600e0Skre grep >/dev/null 2>&1 'echo.*GOOD' X-trace || 687a60600e0Skre atf_fail "T5: -X tracing missing echo after funct redirect" 688a60600e0Skre grep >/dev/null 2>&1 'say.*hello' X-trace && 689a60600e0Skre atf_fail "T5: -X tracing included 'say' after funct redirect" 690a60600e0Skre grep >/dev/null 2>&1 'say.*hello' X-trace-fn || 691a60600e0Skre atf_fail "T5: -X funct tracing missed 'say'" 692a60600e0Skre 693a60600e0Skre rm -f X-trace X-trace-fn 694a60600e0Skre 695a60600e0Skre atf_check -s exit:0 \ 696a60600e0Skre -o match:OKhelloGOOD \ 697a60600e0Skre -e empty \ 698a60600e0Skre ${TEST_SH} -c ' 699a60600e0Skre say() { 700a60600e0Skre printf "%s" "$*" 701a60600e0Skre } 702a60600e0Skre funct() { 703a60600e0Skre local - 704a60600e0Skre 705a60600e0Skre set +X 706a60600e0Skre say hello 707a60600e0Skre } 708a60600e0Skre 709a60600e0Skre set -X 2>X-trace 710a60600e0Skre 711a60600e0Skre printf OK 712a60600e0Skre funct 713a60600e0Skre echo GOOD 714a60600e0Skre ' 715a60600e0Skre test -s X-trace || atf_fail "T6: Failed to create trace output file" 716a60600e0Skre grep >/dev/null 2>&1 'printf.*OK' X-trace || 717a60600e0Skre atf_fail "T6: -X tracing missing printf" 718a60600e0Skre grep >/dev/null 2>&1 funct X-trace || 719a60600e0Skre atf_fail "T6: -X tracing missing funct" 720a60600e0Skre grep >/dev/null 2>&1 'set.*+X' X-trace || 721a60600e0Skre atf_fail "T6: -X tracing missing set +X from in funct" 722a60600e0Skre grep >/dev/null 2>&1 'echo.*GOOD' X-trace || 723a60600e0Skre atf_fail "T6: -X tracing missing echo after funct redirect" 724a60600e0Skre grep >/dev/null 2>&1 'say.*hello' X-trace && 725a60600e0Skre atf_fail "T6: -X tracing included 'say' after funct redirect" 726a60600e0Skre 727a60600e0Skre rm -f X-trace 728a60600e0Skre 729a60600e0Skre atf_check -s exit:0 \ 730a60600e0Skre -o match:OKtracednotraceGOOD \ 731a60600e0Skre -e match:say -e match:traced -e not-match:notrace \ 732a60600e0Skre ${TEST_SH} -c ' 733a60600e0Skre say() { 734a60600e0Skre printf "%s" "$*" 735a60600e0Skre } 736a60600e0Skre funct() { 737a60600e0Skre local - 738a60600e0Skre 739a60600e0Skre set +X -x 740a60600e0Skre 741a60600e0Skre say traced 742a60600e0Skre exec 2>/dev/null 743a60600e0Skre say notrace 744a60600e0Skre 745a60600e0Skre } 746a60600e0Skre 747a60600e0Skre set -X 2>X-trace 748a60600e0Skre 749a60600e0Skre printf OK 750a60600e0Skre funct 751a60600e0Skre echo GOOD 752a60600e0Skre ' 753a60600e0Skre test -s X-trace || atf_fail "T7: Failed to create trace output file" 754a60600e0Skre grep >/dev/null 2>&1 'printf.*OK' X-trace || 755a60600e0Skre atf_fail "T7: -X tracing missing printf" 756a60600e0Skre grep >/dev/null 2>&1 funct X-trace || 757a60600e0Skre atf_fail "T7: -X tracing missing funct" 758a60600e0Skre grep >/dev/null 2>&1 'set.*+X.*-x' X-trace || 759a60600e0Skre atf_fail "T7: -X tracing missing set +X -x from in funct" 760a60600e0Skre grep >/dev/null 2>&1 'echo.*GOOD' X-trace || 761a60600e0Skre atf_fail "T7: -X tracing missing echo after funct +X" 762a60600e0Skre grep >/dev/null 2>&1 'say.*hello' X-trace && 763a60600e0Skre atf_fail "T7: -X tracing included 'say' after funct +X" 764a60600e0Skre 765a60600e0Skre rm -f X-trace X-trace-fn 766a60600e0Skre atf_check -s exit:0 \ 767a60600e0Skre -o "match:OKg'daybye-bye.*hello.*GOOD" \ 768a60600e0Skre -e empty \ 769a60600e0Skre ${TEST_SH} -c ' 770a60600e0Skre say() { 771a60600e0Skre printf "%s" "$*" 772a60600e0Skre } 773a60600e0Skre fn1() { 774a60600e0Skre local - 775a60600e0Skre 776a60600e0Skre set -X 2>>X-trace-fn 777a60600e0Skre say "g'\''day" 778a60600e0Skre "$@" 779a60600e0Skre say bye-bye 780a60600e0Skre } 781a60600e0Skre fn2() { 782a60600e0Skre set +X 783a60600e0Skre say hello 784a60600e0Skre "$@" 785a60600e0Skre say goodbye 786a60600e0Skre } 787a60600e0Skre 788a60600e0Skre set -X 2>X-trace 789a60600e0Skre 790a60600e0Skre printf OK 791a60600e0Skre fn1 792a60600e0Skre fn1 fn2 793a60600e0Skre fn1 fn1 fn2 794a60600e0Skre fn1 fn2 fn1 fn2 fn1 795a60600e0Skre fn1 fn1 fn2 fn2 fn1 796a60600e0Skre echo GOOD 797a60600e0Skre ' 798a60600e0Skre 799a60600e0Skre # That test generally succeeds if the earlier ones did 800a60600e0Skre # and if it did not dump core! 801a60600e0Skre 802a60600e0Skre # But we can check a few things... 803a60600e0Skre 804a60600e0Skre test -s X-trace || atf_fail "T8: Failed to create trace output file" 805a60600e0Skre test -s X-trace-fn || atf_fail "T8: Failed to create trace output file" 806a60600e0Skre grep >/dev/null 2>&1 'printf.*OK' X-trace || 807a60600e0Skre atf_fail "T8: -X tracing missing printf" 808a60600e0Skre grep >/dev/null 2>&1 fn1 X-trace || 809a60600e0Skre atf_fail "T8: -X tracing missing fn1" 810a60600e0Skre grep >/dev/null 2>&1 'set.*-X' X-trace || 811a60600e0Skre atf_fail "T8: -X tracing missing set -X from in fn1" 812a60600e0Skre grep >/dev/null 2>&1 'echo.*GOOD' X-trace || 813a60600e0Skre atf_fail "T8: -X tracing missing echo after fn1 redirect" 814a60600e0Skre grep >/dev/null 2>&1 'say.*hello' X-trace && 815a60600e0Skre atf_fail "T8: -X tracing included 'say' after fn2 +X" 816a60600e0Skre grep >/dev/null 2>&1 'say.*hello' X-trace-fn && 817a60600e0Skre atf_fail "T8: -X fn tracing included 'say' after fn2 +X" 818a60600e0Skre 819a60600e0Skre 820a60600e0Skre rm -f X-trace 821a60600e0Skre 822a60600e0Skre return 0 823a60600e0Skre} 824a60600e0Skre 825c1ce7cf3Schristosopt_test_setup() 826c1ce7cf3Schristos{ 827c1ce7cf3Schristos test -n "$1" || { echo >&2 "Internal error"; exit 1; } 828c1ce7cf3Schristos 829c1ce7cf3Schristos cat > "$1" << 'END_OF_FUNCTIONS' 830c1ce7cf3Schristoslocal_opt_check() 831c1ce7cf3Schristos{ 832c1ce7cf3Schristos local - 833c1ce7cf3Schristos} 834c1ce7cf3Schristos 835c1ce7cf3Schristosinstr() 836c1ce7cf3Schristos{ 837c1ce7cf3Schristos expr "$2" : "\(.*$1\)" >/dev/null 838c1ce7cf3Schristos} 839c1ce7cf3Schristos 840c1ce7cf3Schristossave_opts() 841c1ce7cf3Schristos{ 842c1ce7cf3Schristos local - 843c1ce7cf3Schristos 844c1ce7cf3Schristos set -e 845c1ce7cf3Schristos set -u 846c1ce7cf3Schristos 847c1ce7cf3Schristos instr e "$-" && instr u "$-" && return 0 848c1ce7cf3Schristos echo ERR 849c1ce7cf3Schristos} 850c1ce7cf3Schristos 851c1ce7cf3Schristosfiddle_opts() 852c1ce7cf3Schristos{ 853c1ce7cf3Schristos set -e 854c1ce7cf3Schristos set -u 855c1ce7cf3Schristos 856c1ce7cf3Schristos instr e "$-" && instr u "$-" && return 0 857c1ce7cf3Schristos echo ERR 858c1ce7cf3Schristos} 859c1ce7cf3Schristos 860c1ce7cf3Schristoslocal_test() 861c1ce7cf3Schristos{ 862c1ce7cf3Schristos set +eu 863c1ce7cf3Schristos 864c1ce7cf3Schristos save_opts 865c1ce7cf3Schristos instr '[eu]' "$-" || printf %s "OK" 866c1ce7cf3Schristos 867c1ce7cf3Schristos fiddle_opts 868c1ce7cf3Schristos instr e "$-" && instr u "$-" && printf %s "OK" 869c1ce7cf3Schristos 870c1ce7cf3Schristos set +eu 871c1ce7cf3Schristos} 872c1ce7cf3SchristosEND_OF_FUNCTIONS 873c1ce7cf3Schristos} 874c1ce7cf3Schristos 875c1ce7cf3Schristosatf_test_case restore_local_opts 876c1ce7cf3Schristosrestore_local_opts_head() { 877c1ce7cf3Schristos atf_set "descr" "Tests that 'local -' saves and restores options. " \ 878c1ce7cf3Schristos "Note that "local" is a local shell addition" 879c1ce7cf3Schristos} 880c1ce7cf3Schristosrestore_local_opts_body() { 881c1ce7cf3Schristos atf_require_prog cat 882c1ce7cf3Schristos atf_require_prog expr 883c1ce7cf3Schristos 884c1ce7cf3Schristos FN="test-funcs.$$" 885c1ce7cf3Schristos opt_test_setup "${FN}" || atf_skip "Cannot setup test environment" 886c1ce7cf3Schristos 88706f9bef6Schristos ${TEST_SH} -ec ". './${FN}'; local_opt_check" 2>/dev/null || 888c1ce7cf3Schristos atf_skip "sh extension 'local -' not supported by ${TEST_SH}" 889c1ce7cf3Schristos 890c1ce7cf3Schristos atf_check -s exit:0 -o match:OKOK -o not-match:ERR -e empty \ 89106f9bef6Schristos ${TEST_SH} -ec ". './${FN}'; local_test" 892c1ce7cf3Schristos} 893c1ce7cf3Schristos 894c1ce7cf3Schristosatf_test_case vi_emacs_VE_toggle 895c1ce7cf3Schristosvi_emacs_VE_toggle_head() { 896c1ce7cf3Schristos atf_set "descr" "Tests enabling vi disables emacs (and v.v - but why?)"\ 897c1ce7cf3Schristos " Note that -V and -E are local shell additions" 898c1ce7cf3Schristos} 899c1ce7cf3Schristosvi_emacs_VE_toggle_body() { 900c1ce7cf3Schristos 901c1ce7cf3Schristos test_optional_on_off V E || 902c1ce7cf3Schristos atf_skip "One or both V & E opts unsupported by ${TEST_SH}" 903c1ce7cf3Schristos 90406f9bef6Schristos atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c ' 905c1ce7cf3Schristos q() { 906c1ce7cf3Schristos eval "case \"$-\" in 907c1ce7cf3Schristos (*${2}*) return 1;; 908c1ce7cf3Schristos (*${1}*) return 0;; 909c1ce7cf3Schristos esac" 910c1ce7cf3Schristos return 1 911c1ce7cf3Schristos } 912c1ce7cf3Schristos x() { 913c1ce7cf3Schristos echo >&2 "Option set or toggle failure:" \ 914c1ce7cf3Schristos " on=$1 off=$2 set=$-" 915c1ce7cf3Schristos exit 1 916c1ce7cf3Schristos } 917c1ce7cf3Schristos set -V; q V E || x V E 918c1ce7cf3Schristos set -E; q E V || x E V 919c1ce7cf3Schristos set -V; q V E || x V E 920c1ce7cf3Schristos set +EV; q "" "[VE]" || x "" VE 921c1ce7cf3Schristos exit 0 922c1ce7cf3Schristos ' 923c1ce7cf3Schristos} 924c1ce7cf3Schristos 92556aa5062Skreatf_test_case pipefail 92656aa5062Skrepipefail_head() { 92756aa5062Skre atf_set "descr" "Basic tests of the pipefail option" 92856aa5062Skre} 92956aa5062Skrepipefail_body() { 93056aa5062Skre ${TEST_SH} -c 'set -o pipefail' 2>/dev/null || 93156aa5062Skre atf_skip "pipefail option not supported by ${TEST_SH}" 93256aa5062Skre 93356aa5062Skre atf_check -s exit:0 -o match:'pipefail.*off' -e empty ${TEST_SH} -c \ 93456aa5062Skre 'set -o | grep pipefail' 93556aa5062Skre atf_check -s exit:0 -o match:'pipefail.*on' -e empty ${TEST_SH} -c \ 93656aa5062Skre 'set -o pipefail; set -o | grep pipefail' 93756aa5062Skre 93856aa5062Skre atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \ 93956aa5062Skre '(exit 1) | (exit 2) | (exit 0)' 94056aa5062Skre atf_check -s exit:2 -o empty -e empty ${TEST_SH} -c \ 94156aa5062Skre 'set -o pipefail; (exit 1) | (exit 2) | (exit 0)' 94256aa5062Skre atf_check -s exit:1 -o empty -e empty ${TEST_SH} -c \ 94356aa5062Skre 'set -o pipefail; (exit 1) | (exit 0) | (exit 0)' 94456aa5062Skre atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \ 94556aa5062Skre 'set -o pipefail; (exit 0) | (exit 0) | (exit 0)' 94656aa5062Skre 94756aa5062Skre atf_check -s exit:1 -o empty -e empty ${TEST_SH} -c \ 94856aa5062Skre '! (exit 1) | (exit 2) | (exit 0)' 94956aa5062Skre atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \ 95056aa5062Skre 'set -o pipefail; ! (exit 1) | (exit 2) | (exit 0)' 95156aa5062Skre atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \ 95256aa5062Skre 'set -o pipefail; ! (exit 1) | (exit 0) | (exit 0)' 95356aa5062Skre atf_check -s exit:1 -o empty -e empty ${TEST_SH} -c \ 95456aa5062Skre 'set -o pipefail; ! (exit 0) | (exit 0) | (exit 0)' 95556aa5062Skre 95656aa5062Skre atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \ 95756aa5062Skre '(exit 1) | (exit 2) | (exit 0); echo $?' 95856aa5062Skre atf_check -s exit:0 -o inline:'2\n' -e empty ${TEST_SH} -c \ 95956aa5062Skre 'set -o pipefail; (exit 1) | (exit 2) | (exit 0); echo $?' 96056aa5062Skre atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \ 96156aa5062Skre 'set -o pipefail; (exit 1) | (exit 0) | (exit 0); echo $?' 96256aa5062Skre atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \ 96356aa5062Skre 'set -o pipefail; (exit 0) | (exit 0) | (exit 0); echo $?' 96456aa5062Skre 96556aa5062Skre atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \ 96656aa5062Skre '! (exit 1) | (exit 2) | (exit 0); echo $?' 96756aa5062Skre atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \ 96856aa5062Skre 'set -o pipefail; ! (exit 1) | (exit 2) | (exit 0); echo $?' 96956aa5062Skre atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \ 97056aa5062Skre 'set -o pipefail; ! (exit 1) | (exit 0) | (exit 0); echo $?' 97156aa5062Skre atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \ 97256aa5062Skre 'set -o pipefail; ! (exit 0) | (exit 0) | (exit 0); echo $?' 97356aa5062Skre} 97456aa5062Skre 975c1ce7cf3Schristosatf_test_case xx_bogus 976c1ce7cf3Schristosxx_bogus_head() { 977c1ce7cf3Schristos atf_set "descr" "Tests that attempting to set a nonsense option fails." 978c1ce7cf3Schristos} 979c1ce7cf3Schristosxx_bogus_body() { 980c1ce7cf3Schristos # Biggest problem here is picking a "nonsense option" that is 981c1ce7cf3Schristos # not implemented by any shell, anywhere. Hopefully this will do. 982dd894f6fSchristos 983dd894f6fSchristos # 'set' is a special builtin, so a conforming shell should exit 984dd894f6fSchristos # on an arg error, and the ERR should not be printed. 985c1ce7cf3Schristos atf_check -s not-exit:0 -o empty -e not-empty \ 98606f9bef6Schristos ${TEST_SH} -c 'set -% ; echo ERR' 987c1ce7cf3Schristos} 988c1ce7cf3Schristos 989c1ce7cf3Schristosatf_test_case Option_switching 990c1ce7cf3SchristosOption_switching_head() { 991c1ce7cf3Schristos atf_set "descr" "options can be enabled and disabled" 992c1ce7cf3Schristos} 993c1ce7cf3SchristosOption_switching_body() { 994c1ce7cf3Schristos 995c1ce7cf3Schristos # Cannot test -m, setting it causes test shell to fail... 996c1ce7cf3Schristos # (test shell gets SIGKILL!) Wonder why ... something related to atf 997c1ce7cf3Schristos # That is, it works if just run as "sh -c 'echo $-; set -m; echo $-'" 998c1ce7cf3Schristos 999c1ce7cf3Schristos # Don't bother testing toggling -n, once on, it stays on... 1000c1ce7cf3Schristos # (and because the test fn refuses to allow us to try) 1001c1ce7cf3Schristos 1002c1ce7cf3Schristos # Cannot test -o or -c here, or the extension -s 1003c1ce7cf3Schristos # they can only be used, not switched 1004c1ce7cf3Schristos 1005c1ce7cf3Schristos # these are the posix options, that all shells should implement 1006c1ce7cf3Schristos test_option_on_off a b C e f h u v x # m 1007c1ce7cf3Schristos 1008c1ce7cf3Schristos # and these are extensions that might not exist (non-fatal to test) 1009c1ce7cf3Schristos # -i and -s (and -c) are posix options, but are not required to 1010*f42f89fdSandvar # be accessible via the "set" command, just the command line. 1011c1ce7cf3Schristos # We allow for -i to work with set, as that makes some sense, 1012c1ce7cf3Schristos # -c and -s do not. 1013a60600e0Skre test_optional_on_off E i I p q V X || true 1014c1ce7cf3Schristos 1015c1ce7cf3Schristos # Also test (some) option combinations ... 1016c1ce7cf3Schristos # only testing posix options here, because it is easier... 1017c1ce7cf3Schristos test_option_on_off aeu vx Ca aCefux 1018c1ce7cf3Schristos} 1019c1ce7cf3Schristos 1020c1ce7cf3Schristosatf_init_test_cases() { 1021c1ce7cf3Schristos # tests are run in order sort of names produces, so choose names wisely 1022c1ce7cf3Schristos 1023c1ce7cf3Schristos # this one tests turning on/off all the mandatory. and extra flags 1024c1ce7cf3Schristos atf_add_test_case Option_switching 1025c1ce7cf3Schristos # and this tests the NetBSD "local -" functionality in functions. 1026c1ce7cf3Schristos atf_add_test_case restore_local_opts 1027c1ce7cf3Schristos 1028c1ce7cf3Schristos # no tests for -m (no idea how to do that one) 1029c1ce7cf3Schristos # -I (no easy way to generate the EOF it ignores) 1030c1ce7cf3Schristos # -i (not sure how to test that one at the minute) 103106f9bef6Schristos # -p (because we aren't going to run tests setuid) 1032c1ce7cf3Schristos # -V/-E (too much effort, and a real test would be huge) 1033c1ce7cf3Schristos # -c (because almost all the other tests test it anyway) 1034c1ce7cf3Schristos # -q (because, for now, I am lazy) 1035c1ce7cf3Schristos # -s (coming soon, hopefully) 1036c1ce7cf3Schristos # -o (really +o: again, hopefully soon) 1037c1ce7cf3Schristos # -o longname (again, just laziness, don't wait...) 1038c1ce7cf3Schristos # -h/-b (because NetBSD doesn't implement them) 1039c1ce7cf3Schristos atf_add_test_case set_a 1040c1ce7cf3Schristos atf_add_test_case set_C 1041c1ce7cf3Schristos atf_add_test_case set_e 1042c1ce7cf3Schristos atf_add_test_case set_f 1043c1ce7cf3Schristos atf_add_test_case set_n 1044c1ce7cf3Schristos atf_add_test_case set_u 1045c1ce7cf3Schristos atf_add_test_case set_v 1046c1ce7cf3Schristos atf_add_test_case set_x 1047a60600e0Skre atf_add_test_case set_X 1048c1ce7cf3Schristos 1049c1ce7cf3Schristos atf_add_test_case vi_emacs_VE_toggle 105056aa5062Skre 105156aa5062Skre atf_add_test_case pipefail 105256aa5062Skre 1053c1ce7cf3Schristos atf_add_test_case xx_bogus 1054c1ce7cf3Schristos} 1055