1*640235e2SEnji Cooper# $NetBSD: t_option.sh,v 1.3 2016/03/08 14:19:28 christos Exp $ 2*640235e2SEnji Cooper# 3*640235e2SEnji Cooper# Copyright (c) 2016 The NetBSD Foundation, Inc. 4*640235e2SEnji Cooper# All rights reserved. 5*640235e2SEnji Cooper# 6*640235e2SEnji Cooper# Redistribution and use in source and binary forms, with or without 7*640235e2SEnji Cooper# modification, are permitted provided that the following conditions 8*640235e2SEnji Cooper# are met: 9*640235e2SEnji Cooper# 1. Redistributions of source code must retain the above copyright 10*640235e2SEnji Cooper# notice, this list of conditions and the following disclaimer. 11*640235e2SEnji Cooper# 2. Redistributions in binary form must reproduce the above copyright 12*640235e2SEnji Cooper# notice, this list of conditions and the following disclaimer in the 13*640235e2SEnji Cooper# documentation and/or other materials provided with the distribution. 14*640235e2SEnji Cooper# 15*640235e2SEnji Cooper# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 16*640235e2SEnji Cooper# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 17*640235e2SEnji Cooper# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18*640235e2SEnji Cooper# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 19*640235e2SEnji Cooper# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20*640235e2SEnji Cooper# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21*640235e2SEnji Cooper# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22*640235e2SEnji Cooper# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23*640235e2SEnji Cooper# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24*640235e2SEnji Cooper# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25*640235e2SEnji Cooper# POSSIBILITY OF SUCH DAMAGE. 26*640235e2SEnji Cooper# 27*640235e2SEnji Cooper# the implementation of "sh" to test 28*640235e2SEnji Cooper: ${TEST_SH:="/bin/sh"} 29*640235e2SEnji Cooper 30*640235e2SEnji Cooper# The standard 31*640235e2SEnji Cooper# http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html 32*640235e2SEnji Cooper# says: 33*640235e2SEnji Cooper# ...[lots] 34*640235e2SEnji Cooper 35*640235e2SEnji Coopertest_option_on_off() 36*640235e2SEnji Cooper{ 37*640235e2SEnji Cooper atf_require_prog tr 38*640235e2SEnji Cooper 39*640235e2SEnji Cooper for opt 40*640235e2SEnji Cooper do 41*640235e2SEnji Cooper # t is needed, as inside $()` $- appears to lose 42*640235e2SEnji Cooper # the 'e' option if it happened to already be 43*640235e2SEnji Cooper # set. Must check if that is what should 44*640235e2SEnji Cooper # happen, but that is a different issue. 45*640235e2SEnji Cooper 46*640235e2SEnji Cooper test -z "${opt}" && continue 47*640235e2SEnji Cooper 48*640235e2SEnji Cooper # if we are playing with more that one option at a 49*640235e2SEnji Cooper # time, the code below requires that we start with no 50*640235e2SEnji Cooper # options set, or it will mis-diagnose the situation 51*640235e2SEnji Cooper CLEAR='' 52*640235e2SEnji Cooper test "${#opt}" -gt 1 && 53*640235e2SEnji Cooper CLEAR='xx="$-" && xx=$(echo "$xx" | tr -d cs) && test -n "$xx" && set +"$xx";' 54*640235e2SEnji Cooper 55*640235e2SEnji Cooper atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \ 56*640235e2SEnji Cooper "opt=${opt}"' 57*640235e2SEnji Cooper x() { 58*640235e2SEnji Cooper echo "ERROR: Unable to $1 option $2" >&2 59*640235e2SEnji Cooper exit 1 60*640235e2SEnji Cooper } 61*640235e2SEnji Cooper s() { 62*640235e2SEnji Cooper set -"$1" 63*640235e2SEnji Cooper t="$-" 64*640235e2SEnji Cooper x=$(echo "$t" | tr -d "$1") 65*640235e2SEnji Cooper test "$t" = "$x" && x set "$1" 66*640235e2SEnji Cooper return 0 67*640235e2SEnji Cooper } 68*640235e2SEnji Cooper c() { 69*640235e2SEnji Cooper set +"$1" 70*640235e2SEnji Cooper t="$-" 71*640235e2SEnji Cooper x=$(echo "$t" | tr -d "$1") 72*640235e2SEnji Cooper test "$t" != "$x" && x clear "$1" 73*640235e2SEnji Cooper return 0 74*640235e2SEnji Cooper } 75*640235e2SEnji Cooper '"${CLEAR}"' 76*640235e2SEnji Cooper 77*640235e2SEnji Cooper # if we do not do this, -x tracing splatters stderr 78*640235e2SEnji Cooper # for some shells, -v does as well (is that correct?) 79*640235e2SEnji Cooper case "${opt}" in 80*640235e2SEnji Cooper (*[xv]*) exec 2>/dev/null;; 81*640235e2SEnji Cooper esac 82*640235e2SEnji Cooper 83*640235e2SEnji Cooper o="$-" 84*640235e2SEnji Cooper x=$(echo "$o" | tr -d "$opt") 85*640235e2SEnji Cooper 86*640235e2SEnji Cooper if [ "$o" = "$x" ]; then # option was off 87*640235e2SEnji Cooper s "${opt}" 88*640235e2SEnji Cooper c "${opt}" 89*640235e2SEnji Cooper else 90*640235e2SEnji Cooper c "${opt}" 91*640235e2SEnji Cooper s "${opt}" 92*640235e2SEnji Cooper fi 93*640235e2SEnji Cooper ' 94*640235e2SEnji Cooper done 95*640235e2SEnji Cooper} 96*640235e2SEnji Cooper 97*640235e2SEnji Coopertest_optional_on_off() 98*640235e2SEnji Cooper{ 99*640235e2SEnji Cooper RET=0 100*640235e2SEnji Cooper OPTS= 101*640235e2SEnji Cooper for opt 102*640235e2SEnji Cooper do 103*640235e2SEnji Cooper test "${opt}" = n && continue 104*640235e2SEnji Cooper ${TEST_SH} -c "set -${opt}" 2>/dev/null && 105*640235e2SEnji Cooper OPTS="${OPTS} ${opt}" || RET=1 106*640235e2SEnji Cooper done 107*640235e2SEnji Cooper 108*640235e2SEnji Cooper test -n "${OPTS}" && test_option_on_off ${OPTS} 109*640235e2SEnji Cooper 110*640235e2SEnji Cooper return "${RET}" 111*640235e2SEnji Cooper} 112*640235e2SEnji Cooper 113*640235e2SEnji Cooperatf_test_case set_a 114*640235e2SEnji Cooperset_a_head() { 115*640235e2SEnji Cooper atf_set "descr" "Tests that 'set -a' turns on all var export " \ 116*640235e2SEnji Cooper "and that it behaves as defined by the standard" 117*640235e2SEnji Cooper} 118*640235e2SEnji Cooperset_a_body() { 119*640235e2SEnji Cooper atf_require_prog env 120*640235e2SEnji Cooper atf_require_prog grep 121*640235e2SEnji Cooper 122*640235e2SEnji Cooper test_option_on_off a 123*640235e2SEnji Cooper 124*640235e2SEnji Cooper # without -a, new variables should not be exported (so grep "fails") 125*640235e2SEnji Cooper atf_check -s exit:1 -o empty -e empty ${TEST_SH} -ce \ 126*640235e2SEnji Cooper 'unset VAR; set +a; VAR=value; env | grep "^VAR="' 127*640235e2SEnji Cooper 128*640235e2SEnji Cooper # with -a, they should be 129*640235e2SEnji Cooper atf_check -s exit:0 -o match:VAR=value -e empty ${TEST_SH} -ce \ 130*640235e2SEnji Cooper 'unset VAR; set -a; VAR=value; env | grep "^VAR="' 131*640235e2SEnji Cooper} 132*640235e2SEnji Cooper 133*640235e2SEnji Cooperatf_test_case set_C 134*640235e2SEnji Cooperset_C_head() { 135*640235e2SEnji Cooper atf_set "descr" "Tests that 'set -C' turns on no clobber mode " \ 136*640235e2SEnji Cooper "and that it behaves as defined by the standard" 137*640235e2SEnji Cooper} 138*640235e2SEnji Cooperset_C_body() { 139*640235e2SEnji Cooper atf_require_prog ls 140*640235e2SEnji Cooper 141*640235e2SEnji Cooper test_option_on_off C 142*640235e2SEnji Cooper 143*640235e2SEnji Cooper # Check that the environment to use for the tests is sane ... 144*640235e2SEnji Cooper # we assume current dir is a new tempory directory & is empty 145*640235e2SEnji Cooper 146*640235e2SEnji Cooper test -z "$(ls)" || atf_skip "Test execution directory not clean" 147*640235e2SEnji Cooper test -c "/dev/null" || atf_skip "Problem with /dev/null" 148*640235e2SEnji Cooper 149*640235e2SEnji Cooper echo Dummy_Content > Junk_File 150*640235e2SEnji Cooper echo Precious_Content > Important_File 151*640235e2SEnji Cooper 152*640235e2SEnji Cooper # Check that we can redirect onto file when -C is not set 153*640235e2SEnji Cooper atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \ 154*640235e2SEnji Cooper ' 155*640235e2SEnji Cooper D=$(ls -l Junk_File) || exit 1 156*640235e2SEnji Cooper set +C 157*640235e2SEnji Cooper echo "Overwrite it now" > Junk_File 158*640235e2SEnji Cooper A=$(ls -l Junk_File) || exit 1 159*640235e2SEnji Cooper test "${A}" != "${D}" 160*640235e2SEnji Cooper ' 161*640235e2SEnji Cooper 162*640235e2SEnji Cooper # Check that we cannot redirect onto file when -C is set 163*640235e2SEnji Cooper atf_check -s exit:0 -o empty -e not-empty ${TEST_SH} -c \ 164*640235e2SEnji Cooper ' 165*640235e2SEnji Cooper D=$(ls -l Important_File) || exit 1 166*640235e2SEnji Cooper set -C 167*640235e2SEnji Cooper echo "Fail to Overwrite it now" > Important_File 168*640235e2SEnji Cooper A=$(ls -l Important_File) || exit 1 169*640235e2SEnji Cooper test "${A}" = "${D}" 170*640235e2SEnji Cooper ' 171*640235e2SEnji Cooper 172*640235e2SEnji Cooper # Check that we can append to file, even when -C is set 173*640235e2SEnji Cooper atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \ 174*640235e2SEnji Cooper ' 175*640235e2SEnji Cooper D=$(ls -l Junk_File) || exit 1 176*640235e2SEnji Cooper set -C 177*640235e2SEnji Cooper echo "Append to it now" >> Junk_File 178*640235e2SEnji Cooper A=$(ls -l Junk_File) || exit 1 179*640235e2SEnji Cooper test "${A}" != "${D}" 180*640235e2SEnji Cooper ' 181*640235e2SEnji Cooper 182*640235e2SEnji Cooper # Check that we abort on attempt to redirect onto file when -Ce is set 183*640235e2SEnji Cooper atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \ 184*640235e2SEnji Cooper ' 185*640235e2SEnji Cooper set -Ce 186*640235e2SEnji Cooper echo "Fail to Overwrite it now" > Important_File 187*640235e2SEnji Cooper echo "Should not reach this point" 188*640235e2SEnji Cooper ' 189*640235e2SEnji Cooper 190*640235e2SEnji Cooper # Last check that we can override -C for when we really need to 191*640235e2SEnji Cooper atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \ 192*640235e2SEnji Cooper ' 193*640235e2SEnji Cooper D=$(ls -l Junk_File) || exit 1 194*640235e2SEnji Cooper set -C 195*640235e2SEnji Cooper echo "Change the poor bugger again" >| Junk_File 196*640235e2SEnji Cooper A=$(ls -l Junk_File) || exit 1 197*640235e2SEnji Cooper test "${A}" != "${D}" 198*640235e2SEnji Cooper ' 199*640235e2SEnji Cooper} 200*640235e2SEnji Cooper 201*640235e2SEnji Cooperatf_test_case set_e 202*640235e2SEnji Cooperset_e_head() { 203*640235e2SEnji Cooper atf_set "descr" "Tests that 'set -e' turns on error detection " \ 204*640235e2SEnji Cooper "and that a simple case behaves as defined by the standard" 205*640235e2SEnji Cooper} 206*640235e2SEnji Cooperset_e_body() { 207*640235e2SEnji Cooper test_option_on_off e 208*640235e2SEnji Cooper 209*640235e2SEnji Cooper # Check that -e does nothing if no commands fail 210*640235e2SEnji Cooper atf_check -s exit:0 -o match:I_am_OK -e empty \ 211*640235e2SEnji Cooper ${TEST_SH} -c \ 212*640235e2SEnji Cooper 'false; printf "%s" I_am; set -e; true; printf "%s\n" _OK' 213*640235e2SEnji Cooper 214*640235e2SEnji Cooper # and that it (silently, but with exit status) aborts if cmd fails 215*640235e2SEnji Cooper atf_check -s not-exit:0 -o match:I_am -o not-match:Broken -e empty \ 216*640235e2SEnji Cooper ${TEST_SH} -c \ 217*640235e2SEnji Cooper 'false; printf "%s" I_am; set -e; false; printf "%s\n" _Broken' 218*640235e2SEnji Cooper 219*640235e2SEnji Cooper # same, except -e this time is on from the beginning 220*640235e2SEnji Cooper atf_check -s not-exit:0 -o match:I_am -o not-match:Broken -e empty \ 221*640235e2SEnji Cooper ${TEST_SH} -ec 'printf "%s" I_am; false; printf "%s\n" _Broken' 222*640235e2SEnji Cooper 223*640235e2SEnji Cooper # More checking of -e in other places, there is lots to deal with. 224*640235e2SEnji Cooper} 225*640235e2SEnji Cooper 226*640235e2SEnji Cooperatf_test_case set_f 227*640235e2SEnji Cooperset_f_head() { 228*640235e2SEnji Cooper atf_set "descr" "Tests that 'set -f' turns off pathname expansion " \ 229*640235e2SEnji Cooper "and that it behaves as defined by the standard" 230*640235e2SEnji Cooper} 231*640235e2SEnji Cooperset_f_body() { 232*640235e2SEnji Cooper atf_require_prog ls 233*640235e2SEnji Cooper 234*640235e2SEnji Cooper test_option_on_off f 235*640235e2SEnji Cooper 236*640235e2SEnji Cooper # Check that the environment to use for the tests is sane ... 237*640235e2SEnji Cooper # we assume current dir is a new tempory directory & is empty 238*640235e2SEnji Cooper 239*640235e2SEnji Cooper test -z "$(ls)" || atf_skip "Test execution directory not clean" 240*640235e2SEnji Cooper 241*640235e2SEnji Cooper # we will assume that atf will clean up this junk directory 242*640235e2SEnji Cooper # when we are done. But for testing pathname expansion 243*640235e2SEnji Cooper # we need files 244*640235e2SEnji Cooper 245*640235e2SEnji Cooper for f in a b c d e f aa ab ac ad ae aaa aab aac aad aba abc bbb ccc 246*640235e2SEnji Cooper do 247*640235e2SEnji Cooper echo "$f" > "$f" 248*640235e2SEnji Cooper done 249*640235e2SEnji Cooper 250*640235e2SEnji Cooper atf_check -s exit:0 -o empty -e empty ${TEST_SH} -ec \ 251*640235e2SEnji Cooper 'X=$(echo b*); Y=$(echo b*); test "${X}" != "a*"; 252*640235e2SEnji Cooper test "${X}" = "${Y}"' 253*640235e2SEnji Cooper 254*640235e2SEnji Cooper # now test expansion is different when -f is set 255*640235e2SEnji Cooper atf_check -s exit:0 -o empty -e empty ${TEST_SH} -ec \ 256*640235e2SEnji Cooper 'X=$(echo b*); Y=$(set -f; echo b*); test "${X}" != "${Y}"' 257*640235e2SEnji Cooper} 258*640235e2SEnji Cooper 259*640235e2SEnji Cooperatf_test_case set_n 260*640235e2SEnji Cooperset_n_head() { 261*640235e2SEnji Cooper atf_set "descr" "Tests that 'set -n' supresses command execution " \ 262*640235e2SEnji Cooper "and that it behaves as defined by the standard" 263*640235e2SEnji Cooper} 264*640235e2SEnji Cooperset_n_body() { 265*640235e2SEnji Cooper # pointless to test this, if it turns on, it stays on... 266*640235e2SEnji Cooper # test_option_on_off n 267*640235e2SEnji Cooper # so just allow the tests below to verify it can be turned on 268*640235e2SEnji Cooper 269*640235e2SEnji Cooper # nothing should be executed, hence no output... 270*640235e2SEnji Cooper atf_check -s exit:0 -o empty -e empty \ 271*640235e2SEnji Cooper ${TEST_SH} -enc 'echo ABANDON HOPE; echo ALL YE; echo ...' 272*640235e2SEnji Cooper 273*640235e2SEnji Cooper # this is true even when the "commands" do not exist 274*640235e2SEnji Cooper atf_check -s exit:0 -o empty -e empty \ 275*640235e2SEnji Cooper ${TEST_SH} -enc 'ERR; FAIL; ABANDON HOPE' 276*640235e2SEnji Cooper 277*640235e2SEnji Cooper # but if there is a syntax error, it should be detected (w or w/o -e) 278*640235e2SEnji Cooper atf_check -s not-exit:0 -o empty -e not-empty \ 279*640235e2SEnji Cooper ${TEST_SH} -enc 'echo JUMP; for frogs swim; echo in puddles' 280*640235e2SEnji Cooper atf_check -s not-exit:0 -o empty -e not-empty \ 281*640235e2SEnji Cooper ${TEST_SH} -nc 'echo ABANDON HOPE; echo "ALL YE; echo ...' 282*640235e2SEnji Cooper atf_check -s not-exit:0 -o empty -e not-empty \ 283*640235e2SEnji Cooper ${TEST_SH} -enc 'echo ABANDON HOPE;; echo ALL YE; echo ...' 284*640235e2SEnji Cooper atf_check -s not-exit:0 -o empty -e not-empty \ 285*640235e2SEnji Cooper ${TEST_SH} -nc 'do YOU ABANDON HOPE; for all eternity?' 286*640235e2SEnji Cooper 287*640235e2SEnji Cooper # now test enabling -n in the middle of a script 288*640235e2SEnji Cooper # note that once turned on, it cannot be turned off again. 289*640235e2SEnji Cooper # 290*640235e2SEnji Cooper # omit more complex cases, as those can send some shells 291*640235e2SEnji Cooper # into infinite loops, and believe it or not, that might be OK! 292*640235e2SEnji Cooper 293*640235e2SEnji Cooper atf_check -s exit:0 -o match:first -o not-match:second -e empty \ 294*640235e2SEnji Cooper ${TEST_SH} -c 'echo first; set -n; echo second' 295*640235e2SEnji Cooper atf_check -s exit:0 -o match:first -o not-match:third -e empty \ 296*640235e2SEnji Cooper ${TEST_SH} -c 'echo first; set -n; echo second; set +n; echo third' 297*640235e2SEnji Cooper atf_check -s exit:0 -o inline:'a\nb\n' -e empty \ 298*640235e2SEnji Cooper ${TEST_SH} -c 'for x in a b c d 299*640235e2SEnji Cooper do 300*640235e2SEnji Cooper case "$x" in 301*640235e2SEnji Cooper a);; b);; c) set -n;; d);; 302*640235e2SEnji Cooper esac 303*640235e2SEnji Cooper printf "%s\n" "$x" 304*640235e2SEnji Cooper done' 305*640235e2SEnji Cooper 306*640235e2SEnji Cooper # This last one is a bit more complex to explain, so I will not try 307*640235e2SEnji Cooper 308*640235e2SEnji Cooper # First, we need to know what signal number is used for SIGUSR1 on 309*640235e2SEnji Cooper # the local (testing) system (signal number is $(( $XIT - 128 )) ) 310*640235e2SEnji Cooper 311*640235e2SEnji Cooper # this will take slightly over 1 second elapsed time (the sleep 1) 312*640235e2SEnji Cooper # The "10" for the first sleep just needs to be something big enough 313*640235e2SEnji Cooper # that the rest of the commands have time to complete, even on 314*640235e2SEnji Cooper # very slow testing systems. 10 should be enough. Otherwise irrelevant 315*640235e2SEnji Cooper 316*640235e2SEnji Cooper # The shell will usually blather to stderr about the sleep 10 being 317*640235e2SEnji Cooper # killed, but it affects nothing, so just allow it to cry. 318*640235e2SEnji Cooper 319*640235e2SEnji Cooper (sleep 10 & sleep 1; kill -USR1 $!; wait $!) 320*640235e2SEnji Cooper XIT="$?" 321*640235e2SEnji Cooper 322*640235e2SEnji Cooper # The exit value should be an integer > 128 and < 256 (often 158) 323*640235e2SEnji Cooper # If it is not just skip the test 324*640235e2SEnji Cooper 325*640235e2SEnji Cooper # If we do run the test, it should take (slightly over) either 1 or 2 326*640235e2SEnji Cooper # seconds to complete, depending upon the shell being tested. 327*640235e2SEnji Cooper 328*640235e2SEnji Cooper case "${XIT}" in 329*640235e2SEnji Cooper ( 129 | 1[3-9][0-9] | 2[0-4][0-9] | 25[0-5] ) 330*640235e2SEnji Cooper 331*640235e2SEnji Cooper # The script below should exit with the same code - no output 332*640235e2SEnji Cooper 333*640235e2SEnji Cooper # Or that is the result that seems best explanable. 334*640235e2SEnji Cooper # "set -n" in uses like this is not exactly well defined... 335*640235e2SEnji Cooper 336*640235e2SEnji Cooper # This script comes from a member of the austin group 337*640235e2SEnji Cooper # (they author changes to the posix shell spec - and more.) 338*640235e2SEnji Cooper # The author is also an (occasional?) NetBSD user. 339*640235e2SEnji Cooper atf_check -s exit:${XIT} -o empty -e empty ${TEST_SH} -c ' 340*640235e2SEnji Cooper trap "set -n" USR1 341*640235e2SEnji Cooper { sleep 1; kill -USR1 $$; sleep 1; } & 342*640235e2SEnji Cooper false 343*640235e2SEnji Cooper wait && echo t || echo f 344*640235e2SEnji Cooper wait 345*640235e2SEnji Cooper echo foo 346*640235e2SEnji Cooper ' 347*640235e2SEnji Cooper ;; 348*640235e2SEnji Cooper esac 349*640235e2SEnji Cooper} 350*640235e2SEnji Cooper 351*640235e2SEnji Cooperatf_test_case set_u 352*640235e2SEnji Cooperset_u_head() { 353*640235e2SEnji Cooper atf_set "descr" "Tests that 'set -u' turns on unset var detection " \ 354*640235e2SEnji Cooper "and that it behaves as defined by the standard" 355*640235e2SEnji Cooper} 356*640235e2SEnji Cooperset_u_body() { 357*640235e2SEnji Cooper test_option_on_off u 358*640235e2SEnji Cooper 359*640235e2SEnji Cooper # first make sure it is OK to unset an unset variable 360*640235e2SEnji Cooper atf_check -s exit:0 -o match:OK -e empty ${TEST_SH} -ce \ 361*640235e2SEnji Cooper 'unset _UNSET_VARIABLE_; echo OK' 362*640235e2SEnji Cooper # even if -u is set 363*640235e2SEnji Cooper atf_check -s exit:0 -o match:OK -e empty ${TEST_SH} -cue \ 364*640235e2SEnji Cooper 'unset _UNSET_VARIABLE_; echo OK' 365*640235e2SEnji Cooper 366*640235e2SEnji Cooper # and that without -u accessing an unset variable is harmless 367*640235e2SEnji Cooper atf_check -s exit:0 -o match:OK -e empty ${TEST_SH} -ce \ 368*640235e2SEnji Cooper 'unset X; echo ${X}; echo OK' 369*640235e2SEnji Cooper # and that the unset variable test expansion works properly 370*640235e2SEnji Cooper atf_check -s exit:0 -o match:OKOK -e empty ${TEST_SH} -ce \ 371*640235e2SEnji Cooper 'unset X; printf "%s" ${X-OK}; echo OK' 372*640235e2SEnji Cooper 373*640235e2SEnji Cooper # Next test that with -u set, the shell aborts on access to unset var 374*640235e2SEnji Cooper # do not use -e, want to make sure it is -u that causes abort 375*640235e2SEnji Cooper atf_check -s not-exit:0 -o not-match:ERR -e not-empty ${TEST_SH} -c \ 376*640235e2SEnji Cooper 'unset X; set -u; echo ${X}; echo ERR' 377*640235e2SEnji Cooper # quoting should make no difference... 378*640235e2SEnji Cooper atf_check -s not-exit:0 -o not-match:ERR -e not-empty ${TEST_SH} -c \ 379*640235e2SEnji Cooper 'unset X; set -u; echo "${X}"; echo ERR' 380*640235e2SEnji Cooper 381*640235e2SEnji Cooper # Now a bunch of accesses to unset vars, with -u, in ways that are OK 382*640235e2SEnji Cooper atf_check -s exit:0 -o match:OK -e empty ${TEST_SH} -ce \ 383*640235e2SEnji Cooper 'unset X; set -u; echo ${X-GOOD}; echo OK' 384*640235e2SEnji Cooper atf_check -s exit:0 -o match:OK -e empty ${TEST_SH} -ce \ 385*640235e2SEnji Cooper 'unset X; set -u; echo ${X-OK}' 386*640235e2SEnji Cooper atf_check -s exit:0 -o not-match:ERR -o match:OK -e empty \ 387*640235e2SEnji Cooper ${TEST_SH} -ce 'unset X; set -u; echo ${X+ERR}; echo OK' 388*640235e2SEnji Cooper 389*640235e2SEnji Cooper # and some more ways that are not OK 390*640235e2SEnji Cooper atf_check -s not-exit:0 -o not-match:ERR -e not-empty ${TEST_SH} -c \ 391*640235e2SEnji Cooper 'unset X; set -u; echo ${X#foo}; echo ERR' 392*640235e2SEnji Cooper atf_check -s not-exit:0 -o not-match:ERR -e not-empty ${TEST_SH} -c \ 393*640235e2SEnji Cooper 'unset X; set -u; echo ${X%%bar}; echo ERR' 394*640235e2SEnji Cooper 395*640235e2SEnji Cooper # lastly, just while we are checking unset vars, test aborts w/o -u 396*640235e2SEnji Cooper atf_check -s not-exit:0 -o not-match:ERR -e not-empty ${TEST_SH} -c \ 397*640235e2SEnji Cooper 'unset X; echo ${X?}; echo ERR' 398*640235e2SEnji Cooper atf_check -s not-exit:0 -o not-match:ERR -e match:X_NOT_SET \ 399*640235e2SEnji Cooper ${TEST_SH} -c 'unset X; echo ${X?X_NOT_SET}; echo ERR' 400*640235e2SEnji Cooper} 401*640235e2SEnji Cooper 402*640235e2SEnji Cooperatf_test_case set_v 403*640235e2SEnji Cooperset_v_head() { 404*640235e2SEnji Cooper atf_set "descr" "Tests that 'set -v' turns on input read echoing " \ 405*640235e2SEnji Cooper "and that it behaves as defined by the standard" 406*640235e2SEnji Cooper} 407*640235e2SEnji Cooperset_v_body() { 408*640235e2SEnji Cooper test_option_on_off v 409*640235e2SEnji Cooper 410*640235e2SEnji Cooper # check that -v does nothing if no later input line is read 411*640235e2SEnji Cooper atf_check -s exit:0 \ 412*640235e2SEnji Cooper -o match:OKOK -o not-match:echo -o not-match:printf \ 413*640235e2SEnji Cooper -e empty \ 414*640235e2SEnji Cooper ${TEST_SH} -ec 'printf "%s" OK; set -v; echo OK; exit 0' 415*640235e2SEnji Cooper 416*640235e2SEnji Cooper # but that it does when there are multiple lines 417*640235e2SEnji Cooper cat <<- 'EOF' | 418*640235e2SEnji Cooper set -v 419*640235e2SEnji Cooper printf %s OK 420*640235e2SEnji Cooper echo OK 421*640235e2SEnji Cooper exit 0 422*640235e2SEnji Cooper EOF 423*640235e2SEnji Cooper atf_check -s exit:0 \ 424*640235e2SEnji Cooper -o match:OKOK -o not-match:echo -o not-match:printf \ 425*640235e2SEnji Cooper -e match:printf -e match:OK -e match:echo \ 426*640235e2SEnji Cooper -e not-match:set ${TEST_SH} 427*640235e2SEnji Cooper 428*640235e2SEnji Cooper # and that it can be disabled again 429*640235e2SEnji Cooper cat <<- 'EOF' | 430*640235e2SEnji Cooper set -v 431*640235e2SEnji Cooper printf %s OK 432*640235e2SEnji Cooper set +v 433*640235e2SEnji Cooper echo OK 434*640235e2SEnji Cooper exit 0 435*640235e2SEnji Cooper EOF 436*640235e2SEnji Cooper atf_check -s exit:0 \ 437*640235e2SEnji Cooper -o match:OKOK -o not-match:echo -o not-match:printf \ 438*640235e2SEnji Cooper -e match:printf -e match:OK -e not-match:echo \ 439*640235e2SEnji Cooper ${TEST_SH} 440*640235e2SEnji Cooper 441*640235e2SEnji Cooper # and lastly, that shell keywords do get output when "read" 442*640235e2SEnji Cooper cat <<- 'EOF' | 443*640235e2SEnji Cooper set -v 444*640235e2SEnji Cooper for i in 111 222 333 445*640235e2SEnji Cooper do 446*640235e2SEnji Cooper printf %s $i 447*640235e2SEnji Cooper done 448*640235e2SEnji Cooper exit 0 449*640235e2SEnji Cooper EOF 450*640235e2SEnji Cooper atf_check -s exit:0 \ 451*640235e2SEnji Cooper -o match:111222333 -o not-match:printf \ 452*640235e2SEnji Cooper -o not-match:for -o not-match:do -o not-match:done \ 453*640235e2SEnji Cooper -e match:printf -e match:111 -e not-match:111222 \ 454*640235e2SEnji Cooper -e match:for -e match:do -e match:done \ 455*640235e2SEnji Cooper ${TEST_SH} 456*640235e2SEnji Cooper} 457*640235e2SEnji Cooper 458*640235e2SEnji Cooperatf_test_case set_x 459*640235e2SEnji Cooperset_x_head() { 460*640235e2SEnji Cooper atf_set "descr" "Tests that 'set -x' turns on command exec logging " \ 461*640235e2SEnji Cooper "and that it behaves as defined by the standard" 462*640235e2SEnji Cooper} 463*640235e2SEnji Cooperset_x_body() { 464*640235e2SEnji Cooper test_option_on_off x 465*640235e2SEnji Cooper 466*640235e2SEnji Cooper # check that cmd output appears after -x is enabled 467*640235e2SEnji Cooper atf_check -s exit:0 \ 468*640235e2SEnji Cooper -o match:OKOK -o not-match:echo -o not-match:printf \ 469*640235e2SEnji Cooper -e not-match:printf -e match:OK -e match:echo \ 470*640235e2SEnji Cooper ${TEST_SH} -ec 'printf "%s" OK; set -x; echo OK; exit 0' 471*640235e2SEnji Cooper 472*640235e2SEnji Cooper # and that it stops again afer -x is disabled 473*640235e2SEnji Cooper atf_check -s exit:0 \ 474*640235e2SEnji Cooper -o match:OKOK -o not-match:echo -o not-match:printf \ 475*640235e2SEnji Cooper -e match:printf -e match:OK -e not-match:echo \ 476*640235e2SEnji Cooper ${TEST_SH} -ec 'set -x; printf "%s" OK; set +x; echo OK; exit 0' 477*640235e2SEnji Cooper 478*640235e2SEnji Cooper # also check that PS4 is output correctly 479*640235e2SEnji Cooper atf_check -s exit:0 \ 480*640235e2SEnji Cooper -o match:OK -o not-match:echo \ 481*640235e2SEnji Cooper -e match:OK -e match:Run:echo \ 482*640235e2SEnji Cooper ${TEST_SH} -ec 'PS4=Run:; set -x; echo OK; exit 0' 483*640235e2SEnji Cooper 484*640235e2SEnji Cooper return 0 485*640235e2SEnji Cooper 486*640235e2SEnji Cooper # This one seems controversial... I suspect it is NetBSD's sh 487*640235e2SEnji Cooper # that is wrong to not output "for" "while" "if" ... etc 488*640235e2SEnji Cooper 489*640235e2SEnji Cooper # and lastly, that shell keywords do not get output when "executed" 490*640235e2SEnji Cooper atf_check -s exit:0 \ 491*640235e2SEnji Cooper -o match:111222333 -o not-match:printf \ 492*640235e2SEnji Cooper -o not-match:for \ 493*640235e2SEnji Cooper -e match:printf -e match:111 -e not-match:111222 \ 494*640235e2SEnji Cooper -e not-match:for -e not-match:do -e not-match:done \ 495*640235e2SEnji Cooper ${TEST_SH} -ec \ 496*640235e2SEnji Cooper 'set -x; for i in 111 222 333; do printf "%s" $i; done; echo; exit 0' 497*640235e2SEnji Cooper} 498*640235e2SEnji Cooper 499*640235e2SEnji Cooperopt_test_setup() 500*640235e2SEnji Cooper{ 501*640235e2SEnji Cooper test -n "$1" || { echo >&2 "Internal error"; exit 1; } 502*640235e2SEnji Cooper 503*640235e2SEnji Cooper cat > "$1" << 'END_OF_FUNCTIONS' 504*640235e2SEnji Cooperlocal_opt_check() 505*640235e2SEnji Cooper{ 506*640235e2SEnji Cooper local - 507*640235e2SEnji Cooper} 508*640235e2SEnji Cooper 509*640235e2SEnji Cooperinstr() 510*640235e2SEnji Cooper{ 511*640235e2SEnji Cooper expr "$2" : "\(.*$1\)" >/dev/null 512*640235e2SEnji Cooper} 513*640235e2SEnji Cooper 514*640235e2SEnji Coopersave_opts() 515*640235e2SEnji Cooper{ 516*640235e2SEnji Cooper local - 517*640235e2SEnji Cooper 518*640235e2SEnji Cooper set -e 519*640235e2SEnji Cooper set -u 520*640235e2SEnji Cooper 521*640235e2SEnji Cooper instr e "$-" && instr u "$-" && return 0 522*640235e2SEnji Cooper echo ERR 523*640235e2SEnji Cooper} 524*640235e2SEnji Cooper 525*640235e2SEnji Cooperfiddle_opts() 526*640235e2SEnji Cooper{ 527*640235e2SEnji Cooper set -e 528*640235e2SEnji Cooper set -u 529*640235e2SEnji Cooper 530*640235e2SEnji Cooper instr e "$-" && instr u "$-" && return 0 531*640235e2SEnji Cooper echo ERR 532*640235e2SEnji Cooper} 533*640235e2SEnji Cooper 534*640235e2SEnji Cooperlocal_test() 535*640235e2SEnji Cooper{ 536*640235e2SEnji Cooper set +eu 537*640235e2SEnji Cooper 538*640235e2SEnji Cooper save_opts 539*640235e2SEnji Cooper instr '[eu]' "$-" || printf %s "OK" 540*640235e2SEnji Cooper 541*640235e2SEnji Cooper fiddle_opts 542*640235e2SEnji Cooper instr e "$-" && instr u "$-" && printf %s "OK" 543*640235e2SEnji Cooper 544*640235e2SEnji Cooper set +eu 545*640235e2SEnji Cooper} 546*640235e2SEnji CooperEND_OF_FUNCTIONS 547*640235e2SEnji Cooper} 548*640235e2SEnji Cooper 549*640235e2SEnji Cooperatf_test_case restore_local_opts 550*640235e2SEnji Cooperrestore_local_opts_head() { 551*640235e2SEnji Cooper atf_set "descr" "Tests that 'local -' saves and restores options. " \ 552*640235e2SEnji Cooper "Note that "local" is a local shell addition" 553*640235e2SEnji Cooper} 554*640235e2SEnji Cooperrestore_local_opts_body() { 555*640235e2SEnji Cooper atf_require_prog cat 556*640235e2SEnji Cooper atf_require_prog expr 557*640235e2SEnji Cooper 558*640235e2SEnji Cooper FN="test-funcs.$$" 559*640235e2SEnji Cooper opt_test_setup "${FN}" || atf_skip "Cannot setup test environment" 560*640235e2SEnji Cooper 561*640235e2SEnji Cooper ${TEST_SH} -ec ". './${FN}'; local_opt_check" 2>/dev/null || 562*640235e2SEnji Cooper atf_skip "sh extension 'local -' not supported by ${TEST_SH}" 563*640235e2SEnji Cooper 564*640235e2SEnji Cooper atf_check -s exit:0 -o match:OKOK -o not-match:ERR -e empty \ 565*640235e2SEnji Cooper ${TEST_SH} -ec ". './${FN}'; local_test" 566*640235e2SEnji Cooper} 567*640235e2SEnji Cooper 568*640235e2SEnji Cooperatf_test_case vi_emacs_VE_toggle 569*640235e2SEnji Coopervi_emacs_VE_toggle_head() { 570*640235e2SEnji Cooper atf_set "descr" "Tests enabling vi disables emacs (and v.v - but why?)"\ 571*640235e2SEnji Cooper " Note that -V and -E are local shell additions" 572*640235e2SEnji Cooper} 573*640235e2SEnji Coopervi_emacs_VE_toggle_body() { 574*640235e2SEnji Cooper 575*640235e2SEnji Cooper test_optional_on_off V E || 576*640235e2SEnji Cooper atf_skip "One or both V & E opts unsupported by ${TEST_SH}" 577*640235e2SEnji Cooper 578*640235e2SEnji Cooper atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c ' 579*640235e2SEnji Cooper q() { 580*640235e2SEnji Cooper eval "case \"$-\" in 581*640235e2SEnji Cooper (*${2}*) return 1;; 582*640235e2SEnji Cooper (*${1}*) return 0;; 583*640235e2SEnji Cooper esac" 584*640235e2SEnji Cooper return 1 585*640235e2SEnji Cooper } 586*640235e2SEnji Cooper x() { 587*640235e2SEnji Cooper echo >&2 "Option set or toggle failure:" \ 588*640235e2SEnji Cooper " on=$1 off=$2 set=$-" 589*640235e2SEnji Cooper exit 1 590*640235e2SEnji Cooper } 591*640235e2SEnji Cooper set -V; q V E || x V E 592*640235e2SEnji Cooper set -E; q E V || x E V 593*640235e2SEnji Cooper set -V; q V E || x V E 594*640235e2SEnji Cooper set +EV; q "" "[VE]" || x "" VE 595*640235e2SEnji Cooper exit 0 596*640235e2SEnji Cooper ' 597*640235e2SEnji Cooper} 598*640235e2SEnji Cooper 599*640235e2SEnji Cooperatf_test_case xx_bogus 600*640235e2SEnji Cooperxx_bogus_head() { 601*640235e2SEnji Cooper atf_set "descr" "Tests that attempting to set a nonsense option fails." 602*640235e2SEnji Cooper} 603*640235e2SEnji Cooperxx_bogus_body() { 604*640235e2SEnji Cooper # Biggest problem here is picking a "nonsense option" that is 605*640235e2SEnji Cooper # not implemented by any shell, anywhere. Hopefully this will do. 606*640235e2SEnji Cooper 607*640235e2SEnji Cooper # 'set' is a special builtin, so a conforming shell should exit 608*640235e2SEnji Cooper # on an arg error, and the ERR should not be printed. 609*640235e2SEnji Cooper atf_check -s not-exit:0 -o empty -e not-empty \ 610*640235e2SEnji Cooper ${TEST_SH} -c 'set -% ; echo ERR' 611*640235e2SEnji Cooper} 612*640235e2SEnji Cooper 613*640235e2SEnji Cooperatf_test_case Option_switching 614*640235e2SEnji CooperOption_switching_head() { 615*640235e2SEnji Cooper atf_set "descr" "options can be enabled and disabled" 616*640235e2SEnji Cooper} 617*640235e2SEnji CooperOption_switching_body() { 618*640235e2SEnji Cooper 619*640235e2SEnji Cooper # Cannot test -m, setting it causes test shell to fail... 620*640235e2SEnji Cooper # (test shell gets SIGKILL!) Wonder why ... something related to atf 621*640235e2SEnji Cooper # That is, it works if just run as "sh -c 'echo $-; set -m; echo $-'" 622*640235e2SEnji Cooper 623*640235e2SEnji Cooper # Don't bother testing toggling -n, once on, it stays on... 624*640235e2SEnji Cooper # (and because the test fn refuses to allow us to try) 625*640235e2SEnji Cooper 626*640235e2SEnji Cooper # Cannot test -o or -c here, or the extension -s 627*640235e2SEnji Cooper # they can only be used, not switched 628*640235e2SEnji Cooper 629*640235e2SEnji Cooper # these are the posix options, that all shells should implement 630*640235e2SEnji Cooper test_option_on_off a b C e f h u v x # m 631*640235e2SEnji Cooper 632*640235e2SEnji Cooper # and these are extensions that might not exist (non-fatal to test) 633*640235e2SEnji Cooper # -i and -s (and -c) are posix options, but are not required to 634*640235e2SEnji Cooper # be accessable via the "set" command, just the command line. 635*640235e2SEnji Cooper # We allow for -i to work with set, as that makes some sense, 636*640235e2SEnji Cooper # -c and -s do not. 637*640235e2SEnji Cooper test_optional_on_off E i I p q V || true 638*640235e2SEnji Cooper 639*640235e2SEnji Cooper # Also test (some) option combinations ... 640*640235e2SEnji Cooper # only testing posix options here, because it is easier... 641*640235e2SEnji Cooper test_option_on_off aeu vx Ca aCefux 642*640235e2SEnji Cooper} 643*640235e2SEnji Cooper 644*640235e2SEnji Cooperatf_init_test_cases() { 645*640235e2SEnji Cooper # tests are run in order sort of names produces, so choose names wisely 646*640235e2SEnji Cooper 647*640235e2SEnji Cooper # this one tests turning on/off all the mandatory. and extra flags 648*640235e2SEnji Cooper atf_add_test_case Option_switching 649*640235e2SEnji Cooper # and this tests the NetBSD "local -" functionality in functions. 650*640235e2SEnji Cooper atf_add_test_case restore_local_opts 651*640235e2SEnji Cooper 652*640235e2SEnji Cooper # no tests for -m (no idea how to do that one) 653*640235e2SEnji Cooper # -I (no easy way to generate the EOF it ignores) 654*640235e2SEnji Cooper # -i (not sure how to test that one at the minute) 655*640235e2SEnji Cooper # -p (because we aren't going to run tests setuid) 656*640235e2SEnji Cooper # -V/-E (too much effort, and a real test would be huge) 657*640235e2SEnji Cooper # -c (because almost all the other tests test it anyway) 658*640235e2SEnji Cooper # -q (because, for now, I am lazy) 659*640235e2SEnji Cooper # -s (coming soon, hopefully) 660*640235e2SEnji Cooper # -o (really +o: again, hopefully soon) 661*640235e2SEnji Cooper # -o longname (again, just laziness, don't wait...) 662*640235e2SEnji Cooper # -h/-b (because NetBSD doesn't implement them) 663*640235e2SEnji Cooper atf_add_test_case set_a 664*640235e2SEnji Cooper atf_add_test_case set_C 665*640235e2SEnji Cooper atf_add_test_case set_e 666*640235e2SEnji Cooper atf_add_test_case set_f 667*640235e2SEnji Cooper atf_add_test_case set_n 668*640235e2SEnji Cooper atf_add_test_case set_u 669*640235e2SEnji Cooper atf_add_test_case set_v 670*640235e2SEnji Cooper atf_add_test_case set_x 671*640235e2SEnji Cooper 672*640235e2SEnji Cooper atf_add_test_case vi_emacs_VE_toggle 673*640235e2SEnji Cooper atf_add_test_case xx_bogus 674*640235e2SEnji Cooper} 675