1# $NetBSD: t_redir.sh,v 1.10 2018/11/27 09:55:32 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 36atf_test_case basic_test_method_test 37basic_test_method_test_head() 38{ 39 atf_set "descr" "Tests that test method works as expected" 40} 41basic_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 89atf_test_case do_input_redirections 90do_input_redirections_head() 91{ 92 atf_set "descr" "Tests that simple input redirection works" 93} 94do_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 229atf_test_case do_output_redirections 230do_output_redirections_head() 231{ 232 atf_set "descr" "Test Output redirections" 233} 234do_output_redirections_body() 235{ 236nl=' 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 329atf_test_case do_redirect_input_output 330do_redirect_input_output_head() 331{ 332 atf_set "descr" "Test Input+Output (BiDir) redirections" 333} 334do_redirect_input_output_body() 335{ 336nl=' 337' 338 T=0 339 i() { T=$(expr "$T" + 1); } 340 341 rm -f Output 2>/dev/null || : 342 test -f Output && atf_fail "Unable to remove Output file" 343#1 344 i; atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c '<> Output' 345 test -f Output || atf_fail "#$T: Did not make Output file" 346 347#2 348 echo data >Output 2>/dev/null || : 349 i 350 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \ 351 '<>Output' 352 test -f Output || atf_fail "#$T: Removed Output file" 353 test -s Output || atf_fail "#$T: Did not keep data in Output file" 354 test "$(cat Output)" = "data" || 355 atf_fail "#$T: Incorrect Output: Should be 'data' is '$(cat Output)'" 356 357#3 358 rm -f Output 2>/dev/null || : 359 i 360 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \ 361 'echo Hello 1<>Output' 362 test -s Output || atf_fail "#$T: Did not keep non-empty Output file" 363 test "$(cat Output)" = "Hello" || 364 atf_fail "#$T: Incorrect Output: Should be 'Hello' is '$(cat Output)'" 365 366#4 367 printf data >Output 2>/dev/null || : 368 i 369 atf_check -s exit:0 -o inline:'data' -e empty ${TEST_SH} -c \ 370 'cat <>Output' 371 test -f Output || atf_fail "#$T: Removed Output file" 372 test -s Output || atf_fail "#$T: Did not keep data in Output file" 373 test "$(cat Output)" = "data" || 374 atf_fail "#$T: Incorrect Output: Should be 'data' is '$(cat Output)'" 375 376#5 377 echo data >Output 2>/dev/null || : 378 i 379 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \ 380 'echo Hello 1<>Output' 381 test -s Output || atf_fail "#$T: Did not make non-empty Output file" 382 test "$(cat Output)" = "Hello" || 383 atf_fail "#$T: Incorrect Output: Should be 'Hello' is '$(cat Output)'" 384 385#6 386 printf data >Output 2>/dev/null || : 387 i 388 atf_check -s exit:0 -o inline:data -e empty ${TEST_SH} -c \ 389 '{ cat >&3; printf file; } <>Output 3>&1 >&0' 390 test -f Output || atf_fail "#$T: Removed Output file" 391 test -s Output || atf_fail "#$T: Did not keep data in Output file" 392 test "$(cat Output)" = "datafile" || 393 atf_fail \ 394 "#$T: Incorrect Output: Should be 'datafile' is '$(cat Output)'" 395} 396 397atf_test_case fd_redirections 398fd_redirections_head() 399{ 400 atf_set "descr" "Tests redirections to/from specific descriptors" 401} 402fd_redirections_body() 403{ 404 atf_require_prog /bin/echo 405 406 cat <<- 'DONE' > helper.sh 407 f() { 408 /bin/echo nothing "$1" >& "$1" 409 } 410 for n 411 do 412 eval "f $n $n"'> file-$n' 413 done 414 DONE 415 cat <<- 'DONE' > reread.sh 416 f() { 417 (read -r var; echo "${var}") <&"$1" 418 } 419 for n 420 do 421 x=$( eval "f $n $n"'< file-$n' ) 422 test "${x}" = "nothing $n" || echo "$n" 423 done 424 DONE 425 426 validate() 427 { 428 for n 429 do 430 test -e "file-$n" || atf_fail "file-$n not created" 431 C=$(cat file-"$n") 432 test "$C" = "nothing $n" || 433 atf_fail "file-$n contains '$C' not 'nothing $n'" 434 done 435 } 436 437 atf_check -s exit:0 -e empty -o empty \ 438 ${TEST_SH} helper.sh 1 2 3 4 5 6 7 8 9 439 validate 1 2 3 4 5 6 7 8 9 440 atf_check -s exit:0 -e empty -o empty \ 441 ${TEST_SH} reread.sh 3 4 5 6 7 8 9 442 443 L=$(ulimit -n) 444 if [ "$L" -ge 30 ] 445 then 446 atf_check -s exit:0 -e empty -o empty \ 447 ${TEST_SH} helper.sh 10 15 19 20 25 29 448 validate 10 15 19 20 25 29 449 atf_check -s exit:0 -e empty -o empty \ 450 ${TEST_SH} reread.sh 10 15 19 20 25 29 451 fi 452 if [ "$L" -ge 100 ] 453 then 454 atf_check -s exit:0 -e empty -o empty \ 455 ${TEST_SH} helper.sh 32 33 49 50 51 63 64 65 77 88 99 456 validate 32 33 49 50 51 63 64 65 77 88 99 457 atf_check -s exit:0 -e empty -o empty \ 458 ${TEST_SH} reread.sh 32 33 49 50 51 63 64 65 77 88 99 459 fi 460 if [ "$L" -ge 500 ] 461 then 462 atf_check -s exit:0 -e empty -o empty \ 463 ${TEST_SH} helper.sh 100 101 199 200 222 333 444 499 464 validate 100 101 199 200 222 333 444 499 465 atf_check -s exit:0 -e empty -o empty \ 466 ${TEST_SH} reread.sh 100 101 199 200 222 333 444 499 467 fi 468 if [ "$L" -gt 1005 ] 469 then 470 atf_check -s exit:0 -e empty -o empty \ 471 ${TEST_SH} helper.sh 1000 1001 1002 1003 1004 1005 472 validate 1000 1001 1002 1003 1004 1005 473 atf_check -s exit:0 -e empty -o empty \ 474 ${TEST_SH} reread.sh 1000 1001 1002 1003 1004 1005 475 fi 476} 477 478atf_test_case local_redirections 479local_redirections_head() 480{ 481 atf_set "descr" \ 482 "Tests that exec can reassign file descriptors in the shell itself" 483} 484local_redirections_body() 485{ 486 cat <<- 'DONE' > helper.sh 487 for f 488 do 489 eval "exec $f"'> file-$f' 490 done 491 492 for f 493 do 494 printf '%s\n' "Hello $f" >&"$f" 495 done 496 497 for f 498 do 499 eval "exec $f"'>&-' 500 done 501 502 for f 503 do 504 eval "exec $f"'< file-$f' 505 done 506 507 for f 508 do 509 exec <& "$f" 510 read -r var || echo >&2 "No data in file-$f" 511 read -r x && echo >&2 "Too much data in file-${f}: $x" 512 test "${var}" = "Hello $f" || 513 echo >&2 "file-$f contains '${var}' not 'Hello $f'" 514 done 515 DONE 516 517 atf_check -s exit:0 -o empty -e empty \ 518 ${TEST_SH} helper.sh 3 4 5 6 7 8 9 519 520 L=$(ulimit -n) 521 if [ "$L" -ge 30 ] 522 then 523 atf_check -s exit:0 -o empty -e empty \ 524 ${TEST_SH} helper.sh 10 11 13 15 16 19 20 28 29 525 fi 526 if [ "$L" -ge 100 ] 527 then 528 atf_check -s exit:0 -o empty -e empty \ 529 ${TEST_SH} helper.sh 30 31 32 63 64 65 77 88 99 530 fi 531 if [ "$L" -ge 500 ] 532 then 533 atf_check -s exit:0 -o empty -e empty \ 534 ${TEST_SH} helper.sh 100 101 111 199 200 201 222 333 499 535 fi 536 if [ "$L" -ge 1005 ] 537 then 538 atf_check -s exit:0 -o empty -e empty \ 539 ${TEST_SH} helper.sh 1000 1001 1002 1003 1004 1005 540 fi 541} 542 543atf_test_case named_fd_redirections 544named_fd_redirections_head() 545{ 546 atf_set "descr" "Tests redirections to /dev/stdout (etc)" 547 548} 549named_fd_redirections_body() 550{ 551 if test -c /dev/stdout 552 then 553 atf_check -s exit:0 -o inline:'OK\n' -e empty \ 554 ${TEST_SH} -c 'echo OK >/dev/stdout' 555 atf_check -s exit:0 -o inline:'OK\n' -e empty \ 556 ${TEST_SH} -c '/bin/echo OK >/dev/stdout' 557 fi 558 559 if test -c /dev/stdin 560 then 561 atf_require_prog cat 562 563 echo GOOD | atf_check -s exit:0 -o inline:'GOOD\n' -e empty \ 564 ${TEST_SH} -c 'read var </dev/stdin; echo $var' 565 echo GOOD | atf_check -s exit:0 -o inline:'GOOD\n' -e empty \ 566 ${TEST_SH} -c 'cat </dev/stdin' 567 fi 568 569 if test -c /dev/stderr 570 then 571 atf_check -s exit:0 -e inline:'OK\n' -o empty \ 572 ${TEST_SH} -c 'echo OK 2>/dev/stderr >&2' 573 atf_check -s exit:0 -e inline:'OK\n' -o empty \ 574 ${TEST_SH} -c '/bin/echo OK 2>/dev/stderr >&2' 575 fi 576 577 if test -c /dev/fd/8 && test -c /dev/fd/9 578 then 579 atf_check -s exit:0 -o inline:'EIGHT\n' -e empty \ 580 ${TEST_SH} -c 'printf "%s\n" EIGHT 8>&1 >/dev/fd/8 | 581 cat 9<&0 </dev/fd/9' 582 fi 583 584 return 0 585} 586 587atf_test_case redir_in_case 588redir_in_case_head() 589{ 590 atf_set "descr" "Tests that sh(1) allows just redirections " \ 591 "in case statements. (PR bin/48631)" 592} 593redir_in_case_body() 594{ 595 atf_check -s exit:0 -o empty -e empty \ 596 ${TEST_SH} -c 'case x in (whatever) >foo;; esac' 597 598 atf_check -s exit:0 -o empty -e empty \ 599 ${TEST_SH} -c 'case x in (whatever) >foo 2>&1;; esac' 600 601 atf_check -s exit:0 -o empty -e empty \ 602 ${TEST_SH} -c 'case x in (whatever) >foo 2>&1 </dev/null;; esac' 603 604 atf_check -s exit:0 -o empty -e empty \ 605 ${TEST_SH} -c 'case x in (whatever) >${somewhere};; esac' 606} 607 608atf_test_case incorrect_redirections 609incorrect_redirections_head() 610{ 611 atf_set "descr" "Tests that sh(1) correctly ignores non-redirections" 612} 613incorrect_redirections_body() { 614 615 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c 'echo foo>' 616 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c 'read foo<' 617 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c 'echo foo<>' 618 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \ 619 'echo x > '"$nl" 620 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \ 621 'read x < '"$nl" 622 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \ 623 'echo x <> '"$nl" 624 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \ 625 'echo x >< anything' 626 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \ 627 'echo x >>< anything' 628 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \ 629 'echo x >|< anything' 630 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \ 631 'echo x > ; read x < /dev/null || echo bad' 632 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \ 633 'read x < & echo y > /dev/null; wait && echo bad' 634 635 rm -f Output 2>/dev/null || : 636 atf_check -s exit:0 -e empty -o inline:'A Line > Output\n' \ 637 ${TEST_SH} -c 'echo A Line \> Output' 638 test -f Output && atf_file "File 'Output' appeared and should not have" 639 640 rm -f Output 2>/dev/null || : 641 atf_check -s exit:0 -e empty -o empty \ 642 ${TEST_SH} -c 'echo A Line \>> Output' 643 test -f Output || atf_file "File 'Output' not created when it should" 644 test "$(cat Output)" = 'A Line >' || atf_fail \ 645 "Output file contains '$(cat Output)' instead of '"'A Line >'\' 646 647 rm -f Output \> 2>/dev/null || : 648 atf_check -s exit:0 -e empty -o empty \ 649 ${TEST_SH} -c 'echo A Line >\> Output' 650 test -f Output && atf_file "File 'Output' appeared and should not have" 651 test -f '>' || atf_file "File '>' not created when it should" 652 test "$(cat '>')" = 'A Line Output' || atf_fail \ 653 "Output file ('>') contains '$(cat '>')' instead of 'A Line Output'" 654 655 rm -fr OutDir 656 atf-check -s not-exit:0 -o empty -e not-empty \ 657 ${TEST_SH} -c ': > OutDir/stdout; printf foo' 658 atf-check -s not-exit:0 -o empty -e not-empty \ 659 ${TEST_SH} -c ': > OutDir/stdout || printf foo; printf bar' 660 atf-check -s exit:0 -o inline:bar -e not-empty \ 661 ${TEST_SH} -c '> OutDir/stdout; printf bar' 662 atf-check -s exit:0 -o inline:foobar -e not-empty \ 663 ${TEST_SH} -c '> OutDir/stdout || printf foo; printf bar' 664 atf-check -s exit:0 -o inline:bar -e not-empty \ 665 ${TEST_SH} -c 'command : > OutDir/stdout; printf bar' 666 atf-check -s exit:0 -o inline:foobar -e not-empty ${TEST_SH} -c \ 667 'command : > OutDir/stdout || printf foo; printf bar' 668 atf-check -s not-exit:0 -o empty -e not-empty \ 669 ${TEST_SH} -c ': <> OutDir/stdout; printf foo' 670 671 atf-check -s not-exit:0 -o empty -e not-empty \ 672 ${TEST_SH} -c ': >&8 ; printf foo' 673 atf-check -s not-exit:0 -o empty -e not-empty \ 674 ${TEST_SH} -c ': >&8 || printf foo; printf bar' 675 atf-check -s exit:0 -o inline:bar -e not-empty \ 676 ${TEST_SH} -c '>&8 ; printf bar' 677 atf-check -s exit:0 -o inline:foobar -e not-empty \ 678 ${TEST_SH} -c '>&8 || printf foo; printf bar' 679 atf-check -s exit:0 -o inline:bar -e not-empty \ 680 ${TEST_SH} -c 'command : >&7; printf bar' 681 atf-check -s exit:0 -o inline:foobar -e not-empty ${TEST_SH} -c \ 682 'command : >&7 || printf foo; printf bar' 683 684 return 0 685} 686 687# Many more tests in t_here, so here we have just rudimentary checks 688atf_test_case redir_here_doc 689redir_here_doc_head() 690{ 691 atf_set "descr" "Tests that sh(1) correctly processes 'here' doc " \ 692 "input redirections" 693} 694redir_here_doc_body() 695{ 696 # nb: the printf is not executed, it is data 697 cat <<- 'DONE' | 698 cat <<EOF 699 printf '%s\n' 'hello\n' 700 EOF 701 DONE 702 atf_check -s exit:0 -o match:printf -o match:'hello\\n' \ 703 -e empty ${TEST_SH} 704} 705 706atf_test_case subshell_redirections 707subshell_redirections_head() 708{ 709 atf_set "descr" "Tests redirection interactions between shell and " \ 710 "its sub-shell(s)" 711} 712subshell_redirections_body() 713{ 714 atf_require_prog cat 715 716 LIM=$(ulimit -n) 717 718 cat <<- 'DONE' | 719 exec 6>output-file 720 721 ( printf "hello\n" >&6 ) 722 723 exec 8<output-file 724 725 ( read hello <&8 ; test hello = "$hello" || echo >&2 Hello ) 726 727 ( printf "bye-bye\n" >&6 ) 728 729 ( exec 8<&- ) 730 read bye <&8 || echo >&2 "Closed?" 731 echo Bye="$bye" 732 DONE 733 atf_check -s exit:0 -o match:Bye=bye-bye -e empty \ 734 ${TEST_SH} 735 736 cat <<- 'DONE' | 737 for arg in one-4 two-24 three-14 738 do 739 fd=${arg#*-} 740 file=${arg%-*} 741 eval "exec ${fd}>${file}" 742 done 743 744 for arg in one-5 two-7 three-19 745 do 746 fd=${arg#*-} 747 file=${arg%-*} 748 eval "exec ${fd}<${file}" 749 done 750 751 ( 752 echo line-1 >&4 753 echo line-2 >&24 754 echo line-3 >&14 755 echo go 756 ) | ( 757 read go 758 read x <&5 759 read y <&7 760 read z <&19 761 762 printf "%s\n" "${x}" "${y}" "${z}" 763 ) 764 DONE 765 atf_check -s exit:0 -o inline:'line-1\nline-2\nline-3\n' \ 766 -e empty ${TEST_SH} 767 768 cat <<- 'DONE' | 769 for arg in one-4-5 two-6-7 three-8-9 four-11-10 five-3-12 770 do 771 ofd=${arg##*-} 772 file=${arg%-*} 773 ifd=${file#*-} 774 file=${file%-*} 775 eval "exec ${ofd}>${file}" 776 eval "exec ${ifd}<${file}" 777 done 778 779 ( ( ( echo line-1 >& 13 ) 13>&12 ) 12>&5 ) >stdout 2>errout 780 ( ( ( echo line-2 >& 4) 13>&12 ) 4>&7 ) >>stdout 2>>errout 781 ( ( ( echo line-3 >& 6) 8>&1 6>&11 >&12) 11>&9 >&7 ) >>stdout 782 783 ( ( ( cat <&13 >&12 ) 13<&8 12>&10 ) 10>&1 8<&6 ) 6<&4 784 ( ( ( cat <&4 ) <&4 6<&8 8<&11 ) 785 <&4 4<&6 6<&8 8<&11 ) <&4 4<&6 6<&8 8<&11 11<&3 786 ( ( ( cat <&7 >&1 ) 7<&6 >&10 ) 10>&2 6<&8 ) 2>&1 787 DONE 788 atf_check -s exit:0 -o inline:'line-1\nline-2\nline-3\n' \ 789 -e empty ${TEST_SH} 790} 791 792atf_test_case ulimit_redirection_interaction 793ulimit_redirection_interaction_head() 794{ 795 atf_set "descr" "Tests interactions between redirect and ulimit -n " 796} 797ulimit_redirection_interaction_body() 798{ 799 atf_require_prog ls 800 801 cat <<- 'DONE' > helper.sh 802 oLIM=$(ulimit -n) 803 HRD=$(ulimit -H -n) 804 test "${oLIM}" -lt "${HRD}" && ulimit -n "${HRD}" 805 LIM=$(ulimit -n) 806 807 FDs= 808 LFD=-1 809 while [ ${LIM} -gt 16 ] 810 do 811 FD=$(( ${LIM} - 1 )) 812 if [ "${FD}" -eq "${LFD}" ]; then 813 echo >&2 "Infinite loop... (busted $(( )) ??)" 814 exit 1 815 fi 816 LFD="${FD}" 817 818 eval "exec ${FD}"'> /dev/null' 819 FDs="${FD}${FDs:+ }${FDs}" 820 821 ( 822 FD=$(( ${LIM} + 1 )) 823 eval "exec ${FD}"'> /dev/null' 824 echo "Reached unreachable command" 825 ) 2>/dev/null && echo >&2 "Opened beyond limit!" 826 827 (eval 'ls 2>&1 3>&1 4>&1 5>&1 '"${FD}"'>&1') >&"${FD}" 828 829 LIM=$(( ${LIM} / 2 )) 830 ulimit -S -n "${LIM}" 831 done 832 833 # Even though ulimit has been reduced, open fds should work 834 for FD in ${FDs} 835 do 836 echo ${FD} in ${FDs} >&"${FD}" || exit 1 837 done 838 839 ulimit -S -n "${oLIM}" 840 841 # maybe more later... 842 843 DONE 844 845 atf_check -s exit:0 -o empty -e empty ${TEST_SH} helper.sh 846} 847 848atf_test_case validate_fn_redirects 849validate_fn_redirects_head() 850{ 851 # These test cases inspired by PR bin/48875 and the sh 852 # changes that were required to fix it. 853 854 atf_set "descr" "Tests various redirections applied to functions " \ 855 "See PR bin/48875" 856} 857validate_fn_redirects_body() 858{ 859 cat <<- 'DONE' > f-def 860 f() { 861 printf '%s\n' In-Func 862 } 863 DONE 864 865 atf_check -s exit:0 -o inline:'In-Func\nsuccess1\n' -e empty \ 866 ${TEST_SH} -c ". ./f-def; f ; printf '%s\n' success1" 867 atf_check -s exit:0 -o inline:'success2\n' -e empty \ 868 ${TEST_SH} -c ". ./f-def; f >/dev/null; printf '%s\n' success2" 869 atf_check -s exit:0 -o inline:'success3\n' -e empty \ 870 ${TEST_SH} -c ". ./f-def; f >&- ; printf '%s\n' success3" 871 atf_check -s exit:0 -o inline:'In-Func\nsuccess4\n' -e empty \ 872 ${TEST_SH} -c ". ./f-def; f & wait; printf '%s\n' success4" 873 atf_check -s exit:0 -o inline:'success5\n' -e empty \ 874 ${TEST_SH} -c ". ./f-def; f >&- & wait; printf '%s\n' success5" 875 atf_check -s exit:0 -o inline:'In-Func\nIn-Func\nsuccess6\n' -e empty \ 876 ${TEST_SH} -c ". ./f-def; f;f; printf '%s\n' success6" 877 atf_check -s exit:0 -o inline:'In-Func\nIn-Func\nsuccess7\n' -e empty \ 878 ${TEST_SH} -c ". ./f-def; { f;f;}; printf '%s\n' success7" 879 atf_check -s exit:0 -o inline:'In-Func\nIn-Func\nsuccess8\n' -e empty \ 880 ${TEST_SH} -c ". ./f-def; { f;f;}& wait; printf '%s\n' success8" 881 atf_check -s exit:0 -o inline:'In-Func\nsuccess9\n' -e empty \ 882 ${TEST_SH} -c \ 883 ". ./f-def; { f>/dev/null;f;}& wait; printf '%s\n' success9" 884 atf_check -s exit:0 -o inline:'In-Func\nsuccess10\n' -e empty \ 885 ${TEST_SH} -c \ 886 ". ./f-def; { f;f>/dev/null;}& wait; printf '%s\n' success10" 887 888 # This one tests the issue etcupdate had with the original 48875 fix 889 atf_check -s exit:0 -o inline:'Func a\nFunc b\nFunc c\n' -e empty \ 890 ${TEST_SH} -c ' 891 f() { 892 echo Func "$1" 893 } 894 exec 3<&0 4>&1 895 ( echo x-a; echo y-b; echo z-c ) | 896 while read A 897 do 898 B=${A#?-} 899 f "$B" <&3 >&4 900 done >&2' 901 902 # And this tests a similar condition with that same fix 903 cat <<- 'DONE' >Script 904 f() { 905 printf '%s' " hello $1" 906 } 907 exec 3>&1 908 echo $( for i in a b c 909 do printf '%s' @$i; f $i >&3; done >foo 910 ) 911 printf '%s\n' foo=$(cat foo) 912 DONE 913 atf_check -s exit:0 -e empty \ 914 -o inline:' hello a hello b hello c\nfoo=@a@b@c\n' \ 915 ${TEST_SH} Script 916 917 # Tests with sh reading stdin, which is not quite the same internal 918 # mechanism. 919 echo ". ./f-def || echo >&2 FAIL 920 f 921 printf '%s\n' stdin1 922 "| atf_check -s exit:0 -o inline:'In-Func\nstdin1\n' -e empty ${TEST_SH} 923 924 echo ' 925 . ./f-def || echo >&2 FAIL 926 f >&- 927 printf "%s\n" stdin2 928 ' | atf_check -s exit:0 -o inline:'stdin2\n' -e empty ${TEST_SH} 929 930 cat <<- 'DONE' > fgh.def 931 f() { 932 echo -n f >&3 933 sleep 4 934 echo -n F >&3 935 } 936 g() { 937 echo -n g >&3 938 sleep 2 939 echo -n G >&3 940 } 941 h() { 942 echo -n h >&3 943 } 944 DONE 945 946 atf_check -s exit:0 -o inline:'fFgGh' -e empty \ 947 ${TEST_SH} -c '. ./fgh.def || echo >&2 FAIL 948 exec 3>&1 949 f; g; h' 950 951 atf_check -s exit:0 -o inline:'fghGF' -e empty \ 952 ${TEST_SH} -c '. ./fgh.def || echo >&2 FAIL 953 exec 3>&1 954 f & sleep 1; g & sleep 1; h; wait' 955 956 atf_check -s exit:0 -o inline:'fFgGhX Y\n' -e empty \ 957 ${TEST_SH} -c '. ./fgh.def || echo >&2 FAIL 958 exec 3>&1 959 echo X $( f ; g ; h ) Y' 960 961 # This one is the real test for PR bin/48875. If the 962 # cmdsub does not complete before f g (and h) exit, 963 # then the 'F' & 'G' will precede 'X Y' in the output. 964 # If the cmdsub finishes while f & g are still running, 965 # then the X Y will appear before the F and G. 966 # The trailing "sleep 3" is just so we catch all the 967 # output (otherwise atf_check will be finished while 968 # f & g are still sleeping). 969 970 atf_check -s exit:0 -o inline:'fghX Y\nGF' -e empty \ 971 ${TEST_SH} -c '. ./fgh.def || echo >&2 FAIL 972 exec 3>&1 973 echo X $( f >&- & sleep 1; g >&- & sleep 1 ; h ) Y 974 sleep 3 975 exec 4>&1 || echo FD_FAIL 976 ' 977 978 # Do the test again to verify it also all works reading stdin 979 # (which is a slightly different path through the shell) 980 echo ' 981 . ./fgh.def || echo >&2 FAIL 982 exec 3>&1 983 echo X $( f >&- & sleep 1; g >&- & sleep 1 ; h ) Y 984 sleep 3 985 exec 4>&1 || echo FD_FAIL 986 ' | atf_check -s exit:0 -o inline:'fghX Y\nGF' -e empty ${TEST_SH} 987} 988 989atf_init_test_cases() { 990 atf_add_test_case basic_test_method_test 991 atf_add_test_case do_input_redirections 992 atf_add_test_case do_output_redirections 993 atf_add_test_case do_redirect_input_output 994 atf_add_test_case fd_redirections 995 atf_add_test_case local_redirections 996 atf_add_test_case incorrect_redirections 997 atf_add_test_case named_fd_redirections 998 atf_add_test_case redir_here_doc 999 atf_add_test_case redir_in_case 1000 atf_add_test_case subshell_redirections 1001 atf_add_test_case ulimit_redirection_interaction 1002 atf_add_test_case validate_fn_redirects 1003} 1004