1da2e3ebdSchin########################################################################
2da2e3ebdSchin#                                                                      #
3da2e3ebdSchin#               This software is part of the ast package               #
4b30d1939SAndy Fiddaman#          Copyright (c) 1982-2012 AT&T Intellectual Property          #
5da2e3ebdSchin#                      and is licensed under the                       #
6b30d1939SAndy Fiddaman#                 Eclipse Public License, Version 1.0                  #
77c2fbfb3SApril Chin#                    by AT&T Intellectual Property                     #
8da2e3ebdSchin#                                                                      #
9da2e3ebdSchin#                A copy of the License is available at                 #
10b30d1939SAndy Fiddaman#          http://www.eclipse.org/org/documents/epl-v10.html           #
11b30d1939SAndy Fiddaman#         (with md5 checksum b35adb5213ca9657e911e9befb180842)         #
12da2e3ebdSchin#                                                                      #
13da2e3ebdSchin#              Information and Software Systems Research               #
14da2e3ebdSchin#                            AT&T Research                             #
15da2e3ebdSchin#                           Florham Park NJ                            #
16da2e3ebdSchin#                                                                      #
17da2e3ebdSchin#                  David Korn <dgk@research.att.com>                   #
18da2e3ebdSchin#                                                                      #
19da2e3ebdSchin########################################################################
20da2e3ebdSchinfunction err_exit
21da2e3ebdSchin{
22da2e3ebdSchin	print -u2 -n "\t"
23da2e3ebdSchin	print -u2 -r ${Command}[$1]: "${@:2}"
24da2e3ebdSchin	let Errors+=1
25da2e3ebdSchin}
26da2e3ebdSchinalias err_exit='err_exit $LINENO'
27da2e3ebdSchin
28da2e3ebdSchinCommand=${0##*/}
29da2e3ebdSchininteger Errors=0
3034f9b3eeSRoland Mainz
3134f9b3eeSRoland Mainztmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; }
3234f9b3eeSRoland Mainztrap "cd /; rm -rf $tmp" EXIT
3334f9b3eeSRoland Mainz
3434f9b3eeSRoland Mainz# test basic file operations like redirection, pipes, file expansion
357c2fbfb3SApril Chinset -- \
367c2fbfb3SApril Chin	go+r	0000	\
377c2fbfb3SApril Chin	go-r	0044	\
387c2fbfb3SApril Chin	ug=r	0330	\
397c2fbfb3SApril Chin	go+w	0000	\
407c2fbfb3SApril Chin	go-w	0022	\
417c2fbfb3SApril Chin	ug=w	0550	\
427c2fbfb3SApril Chin	go+x	0000	\
437c2fbfb3SApril Chin	go-x	0011	\
447c2fbfb3SApril Chin	ug=x	0660	\
457c2fbfb3SApril Chin	go-rx	0055	\
467c2fbfb3SApril Chin	uo-wx	0303	\
477c2fbfb3SApril Chin	ug-rw	0660	\
487c2fbfb3SApril Chin	o=	0007
497c2fbfb3SApril Chinwhile	(( $# >= 2 ))
507c2fbfb3SApril Chindo	umask 0
517c2fbfb3SApril Chin	umask $1
527c2fbfb3SApril Chin	g=$(umask)
537c2fbfb3SApril Chin	[[ $g == $2 ]] || err_exit "umask 0; umask $1 failed -- expected $2, got $g"
547c2fbfb3SApril Chin	shift 2
557c2fbfb3SApril Chindone
56da2e3ebdSchinumask u=rwx,go=rx || err_exit "umask u=rws,go=rx failed"
57da2e3ebdSchinif	[[ $(umask -S) != u=rwx,g=rx,o=rx ]]
58da2e3ebdSchinthen	err_exit 'umask -S incorrect'
59da2e3ebdSchinfi
60da2e3ebdSchinpwd=$PWD
61da2e3ebdSchin[[ $SHELL != /* ]] && SHELL=$pwd/$SHELL
6234f9b3eeSRoland Mainzcd $tmp || { err_exit "cd $tmp failed"; exit 1; }
637c2fbfb3SApril Chinum=$(umask -S)
647c2fbfb3SApril Chin( umask 0777; > foobar )
657c2fbfb3SApril Chinrm -f foobar
667c2fbfb3SApril Chin> foobar
677c2fbfb3SApril Chin[[ -r foobar ]] || err_exit 'umask not being restored after subshell'
687c2fbfb3SApril Chinumask "$um"
697c2fbfb3SApril Chinrm -f foobar
70da2e3ebdSchin# optimizer bug test
71da2e3ebdSchin> foobar
72da2e3ebdSchinfor i in 1 2
73da2e3ebdSchindo      print foobar*
74da2e3ebdSchin        rm -f foobar
7534f9b3eeSRoland Mainzdone > out
7634f9b3eeSRoland Mainzif      [[ "$(<out)"  != "foobar"$'\n'"foobar*" ]]
77da2e3ebdSchinthen    print -u2 "optimizer bug with file expansion"
78da2e3ebdSchinfi
7934f9b3eeSRoland Mainzrm -f out foobar
80da2e3ebdSchinmkdir dir
81da2e3ebdSchinif	[[ $(print */) != dir/ ]]
82da2e3ebdSchinthen	err_exit 'file expansion with trailing / not working'
83da2e3ebdSchinfi
84da2e3ebdSchinif	[[ $(print *) != dir ]]
85da2e3ebdSchinthen	err_exit 'file expansion with single file not working'
86da2e3ebdSchinfi
87da2e3ebdSchinprint hi > .foo
88da2e3ebdSchinif	[[ $(print *) != dir ]]
89da2e3ebdSchinthen	err_exit 'file expansion leading . not working'
90da2e3ebdSchinfi
91da2e3ebdSchindate > dat1 || err_exit "date > dat1 failed"
92da2e3ebdSchintest -r dat1 || err_exit "dat1 is not readable"
93da2e3ebdSchinx=dat1
94da2e3ebdSchincat <$x > dat2 || err_exit "cat < $x > dat2 failed"
95da2e3ebdSchincat dat1 dat2 | cat  | cat | cat > dat3 || err_exit "cat pipe failed"
96da2e3ebdSchincat > dat4 <<!
97da2e3ebdSchin$(date)
98da2e3ebdSchin!
99da2e3ebdSchincat dat1 dat2 | cat  | cat | cat > dat5 &
100da2e3ebdSchinwait $!
101da2e3ebdSchinset -- dat*
102da2e3ebdSchinif	(( $# != 5 ))
103da2e3ebdSchinthen	err_exit "dat* matches only $# files"
104da2e3ebdSchinfi
10534f9b3eeSRoland Mainzif	(command > foo\\abc) 2> /dev/null
106da2e3ebdSchinthen	set -- foo*
107da2e3ebdSchin	if	[[ $1 != 'foo\abc' ]]
108da2e3ebdSchin	then	err_exit 'foo* does not match foo\abc'
109da2e3ebdSchin	fi
110da2e3ebdSchinfi
111da2e3ebdSchinif ( : > TT* && : > TTfoo ) 2>/dev/null
112da2e3ebdSchinthen	set -- TT*
113da2e3ebdSchin	if	(( $# < 2 ))
114da2e3ebdSchin	then	err_exit 'TT* not expanding when file TT* exists'
115da2e3ebdSchin	fi
116da2e3ebdSchinfi
117da2e3ebdSchincd ~- || err_exit "cd back failed"
11834f9b3eeSRoland Mainzcat > $tmp/script <<- !
119da2e3ebdSchin	#! $SHELL
120da2e3ebdSchin	print -r -- \$0
121da2e3ebdSchin!
12234f9b3eeSRoland Mainzchmod 755 $tmp/script
12334f9b3eeSRoland Mainzif	[[ $($tmp/script) != "$tmp/script" ]]
124da2e3ebdSchinthen	err_exit '$0 not correct for #! script'
125da2e3ebdSchinfi
126da2e3ebdSchinbar=foo
127da2e3ebdSchineval foo=\$bar
128da2e3ebdSchinif	[[ $foo != foo ]]
129da2e3ebdSchinthen	err_exit 'eval foo=\$bar not working'
130da2e3ebdSchinfi
131da2e3ebdSchinbar='foo=foo\ bar'
132da2e3ebdSchineval $bar
133da2e3ebdSchinif	[[ $foo != 'foo bar' ]]
134da2e3ebdSchinthen	err_exit 'eval foo=\$bar, with bar="foo\ bar" not working'
135da2e3ebdSchinfi
136da2e3ebdSchincd /tmp
137da2e3ebdSchincd ../../tmp || err_exit "cd ../../tmp failed"
138da2e3ebdSchinif	[[ $PWD != /tmp ]]
139da2e3ebdSchinthen	err_exit 'cd ../../tmp is not /tmp'
140da2e3ebdSchinfi
141da2e3ebdSchin( sleep 2; cat <<!
142da2e3ebdSchinfoobar
143da2e3ebdSchin!
14434f9b3eeSRoland Mainz) | cat > $tmp/foobar &
145da2e3ebdSchinwait $!
14634f9b3eeSRoland Mainzfoobar=$( < $tmp/foobar)
147da2e3ebdSchinif	[[ $foobar != foobar ]]
148da2e3ebdSchinthen	err_exit "$foobar is not foobar"
149da2e3ebdSchinfi
150da2e3ebdSchin{
151da2e3ebdSchin	print foo
152da2e3ebdSchin	/bin/echo bar
153da2e3ebdSchin	print bam
15434f9b3eeSRoland Mainz} > $tmp/foobar
15534f9b3eeSRoland Mainzif	[[ $( < $tmp/foobar) != $'foo\nbar\nbam' ]]
15634f9b3eeSRoland Mainzthen	err_exit "output file pointer not shared correctly"
157da2e3ebdSchinfi
15834f9b3eeSRoland Mainzcat > $tmp/foobar <<\!
159da2e3ebdSchin	print foo
160da2e3ebdSchin	/bin/echo bar
161da2e3ebdSchin	print bam
162da2e3ebdSchin!
16334f9b3eeSRoland Mainzchmod +x $tmp/foobar
16434f9b3eeSRoland Mainzif	[[ $($tmp/foobar) != $'foo\nbar\nbam' ]]
16534f9b3eeSRoland Mainzthen	err_exit "script not working"
166da2e3ebdSchinfi
16734f9b3eeSRoland Mainzif	[[ $($tmp/foobar | /bin/cat) != $'foo\nbar\nbam' ]]
16834f9b3eeSRoland Mainzthen	err_exit "script | cat not working"
169da2e3ebdSchinfi
17034f9b3eeSRoland Mainzif	[[ $( $tmp/foobar) != $'foo\nbar\nbam' ]]
17134f9b3eeSRoland Mainzthen	err_exit "output file pointer not shared correctly"
172da2e3ebdSchinfi
17334f9b3eeSRoland Mainzrm -f $tmp/foobar
174da2e3ebdSchinx=$( (print foo) ; (print bar) )
175da2e3ebdSchinif	[[ $x != $'foo\nbar' ]]
176da2e3ebdSchinthen	err_exit " ( (print foo);(print bar ) failed"
177da2e3ebdSchinfi
178da2e3ebdSchinx=$( (/bin/echo foo) ; (print bar) )
179da2e3ebdSchinif	[[ $x != $'foo\nbar' ]]
180da2e3ebdSchinthen	err_exit " ( (/bin/echo);(print bar ) failed"
181da2e3ebdSchinfi
182da2e3ebdSchinx=$( (/bin/echo foo) ; (/bin/echo bar) )
183da2e3ebdSchinif	[[ $x != $'foo\nbar' ]]
184da2e3ebdSchinthen	err_exit " ( (/bin/echo);(/bin/echo bar ) failed"
185da2e3ebdSchinfi
18634f9b3eeSRoland Mainzcat > $tmp/script <<\!
187da2e3ebdSchinif	[[ -p /dev/fd/0 ]]
188da2e3ebdSchinthen	builtin cat
189da2e3ebdSchin	cat - > /dev/null
190da2e3ebdSchin	[[ -p /dev/fd/0 ]] && print ok
191da2e3ebdSchinelse	print no
192da2e3ebdSchinfi
193da2e3ebdSchin!
19434f9b3eeSRoland Mainzchmod +x $tmp/script
19534f9b3eeSRoland Mainzcase $( (print) | $tmp/script;:) in
196da2e3ebdSchinok)	;;
197da2e3ebdSchinno)	err_exit "[[ -p /dev/fd/0 ]] fails for standard input pipe" ;;
198da2e3ebdSchin*)	err_exit "builtin replaces standard input pipe" ;;
199da2e3ebdSchinesac
20034f9b3eeSRoland Mainzprint 'print $0' > $tmp/script
20134f9b3eeSRoland Mainzprint ". $tmp/script" > $tmp/scriptx
20234f9b3eeSRoland Mainzchmod +x $tmp/scriptx
20334f9b3eeSRoland Mainzif	[[ $($tmp/scriptx) != $tmp/scriptx ]]
204da2e3ebdSchinthen	err_exit '$0 not correct for . script'
205da2e3ebdSchinfi
20634f9b3eeSRoland Mainzcd $tmp || { err_exit "cd $tmp failed"; exit 1; }
20734f9b3eeSRoland Mainzprint ./b > ./a; print ./c > b; print ./d > c; print ./e > d; print "echo \"hello there\"" > e
208da2e3ebdSchinchmod 755 a b c d e
209da2e3ebdSchinx=$(./a)
210da2e3ebdSchinif	[[ $x != "hello there" ]]
21134f9b3eeSRoland Mainzthen	err_exit "nested scripts failed"
212da2e3ebdSchinfi
213da2e3ebdSchinx=$( (./a) | cat)
214da2e3ebdSchinif	[[ $x != "hello there" ]]
21534f9b3eeSRoland Mainzthen	err_exit "scripts in subshells fail"
216da2e3ebdSchinfi
217da2e3ebdSchincd ~- || err_exit "cd back failed"
218da2e3ebdSchinx=$( (/bin/echo foo) 2> /dev/null )
219da2e3ebdSchinif	[[ $x != foo ]]
220da2e3ebdSchinthen	err_exit "subshell in command substitution fails"
221da2e3ebdSchinfi
222b30d1939SAndy Fiddamanexec 9>& 1
223da2e3ebdSchinexec 1>&-
224da2e3ebdSchinx=$(print hello)
225da2e3ebdSchinif	[[ $x != hello ]]
226da2e3ebdSchinthen	err_exit "command subsitution with stdout closed failed"
227da2e3ebdSchinfi
228b30d1939SAndy Fiddamanexec >& 9
229da2e3ebdSchincd $pwd
230da2e3ebdSchinx=$(cat <<\! | $SHELL
231da2e3ebdSchin/bin/echo | /bin/cat
232da2e3ebdSchin/bin/echo hello
233da2e3ebdSchin!
234da2e3ebdSchin)
235da2e3ebdSchinif	[[ $x != $'\n'hello ]]
236da2e3ebdSchinthen	err_exit "$SHELL not working when standard input is a pipe"
237da2e3ebdSchinfi
238da2e3ebdSchinx=$( (/bin/echo hello) 2> /dev/null )
239da2e3ebdSchinif	[[ $x != hello ]]
240da2e3ebdSchinthen	err_exit "subshell in command substitution with 1 closed fails"
241da2e3ebdSchinfi
24234f9b3eeSRoland Mainzcat > $tmp/script <<- \!
243da2e3ebdSchinread line 2> /dev/null
244da2e3ebdSchinprint done
245da2e3ebdSchin!
24634f9b3eeSRoland Mainzif	[[ $($SHELL $tmp/script <&-) != done ]]
247da2e3ebdSchinthen	err_exit "executing script with 0 closed fails"
248da2e3ebdSchinfi
249da2e3ebdSchintrap '' INT
25034f9b3eeSRoland Mainzcat > $tmp/script <<- \!
251da2e3ebdSchintrap 'print bad' INT
252da2e3ebdSchinkill -s INT $$
253da2e3ebdSchinprint good
254da2e3ebdSchin!
25534f9b3eeSRoland Mainzchmod +x $tmp/script
25634f9b3eeSRoland Mainzif	[[ $($SHELL  $tmp/script) != good ]]
257da2e3ebdSchinthen	err_exit "traps ignored by parent not ignored"
258da2e3ebdSchinfi
259da2e3ebdSchintrap - INT
26034f9b3eeSRoland Mainzcat > $tmp/script <<- \!
261da2e3ebdSchinread line
262da2e3ebdSchin/bin/cat
263da2e3ebdSchin!
26434f9b3eeSRoland Mainzif	[[ $($SHELL $tmp/script <<!
265da2e3ebdSchinone
266da2e3ebdSchintwo
267da2e3ebdSchin!
268da2e3ebdSchin)	!= two ]]
269da2e3ebdSchinthen	err_exit "standard input not positioned correctly"
270da2e3ebdSchinfi
271da2e3ebdSchinword=$(print $'foo\nbar' | { read line; /bin/cat;})
272da2e3ebdSchinif	[[ $word != bar ]]
273da2e3ebdSchinthen	err_exit "pipe to { read line; /bin/cat;} not working"
274da2e3ebdSchinfi
275da2e3ebdSchinword=$(print $'foo\nbar' | ( read line; /bin/cat) )
276da2e3ebdSchinif	[[ $word != bar ]]
277da2e3ebdSchinthen	err_exit "pipe to ( read line; /bin/cat) not working"
278da2e3ebdSchinfi
279da2e3ebdSchinif	[[ $(print x{a,b}y) != 'xay xby' ]]
280da2e3ebdSchinthen	err_exit 'brace expansion not working'
281da2e3ebdSchinfi
282da2e3ebdSchinif	[[ $(for i in foo bar
283da2e3ebdSchin	  do ( tgz=$(print $i)
284da2e3ebdSchin	  print $tgz)
285da2e3ebdSchin	  done) != $'foo\nbar' ]]
286da2e3ebdSchinthen	err_exit 'for loop subshell optimizer bug'
287da2e3ebdSchinfi
288da2e3ebdSchinunset a1
289da2e3ebdSchinoptbug()
290da2e3ebdSchin{
291da2e3ebdSchin	set -A a1  foo bar bam
292da2e3ebdSchin	integer i
293da2e3ebdSchin	for ((i=0; i < 3; i++))
294da2e3ebdSchin	do
295da2e3ebdSchin		(( ${#a1[@]} < 2 )) && return 0
296da2e3ebdSchin		set -- "${a1[@]}"
297da2e3ebdSchin		shift
298da2e3ebdSchin		set -A a1 -- "$@"
299da2e3ebdSchin	done
300da2e3ebdSchin	return 1
301da2e3ebdSchin}
302da2e3ebdSchinoptbug ||  err_exit 'array size optimzation bug'
3037c2fbfb3SApril Chinwait # not running --pipefail which would interfere with subsequent tests
304da2e3ebdSchin: $(jobs -p) # required to clear jobs for next jobs -p (interactive side effect)
305da2e3ebdSchinsleep 20 &
3067c2fbfb3SApril Chinpids=$!
307da2e3ebdSchinif	[[ $(jobs -p) != $! ]]
30834f9b3eeSRoland Mainzthen	err_exit 'jobs -p not reporting a background job'
309da2e3ebdSchinfi
310da2e3ebdSchinsleep 20 &
3117c2fbfb3SApril Chinpids="$pids $!"
312da2e3ebdSchinfoo()
313da2e3ebdSchin{
314da2e3ebdSchin	set -- $(jobs -p)
315da2e3ebdSchin	(( $# == 2 )) || err_exit "$# jobs not reported -- 2 expected"
316da2e3ebdSchin}
317da2e3ebdSchinfoo
3187c2fbfb3SApril Chinkill $pids
3197c2fbfb3SApril Chin
3207c2fbfb3SApril Chin[[ $( (trap 'print alarm' ALRM; sleep 4) & sleep 2; kill -ALRM $!; sleep 2; wait) == alarm ]] || err_exit 'ALRM signal not working'
321da2e3ebdSchin[[ $($SHELL -c 'trap "" HUP; $SHELL -c "(sleep 2;kill -HUP $$)& sleep 4;print done"') != done ]] && err_exit 'ignored traps not being ignored'
322da2e3ebdSchin[[ $($SHELL -c 'o=foobar; for x in foo bar; do (o=save);print $o;done' 2> /dev/null ) == $'foobar\nfoobar' ]] || err_exit 'for loop optimization subshell bug'
323da2e3ebdSchincommand exec 3<> /dev/null
324b30d1939SAndy Fiddamanif	cat /dev/fd/3 >/dev/null 2>&1  || whence mkfifo > /dev/null
325da2e3ebdSchinthen	[[ $($SHELL -c 'cat <(print foo)' 2> /dev/null) == foo ]] || err_exit 'process substitution not working'
32634f9b3eeSRoland Mainz	[[ $($SHELL -c  $'tee >(grep \'1$\' > '$tmp/scriptx$') > /dev/null <<-  \!!!
327da2e3ebdSchin	line0
328da2e3ebdSchin	line1
329da2e3ebdSchin	line2
330da2e3ebdSchin	!!!
331da2e3ebdSchin	wait
33234f9b3eeSRoland Mainz	cat '$tmp/scriptx 2> /dev/null)  == line1 ]] || err_exit '>() process substitution fails'
33334f9b3eeSRoland Mainz	> $tmp/scriptx
334da2e3ebdSchin	[[ $($SHELL -c  $'
335da2e3ebdSchin	for i in 1
33634f9b3eeSRoland Mainz	do	tee >(grep \'1$\' > '$tmp/scriptx$') > /dev/null  <<-  \!!!
337da2e3ebdSchin		line0
338da2e3ebdSchin		line1
339da2e3ebdSchin		line2
340da2e3ebdSchin		!!!
341da2e3ebdSchin	done
342da2e3ebdSchin	wait
34334f9b3eeSRoland Mainz	cat '$tmp/scriptx 2>> /dev/null) == line1 ]] || err_exit '>() process substitution fails in for loop'
344da2e3ebdSchin	[[ $({ $SHELL -c 'cat <(for i in x y z; do print $i; done)';} 2> /dev/null) == $'x\ny\nz' ]] ||
345da2e3ebdSchin		err_exit 'process substitution of compound commands not working'
346da2e3ebdSchinfi
347da2e3ebdSchin[[ $($SHELL -r 'command -p :' 2>&1) == *restricted* ]]  || err_exit 'command -p not restricted'
34834f9b3eeSRoland Mainzprint cat >  $tmp/scriptx
34934f9b3eeSRoland Mainzchmod +x $tmp/scriptx
35034f9b3eeSRoland Mainz[[ $($SHELL -c "print foo | $tmp/scriptx ;:" 2> /dev/null ) == foo ]] || err_exit 'piping into script fails'
351da2e3ebdSchin[[ $($SHELL -c 'X=1;print -r -- ${X:=$(expr "a(0)" : '"'a*(\([^)]\))')}'" 2> /dev/null) == 1 ]] || err_exit 'x=1;${x:=$(..."...")} failure'
352da2e3ebdSchin[[ $($SHELL -c 'print -r -- ${X:=$(expr "a(0)" : '"'a*(\([^)]\))')}'" 2> /dev/null) == 0 ]] || err_exit '${x:=$(..."...")} failure'
353b30d1939SAndy Fiddamanif	cat /dev/fd/3 >/dev/null 2>&1  || whence mkfifo > /dev/null
354da2e3ebdSchinthen	[[ $(cat <(print hello) ) == hello ]] || err_exit "process substitution not working outside for or while loop"
355da2e3ebdSchin	$SHELL -c '[[ $(for i in 1;do cat <(print hello);done ) == hello ]]' 2> /dev/null|| err_exit "process substitution not working in for or while loop"
356da2e3ebdSchinfi
357da2e3ebdSchinexec 3> /dev/null
35834f9b3eeSRoland Mainzprint 'print foo "$@"' > $tmp/scriptx
35934f9b3eeSRoland Mainz[[ $( print "($tmp/scriptx bar)" | $SHELL 2>/dev/null) == 'foo bar' ]] || err_exit 'script pipe to shell fails'
36034f9b3eeSRoland Mainzprint "#! $SHELL" > $tmp/scriptx
36134f9b3eeSRoland Mainzprint 'print  -- $0' >> $tmp/scriptx
36234f9b3eeSRoland Mainzchmod +x $tmp/scriptx
36334f9b3eeSRoland Mainz[[ $($tmp/scriptx) == $tmp/scriptx ]] || err_exit  "\$0 is $0 instead of $tmp/scriptx"
36434f9b3eeSRoland Mainzcat > $tmp/scriptx <<- \EOF
3657c2fbfb3SApril Chin	myfilter() { x=$(print ok | cat); print  -r -- $SECONDS;}
3667c2fbfb3SApril Chin	set -o pipefail
3677c2fbfb3SApril Chin	sleep 3 | myfilter
3687c2fbfb3SApril ChinEOF
36934f9b3eeSRoland Mainz(( $($SHELL $tmp/scriptx) > 2.0 )) && err_exit 'command substitution causes pipefail option to hang'
370da2e3ebdSchinexec 3<&-
371da2e3ebdSchin( typeset -r foo=bar) 2> /dev/null || err_exit 'readonly variables set in a subshell cannot unset'
3727c2fbfb3SApril Chin$SHELL -c 'x=${ print hello;}; [[ $x == hello ]]' 2> /dev/null || err_exit '${ command;} not supported'
3737c2fbfb3SApril Chin$SHELL 2> /dev/null <<- \EOF || err_exit 'multiline ${...} command substitution not supported'
3747c2fbfb3SApril Chin	x=${
3757c2fbfb3SApril Chin		print hello
3767c2fbfb3SApril Chin	}
3777c2fbfb3SApril Chin	[[ $x == hello ]]
3787c2fbfb3SApril ChinEOF
3797c2fbfb3SApril Chin$SHELL 2> /dev/null <<- \EOF || err_exit '${...} command substitution with side effects not supported '
3807c2fbfb3SApril Chin	y=bye
3817c2fbfb3SApril Chin	x=${
3827c2fbfb3SApril Chin		y=hello
3837c2fbfb3SApril Chin		print hello
3847c2fbfb3SApril Chin	}
3857c2fbfb3SApril Chin	[[ $y == $x ]]
3867c2fbfb3SApril ChinEOF
3877c2fbfb3SApril Chin$SHELL   2> /dev/null <<- \EOF || err_exit 'nested ${...} command substitution not supported'
3887c2fbfb3SApril Chin	x=${
3897c2fbfb3SApril Chin		print ${ print hello;} $(print world)
3907c2fbfb3SApril Chin	}
3917c2fbfb3SApril Chin	[[ $x == 'hello world' ]]
3927c2fbfb3SApril ChinEOF
3937c2fbfb3SApril Chin$SHELL   2> /dev/null <<- \EOF || err_exit 'terminating } is not a reserved word with ${ command }'
3947c2fbfb3SApril Chin	x=${	{ print -n } ; print -n hello ; }  ; print ' world' }
3957c2fbfb3SApril Chin	[[ $x == '}hello world' ]]
3967c2fbfb3SApril ChinEOF
3977c2fbfb3SApril Chin$SHELL   2> /dev/null <<- \EOF || err_exit '${ command;}xxx not working'
3987c2fbfb3SApril Chin	f()
3997c2fbfb3SApril Chin	{
4007c2fbfb3SApril Chin		print foo
4017c2fbfb3SApril Chin	}
4027c2fbfb3SApril Chin	[[ ${ f;}bar == foobar ]]
4037c2fbfb3SApril ChinEOF
4047c2fbfb3SApril Chin
4057c2fbfb3SApril Chinunset foo
40634f9b3eeSRoland Mainz[[ ! ${foo[@]} ]] || err_exit '${foo[@]} is not empty when foo is unset'
40734f9b3eeSRoland Mainz[[ ! ${foo[3]} ]] || err_exit '${foo[3]} is not empty when foo is unset'
4087c2fbfb3SApril Chin[[ $(print  "[${ print foo }]") == '[foo]' ]] || err_exit '${...} not working when } is followed by ]'
4097c2fbfb3SApril Chin[[ $(print  "${ print "[${ print foo }]" }") == '[foo]' ]] || err_exit 'nested ${...} not working when } is followed by ]'
4107c2fbfb3SApril Chinunset foo
4117c2fbfb3SApril Chinfoo=$(false) > /dev/null && err_exit 'failed command substitution with redirection not returning false'
4127c2fbfb3SApril Chinexpected=foreback
413b30d1939SAndy Fiddamangot=$(print -n fore; (sleep 2;print back)&)
4147c2fbfb3SApril Chin[[ $got == $expected ]] || err_exit "command substitution background process output error -- got '$got', expected '$expected'"
4157c2fbfb3SApril Chin
41634f9b3eeSRoland Mainzbinfalse=$(whence -p false)
41734f9b3eeSRoland Mainzfor false in false $binfalse
4187c2fbfb3SApril Chindo	x=$($false) && err_exit "x=\$($false) should fail"
4197c2fbfb3SApril Chin	$($false) && err_exit "\$($false) should fail"
4207c2fbfb3SApril Chin	$($false) > /dev/null && err_exit "\$($false) > /dev/null should fail"
4217c2fbfb3SApril Chindone
42234f9b3eeSRoland Mainzif	env x-a=y >/dev/null 2>&1
42334f9b3eeSRoland Mainzthen	[[ $(env 'x-a=y'  $SHELL -c 'env | grep x-a') == *x-a=y* ]] || err_exit 'invalid environment variables not preserved'
42434f9b3eeSRoland Mainzfi
42534f9b3eeSRoland Mainzfloat s=SECONDS
42634f9b3eeSRoland Mainzsleep=$(whence -p sleep)
42734f9b3eeSRoland Mainzfor i in 1 2
42834f9b3eeSRoland Mainzdo      print $i
42934f9b3eeSRoland Mainzdone | while read sec; do ( $sleep $sec; $sleep $sec) done
43034f9b3eeSRoland Mainz(( (SECONDS-s)  < 4)) && err_exit '"command | while read...done" finishing too fast'
43134f9b3eeSRoland Mainzs=SECONDS
43234f9b3eeSRoland Mainzset -o pipefail
43334f9b3eeSRoland Mainzfor ((i=0; i < 30; i++))
43434f9b3eeSRoland Mainzdo	print hello
43534f9b3eeSRoland Mainz	sleep .1
43634f9b3eeSRoland Mainzdone |  $sleep 1
43734f9b3eeSRoland Mainz(( (SECONDS-s) < 2 )) || err_exit 'early termination not causing broken pipe'
43834f9b3eeSRoland Mainz[[ $({ trap 'print trap' 0; print -n | $(whence -p cat); } & wait $!) == trap ]] || err_exit 'trap on exit not getting triggered'
43934f9b3eeSRoland Mainzvar=$({ trap 'print trap' ERR; print -n | $binfalse; } & wait $!)
44034f9b3eeSRoland Mainz[[ $var == trap ]] || err_exit 'trap on ERR not getting triggered'
44134f9b3eeSRoland Mainz
44234f9b3eeSRoland Mainzexp=
44334f9b3eeSRoland Mainzgot=$(
44434f9b3eeSRoland Mainz	function fun
44534f9b3eeSRoland Mainz	{
44634f9b3eeSRoland Mainz		$binfalse && echo FAILED
44734f9b3eeSRoland Mainz	}
44834f9b3eeSRoland Mainz	: works if this line deleted : |
44934f9b3eeSRoland Mainz	fun
45034f9b3eeSRoland Mainz	: works if this line deleted :
45134f9b3eeSRoland Mainz)
45234f9b3eeSRoland Mainz[[ $got == $exp ]] || err_exit "pipe to function with conditional fails -- expected '$exp', got '$got'"
45334f9b3eeSRoland Mainzgot=$(
45434f9b3eeSRoland Mainz	: works if this line deleted : |
45534f9b3eeSRoland Mainz	{ $binfalse && echo FAILED; }
45634f9b3eeSRoland Mainz	: works if this line deleted :
45734f9b3eeSRoland Mainz)
45834f9b3eeSRoland Mainz[[ $got == $exp ]] || err_exit "pipe to { ... } with conditional fails -- expected '$exp', got '$got'"
45934f9b3eeSRoland Mainz
46034f9b3eeSRoland Mainzgot=$(
46134f9b3eeSRoland Mainz	: works if this line deleted : |
46234f9b3eeSRoland Mainz	( $binfalse && echo FAILED )
46334f9b3eeSRoland Mainz	: works if this line deleted :
46434f9b3eeSRoland Mainz)
46534f9b3eeSRoland Mainz[[ $got == $exp ]] || err_exit "pipe to ( ... ) with conditional fails -- expected '$exp', got '$got'"
46634f9b3eeSRoland Mainz
46734f9b3eeSRoland Mainz( $SHELL -c 'trap : DEBUG; x=( $foo); exit 0') 2> /dev/null  || err_exit 'trap DEBUG fails'
46834f9b3eeSRoland Mainz
469b30d1939SAndy Fiddamanbintrue=$(whence -p true)
4703e14f97fSRoger A. Faulknerset -o pipefail
4713e14f97fSRoger A. Faulknerfloat start=$SECONDS end
4723e14f97fSRoger A. Faulknerfor ((i=0; i < 2; i++))
4733e14f97fSRoger A. Faulknerdo	print foo
4743e14f97fSRoger A. Faulkner	sleep 1.5
475b30d1939SAndy Fiddamandone | { read; $bintrue; end=$SECONDS ;}
4763e14f97fSRoger A. Faulkner(( (SECONDS-start) < 1 )) && err_exit "pipefail not waiting for pipe to finish"
4773e14f97fSRoger A. Faulknerset +o pipefail
478b30d1939SAndy Fiddaman(( (SECONDS-end) > 2 )) &&  err_exit "pipefail causing $bintrue to wait for other end of pipe"
4793e14f97fSRoger A. Faulkner
4803e14f97fSRoger A. Faulkner
4813e14f97fSRoger A. Faulkner{ env A__z=C+SHLVL $SHELL -c : ;} 2> /dev/null || err_exit "SHLVL with wrong attribute fails"
4823e14f97fSRoger A. Faulkner
483b30d1939SAndy Fiddamanif [[ $bintrue ]]
484b30d1939SAndy Fiddamanthen	float t0=SECONDS
485b30d1939SAndy Fiddaman	{ time sleep 1.5 | $bintrue ;} 2> /dev/null
486b30d1939SAndy Fiddaman	(( (SECONDS-t0) < 1 )) && err_exit 'time not waiting for pipeline to complete'
487b30d1939SAndy Fiddamanfi
488b30d1939SAndy Fiddaman
489b30d1939SAndy Fiddamancat > $tmp/foo.sh <<- \EOF
490b30d1939SAndy Fiddaman	eval "cat > /dev/null  < /dev/null"
491b30d1939SAndy Fiddaman	sleep 1
492b30d1939SAndy FiddamanEOF
493b30d1939SAndy Fiddamanfloat sec=SECONDS
494b30d1939SAndy Fiddaman. $tmp/foo.sh  | cat > /dev/null
495b30d1939SAndy Fiddaman(( (SECONDS-sec) < .7 ))  && err_exit '. script does not restore output redirection with eval'
496b30d1939SAndy Fiddaman
497b30d1939SAndy Fiddamanfile=$tmp/foobar
498b30d1939SAndy Fiddamanbuiltin cat
499b30d1939SAndy Fiddamanfor ((n=0; n < 1000; n++))
500b30d1939SAndy Fiddamando
501b30d1939SAndy Fiddaman	> $file
502b30d1939SAndy Fiddaman	{ sleep .001;echo $? >$file;} | cat > /dev/null
503b30d1939SAndy Fiddaman	if	[[ !  -s $file ]]
504b30d1939SAndy Fiddaman	then	err_exit 'output from pipe is lost with pipe to builtin'
505b30d1939SAndy Fiddaman		break;
506b30d1939SAndy Fiddaman	fi
507b30d1939SAndy Fiddamandone
508b30d1939SAndy Fiddaman
509b30d1939SAndy Fiddaman$SHELL -c 'kill -0 123456789123456789123456789' 2> /dev/null && err_exit 'kill not catching process id overflows'
510b30d1939SAndy Fiddaman
511b30d1939SAndy Fiddaman[[ $($SHELL -c '{ cd..; print ok;}' 2> /dev/null) == ok ]] || err_exit 'command name ending in .. causes shell to abort'
512b30d1939SAndy Fiddaman
513b30d1939SAndy Fiddaman$SHELL -xc '$(LD_LIBRARY_PATH=$LD_LIBRARY_PATH exec $SHELL -c :)' > /dev/null 2>&1  || err_exit "ksh -xc '(name=value exec ksh)' fails with err=$?"
514b30d1939SAndy Fiddaman
515b30d1939SAndy Fiddaman$SHELL 2> /dev/null -c $'for i;\ndo :;done' || err_exit 'for i ; <newline> not vaid'
516b30d1939SAndy Fiddaman
517*6ba75e24SJohnothan King# The time keyword should obey the errexit option
518*6ba75e24SJohnothan King# https://www.illumos.org/issues/7694
519*6ba75e24SJohnothan Kingtime_errexit="$tmp/time_errexit.sh"
520*6ba75e24SJohnothan Kingcat > "$time_errexit" << 'EOF'
521*6ba75e24SJohnothan Kingtime false
522*6ba75e24SJohnothan Kingecho FAILURE
523*6ba75e24SJohnothan Kingtrue
524*6ba75e24SJohnothan KingEOF
525*6ba75e24SJohnothan Kinggot=$($SHELL -e "$time_errexit" 2>&1)
526*6ba75e24SJohnothan King(( $? == 0 )) && err_exit "The time keyword ignores the errexit option" \
527*6ba75e24SJohnothan King	"(got $(printf %q "$got"))"
528*6ba75e24SJohnothan King[[ -z $got ]] || err_exit "The time keyword produces output when a timed command fails and the errexit option is on" \
529*6ba75e24SJohnothan King	"(got $(printf %q "$got"))"
530*6ba75e24SJohnothan King
531b30d1939SAndy Fiddamanexit $((Errors<125?Errors:125))
532