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