Home | History | Annotate | Line # | Download | only in sh
t_redir.sh revision 1.7
      1 # $NetBSD: t_redir.sh,v 1.7 2016/05/09 22:34:37 kre Exp $
      2 #
      3 # Copyright (c) 2016 The NetBSD Foundation, Inc.
      4 # All rights reserved.
      5 #
      6 # Redistribution and use in source and binary forms, with or without
      7 # modification, are permitted provided that the following conditions
      8 # are met:
      9 # 1. Redistributions of source code must retain the above copyright
     10 #    notice, this list of conditions and the following disclaimer.
     11 # 2. Redistributions in binary form must reproduce the above copyright
     12 #    notice, this list of conditions and the following disclaimer in the
     13 #    documentation and/or other materials provided with the distribution.
     14 #
     15 # THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     16 # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     17 # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     18 # PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     19 # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     20 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     21 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     22 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     23 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     24 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     25 # POSSIBILITY OF SUCH DAMAGE.
     26 #
     27 # the implementation of "sh" to test
     28 : ${TEST_SH:="/bin/sh"}
     29 
     30 # Any failures in this first test means it is not worth bothering looking
     31 # for causes of failures in any other tests, make this one work first.
     32 
     33 # Problems with this test usually mean inadequate ATF_SHELL used for testing.
     34 # (though if all pass but the last, it might be a TEST_SH problem.)
     35 
     36 atf_test_case basic_test_method_test
     37 basic_test_method_test_head()
     38 {
     39 	atf_set "descr" "Tests that test method works as expected"
     40 }
     41 basic_test_method_test_body()
     42 {
     43 	cat <<- 'DONE' |
     44 	DONE
     45 	atf_check -s exit:0 -o empty -e empty ${TEST_SH}
     46 	cat <<- 'DONE' |
     47 	DONE
     48 	atf_check -s exit:0 -o match:0 -e empty ${TEST_SH} -c 'wc -l'
     49 
     50 	cat <<- 'DONE' |
     51 		echo hello
     52 	DONE
     53 	atf_check -s exit:0 -o match:hello -e empty ${TEST_SH} 
     54 	cat <<- 'DONE' |
     55 		echo hello
     56 	DONE
     57 	atf_check -s exit:0 -o match:1 -e empty ${TEST_SH} -c 'wc -l'
     58 
     59 	cat <<- 'DONE' |
     60 		echo hello\
     61 					world
     62 	DONE
     63 	atf_check -s exit:0 -o match:helloworld -e empty ${TEST_SH} 
     64 	cat <<- 'DONE' |
     65 		echo hello\
     66 					world
     67 	DONE
     68 	atf_check -s exit:0 -o match:2 -e empty ${TEST_SH} -c 'wc -l'
     69 
     70 	printf '%s\n%s\n%s\n' Line1 Line2 Line3 > File
     71 	atf_check -s exit:0 -o inline:'Line1\nLine2\nLine3\n' -e empty \
     72 		${TEST_SH} -c 'cat File'
     73 
     74 	cat <<- 'DONE' |
     75 		set -- X "" '' Y
     76 		echo ARGS="${#}"
     77 		echo '' -$1- -$2- -$3- -$4-
     78 		cat <<EOF
     79 			X=$1
     80 		EOF
     81 		cat <<\EOF
     82 			Y=$4
     83 		EOF
     84 	DONE
     85 	atf_check -s exit:0 -o match:ARGS=4 -o match:'-X- -- -- -Y-' \
     86 		-o match:X=X -o match:'Y=\$4' -e empty ${TEST_SH} 
     87 }
     88 
     89 atf_test_case do_input_redirections
     90 do_input_redirections_head()
     91 {
     92 	atf_set "descr" "Tests that simple input redirection works"
     93 }
     94 do_input_redirections_body()
     95 {
     96 	printf '%s\n%s\n%s\nEND\n' 'First Line' 'Second Line' 'Line 3' >File
     97 
     98 	atf_check -s exit:0 -e empty \
     99 		-o inline:'First Line\nSecond Line\nLine 3\nEND\n' \
    100 		${TEST_SH} -c 'cat < File'
    101 	atf_check -s exit:0 -e empty \
    102 		-o inline:'First Line\nSecond Line\nLine 3\nEND\n' \
    103 		${TEST_SH} -c 'cat <File'
    104 	atf_check -s exit:0 -e empty \
    105 		-o inline:'First Line\nSecond Line\nLine 3\nEND\n' \
    106 		${TEST_SH} -c 'cat< File'
    107 	atf_check -s exit:0 -e empty \
    108 		-o inline:'First Line\nSecond Line\nLine 3\nEND\n' \
    109 		${TEST_SH} -c 'cat < "File"'
    110 	atf_check -s exit:0 -e empty \
    111 		-o inline:'First Line\nSecond Line\nLine 3\nEND\n' \
    112 		${TEST_SH} -c '< File cat'
    113 
    114 	ln File wc
    115 	atf_check -s exit:0 -e empty \
    116 		-o inline:'First Line\nSecond Line\nLine 3\nEND\n' \
    117 		${TEST_SH} -c '< wc cat'
    118 
    119 	mv wc cat
    120 	atf_check -s exit:0 -e empty -o match:4 \
    121 		${TEST_SH} -c '< cat wc'
    122 
    123 
    124 	cat <<- 'EOF' |
    125 		for l in 1 2 3; do
    126 			read line < File
    127 			echo "$line"
    128 		done
    129 	EOF
    130 	atf_check -s exit:0 -e empty \
    131 		-o inline:'First Line\nFirst Line\nFirst Line\n' \
    132 		${TEST_SH}
    133 
    134 	cat <<- 'EOF' |
    135 		for l in 1 2 3; do
    136 			read line
    137 			echo "$line"
    138 		done <File
    139 	EOF
    140 	atf_check -s exit:0 -e empty \
    141 		-o inline:'First Line\nSecond Line\nLine 3\n' \
    142 		${TEST_SH}
    143 
    144 	cat <<- 'EOF' |
    145 		for l in 1 2 3; do
    146 			read line < File
    147 			echo "$line"
    148 		done <File
    149 	EOF
    150 	atf_check -s exit:0 -e empty \
    151 		-o inline:'First Line\nFirst Line\nFirst Line\n' \
    152 		${TEST_SH}
    153 
    154 	cat <<- 'EOF' |
    155 		line=
    156 		while [ "$line" != END ]; do
    157 			read line || exit 1
    158 			echo "$line"
    159 		done <File
    160 	EOF
    161 	atf_check -s exit:0 -e empty \
    162 		-o inline:'First Line\nSecond Line\nLine 3\nEND\n' \
    163 		${TEST_SH}
    164 
    165 	cat <<- 'EOF' |
    166 		while :; do
    167 			read line || exit 0
    168 			echo "$line"
    169 		done <File
    170 	EOF
    171 	atf_check -s exit:0 -e empty \
    172 		-o inline:'First Line\nSecond Line\nLine 3\nEND\n' \
    173 		${TEST_SH}
    174 
    175 	cat <<- 'EOF' |
    176 		l=''
    177 		while read line < File
    178 		do
    179 			echo "$line"
    180 			l="${l}x"
    181 			[ ${#l} -ge 3 ] && break
    182 		done
    183 		echo DONE
    184 	EOF
    185 	atf_check -s exit:0 -e empty \
    186 		-o inline:'First Line\nFirst Line\nFirst Line\nDONE\n' \
    187 		${TEST_SH}
    188 
    189 	cat <<- 'EOF' |
    190 		while read line
    191 		do
    192 			echo "$line"
    193 		done <File
    194 		echo DONE
    195 	EOF
    196 	atf_check -s exit:0 -e empty \
    197 		-o inline:'First Line\nSecond Line\nLine 3\nEND\nDONE\n' \
    198 		${TEST_SH}
    199 
    200 	cat <<- 'EOF' |
    201 		l=''
    202 		while read line
    203 		do
    204 			echo "$line"
    205 			l="${l}x"
    206 			[ ${#l} -ge 3 ] && break
    207 		done <File
    208 		echo DONE
    209 	EOF
    210 	atf_check -s exit:0 -e empty \
    211 		-o inline:'First Line\nSecond Line\nLine 3\nDONE\n' ${TEST_SH}
    212 
    213 	cat <<- 'EOF' |
    214 		l=''
    215 		while read line1 <File
    216 		do
    217 			read line2
    218 			echo "$line1":"$line2"
    219 			l="${l}x"
    220 			[ ${#l} -ge 2 ] && break
    221 		done <File
    222 		echo DONE
    223 	EOF
    224 	atf_check -s exit:0 -e empty \
    225 	    -o inline:'First Line:First Line\nFirst Line:Second Line\nDONE\n' \
    226 		${TEST_SH}
    227 }
    228 
    229 atf_test_case do_output_redirections
    230 do_output_redirections_head()
    231 {
    232 	atf_set "descr" "Test Output redirections"
    233 }
    234 do_output_redirections_body()
    235 {
    236 nl='
    237 '
    238 	T=0
    239 	i() { T=$(expr "$T" + 1); }
    240 
    241 	rm -f Output 2>/dev/null || :
    242 	test -f Output && atf_fail "Unable to remove Output file"
    243 #1
    244 	i; atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c '> Output'
    245 	test -f Output || atf_fail "#$T: Did not make Output file"
    246 #2
    247 	rm -f Output 2>/dev/null || :
    248 	i; atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c '>> Output'
    249 	test -f Output || atf_fail "#$T: Did not make Output file"
    250 #3
    251 	rm -f Output 2>/dev/null || :
    252 	i; atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c '>| Output'
    253 	test -f Output || atf_fail "#$T: Did not make Output file"
    254 
    255 #4
    256 	rm -f Output 2>/dev/null || :
    257 	i
    258 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c 'echo Hello >Output'
    259 	test -s Output || atf_fail "#$T: Did not make non-empty Output file"
    260 	test "$(cat Output)" = "Hello" ||
    261 	  atf_fail "#$T: Incorrect Output: Should be 'Hello' is '$(cat Output)'"
    262 #5
    263 	i
    264 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c 'echo Hello>!Output'
    265 	test -s Output || atf_fail "#$T: Did not make non-empty Output file"
    266 	test "$(cat Output)" = "Hello" ||
    267 	  atf_fail "#$T: Incorrect Output: Should be 'Hello' is '$(cat Output)'"
    268 #6
    269 	i
    270 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c 'echo Bye >>Output'
    271 	test -s Output || atf_fail "#$T: Removed Output file"
    272 	test "$(cat Output)" = "Hello${nl}Bye" || atf_fail \
    273 	  "#$T: Incorrect Output: Should be 'Hello\\nBye' is '$(cat Output)'"
    274 #7
    275 	i; atf_check -s exit:0 -o inline:'line 1\nline 2\n' -e empty \
    276 		${TEST_SH} -c \
    277 		'echo line 1 > Output; echo line 2 >> Output; cat Output'
    278 	test "$(cat Output)" = "line 1${nl}line 2" || atf_fail \
    279 	 "#$T: Incorrect Output: Should be 'line 1\\nline 2' is '$(cat Output)'"
    280 #8
    281 	i; atf_check -s exit:0 -o inline:'line 2\n' -e empty \
    282 		${TEST_SH} -c 'echo line 1 > Output; echo line 2'
    283 	test "$(cat Output)" = "line 1" || atf_fail \
    284 	    "#$T: Incorrect Output: Should be 'line 1' is '$(cat Output)'"
    285 #9
    286 	i; atf_check -s exit:0 -o empty -e empty \
    287 		${TEST_SH} -c '(echo line 1; echo line 2 > Out2) > Out1'
    288 	test "$(cat Out1)" = "line 1" || atf_fail \
    289 	    "#$T: Incorrect Out1: Should be 'line 1' is '$(cat Out1)'"
    290 	test "$(cat Out2)" = "line 2" || atf_fail \
    291 	    "#$T: Incorrect Out2: Should be 'line 2' is '$(cat Out2)'"
    292 #10
    293 	i; atf_check -s exit:0 -o empty -e empty \
    294 		${TEST_SH} -c '{ echo line 1; echo line 2 > Out2;} > Out1'
    295 	test "$(cat Out1)" = "line 1" || atf_fail \
    296 	    "#$T: Incorrect Out1: Should be 'line 1' is '$(cat Out1)'"
    297 	test "$(cat Out2)" = "line 2" || atf_fail \
    298 	    "#$T: Incorrect Out2: Should be 'line 2' is '$(cat Out2)'"
    299 #11
    300 	i; rm -f Out1 Out2 2>/dev/null || :
    301 	cat <<- 'EOF' |
    302 		for arg in 'line 1' 'line 2' 'line 3'
    303 		do
    304 			echo "$arg"
    305 			echo "$arg" > Out1
    306 		done > Out2
    307 	EOF
    308 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} 
    309 	test "$(cat Out1)" = "line 3" || atf_fail \
    310 		"#$T:  Incorrect Out1: Should be 'line 3' is '$(cat Out1)'"
    311 	test "$(cat Out2)" = "line 1${nl}line 2${nl}line 3" || atf_fail \
    312     "#$T: Incorrect Out2: Should be 'line 1\\nline 2\\nline 3' is '$(cat Out2)'"
    313 #12
    314 	i; rm -f Out1 Out2 2>/dev/null || :
    315 	cat <<- 'EOF' |
    316 		for arg in 'line 1' 'line 2' 'line 3'
    317 		do
    318 			echo "$arg"
    319 			echo "$arg" >> Out1
    320 		done > Out2
    321 	EOF
    322 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} 
    323 	test "$(cat Out1)" = "line 1${nl}line 2${nl}line 3" || atf_fail \
    324     "#$T: Incorrect Out1: Should be 'line 1\\nline 2\\nline 3' is '$(cat Out1)'"
    325 	test "$(cat Out2)" = "line 1${nl}line 2${nl}line 3" || atf_fail \
    326     "#$T: Incorrect Out2: Should be 'line 1\\nline 2\\nline 3' is '$(cat Out2)'"
    327 }
    328 
    329 atf_test_case fd_redirections
    330 fd_redirections_head()
    331 {
    332 	atf_set "descr" "Tests redirections to/from specific descriptors"
    333 }
    334 fd_redirections_body()
    335 {
    336 	atf_require_prog /bin/echo
    337 
    338 	cat <<- 'DONE' > helper.sh
    339 		f() {
    340 			/bin/echo nothing "$1" >& "$1"
    341 		}
    342 		for n
    343 		do
    344 			eval "f $n $n"'> file-$n'
    345 		done
    346 	DONE
    347 	cat <<- 'DONE' > reread.sh
    348 		f() {
    349 			(read -r var; echo "${var}") <&"$1"
    350 		}
    351 		for n
    352 		do
    353 			x=$( eval "f $n $n"'< file-$n' )
    354 			test "${x}" = "nothing $n" || echo "$n"
    355 		done
    356 	DONE
    357 
    358 	validate()
    359 	{
    360 	    for n
    361 	    do
    362 		test -e "file-$n" || atf_fail "file-$n not created"
    363 		C=$(cat file-"$n")
    364 		test "$C" = "nothing $n" ||
    365 			atf_fail "file-$n contains '$C' not 'nothing $n'"
    366 	    done
    367 	}
    368 
    369 	atf_check -s exit:0 -e empty -o empty \
    370 		${TEST_SH} helper.sh 1 2 3 4 5 6 7 8 9
    371 	validate 1 2 3 4 5 6 7 8 9
    372 	atf_check -s exit:0 -e empty -o empty \
    373 		${TEST_SH} reread.sh 3 4 5 6 7 8 9
    374 
    375 	L=$(ulimit -n)
    376 	if [ "$L" -ge 30 ]
    377 	then
    378 		atf_check -s exit:0 -e empty -o empty \
    379 			${TEST_SH} helper.sh 10 15 19 20 25 29
    380 		validate 10 15 19 20 25 29
    381 		atf_check -s exit:0 -e empty -o empty \
    382 			${TEST_SH} reread.sh 10 15 19 20 25 29
    383 	fi
    384 	if [ "$L" -ge 100 ]
    385 	then
    386 		atf_check -s exit:0 -e empty -o empty \
    387 			${TEST_SH} helper.sh 32 33 49 50 51 63 64 65 77 88 99
    388 		validate 32 33 49 50 51 63 64 65 77 88 99
    389 		atf_check -s exit:0 -e empty -o empty \
    390 			${TEST_SH} reread.sh 32 33 49 50 51 63 64 65 77 88 99
    391 	fi
    392 	if [ "$L" -ge 500 ]
    393 	then
    394 		atf_check -s exit:0 -e empty -o empty \
    395 			${TEST_SH} helper.sh 100 101 199 200 222 333 444 499
    396 		validate 100 101 199 200 222 333 444 499
    397 		atf_check -s exit:0 -e empty -o empty \
    398 			${TEST_SH} reread.sh 100 101 199 200 222 333 444 499
    399 	fi
    400 	if [ "$L" -gt 1005 ]
    401 	then
    402 		atf_check -s exit:0 -e empty -o empty \
    403 			${TEST_SH} helper.sh 1000 1001 1002 1003 1004 1005
    404 		validate 1000 1001 1002 1003 1004 1005
    405 		atf_check -s exit:0 -e empty -o empty \
    406 			${TEST_SH} reread.sh 1000 1001 1002 1003 1004 1005
    407 	fi
    408 } 
    409 
    410 atf_test_case local_redirections
    411 local_redirections_head()
    412 {
    413 	atf_set "descr" \
    414 	    "Tests that exec can reassign file descriptors in the shell itself"
    415 }
    416 local_redirections_body()
    417 {
    418 	cat <<- 'DONE' > helper.sh
    419 		for f
    420 		do
    421 			eval "exec $f"'> file-$f'
    422 		done
    423 
    424 		for f
    425 		do
    426 			printf '%s\n' "Hello $f" >&"$f"
    427 		done
    428 
    429 		for f
    430 		do
    431 			eval "exec $f"'>&-'
    432 		done
    433 
    434 		for f
    435 		do
    436 			eval "exec $f"'< file-$f'
    437 		done
    438 
    439 		for f
    440 		do
    441 			exec <& "$f"
    442 			read -r var || echo >&2 "No data in file-$f"
    443 			read -r x && echo >&2 "Too much data in file-${f}: $x"
    444 			test "${var}" = "Hello $f" ||
    445 			    echo >&2 "file-$f contains '${var}' not 'Hello $f'"
    446 		done
    447 	DONE
    448 
    449 	atf_check -s exit:0 -o empty -e empty \
    450 		${TEST_SH} helper.sh 3 4 5 6 7 8 9
    451 
    452 	L=$(ulimit -n)
    453 	if [ "$L" -ge 30 ]
    454 	then
    455 		atf_check -s exit:0 -o empty -e empty \
    456 			${TEST_SH} helper.sh 10 11 13 15 16 19 20 28 29
    457 	fi
    458 	if [ "$L" -ge 100 ]
    459 	then
    460 		atf_check -s exit:0 -o empty -e empty \
    461 			${TEST_SH} helper.sh 30 31 32 63 64 65 77 88 99
    462 	fi
    463 	if [ "$L" -ge 500 ]
    464 	then
    465 		atf_check -s exit:0 -o empty -e empty \
    466 			${TEST_SH} helper.sh 100 101 111 199 200 201 222 333 499
    467 	fi
    468 	if [ "$L" -ge 1005 ]
    469 	then
    470 		atf_check -s exit:0 -o empty -e empty \
    471 			${TEST_SH} helper.sh 1000 1001 1002 1003 1004 1005
    472 	fi
    473 }
    474 
    475 atf_test_case named_fd_redirections
    476 named_fd_redirections_head()
    477 {
    478 	atf_set "descr" "Tests redirections to /dev/stdout (etc)"
    479 
    480 }
    481 named_fd_redirections_body()
    482 {
    483 	if test -c /dev/stdout
    484 	then
    485 		atf_check -s exit:0 -o inline:'OK\n' -e empty \
    486 			${TEST_SH} -c 'echo OK >/dev/stdout'
    487 		atf_check -s exit:0 -o inline:'OK\n' -e empty \
    488 			${TEST_SH} -c '/bin/echo OK >/dev/stdout'
    489 	fi
    490 
    491 	if test -c /dev/stdin
    492 	then
    493 		atf_require_prog cat
    494 
    495 		echo GOOD | atf_check -s exit:0 -o inline:'GOOD\n' -e empty \
    496 			${TEST_SH} -c 'read var </dev/stdin; echo $var'
    497 		echo GOOD | atf_check -s exit:0 -o inline:'GOOD\n' -e empty \
    498 			${TEST_SH} -c 'cat </dev/stdin'
    499 	fi
    500 
    501 	if test -c /dev/stderr
    502 	then
    503 		atf_check -s exit:0 -e inline:'OK\n' -o empty \
    504 			${TEST_SH} -c 'echo OK 2>/dev/stderr >&2'
    505 		atf_check -s exit:0 -e inline:'OK\n' -o empty \
    506 			${TEST_SH} -c '/bin/echo OK 2>/dev/stderr >&2'
    507 	fi
    508 
    509 	if test -c /dev/fd/8 && test -c /dev/fd/9
    510 	then
    511 		atf_check -s exit:0 -o inline:'EIGHT\n' -e empty \
    512 			${TEST_SH} -c 'printf "%s\n" EIGHT 8>&1 >/dev/fd/8 |
    513 					cat 9<&0 </dev/fd/9'
    514 	fi
    515 
    516 	return 0
    517 }
    518 
    519 atf_test_case redir_in_case
    520 redir_in_case_head()
    521 {
    522 	atf_set "descr" "Tests that sh(1) allows just redirections " \
    523 	                "in case statements. (PR bin/48631)"
    524 }
    525 redir_in_case_body()
    526 {
    527 	atf_check -s exit:0 -o empty -e empty \
    528 	    ${TEST_SH} -c 'case x in (whatever) >foo;; esac'
    529 
    530 	atf_check -s exit:0 -o empty -e empty \
    531 	    ${TEST_SH} -c 'case x in (whatever) >foo 2>&1;; esac'
    532 
    533 	atf_check -s exit:0 -o empty -e empty \
    534 	    ${TEST_SH} -c 'case x in (whatever) >foo 2>&1 </dev/null;; esac'
    535 
    536 	atf_check -s exit:0 -o empty -e empty \
    537 	    ${TEST_SH} -c 'case x in (whatever) >${somewhere};; esac'
    538 }
    539 
    540 atf_test_case incorrect_redirections
    541 incorrect_redirections_head()
    542 {
    543 	atf_set "descr" "Tests that sh(1) correctly ignores non-redirections"
    544 }
    545 incorrect_redirections_body() {
    546 
    547 	atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c 'echo foo>'
    548 	atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c 'read foo<'
    549 	atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c 'echo foo<>'
    550 	atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
    551 		'echo x > '"$nl"
    552 	atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
    553 		'read x < '"$nl"
    554 	atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
    555 		'echo x <> '"$nl"
    556 	atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
    557 		'echo x >< anything'
    558 	atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
    559 		'echo x >>< anything'
    560 	atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
    561 		'echo x >|< anything'
    562 	atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
    563 		'echo x > ; read x < /dev/null || echo bad'
    564 	atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
    565 		'read x < & echo y > /dev/null; wait && echo bad'
    566 
    567 	rm -f Output 2>/dev/null || :
    568 	atf_check -s exit:0 -e empty -o inline:'A Line > Output\n' \
    569 		${TEST_SH} -c 'echo A Line \> Output'
    570 	test -f Output && atf_file "File 'Output' appeared and should not have"
    571 
    572 	rm -f Output 2>/dev/null || :
    573 	atf_check -s exit:0 -e empty -o empty \
    574 		${TEST_SH} -c 'echo A Line \>> Output'
    575 	test -f Output || atf_file "File 'Output' not created when it should"
    576 	test "$(cat Output)" = 'A Line >' || atf_fail \
    577 		"Output file contains '$(cat Output)' instead of '"'A Line >'\'
    578 
    579 	rm -f Output \> 2>/dev/null || :
    580 	atf_check -s exit:0 -e empty -o empty \
    581 		${TEST_SH} -c 'echo A Line >\> Output'
    582 	test -f Output && atf_file "File 'Output' appeared and should not have"
    583 	test -f '>' || atf_file "File '>' not created when it should"
    584 	test "$(cat '>')" = 'A Line Output' || atf_fail \
    585 	    "Output file ('>') contains '$(cat '>')' instead of 'A Line Output'"
    586 }
    587 
    588 # Many more tests in t_here, so here we have just rudimentary checks
    589 atf_test_case redir_here_doc
    590 redir_here_doc_head()
    591 {
    592 	atf_set "descr" "Tests that sh(1) correctly processes 'here' doc " \
    593 	                "input redirections"
    594 }
    595 redir_here_doc_body()
    596 {
    597 	# nb: the printf is not executed, it is data
    598 	cat <<- 'DONE' |
    599 		cat <<EOF
    600 			printf '%s\n' 'hello\n'
    601 		EOF
    602 	DONE
    603 	atf_check -s exit:0 -o match:printf -o match:'hello\\n' \
    604 		-e empty ${TEST_SH} 
    605 }
    606 
    607 atf_test_case subshell_redirections
    608 subshell_redirections_head()
    609 {
    610 	atf_set "descr" "Tests redirection interactions between shell and " \
    611 			"its sub-shell(s)"
    612 }
    613 subshell_redirections_body()
    614 {
    615 	atf_require_prog cat
    616 
    617 	LIM=$(ulimit -n)
    618 
    619 	cat <<- 'DONE' |
    620 		exec 6>output-file
    621 
    622 		( printf "hello\n" >&6 )
    623 
    624 		exec 8<output-file
    625 
    626 		( read hello <&8 ; test hello = "$hello" || echo >&2 Hello )
    627 
    628 		( printf "bye-bye\n" >&6 )
    629 
    630 		( exec 8<&- )
    631 		read bye <&8 || echo >&2 "Closed?"
    632 		echo Bye="$bye"
    633 	DONE
    634 	atf_check -s exit:0 -o match:Bye=bye-bye -e empty \
    635 		${TEST_SH}
    636 
    637 	cat <<- 'DONE' |
    638 		for arg in one-4 two-24 three-14
    639 		do
    640 			fd=${arg#*-}
    641 			file=${arg%-*}
    642 			eval "exec ${fd}>${file}"
    643 		done
    644 
    645 		for arg in one-5 two-7 three-19
    646 		do
    647 			fd=${arg#*-}
    648 			file=${arg%-*}
    649 			eval "exec ${fd}<${file}"
    650 		done
    651 
    652 		(
    653 			echo line-1 >&4
    654 			echo line-2 >&24
    655 			echo line-3 >&14
    656 			echo go
    657 		) | (
    658 			read go
    659 			read x <&5
    660 			read y <&7
    661 			read z <&19
    662 
    663 			printf "%s\n" "${x}" "${y}" "${z}"
    664 		)
    665 	DONE
    666 	atf_check -s exit:0 -o inline:'line-1\nline-2\nline-3\n' \
    667 		-e empty ${TEST_SH}
    668 
    669 	cat <<- 'DONE' |
    670 		for arg in one-4-5 two-6-7 three-8-9 four-11-10 five-3-12
    671 		do
    672 			ofd=${arg##*-}
    673 			file=${arg%-*}
    674 			ifd=${file#*-}
    675 			file=${file%-*}
    676 			eval "exec ${ofd}>${file}"
    677 			eval "exec ${ifd}<${file}"
    678 		done
    679 
    680 		( ( ( echo line-1 >& 13 ) 13>&12 ) 12>&5 ) >stdout 2>errout
    681 		( ( ( echo line-2 >& 4) 13>&12 ) 4>&7 ) >>stdout 2>>errout
    682 		( ( ( echo line-3 >& 6) 8>&1 6>&11 >&12) 11>&9 >&7 ) >>stdout
    683 
    684 		( ( ( cat <&13 >&12 ) 13<&8 12>&10 ) 10>&1 8<&6 ) 6<&4
    685 		( ( ( cat <&4 ) <&4 6<&8 8<&11  )
    686 			<&4 4<&6 6<&8 8<&11 ) <&4 4<&6 6<&8 8<&11 11<&3
    687 		( ( ( cat <&7 >&1 ) 7<&6 >&10 ) 10>&2 6<&8 ) 2>&1
    688 	DONE
    689 	atf_check -s exit:0 -o inline:'line-1\nline-2\nline-3\n' \
    690 		-e empty ${TEST_SH}
    691 }
    692 
    693 atf_test_case ulimit_redirection_interaction
    694 ulimit_redirection_interaction_head()
    695 {
    696 	atf_set "descr" "Tests interactions between redirect and ulimit -n "
    697 }
    698 ulimit_redirection_interaction_body()
    699 {
    700 	atf_require_prog ls
    701 
    702 	cat <<- 'DONE' > helper.sh
    703 		oLIM=$(ulimit -n)
    704 		HRD=$(ulimit -H -n)
    705 		test "${oLIM}" -lt "${HRD}"  && ulimit -n "${HRD}"
    706 		LIM=$(ulimit -n)
    707 
    708 		FDs=
    709 		LFD=-1
    710 		while [ ${LIM} -gt 16 ]
    711 		do
    712 			FD=$(( ${LIM} - 1 ))
    713 			if [ "${FD}" -eq "${LFD}" ]; then
    714 				echo >&2 "Infinite loop... (busted $(( )) ??)"
    715 				exit 1
    716 			fi
    717 			LFD="${FD}"
    718 
    719 			eval "exec ${FD}"'> /dev/null'
    720 			FDs="${FD}${FDs:+ }${FDs}"
    721 
    722 			(
    723 				FD=$(( ${LIM} + 1 ))
    724 				eval "exec ${FD}"'> /dev/null'
    725 				echo "Reached unreachable command"
    726 			) 2>/dev/null && echo >&2 "Opened beyond limit!"
    727 
    728 			(eval 'ls 2>&1 3>&1 4>&1 5>&1 '"${FD}"'>&1') >&"${FD}"
    729 
    730 			LIM=$(( ${LIM} / 2 ))
    731 			ulimit -S -n "${LIM}"
    732 		done
    733 
    734 		# Even though ulimit has been reduced, open fds should work
    735 		for FD in ${FDs}
    736 		do
    737 			echo ${FD} in ${FDs} >&"${FD}" || exit 1
    738 		done
    739 
    740 		ulimit -S -n "${oLIM}"
    741 
    742 		# maybe more later...
    743 
    744 	DONE
    745 
    746 	atf_check -s exit:0 -o empty -e empty ${TEST_SH} helper.sh
    747 }
    748 
    749 atf_test_case validate_fn_redirects
    750 validate_fn_redirects_head()
    751 {
    752 	# These test cases inspired by PR bin/48875 and the sh
    753 	# changes that were required to fix it.
    754 
    755 	atf_set "descr" "Tests various redirections applied to functions " \
    756 		"See PR bin/48875"
    757 }
    758 validate_fn_redirects_body()
    759 {
    760 	cat <<- 'DONE' > f-def
    761 		f() {
    762 			printf '%s\n' In-Func
    763 		}
    764 	DONE
    765 
    766 	atf_check -s exit:0 -o inline:'In-Func\nsuccess1\n' -e empty \
    767 		${TEST_SH} -c ". ./f-def; f ; printf '%s\n' success1"
    768 	atf_check -s exit:0 -o inline:'success2\n' -e empty \
    769 		${TEST_SH} -c ". ./f-def; f >/dev/null; printf '%s\n' success2"
    770 	atf_check -s exit:0 -o inline:'success3\n' -e empty \
    771 		${TEST_SH} -c ". ./f-def; f >&- ; printf '%s\n' success3"
    772 	atf_check -s exit:0 -o inline:'In-Func\nsuccess4\n' -e empty \
    773 		${TEST_SH} -c ". ./f-def; f & wait; printf '%s\n' success4"
    774 	atf_check -s exit:0 -o inline:'success5\n' -e empty \
    775 		${TEST_SH} -c ". ./f-def; f >&- & wait; printf '%s\n' success5"
    776 	atf_check -s exit:0 -o inline:'In-Func\nIn-Func\nsuccess6\n' -e empty \
    777 		${TEST_SH} -c ". ./f-def; f;f; printf '%s\n' success6"
    778 	atf_check -s exit:0 -o inline:'In-Func\nIn-Func\nsuccess7\n' -e empty \
    779 		${TEST_SH} -c ". ./f-def; { f;f;}; printf '%s\n' success7"
    780 	atf_check -s exit:0 -o inline:'In-Func\nIn-Func\nsuccess8\n' -e empty \
    781 		${TEST_SH} -c ". ./f-def; { f;f;}& wait; printf '%s\n' success8"
    782 	atf_check -s exit:0 -o inline:'In-Func\nsuccess9\n' -e empty \
    783 		${TEST_SH} -c \
    784 		   ". ./f-def; { f>/dev/null;f;}& wait; printf '%s\n' success9"
    785 	atf_check -s exit:0 -o inline:'In-Func\nsuccess10\n' -e empty \
    786 		${TEST_SH} -c \
    787 		   ". ./f-def; { f;f>/dev/null;}& wait; printf '%s\n' success10"
    788 
    789 	# Tests with sh reading stdin, which is not quite the same internal
    790 	# mechanism.
    791 	echo ". ./f-def || echo >&2 FAIL
    792 		f
    793 		printf '%s\n' stdin1
    794 	"| atf_check -s exit:0 -o inline:'In-Func\nstdin1\n' -e empty ${TEST_SH}
    795 
    796 	echo '
    797 		. ./f-def || echo >&2 FAIL
    798 		f >&-
    799 		printf '%s\n' stdin2
    800 	' | atf_check -s exit:0 -o inline:'stdin2\n' -e empty ${TEST_SH}
    801 
    802 	cat <<- 'DONE' > fgh.def
    803 		f() {
    804 			echo -n f >&3
    805 			sleep 4
    806 			echo -n F >&3
    807 		}
    808 		g() {
    809 			echo -n g >&3
    810 			sleep 2
    811 			echo -n G >&3
    812 		}
    813 		h() {
    814 			echo -n h >&3
    815 		}
    816 	DONE
    817 
    818 	atf_check -s exit:0 -o inline:'fFgGh' -e empty \
    819 		${TEST_SH} -c '. ./fgh.def || echo >&2 FAIL
    820 			exec 3>&1
    821 			f; g; h'
    822 
    823 	atf_check -s exit:0 -o inline:'fghGF' -e empty \
    824 		${TEST_SH} -c '. ./fgh.def || echo >&2 FAIL
    825 			exec 3>&1
    826 			f & sleep 1; g & sleep 1; h; wait'
    827 
    828 	atf_check -s exit:0 -o inline:'fFgGhX Y\n' -e empty \
    829 		${TEST_SH} -c '. ./fgh.def || echo >&2 FAIL
    830 			exec 3>&1
    831 			echo X $( f ; g ; h ) Y'
    832 
    833 	# This one is the real test for PR bin/48875.  If the
    834 	# cmdsub does not complete before f g (and h) exit,
    835 	# then the 'F' & 'G' will precede 'X Y' in the output.
    836 	# If the cmdsub finishes while f & g are still running,
    837 	# then the X Y will appear before the F and G.
    838 	# The trailing "sleep 3" is just so we catch all the
    839 	# output (otherwise atf_check will be finished while
    840 	# f & g are still sleeping).
    841 
    842 	atf_check -s exit:0 -o inline:'fghX Y\nGF' -e empty \
    843 		${TEST_SH} -c '. ./fgh.def || echo >&2 FAIL
    844 			exec 3>&1
    845 			echo X $( f >&- & sleep 1; g >&- & sleep 1 ; h ) Y
    846 			sleep 3
    847 			exec 4>&1 || echo FD_FAIL
    848 			'
    849 
    850 	# Do the test again to verify it also all works reading stdin
    851 	# (which is a slightly different path through the shell)
    852 	echo '
    853 		. ./fgh.def || echo >&2 FAIL
    854 		exec 3>&1
    855 		echo X $( f >&- & sleep 1; g >&- & sleep 1 ; h ) Y
    856 		sleep 3
    857 		exec 4>&1 || echo FD_FAIL
    858 	' | atf_check -s exit:0 -o inline:'fghX Y\nGF' -e empty ${TEST_SH}
    859 }
    860 
    861 atf_init_test_cases() {
    862 	atf_add_test_case basic_test_method_test
    863 	atf_add_test_case do_input_redirections
    864 	atf_add_test_case do_output_redirections
    865 	atf_add_test_case fd_redirections
    866 	atf_add_test_case local_redirections
    867 	atf_add_test_case incorrect_redirections
    868 	atf_add_test_case named_fd_redirections
    869 	atf_add_test_case redir_here_doc
    870 	atf_add_test_case redir_in_case
    871 	atf_add_test_case subshell_redirections
    872 	atf_add_test_case ulimit_redirection_interaction
    873 	atf_add_test_case validate_fn_redirects
    874 }
    875