1303980Sngie# $NetBSD: t_option.sh,v 1.3 2016/03/08 14:19:28 christos Exp $ 2303980Sngie# 3303980Sngie# Copyright (c) 2016 The NetBSD Foundation, Inc. 4303980Sngie# All rights reserved. 5303980Sngie# 6303980Sngie# Redistribution and use in source and binary forms, with or without 7303980Sngie# modification, are permitted provided that the following conditions 8303980Sngie# are met: 9303980Sngie# 1. Redistributions of source code must retain the above copyright 10303980Sngie# notice, this list of conditions and the following disclaimer. 11303980Sngie# 2. Redistributions in binary form must reproduce the above copyright 12303980Sngie# notice, this list of conditions and the following disclaimer in the 13303980Sngie# documentation and/or other materials provided with the distribution. 14303980Sngie# 15303980Sngie# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 16303980Sngie# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 17303980Sngie# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18303980Sngie# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 19303980Sngie# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20303980Sngie# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21303980Sngie# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22303980Sngie# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23303980Sngie# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24303980Sngie# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25303980Sngie# POSSIBILITY OF SUCH DAMAGE. 26303980Sngie# 27303980Sngie# the implementation of "sh" to test 28303980Sngie: ${TEST_SH:="/bin/sh"} 29303980Sngie 30303980Sngie# The standard 31303980Sngie# http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html 32303980Sngie# says: 33303980Sngie# ...[lots] 34303980Sngie 35303980Sngietest_option_on_off() 36303980Sngie{ 37303980Sngie atf_require_prog tr 38303980Sngie 39303980Sngie for opt 40303980Sngie do 41303980Sngie # t is needed, as inside $()` $- appears to lose 42303980Sngie # the 'e' option if it happened to already be 43303980Sngie # set. Must check if that is what should 44303980Sngie # happen, but that is a different issue. 45303980Sngie 46303980Sngie test -z "${opt}" && continue 47303980Sngie 48303980Sngie # if we are playing with more that one option at a 49303980Sngie # time, the code below requires that we start with no 50303980Sngie # options set, or it will mis-diagnose the situation 51303980Sngie CLEAR='' 52303980Sngie test "${#opt}" -gt 1 && 53303980Sngie CLEAR='xx="$-" && xx=$(echo "$xx" | tr -d cs) && test -n "$xx" && set +"$xx";' 54303980Sngie 55303980Sngie atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \ 56303980Sngie "opt=${opt}"' 57303980Sngie x() { 58303980Sngie echo "ERROR: Unable to $1 option $2" >&2 59303980Sngie exit 1 60303980Sngie } 61303980Sngie s() { 62303980Sngie set -"$1" 63303980Sngie t="$-" 64303980Sngie x=$(echo "$t" | tr -d "$1") 65303980Sngie test "$t" = "$x" && x set "$1" 66303980Sngie return 0 67303980Sngie } 68303980Sngie c() { 69303980Sngie set +"$1" 70303980Sngie t="$-" 71303980Sngie x=$(echo "$t" | tr -d "$1") 72303980Sngie test "$t" != "$x" && x clear "$1" 73303980Sngie return 0 74303980Sngie } 75303980Sngie '"${CLEAR}"' 76303980Sngie 77303980Sngie # if we do not do this, -x tracing splatters stderr 78303980Sngie # for some shells, -v does as well (is that correct?) 79303980Sngie case "${opt}" in 80303980Sngie (*[xv]*) exec 2>/dev/null;; 81303980Sngie esac 82303980Sngie 83303980Sngie o="$-" 84303980Sngie x=$(echo "$o" | tr -d "$opt") 85303980Sngie 86303980Sngie if [ "$o" = "$x" ]; then # option was off 87303980Sngie s "${opt}" 88303980Sngie c "${opt}" 89303980Sngie else 90303980Sngie c "${opt}" 91303980Sngie s "${opt}" 92303980Sngie fi 93303980Sngie ' 94303980Sngie done 95303980Sngie} 96303980Sngie 97303980Sngietest_optional_on_off() 98303980Sngie{ 99303980Sngie RET=0 100303980Sngie OPTS= 101303980Sngie for opt 102303980Sngie do 103303980Sngie test "${opt}" = n && continue 104303980Sngie ${TEST_SH} -c "set -${opt}" 2>/dev/null && 105303980Sngie OPTS="${OPTS} ${opt}" || RET=1 106303980Sngie done 107303980Sngie 108303980Sngie test -n "${OPTS}" && test_option_on_off ${OPTS} 109303980Sngie 110303980Sngie return "${RET}" 111303980Sngie} 112303980Sngie 113303980Sngieatf_test_case set_a 114303980Sngieset_a_head() { 115303980Sngie atf_set "descr" "Tests that 'set -a' turns on all var export " \ 116303980Sngie "and that it behaves as defined by the standard" 117303980Sngie} 118303980Sngieset_a_body() { 119303980Sngie atf_require_prog env 120303980Sngie atf_require_prog grep 121303980Sngie 122303980Sngie test_option_on_off a 123303980Sngie 124303980Sngie # without -a, new variables should not be exported (so grep "fails") 125303980Sngie atf_check -s exit:1 -o empty -e empty ${TEST_SH} -ce \ 126303980Sngie 'unset VAR; set +a; VAR=value; env | grep "^VAR="' 127303980Sngie 128303980Sngie # with -a, they should be 129303980Sngie atf_check -s exit:0 -o match:VAR=value -e empty ${TEST_SH} -ce \ 130303980Sngie 'unset VAR; set -a; VAR=value; env | grep "^VAR="' 131303980Sngie} 132303980Sngie 133303980Sngieatf_test_case set_C 134303980Sngieset_C_head() { 135303980Sngie atf_set "descr" "Tests that 'set -C' turns on no clobber mode " \ 136303980Sngie "and that it behaves as defined by the standard" 137303980Sngie} 138303980Sngieset_C_body() { 139303980Sngie atf_require_prog ls 140303980Sngie 141303980Sngie test_option_on_off C 142303980Sngie 143303980Sngie # Check that the environment to use for the tests is sane ... 144303980Sngie # we assume current dir is a new tempory directory & is empty 145303980Sngie 146303980Sngie test -z "$(ls)" || atf_skip "Test execution directory not clean" 147303980Sngie test -c "/dev/null" || atf_skip "Problem with /dev/null" 148303980Sngie 149303980Sngie echo Dummy_Content > Junk_File 150303980Sngie echo Precious_Content > Important_File 151303980Sngie 152303980Sngie # Check that we can redirect onto file when -C is not set 153303980Sngie atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \ 154303980Sngie ' 155303980Sngie D=$(ls -l Junk_File) || exit 1 156303980Sngie set +C 157303980Sngie echo "Overwrite it now" > Junk_File 158303980Sngie A=$(ls -l Junk_File) || exit 1 159303980Sngie test "${A}" != "${D}" 160303980Sngie ' 161303980Sngie 162303980Sngie # Check that we cannot redirect onto file when -C is set 163303980Sngie atf_check -s exit:0 -o empty -e not-empty ${TEST_SH} -c \ 164303980Sngie ' 165303980Sngie D=$(ls -l Important_File) || exit 1 166303980Sngie set -C 167303980Sngie echo "Fail to Overwrite it now" > Important_File 168303980Sngie A=$(ls -l Important_File) || exit 1 169303980Sngie test "${A}" = "${D}" 170303980Sngie ' 171303980Sngie 172303980Sngie # Check that we can append to file, even when -C is set 173303980Sngie atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \ 174303980Sngie ' 175303980Sngie D=$(ls -l Junk_File) || exit 1 176303980Sngie set -C 177303980Sngie echo "Append to it now" >> Junk_File 178303980Sngie A=$(ls -l Junk_File) || exit 1 179303980Sngie test "${A}" != "${D}" 180303980Sngie ' 181303980Sngie 182303980Sngie # Check that we abort on attempt to redirect onto file when -Ce is set 183303980Sngie atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \ 184303980Sngie ' 185303980Sngie set -Ce 186303980Sngie echo "Fail to Overwrite it now" > Important_File 187303980Sngie echo "Should not reach this point" 188303980Sngie ' 189303980Sngie 190303980Sngie # Last check that we can override -C for when we really need to 191303980Sngie atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \ 192303980Sngie ' 193303980Sngie D=$(ls -l Junk_File) || exit 1 194303980Sngie set -C 195303980Sngie echo "Change the poor bugger again" >| Junk_File 196303980Sngie A=$(ls -l Junk_File) || exit 1 197303980Sngie test "${A}" != "${D}" 198303980Sngie ' 199303980Sngie} 200303980Sngie 201303980Sngieatf_test_case set_e 202303980Sngieset_e_head() { 203303980Sngie atf_set "descr" "Tests that 'set -e' turns on error detection " \ 204303980Sngie "and that a simple case behaves as defined by the standard" 205303980Sngie} 206303980Sngieset_e_body() { 207303980Sngie test_option_on_off e 208303980Sngie 209303980Sngie # Check that -e does nothing if no commands fail 210303980Sngie atf_check -s exit:0 -o match:I_am_OK -e empty \ 211303980Sngie ${TEST_SH} -c \ 212303980Sngie 'false; printf "%s" I_am; set -e; true; printf "%s\n" _OK' 213303980Sngie 214303980Sngie # and that it (silently, but with exit status) aborts if cmd fails 215303980Sngie atf_check -s not-exit:0 -o match:I_am -o not-match:Broken -e empty \ 216303980Sngie ${TEST_SH} -c \ 217303980Sngie 'false; printf "%s" I_am; set -e; false; printf "%s\n" _Broken' 218303980Sngie 219303980Sngie # same, except -e this time is on from the beginning 220303980Sngie atf_check -s not-exit:0 -o match:I_am -o not-match:Broken -e empty \ 221303980Sngie ${TEST_SH} -ec 'printf "%s" I_am; false; printf "%s\n" _Broken' 222303980Sngie 223303980Sngie # More checking of -e in other places, there is lots to deal with. 224303980Sngie} 225303980Sngie 226303980Sngieatf_test_case set_f 227303980Sngieset_f_head() { 228303980Sngie atf_set "descr" "Tests that 'set -f' turns off pathname expansion " \ 229303980Sngie "and that it behaves as defined by the standard" 230303980Sngie} 231303980Sngieset_f_body() { 232303980Sngie atf_require_prog ls 233303980Sngie 234303980Sngie test_option_on_off f 235303980Sngie 236303980Sngie # Check that the environment to use for the tests is sane ... 237303980Sngie # we assume current dir is a new tempory directory & is empty 238303980Sngie 239303980Sngie test -z "$(ls)" || atf_skip "Test execution directory not clean" 240303980Sngie 241303980Sngie # we will assume that atf will clean up this junk directory 242303980Sngie # when we are done. But for testing pathname expansion 243303980Sngie # we need files 244303980Sngie 245303980Sngie for f in a b c d e f aa ab ac ad ae aaa aab aac aad aba abc bbb ccc 246303980Sngie do 247303980Sngie echo "$f" > "$f" 248303980Sngie done 249303980Sngie 250303980Sngie atf_check -s exit:0 -o empty -e empty ${TEST_SH} -ec \ 251303980Sngie 'X=$(echo b*); Y=$(echo b*); test "${X}" != "a*"; 252303980Sngie test "${X}" = "${Y}"' 253303980Sngie 254303980Sngie # now test expansion is different when -f is set 255303980Sngie atf_check -s exit:0 -o empty -e empty ${TEST_SH} -ec \ 256303980Sngie 'X=$(echo b*); Y=$(set -f; echo b*); test "${X}" != "${Y}"' 257303980Sngie} 258303980Sngie 259303980Sngieatf_test_case set_n 260303980Sngieset_n_head() { 261303980Sngie atf_set "descr" "Tests that 'set -n' supresses command execution " \ 262303980Sngie "and that it behaves as defined by the standard" 263303980Sngie} 264303980Sngieset_n_body() { 265303980Sngie # pointless to test this, if it turns on, it stays on... 266303980Sngie # test_option_on_off n 267303980Sngie # so just allow the tests below to verify it can be turned on 268303980Sngie 269303980Sngie # nothing should be executed, hence no output... 270303980Sngie atf_check -s exit:0 -o empty -e empty \ 271303980Sngie ${TEST_SH} -enc 'echo ABANDON HOPE; echo ALL YE; echo ...' 272303980Sngie 273303980Sngie # this is true even when the "commands" do not exist 274303980Sngie atf_check -s exit:0 -o empty -e empty \ 275303980Sngie ${TEST_SH} -enc 'ERR; FAIL; ABANDON HOPE' 276303980Sngie 277303980Sngie # but if there is a syntax error, it should be detected (w or w/o -e) 278303980Sngie atf_check -s not-exit:0 -o empty -e not-empty \ 279303980Sngie ${TEST_SH} -enc 'echo JUMP; for frogs swim; echo in puddles' 280303980Sngie atf_check -s not-exit:0 -o empty -e not-empty \ 281303980Sngie ${TEST_SH} -nc 'echo ABANDON HOPE; echo "ALL YE; echo ...' 282303980Sngie atf_check -s not-exit:0 -o empty -e not-empty \ 283303980Sngie ${TEST_SH} -enc 'echo ABANDON HOPE;; echo ALL YE; echo ...' 284303980Sngie atf_check -s not-exit:0 -o empty -e not-empty \ 285303980Sngie ${TEST_SH} -nc 'do YOU ABANDON HOPE; for all eternity?' 286303980Sngie 287303980Sngie # now test enabling -n in the middle of a script 288303980Sngie # note that once turned on, it cannot be turned off again. 289303980Sngie # 290303980Sngie # omit more complex cases, as those can send some shells 291303980Sngie # into infinite loops, and believe it or not, that might be OK! 292303980Sngie 293303980Sngie atf_check -s exit:0 -o match:first -o not-match:second -e empty \ 294303980Sngie ${TEST_SH} -c 'echo first; set -n; echo second' 295303980Sngie atf_check -s exit:0 -o match:first -o not-match:third -e empty \ 296303980Sngie ${TEST_SH} -c 'echo first; set -n; echo second; set +n; echo third' 297303980Sngie atf_check -s exit:0 -o inline:'a\nb\n' -e empty \ 298303980Sngie ${TEST_SH} -c 'for x in a b c d 299303980Sngie do 300303980Sngie case "$x" in 301303980Sngie a);; b);; c) set -n;; d);; 302303980Sngie esac 303303980Sngie printf "%s\n" "$x" 304303980Sngie done' 305303980Sngie 306303980Sngie # This last one is a bit more complex to explain, so I will not try 307303980Sngie 308303980Sngie # First, we need to know what signal number is used for SIGUSR1 on 309303980Sngie # the local (testing) system (signal number is $(( $XIT - 128 )) ) 310303980Sngie 311303980Sngie # this will take slightly over 1 second elapsed time (the sleep 1) 312303980Sngie # The "10" for the first sleep just needs to be something big enough 313303980Sngie # that the rest of the commands have time to complete, even on 314303980Sngie # very slow testing systems. 10 should be enough. Otherwise irrelevant 315303980Sngie 316303980Sngie # The shell will usually blather to stderr about the sleep 10 being 317303980Sngie # killed, but it affects nothing, so just allow it to cry. 318303980Sngie 319303980Sngie (sleep 10 & sleep 1; kill -USR1 $!; wait $!) 320303980Sngie XIT="$?" 321303980Sngie 322303980Sngie # The exit value should be an integer > 128 and < 256 (often 158) 323303980Sngie # If it is not just skip the test 324303980Sngie 325303980Sngie # If we do run the test, it should take (slightly over) either 1 or 2 326303980Sngie # seconds to complete, depending upon the shell being tested. 327303980Sngie 328303980Sngie case "${XIT}" in 329303980Sngie ( 129 | 1[3-9][0-9] | 2[0-4][0-9] | 25[0-5] ) 330303980Sngie 331303980Sngie # The script below should exit with the same code - no output 332303980Sngie 333303980Sngie # Or that is the result that seems best explanable. 334303980Sngie # "set -n" in uses like this is not exactly well defined... 335303980Sngie 336303980Sngie # This script comes from a member of the austin group 337303980Sngie # (they author changes to the posix shell spec - and more.) 338303980Sngie # The author is also an (occasional?) NetBSD user. 339303980Sngie atf_check -s exit:${XIT} -o empty -e empty ${TEST_SH} -c ' 340303980Sngie trap "set -n" USR1 341303980Sngie { sleep 1; kill -USR1 $$; sleep 1; } & 342303980Sngie false 343303980Sngie wait && echo t || echo f 344303980Sngie wait 345303980Sngie echo foo 346303980Sngie ' 347303980Sngie ;; 348303980Sngie esac 349303980Sngie} 350303980Sngie 351303980Sngieatf_test_case set_u 352303980Sngieset_u_head() { 353303980Sngie atf_set "descr" "Tests that 'set -u' turns on unset var detection " \ 354303980Sngie "and that it behaves as defined by the standard" 355303980Sngie} 356303980Sngieset_u_body() { 357303980Sngie test_option_on_off u 358303980Sngie 359303980Sngie # first make sure it is OK to unset an unset variable 360303980Sngie atf_check -s exit:0 -o match:OK -e empty ${TEST_SH} -ce \ 361303980Sngie 'unset _UNSET_VARIABLE_; echo OK' 362303980Sngie # even if -u is set 363303980Sngie atf_check -s exit:0 -o match:OK -e empty ${TEST_SH} -cue \ 364303980Sngie 'unset _UNSET_VARIABLE_; echo OK' 365303980Sngie 366303980Sngie # and that without -u accessing an unset variable is harmless 367303980Sngie atf_check -s exit:0 -o match:OK -e empty ${TEST_SH} -ce \ 368303980Sngie 'unset X; echo ${X}; echo OK' 369303980Sngie # and that the unset variable test expansion works properly 370303980Sngie atf_check -s exit:0 -o match:OKOK -e empty ${TEST_SH} -ce \ 371303980Sngie 'unset X; printf "%s" ${X-OK}; echo OK' 372303980Sngie 373303980Sngie # Next test that with -u set, the shell aborts on access to unset var 374303980Sngie # do not use -e, want to make sure it is -u that causes abort 375303980Sngie atf_check -s not-exit:0 -o not-match:ERR -e not-empty ${TEST_SH} -c \ 376303980Sngie 'unset X; set -u; echo ${X}; echo ERR' 377303980Sngie # quoting should make no difference... 378303980Sngie atf_check -s not-exit:0 -o not-match:ERR -e not-empty ${TEST_SH} -c \ 379303980Sngie 'unset X; set -u; echo "${X}"; echo ERR' 380303980Sngie 381303980Sngie # Now a bunch of accesses to unset vars, with -u, in ways that are OK 382303980Sngie atf_check -s exit:0 -o match:OK -e empty ${TEST_SH} -ce \ 383303980Sngie 'unset X; set -u; echo ${X-GOOD}; echo OK' 384303980Sngie atf_check -s exit:0 -o match:OK -e empty ${TEST_SH} -ce \ 385303980Sngie 'unset X; set -u; echo ${X-OK}' 386303980Sngie atf_check -s exit:0 -o not-match:ERR -o match:OK -e empty \ 387303980Sngie ${TEST_SH} -ce 'unset X; set -u; echo ${X+ERR}; echo OK' 388303980Sngie 389303980Sngie # and some more ways that are not OK 390303980Sngie atf_check -s not-exit:0 -o not-match:ERR -e not-empty ${TEST_SH} -c \ 391303980Sngie 'unset X; set -u; echo ${X#foo}; echo ERR' 392303980Sngie atf_check -s not-exit:0 -o not-match:ERR -e not-empty ${TEST_SH} -c \ 393303980Sngie 'unset X; set -u; echo ${X%%bar}; echo ERR' 394303980Sngie 395303980Sngie # lastly, just while we are checking unset vars, test aborts w/o -u 396303980Sngie atf_check -s not-exit:0 -o not-match:ERR -e not-empty ${TEST_SH} -c \ 397303980Sngie 'unset X; echo ${X?}; echo ERR' 398303980Sngie atf_check -s not-exit:0 -o not-match:ERR -e match:X_NOT_SET \ 399303980Sngie ${TEST_SH} -c 'unset X; echo ${X?X_NOT_SET}; echo ERR' 400303980Sngie} 401303980Sngie 402303980Sngieatf_test_case set_v 403303980Sngieset_v_head() { 404303980Sngie atf_set "descr" "Tests that 'set -v' turns on input read echoing " \ 405303980Sngie "and that it behaves as defined by the standard" 406303980Sngie} 407303980Sngieset_v_body() { 408303980Sngie test_option_on_off v 409303980Sngie 410303980Sngie # check that -v does nothing if no later input line is read 411303980Sngie atf_check -s exit:0 \ 412303980Sngie -o match:OKOK -o not-match:echo -o not-match:printf \ 413303980Sngie -e empty \ 414303980Sngie ${TEST_SH} -ec 'printf "%s" OK; set -v; echo OK; exit 0' 415303980Sngie 416303980Sngie # but that it does when there are multiple lines 417303980Sngie cat <<- 'EOF' | 418303980Sngie set -v 419303980Sngie printf %s OK 420303980Sngie echo OK 421303980Sngie exit 0 422303980Sngie EOF 423303980Sngie atf_check -s exit:0 \ 424303980Sngie -o match:OKOK -o not-match:echo -o not-match:printf \ 425303980Sngie -e match:printf -e match:OK -e match:echo \ 426303980Sngie -e not-match:set ${TEST_SH} 427303980Sngie 428303980Sngie # and that it can be disabled again 429303980Sngie cat <<- 'EOF' | 430303980Sngie set -v 431303980Sngie printf %s OK 432303980Sngie set +v 433303980Sngie echo OK 434303980Sngie exit 0 435303980Sngie EOF 436303980Sngie atf_check -s exit:0 \ 437303980Sngie -o match:OKOK -o not-match:echo -o not-match:printf \ 438303980Sngie -e match:printf -e match:OK -e not-match:echo \ 439303980Sngie ${TEST_SH} 440303980Sngie 441303980Sngie # and lastly, that shell keywords do get output when "read" 442303980Sngie cat <<- 'EOF' | 443303980Sngie set -v 444303980Sngie for i in 111 222 333 445303980Sngie do 446303980Sngie printf %s $i 447303980Sngie done 448303980Sngie exit 0 449303980Sngie EOF 450303980Sngie atf_check -s exit:0 \ 451303980Sngie -o match:111222333 -o not-match:printf \ 452303980Sngie -o not-match:for -o not-match:do -o not-match:done \ 453303980Sngie -e match:printf -e match:111 -e not-match:111222 \ 454303980Sngie -e match:for -e match:do -e match:done \ 455303980Sngie ${TEST_SH} 456303980Sngie} 457303980Sngie 458303980Sngieatf_test_case set_x 459303980Sngieset_x_head() { 460303980Sngie atf_set "descr" "Tests that 'set -x' turns on command exec logging " \ 461303980Sngie "and that it behaves as defined by the standard" 462303980Sngie} 463303980Sngieset_x_body() { 464303980Sngie test_option_on_off x 465303980Sngie 466303980Sngie # check that cmd output appears after -x is enabled 467303980Sngie atf_check -s exit:0 \ 468303980Sngie -o match:OKOK -o not-match:echo -o not-match:printf \ 469303980Sngie -e not-match:printf -e match:OK -e match:echo \ 470303980Sngie ${TEST_SH} -ec 'printf "%s" OK; set -x; echo OK; exit 0' 471303980Sngie 472303980Sngie # and that it stops again afer -x is disabled 473303980Sngie atf_check -s exit:0 \ 474303980Sngie -o match:OKOK -o not-match:echo -o not-match:printf \ 475303980Sngie -e match:printf -e match:OK -e not-match:echo \ 476303980Sngie ${TEST_SH} -ec 'set -x; printf "%s" OK; set +x; echo OK; exit 0' 477303980Sngie 478303980Sngie # also check that PS4 is output correctly 479303980Sngie atf_check -s exit:0 \ 480303980Sngie -o match:OK -o not-match:echo \ 481303980Sngie -e match:OK -e match:Run:echo \ 482303980Sngie ${TEST_SH} -ec 'PS4=Run:; set -x; echo OK; exit 0' 483303980Sngie 484303980Sngie return 0 485303980Sngie 486303980Sngie # This one seems controversial... I suspect it is NetBSD's sh 487303980Sngie # that is wrong to not output "for" "while" "if" ... etc 488303980Sngie 489303980Sngie # and lastly, that shell keywords do not get output when "executed" 490303980Sngie atf_check -s exit:0 \ 491303980Sngie -o match:111222333 -o not-match:printf \ 492303980Sngie -o not-match:for \ 493303980Sngie -e match:printf -e match:111 -e not-match:111222 \ 494303980Sngie -e not-match:for -e not-match:do -e not-match:done \ 495303980Sngie ${TEST_SH} -ec \ 496303980Sngie 'set -x; for i in 111 222 333; do printf "%s" $i; done; echo; exit 0' 497303980Sngie} 498303980Sngie 499303980Sngieopt_test_setup() 500303980Sngie{ 501303980Sngie test -n "$1" || { echo >&2 "Internal error"; exit 1; } 502303980Sngie 503303980Sngie cat > "$1" << 'END_OF_FUNCTIONS' 504303980Sngielocal_opt_check() 505303980Sngie{ 506303980Sngie local - 507303980Sngie} 508303980Sngie 509303980Sngieinstr() 510303980Sngie{ 511303980Sngie expr "$2" : "\(.*$1\)" >/dev/null 512303980Sngie} 513303980Sngie 514303980Sngiesave_opts() 515303980Sngie{ 516303980Sngie local - 517303980Sngie 518303980Sngie set -e 519303980Sngie set -u 520303980Sngie 521303980Sngie instr e "$-" && instr u "$-" && return 0 522303980Sngie echo ERR 523303980Sngie} 524303980Sngie 525303980Sngiefiddle_opts() 526303980Sngie{ 527303980Sngie set -e 528303980Sngie set -u 529303980Sngie 530303980Sngie instr e "$-" && instr u "$-" && return 0 531303980Sngie echo ERR 532303980Sngie} 533303980Sngie 534303980Sngielocal_test() 535303980Sngie{ 536303980Sngie set +eu 537303980Sngie 538303980Sngie save_opts 539303980Sngie instr '[eu]' "$-" || printf %s "OK" 540303980Sngie 541303980Sngie fiddle_opts 542303980Sngie instr e "$-" && instr u "$-" && printf %s "OK" 543303980Sngie 544303980Sngie set +eu 545303980Sngie} 546303980SngieEND_OF_FUNCTIONS 547303980Sngie} 548303980Sngie 549303980Sngieatf_test_case restore_local_opts 550303980Sngierestore_local_opts_head() { 551303980Sngie atf_set "descr" "Tests that 'local -' saves and restores options. " \ 552303980Sngie "Note that "local" is a local shell addition" 553303980Sngie} 554303980Sngierestore_local_opts_body() { 555303980Sngie atf_require_prog cat 556303980Sngie atf_require_prog expr 557303980Sngie 558303980Sngie FN="test-funcs.$$" 559303980Sngie opt_test_setup "${FN}" || atf_skip "Cannot setup test environment" 560303980Sngie 561303980Sngie ${TEST_SH} -ec ". './${FN}'; local_opt_check" 2>/dev/null || 562303980Sngie atf_skip "sh extension 'local -' not supported by ${TEST_SH}" 563303980Sngie 564303980Sngie atf_check -s exit:0 -o match:OKOK -o not-match:ERR -e empty \ 565303980Sngie ${TEST_SH} -ec ". './${FN}'; local_test" 566303980Sngie} 567303980Sngie 568303980Sngieatf_test_case vi_emacs_VE_toggle 569303980Sngievi_emacs_VE_toggle_head() { 570303980Sngie atf_set "descr" "Tests enabling vi disables emacs (and v.v - but why?)"\ 571303980Sngie " Note that -V and -E are local shell additions" 572303980Sngie} 573303980Sngievi_emacs_VE_toggle_body() { 574303980Sngie 575303980Sngie test_optional_on_off V E || 576303980Sngie atf_skip "One or both V & E opts unsupported by ${TEST_SH}" 577303980Sngie 578303980Sngie atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c ' 579303980Sngie q() { 580303980Sngie eval "case \"$-\" in 581303980Sngie (*${2}*) return 1;; 582303980Sngie (*${1}*) return 0;; 583303980Sngie esac" 584303980Sngie return 1 585303980Sngie } 586303980Sngie x() { 587303980Sngie echo >&2 "Option set or toggle failure:" \ 588303980Sngie " on=$1 off=$2 set=$-" 589303980Sngie exit 1 590303980Sngie } 591303980Sngie set -V; q V E || x V E 592303980Sngie set -E; q E V || x E V 593303980Sngie set -V; q V E || x V E 594303980Sngie set +EV; q "" "[VE]" || x "" VE 595303980Sngie exit 0 596303980Sngie ' 597303980Sngie} 598303980Sngie 599303980Sngieatf_test_case xx_bogus 600303980Sngiexx_bogus_head() { 601303980Sngie atf_set "descr" "Tests that attempting to set a nonsense option fails." 602303980Sngie} 603303980Sngiexx_bogus_body() { 604303980Sngie # Biggest problem here is picking a "nonsense option" that is 605303980Sngie # not implemented by any shell, anywhere. Hopefully this will do. 606303980Sngie 607303980Sngie # 'set' is a special builtin, so a conforming shell should exit 608303980Sngie # on an arg error, and the ERR should not be printed. 609303980Sngie atf_check -s not-exit:0 -o empty -e not-empty \ 610303980Sngie ${TEST_SH} -c 'set -% ; echo ERR' 611303980Sngie} 612303980Sngie 613303980Sngieatf_test_case Option_switching 614303980SngieOption_switching_head() { 615303980Sngie atf_set "descr" "options can be enabled and disabled" 616303980Sngie} 617303980SngieOption_switching_body() { 618303980Sngie 619303980Sngie # Cannot test -m, setting it causes test shell to fail... 620303980Sngie # (test shell gets SIGKILL!) Wonder why ... something related to atf 621303980Sngie # That is, it works if just run as "sh -c 'echo $-; set -m; echo $-'" 622303980Sngie 623303980Sngie # Don't bother testing toggling -n, once on, it stays on... 624303980Sngie # (and because the test fn refuses to allow us to try) 625303980Sngie 626303980Sngie # Cannot test -o or -c here, or the extension -s 627303980Sngie # they can only be used, not switched 628303980Sngie 629303980Sngie # these are the posix options, that all shells should implement 630303980Sngie test_option_on_off a b C e f h u v x # m 631303980Sngie 632303980Sngie # and these are extensions that might not exist (non-fatal to test) 633303980Sngie # -i and -s (and -c) are posix options, but are not required to 634303980Sngie # be accessable via the "set" command, just the command line. 635303980Sngie # We allow for -i to work with set, as that makes some sense, 636303980Sngie # -c and -s do not. 637303980Sngie test_optional_on_off E i I p q V || true 638303980Sngie 639303980Sngie # Also test (some) option combinations ... 640303980Sngie # only testing posix options here, because it is easier... 641303980Sngie test_option_on_off aeu vx Ca aCefux 642303980Sngie} 643303980Sngie 644303980Sngieatf_init_test_cases() { 645303980Sngie # tests are run in order sort of names produces, so choose names wisely 646303980Sngie 647303980Sngie # this one tests turning on/off all the mandatory. and extra flags 648303980Sngie atf_add_test_case Option_switching 649303980Sngie # and this tests the NetBSD "local -" functionality in functions. 650303980Sngie atf_add_test_case restore_local_opts 651303980Sngie 652303980Sngie # no tests for -m (no idea how to do that one) 653303980Sngie # -I (no easy way to generate the EOF it ignores) 654303980Sngie # -i (not sure how to test that one at the minute) 655303980Sngie # -p (because we aren't going to run tests setuid) 656303980Sngie # -V/-E (too much effort, and a real test would be huge) 657303980Sngie # -c (because almost all the other tests test it anyway) 658303980Sngie # -q (because, for now, I am lazy) 659303980Sngie # -s (coming soon, hopefully) 660303980Sngie # -o (really +o: again, hopefully soon) 661303980Sngie # -o longname (again, just laziness, don't wait...) 662303980Sngie # -h/-b (because NetBSD doesn't implement them) 663303980Sngie atf_add_test_case set_a 664303980Sngie atf_add_test_case set_C 665303980Sngie atf_add_test_case set_e 666303980Sngie atf_add_test_case set_f 667303980Sngie atf_add_test_case set_n 668303980Sngie atf_add_test_case set_u 669303980Sngie atf_add_test_case set_v 670303980Sngie atf_add_test_case set_x 671303980Sngie 672303980Sngie atf_add_test_case vi_emacs_VE_toggle 673303980Sngie atf_add_test_case xx_bogus 674303980Sngie} 675