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:
parent
ba1f2ba9c3
commit
712261c89b
15 changed files with 178 additions and 120 deletions
|
@ -38,6 +38,13 @@ tmp=$(
|
||||||
trap 'cd / && rm -rf "$tmp"' EXIT
|
trap 'cd / && rm -rf "$tmp"' EXIT
|
||||||
bincat=$(whence -p cat)
|
bincat=$(whence -p cat)
|
||||||
binecho=$(whence -p echo)
|
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
|
# test basic file operations like redirection, pipes, file expansion
|
||||||
set -- \
|
set -- \
|
||||||
|
@ -146,7 +153,7 @@ cd ../../tmp || err_exit "cd ../../tmp failed"
|
||||||
if [[ $PWD != /tmp ]]
|
if [[ $PWD != /tmp ]]
|
||||||
then err_exit 'cd ../../tmp is not /tmp'
|
then err_exit 'cd ../../tmp is not /tmp'
|
||||||
fi
|
fi
|
||||||
( sleep 2; cat <<!
|
( sleep .2; cat <<!
|
||||||
foobar
|
foobar
|
||||||
!
|
!
|
||||||
) | cat > $tmp/foobar &
|
) | cat > $tmp/foobar &
|
||||||
|
@ -294,7 +301,7 @@ if [[ $(for i in foo bar
|
||||||
then err_exit 'for loop subshell optimizer bug'
|
then err_exit 'for loop subshell optimizer bug'
|
||||||
fi
|
fi
|
||||||
unset a1
|
unset a1
|
||||||
optbug()
|
function optbug
|
||||||
{
|
{
|
||||||
set -A a1 foo bar bam
|
set -A a1 foo bar bam
|
||||||
integer i
|
integer i
|
||||||
|
@ -307,15 +314,15 @@ optbug()
|
||||||
done
|
done
|
||||||
return 1
|
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
|
wait # not running --pipefail which would interfere with subsequent tests
|
||||||
: $(jobs -p) # required to clear jobs for next jobs -p (interactive side effect)
|
: $(jobs -p) # required to clear jobs for next jobs -p (interactive side effect)
|
||||||
sleep 20 &
|
sleep 2 &
|
||||||
pids=$!
|
pids=$!
|
||||||
if [[ $(jobs -p) != $! ]]
|
if [[ $(jobs -p) != $! ]]
|
||||||
then err_exit 'jobs -p not reporting a background job'
|
then err_exit 'jobs -p not reporting a background job'
|
||||||
fi
|
fi
|
||||||
sleep 20 &
|
sleep 2 &
|
||||||
pids="$pids $!"
|
pids="$pids $!"
|
||||||
foo()
|
foo()
|
||||||
{
|
{
|
||||||
|
@ -325,8 +332,8 @@ foo()
|
||||||
foo
|
foo
|
||||||
kill $pids
|
kill $pids
|
||||||
|
|
||||||
[[ $( (trap 'print alarm' ALRM; sleep 4) & sleep 2; kill -ALRM $!; sleep 2; wait) == alarm ]] || err_exit 'ALRM signal not working'
|
[[ $( (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 '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'
|
[[ $($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
|
command exec 3<> /dev/null
|
||||||
if cat /dev/fd/3 >/dev/null 2>&1 || whence mkfifo > /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
|
cat > $tmp/scriptx <<- \EOF
|
||||||
myfilter() { x=$(print ok | cat); print -r -- $SECONDS;}
|
myfilter() { x=$(print ok | cat); print -r -- $SECONDS;}
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
sleep 3 | myfilter
|
sleep .3 | myfilter
|
||||||
EOF
|
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<&-
|
exec 3<&-
|
||||||
( typeset -r foo=bar) 2> /dev/null || err_exit 'readonly variables set in a subshell cannot unset'
|
( 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'
|
$SHELL -c 'x=${ print hello;}; [[ $x == hello ]]' 2> /dev/null || err_exit '${ command;} not supported'
|
||||||
|
@ -418,7 +425,7 @@ unset foo
|
||||||
unset foo
|
unset foo
|
||||||
foo=$(false) > /dev/null && err_exit 'failed command substitution with redirection not returning false'
|
foo=$(false) > /dev/null && err_exit 'failed command substitution with redirection not returning false'
|
||||||
expected=foreback
|
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'"
|
[[ $got == $expected ]] || err_exit "command substitution background process output error -- got '$got', expected '$expected'"
|
||||||
|
|
||||||
binfalse=$(whence -p false)
|
binfalse=$(whence -p false)
|
||||||
|
@ -430,19 +437,20 @@ done
|
||||||
if env x-a=y >/dev/null 2>&1
|
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'
|
then [[ $(env 'x-a=y' $SHELL -c 'env | grep x-a') == *x-a=y* ]] || err_exit 'invalid environment variables not preserved'
|
||||||
fi
|
fi
|
||||||
|
|
||||||
float s=SECONDS
|
float s=SECONDS
|
||||||
sleep=$(whence -p sleep)
|
for i in .1 .2
|
||||||
for i in 1 2
|
|
||||||
do print $i
|
do print $i
|
||||||
done | while read sec; do ( $sleep $sec; $sleep $sec) done
|
done | while read sec; do ( "$binsleep" "$sec"; "$binsleep" "$sec") done
|
||||||
(( (SECONDS-s) < 4)) && err_exit '"command | while read...done" finishing too fast'
|
(( (SECONDS-s) < .4)) && err_exit '"command | while read...done" finishing too fast'
|
||||||
s=SECONDS
|
s=SECONDS
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
for ((i=0; i < 30; i++))
|
for ((i=0; i < 30; i++))
|
||||||
do print hello 2>/dev/null
|
do print hello 2>/dev/null
|
||||||
sleep .1
|
sleep .01
|
||||||
done | $sleep 1
|
done | "$binsleep" .1
|
||||||
(( (SECONDS-s) < 2 )) || err_exit 'early termination not causing broken pipe'
|
(( (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'
|
[[ $({ 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 'print trap' ERR; print -n | $binfalse; } & wait $!)
|
||||||
[[ $var == trap ]] || err_exit 'trap on ERR not getting triggered'
|
[[ $var == trap ]] || err_exit 'trap on ERR not getting triggered'
|
||||||
|
@ -479,28 +487,28 @@ set -o pipefail
|
||||||
float start=$SECONDS end
|
float start=$SECONDS end
|
||||||
for ((i=0; i < 2; i++))
|
for ((i=0; i < 2; i++))
|
||||||
do print foo 2>/dev/null
|
do print foo 2>/dev/null
|
||||||
sleep 1.5
|
sleep .15
|
||||||
done | { read; $bintrue; end=$SECONDS ;}
|
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
|
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"
|
{ env A__z=C+SHLVL $SHELL -c : ;} 2> /dev/null || err_exit "SHLVL with wrong attribute fails"
|
||||||
|
|
||||||
if [[ $bintrue ]]
|
if [[ $bintrue ]]
|
||||||
then float t0=SECONDS
|
then float t0=SECONDS
|
||||||
{ time sleep 1.5 | $bintrue ;} 2> /dev/null
|
{ time sleep .15 | $bintrue ;} 2> /dev/null
|
||||||
(( (SECONDS-t0) < 1 )) && err_exit 'time not waiting for pipeline to complete'
|
(( (SECONDS-t0) < .1 )) && err_exit 'time not waiting for pipeline to complete'
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cat > $tmp/foo.sh <<- \EOF
|
cat > $tmp/foo.sh <<- \EOF
|
||||||
eval "cat > /dev/null < /dev/null"
|
eval "cat > /dev/null < /dev/null"
|
||||||
sleep 1
|
sleep .1
|
||||||
EOF
|
EOF
|
||||||
float sec=SECONDS
|
float sec=SECONDS
|
||||||
. $tmp/foo.sh | cat > /dev/null
|
. $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
|
file=$tmp/foobar
|
||||||
builtin cat
|
builtin cat
|
||||||
|
|
|
@ -130,7 +130,7 @@ fi
|
||||||
if [[ ! -w /dev/fd/2 ]]
|
if [[ ! -w /dev/fd/2 ]]
|
||||||
then err_exit "/dev/fd/2 not open for writing"
|
then err_exit "/dev/fd/2 not open for writing"
|
||||||
fi
|
fi
|
||||||
sleep 1
|
sleep .01
|
||||||
> $newer_file
|
> $newer_file
|
||||||
if [[ ! $file -ot $newer_file ]]
|
if [[ ! $file -ot $newer_file ]]
|
||||||
then err_exit "$file should be older than $newer_file"
|
then err_exit "$file should be older than $newer_file"
|
||||||
|
@ -235,10 +235,10 @@ done
|
||||||
rm -rf $file
|
rm -rf $file
|
||||||
{
|
{
|
||||||
[[ -N $file ]] && err_exit 'test -N $tmp/*: st_mtime>st_atime after creat'
|
[[ -N $file ]] && err_exit 'test -N $tmp/*: st_mtime>st_atime after creat'
|
||||||
sleep 2
|
sleep .02
|
||||||
print 'hello world'
|
print 'hello world'
|
||||||
[[ -N $file ]] || err_exit 'test -N $tmp/*: st_mtime<=st_atime after write'
|
[[ -N $file ]] || err_exit 'test -N $tmp/*: st_mtime<=st_atime after write'
|
||||||
sleep 2
|
sleep .02
|
||||||
read
|
read
|
||||||
[[ -N $file ]] && err_exit 'test -N $tmp/*: st_mtime>st_atime after read'
|
[[ -N $file ]] && err_exit 'test -N $tmp/*: st_mtime>st_atime after read'
|
||||||
} > $file < $file
|
} > $file < $file
|
||||||
|
|
|
@ -385,7 +385,7 @@ do arg=$1 val=$2 code=$3
|
||||||
shift 3
|
shift 3
|
||||||
for fmt in '%d' '%g'
|
for fmt in '%d' '%g'
|
||||||
do out=$(printf "$fmt" "$arg" 2>/dev/null)
|
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
|
printf "$fmt" "$arg" >/dev/null 2>&1
|
||||||
ret=$?
|
ret=$?
|
||||||
[[ $out == $val ]] || err_exit "printf $fmt $arg failed -- expected '$val', got '$out'"
|
[[ $out == $val ]] || err_exit "printf $fmt $arg failed -- expected '$val', got '$out'"
|
||||||
|
|
|
@ -109,7 +109,7 @@ do
|
||||||
$cat |&
|
$cat |&
|
||||||
!
|
!
|
||||||
chmod +x $file
|
chmod +x $file
|
||||||
sleep 10 |&
|
sleep 1 |&
|
||||||
$file 2> /dev/null || err_exit "parent $cat coprocess prevents script coprocess"
|
$file 2> /dev/null || err_exit "parent $cat coprocess prevents script coprocess"
|
||||||
exec 5<&p 6>&p
|
exec 5<&p 6>&p
|
||||||
exec 5<&- 6>&-
|
exec 5<&- 6>&-
|
||||||
|
@ -119,15 +119,15 @@ do
|
||||||
cop=$!
|
cop=$!
|
||||||
exp=Done
|
exp=Done
|
||||||
print -p $'print hello | '$cat$'\nprint '$exp
|
print -p $'print hello | '$cat$'\nprint '$exp
|
||||||
read -t 5 -p
|
read -t 1 -p
|
||||||
read -t 5 -p
|
read -t 1 -p
|
||||||
got=$REPLY
|
got=$REPLY
|
||||||
if [[ $got != $exp ]]
|
if [[ $got != $exp ]]
|
||||||
then err_exit "${SHELL-ksh} $cat coprocess io failed -- got '$got', expected '$exp'"
|
then err_exit "${SHELL-ksh} $cat coprocess io failed -- got '$got', expected '$exp'"
|
||||||
fi
|
fi
|
||||||
exec 5<&p 6>&p
|
exec 5<&p 6>&p
|
||||||
exec 5<&- 6>&-
|
exec 5<&- 6>&-
|
||||||
{ sleep 4; kill $cop; } 2>/dev/null &
|
{ sleep .4; kill $cop; } 2>/dev/null &
|
||||||
spy=$!
|
spy=$!
|
||||||
if wait $cop 2>/dev/null
|
if wait $cop 2>/dev/null
|
||||||
then kill $spy 2>/dev/null
|
then kill $spy 2>/dev/null
|
||||||
|
@ -140,15 +140,15 @@ do
|
||||||
echo line2 | grep 'line1'
|
echo line2 | grep 'line1'
|
||||||
} |&
|
} |&
|
||||||
SECONDS=0 count=0
|
SECONDS=0 count=0
|
||||||
while read -p -t 10 line
|
while read -p -t 1 line
|
||||||
do ((count++))
|
do ((count++))
|
||||||
done
|
done
|
||||||
if (( SECONDS > 8 ))
|
if (( SECONDS > .8 ))
|
||||||
then err_exit "$cat coprocess read -p hanging (SECONDS=$SECONDS count=$count)"
|
then err_exit "$cat coprocess read -p hanging (SECONDS=$SECONDS count=$count)"
|
||||||
fi
|
fi
|
||||||
wait $!
|
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"
|
err_exit "$cat coprocess cleanup not working correctly"
|
||||||
{ : |& } 2>/dev/null ||
|
{ : |& } 2>/dev/null ||
|
||||||
err_exit "subshell $cat coprocess lingers in parent"
|
err_exit "subshell $cat coprocess lingers in parent"
|
||||||
|
@ -166,7 +166,7 @@ do
|
||||||
wait $!
|
wait $!
|
||||||
done
|
done
|
||||||
print
|
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 == $e ]] || err_exit "$cat coprocess timing bug -- expected $e, got '$r'"
|
||||||
|
|
||||||
r=
|
r=
|
||||||
|
@ -174,21 +174,21 @@ do
|
||||||
integer i
|
integer i
|
||||||
for ((i = 1; i <= N; i++))
|
for ((i = 1; i <= N; i++))
|
||||||
do print $i |&
|
do print $i |&
|
||||||
sleep 0.01
|
sleep 0.001
|
||||||
r=$r$($cat <&p)
|
r=$r$($cat <&p)
|
||||||
wait $!
|
wait $!
|
||||||
done
|
done
|
||||||
print $r
|
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'"
|
[[ $r == $e ]] || err_exit "$cat coprocess command substitution bug -- expected $e, got '$r'"
|
||||||
|
|
||||||
(
|
(
|
||||||
$cat |&
|
$cat |&
|
||||||
sleep 0.01
|
sleep 0.001
|
||||||
exec 6>&p
|
exec 6>&p
|
||||||
print -u6 ok
|
print -u6 ok
|
||||||
exec 6>&-
|
exec 6>&-
|
||||||
sleep 2
|
sleep .2
|
||||||
kill $! 2> /dev/null
|
kill $! 2> /dev/null
|
||||||
) && err_exit "$cat coprocess with subshell would hang"
|
) && err_exit "$cat coprocess with subshell would hang"
|
||||||
for sig in IOT ABRT
|
for sig in IOT ABRT
|
||||||
|
@ -198,12 +198,12 @@ do
|
||||||
pid=\$!
|
pid=\$!
|
||||||
trap "print TRAP" \$sig
|
trap "print TRAP" \$sig
|
||||||
(
|
(
|
||||||
sleep 2
|
sleep .2
|
||||||
kill -\$sig \$\$
|
kill -\$sig \$\$
|
||||||
sleep 2
|
sleep .2
|
||||||
kill -\$sig \$\$
|
kill -\$sig \$\$
|
||||||
kill \$pid
|
kill \$pid
|
||||||
sleep 2
|
sleep .2
|
||||||
kill \$\$
|
kill \$\$
|
||||||
) &
|
) &
|
||||||
while read -p || ((\$? > 256))
|
while read -p || ((\$? > 256))
|
||||||
|
@ -218,7 +218,7 @@ do
|
||||||
done
|
done
|
||||||
|
|
||||||
trap 'sleep_pid=; kill $pid; err_exit "$cat coprocess 1 hung"' TERM
|
trap 'sleep_pid=; kill $pid; err_exit "$cat coprocess 1 hung"' TERM
|
||||||
{ sleep 5; kill $$; } &
|
{ sleep .5; kill $$; } &
|
||||||
sleep_pid=$!
|
sleep_pid=$!
|
||||||
$cat |&
|
$cat |&
|
||||||
pid=$!
|
pid=$!
|
||||||
|
@ -232,7 +232,7 @@ do
|
||||||
[[ $sleep_pid ]] && kill $sleep_pid
|
[[ $sleep_pid ]] && kill $sleep_pid
|
||||||
|
|
||||||
trap 'sleep_pid=; kill $pid; err_exit "$cat coprocess 2 hung"' TERM
|
trap 'sleep_pid=; kill $pid; err_exit "$cat coprocess 2 hung"' TERM
|
||||||
{ sleep 5; kill $$; } &
|
{ sleep .5; kill $$; } &
|
||||||
sleep_pid=$!
|
sleep_pid=$!
|
||||||
$cat |&
|
$cat |&
|
||||||
pid=$!
|
pid=$!
|
||||||
|
@ -244,7 +244,7 @@ do
|
||||||
[[ $sleep_pid ]] && kill $sleep_pid
|
[[ $sleep_pid ]] && kill $sleep_pid
|
||||||
|
|
||||||
trap 'sleep_pid=; kill $pid; err_exit "$cat coprocess 3 hung"' TERM
|
trap 'sleep_pid=; kill $pid; err_exit "$cat coprocess 3 hung"' TERM
|
||||||
{ sleep 5; kill $$; } &
|
{ sleep .5; kill $$; } &
|
||||||
sleep_pid=$!
|
sleep_pid=$!
|
||||||
$cat |&
|
$cat |&
|
||||||
pid=$!
|
pid=$!
|
||||||
|
|
|
@ -981,10 +981,17 @@ function _Dbg_debug_trap_handler
|
||||||
done
|
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))
|
((baseline=LINENO+2))
|
||||||
trap '_Dbg_debug_trap_handler' DEBUG
|
trap '_Dbg_debug_trap_handler' DEBUG
|
||||||
. $tmp/debug foo bar
|
. $tmp/debug foo bar
|
||||||
trap '' DEBUG
|
trap '' DEBUG
|
||||||
|
exit $Errors
|
||||||
|
)
|
||||||
|
Errors=$?
|
||||||
|
|
||||||
caller() {
|
caller() {
|
||||||
integer .level=.sh.level .max=.sh.level-1
|
integer .level=.sh.level .max=.sh.level-1
|
||||||
|
|
|
@ -99,6 +99,7 @@ fi
|
||||||
|
|
||||||
# 2004-11-25 ancient /dev/fd/N redirection bug fix
|
# 2004-11-25 ancient /dev/fd/N redirection bug fix
|
||||||
got=$(
|
got=$(
|
||||||
|
set +x
|
||||||
{
|
{
|
||||||
print -n 1
|
print -n 1
|
||||||
print -n 2 > ${FDFS[fdfs].dir}/2
|
print -n 2 > ${FDFS[fdfs].dir}/2
|
||||||
|
@ -338,16 +339,16 @@ read -n3 a <<!
|
||||||
abcdefg
|
abcdefg
|
||||||
!
|
!
|
||||||
[[ $a == abc ]] || err_exit 'read -n3 here-document not working'
|
[[ $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'
|
[[ $a == abc ]] || err_exit 'read -N3 from pipe not working'
|
||||||
[[ $b == d ]] || err_exit 'read -N1 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'
|
[[ $a == a ]] || err_exit 'read -n3 from pipe not working'
|
||||||
if mkfifo $tmp/fifo 2> /dev/null
|
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 -n3 -t1 a || err_exit 'read -n3 from fifo timed out'
|
||||||
read -u5 -n1 -t3 b || err_exit 'read -n1 from fifo timed out'
|
read -u5 -n1 -t1 b || err_exit 'read -n1 from fifo timed out'
|
||||||
} 5< $tmp/fifo
|
} 5< $tmp/fifo
|
||||||
exp=a
|
exp=a
|
||||||
got=$a
|
got=$a
|
||||||
|
@ -358,10 +359,10 @@ then (print -n a; sleep 2; print -n bcde) > $tmp/fifo &
|
||||||
rm -f $tmp/fifo
|
rm -f $tmp/fifo
|
||||||
wait
|
wait
|
||||||
mkfifo $tmp/fifo 2> /dev/null
|
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 -N3 -t1 a || err_exit 'read -N3 from fifo timed out'
|
||||||
read -u5 -N1 -t3 b || err_exit 'read -N1 from fifo timed out'
|
read -u5 -N1 -t1 b || err_exit 'read -N1 from fifo timed out'
|
||||||
} 5< $tmp/fifo
|
} 5< $tmp/fifo
|
||||||
exp=abc
|
exp=abc
|
||||||
got=$a
|
got=$a
|
||||||
|
@ -373,16 +374,16 @@ then (print -n a; sleep 2; print -n bcde) > $tmp/fifo &
|
||||||
fi
|
fi
|
||||||
(
|
(
|
||||||
print -n 'prompt1: '
|
print -n 'prompt1: '
|
||||||
sleep .1
|
sleep .01
|
||||||
print line2
|
print line2
|
||||||
sleep .1
|
sleep .01
|
||||||
print -n 'prompt2: '
|
print -n 'prompt2: '
|
||||||
sleep .1
|
sleep .01
|
||||||
) | {
|
) | {
|
||||||
read -t2 -n 1000 line1
|
read -t1 -n 1000 line1
|
||||||
read -t2 -n 1000 line2
|
read -t1 -n 1000 line2
|
||||||
read -t2 -n 1000 line3
|
read -t1 -n 1000 line3
|
||||||
read -t2 -n 1000 line4
|
read -t1 -n 1000 line4
|
||||||
}
|
}
|
||||||
[[ $? == 0 ]] && err_exit 'should have timed out'
|
[[ $? == 0 ]] && err_exit 'should have timed out'
|
||||||
[[ $line1 == 'prompt1: ' ]] || err_exit "line1 should be 'prompt1: '"
|
[[ $line1 == 'prompt1: ' ]] || err_exit "line1 should be 'prompt1: '"
|
||||||
|
@ -410,7 +411,7 @@ do a=$1
|
||||||
shift 4
|
shift 4
|
||||||
for ((i = 0; i < 2; i++))
|
for ((i = 0; i < 2; i++))
|
||||||
do for lc_all in C $lc_utf8
|
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'"
|
[[ $g == "${e[i]}" ]] || err_exit "LC_ALL=$lc_all read ${o[i]} from pipe '$a $b' failed -- expected '${e[i]}', got '$g'"
|
||||||
done
|
done
|
||||||
done
|
done
|
||||||
|
@ -437,12 +438,14 @@ then export LC_ALL=$lc_utf8
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
exec 3<&2
|
|
||||||
file=$tmp/file
|
file=$tmp/file
|
||||||
|
(
|
||||||
|
: disabling xtrace so we can redirect stderr for this test
|
||||||
|
set +x
|
||||||
redirect 5>$file 2>&5
|
redirect 5>$file 2>&5
|
||||||
print -u5 -f 'This is a test\n'
|
print -u5 -f 'This is a test\n'
|
||||||
print -u2 OK
|
print -u2 OK
|
||||||
exec 2<&3
|
)
|
||||||
exp=$'This is a test\nOK'
|
exp=$'This is a test\nOK'
|
||||||
got=$(< $file)
|
got=$(< $file)
|
||||||
[[ $got == $exp ]] || err_exit "output garbled when stderr is duped -- expected $(printf %q "$exp"), got $(printf %q "$got")"
|
[[ $got == $exp ]] || err_exit "output garbled when stderr is duped -- expected $(printf %q "$exp"), got $(printf %q "$got")"
|
||||||
|
|
|
@ -200,11 +200,11 @@ got="$(<out)"
|
||||||
# multibyte identifiers
|
# multibyte identifiers
|
||||||
|
|
||||||
exp=OK
|
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 == "$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 == "$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'"
|
[[ $got == "$exp" ]] || err_exit "multibyte posix function definition/execution failed -- expected '$exp', got '$got'"
|
||||||
|
|
||||||
# this locale is supported by ast on all platforms
|
# this locale is supported by ast on all platforms
|
||||||
|
|
|
@ -73,7 +73,7 @@ then
|
||||||
got=$(printf %q "$got")
|
got=$(printf %q "$got")
|
||||||
err_exit "\$ENV file &>/dev/null does not redirect stdout -- expected '', got $got"
|
err_exit "\$ENV file &>/dev/null does not redirect stdout -- expected '', got $got"
|
||||||
fi
|
fi
|
||||||
got=$($SHELL -E -c : 2>&1 >/dev/null)
|
got=$(set +x; $SHELL -E -c : 2>&1 >/dev/null)
|
||||||
if [[ $got != *nonstandard* || $got == *$'\n'* ]]
|
if [[ $got != *nonstandard* || $got == *$'\n'* ]]
|
||||||
then
|
then
|
||||||
got=$(printf %q "$got")
|
got=$(printf %q "$got")
|
||||||
|
@ -151,11 +151,11 @@ then
|
||||||
else
|
else
|
||||||
[[ $(print env_hit | HOME=$tmp $SHELL 2>&1) == "OK" ]] &&
|
[[ $(print env_hit | HOME=$tmp $SHELL 2>&1) == "OK" ]] &&
|
||||||
err_exit 'nointeractive shell reads $HOME/.kshrc file'
|
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'
|
err_exit '-E ignores $HOME/.kshrc file'
|
||||||
[[ $(print env_hit | HOME=$tmp $SHELL +E 2>&1) == "OK" ]] &&
|
[[ $(print env_hit | HOME=$tmp $SHELL +E 2>&1) == "OK" ]] &&
|
||||||
err_exit '+E reads $HOME/.kshrc file'
|
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'
|
err_exit '--rc ignores $HOME/.kshrc file'
|
||||||
[[ $(print env_hit | HOME=$tmp $SHELL --norc 2>&1) == "OK" ]] &&
|
[[ $(print env_hit | HOME=$tmp $SHELL --norc 2>&1) == "OK" ]] &&
|
||||||
err_exit '--norc reads $HOME/.kshrc file'
|
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='true|true|false' )
|
||||||
( nopipefail=1 pipefail=1 command='false|false|false' )
|
( nopipefail=1 pipefail=1 command='false|false|false' )
|
||||||
( nopipefail=0 pipefail=0 command='true|true|true' )
|
( 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
|
set --nopipefail
|
||||||
for ((i = 0; i < ${#pipeline[@]}; i++ ))
|
for ((i = 0; i < ${#pipeline[@]}; i++ ))
|
||||||
|
@ -443,10 +443,10 @@ export ENV= PS1="(:$$:)"
|
||||||
histfile=$tmp/history
|
histfile=$tmp/history
|
||||||
exp=$(HISTFILE=$histfile $SHELL -c $'function foo\n{\ncat\n}\ntype foo')
|
exp=$(HISTFILE=$histfile $SHELL -c $'function foo\n{\ncat\n}\ntype foo')
|
||||||
for var in HISTSIZE HISTFILE
|
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=${got##*"$PS1"}
|
||||||
[[ $got == "$exp" ]] || err_exit "function definition inside (...) with $var unset fails -- got '$got', expected '$exp'"
|
[[ $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=${got##*"$PS1"}
|
||||||
[[ $got == "$exp" ]] || err_exit "function definition inside {...;} with $var unset fails -- got '$got', expected '$exp'"
|
[[ $got == "$exp" ]] || err_exit "function definition inside {...;} with $var unset fails -- got '$got', expected '$exp'"
|
||||||
done
|
done
|
||||||
|
|
|
@ -342,7 +342,7 @@ function foo
|
||||||
|
|
||||||
# whence -q bug fix
|
# whence -q bug fix
|
||||||
$SHELL -c 'whence -q cat' & pid=$!
|
$SHELL -c 'whence -q cat' & pid=$!
|
||||||
sleep 3
|
sleep .1
|
||||||
kill $! 2> /dev/null && err_exit 'whence -q appears to be hung'
|
kill $! 2> /dev/null && err_exit 'whence -q appears to be hung'
|
||||||
|
|
||||||
FPATH=$PWD
|
FPATH=$PWD
|
||||||
|
|
|
@ -207,7 +207,7 @@ done
|
||||||
shift $OPTIND-1
|
shift $OPTIND-1
|
||||||
|
|
||||||
if (( debug )) || [[ $trace ]]
|
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 ))
|
if (( debug ))
|
||||||
then set -x
|
then set -x
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -26,7 +26,7 @@ function err_exit
|
||||||
|
|
||||||
alias err_exit='err_exit $LINENO'
|
alias err_exit='err_exit $LINENO'
|
||||||
|
|
||||||
float DELAY=${1:-0.2}
|
float DELAY=${1:-0.02}
|
||||||
integer FOREGROUND=10 BACKGROUND=2 Errors=0
|
integer FOREGROUND=10 BACKGROUND=2 Errors=0
|
||||||
|
|
||||||
tmp=$(
|
tmp=$(
|
||||||
|
@ -82,7 +82,7 @@ then
|
||||||
integer running=0 maxrunning=0
|
integer running=0 maxrunning=0
|
||||||
trap "((running--))" CHLD
|
trap "((running--))" CHLD
|
||||||
for ((i=0; i<JOBCOUNT; i++))
|
for ((i=0; i<JOBCOUNT; i++))
|
||||||
do sleep 1 &
|
do sleep .1 &
|
||||||
if ((++running > maxrunning))
|
if ((++running > maxrunning))
|
||||||
then ((maxrunning=running))
|
then ((maxrunning=running))
|
||||||
fi
|
fi
|
||||||
|
@ -101,13 +101,13 @@ then
|
||||||
unset proc[\$!]
|
unset proc[\$!]
|
||||||
" CHLD
|
" CHLD
|
||||||
|
|
||||||
{ sleep 3; print a; exit 1; } &
|
{ sleep .3; print a; exit 1; } &
|
||||||
proc[$!]=( name=a status=1 )
|
proc[$!]=( name=a status=1 )
|
||||||
|
|
||||||
{ sleep 2; print b; exit 2; } &
|
{ sleep .2; print b; exit 2; } &
|
||||||
proc[$!]=( name=b status=2 )
|
proc[$!]=( name=b status=2 )
|
||||||
|
|
||||||
{ sleep 1; print c; exit 3; } &
|
{ sleep .1; print c; exit 3; } &
|
||||||
proc[$!]=( name=c status=3 )
|
proc[$!]=( name=c status=3 )
|
||||||
|
|
||||||
while (( ${#proc[@]} ))
|
while (( ${#proc[@]} ))
|
||||||
|
@ -120,8 +120,8 @@ then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
{
|
{
|
||||||
got=$( ( sleep 1;print $'\n') | $SHELL -c 'function handler { : ;}
|
got=$( ( sleep .1;print $'\n') | $SHELL -c 'function handler { : ;}
|
||||||
trap handler CHLD; sleep .3 & IFS= read; print good')
|
trap handler CHLD; sleep .03 & IFS= read; print good')
|
||||||
} 2> /dev/null
|
} 2> /dev/null
|
||||||
[[ $got == good ]] || err_exit 'SIGCLD handler effects read behavior'
|
[[ $got == good ]] || err_exit 'SIGCLD handler effects read behavior'
|
||||||
|
|
||||||
|
@ -129,9 +129,9 @@ set -- $(
|
||||||
(
|
(
|
||||||
$SHELL -xc $'
|
$SHELL -xc $'
|
||||||
trap \'wait $!; print $! $?\' CHLD
|
trap \'wait $!; print $! $?\' CHLD
|
||||||
{ sleep 0.1; exit 9; } &
|
{ sleep 0.01; exit 9; } &
|
||||||
print $!
|
print $!
|
||||||
sleep 0.5
|
sleep 0.05
|
||||||
'
|
'
|
||||||
) 2>/dev/null; print $?
|
) 2>/dev/null; print $?
|
||||||
)
|
)
|
||||||
|
@ -155,11 +155,11 @@ done
|
||||||
(( d==2000 )) || err_exit "trap '' CHLD causes side effects d=$d"
|
(( d==2000 )) || err_exit "trap '' CHLD causes side effects d=$d"
|
||||||
trap - CHLD
|
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 == *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'
|
[[ $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
|
chmod +x $tmp/foobar
|
||||||
x=$($SHELL -c "echo | $tmp/foobar")
|
x=$($SHELL -c "echo | $tmp/foobar")
|
||||||
[[ $x == *Done* ]] || err_exit 'SIGCHLD blocked for script at end of pipeline'
|
[[ $x == *Done* ]] || err_exit 'SIGCHLD blocked for script at end of pipeline'
|
||||||
|
|
|
@ -56,7 +56,8 @@ do if ! n=$(kill -l $s 2>/dev/null)
|
||||||
done
|
done
|
||||||
|
|
||||||
(
|
(
|
||||||
set --pipefail
|
: disabling xtrace for this test
|
||||||
|
set +x --pipefail
|
||||||
{
|
{
|
||||||
$SHELL 2> out2 <<- \EOF
|
$SHELL 2> out2 <<- \EOF
|
||||||
g=false
|
g=false
|
||||||
|
@ -67,6 +68,7 @@ done
|
||||||
EOF
|
EOF
|
||||||
} | head > /dev/null
|
} | head > /dev/null
|
||||||
(( $? == 0)) || err_exit "SIGPIPE with wrong error code $?"
|
(( $? == 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'
|
[[ $(<out2) == $'PIPED\nPIPED' ]] || err_exit 'SIGPIPE output on standard error is not correct'
|
||||||
) &
|
) &
|
||||||
cop=$!
|
cop=$!
|
||||||
|
@ -74,7 +76,7 @@ cop=$!
|
||||||
spy=$!
|
spy=$!
|
||||||
if wait $cop 2>/dev/null
|
if wait $cop 2>/dev/null
|
||||||
then kill $spy 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
|
fi
|
||||||
wait
|
wait
|
||||||
rm -f out2
|
rm -f out2
|
||||||
|
|
|
@ -19,14 +19,15 @@
|
||||||
########################################################################
|
########################################################################
|
||||||
function err_exit
|
function err_exit
|
||||||
{
|
{
|
||||||
print -u$Error_fd -n "\t"
|
print -u2 -n "\t"
|
||||||
print -u$Error_fd -r ${Command}[$1]: "${@:2}"
|
print -u2 -r ${Command}[$1]: "${@:2}"
|
||||||
(( Errors+=1 ))
|
(( Errors+=1 ))
|
||||||
}
|
}
|
||||||
alias err_exit='err_exit $LINENO'
|
alias err_exit='err_exit $LINENO'
|
||||||
|
|
||||||
Command=${0##*/}
|
Command=${0##*/}
|
||||||
integer Errors=0 Error_fd=2
|
integer Errors=0
|
||||||
|
typeset -F SECONDS # for fractional seconds in PS4
|
||||||
|
|
||||||
tmp=$(
|
tmp=$(
|
||||||
d=${TMPDIR:-/tmp}/ksh93.subshell.$$.${RANDOM:-0}
|
d=${TMPDIR:-/tmp}/ksh93.subshell.$$.${RANDOM:-0}
|
||||||
|
@ -40,6 +41,13 @@ trap 'cd / && rm -rf "$tmp"' EXIT
|
||||||
builtin getconf
|
builtin getconf
|
||||||
bincat=$(PATH=$(getconf PATH) whence -p cat)
|
bincat=$(PATH=$(getconf PATH) whence -p cat)
|
||||||
binecho=$(PATH=$(getconf PATH) whence -p echo)
|
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=()
|
||||||
z.foo=( [one]=hello [two]=(x=3 y=4) [three]=hi)
|
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'
|
[[ ${l+foo} != foo ]] || err_exit 'l should be unset'
|
||||||
|
|
||||||
Error_fd=9
|
|
||||||
eval "exec $Error_fd>&2 2>/dev/null"
|
|
||||||
|
|
||||||
TEST_notfound=notfound
|
TEST_notfound=notfound
|
||||||
while whence $TEST_notfound >/dev/null 2>&1
|
while whence $TEST_notfound >/dev/null 2>&1
|
||||||
do TEST_notfound=notfound-$RANDOM
|
do TEST_notfound=notfound-$RANDOM
|
||||||
|
@ -220,7 +225,7 @@ do for TEST_exec in '' 'exec'
|
||||||
sleep 2
|
sleep 2
|
||||||
kill -KILL $$
|
kill -KILL $$
|
||||||
} &
|
} &
|
||||||
'"$TEST_test"'
|
{ '"$TEST_test"'; } 2>/dev/null
|
||||||
kill $!
|
kill $!
|
||||||
print ok
|
print ok
|
||||||
')
|
')
|
||||||
|
@ -394,7 +399,7 @@ do cat $tmp/buf $tmp/buf > $tmp/tmp
|
||||||
wait $m
|
wait $m
|
||||||
h=$?
|
h=$?
|
||||||
kill -9 $k
|
kill -9 $k
|
||||||
wait $k
|
{ wait $k; } 2>/dev/null # suppress 'wait: $pid: Killed'
|
||||||
got=$(<$tmp/out)
|
got=$(<$tmp/out)
|
||||||
if [[ ! $got ]] && (( h ))
|
if [[ ! $got ]] && (( h ))
|
||||||
then got=HUNG
|
then got=HUNG
|
||||||
|
@ -427,7 +432,7 @@ done
|
||||||
# specifics -- there's more?
|
# 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
|
eval $cmd
|
||||||
m=$!
|
m=$!
|
||||||
{ sleep 4; kill -9 $m; } &
|
{ sleep 4; kill -9 $m; } &
|
||||||
|
@ -447,13 +452,11 @@ then err_exit "eval '$cmd' failed -- expected '$exp', got '$got'"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
float t1=$SECONDS
|
float t1=$SECONDS
|
||||||
sleep=$(whence -p sleep)
|
|
||||||
if [[ $sleep ]]
|
$SHELL -c '( "$1" 5 </dev/null >/dev/null 2>&1 & );exit 0' x "$binsleep" | cat
|
||||||
then
|
(( (SECONDS-t1) > 4 )) && err_exit '/bin/sleep& in subshell hanging'
|
||||||
$SHELL -c "( $sleep 5 </dev/null >/dev/null 2>&1 & );exit 0" | cat
|
((t1=SECONDS))
|
||||||
(( (SECONDS-t1) > 4 )) && err_exit '/bin/sleep& in subshell hanging'
|
|
||||||
((t1=SECONDS))
|
|
||||||
fi
|
|
||||||
$SHELL -c '( sleep 5 </dev/null >/dev/null 2>&1 & );exit 0' | cat
|
$SHELL -c '( sleep 5 </dev/null >/dev/null 2>&1 & );exit 0' | cat
|
||||||
(( (SECONDS-t1) > 4 )) && err_exit 'sleep& in subshell hanging'
|
(( (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)
|
||||||
[[ ${.sh.foo} == foobar ]] && err_exit '.sh subvariables in subshells remain set'
|
[[ ${.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
|
# config hang bug
|
||||||
integer i
|
integer i
|
||||||
|
@ -542,7 +545,7 @@ $SHELL <<- \EOF
|
||||||
(( ${#out} == 96011 )) || err_exit "\${#out} is ${#out} should be 96011"
|
(( ${#out} == 96011 )) || err_exit "\${#out} is ${#out} should be 96011"
|
||||||
EOF
|
EOF
|
||||||
} & pid=$!
|
} & 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'
|
(( $? == 0 )) && err_exit 'process has hung'
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -613,7 +616,7 @@ $SHELL <<- \EOF
|
||||||
wc=$(whence wc) head=$(whence head)
|
wc=$(whence wc) head=$(whence head)
|
||||||
print > /dev/null $( ( $head -c 1 /dev/zero | ( $wc -c) 3>&1 ) 3>&1) &
|
print > /dev/null $( ( $head -c 1 /dev/zero | ( $wc -c) 3>&1 ) 3>&1) &
|
||||||
pid=$!
|
pid=$!
|
||||||
sleep 2
|
sleep .2
|
||||||
kill -9 $! 2> /dev/null && err_exit '/dev/zero in command substitution hangs'
|
kill -9 $! 2> /dev/null && err_exit '/dev/zero in command substitution hangs'
|
||||||
wait $!
|
wait $!
|
||||||
EOF
|
EOF
|
||||||
|
@ -685,13 +688,13 @@ expect=$'sub3\nok_nonexistent\nsub2\nsub1\nmainfunction'
|
||||||
|
|
||||||
alias al="echo 'mainalias'"
|
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)'
|
[[ $(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 ${ ...; }'
|
|| err_exit 'main shell alias wrongly survives unset within ${ ...; }'
|
||||||
|
|
||||||
# ...alias can be redefined in subshell
|
# ...alias can be redefined in subshell
|
||||||
|
|
|
@ -26,7 +26,10 @@ function err_exit
|
||||||
alias err_exit='err_exit $LINENO'
|
alias err_exit='err_exit $LINENO'
|
||||||
|
|
||||||
Command=${0##*/}
|
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
|
base=/home/dgk/foo//bar
|
||||||
string1=$base/abcabcabc
|
string1=$base/abcabcabc
|
||||||
if [[ ${string1:0} != "$string1" ]]
|
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//+/'"'|'"'}"'
|
[[ $(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
|
unset x
|
||||||
x=abcedfg
|
x=abcedfg
|
||||||
: ${x%@(d)f@(g)}
|
: ${x%@(d)f@(g)}
|
||||||
|
@ -270,6 +276,10 @@ x=abcedfg
|
||||||
x=abcedddfg
|
x=abcedddfg
|
||||||
: ${x%%+(d)f@(g)}
|
: ${x%%+(d)f@(g)}
|
||||||
[[ ${.sh.match[1]} == ddd ]] || err_exit '.sh.match[1] not ddd'
|
[[ ${.sh.match[1]} == ddd ]] || err_exit '.sh.match[1] not ddd'
|
||||||
|
exit $Errors
|
||||||
|
)
|
||||||
|
Errors=$?
|
||||||
|
|
||||||
unset a b
|
unset a b
|
||||||
a='\[abc @(*) def\]'
|
a='\[abc @(*) def\]'
|
||||||
b='[abc 123 def]'
|
b='[abc 123 def]'
|
||||||
|
@ -296,10 +306,16 @@ integer i
|
||||||
for((i=0; i < ${#string}; i++))
|
for((i=0; i < ${#string}; i++))
|
||||||
do pattern+='@(?)'
|
do pattern+='@(?)'
|
||||||
done
|
done
|
||||||
|
|
||||||
|
(
|
||||||
|
PS4=$tmpPS4
|
||||||
[[ $(string=$string $SHELL -c ": \${string/$pattern/}; print \${.sh.match[26]}") == Z ]] || err_exit -u2 'sh.match[26] not Z'
|
[[ $(string=$string $SHELL -c ": \${string/$pattern/}; print \${.sh.match[26]}") == Z ]] || err_exit -u2 'sh.match[26] not Z'
|
||||||
: ${string/$pattern/}
|
: ${string/$pattern/}
|
||||||
(( ${#.sh.match[@]} == 53 )) || err_exit '.sh.match has wrong number of elements'
|
(( ${#.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'
|
[[ ${.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'
|
D=$';' E=$'\\\\' Q=$'"' S=$'\'' M='nested pattern substitution failed'
|
||||||
|
|
||||||
|
@ -497,7 +513,7 @@ pattern=00
|
||||||
var=100
|
var=100
|
||||||
[[ $( print $(( ${var%%00} )) ) == 1 ]] || err_exit "arithmetic with embedded patterns fails"
|
[[ $( print $(( ${var%%00} )) ) == 1 ]] || err_exit "arithmetic with embedded patterns fails"
|
||||||
[[ $( print $(( ${var%%$pattern} )) ) == 1 ]] || err_exit "arithmetic with embedded pattern variables 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'
|
then err_exit '${.sh.match[1]:1:${#.sh.match[1]}} not expanding correctly'
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -586,6 +602,9 @@ got=$($SHELL -c 'A=""; B="B"; for I in ${A[@]} ${B[@]}; do echo "\"$I\""; done')
|
||||||
A='|'
|
A='|'
|
||||||
[[ $A == $A ]] || err_exit 'With A="|", [[ $A == $A ]] does not match'
|
[[ $A == $A ]] || err_exit 'With A="|", [[ $A == $A ]] does not match'
|
||||||
|
|
||||||
|
(
|
||||||
|
PS4=$tmpPS4
|
||||||
|
|
||||||
x="111 222 333 444 555 666"
|
x="111 222 333 444 555 666"
|
||||||
[[ $x == ~(E)(...).(...).(...) ]]
|
[[ $x == ~(E)(...).(...).(...) ]]
|
||||||
[[ -v .sh.match[0] ]] || err_exit '[[ -v .sh.match[0] ]] should be true'
|
[[ -v .sh.match[0] ]] || err_exit '[[ -v .sh.match[0] ]] should be true'
|
||||||
|
@ -597,6 +616,10 @@ x="foo bar"
|
||||||
dummy=${x/~(E)(*)/}
|
dummy=${x/~(E)(*)/}
|
||||||
[[ ${ print -v .sh.match;} ]] && err_exit 'print -v should show .sh.match empty when there are no matches'
|
[[ ${ 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
|
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
|
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'
|
[[ ${##[0-9]} == 2 ]] || err_exit '${##[0-9]} should be 2 with $#==12'
|
||||||
|
@ -614,16 +637,21 @@ fi
|
||||||
|
|
||||||
function foo
|
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:]])/_}"
|
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)'
|
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'
|
[[ $(print -v .sh.match) == "$exp" ]] || err_exit '.sh.match not correct with alternations'
|
||||||
}
|
}
|
||||||
foo
|
foo
|
||||||
|
|
||||||
|
(
|
||||||
|
PS4=$tmpPS4
|
||||||
x="a 1 b"
|
x="a 1 b"
|
||||||
d=${x/~(E)(([[:digit:]])[[:space:]]*|([[:alpha:]]))/X}
|
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'
|
[[ $(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
|
unset v
|
||||||
typeset -a arr=( 0 1 2 3 4 )
|
typeset -a arr=( 0 1 2 3 4 )
|
||||||
|
@ -654,11 +682,16 @@ do err_exit "\${@:0:-1} should not generate ${v:-empty_string}"
|
||||||
break
|
break
|
||||||
done
|
done
|
||||||
|
|
||||||
|
(
|
||||||
|
PS4=$tmpPS4
|
||||||
unset v d
|
unset v d
|
||||||
v=abbbc
|
v=abbbc
|
||||||
d="${v/~(E)b{2,4}/dummy}"
|
d="${v/~(E)b{2,4}/dummy}"
|
||||||
[[ ${.sh.match} == bbb ]] || err_exit '.sh.match wrong after ${s/~(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'
|
[[ $d == adummyc ]] || err_exit '${s/~(E)b{2,4}/dummy} not working'
|
||||||
|
exit $Errors
|
||||||
|
)
|
||||||
|
Errors=$?
|
||||||
|
|
||||||
|
# ======
|
||||||
exit $((Errors<125?Errors:125))
|
exit $((Errors<125?Errors:125))
|
||||||
|
|
|
@ -47,9 +47,10 @@ if (( RANDOM==RANDOM || $RANDOM==$RANDOM ))
|
||||||
then err_exit RANDOM variable not working
|
then err_exit RANDOM variable not working
|
||||||
fi
|
fi
|
||||||
# SECONDS
|
# SECONDS
|
||||||
sleep 3
|
let SECONDS=0.0
|
||||||
if (( SECONDS < 2 ))
|
sleep .001
|
||||||
then err_exit SECONDS variable not working
|
if (( SECONDS < .001 ))
|
||||||
|
then err_exit "either 'sleep' or \$SECONDS not working"
|
||||||
fi
|
fi
|
||||||
# _
|
# _
|
||||||
set abc def
|
set abc def
|
||||||
|
@ -217,6 +218,7 @@ x error"
|
||||||
then err_exit "\${#$i} not correct"
|
then err_exit "\${#$i} not correct"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
kill -s 0 $! || err_exit '$! does not point to latest asynchronous process'
|
||||||
kill $!
|
kill $!
|
||||||
unset x
|
unset x
|
||||||
CDPATH=/
|
CDPATH=/
|
||||||
|
@ -433,12 +435,12 @@ fi
|
||||||
function foo
|
function foo
|
||||||
{
|
{
|
||||||
typeset SECONDS=0
|
typeset SECONDS=0
|
||||||
sleep 1.5
|
sleep .002
|
||||||
print $SECONDS
|
print $SECONDS
|
||||||
|
|
||||||
}
|
}
|
||||||
x=$(foo)
|
x=$(foo)
|
||||||
(( x >1 && x < 2 ))
|
(( x >.001 && x < .01 ))
|
||||||
'
|
'
|
||||||
} 2> /dev/null || err_exit 'SECONDS not working in function'
|
} 2> /dev/null || err_exit 'SECONDS not working in function'
|
||||||
cat > $tmp/script <<-\!
|
cat > $tmp/script <<-\!
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue