1
0
Fork 0
mirror of git://git.code.sf.net/p/cdesktopenv/code synced 2025-03-09 15:50:02 +00:00

shtests: More speedups; also fix xtrace (re: 734e5953)

This reduces a bunch more unnecessarily long sleeps to give
asynchronous processes time to run, etc. (No, we don't need to be
compatible anymore with your cool 1985 Intel 80386DX 16 MHz
battlestation...) Running the test suite is almost tolerable now,
making me much more likely to actually run the regression test
suite and catch my own regressions.

In addition, there are various fixes to make the test suite
compatible with 'set -x' ('set -o xtrace') so that you can now
actually *use* the documented 'bin/shtests -x' option. Recommend
combining with '-p' to avoid tracing everything three times.

I've also added a really useful $PS4 trace prompt to shtests that
traces pretty much everything there is to trace. (It does use
expansions that modify ${.sh.match}, which affected several tests,
particularly in tests/substring.sh; for those we need to set a
temporary simpler $PS4.)

(cherry picked from commit c3a5d47cfe880b526cabb5370ddaced0e8626acd)
This commit is contained in:
Martijn Dekker 2020-06-08 23:02:26 +02:00
parent ba1f2ba9c3
commit 712261c89b
15 changed files with 178 additions and 120 deletions

View file

