]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/netbsd-tests/bin/sh/t_redir.sh
MFC r305358,r305449,r305451,r306367,r306397,r309474:
[FreeBSD/stable/10.git] / contrib / netbsd-tests / bin / sh / t_redir.sh
1 # $NetBSD: t_redir.sh,v 1.9 2016/05/14 00:33:02 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         # This one tests the issue etcupdate had with the original 48875 fix
790         atf_check -s exit:0 -o inline:'Func a\nFunc b\nFunc c\n' -e empty \
791                 ${TEST_SH} -c '
792                         f() {
793                                 echo Func "$1"
794                         }
795                         exec 3<&0 4>&1
796                         ( echo x-a; echo y-b; echo z-c ) |
797                         while read A
798                         do
799                                 B=${A#?-}
800                                 f "$B" <&3 >&4
801                         done >&2'
802
803         # And this tests a similar condition with that same fix
804         cat  <<- 'DONE' >Script
805                 f() {
806                         printf '%s' " hello $1"
807                 }
808                 exec 3>&1
809                 echo $( for i in a b c
810                         do printf '%s' @$i; f $i >&3; done >foo
811                 )
812                 printf '%s\n' foo=$(cat foo)
813         DONE
814         atf_check -s exit:0 -e empty \
815             -o inline:' hello a hello b hello c\nfoo=@a@b@c\n' \
816             ${TEST_SH} Script
817
818         # Tests with sh reading stdin, which is not quite the same internal
819         # mechanism.
820         echo ". ./f-def || echo >&2 FAIL
821                 f
822                 printf '%s\n' stdin1
823         "| atf_check -s exit:0 -o inline:'In-Func\nstdin1\n' -e empty ${TEST_SH}
824
825         echo '
826                 . ./f-def || echo >&2 FAIL
827                 f >&-
828                 printf "%s\n" stdin2
829         ' | atf_check -s exit:0 -o inline:'stdin2\n' -e empty ${TEST_SH}
830
831         cat <<- 'DONE' > fgh.def
832                 f() {
833                         echo -n f >&3
834                         sleep 4
835                         echo -n F >&3
836                 }
837                 g() {
838                         echo -n g >&3
839                         sleep 2
840                         echo -n G >&3
841                 }
842                 h() {
843                         echo -n h >&3
844                 }
845         DONE
846
847         atf_check -s exit:0 -o inline:'fFgGh' -e empty \
848                 ${TEST_SH} -c '. ./fgh.def || echo >&2 FAIL
849                         exec 3>&1
850                         f; g; h'
851
852         atf_check -s exit:0 -o inline:'fghGF' -e empty \
853                 ${TEST_SH} -c '. ./fgh.def || echo >&2 FAIL
854                         exec 3>&1
855                         f & sleep 1; g & sleep 1; h; wait'
856
857         atf_check -s exit:0 -o inline:'fFgGhX Y\n' -e empty \
858                 ${TEST_SH} -c '. ./fgh.def || echo >&2 FAIL
859                         exec 3>&1
860                         echo X $( f ; g ; h ) Y'
861
862         # This one is the real test for PR bin/48875.  If the
863         # cmdsub does not complete before f g (and h) exit,
864         # then the 'F' & 'G' will precede 'X Y' in the output.
865         # If the cmdsub finishes while f & g are still running,
866         # then the X Y will appear before the F and G.
867         # The trailing "sleep 3" is just so we catch all the
868         # output (otherwise atf_check will be finished while
869         # f & g are still sleeping).
870
871         atf_check -s exit:0 -o inline:'fghX Y\nGF' -e empty \
872                 ${TEST_SH} -c '. ./fgh.def || echo >&2 FAIL
873                         exec 3>&1
874                         echo X $( f >&- & sleep 1; g >&- & sleep 1 ; h ) Y
875                         sleep 3
876                         exec 4>&1 || echo FD_FAIL
877                         '
878
879         # Do the test again to verify it also all works reading stdin
880         # (which is a slightly different path through the shell)
881         echo '
882                 . ./fgh.def || echo >&2 FAIL
883                 exec 3>&1
884                 echo X $( f >&- & sleep 1; g >&- & sleep 1 ; h ) Y
885                 sleep 3
886                 exec 4>&1 || echo FD_FAIL
887         ' | atf_check -s exit:0 -o inline:'fghX Y\nGF' -e empty ${TEST_SH}
888 }
889
890 atf_init_test_cases() {
891         atf_add_test_case basic_test_method_test
892         atf_add_test_case do_input_redirections
893         atf_add_test_case do_output_redirections
894         atf_add_test_case fd_redirections
895         atf_add_test_case local_redirections
896         atf_add_test_case incorrect_redirections
897         atf_add_test_case named_fd_redirections
898         atf_add_test_case redir_here_doc
899         atf_add_test_case redir_in_case
900         atf_add_test_case subshell_redirections
901         atf_add_test_case ulimit_redirection_interaction
902         atf_add_test_case validate_fn_redirects
903 }