xref: /titanic_50/usr/src/lib/libshell/common/tests/subshell.sh (revision 3e14f97f673e8a630f076077de35afdd43dc1587)
17c2fbfb3SApril Chin########################################################################
27c2fbfb3SApril Chin#                                                                      #
37c2fbfb3SApril Chin#               This software is part of the ast package               #
4*3e14f97fSRoger A. Faulkner#          Copyright (c) 1982-2010 AT&T Intellectual Property          #
57c2fbfb3SApril Chin#                      and is licensed under the                       #
67c2fbfb3SApril Chin#                  Common Public License, Version 1.0                  #
77c2fbfb3SApril Chin#                    by AT&T Intellectual Property                     #
87c2fbfb3SApril Chin#                                                                      #
97c2fbfb3SApril Chin#                A copy of the License is available at                 #
107c2fbfb3SApril Chin#            http://www.opensource.org/licenses/cpl1.0.txt             #
117c2fbfb3SApril Chin#         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         #
127c2fbfb3SApril Chin#                                                                      #
137c2fbfb3SApril Chin#              Information and Software Systems Research               #
147c2fbfb3SApril Chin#                            AT&T Research                             #
157c2fbfb3SApril Chin#                           Florham Park NJ                            #
167c2fbfb3SApril Chin#                                                                      #
177c2fbfb3SApril Chin#                  David Korn <dgk@research.att.com>                   #
187c2fbfb3SApril Chin#                                                                      #
197c2fbfb3SApril Chin########################################################################
207c2fbfb3SApril Chinfunction err_exit
217c2fbfb3SApril Chin{
227c2fbfb3SApril Chin	print -u$Error_fd -n "\t"
237c2fbfb3SApril Chin	print -u$Error_fd -r ${Command}[$1]: "${@:2}"
247c2fbfb3SApril Chin	(( Errors+=1 ))
257c2fbfb3SApril Chin}
267c2fbfb3SApril Chinalias err_exit='err_exit $LINENO'
2734f9b3eeSRoland Mainz
287c2fbfb3SApril ChinCommand=${0##*/}
297c2fbfb3SApril Chininteger Errors=0 Error_fd=2
307c2fbfb3SApril Chin
3134f9b3eeSRoland Mainztmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; }
3234f9b3eeSRoland Mainztrap "cd /; rm -rf $tmp" EXIT
3334f9b3eeSRoland Mainz
3434f9b3eeSRoland Mainzbincat=$(PATH=$(getconf PATH) whence -p cat)
3534f9b3eeSRoland Mainz
367c2fbfb3SApril Chinz=()
377c2fbfb3SApril Chinz.foo=( [one]=hello [two]=(x=3 y=4) [three]=hi)
387c2fbfb3SApril Chinz.bar[0]=hello
397c2fbfb3SApril Chinz.bar[2]=world
407c2fbfb3SApril Chinz.bar[1]=(x=4 y=5)
417c2fbfb3SApril Chinval='(
427c2fbfb3SApril Chin	typeset -a bar=(
437c2fbfb3SApril Chin		[0]=hello
447c2fbfb3SApril Chin		[2]=world
457c2fbfb3SApril Chin		[1]=(
467c2fbfb3SApril Chin			x=4
477c2fbfb3SApril Chin			y=5
487c2fbfb3SApril Chin		)
497c2fbfb3SApril Chin	)
507c2fbfb3SApril Chin	typeset -A foo=(
517c2fbfb3SApril Chin		[one]=hello
527c2fbfb3SApril Chin		[three]=hi
537c2fbfb3SApril Chin		[two]=(
547c2fbfb3SApril Chin			x=3
557c2fbfb3SApril Chin			y=4
567c2fbfb3SApril Chin		)
577c2fbfb3SApril Chin	)
587c2fbfb3SApril Chin)'
597c2fbfb3SApril Chin[[ $z == "$val" ]] || err_exit 'compound variable with mixed arrays not working'
607c2fbfb3SApril Chinz.bar[1]=yesyes
617c2fbfb3SApril Chin[[ ${z.bar[1]} == yesyes ]] || err_exit 'reassign of index array compound variable fails'
627c2fbfb3SApril Chinz.bar[1]=(x=12 y=5)
637c2fbfb3SApril Chin[[ ${z.bar[1]} == $'(\n\tx=12\n\ty=5\n)' ]] || err_exit 'reassign array simple to compound variable fails'
647c2fbfb3SApril Chineval val="$z"
657c2fbfb3SApril Chin(
667c2fbfb3SApril Chin	z.foo[three]=good
677c2fbfb3SApril Chin	[[ ${z.foo[three]} == good ]] || err_exit 'associative array assignment in subshell not working'
687c2fbfb3SApril Chin)
697c2fbfb3SApril Chin[[ $z == "$val" ]] || err_exit 'compound variable changes after associative array assignment'
707c2fbfb3SApril Chineval val="$z"
717c2fbfb3SApril Chin(
727c2fbfb3SApril Chinfalse
737c2fbfb3SApril Chin	z.foo[two]=ok
747c2fbfb3SApril Chin	[[ ${z.foo[two]} == ok ]] || err_exit 'associative array assignment to compound variable in subshell not working'
757c2fbfb3SApril Chin	z.bar[1]=yes
767c2fbfb3SApril Chin	[[ ${z.bar[1]} == yes ]] || err_exit 'index array assignment to compound variable in subshell not working'
777c2fbfb3SApril Chin)
787c2fbfb3SApril Chin[[ $z == "$val" ]] || err_exit 'compound variable changes after associative array assignment'
797c2fbfb3SApril Chin
807c2fbfb3SApril Chinx=(
817c2fbfb3SApril Chin	foo=( qqq=abc rrr=def)
827c2fbfb3SApril Chin	bar=( zzz=no rst=fed)
837c2fbfb3SApril Chin)
847c2fbfb3SApril Chineval val="$x"
857c2fbfb3SApril Chin(
867c2fbfb3SApril Chin	unset x.foo
877c2fbfb3SApril Chin	[[ ${x.foo.qqq} ]] && err_exit 'x.foo.qqq should be unset'
887c2fbfb3SApril Chin	x.foo=good
897c2fbfb3SApril Chin	[[ ${x.foo} == good ]] || err_exit 'x.foo should be good'
907c2fbfb3SApril Chin)
917c2fbfb3SApril Chin[[ $x == "$val" ]] || err_exit 'compound variable changes after unset leaves'
927c2fbfb3SApril Chinunset l
937c2fbfb3SApril Chin(
947c2fbfb3SApril Chin	l=( a=1 b="BE" )
957c2fbfb3SApril Chin)
967c2fbfb3SApril Chin[[ ${l+foo} != foo ]] || err_exit 'l should be unset'
977c2fbfb3SApril Chin
987c2fbfb3SApril ChinError_fd=9
997c2fbfb3SApril Chineval "exec $Error_fd>&2 2>/dev/null"
1007c2fbfb3SApril Chin
1017c2fbfb3SApril ChinTEST_notfound=notfound
1027c2fbfb3SApril Chinwhile	whence $TEST_notfound >/dev/null 2>&1
1037c2fbfb3SApril Chindo	TEST_notfound=notfound-$RANDOM
1047c2fbfb3SApril Chindone
1057c2fbfb3SApril Chin
1067c2fbfb3SApril Chininteger BS=1024 nb=64 ss=60 bs no
1077c2fbfb3SApril Chinfor bs in $BS 1
1087c2fbfb3SApril Chindo	$SHELL -c '
1097c2fbfb3SApril Chin		{
1107c2fbfb3SApril Chin			sleep '$ss'
1117c2fbfb3SApril Chin			kill -KILL $$
1127c2fbfb3SApril Chin		} &
1137c2fbfb3SApril Chin		set -- $(printf %.'$(($BS*$nb))'c x | dd bs='$bs')
1147c2fbfb3SApril Chin		print ${#1}
1157c2fbfb3SApril Chin		kill $!
11634f9b3eeSRoland Mainz	' > $tmp/sub 2>/dev/null
11734f9b3eeSRoland Mainz	no=$(<$tmp/sub)
1187c2fbfb3SApril Chin	(( no == (BS * nb) )) || err_exit "shell hangs on command substitution output size >= $BS*$nb with write size $bs -- expected $((BS*nb)), got ${no:-0}"
1197c2fbfb3SApril Chindone
1207c2fbfb3SApril Chin# this time with redirection on the trailing command
1217c2fbfb3SApril Chinfor bs in $BS 1
1227c2fbfb3SApril Chindo	$SHELL -c '
1237c2fbfb3SApril Chin		{
1247c2fbfb3SApril Chin			sleep 2
1257c2fbfb3SApril Chin			sleep '$ss'
1267c2fbfb3SApril Chin			kill -KILL $$
1277c2fbfb3SApril Chin		} &
1287c2fbfb3SApril Chin		set -- $(printf %.'$(($BS*$nb))'c x | dd bs='$bs' 2>/dev/null)
1297c2fbfb3SApril Chin		print ${#1}
1307c2fbfb3SApril Chin		kill $!
13134f9b3eeSRoland Mainz	' > $tmp/sub 2>/dev/null
13234f9b3eeSRoland Mainz	no=$(<$tmp/sub)
1337c2fbfb3SApril Chin	(( no == (BS * nb) )) || err_exit "shell hangs on command substitution output size >= $BS*$nb with write size $bs and trailing redirection -- expected $((BS*nb)), got ${no:-0}"
1347c2fbfb3SApril Chindone
1357c2fbfb3SApril Chin
1367c2fbfb3SApril Chin# exercise command substitutuion trailing newline logic w.r.t. pipe vs. tmp file io
1377c2fbfb3SApril Chin
1387c2fbfb3SApril Chinset -- \
1397c2fbfb3SApril Chin	'post-line print'								\
1407c2fbfb3SApril Chin	'$TEST_unset; ($TEST_fork; print 1); print'					\
1417c2fbfb3SApril Chin	1										\
1427c2fbfb3SApril Chin	'pre-line print'								\
1437c2fbfb3SApril Chin	'$TEST_unset; ($TEST_fork; print); print 1'					\
1447c2fbfb3SApril Chin	$'\n1'										\
1457c2fbfb3SApril Chin	'multiple pre-line print'							\
1467c2fbfb3SApril Chin	'$TEST_unset; ($TEST_fork; print); print; ($TEST_fork; print 1); print'		\
1477c2fbfb3SApril Chin	$'\n\n1'									\
1487c2fbfb3SApril Chin	'multiple post-line print'							\
1497c2fbfb3SApril Chin	'$TEST_unset; ($TEST_fork; print 1); print; ($TEST_fork; print); print'		\
1507c2fbfb3SApril Chin	1										\
1517c2fbfb3SApril Chin	'intermediate print'								\
1527c2fbfb3SApril Chin	'$TEST_unset; ($TEST_fork; print 1); print; ($TEST_fork; print 2); print'	\
1537c2fbfb3SApril Chin	$'1\n\n2'									\
1547c2fbfb3SApril Chin	'simple variable'								\
1557c2fbfb3SApril Chin	'$TEST_unset; ($TEST_fork; l=2; print "$l"); print $l'				\
1567c2fbfb3SApril Chin	2										\
1577c2fbfb3SApril Chin	'compound variable'								\
1587c2fbfb3SApril Chin	'$TEST_unset; ($TEST_fork; l=(a=2 b="BE"); print "$l"); print $l'		\
1597c2fbfb3SApril Chin	$'(\n\ta=2\n\tb=BE\n)'								\
1607c2fbfb3SApril Chin
1617c2fbfb3SApril Chinexport TEST_fork TEST_unset
1627c2fbfb3SApril Chin
1637c2fbfb3SApril Chinwhile	(( $# >= 3 ))
1647c2fbfb3SApril Chindo	txt=$1
1657c2fbfb3SApril Chin	cmd=$2
1667c2fbfb3SApril Chin	exp=$3
1677c2fbfb3SApril Chin	shift 3
1687c2fbfb3SApril Chin	for TEST_unset in '' 'unset var'
1697c2fbfb3SApril Chin	do	for TEST_fork in '' 'ulimit -c 0'
1707c2fbfb3SApril Chin		do	for TEST_shell in "eval" "$SHELL -c"
1717c2fbfb3SApril Chin			do	if	! got=$($TEST_shell "$cmd")
1727c2fbfb3SApril Chin				then	err_exit "${TEST_shell/*-c/\$SHELL -c} ${TEST_unset:+unset }${TEST_fork:+fork }$txt print failed"
1737c2fbfb3SApril Chin				elif	[[ "$got" != "$exp" ]]
1747c2fbfb3SApril Chin				then	EXP=$(printf %q "$exp")
1757c2fbfb3SApril Chin					GOT=$(printf %q "$got")
1767c2fbfb3SApril Chin					err_exit "${TEST_shell/*-c/\$SHELL -c} ${TEST_unset:+unset }${TEST_fork:+fork }$txt command substitution failed -- expected $EXP, got $GOT"
1777c2fbfb3SApril Chin				fi
1787c2fbfb3SApril Chin			done
1797c2fbfb3SApril Chin		done
1807c2fbfb3SApril Chin	done
1817c2fbfb3SApril Chindone
1827c2fbfb3SApril Chin
1837c2fbfb3SApril Chinr=$( ($SHELL -c '
1847c2fbfb3SApril Chin	{
1857c2fbfb3SApril Chin		sleep 32
1867c2fbfb3SApril Chin		kill -KILL $$
1877c2fbfb3SApril Chin	} &
1887c2fbfb3SApril Chin	for v in $(set | sed "s/=.*//")
1897c2fbfb3SApril Chin	do	command unset $v
1907c2fbfb3SApril Chin	done
1917c2fbfb3SApril Chin	typeset -Z5 I
1927c2fbfb3SApril Chin	for ((I = 0; I < 1024; I++))
1937c2fbfb3SApril Chin	do	eval A$I=1234567890
1947c2fbfb3SApril Chin	done
1957c2fbfb3SApril Chin	a=$(set 2>&1)
1967c2fbfb3SApril Chin	print ok
1977c2fbfb3SApril Chin	kill -KILL $!
1987c2fbfb3SApril Chin') 2>/dev/null)
1997c2fbfb3SApril Chin[[ $r == ok ]] || err_exit "large subshell command substitution hangs"
2007c2fbfb3SApril Chin
2017c2fbfb3SApril Chinfor TEST_command in '' $TEST_notfound
2027c2fbfb3SApril Chindo	for TEST_exec in '' 'exec'
2037c2fbfb3SApril Chin	do	for TEST_fork in '' 'ulimit -c 0;'
2047c2fbfb3SApril Chin		do	for TEST_redirect in '' '>/dev/null'
2057c2fbfb3SApril Chin			do	for TEST_substitute in '' ': $'
2067c2fbfb3SApril Chin				do
2077c2fbfb3SApril Chin
2087c2fbfb3SApril Chin	TEST_test="$TEST_substitute($TEST_fork $TEST_exec $TEST_command $TEST_redirect)"
2097c2fbfb3SApril Chin	[[ $TEST_test == '('*([[:space:]])')' ]] && continue
2107c2fbfb3SApril Chin	r=$($SHELL -c '
2117c2fbfb3SApril Chin		{
2127c2fbfb3SApril Chin			sleep 2
2137c2fbfb3SApril Chin			kill -KILL $$
2147c2fbfb3SApril Chin		} &
2157c2fbfb3SApril Chin		'"$TEST_test"'
2167c2fbfb3SApril Chin		kill $!
2177c2fbfb3SApril Chin		print ok
2187c2fbfb3SApril Chin		')
2197c2fbfb3SApril Chin	[[ $r == ok ]] || err_exit "shell hangs on $TEST_test"
2207c2fbfb3SApril Chin
2217c2fbfb3SApril Chin				done
2227c2fbfb3SApril Chin			done
2237c2fbfb3SApril Chin		done
2247c2fbfb3SApril Chin	done
2257c2fbfb3SApril Chindone
2267c2fbfb3SApril Chin
22734f9b3eeSRoland Mainz$SHELL -c '( autoload xxxxx);print -n' ||  err_exit 'autoloaded functions in subshells can cause failure'
22834f9b3eeSRoland Mainzfoo=$($SHELL  <<- ++EOF++
22934f9b3eeSRoland Mainz	(trap 'print bar' EXIT;print -n foo)
23034f9b3eeSRoland Mainz	++EOF++
23134f9b3eeSRoland Mainz)
23234f9b3eeSRoland Mainz[[ $foo == foobar ]] || err_exit 'trap on exit when last commands is subshell is not triggered'
23334f9b3eeSRoland Mainz
23434f9b3eeSRoland Mainzerr=$(
23534f9b3eeSRoland Mainz	$SHELL  2>&1  <<- \EOF
23634f9b3eeSRoland Mainz	        date=$(whence -p date)
23734f9b3eeSRoland Mainz	        function foo
23834f9b3eeSRoland Mainz	        {
23934f9b3eeSRoland Mainz	                x=$( $date > /dev/null 2>&1 ;:)
24034f9b3eeSRoland Mainz	        }
24134f9b3eeSRoland Mainz		# consume almost all fds to push the test to the fd limit #
24234f9b3eeSRoland Mainz		integer max=$(ulimit --nofile)
24334f9b3eeSRoland Mainz		(( max -= 6 ))
24434f9b3eeSRoland Mainz		for ((i=20; i < max; i++))
24534f9b3eeSRoland Mainz		do	exec {i}>&1
24634f9b3eeSRoland Mainz		done
24734f9b3eeSRoland Mainz	        for ((i=0; i < 20; i++))
24834f9b3eeSRoland Mainz	        do      y=$(foo)
24934f9b3eeSRoland Mainz	        done
25034f9b3eeSRoland Mainz	EOF
25134f9b3eeSRoland Mainz) || {
25234f9b3eeSRoland Mainz	err=${err%%$'\n'*}
25334f9b3eeSRoland Mainz	err=${err#*:}
25434f9b3eeSRoland Mainz	err=${err##[[:space:]]}
25534f9b3eeSRoland Mainz	err_exit "nested command substitution with redirections failed -- $err"
25634f9b3eeSRoland Mainz}
25734f9b3eeSRoland Mainz
25834f9b3eeSRoland Mainzexp=0
25934f9b3eeSRoland Mainz$SHELL -c $'
26034f9b3eeSRoland Mainz	function foobar
26134f9b3eeSRoland Mainz	{
26234f9b3eeSRoland Mainz		print "hello world"
26334f9b3eeSRoland Mainz	}
26434f9b3eeSRoland Mainz	[[ $(getopts \'[+?X\ffoobar\fX]\' v --man 2>&1) == *"Xhello worldX"* ]]
26534f9b3eeSRoland Mainz	exit '$exp$'
26634f9b3eeSRoland Mainz'
26734f9b3eeSRoland Mainzgot=$?
26834f9b3eeSRoland Mainz[[ $got == $exp ]] || err_exit "getopts --man runtime callout with nonzero exit terminates shell -- expected '$exp', got '$got'"
26934f9b3eeSRoland Mainzexp=ok
27034f9b3eeSRoland Mainzgot=$($SHELL -c $'
27134f9b3eeSRoland Mainz	function foobar
27234f9b3eeSRoland Mainz	{
27334f9b3eeSRoland Mainz		print "hello world"
27434f9b3eeSRoland Mainz	}
27534f9b3eeSRoland Mainz	[[ $(getopts \'[+?X\ffoobar\fX]\' v --man 2>&1) == *"Xhello worldX"* ]]
27634f9b3eeSRoland Mainz	print '$exp$'
27734f9b3eeSRoland Mainz')
27834f9b3eeSRoland Mainz[[ $got == $exp ]] || err_exit "getopts --man runtime callout with nonzero exit terminates shell -- expected '$exp', got '$got'"
27934f9b3eeSRoland Mainz
28034f9b3eeSRoland Mainz# command substitution variations #
28134f9b3eeSRoland Mainzset -- \
28234f9b3eeSRoland Mainz	'$('			')'		\
28334f9b3eeSRoland Mainz	'${ '			'; }'		\
28434f9b3eeSRoland Mainz	'$(ulimit -c 0; '	')'		\
28534f9b3eeSRoland Mainz	'$( ('			') )'		\
28634f9b3eeSRoland Mainz	'${ ('			'); }'		\
28734f9b3eeSRoland Mainz	'`'			'`'		\
28834f9b3eeSRoland Mainz	'`('			')`'		\
28934f9b3eeSRoland Mainz	'`ulimit -c 0; '	'`'		\
29034f9b3eeSRoland Mainz	# end of table #
29134f9b3eeSRoland Mainzexp=ok
29234f9b3eeSRoland Mainztestcase[1]='
29334f9b3eeSRoland Mainz	if	%sexpr "NOMATCH" : ".*Z" >/dev/null%s
29434f9b3eeSRoland Mainz	then	print error
29534f9b3eeSRoland Mainz	else	print ok
29634f9b3eeSRoland Mainz	fi
29734f9b3eeSRoland Mainz	exit %s
29834f9b3eeSRoland Mainz'
29934f9b3eeSRoland Mainztestcase[2]='
30034f9b3eeSRoland Mainz	function bar
30134f9b3eeSRoland Mainz	{
30234f9b3eeSRoland Mainz		pipeout=%1$sprintf Ok | tr O o%2$s
30334f9b3eeSRoland Mainz		print $pipeout
30434f9b3eeSRoland Mainz		return 0
30534f9b3eeSRoland Mainz	}
30634f9b3eeSRoland Mainz	foo=%1$sbar%2$s || foo="exit status $?"
30734f9b3eeSRoland Mainz	print $foo
30834f9b3eeSRoland Mainz	exit %3$s
30934f9b3eeSRoland Mainz'
31034f9b3eeSRoland Mainzwhile	(( $# >= 2 ))
31134f9b3eeSRoland Mainzdo	for ((TEST=1; TEST<=${#testcase[@]}; TEST++))
31234f9b3eeSRoland Mainz	do	body=${testcase[TEST]}
31334f9b3eeSRoland Mainz		for code in 0 2
31434f9b3eeSRoland Mainz		do	got=${ printf "$body" "$1" "$2" "$code" | $SHELL 2>&1 }
31534f9b3eeSRoland Mainz			status=$?
31634f9b3eeSRoland Mainz			if	(( status != code ))
31734f9b3eeSRoland Mainz			then	err_exit "test $TEST '$1...$2 exit $code' failed -- exit status $status, expected $code"
31834f9b3eeSRoland Mainz			elif	[[ $got != $exp ]]
31934f9b3eeSRoland Mainz			then	err_exit "test $TEST '$1...$2 exit $code' failed -- got '$got', expected '$exp'"
32034f9b3eeSRoland Mainz			fi
32134f9b3eeSRoland Mainz		done
32234f9b3eeSRoland Mainz	done
32334f9b3eeSRoland Mainz	shift 2
32434f9b3eeSRoland Mainzdone
32534f9b3eeSRoland Mainz
32634f9b3eeSRoland Mainz# the next tests loop on all combinations of
32734f9b3eeSRoland Mainz#	{ SUB CAT INS TST APP } X { file-sizes }
32834f9b3eeSRoland Mainz# where the file size starts at 1Ki and doubles up to and including 1Mi
32934f9b3eeSRoland Mainz#
33034f9b3eeSRoland Mainz# the tests and timeouts are done in async subshells to prevent
33134f9b3eeSRoland Mainz# the test harness from hanging
33234f9b3eeSRoland Mainz
33334f9b3eeSRoland MainzSUB=(
33434f9b3eeSRoland Mainz	( BEG='$( '	END=' )'	)
33534f9b3eeSRoland Mainz	( BEG='${ '	END='; }'	)
33634f9b3eeSRoland Mainz)
33734f9b3eeSRoland MainzCAT=(  cat  $bincat  )
33834f9b3eeSRoland MainzINS=(  ""  "builtin cat; "  "builtin -d cat $bincat; "  ": > /dev/null; "  )
33934f9b3eeSRoland MainzAPP=(  ""  "; :"  )
34034f9b3eeSRoland MainzTST=(
34134f9b3eeSRoland Mainz	( CMD='print foo | $cat'			EXP=3		)
34234f9b3eeSRoland Mainz	( CMD='$cat < $tmp/lin'						)
34334f9b3eeSRoland Mainz	( CMD='cat $tmp/lin | $cat'					)
34434f9b3eeSRoland Mainz	( CMD='read v < $tmp/buf; print $v'		LIM=4*1024	)
34534f9b3eeSRoland Mainz	( CMD='cat $tmp/buf | read v; print $v'		LIM=4*1024	)
34634f9b3eeSRoland Mainz)
34734f9b3eeSRoland Mainz
34834f9b3eeSRoland Mainzcommand exec 3<> /dev/null
34934f9b3eeSRoland Mainzif	cat /dev/fd/3 >/dev/null 2>&1
35034f9b3eeSRoland Mainzthen	T=${#TST[@]}
35134f9b3eeSRoland Mainz	TST[T].CMD='$cat <(print foo)'
35234f9b3eeSRoland Mainz	TST[T].EXP=3
35334f9b3eeSRoland Mainzfi
35434f9b3eeSRoland Mainz
35534f9b3eeSRoland Mainz# prime the two data files to 512 bytes each
35634f9b3eeSRoland Mainz# $tmp/lin has newlines every 16 bytes and $tmp/buf has no newlines
35734f9b3eeSRoland Mainz# the outer loop doubles the file size at top
35834f9b3eeSRoland Mainz
35934f9b3eeSRoland Mainzbuf=$'1234567890abcdef'
36034f9b3eeSRoland Mainzlin=$'\n1234567890abcde'
36134f9b3eeSRoland Mainzfor ((i=0; i<5; i++))
36234f9b3eeSRoland Mainzdo	buf=$buf$buf
36334f9b3eeSRoland Mainz	lin=$lin$lin
36434f9b3eeSRoland Mainzdone
36534f9b3eeSRoland Mainzprint -n "$buf" > $tmp/buf
36634f9b3eeSRoland Mainzprint -n "$lin" > $tmp/lin
36734f9b3eeSRoland Mainz
36834f9b3eeSRoland Mainzunset SKIP
36934f9b3eeSRoland Mainzfor ((n=1024; n<=1024*1024; n*=2))
37034f9b3eeSRoland Mainzdo	cat $tmp/buf $tmp/buf > $tmp/tmp
37134f9b3eeSRoland Mainz	mv $tmp/tmp $tmp/buf
37234f9b3eeSRoland Mainz	cat $tmp/lin $tmp/lin > $tmp/tmp
37334f9b3eeSRoland Mainz	mv $tmp/tmp $tmp/lin
37434f9b3eeSRoland Mainz	for ((S=0; S<${#SUB[@]}; S++))
37534f9b3eeSRoland Mainz	do	for ((C=0; C<${#CAT[@]}; C++))
37634f9b3eeSRoland Mainz		do	cat=${CAT[C]}
37734f9b3eeSRoland Mainz			for ((I=0; I<${#INS[@]}; I++))
37834f9b3eeSRoland Mainz			do	for ((A=0; A<${#APP[@]}; A++))
37934f9b3eeSRoland Mainz				do	for ((T=0; T<${#TST[@]}; T++))
38034f9b3eeSRoland Mainz					do	#undent...#
38134f9b3eeSRoland Mainz
38234f9b3eeSRoland Mainz	if	[[ ! ${SKIP[S][C][I][A][T]} ]]
38334f9b3eeSRoland Mainz	then	eval "{ x=${SUB[S].BEG}${INS[I]}${TST[T].CMD}${APP[A]}${SUB[S].END}; print \${#x}; } >\$tmp/out &"
38434f9b3eeSRoland Mainz		m=$!
38534f9b3eeSRoland Mainz		{ sleep 4; kill -9 $m; } &
38634f9b3eeSRoland Mainz		k=$!
38734f9b3eeSRoland Mainz		wait $m
38834f9b3eeSRoland Mainz		h=$?
38934f9b3eeSRoland Mainz		kill -9 $k
39034f9b3eeSRoland Mainz		wait $k
39134f9b3eeSRoland Mainz		got=$(<$tmp/out)
39234f9b3eeSRoland Mainz		if	[[ ! $got ]] && (( h ))
39334f9b3eeSRoland Mainz		then	got=HUNG
39434f9b3eeSRoland Mainz		fi
39534f9b3eeSRoland Mainz		if	[[ ${TST[T].EXP} ]]
39634f9b3eeSRoland Mainz		then	exp=${TST[T].EXP}
39734f9b3eeSRoland Mainz		else	exp=$n
39834f9b3eeSRoland Mainz		fi
39934f9b3eeSRoland Mainz		if	[[ $got != $exp ]]
40034f9b3eeSRoland Mainz		then	# on failure skip similar tests on larger files sizes #
40134f9b3eeSRoland Mainz			SKIP[S][C][I][A][T]=1
40234f9b3eeSRoland Mainz			siz=$(printf $'%#i' $exp)
40334f9b3eeSRoland Mainz			cmd=${TST[T].CMD//\$cat/$cat}
40434f9b3eeSRoland Mainz			cmd=${cmd//\$tmp\/buf/$siz.buf}
40534f9b3eeSRoland Mainz			cmd=${cmd//\$tmp\/lin/$siz.lin}
40634f9b3eeSRoland Mainz			err_exit "'x=${SUB[S].BEG}${INS[I]}${cmd}${APP[A]}${SUB[S].END} && print \${#x}' failed -- expected '$exp', got '$got'"
40734f9b3eeSRoland Mainz		elif	[[ ${TST[T].EXP} ]] || (( TST[T].LIM >= n ))
40834f9b3eeSRoland Mainz		then	SKIP[S][C][I][A][T]=1
40934f9b3eeSRoland Mainz		fi
41034f9b3eeSRoland Mainz	fi
41134f9b3eeSRoland Mainz
41234f9b3eeSRoland Mainz						#...indent#
41334f9b3eeSRoland Mainz					done
41434f9b3eeSRoland Mainz				done
41534f9b3eeSRoland Mainz			done
41634f9b3eeSRoland Mainz		done
41734f9b3eeSRoland Mainz	done
41834f9b3eeSRoland Mainzdone
41934f9b3eeSRoland Mainz
42034f9b3eeSRoland Mainz# specifics -- there's more?
42134f9b3eeSRoland Mainz
42234f9b3eeSRoland Mainz{
42334f9b3eeSRoland Mainz	cmd='{ exec 5>/dev/null; print "$(eval ls -d . 2>&1 1>&5)"; } >$tmp/out &'
42434f9b3eeSRoland Mainz	eval $cmd
42534f9b3eeSRoland Mainz	m=$!
42634f9b3eeSRoland Mainz	{ sleep 4; kill -9 $m; } &
42734f9b3eeSRoland Mainz	k=$!
42834f9b3eeSRoland Mainz	wait $m
42934f9b3eeSRoland Mainz	h=$?
43034f9b3eeSRoland Mainz	kill -9 $k
43134f9b3eeSRoland Mainz	wait $k
43234f9b3eeSRoland Mainz	got=$(<$tmp/out)
43334f9b3eeSRoland Mainz} 2>/dev/null
43434f9b3eeSRoland Mainzexp=''
43534f9b3eeSRoland Mainzif	[[ ! $got ]] && (( h ))
43634f9b3eeSRoland Mainzthen	got=HUNG
43734f9b3eeSRoland Mainzfi
43834f9b3eeSRoland Mainzif	[[ $got != $exp ]]
43934f9b3eeSRoland Mainzthen	err_exit "eval '$cmd' failed -- expected '$exp', got '$got'"
44034f9b3eeSRoland Mainzfi
44134f9b3eeSRoland Mainz
44234f9b3eeSRoland Mainzfloat t1=$SECONDS
44334f9b3eeSRoland Mainzsleep=$(whence -p sleep)
44434f9b3eeSRoland Mainzif	[[ $sleep ]]
44534f9b3eeSRoland Mainzthen
44634f9b3eeSRoland Mainz	$SHELL -c "( $sleep 5 </dev/null >/dev/null 2>&1 & );exit 0" | cat
44734f9b3eeSRoland Mainz	(( (SECONDS-t1) > 4 )) && err_exit '/bin/sleep& in subshell hanging'
44834f9b3eeSRoland Mainz	((t1=SECONDS))
44934f9b3eeSRoland Mainzfi
45034f9b3eeSRoland Mainz$SHELL -c '( sleep 5 </dev/null >/dev/null 2>&1 & );exit 0' | cat
45134f9b3eeSRoland Mainz(( (SECONDS-t1) > 4 )) && err_exit 'sleep& in subshell hanging'
45234f9b3eeSRoland Mainz
453*3e14f97fSRoger A. Faulknerexp=HOME=$HOME
454*3e14f97fSRoger A. Faulkner( HOME=/bin/sh )
455*3e14f97fSRoger A. Faulknergot=$(env | grep ^HOME=)
456*3e14f97fSRoger A. Faulkner[[ $got == "$exp" ]] ||  err_exit "( HOME=/bin/sh ) cleanup failed -- expected '$exp', got '$got'"
457*3e14f97fSRoger A. Faulkner
458*3e14f97fSRoger A. Faulknercmd='echo $((case x in x)echo ok;esac);:)'
459*3e14f97fSRoger A. Faulknerexp=ok
460*3e14f97fSRoger A. Faulknergot=$($SHELL -c "$cmd" 2>&1)
461*3e14f97fSRoger A. Faulkner[[ $got == "$exp" ]] ||  err_exit "'$cmd' failed -- expected '$exp', got '$got'"
462*3e14f97fSRoger A. Faulkner
463*3e14f97fSRoger A. Faulknercmd='eval "for i in 1 2; do eval /bin/echo x; done"'
464*3e14f97fSRoger A. Faulknerexp=$'x\nx'
465*3e14f97fSRoger A. Faulknergot=$($SHELL -c "$cmd")
466*3e14f97fSRoger A. Faulknerif	[[ $got != "$exp" ]]
467*3e14f97fSRoger A. Faulknerthen	EXP=$(printf %q "$exp")
468*3e14f97fSRoger A. Faulkner	GOT=$(printf %q "$got")
469*3e14f97fSRoger A. Faulkner	err_exit "'$cmd' failed -- expected $EXP, got $GOT"
470*3e14f97fSRoger A. Faulknerfi
471*3e14f97fSRoger A. Faulkner
4727c2fbfb3SApril Chinexit $Errors
473