Home | History | Annotate | Line # | Download | only in sh
t_option.sh revision 1.3
      1  1.3  christos # $NetBSD: t_option.sh,v 1.3 2016/03/08 14:19:28 christos 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.1  christos 			(*[xv]*)	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.1  christos 	# first make sure it is OK to unset an unset variable
    360  1.2  christos 	atf_check -s exit:0 -o match:OK -e empty ${TEST_SH} -ce \
    361  1.1  christos 		'unset _UNSET_VARIABLE_; echo OK'
    362  1.1  christos 	# even if -u is set
    363  1.2  christos 	atf_check -s exit:0 -o match:OK -e empty ${TEST_SH} -cue \
    364  1.1  christos 		'unset _UNSET_VARIABLE_; echo OK'
    365  1.1  christos 
    366  1.1  christos 	# and that without -u accessing an unset variable is harmless
    367  1.2  christos 	atf_check -s exit:0 -o match:OK -e empty ${TEST_SH} -ce \
    368  1.1  christos 		'unset X; echo ${X}; echo OK'
    369  1.1  christos 	# and that the unset variable test expansion works properly
    370  1.2  christos 	atf_check -s exit:0 -o match:OKOK -e empty ${TEST_SH} -ce \
    371  1.1  christos 		'unset X; printf "%s" ${X-OK}; echo OK'
    372  1.1  christos 
    373  1.1  christos 	# Next test that with -u set, the shell aborts on access to unset var
    374  1.1  christos 	# do not use -e, want to make sure it is -u that causes abort
    375  1.2  christos 	atf_check -s not-exit:0 -o not-match:ERR -e not-empty ${TEST_SH} -c \
    376  1.1  christos 		'unset X; set -u; echo ${X}; echo ERR'
    377  1.1  christos 	# quoting should make no difference...
    378  1.2  christos 	atf_check -s not-exit:0 -o not-match:ERR -e not-empty ${TEST_SH} -c \
    379  1.1  christos 		'unset X; set -u; echo "${X}"; echo ERR'
    380  1.1  christos 
    381  1.1  christos 	# Now a bunch of accesses to unset vars, with -u, in ways that are OK
    382  1.2  christos 	atf_check -s exit:0 -o match:OK -e empty ${TEST_SH} -ce \
    383  1.1  christos 		'unset X; set -u; echo ${X-GOOD}; echo 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-OK}'
    386  1.1  christos 	atf_check -s exit:0 -o not-match:ERR -o match:OK -e empty \
    387  1.2  christos 		${TEST_SH} -ce 'unset X; set -u; echo ${X+ERR}; echo OK'
    388  1.1  christos 
    389  1.1  christos 	# and some more ways that are not OK
    390  1.2  christos 	atf_check -s not-exit:0 -o not-match:ERR -e not-empty ${TEST_SH} -c \
    391  1.1  christos 		'unset X; set -u; echo ${X#foo}; echo ERR'
    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%%bar}; echo ERR'
    394  1.1  christos 
    395  1.1  christos 	# lastly, just while we are checking unset vars, test aborts w/o -u
    396  1.2  christos 	atf_check -s not-exit:0 -o not-match:ERR -e not-empty ${TEST_SH} -c \
    397  1.1  christos 		'unset X; echo ${X?}; echo ERR'
    398  1.1  christos 	atf_check -s not-exit:0 -o not-match:ERR -e match:X_NOT_SET \
    399  1.2  christos 		${TEST_SH} -c 'unset X; echo ${X?X_NOT_SET}; echo ERR'
    400  1.1  christos }
    401  1.1  christos 
    402  1.1  christos atf_test_case set_v
    403  1.1  christos set_v_head() {
    404  1.1  christos 	atf_set "descr" "Tests that 'set -v' turns on input read echoing " \
    405  1.1  christos 	                "and that it behaves as defined by the standard"
    406  1.1  christos }
    407  1.1  christos set_v_body() {
    408  1.1  christos 	test_option_on_off v
    409  1.1  christos 
    410  1.1  christos 	# check that -v does nothing if no later input line is read
    411  1.1  christos 	atf_check -s exit:0 \
    412  1.1  christos 			-o match:OKOK -o not-match:echo -o not-match:printf \
    413  1.1  christos 			-e empty \
    414  1.2  christos 		${TEST_SH} -ec 'printf "%s" OK; set -v; echo OK; exit 0'
    415  1.1  christos 
    416  1.1  christos 	# but that it does when there are multiple lines
    417  1.3  christos 	cat <<- 'EOF' |
    418  1.3  christos 		set -v
    419  1.3  christos 		printf %s OK
    420  1.3  christos 		echo OK
    421  1.3  christos 		exit 0
    422  1.3  christos 	EOF
    423  1.1  christos 	atf_check -s exit:0 \
    424  1.1  christos 			-o match:OKOK -o not-match:echo -o not-match:printf \
    425  1.1  christos 			-e match:printf -e match:OK -e match:echo \
    426  1.3  christos 			-e not-match:set ${TEST_SH}
    427  1.1  christos 
    428  1.1  christos 	# and that it can be disabled again
    429  1.3  christos 	cat <<- 'EOF' |
    430  1.3  christos 		set -v
    431  1.3  christos 		printf %s OK
    432  1.3  christos 		set +v
    433  1.3  christos 		echo OK
    434  1.3  christos 		exit 0
    435  1.3  christos 	EOF
    436  1.1  christos 	atf_check -s exit:0 \
    437  1.1  christos 			-o match:OKOK -o not-match:echo -o not-match:printf \
    438  1.1  christos 			-e match:printf -e match:OK -e not-match:echo \
    439  1.3  christos 				${TEST_SH}
    440  1.1  christos 
    441  1.1  christos 	# and lastly, that shell keywords do get output when "read"
    442  1.3  christos 	cat <<- 'EOF' |
    443  1.3  christos 		set -v
    444  1.3  christos 		for i in 111 222 333
    445  1.3  christos 		do
    446  1.3  christos 			printf %s $i
    447  1.3  christos 		done
    448  1.3  christos 		exit 0
    449  1.3  christos 	EOF
    450  1.1  christos 	atf_check -s exit:0 \
    451  1.1  christos 			-o match:111222333 -o not-match:printf \
    452  1.1  christos 			-o not-match:for -o not-match:do -o not-match:done \
    453  1.1  christos 			-e match:printf -e match:111 -e not-match:111222 \
    454  1.1  christos 			-e match:for -e match:do -e match:done \
    455  1.3  christos 				${TEST_SH}
    456  1.1  christos }
    457  1.1  christos 
    458  1.1  christos atf_test_case set_x
    459  1.1  christos set_x_head() {
    460  1.1  christos 	atf_set "descr" "Tests that 'set -x' turns on command exec logging " \
    461  1.1  christos 	                "and that it behaves as defined by the standard"
    462  1.1  christos }
    463  1.1  christos set_x_body() {
    464  1.1  christos 	test_option_on_off x
    465  1.1  christos 
    466  1.1  christos 	# check that cmd output appears after -x is enabled
    467  1.1  christos 	atf_check -s exit:0 \
    468  1.1  christos 			-o match:OKOK -o not-match:echo -o not-match:printf \
    469  1.1  christos 			-e not-match:printf -e match:OK -e match:echo \
    470  1.2  christos 		${TEST_SH} -ec 'printf "%s" OK; set -x; echo OK; exit 0'
    471  1.1  christos 
    472  1.1  christos 	# and that it stops again afer -x is disabled
    473  1.1  christos 	atf_check -s exit:0 \
    474  1.1  christos 			-o match:OKOK -o not-match:echo -o not-match:printf \
    475  1.1  christos 			-e match:printf -e match:OK -e not-match:echo \
    476  1.2  christos 	    ${TEST_SH} -ec 'set -x; printf "%s" OK; set +x; echo OK; exit 0'
    477  1.1  christos 
    478  1.1  christos 	# also check that PS4 is output correctly
    479  1.1  christos 	atf_check -s exit:0 \
    480  1.1  christos 			-o match:OK -o not-match:echo \
    481  1.1  christos 			-e match:OK -e match:Run:echo \
    482  1.2  christos 		${TEST_SH} -ec 'PS4=Run:; set -x; echo OK; exit 0'
    483  1.1  christos 
    484  1.1  christos 	return 0
    485  1.1  christos 
    486  1.1  christos 	# This one seems controversial... I suspect it is NetBSD's sh
    487  1.1  christos 	# that is wrong to not output "for" "while" "if" ... etc
    488  1.1  christos 
    489  1.1  christos 	# and lastly, that shell keywords do not get output when "executed"
    490  1.1  christos 	atf_check -s exit:0 \
    491  1.1  christos 			-o match:111222333 -o not-match:printf \
    492  1.1  christos 			-o not-match:for \
    493  1.1  christos 			-e match:printf -e match:111 -e not-match:111222 \
    494  1.1  christos 			-e not-match:for -e not-match:do -e not-match:done \
    495  1.2  christos 		${TEST_SH} -ec \
    496  1.1  christos 	   'set -x; for i in 111 222 333; do printf "%s" $i; done; echo; exit 0'
    497  1.1  christos }
    498  1.1  christos 
    499  1.1  christos opt_test_setup()
    500  1.1  christos {
    501  1.1  christos 	test -n "$1" || { echo >&2 "Internal error"; exit 1; }
    502  1.1  christos 
    503  1.1  christos 	cat > "$1" << 'END_OF_FUNCTIONS'
    504  1.1  christos local_opt_check()
    505  1.1  christos {
    506  1.1  christos 	local -
    507  1.1  christos }
    508  1.1  christos 
    509  1.1  christos instr()
    510  1.1  christos {
    511  1.1  christos 	expr "$2" : "\(.*$1\)" >/dev/null
    512  1.1  christos }
    513  1.1  christos 
    514  1.1  christos save_opts()
    515  1.1  christos {
    516  1.1  christos 	local -
    517  1.1  christos 
    518  1.1  christos 	set -e
    519  1.1  christos 	set -u
    520  1.1  christos 
    521  1.1  christos 	instr e "$-" && instr u "$-" && return 0
    522  1.1  christos 	echo ERR
    523  1.1  christos }
    524  1.1  christos 
    525  1.1  christos fiddle_opts()
    526  1.1  christos {
    527  1.1  christos 	set -e
    528  1.1  christos 	set -u
    529  1.1  christos 
    530  1.1  christos 	instr e "$-" && instr u "$-" && return 0
    531  1.1  christos 	echo ERR
    532  1.1  christos }
    533  1.1  christos 
    534  1.1  christos local_test()
    535  1.1  christos {
    536  1.1  christos 	set +eu
    537  1.1  christos 
    538  1.1  christos 	save_opts
    539  1.1  christos 	instr '[eu]' "$-" || printf %s "OK"
    540  1.1  christos 
    541  1.1  christos 	fiddle_opts
    542  1.1  christos 	instr e "$-" && instr u "$-" && printf %s "OK"
    543  1.1  christos 
    544  1.1  christos 	set +eu
    545  1.1  christos }
    546  1.1  christos END_OF_FUNCTIONS
    547  1.1  christos }
    548  1.1  christos 
    549  1.1  christos atf_test_case restore_local_opts
    550  1.1  christos restore_local_opts_head() {
    551  1.1  christos 	atf_set "descr" "Tests that 'local -' saves and restores options.  " \
    552  1.1  christos 			"Note that "local" is a local shell addition"
    553  1.1  christos }
    554  1.1  christos restore_local_opts_body() {
    555  1.1  christos 	atf_require_prog cat
    556  1.1  christos 	atf_require_prog expr
    557  1.1  christos 
    558  1.1  christos 	FN="test-funcs.$$"
    559  1.1  christos 	opt_test_setup "${FN}" || atf_skip "Cannot setup test environment"
    560  1.1  christos 
    561  1.2  christos 	${TEST_SH} -ec ". './${FN}'; local_opt_check" 2>/dev/null ||
    562  1.1  christos 		atf_skip "sh extension 'local -' not supported by ${TEST_SH}"
    563  1.1  christos 
    564  1.1  christos 	atf_check -s exit:0 -o match:OKOK -o not-match:ERR -e empty \
    565  1.2  christos 		${TEST_SH} -ec ". './${FN}'; local_test"
    566  1.1  christos }
    567  1.1  christos 
    568  1.1  christos atf_test_case vi_emacs_VE_toggle
    569  1.1  christos vi_emacs_VE_toggle_head() {
    570  1.1  christos 	atf_set "descr" "Tests enabling vi disables emacs (and v.v - but why?)"\
    571  1.1  christos 			"  Note that -V and -E are local shell additions"
    572  1.1  christos }
    573  1.1  christos vi_emacs_VE_toggle_body() {
    574  1.1  christos 
    575  1.1  christos 	test_optional_on_off V E ||
    576  1.1  christos 	  atf_skip "One or both V & E opts unsupported by ${TEST_SH}"
    577  1.1  christos 
    578  1.2  christos 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c '
    579  1.1  christos 		q() {
    580  1.1  christos 			eval "case \"$-\" in
    581  1.1  christos 			(*${2}*)	return 1;;
    582  1.1  christos 			(*${1}*)	return 0;;
    583  1.1  christos 			esac"
    584  1.1  christos 			return 1
    585  1.1  christos 		}
    586  1.1  christos 		x() {
    587  1.1  christos 			echo >&2 "Option set or toggle failure:" \
    588  1.1  christos 					" on=$1 off=$2 set=$-"
    589  1.1  christos 			exit 1
    590  1.1  christos 		}
    591  1.1  christos 		set -V; q V E || x V E
    592  1.1  christos 		set -E; q E V || x E V
    593  1.1  christos 		set -V; q V E || x V E
    594  1.1  christos 		set +EV; q "" "[VE]" || x "" VE
    595  1.1  christos 		exit 0
    596  1.1  christos 	'
    597  1.1  christos }
    598  1.1  christos 
    599  1.1  christos atf_test_case xx_bogus
    600  1.1  christos xx_bogus_head() {
    601  1.1  christos 	atf_set "descr" "Tests that attempting to set a nonsense option fails."
    602  1.1  christos }
    603  1.1  christos xx_bogus_body() {
    604  1.1  christos 	# Biggest problem here is picking a "nonsense option" that is
    605  1.1  christos 	# not implemented by any shell, anywhere.  Hopefully this will do.
    606  1.3  christos 
    607  1.3  christos 	# 'set' is a special builtin, so a conforming shell should exit
    608  1.3  christos 	# on an arg error, and the ERR should not be printed.
    609  1.1  christos 	atf_check -s not-exit:0 -o empty -e not-empty \
    610  1.2  christos 		${TEST_SH} -c 'set -% ; echo ERR'
    611  1.1  christos }
    612  1.1  christos 
    613  1.1  christos atf_test_case Option_switching
    614  1.1  christos Option_switching_head() {
    615  1.1  christos 	atf_set "descr" "options can be enabled and disabled"
    616  1.1  christos }
    617  1.1  christos Option_switching_body() {
    618  1.1  christos 
    619  1.1  christos 	# Cannot test -m, setting it causes test shell to fail...
    620  1.1  christos 	# (test shell gets SIGKILL!)  Wonder why ... something related to atf
    621  1.1  christos 	# That is, it works if just run as "sh -c 'echo $-; set -m; echo $-'"
    622  1.1  christos 
    623  1.1  christos 	# Don't bother testing toggling -n, once on, it stays on...
    624  1.1  christos 	# (and because the test fn refuses to allow us to try)
    625  1.1  christos 
    626  1.1  christos 	# Cannot test -o or -c here, or the extension -s
    627  1.1  christos 	# they can only be used, not switched
    628  1.1  christos 
    629  1.1  christos 	# these are the posix options, that all shells should implement
    630  1.1  christos 	test_option_on_off a b C e f h u v x      # m
    631  1.1  christos 
    632  1.1  christos 	# and these are extensions that might not exist (non-fatal to test)
    633  1.1  christos 	# -i and -s (and -c) are posix options, but are not required to
    634  1.1  christos 	# be accessable via the "set" command, just the command line.
    635  1.1  christos 	# We allow for -i to work with set, as that makes some sense,
    636  1.1  christos 	# -c and -s do not.
    637  1.1  christos 	test_optional_on_off E i I p q V || true
    638  1.1  christos 
    639  1.1  christos 	# Also test (some) option combinations ...
    640  1.1  christos 	# only testing posix options here, because it is easier...
    641  1.1  christos 	test_option_on_off aeu vx Ca aCefux
    642  1.1  christos }
    643  1.1  christos 
    644  1.1  christos atf_init_test_cases() {
    645  1.1  christos 	# tests are run in order sort of names produces, so choose names wisely
    646  1.1  christos 
    647  1.1  christos 	# this one tests turning on/off all the mandatory. and extra flags
    648  1.1  christos 	atf_add_test_case Option_switching
    649  1.1  christos 	# and this tests the NetBSD "local -" functionality in functions.
    650  1.1  christos 	atf_add_test_case restore_local_opts
    651  1.1  christos 
    652  1.1  christos 	# no tests for	-m (no idea how to do that one)
    653  1.1  christos 	#		-I (no easy way to generate the EOF it ignores)
    654  1.1  christos 	#		-i (not sure how to test that one at the minute)
    655  1.2  christos 	#		-p (because we aren't going to run tests setuid)
    656  1.1  christos 	#		-V/-E (too much effort, and a real test would be huge)
    657  1.1  christos 	#		-c (because almost all the other tests test it anyway)
    658  1.1  christos 	#		-q (because, for now, I am lazy)
    659  1.1  christos 	#		-s (coming soon, hopefully)
    660  1.1  christos 	#		-o (really +o: again, hopefully soon)
    661  1.1  christos 	#		-o longname (again, just laziness, don't wait...)
    662  1.1  christos 	# 		-h/-b (because NetBSD doesn't implement them)
    663  1.1  christos 	atf_add_test_case set_a
    664  1.1  christos 	atf_add_test_case set_C
    665  1.1  christos 	atf_add_test_case set_e
    666  1.1  christos 	atf_add_test_case set_f
    667  1.1  christos 	atf_add_test_case set_n
    668  1.1  christos 	atf_add_test_case set_u
    669  1.1  christos 	atf_add_test_case set_v
    670  1.1  christos 	atf_add_test_case set_x
    671  1.1  christos 
    672  1.1  christos 	atf_add_test_case vi_emacs_VE_toggle
    673  1.1  christos 	atf_add_test_case xx_bogus
    674  1.1  christos }
    675