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 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

View file

@ -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

View 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'"

View file

@ -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=$!

View file

@ -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

View file

@ -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")"

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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'

View file

@ -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

View file

@ -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

View file

@ -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))

View file

@ -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 <<-\!