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