Home | History | Annotate | Line # | Download | only in sh
t_option.sh revision 1.6
      1  1.6       kre # $NetBSD: t_option.sh,v 1.6 2017/11/16 19:41:41 kre 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.1  christos 	atf_set "descr" "Tests that 'set -n' supresses 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.3  christos 				${TEST_SH}
    458  1.1  christos }
    459  1.1  christos 
    460  1.1  christos atf_test_case set_x
    461  1.1  christos set_x_head() {
    462  1.1  christos 	atf_set "descr" "Tests that 'set -x' turns on command exec logging " \
    463  1.1  christos 	                "and that it behaves as defined by the standard"
    464  1.1  christos }
    465  1.1  christos set_x_body() {
    466  1.1  christos 	test_option_on_off x
    467  1.1  christos 
    468  1.1  christos 	# check that cmd output appears after -x is enabled
    469  1.1  christos 	atf_check -s exit:0 \
    470  1.1  christos 			-o match:OKOK -o not-match:echo -o not-match:printf \
    471  1.1  christos 			-e not-match:printf -e match:OK -e match:echo \
    472  1.2  christos 		${TEST_SH} -ec 'printf "%s" OK; set -x; echo OK; exit 0'
    473  1.1  christos 
    474  1.1  christos 	# and that it stops again afer -x is disabled
    475  1.1  christos 	atf_check -s exit:0 \
    476  1.1  christos 			-o match:OKOK -o not-match:echo -o not-match:printf \
    477  1.1  christos 			-e match:printf -e match:OK -e not-match:echo \
    478  1.2  christos 	    ${TEST_SH} -ec 'set -x; printf "%s" OK; set +x; echo OK; exit 0'
    479  1.1  christos 
    480  1.1  christos 	# also check that PS4 is output correctly
    481  1.1  christos 	atf_check -s exit:0 \
    482  1.1  christos 			-o match:OK -o not-match:echo \
    483  1.1  christos 			-e match:OK -e match:Run:echo \
    484  1.2  christos 		${TEST_SH} -ec 'PS4=Run:; set -x; echo OK; exit 0'
    485  1.1  christos 
    486  1.1  christos 	return 0
    487  1.1  christos 
    488  1.1  christos 	# This one seems controversial... I suspect it is NetBSD's sh
    489  1.1  christos 	# that is wrong to not output "for" "while" "if" ... etc
    490  1.1  christos 
    491  1.1  christos 	# and lastly, that shell keywords do not get output when "executed"
    492  1.1  christos 	atf_check -s exit:0 \
    493  1.1  christos 			-o match:111222333 -o not-match:printf \
    494  1.1  christos 			-o not-match:for \
    495  1.1  christos 			-e match:printf -e match:111 -e not-match:111222 \
    496  1.1  christos 			-e not-match:for -e not-match:do -e not-match:done \
    497  1.2  christos 		${TEST_SH} -ec \
    498  1.1  christos 	   'set -x; for i in 111 222 333; do printf "%s" $i; done; echo; exit 0'
    499  1.1  christos }
    500  1.1  christos 
    501  1.6       kre atf_test_case set_X
    502  1.6       kre set_X_head() {
    503  1.6       kre 	atf_set "descr" "Tests that 'set -X' turns on command exec logging " \
    504  1.6       kre 	                "and that it enables set -x and retains a single fd"
    505  1.6       kre }
    506  1.6       kre set_X_body() {
    507  1.6       kre 
    508  1.6       kre 	# First we need to verify that $TEST_SH supports -X
    509  1.6       kre 	test_optional_on_off X					||
    510  1.6       kre 		atf_skip "$TEST_SH does not support -X"
    511  1.6       kre 
    512  1.6       kre 	# and that the -X it implements is the -X we expect
    513  1.6       kre 	$TEST_SH -c 'exec 2>/dev/null;
    514  1.6       kre 		set +x; set -X;
    515  1.6       kre 		case "$-" in (*x*) exit 0;; esac;
    516  1.6       kre 		exit 1'						||
    517  1.6       kre 			atf_skip "$TEST_SH supports -X but not 'the' -X"
    518  1.6       kre 
    519  1.6       kre 	# Above has already tested that set -X => set -x
    520  1.6       kre 	# Now test that set +X => set +x
    521  1.6       kre 	# and that set -x and set +x do not affect -X
    522  1.6       kre 
    523  1.6       kre 	atf_check -s exit:0 -o empty -e ignore ${TEST_SH} -c \
    524  1.6       kre 		'set -x; set +X; case "$-" in (*x*) echo FAIL; exit 1;; esac'
    525  1.6       kre 
    526  1.6       kre 	atf_check -s exit:0 -o empty -e ignore ${TEST_SH} -c \
    527  1.6       kre 		'set -X; set +x;
    528  1.6       kre 		 case "$-" in (*x*) echo FAIL; exit 1;; esac
    529  1.6       kre 		 case "$-" in (*X*) exit 0;; esac; echo ERROR; exit 2'
    530  1.6       kre 
    531  1.6       kre 	atf_check -s exit:0 -o empty -e ignore ${TEST_SH} -c \
    532  1.6       kre 		'set -X; set +x; set -x;
    533  1.6       kre 		 case "$-" in (*x*X*|*X*x*) exit 0;; esac; echo ERROR; exit 2'
    534  1.6       kre 
    535  1.6       kre 	atf_check -s exit:0 -o empty -e ignore ${TEST_SH} -c \
    536  1.6       kre 		'set +X; set -x;
    537  1.6       kre 		 case "$-" in (*X*) echo FAIL; exit 1;; esac
    538  1.6       kre 		 case "$-" in (*x*) exit 0;; esac; echo ERROR; exit 2'
    539  1.6       kre 
    540  1.6       kre 	atf_check -s exit:0 -o empty -e ignore ${TEST_SH} -c \
    541  1.6       kre 		'set +X; set -x; set +x;
    542  1.6       kre 		 case "$-" in (*[xX]*) echo FAULT; exit 3;; esac'
    543  1.6       kre 
    544  1.6       kre 	# The following just verify regular tracing using -X instead of -x
    545  1.6       kre 	# These are the same tests as the -x test (set_x) performs.
    546  1.6       kre 
    547  1.6       kre 	# check that cmd output appears after -X is enabled
    548  1.6       kre 	atf_check -s exit:0 \
    549  1.6       kre 			-o match:OKOK -o not-match:echo -o not-match:printf \
    550  1.6       kre 			-e not-match:printf -e match:OK -e match:echo \
    551  1.6       kre 		${TEST_SH} -ec 'printf "%s" OK; set -X; echo OK; exit 0'
    552  1.6       kre 
    553  1.6       kre 	# and that it stops again afer -X is disabled
    554  1.6       kre 	atf_check -s exit:0 \
    555  1.6       kre 			-o match:OKOK -o not-match:echo -o not-match:printf \
    556  1.6       kre 			-e match:printf -e match:OK -e not-match:echo \
    557  1.6       kre 	    ${TEST_SH} -ec 'set -X; printf "%s" OK; set +X; echo OK; exit 0'
    558  1.6       kre 
    559  1.6       kre 	# also check that PS4 is output correctly
    560  1.6       kre 	atf_check -s exit:0 \
    561  1.6       kre 			-o match:OK -o not-match:echo \
    562  1.6       kre 			-e match:OK -e match:Run:echo \
    563  1.6       kre 		${TEST_SH} -ec 'PS4=Run:; set -X; echo OK; exit 0'
    564  1.6       kre 
    565  1.6       kre 	# end copies of -x tests ...
    566  1.6       kre 
    567  1.6       kre 	# now check that we can move stderr around without affecting -X output
    568  1.6       kre 
    569  1.6       kre 	atf_check -s exit:0 \
    570  1.6       kre 			-o match:OKOK -o not-match:echo -o not-match:printf \
    571  1.6       kre 			-e match:printf -e match:OK -e match:echo \
    572  1.6       kre 		${TEST_SH} -ecX 'printf "%s" OK; exec 2>/dev/null; echo OK'
    573  1.6       kre 	atf_check -s exit:0 \
    574  1.6       kre 			-o match:OKOK -o not-match:echo -o not-match:printf \
    575  1.6       kre 			-e match:printf -e match:OK -e match:echo \
    576  1.6       kre 		${TEST_SH} -ecX 'printf "%s" OK; exec 2>&1; echo OK'
    577  1.6       kre 	atf_check -s exit:0 \
    578  1.6       kre 			-o match:OKOK -o not-match:echo -o not-match:printf \
    579  1.6       kre 			-e match:printf -e match:OK -e match:echo \
    580  1.6       kre 		${TEST_SH} -ecX 'printf "%s" OK; exec 2>&-; echo OK'
    581  1.6       kre 
    582  1.6       kre 	# and that we can put tracing on an external file, leaving stderr alone
    583  1.6       kre 
    584  1.6       kre 	atf_require_prog grep
    585  1.6       kre 
    586  1.6       kre 	rm -f X-trace
    587  1.6       kre 	atf_check -s exit:0 \
    588  1.6       kre 			-o match:OKOK -o not-match:echo -o not-match:printf \
    589  1.6       kre 			-e empty \
    590  1.6       kre 		${TEST_SH} -ec 'PS4=; set -X 2>X-trace; printf "%s" OK; echo OK'
    591  1.6       kre 	test -s X-trace || atf_fail "T1: Failed to create trace output file"
    592  1.6       kre 	grep >/dev/null 2>&1 'printf.*%s.*OK' X-trace ||
    593  1.6       kre 		atf_fail "T1: -X tracing missing printf"
    594  1.6       kre 	grep >/dev/null 2>&1 'echo.*OK' X-trace ||
    595  1.6       kre 		atf_fail "T1: -X tracing missing echo"
    596  1.6       kre 
    597  1.6       kre 	rm -f X-trace
    598  1.6       kre 	atf_check -s exit:0 \
    599  1.6       kre 			-o match:OKOK -o not-match:echo -o not-match:printf \
    600  1.6       kre 			-e empty \
    601  1.6       kre 		${TEST_SH} -ec \
    602  1.6       kre 			'PS4=; set -X 2>X-trace;
    603  1.6       kre 			printf "%s" OK;
    604  1.6       kre 			exec 2>/dev/null;
    605  1.6       kre 			echo OK'
    606  1.6       kre 	test -s X-trace || atf_fail "T2: Failed to create trace output file"
    607  1.6       kre 	grep >/dev/null 2>&1 'printf.*%s.*OK' X-trace ||
    608  1.6       kre 		atf_fail "T2: -X tracing missing printf"
    609  1.6       kre 	grep >/dev/null 2>&1 'exec' X-trace ||
    610  1.6       kre 		atf_fail "T2: -X tracing missing exec"
    611  1.6       kre 	grep >/dev/null 2>&1 'echo.*OK' X-trace ||
    612  1.6       kre 		atf_fail "T2: -X tracing missing echo after stderr redirect"
    613  1.6       kre 
    614  1.6       kre 	rm -f X-trace
    615  1.6       kre 	atf_check -s exit:0 \
    616  1.6       kre 			-o match:OKOK -o not-match:echo -o not-match:printf \
    617  1.6       kre 			-e empty \
    618  1.6       kre 		${TEST_SH} -ec \
    619  1.6       kre 			'PS4=; set -X 2>X-trace;
    620  1.6       kre 			printf "%s" OK;
    621  1.6       kre 			set -X 2>/dev/null;
    622  1.6       kre 			echo OK'
    623  1.6       kre 	test -s X-trace || atf_fail "T3: Failed to create trace output file"
    624  1.6       kre 	grep >/dev/null 2>&1 'printf.*%s.*OK' X-trace ||
    625  1.6       kre 		atf_fail "T3: -X tracing missing printf"
    626  1.6       kre 	grep >/dev/null 2>&1 'set.*-X' X-trace ||
    627  1.6       kre 		atf_fail "T3: -X tracing missing set -X"
    628  1.6       kre 	grep >/dev/null 2>&1 'echo.*OK' X-trace &&
    629  1.6       kre 		atf_fail "T3: -X tracing included echo after set -X redirect"
    630  1.6       kre 
    631  1.6       kre 	rm -f X-trace
    632  1.6       kre 	atf_check -s exit:0 \
    633  1.6       kre 			-o match:OKOK -o not-match:echo -o not-match:printf \
    634  1.6       kre 			-e match:echo -e match:OK -e not-match:printf \
    635  1.6       kre 		${TEST_SH} -ec \
    636  1.6       kre 			'PS4=; set -X 2>X-trace;
    637  1.6       kre 			printf "%s" OK;
    638  1.6       kre 			set -X;
    639  1.6       kre 			echo OK'
    640  1.6       kre 	test -s X-trace || atf_fail "T4: Failed to create trace output file"
    641  1.6       kre 	grep >/dev/null 2>&1 'printf.*%s.*OK' X-trace ||
    642  1.6       kre 		atf_fail "T4: -X tracing missing printf"
    643  1.6       kre 	grep >/dev/null 2>&1 'set.*-X' X-trace ||
    644  1.6       kre 		atf_fail "T4: -X tracing missing set -X"
    645  1.6       kre 	grep >/dev/null 2>&1 'echo.*OK' X-trace &&
    646  1.6       kre 		atf_fail "T4: -X tracing included echo after set -X redirect"
    647  1.6       kre 
    648  1.6       kre 	# Now check that -X and the tracing files work properly wrt functions
    649  1.6       kre 
    650  1.6       kre 	# a shell that supports -X should support "local -" ... but verify
    651  1.6       kre 
    652  1.6       kre 	( ${TEST_SH} -c 'fn() { local - || exit 2; set -f; }; set +f; fn;
    653  1.6       kre 		case "$-" in ("*f*") exit 1;; esac; exit 0' ) 2>/dev/null ||
    654  1.6       kre 			atf_skip "-X function test: 'local -' unsupported"
    655  1.6       kre 
    656  1.6       kre 	rm -f X-trace X-trace-fn
    657  1.6       kre 	atf_check -s exit:0 \
    658  1.6       kre 			-o match:OKhelloGOOD		\
    659  1.6       kre 			-e empty			\
    660  1.6       kre 		${TEST_SH} -c '
    661  1.6       kre 			say() {
    662  1.6       kre 				printf "%s" "$*"
    663  1.6       kre 			}
    664  1.6       kre 			funct() {
    665  1.6       kre 				local -
    666  1.6       kre 
    667  1.6       kre 				set -X 2>X-trace-fn
    668  1.6       kre 				say hello
    669  1.6       kre 			}
    670  1.6       kre 
    671  1.6       kre 			set -X 2>X-trace
    672  1.6       kre 
    673  1.6       kre 			printf OK
    674  1.6       kre 			funct
    675  1.6       kre 			echo GOOD
    676  1.6       kre 		'
    677  1.6       kre 	test -s X-trace || atf_fail "T5: Failed to create trace output file"
    678  1.6       kre 	test -s X-trace-fn || atf_fail "T5: Failed to create fn trace output"
    679  1.6       kre 	grep >/dev/null 2>&1 'printf.*OK' X-trace ||
    680  1.6       kre 		atf_fail "T5: -X tracing missing printf"
    681  1.6       kre 	grep >/dev/null 2>&1 funct X-trace ||
    682  1.6       kre 		atf_fail "T5: -X tracing missing funct"
    683  1.6       kre 	grep >/dev/null 2>&1 'set.*-X' X-trace ||
    684  1.6       kre 		atf_fail "T5: -X tracing missing set -X from in funct"
    685  1.6       kre 	grep >/dev/null 2>&1 'echo.*GOOD' X-trace ||
    686  1.6       kre 		atf_fail "T5: -X tracing missing echo after funct redirect"
    687  1.6       kre 	grep >/dev/null 2>&1 'say.*hello' X-trace &&
    688  1.6       kre 		atf_fail "T5: -X tracing included 'say' after funct redirect"
    689  1.6       kre 	grep >/dev/null 2>&1 'say.*hello' X-trace-fn ||
    690  1.6       kre 		atf_fail "T5: -X funct tracing missed 'say'"
    691  1.6       kre 
    692  1.6       kre 	rm -f X-trace X-trace-fn
    693  1.6       kre 
    694  1.6       kre 	atf_check -s exit:0 \
    695  1.6       kre 			-o match:OKhelloGOOD		\
    696  1.6       kre 			-e empty			\
    697  1.6       kre 		${TEST_SH} -c '
    698  1.6       kre 			say() {
    699  1.6       kre 				printf "%s" "$*"
    700  1.6       kre 			}
    701  1.6       kre 			funct() {
    702  1.6       kre 				local -
    703  1.6       kre 
    704  1.6       kre 				set +X
    705  1.6       kre 				say hello
    706  1.6       kre 			}
    707  1.6       kre 
    708  1.6       kre 			set -X 2>X-trace
    709  1.6       kre 
    710  1.6       kre 			printf OK
    711  1.6       kre 			funct
    712  1.6       kre 			echo GOOD
    713  1.6       kre 		'
    714  1.6       kre 	test -s X-trace || atf_fail "T6: Failed to create trace output file"
    715  1.6       kre 	grep >/dev/null 2>&1 'printf.*OK' X-trace ||
    716  1.6       kre 		atf_fail "T6: -X tracing missing printf"
    717  1.6       kre 	grep >/dev/null 2>&1 funct X-trace ||
    718  1.6       kre 		atf_fail "T6: -X tracing missing funct"
    719  1.6       kre 	grep >/dev/null 2>&1 'set.*+X' X-trace ||
    720  1.6       kre 		atf_fail "T6: -X tracing missing set +X from in funct"
    721  1.6       kre 	grep >/dev/null 2>&1 'echo.*GOOD' X-trace ||
    722  1.6       kre 		atf_fail "T6: -X tracing missing echo after funct redirect"
    723  1.6       kre 	grep >/dev/null 2>&1 'say.*hello' X-trace &&
    724  1.6       kre 		atf_fail "T6: -X tracing included 'say' after funct redirect"
    725  1.6       kre 
    726  1.6       kre 	rm -f X-trace
    727  1.6       kre 
    728  1.6       kre 	atf_check -s exit:0 \
    729  1.6       kre 			-o match:OKtracednotraceGOOD \
    730  1.6       kre 			-e match:say -e match:traced -e not-match:notrace \
    731  1.6       kre 		${TEST_SH} -c '
    732  1.6       kre 			say() {
    733  1.6       kre 				printf "%s" "$*"
    734  1.6       kre 			}
    735  1.6       kre 			funct() {
    736  1.6       kre 				local -
    737  1.6       kre 
    738  1.6       kre 				set +X -x
    739  1.6       kre 
    740  1.6       kre 				say traced
    741  1.6       kre 				exec 2>/dev/null
    742  1.6       kre 				say notrace
    743  1.6       kre 
    744  1.6       kre 			}
    745  1.6       kre 
    746  1.6       kre 			set -X 2>X-trace
    747  1.6       kre 
    748  1.6       kre 			printf OK
    749  1.6       kre 			funct
    750  1.6       kre 			echo GOOD
    751  1.6       kre 		'
    752  1.6       kre 	test -s X-trace || atf_fail "T7: Failed to create trace output file"
    753  1.6       kre 	grep >/dev/null 2>&1 'printf.*OK' X-trace ||
    754  1.6       kre 		atf_fail "T7: -X tracing missing printf"
    755  1.6       kre 	grep >/dev/null 2>&1 funct X-trace ||
    756  1.6       kre 		atf_fail "T7: -X tracing missing funct"
    757  1.6       kre 	grep >/dev/null 2>&1 'set.*+X.*-x' X-trace ||
    758  1.6       kre 		atf_fail "T7: -X tracing missing set +X -x from in funct"
    759  1.6       kre 	grep >/dev/null 2>&1 'echo.*GOOD' X-trace ||
    760  1.6       kre 		atf_fail "T7: -X tracing missing echo after funct +X"
    761  1.6       kre 	grep >/dev/null 2>&1 'say.*hello' X-trace &&
    762  1.6       kre 		atf_fail "T7: -X tracing included 'say' after funct +X"
    763  1.6       kre 
    764  1.6       kre 	rm -f X-trace X-trace-fn
    765  1.6       kre 	atf_check -s exit:0 \
    766  1.6       kre 			-o "match:OKg'daybye-bye.*hello.*GOOD"		\
    767  1.6       kre 			-e empty 					\
    768  1.6       kre 		${TEST_SH} -c '
    769  1.6       kre 			say() {
    770  1.6       kre 				printf "%s" "$*"
    771  1.6       kre 			}
    772  1.6       kre 			fn1() {
    773  1.6       kre 				local -
    774  1.6       kre 
    775  1.6       kre 				set -X 2>>X-trace-fn
    776  1.6       kre 				say "g'\''day"
    777  1.6       kre 				"$@"
    778  1.6       kre 				say bye-bye
    779  1.6       kre 			}
    780  1.6       kre 			fn2() {
    781  1.6       kre 				set +X
    782  1.6       kre 				say hello
    783  1.6       kre 				"$@"
    784  1.6       kre 				say goodbye
    785  1.6       kre 			}
    786  1.6       kre 
    787  1.6       kre 			set -X 2>X-trace
    788  1.6       kre 
    789  1.6       kre 			printf OK
    790  1.6       kre 			fn1
    791  1.6       kre 			fn1 fn2
    792  1.6       kre 			fn1 fn1 fn2
    793  1.6       kre 			fn1 fn2 fn1 fn2 fn1
    794  1.6       kre 			fn1 fn1 fn2 fn2 fn1
    795  1.6       kre 			echo GOOD
    796  1.6       kre 		'
    797  1.6       kre 
    798  1.6       kre 	# That test generally succeeds if the earlier ones did 
    799  1.6       kre 	# and if it did not dump core!
    800  1.6       kre 
    801  1.6       kre 	# But we can check a few things...
    802  1.6       kre 
    803  1.6       kre 	test -s X-trace || atf_fail "T8: Failed to create trace output file"
    804  1.6       kre 	test -s X-trace-fn || atf_fail "T8: Failed to create trace output file"
    805  1.6       kre 	grep >/dev/null 2>&1 'printf.*OK' X-trace ||
    806  1.6       kre 		atf_fail "T8: -X tracing missing printf"
    807  1.6       kre 	grep >/dev/null 2>&1 fn1 X-trace ||
    808  1.6       kre 		atf_fail "T8: -X tracing missing fn1"
    809  1.6       kre 	grep >/dev/null 2>&1 'set.*-X' X-trace ||
    810  1.6       kre 		atf_fail "T8: -X tracing missing set -X from in fn1"
    811  1.6       kre 	grep >/dev/null 2>&1 'echo.*GOOD' X-trace ||
    812  1.6       kre 		atf_fail "T8: -X tracing missing echo after fn1 redirect"
    813  1.6       kre 	grep >/dev/null 2>&1 'say.*hello' X-trace &&
    814  1.6       kre 		atf_fail "T8: -X tracing included 'say' after fn2 +X"
    815  1.6       kre 	grep >/dev/null 2>&1 'say.*hello' X-trace-fn &&
    816  1.6       kre 		atf_fail "T8: -X fn tracing included 'say' after fn2 +X"
    817  1.6       kre 
    818  1.6       kre 
    819  1.6       kre 	rm -f X-trace
    820  1.6       kre 
    821  1.6       kre 	return 0
    822  1.6       kre }
    823  1.6       kre 
    824  1.1  christos opt_test_setup()
    825  1.1  christos {
    826  1.1  christos 	test -n "$1" || { echo >&2 "Internal error"; exit 1; }
    827  1.1  christos 
    828  1.1  christos 	cat > "$1" << 'END_OF_FUNCTIONS'
    829  1.1  christos local_opt_check()
    830  1.1  christos {
    831  1.1  christos 	local -
    832  1.1  christos }
    833  1.1  christos 
    834  1.1  christos instr()
    835  1.1  christos {
    836  1.1  christos 	expr "$2" : "\(.*$1\)" >/dev/null
    837  1.1  christos }
    838  1.1  christos 
    839  1.1  christos save_opts()
    840  1.1  christos {
    841  1.1  christos 	local -
    842  1.1  christos 
    843  1.1  christos 	set -e
    844  1.1  christos 	set -u
    845  1.1  christos 
    846  1.1  christos 	instr e "$-" && instr u "$-" && return 0
    847  1.1  christos 	echo ERR
    848  1.1  christos }
    849  1.1  christos 
    850  1.1  christos fiddle_opts()
    851  1.1  christos {
    852  1.1  christos 	set -e
    853  1.1  christos 	set -u
    854  1.1  christos 
    855  1.1  christos 	instr e "$-" && instr u "$-" && return 0
    856  1.1  christos 	echo ERR
    857  1.1  christos }
    858  1.1  christos 
    859  1.1  christos local_test()
    860  1.1  christos {
    861  1.1  christos 	set +eu
    862  1.1  christos 
    863  1.1  christos 	save_opts
    864  1.1  christos 	instr '[eu]' "$-" || printf %s "OK"
    865  1.1  christos 
    866  1.1  christos 	fiddle_opts
    867  1.1  christos 	instr e "$-" && instr u "$-" && printf %s "OK"
    868  1.1  christos 
    869  1.1  christos 	set +eu
    870  1.1  christos }
    871  1.1  christos END_OF_FUNCTIONS
    872  1.1  christos }
    873  1.1  christos 
    874  1.1  christos atf_test_case restore_local_opts
    875  1.1  christos restore_local_opts_head() {
    876  1.1  christos 	atf_set "descr" "Tests that 'local -' saves and restores options.  " \
    877  1.1  christos 			"Note that "local" is a local shell addition"
    878  1.1  christos }
    879  1.1  christos restore_local_opts_body() {
    880  1.1  christos 	atf_require_prog cat
    881  1.1  christos 	atf_require_prog expr
    882  1.1  christos 
    883  1.1  christos 	FN="test-funcs.$$"
    884  1.1  christos 	opt_test_setup "${FN}" || atf_skip "Cannot setup test environment"
    885  1.1  christos 
    886  1.2  christos 	${TEST_SH} -ec ". './${FN}'; local_opt_check" 2>/dev/null ||
    887  1.1  christos 		atf_skip "sh extension 'local -' not supported by ${TEST_SH}"
    888  1.1  christos 
    889  1.1  christos 	atf_check -s exit:0 -o match:OKOK -o not-match:ERR -e empty \
    890  1.2  christos 		${TEST_SH} -ec ". './${FN}'; local_test"
    891  1.1  christos }
    892  1.1  christos 
    893  1.1  christos atf_test_case vi_emacs_VE_toggle
    894  1.1  christos vi_emacs_VE_toggle_head() {
    895  1.1  christos 	atf_set "descr" "Tests enabling vi disables emacs (and v.v - but why?)"\
    896  1.1  christos 			"  Note that -V and -E are local shell additions"
    897  1.1  christos }
    898  1.1  christos vi_emacs_VE_toggle_body() {
    899  1.1  christos 
    900  1.1  christos 	test_optional_on_off V E ||
    901  1.1  christos 	  atf_skip "One or both V & E opts unsupported by ${TEST_SH}"
    902  1.1  christos 
    903  1.2  christos 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c '
    904  1.1  christos 		q() {
    905  1.1  christos 			eval "case \"$-\" in
    906  1.1  christos 			(*${2}*)	return 1;;
    907  1.1  christos 			(*${1}*)	return 0;;
    908  1.1  christos 			esac"
    909  1.1  christos 			return 1
    910  1.1  christos 		}
    911  1.1  christos 		x() {
    912  1.1  christos 			echo >&2 "Option set or toggle failure:" \
    913  1.1  christos 					" on=$1 off=$2 set=$-"
    914  1.1  christos 			exit 1
    915  1.1  christos 		}
    916  1.1  christos 		set -V; q V E || x V E
    917  1.1  christos 		set -E; q E V || x E V
    918  1.1  christos 		set -V; q V E || x V E
    919  1.1  christos 		set +EV; q "" "[VE]" || x "" VE
    920  1.1  christos 		exit 0
    921  1.1  christos 	'
    922  1.1  christos }
    923  1.1  christos 
    924  1.5       kre atf_test_case pipefail
    925  1.5       kre pipefail_head() {
    926  1.5       kre 	atf_set "descr" "Basic tests of the pipefail option"
    927  1.5       kre }
    928  1.5       kre pipefail_body() {
    929  1.5       kre 	${TEST_SH} -c 'set -o pipefail' 2>/dev/null ||
    930  1.5       kre 		atf_skip "pipefail option not supported by ${TEST_SH}"
    931  1.5       kre 
    932  1.5       kre 	atf_check -s exit:0 -o match:'pipefail.*off' -e empty ${TEST_SH} -c \
    933  1.5       kre 		'set -o | grep pipefail'
    934  1.5       kre 	atf_check -s exit:0 -o match:'pipefail.*on' -e empty ${TEST_SH} -c \
    935  1.5       kre 		'set -o pipefail; set -o | grep pipefail'
    936  1.5       kre 
    937  1.5       kre 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    938  1.5       kre 		'(exit 1) | (exit 2) | (exit 0)'
    939  1.5       kre 	atf_check -s exit:2 -o empty -e empty ${TEST_SH} -c \
    940  1.5       kre 		'set -o pipefail; (exit 1) | (exit 2) | (exit 0)'
    941  1.5       kre 	atf_check -s exit:1 -o empty -e empty ${TEST_SH} -c \
    942  1.5       kre 		'set -o pipefail; (exit 1) | (exit 0) | (exit 0)'
    943  1.5       kre 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    944  1.5       kre 		'set -o pipefail; (exit 0) | (exit 0) | (exit 0)'
    945  1.5       kre 
    946  1.5       kre 	atf_check -s exit:1 -o empty -e empty ${TEST_SH} -c \
    947  1.5       kre 		'! (exit 1) | (exit 2) | (exit 0)'
    948  1.5       kre 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    949  1.5       kre 		'set -o pipefail; ! (exit 1) | (exit 2) | (exit 0)'
    950  1.5       kre 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
    951  1.5       kre 		'set -o pipefail; ! (exit 1) | (exit 0) | (exit 0)'
    952  1.5       kre 	atf_check -s exit:1 -o empty -e empty ${TEST_SH} -c \
    953  1.5       kre 		'set -o pipefail; ! (exit 0) | (exit 0) | (exit 0)'
    954  1.5       kre 
    955  1.5       kre 	atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
    956  1.5       kre 		'(exit 1) | (exit 2) | (exit 0); echo $?'
    957  1.5       kre 	atf_check -s exit:0 -o inline:'2\n' -e empty ${TEST_SH} -c \
    958  1.5       kre 		'set -o pipefail; (exit 1) | (exit 2) | (exit 0); echo $?'
    959  1.5       kre 	atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
    960  1.5       kre 		'set -o pipefail; (exit 1) | (exit 0) | (exit 0); echo $?'
    961  1.5       kre 	atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
    962  1.5       kre 		'set -o pipefail; (exit 0) | (exit 0) | (exit 0); echo $?'
    963  1.5       kre 
    964  1.5       kre 	atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
    965  1.5       kre 		'! (exit 1) | (exit 2) | (exit 0); echo $?'
    966  1.5       kre 	atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
    967  1.5       kre 		'set -o pipefail; ! (exit 1) | (exit 2) | (exit 0); echo $?'
    968  1.5       kre 	atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
    969  1.5       kre 		'set -o pipefail; ! (exit 1) | (exit 0) | (exit 0); echo $?'
    970  1.5       kre 	atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
    971  1.5       kre 		'set -o pipefail; ! (exit 0) | (exit 0) | (exit 0); echo $?'
    972  1.5       kre }
    973  1.5       kre 
    974  1.1  christos atf_test_case xx_bogus
    975  1.1  christos xx_bogus_head() {
    976  1.1  christos 	atf_set "descr" "Tests that attempting to set a nonsense option fails."
    977  1.1  christos }
    978  1.1  christos xx_bogus_body() {
    979  1.1  christos 	# Biggest problem here is picking a "nonsense option" that is
    980  1.1  christos 	# not implemented by any shell, anywhere.  Hopefully this will do.
    981  1.3  christos 
    982  1.3  christos 	# 'set' is a special builtin, so a conforming shell should exit
    983  1.3  christos 	# on an arg error, and the ERR should not be printed.
    984  1.1  christos 	atf_check -s not-exit:0 -o empty -e not-empty \
    985  1.2  christos 		${TEST_SH} -c 'set -% ; echo ERR'
    986  1.1  christos }
    987  1.1  christos 
    988  1.1  christos atf_test_case Option_switching
    989  1.1  christos Option_switching_head() {
    990  1.1  christos 	atf_set "descr" "options can be enabled and disabled"
    991  1.1  christos }
    992  1.1  christos Option_switching_body() {
    993  1.1  christos 
    994  1.1  christos 	# Cannot test -m, setting it causes test shell to fail...
    995  1.1  christos 	# (test shell gets SIGKILL!)  Wonder why ... something related to atf
    996  1.1  christos 	# That is, it works if just run as "sh -c 'echo $-; set -m; echo $-'"
    997  1.1  christos 
    998  1.1  christos 	# Don't bother testing toggling -n, once on, it stays on...
    999  1.1  christos 	# (and because the test fn refuses to allow us to try)
   1000  1.1  christos 
   1001  1.1  christos 	# Cannot test -o or -c here, or the extension -s
   1002  1.1  christos 	# they can only be used, not switched
   1003  1.1  christos 
   1004  1.1  christos 	# these are the posix options, that all shells should implement
   1005  1.1  christos 	test_option_on_off a b C e f h u v x      # m
   1006  1.1  christos 
   1007  1.1  christos 	# and these are extensions that might not exist (non-fatal to test)
   1008  1.1  christos 	# -i and -s (and -c) are posix options, but are not required to
   1009  1.1  christos 	# be accessable via the "set" command, just the command line.
   1010  1.1  christos 	# We allow for -i to work with set, as that makes some sense,
   1011  1.1  christos 	# -c and -s do not.
   1012  1.6       kre 	test_optional_on_off E i I p q V X || true
   1013  1.1  christos 
   1014  1.1  christos 	# Also test (some) option combinations ...
   1015  1.1  christos 	# only testing posix options here, because it is easier...
   1016  1.1  christos 	test_option_on_off aeu vx Ca aCefux
   1017  1.1  christos }
   1018  1.1  christos 
   1019  1.1  christos atf_init_test_cases() {
   1020  1.1  christos 	# tests are run in order sort of names produces, so choose names wisely
   1021  1.1  christos 
   1022  1.1  christos 	# this one tests turning on/off all the mandatory. and extra flags
   1023  1.1  christos 	atf_add_test_case Option_switching
   1024  1.1  christos 	# and this tests the NetBSD "local -" functionality in functions.
   1025  1.1  christos 	atf_add_test_case restore_local_opts
   1026  1.1  christos 
   1027  1.1  christos 	# no tests for	-m (no idea how to do that one)
   1028  1.1  christos 	#		-I (no easy way to generate the EOF it ignores)
   1029  1.1  christos 	#		-i (not sure how to test that one at the minute)
   1030  1.2  christos 	#		-p (because we aren't going to run tests setuid)
   1031  1.1  christos 	#		-V/-E (too much effort, and a real test would be huge)
   1032  1.1  christos 	#		-c (because almost all the other tests test it anyway)
   1033  1.1  christos 	#		-q (because, for now, I am lazy)
   1034  1.1  christos 	#		-s (coming soon, hopefully)
   1035  1.1  christos 	#		-o (really +o: again, hopefully soon)
   1036  1.1  christos 	#		-o longname (again, just laziness, don't wait...)
   1037  1.1  christos 	# 		-h/-b (because NetBSD doesn't implement them)
   1038  1.1  christos 	atf_add_test_case set_a
   1039  1.1  christos 	atf_add_test_case set_C
   1040  1.1  christos 	atf_add_test_case set_e
   1041  1.1  christos 	atf_add_test_case set_f
   1042  1.1  christos 	atf_add_test_case set_n
   1043  1.1  christos 	atf_add_test_case set_u
   1044  1.1  christos 	atf_add_test_case set_v
   1045  1.1  christos 	atf_add_test_case set_x
   1046  1.6       kre 	atf_add_test_case set_X
   1047  1.1  christos 
   1048  1.1  christos 	atf_add_test_case vi_emacs_VE_toggle
   1049  1.5       kre 
   1050  1.5       kre 	atf_add_test_case pipefail
   1051  1.5       kre 
   1052  1.1  christos 	atf_add_test_case xx_bogus
   1053  1.1  christos }
   1054