@ -38,6 +38,13 @@ tmp=$(
trap 'cd / && rm -rf "$tmp"' EXIT
bincat=$(whence -p cat)
binecho=$(whence -p echo)
# make an external 'sleep' command that supports fractional seconds
binsleep=$tmp/.sleep.sh # hide to exclude from simple wildcard expansion
cat >"$binsleep" <<EOF
#!$SHELL
sleep "\$@"
EOF
chmod +x "$binsleep"
# test basic file operations like redirection, pipes, file expansion
set -- \
@ -146,7 +153,7 @@ cd ../../tmp || err_exit "cd ../../tmp failed"
if [[ $PWD != /tmp ]]
then err_exit 'cd ../../tmp is not /tmp'
fi
( sleep 2; cat <<!
( sleep .2; cat <<!
foobar
!
) | cat > $tmp/foobar &
@ -294,7 +301,7 @@ if [[ $(for i in foo bar
then err_exit 'for loop subshell optimizer bug'
fi
unset a1
optbug()
function optbug
{
set -A a1 foo bar bam
integer i
@ -307,15 +314,15 @@ optbug()
done
return 1
}
optbug || err_exit 'array size optimzation bug'
optbug || err_exit 'array size optimization bug'
wait # not running --pipefail which would interfere with subsequent tests
: $(jobs -p) # required to clear jobs for next jobs -p (interactive side effect)
sleep 20 &
sleep 2 &
pids=$!
if [[ $(jobs -p) != $! ]]
then err_exit 'jobs -p not reporting a background job'
fi
sleep 20 &
sleep 2 &
pids="$pids $!"
foo()
{
@ -325,8 +332,8 @@ foo()
foo
kill $pids
[[ $( (trap 'print alarm' ALRM; sleep 4) & sleep 2; kill -ALRM $!; sleep 2; wait) == alarm ]] || err_exit 'ALRM signal not working'
[[ $($SHELL -c 'trap "" HUP; $SHELL -c "(sleep 2;kill -HUP $$)& sleep 4;print done"') != done ]] && err_exit 'ignored traps not being ignored'
[[ $( (trap 'print alarm' ALRM; sleep .4) & sleep .2; kill -ALRM $!; sleep .2; wait) == alarm ]] || err_exit 'ALRM signal not working'
[[ $($SHELL -c 'trap "" HUP; $SHELL -c "(sleep .2;kill -HUP $$)& sleep .4;print done"') != done ]] && err_exit 'ignored traps not being ignored'
[[ $($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'
command exec 3<> /dev/null
if cat /dev/fd/3 >/dev/null 2>&1 || whence mkfifo > /dev/null
@ -372,9 +379,9 @@ chmod +x $tmp/scriptx
cat > $tmp/scriptx <<- \EOF
myfilter() { x=$(print ok | cat); print -r -- $SECONDS;}
set -o pipefail
sleep 3 | myfilter
sleep .3 | myfilter
EOF
(( $($SHELL $tmp/scriptx) > 2.0 )) && err_exit 'command substitution causes pipefail option to hang'
(( $($SHELL $tmp/scriptx) > .2 )) && err_exit 'command substitution causes pipefail option to hang'
exec 3<&-
( typeset -r foo=bar) 2> /dev/null || err_exit 'readonly variables set in a subshell cannot unset'
$SHELL -c 'x=${ print hello;}; [[ $x == hello ]]' 2> /dev/null || err_exit '${ command;} not supported'
@ -418,7 +425,7 @@ unset foo
unset foo
foo=$(false) > /dev/null && err_exit 'failed command substitution with redirection not returning false'
expected=foreback
got=$(print -n fore; (sleep 2;print back)&)
got=$(print -n fore; (sleep .2;print back)&)
[[ $got == $expected ]] || err_exit "command substitution background process output error -- got '$got', expected '$expected'"
binfalse=$(whence -p false)
@ -430,19 +437,20 @@ done
if env x-a=y >/dev/null 2>&1
then [[ $(env 'x-a=y' $SHELL -c 'env | grep x-a') == *x-a=y* ]] || err_exit 'invalid environment variables not preserved'
fi
float s=SECONDS
sleep=$(whence -p sleep)
for i in 1 2
for i in .1 .2
do print $i
done | while read sec; do ( $sleep $sec; $sleep $sec) done
(( (SECONDS-s) < 4)) && err_exit '"command | while read...done" finishing too fast'
done | while read sec; do ( "$binsleep" "$sec"; "$binsleep" "$sec") done
(( (SECONDS-s) < .4)) && err_exit '"command | while read...done" finishing too fast'
s=SECONDS
set -o pipefail
for ((i=0; i < 30; i++))
do print hello 2>/dev/null
sleep .1
done | $sleep 1
(( (SECONDS-s) < 2 )) || err_exit 'early termination not causing broken pipe'
sleep .01
done | "$binsleep" .1
(( (SECONDS-s) < .2 )) || err_exit 'early termination not causing broken pipe'
[[ $({ trap 'print trap' 0; print -n | $(whence -p cat); } & wait $!) == trap ]] || err_exit 'trap on exit not getting triggered'
var=$({ trap 'print trap' ERR; print -n | $binfalse; } & wait $!)
[[ $var == trap ]] || err_exit 'trap on ERR not getting triggered'
@ -479,28 +487,28 @@ set -o pipefail
float start=$SECONDS end
for ((i=0; i < 2; i++))
do print foo 2>/dev/null
sleep 1.5
sleep .15
done | { read; $bintrue; end=$SECONDS ;}
(( (SECONDS-start) < 1 )) && err_exit "pipefail not waiting for pipe to finish"
(( (SECONDS-start) < .1 )) && err_exit "pipefail not waiting for pipe to finish"
set +o pipefail
(( (SECONDS-end) > 2 )) && err_exit "pipefail causing $bintrue to wait for other end of pipe"
(( (SECONDS-end) > .2 )) && err_exit "pipefail causing $bintrue to wait for other end of pipe"
{ env A__z=C+SHLVL $SHELL -c : ;} 2> /dev/null || err_exit "SHLVL with wrong attribute fails"
if [[ $bintrue ]]
then float t0=SECONDS
{ time sleep 1.5 | $bintrue ;} 2> /dev/null
(( (SECONDS-t0) < 1 )) && err_exit 'time not waiting for pipeline to complete'
{ time sleep .15 | $bintrue ;} 2> /dev/null
(( (SECONDS-t0) < .1 )) && err_exit 'time not waiting for pipeline to complete'
fi
cat > $tmp/foo.sh <<- \EOF
eval "cat > /dev/null < /dev/null"
sleep 1
sleep .1
EOF
float sec=SECONDS
. $tmp/foo.sh | cat > /dev/null
(( (SECONDS-sec) < .7 )) && err_exit '. script does not restore output redirection with eval'
(( (SECONDS-sec) < .07 )) && err_exit '. script does not restore output redirection with eval'
file=$tmp/foobar
builtin cat

View file

@ -130,7 +130,7 @@ fi
if [[ ! -w /dev/fd/2 ]]
then err_exit "/dev/fd/2 not open for writing"
fi
sleep 1
sleep .01
> $newer_file
if [[ ! $file -ot $newer_file ]]
then err_exit "$file should be older than $newer_file"
@ -235,10 +235,10 @@ done
rm -rf $file
{
[[ -N $file ]] && err_exit 'test -N $tmp/*: st_mtime>st_atime after creat'
sleep 2
sleep .02
print 'hello world'
[[ -N $file ]] || err_exit 'test -N $tmp/*: st_mtime<=st_atime after write'
sleep 2
sleep .02
read
[[ -N $file ]] && err_exit 'test -N $tmp/*: st_mtime>st_atime after read'
} > $file < $file

View file

@ -385,7 +385,7 @@ do arg=$1 val=$2 code=$3
shift 3
for fmt in '%d' '%g'
do out=$(printf "$fmt" "$arg" 2>/dev/null)
err=$(printf "$fmt" "$arg" 2>&1 >/dev/null)
err=$(set +x; printf "$fmt" "$arg" 2>&1 >/dev/null)
printf "$fmt" "$arg" >/dev/null 2>&1
ret=$?
[[ $out == $val ]] || err_exit "printf $fmt $arg failed -- expected '$val', got '$out'"

View file

@ -109,7 +109,7 @@ do
$cat |&
!
chmod +x $file
sleep 10 |&
sleep 1 |&
$file 2> /dev/null || err_exit "parent $cat coprocess prevents script coprocess"
exec 5<&p 6>&p
exec 5<&- 6>&-
@ -119,15 +119,15 @@ do
cop=$!
exp=Done
print -p $'print hello | '$cat$'\nprint '$exp
read -t 5 -p
read -t 5 -p
read -t 1 -p
read -t 1 -p
got=$REPLY
if [[ $got != $exp ]]
then err_exit "${SHELL-ksh} $cat coprocess io failed -- got '$got', expected '$exp'"
fi
exec 5<&p 6>&p
exec 5<&- 6>&-
{ sleep 4; kill $cop; } 2>/dev/null &
{ sleep .4; kill $cop; } 2>/dev/null &
spy=$!
if wait $cop 2>/dev/null
then kill $spy 2>/dev/null
@ -140,15 +140,15 @@ do
echo line2 | grep 'line1'
} |&
SECONDS=0 count=0
while read -p -t 10 line
while read -p -t 1 line
do ((count++))
done
if (( SECONDS > 8 ))
if (( SECONDS > .8 ))
then err_exit "$cat coprocess read -p hanging (SECONDS=$SECONDS count=$count)"
fi
wait $!
( sleep 3 |& sleep 1 && kill $!; sleep 1; sleep 3 |& sleep 1 && kill $! ) ||
( sleep .3 |& sleep .1 && kill $!; sleep .1; sleep .3 |& sleep .1 && kill $! ) ||
err_exit "$cat coprocess cleanup not working correctly"
{ : |& } 2>/dev/null ||
err_exit "subshell $cat coprocess lingers in parent"
@ -166,7 +166,7 @@ do
wait $!
done
print
) 2>/dev/null | read -t 10 r
) 2>/dev/null | read -t 1 r
[[ $r == $e ]] || err_exit "$cat coprocess timing bug -- expected $e, got '$r'"
r=
@ -174,21 +174,21 @@ do
integer i
for ((i = 1; i <= N; i++))
do print $i |&
sleep 0.01
sleep 0.001
r=$r$($cat <&p)
wait $!
done
print $r
) 2>/dev/null | read -t 10 r
) 2>/dev/null | read -t 1 r
[[ $r == $e ]] || err_exit "$cat coprocess command substitution bug -- expected $e, got '$r'"
(
$cat |&
sleep 0.01
sleep 0.001
exec 6>&p
print -u6 ok
exec 6>&-
sleep 2
sleep .2
kill $! 2> /dev/null
) && err_exit "$cat coprocess with subshell would hang"
for sig in IOT ABRT
@ -198,12 +198,12 @@ do
pid=\$!
trap "print TRAP" \$sig
(
sleep 2
sleep .2
kill -\$sig \$\$
sleep 2
sleep .2
kill -\$sig \$\$
kill \$pid
sleep 2
sleep .2
kill \$\$
) &
while read -p || ((\$? > 256))
@ -218,7 +218,7 @@ do
done
trap 'sleep_pid=; kill $pid; err_exit "$cat coprocess 1 hung"' TERM
{ sleep 5; kill $$; } &
{ sleep .5; kill $$; } &
sleep_pid=$!
$cat |&
pid=$!
@ -232,7 +232,7 @@ do
[[ $sleep_pid ]] && kill $sleep_pid
trap 'sleep_pid=; kill $pid; err_exit "$cat coprocess 2 hung"' TERM
{ sleep 5; kill $$; } &
{ sleep .5; kill $$; } &
sleep_pid=$!
$cat |&
pid=$!
@ -244,7 +244,7 @@ do
[[ $sleep_pid ]] && kill $sleep_pid
trap 'sleep_pid=; kill $pid; err_exit "$cat coprocess 3 hung"' TERM
{ sleep 5; kill $$; } &
{ sleep .5; kill $$; } &
sleep_pid=$!
$cat |&
pid=$!

View file

@ -981,10 +981,17 @@ function _Dbg_debug_trap_handler
done
}
(
: 'Disabling xtrace while running _Dbg_* functions'
set +x # TODO: the _Dbg_* functions are incompatible with xtrace. To expose the regression
# test failures, run 'bin/shtests -x -p functions'. Is this a bug in ksh?
((baseline=LINENO+2))
trap '_Dbg_debug_trap_handler' DEBUG
. $tmp/debug foo bar
trap '' DEBUG
exit $Errors
)
Errors=$?
caller() {
integer .level=.sh.level .max=.sh.level-1

View file

@ -99,6 +99,7 @@ fi
# 2004-11-25 ancient /dev/fd/N redirection bug fix
got=$(
set +x
{
print -n 1
print -n 2 > ${FDFS[fdfs].dir}/2
@ -338,16 +339,16 @@ read -n3 a <<!
abcdefg
!
[[ $a == abc ]] || err_exit 'read -n3 here-document not working'
(print -n a; sleep 1; print -n bcde) | { read -N3 a; read -N1 b;}
(print -n a; sleep .1; print -n bcde) | { read -N3 a; read -N1 b;}
[[ $a == abc ]] || err_exit 'read -N3 from pipe not working'
[[ $b == d ]] || err_exit 'read -N1 from pipe not working'
(print -n a; sleep 1; print -n bcde) 2>/dev/null |read -n3 a
(print -n a; sleep .1; print -n bcde) 2>/dev/null |read -n3 a
[[ $a == a ]] || err_exit 'read -n3 from pipe not working'
if mkfifo $tmp/fifo 2> /dev/null
then (print -n a; sleep 2; print -n bcde) > $tmp/fifo &
then (print -n a; sleep .2; print -n bcde) > $tmp/fifo &
{
read -u5 -n3 -t3 a || err_exit 'read -n3 from fifo timed out'
read -u5 -n1 -t3 b || err_exit 'read -n1 from fifo timed out'
read -u5 -n3 -t1 a || err_exit 'read -n3 from fifo timed out'
read -u5 -n1 -t1 b || err_exit 'read -n1 from fifo timed out'
} 5< $tmp/fifo
exp=a
got=$a
@ -358,10 +359,10 @@ then (print -n a; sleep 2; print -n bcde) > $tmp/fifo &
rm -f $tmp/fifo
wait
mkfifo $tmp/fifo 2> /dev/null
(print -n a; sleep 2; print -n bcde) > $tmp/fifo &
(print -n a; sleep .2; print -n bcde) > $tmp/fifo &
{
read -u5 -N3 -t3 a || err_exit 'read -N3 from fifo timed out'
read -u5 -N1 -t3 b || err_exit 'read -N1 from fifo timed out'
read -u5 -N3 -t1 a || err_exit 'read -N3 from fifo timed out'
read -u5 -N1 -t1 b || err_exit 'read -N1 from fifo timed out'
} 5< $tmp/fifo
exp=abc
got=$a
@ -373,16 +374,16 @@ then (print -n a; sleep 2; print -n bcde) > $tmp/fifo &
fi
(
print -n 'prompt1: '
sleep .1
sleep .01
print line2
sleep .1
sleep .01
print -n 'prompt2: '
sleep .1
sleep .01
) | {
read -t2 -n 1000 line1
read -t2 -n 1000 line2
read -t2 -n 1000 line3
read -t2 -n 1000 line4
read -t1 -n 1000 line1
read -t1 -n 1000 line2
read -t1 -n 1000 line3
read -t1 -n 1000 line4
}
[[ $? == 0 ]] && err_exit 'should have timed out'
[[ $line1 == 'prompt1: ' ]] || err_exit "line1 should be 'prompt1: '"
@ -410,7 +411,7 @@ do a=$1
shift 4
for ((i = 0; i < 2; i++))
do for lc_all in C $lc_utf8
do g=$(LC_ALL=$lc_all $SHELL -c "{ print -n '$a'; sleep 0.2; print -n '$b'; sleep 0.2; } | { read ${o[i]} a; print -n \$a; read a; print -n \ \$a; }")
do g=$(LC_ALL=$lc_all $SHELL -c "{ print -n '$a'; sleep .02; print -n '$b'; sleep .02; } | { read ${o[i]} a; print -n \$a; read a; print -n \ \$a; }")
[[ $g == "${e[i]}" ]] || err_exit "LC_ALL=$lc_all read ${o[i]} from pipe '$a $b' failed -- expected '${e[i]}', got '$g'"
done
done
@ -437,12 +438,14 @@ then export LC_ALL=$lc_utf8
fi
fi
exec 3<&2
file=$tmp/file
(
: disabling xtrace so we can redirect stderr for this test
set +x
redirect 5>$file 2>&5
print -u5 -f 'This is a test\n'
print -u2 OK
exec 2<&3
)
exp=$'This is a test\nOK'
got=$(< $file)
[[ $got == $exp ]] || err_exit "output garbled when stderr is duped -- expected $(printf %q "$exp"), got $(printf %q "$got")"

View file

@ -200,11 +200,11 @@ got="$(<out)"
# multibyte identifiers
exp=OK
got=$(LC_ALL=C.UTF-8 $SHELL -c $'\u[5929]=OK; print ${\u[5929]}' 2>&1)
got=$(set +x; LC_ALL=C.UTF-8 $SHELL -c $'\u[5929]=OK; print ${\u[5929]}' 2>&1)
[[ $got == "$exp" ]] || err_exit "multibyte variable definition/expansion failed -- expected '$exp', got '$got'"
got=$(LC_ALL=C.UTF-8 $SHELL -c $'function \u[5929]\n{\nprint OK;\n}; \u[5929]' 2>&1)
got=$(set +x; LC_ALL=C.UTF-8 $SHELL -c $'function \u[5929]\n{\nprint OK;\n}; \u[5929]' 2>&1)
[[ $got == "$exp" ]] || err_exit "multibyte ksh function definition/execution failed -- expected '$exp', got '$got'"
got=$(LC_ALL=C.UTF-8 $SHELL -c $'\u[5929]()\n{\nprint OK;\n}; \u[5929]' 2>&1)
got=$(set +x; LC_ALL=C.UTF-8 $SHELL -c $'\u[5929]()\n{\nprint OK;\n}; \u[5929]' 2>&1)
[[ $got == "$exp" ]] || err_exit "multibyte posix function definition/execution failed -- expected '$exp', got '$got'"
# this locale is supported by ast on all platforms

View file

@ -73,7 +73,7 @@ then
got=$(printf %q "$got")
err_exit "\$ENV file &>/dev/null does not redirect stdout -- expected '', got $got"
fi
got=$($SHELL -E -c : 2>&1 >/dev/null)
got=$(set +x; $SHELL -E -c : 2>&1 >/dev/null)
if [[ $got != *nonstandard* || $got == *$'\n'* ]]
then
got=$(printf %q "$got")
@ -151,11 +151,11 @@ then
else
[[ $(print env_hit | HOME=$tmp $SHELL 2>&1) == "OK" ]] &&
err_exit 'nointeractive shell reads $HOME/.kshrc file'
[[ $(print env_hit | HOME=$tmp $SHELL -E 2>&1) == "OK" ]] ||
[[ $(set +x; print env_hit | HOME=$tmp $SHELL -E 2>&1) == "OK" ]] ||
err_exit '-E ignores $HOME/.kshrc file'
[[ $(print env_hit | HOME=$tmp $SHELL +E 2>&1) == "OK" ]] &&
err_exit '+E reads $HOME/.kshrc file'
[[ $(print env_hit | HOME=$tmp $SHELL --rc 2>&1) == "OK" ]] ||
[[ $(set +x; print env_hit | HOME=$tmp $SHELL --rc 2>&1) == "OK" ]] ||
err_exit '--rc ignores $HOME/.kshrc file'
[[ $(print env_hit | HOME=$tmp $SHELL --norc 2>&1) == "OK" ]] &&
err_exit '--norc reads $HOME/.kshrc file'
@ -368,7 +368,7 @@ pipeline=(
( nopipefail=1 pipefail=1 command='true|true|false' )
( nopipefail=1 pipefail=1 command='false|false|false' )
( nopipefail=0 pipefail=0 command='true|true|true' )
( nopipefail=0 pipefail=0 command='print hi|(sleep 1;"$bincat")>/dev/null' )
( nopipefail=0 pipefail=0 command='print hi|(sleep .1;"$bincat")>/dev/null' )
)
set --nopipefail
for ((i = 0; i < ${#pipeline[@]}; i++ ))
@ -443,10 +443,10 @@ export ENV= PS1="(:$$:)"
histfile=$tmp/history
exp=$(HISTFILE=$histfile $SHELL -c $'function foo\n{\ncat\n}\ntype foo')
for var in HISTSIZE HISTFILE
do got=$( ( HISTFILE=$histfile $SHELL +E -ic $'unset '$var$'\nfunction foo\n{\ncat\n}\ntype foo\nexit' ) 2>&1 )
do got=$( set +x; ( HISTFILE=$histfile $SHELL +E -ic $'unset '$var$'\nfunction foo\n{\ncat\n}\ntype foo\nexit' ) 2>&1 )
got=${got##*"$PS1"}
[[ $got == "$exp" ]] || err_exit "function definition inside (...) with $var unset fails -- got '$got', expected '$exp'"
got=$( { HISTFILE=$histfile $SHELL +E -ic $'unset '$var$'\nfunction foo\n{\ncat\n}\ntype foo\nexit' ;} 2>&1 )
got=$( set +x; { HISTFILE=$histfile $SHELL +E -ic $'unset '$var$'\nfunction foo\n{\ncat\n}\ntype foo\nexit' ;} 2>&1 )
got=${got##*"$PS1"}
[[ $got == "$exp" ]] || err_exit "function definition inside {...;} with $var unset fails -- got '$got', expected '$exp'"
done

View file

@ -342,7 +342,7 @@ function foo
# whence -q bug fix
$SHELL -c 'whence -q cat' & pid=$!
sleep 3
sleep .1
kill $! 2> /dev/null && err_exit 'whence -q appears to be hung'
FPATH=$PWD

View file

@ -207,7 +207,7 @@ done
shift $OPTIND-1
if (( debug )) || [[ $trace ]]
then export PS4=':$LINENO: '
then export PS4='+ [${SECONDS:+${SECONDS%????}s|}${.sh.subshell:+S${.sh.subshell},}${.sh.file:+${.sh.file#${.sh.file%/*/*}/},}${.sh.fun:+${.sh.fun},}${LINENO:+L$LINENO,}e$?] '
if (( debug ))
then set -x
fi

View file

@ -26,7 +26,7 @@ function err_exit
alias err_exit='err_exit $LINENO'
float DELAY=${1:-0.2}
float DELAY=${1:-0.02}
integer FOREGROUND=10 BACKGROUND=2 Errors=0
tmp=$(
@ -82,7 +82,7 @@ then
integer running=0 maxrunning=0
trap "((running--))" CHLD
for ((i=0; i<JOBCOUNT; i++))
do sleep 1 &
do sleep .1 &
if ((++running > maxrunning))
then ((maxrunning=running))
fi
@ -101,13 +101,13 @@ then
unset proc[\$!]
" CHLD
{ sleep 3; print a; exit 1; } &
{ sleep .3; print a; exit 1; } &
proc[$!]=( name=a status=1 )
{ sleep 2; print b; exit 2; } &
{ sleep .2; print b; exit 2; } &
proc[$!]=( name=b status=2 )
{ sleep 1; print c; exit 3; } &
{ sleep .1; print c; exit 3; } &
proc[$!]=( name=c status=3 )
while (( ${#proc[@]} ))
@ -120,8 +120,8 @@ then
fi
{
got=$( ( sleep 1;print $'\n') | $SHELL -c 'function handler { : ;}
trap handler CHLD; sleep .3 & IFS= read; print good')
got=$( ( sleep .1;print $'\n') | $SHELL -c 'function handler { : ;}
trap handler CHLD; sleep .03 & IFS= read; print good')
} 2> /dev/null
[[ $got == good ]] || err_exit 'SIGCLD handler effects read behavior'
@ -129,9 +129,9 @@ set -- $(
(
$SHELL -xc $'
trap \'wait $!; print $! $?\' CHLD
{ sleep 0.1; exit 9; } &
{ sleep 0.01; exit 9; } &
print $!
sleep 0.5
sleep 0.05
'
) 2>/dev/null; print $?
)
@ -155,11 +155,11 @@ done
(( d==2000 )) || err_exit "trap '' CHLD causes side effects d=$d"
trap - CHLD
x=$($SHELL 2> /dev/null -ic '/dev/null/notfound; sleep .5 & sleep 1;jobs')
x=$($SHELL 2> /dev/null -ic '/dev/null/notfound; sleep .05 & sleep .1;jobs')
[[ $x == *Done* ]] || err_exit 'SIGCHLD blocked after notfound'
x=$($SHELL 2> /dev/null -ic 'kill -0 12345678901234567876; sleep .5 & sleep 1;jobs')
x=$($SHELL 2> /dev/null -ic 'kill -0 12345678901234567876; sleep .05 & sleep .1;jobs')
[[ $x == *Done* ]] || err_exit 'SIGCHLD blocked after error message'
print 'set -o monitor;sleep .5 & sleep 1;jobs' > $tmp/foobar
print 'set -o monitor;sleep .05 & sleep .1;jobs' > $tmp/foobar
chmod +x $tmp/foobar
x=$($SHELL -c "echo | $tmp/foobar")
[[ $x == *Done* ]] || err_exit 'SIGCHLD blocked for script at end of pipeline'

View file

@ -56,7 +56,8 @@ do if ! n=$(kill -l $s 2>/dev/null)
done
(
set --pipefail
: disabling xtrace for this test
set +x --pipefail
{
$SHELL 2> out2 <<- \EOF
g=false
@ -67,6 +68,7 @@ done
EOF
} | head > /dev/null
(( $? == 0)) || err_exit "SIGPIPE with wrong error code $?"
# The below is kind of bogus as the err_exit from a bg job is never counterd. But see extra check below.
[[ $(<out2) == $'PIPED\nPIPED' ]] || err_exit 'SIGPIPE output on standard error is not correct'
) &
cop=$!
@ -74,7 +76,7 @@ cop=$!
spy=$!
if wait $cop 2>/dev/null
then kill $spy 2>/dev/null
else err_exit "pipe with --pipefail PIPE trap hangs"
else err_exit "pipe with --pipefail PIPE trap hangs or produced an error"
fi
wait
rm -f out2

View file

@ -19,14 +19,15 @@
########################################################################
function err_exit
{
print -u$Error_fd -n "\t"
print -u$Error_fd -r ${Command}[$1]: "${@:2}"
print -u2 -n "\t"
print -u2 -r ${Command}[$1]: "${@:2}"
(( Errors+=1 ))
}
alias err_exit='err_exit $LINENO'
Command=${0##*/}
integer Errors=0 Error_fd=2
integer Errors=0
typeset -F SECONDS # for fractional seconds in PS4
tmp=$(
d=${TMPDIR:-/tmp}/ksh93.subshell.$$.${RANDOM:-0}
@ -40,6 +41,13 @@ trap 'cd / && rm -rf "$tmp"' EXIT
builtin getconf
bincat=$(PATH=$(getconf PATH) whence -p cat)
binecho=$(PATH=$(getconf PATH) whence -p echo)
# make an external 'sleep' command that supports fractional seconds
binsleep=$tmp/.sleep.sh # hide to exclude from simple wildcard expansion
cat >"$binsleep" <<EOF
#!$SHELL
sleep "\$@"
EOF
chmod +x "$binsleep"
z=()
z.foo=( [one]=hello [two]=(x=3 y=4) [three]=hi)
@ -102,9 +110,6 @@ unset l
)
[[ ${l+foo} != foo ]] || err_exit 'l should be unset'
Error_fd=9
eval "exec $Error_fd>&2 2>/dev/null"
TEST_notfound=notfound
while whence $TEST_notfound >/dev/null 2>&1
do TEST_notfound=notfound-$RANDOM
@ -220,7 +225,7 @@ do for TEST_exec in '' 'exec'
sleep 2
kill -KILL $$
} &
'"$TEST_test"'
{ '"$TEST_test"'; } 2>/dev/null
kill $!
print ok
')
@ -394,7 +399,7 @@ do cat $tmp/buf $tmp/buf > $tmp/tmp
wait $m
h=$?
kill -9 $k
wait $k
{ wait $k; } 2>/dev/null # suppress 'wait: $pid: Killed'
got=$(<$tmp/out)
if [[ ! $got ]] && (( h ))
then got=HUNG
@ -427,7 +432,7 @@ done
# specifics -- there's more?
{
cmd='{ exec 5>/dev/null; print "$(eval ls -d . 2>&1 1>&5)"; } >$tmp/out &'
cmd='{ exec 5>/dev/null; print "$(set +x; eval ls -d . 2>&1 1>&5)"; } >$tmp/out &'
eval $cmd
m=$!
{ sleep 4; kill -9 $m; } &
@ -447,13 +452,11 @@ then err_exit "eval '$cmd' failed -- expected '$exp', got '$got'"
fi
float t1=$SECONDS
sleep=$(whence -p sleep)
if [[ $sleep ]]
then
$SHELL -c "( $sleep 5 </dev/null >/dev/null 2>&1 & );exit 0" | cat
(( (SECONDS-t1) > 4 )) && err_exit '/bin/sleep& in subshell hanging'
((t1=SECONDS))
fi
$SHELL -c '( "$1" 5 </dev/null >/dev/null 2>&1 & );exit 0' x "$binsleep" | cat
(( (SECONDS-t1) > 4 )) && err_exit '/bin/sleep& in subshell hanging'
((t1=SECONDS))
$SHELL -c '( sleep 5 </dev/null >/dev/null 2>&1 & );exit 0' | cat
(( (SECONDS-t1) > 4 )) && err_exit 'sleep& in subshell hanging'
@ -483,7 +486,7 @@ $SHELL -c 'sleep 20 & pid=$!; { x=$( ( seq 60000 ) );kill -9 $pid;}&;wait $pid'
(.sh.foo=foobar)
[[ ${.sh.foo} == foobar ]] && err_exit '.sh subvariables in subshells remain set'
[[ $($SHELL -c 'print 1 | : "$("$bincat" <("$bincat"))"') ]] && err_exit 'process substitution not working correctly in subshells'
[[ $(export bincat; $SHELL -c 'print 1 | : "$("$bincat" <("$bincat"))"') ]] && err_exit 'process substitution not working correctly in subshells'
# config hang bug
integer i
@ -542,7 +545,7 @@ $SHELL <<- \EOF
(( ${#out} == 96011 )) || err_exit "\${#out} is ${#out} should be 96011"
EOF
} & pid=$!
$SHELL -c "{ sleep 4 && kill $pid ;}" 2> /dev/null
$SHELL -c "{ sleep .4 && kill $pid ;}" 2> /dev/null
(( $? == 0 )) && err_exit 'process has hung'
{
@ -613,7 +616,7 @@ $SHELL <<- \EOF
wc=$(whence wc) head=$(whence head)
print > /dev/null $( ( $head -c 1 /dev/zero | ( $wc -c) 3>&1 ) 3>&1) &
pid=$!
sleep 2
sleep .2
kill -9 $! 2> /dev/null && err_exit '/dev/zero in command substitution hangs'
wait $!
EOF
@ -685,13 +688,13 @@ expect=$'sub3\nok_nonexistent\nsub2\nsub1\nmainfunction'
alias al="echo 'mainalias'"
(unalias al; alias al >/dev/null) && err_exit 'alias fails to be unset in subshell'
(unalias al; alias al 2>/dev/null) && err_exit 'alias fails to be unset in subshell'
v=$(unalias al; alias al >/dev/null) && err_exit 'alias fails to be unset in comsub'
v=$(unalias al; alias al 2>/dev/null) && err_exit 'alias fails to be unset in comsub'
[[ $(eval 'al') == 'mainalias' ]] || err_exit 'main alias fails to survive unset in subshell(s)'
v=${ eval 'al'; unalias al 2>&1; } && [[ $v == 'mainalias' ]] && ! alias al >/dev/null \
v=${ eval 'al'; unalias al 2>&1; } && [[ $v == 'mainalias' ]] && ! alias al 2>/dev/null \
|| err_exit 'main shell alias wrongly survives unset within ${ ...; }'
# ...alias can be redefined in subshell

View file

@ -26,7 +26,10 @@ function err_exit
alias err_exit='err_exit $LINENO'
Command=${0##*/}
integer Errors=0 j=4
integer Errors=0
tmpPS4='+ [temp_PS4|L$LINENO|e$?] ' # used to avoid interference to ${.sh.match} from $PS4 set by shtests
integer j=4
base=/home/dgk/foo//bar
string1=$base/abcabcabc
if [[ ${string1:0} != "$string1" ]]
@ -261,6 +264,9 @@ foo='foo+bar+'
[[ $(print -r -- ${foo//+/"|"}) != 'foo|bar|' ]] && err_exit '${foobar//+/"|"}'
[[ $(print -r -- "${foo//+/'|'}") != 'foo|bar|' ]] && err_exit '"${foobar//+/'"'|'"'}"'
[[ $(print -r -- "${foo//+/"|"}") != 'foo|bar|' ]] && err_exit '"${foobar//+/"|"}"'
(
PS4=$tmpPS4
unset x
x=abcedfg
: ${x%@(d)f@(g)}
@ -270,6 +276,10 @@ x=abcedfg
x=abcedddfg
: ${x%%+(d)f@(g)}
[[ ${.sh.match[1]} == ddd ]] || err_exit '.sh.match[1] not ddd'
exit $Errors
)
Errors=$?
unset a b
a='\[abc @(*) def\]'
b='[abc 123 def]'
@ -296,10 +306,16 @@ integer i
for((i=0; i < ${#string}; i++))
do pattern+='@(?)'
done
(
PS4=$tmpPS4
[[ $(string=$string $SHELL -c ": \${string/$pattern/}; print \${.sh.match[26]}") == Z ]] || err_exit -u2 'sh.match[26] not Z'
: ${string/$pattern/}
(( ${#.sh.match[@]} == 53 )) || err_exit '.sh.match has wrong number of elements'
[[ ${.sh.match[@]:2:4} == 'B C D E' ]] || err_exit '${.sh.match[@]:2:4} incorrect'
exit $Errors
)
Errors=$?
D=$';' E=$'\\\\' Q=$'"' S=$'\'' M='nested pattern substitution failed'
@ -497,7 +513,7 @@ pattern=00
var=100
[[ $( print $(( ${var%%00} )) ) == 1 ]] || err_exit "arithmetic with embedded patterns fails"
[[ $( print $(( ${var%%$pattern} )) ) == 1 ]] || err_exit "arithmetic with embedded pattern variables fails"
if [[ ax == @(a)* ]] && [[ ${.sh.match[1]:0:${#.sh.match[1]}} != a ]]
if (PS4=$tmpPS4; [[ ax == @(a)* ]] && [[ ${.sh.match[1]:0:${#.sh.match[1]}} != a ]])
then err_exit '${.sh.match[1]:1:${#.sh.match[1]}} not expanding correctly'
fi
@ -586,6 +602,9 @@ got=$($SHELL -c 'A=""; B="B"; for I in ${A[@]} ${B[@]}; do echo "\"$I\""; done')
A='|'
[[ $A == $A ]] || err_exit 'With A="|", [[ $A == $A ]] does not match'
(
PS4=$tmpPS4
x="111 222 333 444 555 666"
[[ $x == ~(E)(...).(...).(...) ]]
[[ -v .sh.match[0] ]] || err_exit '[[ -v .sh.match[0] ]] should be true'
@ -597,6 +616,10 @@ x="foo bar"
dummy=${x/~(E)(*)/}
[[ ${ print -v .sh.match;} ]] && err_exit 'print -v should show .sh.match empty when there are no matches'
exit $Errors
)
Errors=$?
if $SHELL -c 'set 1 2 3 4 5 6 7 8 9 10 11 12; : ${##[0-9]}' 2>/dev/null
then set 1 2 3 4 5 6 7 8 9 10 11 12
[[ ${##[0-9]} == 2 ]] || err_exit '${##[0-9]} should be 2 with $#==12'
@ -614,16 +637,21 @@ fi
function foo
{
typeset x="123 456 789 abc"
typeset PS4=$tmpPS4 x="123 456 789 abc"
typeset dummy="${x/~(E-g)([[:digit:]][[:digit:]])((X)|([[:digit:]]))([[:blank:]])/_}"
exp=$'(\n\t[0]=\'123 \'\n\t[1]=12\n\t[2]=3\n\t[4]=3\n\t[5]=\' \'\n)'
[[ $(print -v .sh.match) == "$exp" ]] || err_exit '.sh.match not correct with alternations'
}
foo
(
PS4=$tmpPS4
x="a 1 b"
d=${x/~(E)(([[:digit:]])[[:space:]]*|([[:alpha:]]))/X}
[[ $(print -v .sh.match) == $'(\n\t[0]=a\n\t[1]=a\n\t[3]=a\n)' ]] || err_exit '.sh.match not sparse'
exit $Errors
)
Errors=$?
unset v
typeset -a arr=( 0 1 2 3 4 )
@ -654,11 +682,16 @@ do err_exit "\${@:0:-1} should not generate ${v:-empty_string}"
break
done
(
PS4=$tmpPS4
unset v d
v=abbbc
d="${v/~(E)b{2,4}/dummy}"
[[ ${.sh.match} == bbb ]] || err_exit '.sh.match wrong after ${s/~(E)b{2,4}/dummy}'
[[ $d == adummyc ]] || err_exit '${s/~(E)b{2,4}/dummy} not working'
exit $Errors
)
Errors=$?
# ======
exit $((Errors<125?Errors:125))

View file

@ -47,9 +47,10 @@ if (( RANDOM==RANDOM || $RANDOM==$RANDOM ))
then err_exit RANDOM variable not working
fi
# SECONDS
sleep 3
if (( SECONDS < 2 ))
then err_exit SECONDS variable not working
let SECONDS=0.0
sleep .001
if (( SECONDS < .001 ))
then err_exit "either 'sleep' or \$SECONDS not working"
fi
# _
set abc def
@ -217,6 +218,7 @@ x error"
then err_exit "\${#$i} not correct"
fi
done
kill -s 0 $! || err_exit '$! does not point to latest asynchronous process'
kill $!
unset x
CDPATH=/
@ -433,12 +435,12 @@ fi
function foo
{
typeset SECONDS=0
sleep 1.5
sleep .002
print $SECONDS
}
x=$(foo)
(( x >1 && x < 2 ))
(( x >.001 && x < .01 ))
'
} 2> /dev/null || err_exit 'SECONDS not working in function'
cat > $tmp/script <<-\!