1# $NetBSD: t_redir.sh,v 1.14 2021/11/21 20:50:35 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 atf_fail 'empty piped input' 47 cat <<- 'DONE' | 48 DONE 49 atf_check -s exit:0 -o match:0 -e empty ${TEST_SH} -c 'wc -l' || 50 atf_fail 'empty piped input line count' 51 52 cat <<- 'DONE' | 53 echo hello 54 DONE 55 atf_check -s exit:0 -o match:hello -e empty ${TEST_SH} || 56 atf_fail 'piped hello' 57 cat <<- 'DONE' | 58 echo hello 59 DONE 60 atf_check -s exit:0 -o match:1 -e empty ${TEST_SH} -c 'wc -l' || 61 atf_fail 'piped hello line count' 62 63 cat <<- 'DONE' | 64 echo hello\ 65 world 66 DONE 67 atf_check -s exit:0 -o match:helloworld -e empty ${TEST_SH} || 68 atf_fail 'piped hello world' 69 cat <<- 'DONE' | 70 echo hello\ 71 world 72 DONE 73 atf_check -s exit:0 -o match:2 -e empty ${TEST_SH} -c 'wc -l' || 74 atf_fail 'piped hello world line check' 75 76 printf '%s\n%s\n%s\n' Line1 Line2 Line3 > File 77 atf_check -s exit:0 -o inline:'Line1\nLine2\nLine3\n' -e empty \ 78 ${TEST_SH} -c 'cat File' 79 80 cat <<- 'DONE' | 81 set -- X "" '' Y 82 echo ARGS="${#}" 83 echo '' -$1- -$2- -$3- -$4- 84 cat <<EOF 85 X=$1 86 EOF 87 cat <<\EOF 88 Y=$4 89 EOF 90 DONE 91 atf_check -s exit:0 -o match:ARGS=4 -o match:'-X- -- -- -Y-' \ 92 -o match:X=X -o match:'Y=\$4' -e empty ${TEST_SH} || 93 atf_fail "complex piped input" 94 95 cat <<- 'DONE' | 96 echo expect to see a non-detected failure here 97 DONE 98 atf_check -s exit:1 -o empty -e empty ${TEST_SH} && 99 atf_fail "Failed to fail as expected" 100 101 return 0 102} 103 104atf_test_case do_input_redirections 105do_input_redirections_head() 106{ 107 atf_set "descr" "Tests that simple input redirection works" 108} 109do_input_redirections_body() 110{ 111 printf '%s\n%s\n%s\nEND\n' 'First Line' 'Second Line' 'Line 3' >File 112 113 atf_check -s exit:0 -e empty \ 114 -o inline:'First Line\nSecond Line\nLine 3\nEND\n' \ 115 ${TEST_SH} -c 'cat < File' 116 atf_check -s exit:0 -e empty \ 117 -o inline:'First Line\nSecond Line\nLine 3\nEND\n' \ 118 ${TEST_SH} -c 'cat <File' 119 atf_check -s exit:0 -e empty \ 120 -o inline:'First Line\nSecond Line\nLine 3\nEND\n' \ 121 ${TEST_SH} -c 'cat< File' 122 atf_check -s exit:0 -e empty \ 123 -o inline:'First Line\nSecond Line\nLine 3\nEND\n' \ 124 ${TEST_SH} -c 'cat < "File"' 125 atf_check -s exit:0 -e empty \ 126 -o inline:'First Line\nSecond Line\nLine 3\nEND\n' \ 127 ${TEST_SH} -c '< File cat' 128 129 ln File wc 130 atf_check -s exit:0 -e empty \ 131 -o inline:'First Line\nSecond Line\nLine 3\nEND\n' \ 132 ${TEST_SH} -c '< wc cat' 133 134 mv wc cat 135 atf_check -s exit:0 -e empty -o match:4 \ 136 ${TEST_SH} -c '< cat wc' 137 138 139 cat <<- 'EOF' | 140 for l in 1 2 3; do 141 read line < File 142 echo "$line" 143 done 144 EOF 145 atf_check -s exit:0 -e empty \ 146 -o inline:'First Line\nFirst Line\nFirst Line\n' \ 147 ${TEST_SH} || 148 atf_fail 'loop rereading first line' 149 150 cat <<- 'EOF' | 151 for l in 1 2 3; do 152 read line 153 echo "$line" 154 done <File 155 EOF 156 atf_check -s exit:0 -e empty \ 157 -o inline:'First Line\nSecond Line\nLine 3\n' \ 158 ${TEST_SH} || 159 atf_fail 'loop reading file' 160 161 cat <<- 'EOF' | 162 for l in 1 2 3; do 163 read line < File 164 echo "$line" 165 done <File 166 EOF 167 atf_check -s exit:0 -e empty \ 168 -o inline:'First Line\nFirst Line\nFirst Line\n' \ 169 ${TEST_SH} || 170 atf_fail 'double redirect' 171 172 cat <<- 'EOF' | 173 line= 174 while [ "$line" != END ]; do 175 read line || exit 1 176 echo "$line" 177 done <File 178 EOF 179 atf_check -s exit:0 -e empty \ 180 -o inline:'First Line\nSecond Line\nLine 3\nEND\n' \ 181 ${TEST_SH} || 182 atf_fail 'read and test content' 183 184 cat <<- 'EOF' | 185 while :; do 186 read line || exit 0 187 echo "$line" 188 done <File 189 EOF 190 atf_check -s exit:0 -e empty \ 191 -o inline:'First Line\nSecond Line\nLine 3\nEND\n' \ 192 ${TEST_SH} || 193 atf_fail 'read and test status' 194 195 cat <<- 'EOF' | 196 l='' 197 while read line < File 198 do 199 echo "$line" 200 l="${l}x" 201 [ ${#l} -ge 3 ] && break 202 done 203 echo DONE 204 EOF 205 atf_check -s exit:0 -e empty \ 206 -o inline:'First Line\nFirst Line\nFirst Line\nDONE\n' \ 207 ${TEST_SH} || 208 atf_fail 'read 3 lines' 209 210 cat <<- 'EOF' | 211 while read line 212 do 213 echo "$line" 214 done <File 215 echo DONE 216 EOF 217 atf_check -s exit:0 -e empty \ 218 -o inline:'First Line\nSecond Line\nLine 3\nEND\nDONE\n' \ 219 ${TEST_SH} || 220 atf_fail 'read to EOF' 221 222 cat <<- 'EOF' | 223 l='' 224 while read line 225 do 226 echo "$line" 227 l="${l}x" 228 [ ${#l} -ge 3 ] && break 229 done <File 230 echo DONE 231 EOF 232 atf_check -s exit:0 -e empty \ 233 -o inline:'First Line\nSecond Line\nLine 3\nDONE\n' \ 234 ${TEST_SH} || 235 atf_fail 'read 3 and break' 236 237 cat <<- 'EOF' | 238 l='' 239 while read line1 <File 240 do 241 read line2 242 echo "$line1":"$line2" 243 l="${l}x" 244 [ ${#l} -ge 2 ] && break 245 done <File 246 echo DONE 247 EOF 248 atf_check -s exit:0 -e empty \ 249 -o inline:'First Line:First Line\nFirst Line:Second Line\nDONE\n' \ 250 ${TEST_SH} || 251 atf_fail 'read and read again' 252} 253 254atf_test_case do_output_redirections 255do_output_redirections_head() 256{ 257 atf_set "descr" "Test Output redirections" 258} 259do_output_redirections_body() 260{ 261nl=' 262' 263 T=0 264 i() { T=$(expr "$T" + 1); } 265 266 rm -f Output 2>/dev/null || : 267 test -f Output && atf_fail "Unable to remove Output file" 268#1 269 i; atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c '> Output' 270 test -f Output || atf_fail "#$T: Did not make Output file" 271#2 272 rm -f Output 2>/dev/null || : 273 i; atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c '>> Output' 274 test -f Output || atf_fail "#$T: Did not make Output file" 275#3 276 rm -f Output 2>/dev/null || : 277 i; atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c '>| Output' 278 test -f Output || atf_fail "#$T: Did not make Output file" 279 280#4 281 rm -f Output 2>/dev/null || : 282 i 283 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c 'echo Hello >Output' 284 test -s Output || atf_fail "#$T: Did not make non-empty Output file" 285 test "$(cat Output)" = "Hello" || 286 atf_fail "#$T: Incorrect Output: Should be 'Hello' is '$(cat Output)'" 287#5 288 i 289 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c 'echo Hello>!Output' 290 test -s Output || atf_fail "#$T: Did not make non-empty Output file" 291 test "$(cat Output)" = "Hello" || 292 atf_fail "#$T: Incorrect Output: Should be 'Hello' is '$(cat Output)'" 293#6 294 i 295 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c 'echo Bye >>Output' 296 test -s Output || atf_fail "#$T: Removed Output file" 297 test "$(cat Output)" = "Hello${nl}Bye" || atf_fail \ 298 "#$T: Incorrect Output: Should be 'Hello\\nBye' is '$(cat Output)'" 299#7 300 i; atf_check -s exit:0 -o inline:'line 1\nline 2\n' -e empty \ 301 ${TEST_SH} -c \ 302 'echo line 1 > Output; echo line 2 >> Output; cat Output' 303 test "$(cat Output)" = "line 1${nl}line 2" || atf_fail \ 304 "#$T: Incorrect Output: Should be 'line 1\\nline 2' is '$(cat Output)'" 305#8 306 i; atf_check -s exit:0 -o inline:'line 2\n' -e empty \ 307 ${TEST_SH} -c 'echo line 1 > Output; echo line 2' 308 test "$(cat Output)" = "line 1" || atf_fail \ 309 "#$T: Incorrect Output: Should be 'line 1' is '$(cat Output)'" 310#9 311 i; atf_check -s exit:0 -o empty -e empty \ 312 ${TEST_SH} -c '(echo line 1; echo line 2 > Out2) > Out1' 313 test "$(cat Out1)" = "line 1" || atf_fail \ 314 "#$T: Incorrect Out1: Should be 'line 1' is '$(cat Out1)'" 315 test "$(cat Out2)" = "line 2" || atf_fail \ 316 "#$T: Incorrect Out2: Should be 'line 2' is '$(cat Out2)'" 317#10 318 i; atf_check -s exit:0 -o empty -e empty \ 319 ${TEST_SH} -c '{ echo line 1; echo line 2 > Out2;} > Out1' 320 test "$(cat Out1)" = "line 1" || atf_fail \ 321 "#$T: Incorrect Out1: Should be 'line 1' is '$(cat Out1)'" 322 test "$(cat Out2)" = "line 2" || atf_fail \ 323 "#$T: Incorrect Out2: Should be 'line 2' is '$(cat Out2)'" 324#11 325 i; rm -f Out1 Out2 2>/dev/null || : 326 cat <<- 'EOF' | 327 for arg in 'line 1' 'line 2' 'line 3' 328 do 329 echo "$arg" 330 echo "$arg" > Out1 331 done > Out2 332 EOF 333 atf_check -s exit:0 -o empty -e empty ${TEST_SH} || 334 atf_fail "#$T: not empty/empty/0" 335 test "$(cat Out1)" = "line 3" || atf_fail \ 336 "#$T: Incorrect Out1: Should be 'line 3' is '$(cat Out1)'" 337 test "$(cat Out2)" = "line 1${nl}line 2${nl}line 3" || atf_fail \ 338 "#$T: Incorrect Out2: Should be 'line 1\\nline 2\\nline 3' is '$(cat Out2)'" 339#12 340 i; rm -f Out1 Out2 2>/dev/null || : 341 cat <<- 'EOF' | 342 for arg in 'line 1' 'line 2' 'line 3' 343 do 344 echo "$arg" 345 echo "$arg" >> Out1 346 done > Out2 347 EOF 348 atf_check -s exit:0 -o empty -e empty ${TEST_SH} || 349 atf_fail "#$T: not empty/empty/0" 350 test "$(cat Out1)" = "line 1${nl}line 2${nl}line 3" || atf_fail \ 351 "#$T: Incorrect Out1: Should be 'line 1\\nline 2\\nline 3' is '$(cat Out1)'" 352 test "$(cat Out2)" = "line 1${nl}line 2${nl}line 3" || atf_fail \ 353 "#$T: Incorrect Out2: Should be 'line 1\\nline 2\\nline 3' is '$(cat Out2)'" 354} 355 356atf_test_case do_redirect_input_output 357do_redirect_input_output_head() 358{ 359 atf_set "descr" "Test Input+Output (BiDir) redirections" 360} 361do_redirect_input_output_body() 362{ 363nl=' 364' 365 T=0 366 i() { T=$(expr "$T" + 1); } 367 368 rm -f Output 2>/dev/null || : 369 test -f Output && atf_fail "Unable to remove Output file" 370#1 371 i; atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c '<> Output' 372 test -f Output || atf_fail "#$T: Did not make Output file" 373 374#2 375 echo data >Output 2>/dev/null || : 376 i 377 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \ 378 '<>Output' 379 test -f Output || atf_fail "#$T: Removed Output file" 380 test -s Output || atf_fail "#$T: Did not keep data in Output file" 381 test "$(cat Output)" = "data" || 382 atf_fail "#$T: Incorrect Output: Should be 'data' is '$(cat Output)'" 383 384#3 385 rm -f Output 2>/dev/null || : 386 i 387 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \ 388 'echo Hello 1<>Output' 389 test -s Output || atf_fail "#$T: Did not keep non-empty Output file" 390 test "$(cat Output)" = "Hello" || 391 atf_fail "#$T: Incorrect Output: Should be 'Hello' is '$(cat Output)'" 392 393#4 394 printf data >Output 2>/dev/null || : 395 i 396 atf_check -s exit:0 -o inline:'data' -e empty ${TEST_SH} -c \ 397 'cat <>Output' 398 test -f Output || atf_fail "#$T: Removed Output file" 399 test -s Output || atf_fail "#$T: Did not keep data in Output file" 400 test "$(cat Output)" = "data" || 401 atf_fail "#$T: Incorrect Output: Should be 'data' is '$(cat Output)'" 402 403#5 404 echo data >Output 2>/dev/null || : 405 i 406 atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \ 407 'echo Hello 1<>Output' 408 test -s Output || atf_fail "#$T: Did not make non-empty Output file" 409 test "$(cat Output)" = "Hello" || 410 atf_fail "#$T: Incorrect Output: Should be 'Hello' is '$(cat Output)'" 411 412#6 413 printf data >Output 2>/dev/null || : 414 i 415 atf_check -s exit:0 -o inline:data -e empty ${TEST_SH} -c \ 416 '{ cat >&3; printf file; } <>Output 3>&1 >&0' 417 test -f Output || atf_fail "#$T: Removed Output file" 418 test -s Output || atf_fail "#$T: Did not keep data in Output file" 419 test "$(cat Output)" = "datafile" || 420 atf_fail \ 421 "#$T: Incorrect Output: Should be 'datafile' is '$(cat Output)'" 422} 423 424atf_test_case fd_redirections 425fd_redirections_head() 426{ 427 atf_set "descr" "Tests redirections to/from specific descriptors" 428} 429fd_redirections_body() 430{ 431 atf_require_prog /bin/echo 432 433 cat <<- 'DONE' > helper.sh 434 f() { 435 /bin/echo nothing "$1" >& "$1" 436 } 437 for n 438 do 439 eval "f $n $n"'> file-$n' 440 done 441 DONE 442 cat <<- 'DONE' > reread.sh 443 f() { 444 (read -r var; echo "${var}") <&"$1" 445 } 446 for n 447 do 448 x=$( eval "f $n $n"'< file-$n' ) 449 test "${x}" = "nothing $n" || echo "$n" 450 done 451 DONE 452 453 validate() 454 { 455 for n 456 do 457 test -e "file-$n" || atf_fail "file-$n not created" 458 C=$(cat file-"$n") 459 test "$C" = "nothing $n" || 460 atf_fail "file-$n contains '$C' not 'nothing $n'" 461 done 462 } 463 464 atf_check -s exit:0 -e empty -o empty \ 465 ${TEST_SH} helper.sh 1 2 3 4 5 6 7 8 9 466 validate 1 2 3 4 5 6 7 8 9 467 atf_check -s exit:0 -e empty -o empty \ 468 ${TEST_SH} reread.sh 3 4 5 6 7 8 9 469 470 L=$(ulimit -n) 471 if [ "$L" -ge 30 ] 472 then 473 atf_check -s exit:0 -e empty -o empty \ 474 ${TEST_SH} helper.sh 10 15 19 20 25 29 475 validate 10 15 19 20 25 29 476 atf_check -s exit:0 -e empty -o empty \ 477 ${TEST_SH} reread.sh 10 15 19 20 25 29 478 fi 479 if [ "$L" -ge 100 ] 480 then 481 atf_check -s exit:0 -e empty -o empty \ 482 ${TEST_SH} helper.sh 32 33 49 50 51 63 64 65 77 88 99 483 validate 32 33 49 50 51 63 64 65 77 88 99 484 atf_check -s exit:0 -e empty -o empty \ 485 ${TEST_SH} reread.sh 32 33 49 50 51 63 64 65 77 88 99 486 fi 487 if [ "$L" -ge 500 ] 488 then 489 atf_check -s exit:0 -e empty -o empty \ 490 ${TEST_SH} helper.sh 100 101 199 200 222 333 444 499 491 validate 100 101 199 200 222 333 444 499 492 atf_check -s exit:0 -e empty -o empty \ 493 ${TEST_SH} reread.sh 100 101 199 200 222 333 444 499 494 fi 495 if [ "$L" -gt 1005 ] 496 then 497 atf_check -s exit:0 -e empty -o empty \ 498 ${TEST_SH} helper.sh 1000 1001 1002 1003 1004 1005 499 validate 1000 1001 1002 1003 1004 1005 500 atf_check -s exit:0 -e empty -o empty \ 501 ${TEST_SH} reread.sh 1000 1001 1002 1003 1004 1005 502 fi 503} 504 505atf_test_case local_redirections 506local_redirections_head() 507{ 508 atf_set "descr" \ 509 "Tests that exec can reassign file descriptors in the shell itself" 510} 511local_redirections_body() 512{ 513 cat <<- 'DONE' > helper.sh 514 for f 515 do 516 eval "exec $f"'> file-$f' 517 done 518 519 for f 520 do 521 printf '%s\n' "Hello $f" >&"$f" 522 done 523 524 for f 525 do 526 eval "exec $f"'>&-' 527 done 528 529 for f 530 do 531 eval "exec $f"'< file-$f' 532 done 533 534 for f 535 do 536 exec <& "$f" 537 read -r var || echo >&2 "No data in file-$f" 538 read -r x && echo >&2 "Too much data in file-${f}: $x" 539 test "${var}" = "Hello $f" || 540 echo >&2 "file-$f contains '${var}' not 'Hello $f'" 541 done 542 DONE 543 544 atf_check -s exit:0 -o empty -e empty \ 545 ${TEST_SH} helper.sh 3 4 5 6 7 8 9 546 547 L=$(ulimit -n) 548 if [ "$L" -ge 30 ] 549 then 550 atf_check -s exit:0 -o empty -e empty \ 551 ${TEST_SH} helper.sh 10 11 13 15 16 19 20 28 29 552 fi 553 if [ "$L" -ge 100 ] 554 then 555 atf_check -s exit:0 -o empty -e empty \ 556 ${TEST_SH} helper.sh 30 31 32 63 64 65 77 88 99 557 fi 558 if [ "$L" -ge 500 ] 559 then 560 atf_check -s exit:0 -o empty -e empty \ 561 ${TEST_SH} helper.sh 100 101 111 199 200 201 222 333 499 562 fi 563 if [ "$L" -ge 1005 ] 564 then 565 atf_check -s exit:0 -o empty -e empty \ 566 ${TEST_SH} helper.sh 1000 1001 1002 1003 1004 1005 567 fi 568} 569 570atf_test_case named_fd_redirections 571named_fd_redirections_head() 572{ 573 atf_set "descr" "Tests redirections to /dev/stdout (etc)" 574 575} 576named_fd_redirections_body() 577{ 578 if test -c /dev/stdout 579 then 580 atf_check -s exit:0 -o inline:'OK\n' -e empty \ 581 ${TEST_SH} -c 'echo OK >/dev/stdout' 582 atf_check -s exit:0 -o inline:'OK\n' -e empty \ 583 ${TEST_SH} -c '/bin/echo OK >/dev/stdout' 584 fi 585 586 if test -c /dev/stdin 587 then 588 atf_require_prog cat 589 590 echo GOOD | atf_check -s exit:0 -o inline:'GOOD\n' -e empty \ 591 ${TEST_SH} -c 'read var </dev/stdin; echo $var' || 592 atf_fail "/dev/stdin test 1" 593 echo GOOD | atf_check -s exit:0 -o inline:'GOOD\n' -e empty \ 594 ${TEST_SH} -c 'cat </dev/stdin' || 595 atf_fail "/dev/stdin test 2" 596 fi 597 598 if test -c /dev/stderr 599 then 600 atf_check -s exit:0 -e inline:'OK\n' -o empty \ 601 ${TEST_SH} -c 'echo OK 2>/dev/stderr >&2' 602 atf_check -s exit:0 -e inline:'OK\n' -o empty \ 603 ${TEST_SH} -c '/bin/echo OK 2>/dev/stderr >&2' 604 fi 605 606 if test -c /dev/fd/8 && test -c /dev/fd/9 607 then 608 atf_check -s exit:0 -o inline:'EIGHT\n' -e empty \ 609 ${TEST_SH} -c 'printf "%s\n" EIGHT 8>&1 >/dev/fd/8 | 610 cat 9<&0 </dev/fd/9' 611 fi 612 613 return 0 614} 615 616atf_test_case redir_in_case 617redir_in_case_head() 618{ 619 atf_set "descr" "Tests that sh(1) allows just redirections " \ 620 "in case statements. (PR bin/48631)" 621} 622redir_in_case_body() 623{ 624 atf_check -s exit:0 -o empty -e empty \ 625 ${TEST_SH} -c 'case x in (whatever) >foo;; esac' 626 627 atf_check -s exit:0 -o empty -e empty \ 628 ${TEST_SH} -c 'case x in (whatever) >foo 2>&1;; esac' 629 630 atf_check -s exit:0 -o empty -e empty \ 631 ${TEST_SH} -c 'case x in (whatever) >foo 2>&1 </dev/null;; esac' 632 633 atf_check -s exit:0 -o empty -e empty \ 634 ${TEST_SH} -c 'case x in (whatever) >${somewhere};; esac' 635} 636 637atf_test_case incorrect_redirections 638incorrect_redirections_head() 639{ 640 atf_set "descr" "Tests that sh(1) correctly ignores non-redirections" 641} 642incorrect_redirections_body() { 643 644 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c 'echo foo>' 645 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c 'read foo<' 646 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c 'echo foo<>' 647 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \ 648 'echo x > '"$nl" 649 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \ 650 'read x < '"$nl" 651 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \ 652 'echo x <> '"$nl" 653 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \ 654 'echo x >< anything' 655 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \ 656 'echo x >>< anything' 657 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \ 658 'echo x >|< anything' 659 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \ 660 'echo x > ; read x < /dev/null || echo bad' 661 atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \ 662 'read x < & echo y > /dev/null; wait && echo bad' 663 664 rm -f Output 2>/dev/null || : 665 atf_check -s exit:0 -e empty -o inline:'A Line > Output\n' \ 666 ${TEST_SH} -c 'echo A Line \> Output' 667 test -f Output && atf_file "File 'Output' appeared and should not have" 668 669 rm -f Output 2>/dev/null || : 670 atf_check -s exit:0 -e empty -o empty \ 671 ${TEST_SH} -c 'echo A Line \>> Output' 672 test -f Output || atf_file "File 'Output' not created when it should" 673 test "$(cat Output)" = 'A Line >' || atf_fail \ 674 "Output file contains '$(cat Output)' instead of '"'A Line >'\' 675 676 rm -f Output \> 2>/dev/null || : 677 atf_check -s exit:0 -e empty -o empty \ 678 ${TEST_SH} -c 'echo A Line >\> Output' 679 test -f Output && atf_file "File 'Output' appeared and should not have" 680 test -f '>' || atf_file "File '>' not created when it should" 681 test "$(cat '>')" = 'A Line Output' || atf_fail \ 682 "Output file ('>') contains '$(cat '>')' instead of 'A Line Output'" 683 684 rm -fr OutDir 685 atf-check -s not-exit:0 -o empty -e not-empty \ 686 ${TEST_SH} -c ': > OutDir/stdout; printf foo' 687 atf-check -s not-exit:0 -o empty -e not-empty \ 688 ${TEST_SH} -c ': > OutDir/stdout || printf foo; printf bar' 689 atf-check -s exit:0 -o inline:bar -e not-empty \ 690 ${TEST_SH} -c '> OutDir/stdout; printf bar' 691 atf-check -s exit:0 -o inline:foobar -e not-empty \ 692 ${TEST_SH} -c '> OutDir/stdout || printf foo; printf bar' 693 atf-check -s exit:0 -o inline:bar -e not-empty \ 694 ${TEST_SH} -c 'command : > OutDir/stdout; printf bar' 695 atf-check -s exit:0 -o inline:foobar -e not-empty ${TEST_SH} -c \ 696 'command : > OutDir/stdout || printf foo; printf bar' 697 atf-check -s not-exit:0 -o empty -e not-empty \ 698 ${TEST_SH} -c ': <> OutDir/stdout; printf foo' 699 700 atf-check -s not-exit:0 -o empty -e not-empty \ 701 ${TEST_SH} -c ': >&8 ; printf foo' 702 atf-check -s not-exit:0 -o empty -e not-empty \ 703 ${TEST_SH} -c ': >&8 || printf foo; printf bar' 704 atf-check -s exit:0 -o inline:bar -e not-empty \ 705 ${TEST_SH} -c '>&8 ; printf bar' 706 atf-check -s exit:0 -o inline:foobar -e not-empty \ 707 ${TEST_SH} -c '>&8 || printf foo; printf bar' 708 atf-check -s exit:0 -o inline:bar -e not-empty \ 709 ${TEST_SH} -c 'command : >&7; printf bar' 710 atf-check -s exit:0 -o inline:foobar -e not-empty ${TEST_SH} -c \ 711 'command : >&7 || printf foo; printf bar' 712 713 return 0 714} 715 716# Many more tests in t_here, so here we have just rudimentary checks 717atf_test_case redir_here_doc 718redir_here_doc_head() 719{ 720 atf_set "descr" "Tests that sh(1) correctly processes 'here' doc " \ 721 "input redirections" 722} 723redir_here_doc_body() 724{ 725 # nb: the printf is not executed, it is data 726 cat <<- 'DONE' | 727 cat <<EOF 728 printf '%s\n' 'hello\n' 729 EOF 730 DONE 731 atf_check -s exit:0 -o match:printf -o match:'hello\\n' \ 732 -e empty ${TEST_SH} || 733 atf_fail "redir_here_doc failed" 734} 735 736atf_test_case subshell_redirections 737subshell_redirections_head() 738{ 739 atf_set "descr" "Tests redirection interactions between shell and " \ 740 "its sub-shell(s)" 741} 742subshell_redirections_body() 743{ 744 atf_require_prog cat 745 746 LIM=$(ulimit -n) 747 748 cat <<- 'DONE' | 749 exec 6>output-file 750 751 ( printf "hello\n" >&6 ) 752 753 exec 8<output-file 754 755 ( read hello <&8 ; test hello = "$hello" || echo >&2 Hello ) 756 757 ( printf "bye-bye\n" >&6 ) 758 759 ( exec 8<&- ) 760 read bye <&8 || echo >&2 "Closed?" 761 echo Bye="$bye" 762 DONE 763 atf_check -s exit:0 -o match:Bye=bye-bye -e empty \ 764 ${TEST_SH} || 765 atf_fail 'bye-bye failure' 766 767 cat <<- 'DONE' | 768 for arg in one-4 two-24 three-14 769 do 770 fd=${arg#*-} 771 file=${arg%-*} 772 eval "exec ${fd}>${file}" 773 done 774 775 for arg in one-5 two-7 three-19 776 do 777 fd=${arg#*-} 778 file=${arg%-*} 779 eval "exec ${fd}<${file}" 780 done 781 782 ( 783 echo line-1 >&4 784 echo line-2 >&24 785 echo line-3 >&14 786 echo go 787 ) | ( 788 read go 789 read x <&5 790 read y <&7 791 read z <&19 792 793 printf "%s\n" "${x}" "${y}" "${z}" 794 ) 795 DONE 796 atf_check -s exit:0 -o inline:'line-1\nline-2\nline-3\n' \ 797 -e empty ${TEST_SH} || 798 atf_fail 'complex 3 line redirects' 799 800 cat <<- 'DONE' | 801 for arg in one-4-5 two-6-7 three-8-9 four-11-10 five-3-12 802 do 803 ofd=${arg##*-} 804 file=${arg%-*} 805 ifd=${file#*-} 806 file=${file%-*} 807 eval "exec ${ofd}>${file}" 808 eval "exec ${ifd}<${file}" 809 done 810 811 ( ( ( echo line-1 >& 13 ) 13>&12 ) 12>&5 ) >stdout 2>errout 812 ( ( ( echo line-2 >& 4) 13>&12 ) 4>&7 ) >>stdout 2>>errout 813 ( ( ( echo line-3 >& 6) 8>&1 6>&11 >&12) 11>&9 >&7 ) >>stdout 814 815 ( ( ( cat <&13 >&12 ) 13<&8 12>&10 ) 10>&1 8<&6 ) 6<&4 816 ( ( ( cat <&4 ) <&4 6<&8 8<&11 ) 817 <&4 4<&6 6<&8 8<&11 ) <&4 4<&6 6<&8 8<&11 11<&3 818 ( ( ( cat <&7 >&1 ) 7<&6 >&10 ) 10>&2 6<&8 ) 2>&1 819 DONE 820 atf_check -s exit:0 -o inline:'line-1\nline-2\nline-3\n' \ 821 -e empty ${TEST_SH} || 822 atf_fail 'absurd 3 line redirects' 823} 824 825atf_test_case ulimit_redirection_interaction 826ulimit_redirection_interaction_head() 827{ 828 atf_set "descr" "Tests interactions between redirect and ulimit -n " 829} 830ulimit_redirection_interaction_body() 831{ 832 atf_require_prog ls 833 834 cat <<- 'DONE' > helper.sh 835 oLIM=$(ulimit -n) 836 HRD=$(ulimit -H -n) 837 test "${oLIM}" -lt "${HRD}" && ulimit -n "${HRD}" 838 LIM=$(ulimit -n) 839 840 FDs= 841 LFD=-1 842 while [ ${LIM} -gt 16 ] 843 do 844 FD=$(( ${LIM} - 1 )) 845 if [ "${FD}" -eq "${LFD}" ]; then 846 echo >&2 "Infinite loop... (busted $(( )) ??)" 847 exit 1 848 fi 849 LFD="${FD}" 850 851 eval "exec ${FD}"'> /dev/null' 852 FDs="${FD}${FDs:+ }${FDs}" 853 854 ( 855 FD=$(( ${LIM} + 1 )) 856 eval "exec ${FD}"'> /dev/null' 857 echo "Reached unreachable command" 858 ) 2>/dev/null && echo >&2 "Opened beyond limit!" 859 860 (eval 'ls 2>&1 3>&1 4>&1 5>&1 '"${FD}"'>&1') >&"${FD}" 861 862 LIM=$(( ${LIM} / 2 )) 863 ulimit -S -n "${LIM}" 864 done 865 866 # Even though ulimit has been reduced, open fds should work 867 for FD in ${FDs} 868 do 869 echo ${FD} in ${FDs} >&"${FD}" || exit 1 870 done 871 872 ulimit -S -n "${oLIM}" 873 874 # maybe more later... 875 876 DONE 877 878 atf_check -s exit:0 -o empty -e empty ${TEST_SH} helper.sh 879} 880 881atf_test_case validate_fn_redirects 882validate_fn_redirects_head() 883{ 884 # These test cases inspired by PR bin/48875 and the sh 885 # changes that were required to fix it. 886 887 atf_set "descr" "Tests various redirections applied to functions " \ 888 "See PR bin/48875" 889} 890validate_fn_redirects_body() 891{ 892 cat <<- 'DONE' > f-def 893 f() { 894 printf '%s\n' In-Func 895 } 896 DONE 897 898 atf_check -s exit:0 -o inline:'In-Func\nsuccess1\n' -e empty \ 899 ${TEST_SH} -c ". ./f-def; f ; printf '%s\n' success1" 900 atf_check -s exit:0 -o inline:'success2\n' -e empty \ 901 ${TEST_SH} -c ". ./f-def; f >/dev/null; printf '%s\n' success2" 902 atf_check -s exit:0 -o inline:'success3\n' -e not-empty \ 903 ${TEST_SH} -c ". ./f-def; f >&- ; printf '%s\n' success3" 904 atf_check -s exit:0 -o inline:'In-Func\nsuccess4\n' -e empty \ 905 ${TEST_SH} -c ". ./f-def; f & wait; printf '%s\n' success4" 906 atf_check -s exit:0 -o inline:'success5\n' -e not-empty \ 907 ${TEST_SH} -c ". ./f-def; f >&- & wait; printf '%s\n' success5" 908 atf_check -s exit:0 -o inline:'In-Func\nIn-Func\nsuccess6\n' -e empty \ 909 ${TEST_SH} -c ". ./f-def; f;f; printf '%s\n' success6" 910 atf_check -s exit:0 -o inline:'In-Func\nIn-Func\nsuccess7\n' -e empty \ 911 ${TEST_SH} -c ". ./f-def; { f;f;}; printf '%s\n' success7" 912 atf_check -s exit:0 -o inline:'In-Func\nIn-Func\nsuccess8\n' -e empty \ 913 ${TEST_SH} -c ". ./f-def; { f;f;}& wait; printf '%s\n' success8" 914 atf_check -s exit:0 -o inline:'In-Func\nsuccess9\n' -e empty \ 915 ${TEST_SH} -c \ 916 ". ./f-def; { f>/dev/null;f;}& wait; printf '%s\n' success9" 917 atf_check -s exit:0 -o inline:'In-Func\nsuccess10\n' -e empty \ 918 ${TEST_SH} -c \ 919 ". ./f-def; { f;f>/dev/null;}& wait; printf '%s\n' success10" 920 921 # This one tests the issue etcupdate had with the original 48875 fix 922 atf_check -s exit:0 -o inline:'Func a\nFunc b\nFunc c\n' -e empty \ 923 ${TEST_SH} -c ' 924 f() { 925 echo Func "$1" 926 } 927 exec 3<&0 4>&1 928 ( echo x-a; echo y-b; echo z-c ) | 929 while read A 930 do 931 B=${A#?-} 932 f "$B" <&3 >&4 933 done >&2' 934 935 # And this tests a similar condition with that same fix 936 cat <<- 'DONE' >Script 937 f() { 938 printf '%s' " hello $1" 939 } 940 exec 3>&1 941 echo $( for i in a b c 942 do printf '%s' @$i; f $i >&3; done >foo 943 ) 944 printf '%s\n' foo=$(cat foo) 945 DONE 946 atf_check -s exit:0 -e empty \ 947 -o inline:' hello a hello b hello c\nfoo=@a@b@c\n' \ 948 ${TEST_SH} Script 949 950 # Tests with sh reading stdin, which is not quite the same internal 951 # mechanism. 952 echo ". ./f-def || echo >&2 FAIL 953 f 954 printf '%s\n' stdin1 955 " | atf_check -s exit:0 -o inline:'In-Func\nstdin1\n' -e empty \ 956 ${TEST_SH} || 957 atf_fail "stdin1 test failure" 958 959 echo ' 960 . ./f-def || echo >&2 FAIL 961 f >&- 2>/dev/null 962 printf "%s\n" stdin2 963 ' | atf_check -s exit:0 -o inline:'stdin2\n' -e empty ${TEST_SH} || 964 atf_fail "stdin2 test failure" 965 966 cat <<- 'DONE' > fgh.def 967 f() { 968 echo -n f >&3 969 sleep 4 970 echo -n F >&3 971 } 972 g() { 973 echo -n g >&3 974 sleep 2 975 echo -n G >&3 976 } 977 h() { 978 echo -n h >&3 979 } 980 DONE 981 982 atf_check -s exit:0 -o inline:'fFgGh' -e empty \ 983 ${TEST_SH} -c '. ./fgh.def || echo >&2 FAIL 984 exec 3>&1 985 f; g; h' 986 987 atf_check -s exit:0 -o inline:'fghGF' -e empty \ 988 ${TEST_SH} -c '. ./fgh.def || echo >&2 FAIL 989 exec 3>&1 990 f & sleep 1; g & sleep 1; h; wait' 991 992 atf_check -s exit:0 -o inline:'fFgGhX Y\n' -e empty \ 993 ${TEST_SH} -c '. ./fgh.def || echo >&2 FAIL 994 exec 3>&1 995 echo X $( f ; g ; h ) Y' 996 997 # This one is the real test for PR bin/48875. If the 998 # cmdsub does not complete before f g (and h) exit, 999 # then the 'F' & 'G' will precede 'X Y' in the output. 1000 # If the cmdsub finishes while f & g are still running, 1001 # then the X Y will appear before the F and G. 1002 # The trailing "sleep 3" is just so we catch all the 1003 # output (otherwise atf_check will be finished while 1004 # f & g are still sleeping). 1005 1006 atf_check -s exit:0 -o inline:'fghX Y\nGF' -e empty \ 1007 ${TEST_SH} -c '. ./fgh.def || echo >&2 FAIL 1008 exec 3>&1 1009 echo X $( f >&- & sleep 1; g >&- & sleep 1 ; h ) Y 1010 sleep 3 1011 exec 4>&1 || echo FD_FAIL 1012 ' 1013 1014 # Do the test again to verify it also all works reading stdin 1015 # (which is a slightly different path through the shell) 1016 echo ' 1017 . ./fgh.def || echo >&2 FAIL 1018 exec 3>&1 1019 echo X $( f >&- & sleep 1; g >&- & sleep 1 ; h ) Y 1020 sleep 3 1021 exec 4>&1 || echo FD_FAIL 1022 ' | atf_check -s exit:0 -o inline:'fghX Y\nGF' -e empty ${TEST_SH} || 1023 atf_fail "48875 stdin variant failure" 1024} 1025 1026atf_init_test_cases() { 1027 atf_add_test_case basic_test_method_test 1028 atf_add_test_case do_input_redirections 1029 atf_add_test_case do_output_redirections 1030 atf_add_test_case do_redirect_input_output 1031 atf_add_test_case fd_redirections 1032 atf_add_test_case local_redirections 1033 atf_add_test_case incorrect_redirections 1034 atf_add_test_case named_fd_redirections 1035 atf_add_test_case redir_here_doc 1036 atf_add_test_case redir_in_case 1037 atf_add_test_case subshell_redirections 1038 atf_add_test_case ulimit_redirection_interaction 1039 atf_add_test_case validate_fn_redirects 1040} 1041