mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-02-24 15:04:13 +00:00
The fix was incomplete because some tests have to unset HISTFILE, which reverted them to using ~/.sh_history by default. src/cmd/ksh93/tests/shtests: - Instead of setting HISTFILE, set HOME to the temporary directory $tmp, so nothing will write to the real user directory and the default history file is $tmp/.sh_history. src/cmd/ksh93/tests/attributes.sh: - Restore HISTFILE after a test that requires setting HISTFILE=foo.
447 lines
11 KiB
Text
Executable file
447 lines
11 KiB
Text
Executable file
: ksh regression test harness :
|
|
|
|
USAGE_LICENSE="[-author?David Korn <dgk@research.att.com>][-author?Glenn Fowler <gsf@research.att.com>][-copyright?Copyright (c) 2000-2012 AT&T Intellectual Property][-license?http://www.eclipse.org/org/documents/epl-v10.html]"
|
|
|
|
command=shtests
|
|
|
|
setslocale='*@(locale).sh'
|
|
timesensitive='*@(options|sigchld|subshell).sh'
|
|
valgrindflags='--xml=yes --log-file=/dev/null --track-origins=yes --read-var-info=yes'
|
|
|
|
USAGE=$'
|
|
[-s8?
|
|
@(#)$Id: shtests (AT&T Research/ksh93) 2020-08-11 $
|
|
]
|
|
'$USAGE_LICENSE$'
|
|
[+NAME?shtests - ksh regression test harness]
|
|
[+DESCRIPTION?\bshtests\b is the \bksh\b(1) regression test harness for
|
|
\b$SHELL\b or \bksh\b if \bSHELL\b is not defined and exported. If
|
|
none of the \b--posix --utf8 --compile\b options are specified then
|
|
all three are enabled.]
|
|
[+INPUT FILES?\bshtests\b regression test files are shell scripts that
|
|
run in an environment controlled by \bshtests\b. An identification
|
|
message is printed before and after each test on the standard output.
|
|
The default environment settings are:]
|
|
{
|
|
[+unset LANG]
|
|
[+unset LC_ALL]
|
|
[+LC_NUMERIC=C?\b.\b radix point assumed by all test scripts.]
|
|
[+VMALLOC_OPTIONS=abort?\bvmalloc\b(1) arena checking enabled
|
|
with \babort(2)\b on error.]
|
|
}
|
|
[c:compile?Run test scripts using \bshcomp\b(1).]
|
|
[d:debug?Enable \bshtests\b execution trace.]
|
|
[k:keep?Keep temporary files after test run; shtests will report the location.]
|
|
[l:locale?Disable \b--utf8\b and run the \b--posix\b and \b--compile\b
|
|
tests, if enabled, in the locale of the caller. However, for locales
|
|
where \b.\b is not the radix point, \bLC_NUMERIC\b is set to \bC\b
|
|
to avoid invalid regressions.]
|
|
[p:posix?Run the test scripts in the posix/C locale.]
|
|
[t!:time?Include the current date/time in the test identification
|
|
messages.]
|
|
[u:utf8?Run the test scripts in the ast-specific C.UTF-8 locale.]
|
|
[v!:vmalloc_options?Run tests with \bVMALLOC_OPTIONS=abort\b. Test
|
|
script names matching \b'$timesensitive$'\b are run with
|
|
\bVMALLOC_OPTIONS\b unset.]
|
|
[V:valgrind?Set \b--novmalloc_options\b and run the test scripts with
|
|
\bvalgrind\b(1) on \bksh\b. If \b$SHELL-g\b exists and is executable,
|
|
then it is used instead of \b$SHELL\b.]
|
|
[x:trace?Enable script execution trace.]
|
|
|
|
[ test.sh ... ] [ name=value ... ]
|
|
|
|
[+SEE ALSO?\bksh\b(1), \bregress\b(1), \brt\b(1)]
|
|
'
|
|
|
|
function usage
|
|
{
|
|
OPTIND=0
|
|
getopts -a $command "$USAGE" OPT '--??long'
|
|
exit 2
|
|
}
|
|
|
|
function valxml
|
|
{
|
|
typeset state=INIT data dir file fn line what
|
|
integer errors=0
|
|
|
|
#print === $1 ===; cat $1; print === ===
|
|
while read data
|
|
do case $state in
|
|
INIT) case $data in
|
|
'<error>')
|
|
state=ERROR
|
|
;;
|
|
esac
|
|
;;
|
|
ERROR) case $data in
|
|
'<kind>'Leak*'</kind>')
|
|
state=SKIP
|
|
;;
|
|
'<kind>'*'</kind>')
|
|
state=KEEP
|
|
what=UNKNOWN
|
|
;;
|
|
esac
|
|
;;
|
|
FRAME) case $data in
|
|
'<dir>'*'</dir>')
|
|
dir=${data#'<dir>'}
|
|
dir=${dir%'</dir>'}
|
|
;;
|
|
'<file>'*'</file>')
|
|
file=${data#'<file>'}
|
|
file=${file%'</file>'}
|
|
;;
|
|
'<fn>'*'</fn>')
|
|
fn=${data#'<fn>'}
|
|
fn=${fn%'</fn>'}
|
|
;;
|
|
'<line>'*'</line>')
|
|
line=${data#'<line>'}
|
|
line=${line%'</line>'}
|
|
;;
|
|
'</frame>')
|
|
[[ $dir ]] && dir+=/
|
|
dir+=$file
|
|
[[ $dir ]] && dir+=:
|
|
[[ $line ]] && dir+=$line:
|
|
[[ $fn ]] && dir+=$fn
|
|
[[ $dir ]] && echo $'\t '$dir
|
|
state=KEEP
|
|
;;
|
|
esac
|
|
;;
|
|
KEEP) case $data in
|
|
'<auxwhat>'*'</auxwhat>')
|
|
what=${data#'<auxwhat>'}
|
|
what=${what%'</auxwhat>'}
|
|
echo $'\t'"$what"
|
|
;;
|
|
'<frame>')
|
|
state=FRAME
|
|
dir=
|
|
file=
|
|
fn=
|
|
line=
|
|
;;
|
|
'<what>Syscall param mount(type) points to unaddressable byte(s)</what>')
|
|
state=SKIP
|
|
;;
|
|
'<what>'*'</what>')
|
|
(( errors++ ))
|
|
what=${data#'<what>'}
|
|
what=${what%'</what>'}
|
|
echo $'\n\t'"$what"
|
|
;;
|
|
'<xwhat>')
|
|
state=WHAT
|
|
;;
|
|
'</error>')
|
|
state=INIT
|
|
;;
|
|
esac
|
|
;;
|
|
SKIP) case $data in
|
|
'</error>')
|
|
state=INIT
|
|
;;
|
|
esac
|
|
;;
|
|
WHAT) case $data in
|
|
'<text>'*'</text>')
|
|
(( errors++ ))
|
|
what=${data#'<text>'}
|
|
what=${what%'</text>'}
|
|
echo $'\n\t'"$what"
|
|
;;
|
|
'</xwhat>')
|
|
state=KEEP
|
|
;;
|
|
esac
|
|
;;
|
|
esac
|
|
done < "$1"
|
|
(( errors )) && echo
|
|
return $errors
|
|
}
|
|
|
|
unset DISPLAY FIGNORE HISTFILE
|
|
export ENV=/./dev/null
|
|
trap + PIPE # unadvertized -- set SIGPIPE to SIG_DFL #
|
|
|
|
integer compile=-1 posix=-1 utf8=-1
|
|
integer debug=0 keep=0 locale=0 time=1
|
|
typeset vmalloc_options=abort trace= valgrind=
|
|
vmalloc_options= #XXX# until multi-region vmalloc trace fixed #XXX#
|
|
|
|
while getopts -a $command "$USAGE" OPT
|
|
do case $OPT in
|
|
c) if (( $OPTARG ))
|
|
then compile=2
|
|
else compile=0
|
|
fi
|
|
;;
|
|
d) debug=$OPTARG
|
|
;;
|
|
k) keep=$OPTARG
|
|
;;
|
|
l) locale=$OPTARG
|
|
;;
|
|
p) posix=$OPTARG
|
|
;;
|
|
t) time=$OPTARG
|
|
;;
|
|
u) utf8=$OPTARG
|
|
;;
|
|
v) if (( OPTARG ))
|
|
then vmalloc_options=abort
|
|
else vmalloc_options=
|
|
fi
|
|
;;
|
|
V) valgrind="${VALGRIND:-valgrind} ${VALGRINDFLAGS:-$valgrindflags}"
|
|
vmalloc_options=
|
|
;;
|
|
x) trace=-x
|
|
;;
|
|
*) usage
|
|
;;
|
|
esac
|
|
done
|
|
shift $OPTIND-1
|
|
|
|
if (( debug )) || [[ $trace ]]
|
|
then export PS4='+ [${SECONDS:+${SECONDS%????}s|}${.sh.subshell:+S${.sh.subshell},}${.sh.file:+${.sh.file#${.sh.file%/*/*}/},}${.sh.fun:+${.sh.fun},}${LINENO:+L$LINENO,}e$?] '
|
|
if (( debug ))
|
|
then set -x
|
|
fi
|
|
fi
|
|
|
|
while [[ $1 == *=* ]]
|
|
do eval export "$1"
|
|
shift
|
|
done
|
|
|
|
if (( compile <= 0 && posix <= 0 && utf8 <= 0 ))
|
|
then (( compile )) && compile=1
|
|
(( posix )) && posix=1
|
|
(( utf8 )) && utf8=1
|
|
fi
|
|
(( compile < 0 )) && compile=0
|
|
(( posix < 0 )) && posix=0
|
|
(( utf8 < 0 )) && utf8=0
|
|
if (( locale ))
|
|
then utf8=0
|
|
if [[ $LC_ALL ]]
|
|
then export LANG=$LC_ALL
|
|
unset ${!LC_*}
|
|
fi
|
|
if ! let 1.0 2>/dev/null
|
|
then export LC_NUMERIC=C
|
|
fi
|
|
else unset LANG LC_ALL
|
|
export LC_NUMERIC=C
|
|
fi
|
|
if [[ $VMALLOC_OPTIONS ]]
|
|
then vmalloc_options=$VMALLOC_OPTIONS
|
|
else VMALLOC_OPTIONS=$vmalloc_options
|
|
fi
|
|
[[ $VMALLOC_OPTIONS ]] || timesensitive=.
|
|
export PATH PWD SHCOMP SHELL VMALLOC_OPTIONS
|
|
PWD=$(pwd)
|
|
SHELL=${SHELL-ksh}
|
|
case $0 in
|
|
/*) d=$(dirname $0);;
|
|
*/*) d=$PWD/$(dirname $0);;
|
|
*) d=$PWD;;
|
|
esac
|
|
case $SHELL in
|
|
/*) ;;
|
|
*/*) SHELL=$d/$SHELL;;
|
|
*) SHELL=$(whence $SHELL);;
|
|
esac
|
|
PATH=$(
|
|
PATH=/run/current-system/sw/bin:/usr/xpg7/bin:/usr/xpg6/bin:/usr/xpg4/bin:/bin:/usr/bin:$PATH
|
|
getconf PATH 2>/dev/null || { builtin getconf 2>/dev/null && getconf PATH; }
|
|
) || PATH=/bin:/usr/bin
|
|
if [[ -d /usr/ucb ]]
|
|
then PATH=$PATH:/usr/ucb
|
|
fi
|
|
PATH=$PATH:$d
|
|
if [[ $INSTALLROOT && -r $INSTALLROOT/bin/.paths ]]
|
|
then PATH=$INSTALLROOT/bin:$PATH
|
|
fi
|
|
if [[ ${SHELL%/*} != $INSTALLROOT/bin ]]
|
|
then PATH=${SHELL%/*}:$PATH
|
|
fi
|
|
if [[ ! $SHCOMP ]]
|
|
then s=${SHELL:##*sh}
|
|
s=${SHELL:%/*}/shcomp$s
|
|
if [[ -x $s ]]
|
|
then SHCOMP=$s
|
|
elif [[ -x ${s%-g} ]]
|
|
then SHCOMP=${s%-g}
|
|
else SHCOMP=shcomp
|
|
fi
|
|
fi
|
|
|
|
tmp=$(
|
|
d=${TMPDIR:-/tmp}/ksh93.shtests.$$.${RANDOM:-0}
|
|
mkdir -m700 -- "$d" && CDPATH= cd -P -- "$d" && pwd
|
|
) || {
|
|
echo 'mkdir failed' >&2
|
|
exit 1
|
|
}
|
|
if (( keep ))
|
|
then trap 'printf "\nTemporary files left in: %s\n" "$tmp"' EXIT
|
|
else trap 'cd / && rm -rf "$tmp"' EXIT
|
|
fi
|
|
|
|
# for interactive shell ('ksh -i') tests: avoid affecting ~/.sh_history
|
|
# (some tests must unset or modify $HISTFILE, so set $HOME instead)
|
|
export HOME=$tmp
|
|
|
|
if (( compile ))
|
|
then if whence $SHCOMP > /dev/null
|
|
then :
|
|
elif (( compile > 1 ))
|
|
then echo $0: --compile: $SHCOMP not found >&2
|
|
exit 1
|
|
else compile=0
|
|
fi
|
|
fi
|
|
if [[ $valgrind ]]
|
|
then if [[ -x $SHELL-g ]]
|
|
then SHELL=$SHELL-g
|
|
fi
|
|
valxml=$tmp/valgrind.xml
|
|
valgrind+=" --xml-file=$valxml"
|
|
fi
|
|
typeset -A tests
|
|
typeset -i total_e=0
|
|
for i in ${*-*.sh}
|
|
do [[ $i == *.sh ]] || i+='.sh'
|
|
if [[ ! -r $i ]]
|
|
then echo $0: $i: not found >&2
|
|
(( ++total_e ))
|
|
continue
|
|
fi
|
|
t=$(grep -c err_exit $i)
|
|
if (( t > 2 ))
|
|
then (( t = t - 2 ))
|
|
fi
|
|
tests[$i]=$t
|
|
T=test
|
|
if (( t != 1 ))
|
|
then T=${T}s
|
|
fi
|
|
u=${i##*/}
|
|
u=${u%.sh}
|
|
if [[ $i == $timesensitive ]]
|
|
then VMALLOC_OPTIONS=
|
|
fi
|
|
if (( posix || utf8 ))
|
|
then locales=
|
|
(( posix )) && locales+=" ${LANG:-C}"
|
|
[[ $utf8 == 0 || $i == $setslocale ]] || locales+=" C.UTF-8"
|
|
for lang in $locales
|
|
do o=$u
|
|
tmp_s=$tmp/$u.$lang
|
|
mkdir -m700 "$tmp_s" || exit
|
|
if [[ $lang == C ]]
|
|
then lang=
|
|
else o="$o($lang)"
|
|
lang=LANG=$lang
|
|
fi
|
|
echo test $o begins ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"}
|
|
(
|
|
export ${lang:+"$lang"} "tmp=$tmp_s"
|
|
$valgrind $SHELL $trace $i
|
|
)
|
|
e=$?
|
|
if (( !keep ))
|
|
then rm -rf "$tmp_s"
|
|
fi
|
|
if [[ $valgrind ]]
|
|
then valxml $valxml
|
|
(( e += $? ))
|
|
fi
|
|
if (( e > 128 && ++total_e ))
|
|
then E="(killed by SIG$(kill -l "$e"))"
|
|
elif (( e == 1 && ++total_e ))
|
|
then E="1 error"
|
|
else E="$e errors"
|
|
(( total_e += e ))
|
|
fi
|
|
if (( e == 0 ))
|
|
then echo test $o passed ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"} "[ $t $T $E ]"
|
|
else echo test $o failed ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"} with exit code $e "[ $t $T $E ]"
|
|
fi
|
|
case $E in
|
|
*INT\)) kill -s INT $$ ;; # if test was ^C'd, don't keep going but pass down SIGINT
|
|
esac
|
|
done
|
|
fi
|
|
if (( compile ))
|
|
then c=$tmp/shcomp-$u.ksh
|
|
o="$u(shcomp)"
|
|
echo test $o begins ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"}
|
|
tmp_s=$tmp/$u.shcomp
|
|
mkdir -m700 "$tmp_s" || exit
|
|
if $SHCOMP $i > $c
|
|
then if tmp=$tmp_s $valgrind $SHELL $trace $c
|
|
then echo test $o passed ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"} "[ $t $T 0 errors ]"
|
|
else e=$?
|
|
if (( e > 128 && ++total_e ))
|
|
then E="(killed by SIG$(kill -l "$e"))"
|
|
elif (( e == 1 && ++total_e ))
|
|
then E="1 error"
|
|
else E="$e errors"
|
|
(( total_e += e ))
|
|
fi
|
|
echo test $o failed ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"} with exit code $e "[ $t $T $E ]"
|
|
case $E in
|
|
*INT\)) kill -s INT $$ ;; # if test was ^C'd, don't keep going but pass down SIGINT
|
|
esac
|
|
fi
|
|
else e=$?
|
|
(( ++total_e ))
|
|
echo test $o failed to compile ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"} with exit code $e "[ 1 test 1 error ]"
|
|
fi
|
|
if (( !keep ))
|
|
then rm -rf "$tmp_s" "$c"
|
|
fi
|
|
if [[ $i == $timesensitive ]]
|
|
then VMALLOC_OPTIONS=$vmalloc_options
|
|
fi
|
|
fi
|
|
done
|
|
print "Total errors: $total_e"
|
|
|
|
# This test harness should continue to work with old and buggy versions of ksh93, so check
|
|
# if we have the 'times' builtin and can use process substitution with output redirection.
|
|
# See: https://github.com/ksh93/ksh/commit/65d363fd
|
|
# https://github.com/ksh93/ksh/issues/2
|
|
if ( ulimit -t unlimited # fork to circumvent old ksh bugs
|
|
unalias times
|
|
PATH=/dev/null whence -q times || exit
|
|
cd "$tmp" || exit
|
|
echo ok > >(cat > procsubst_test)
|
|
wait
|
|
[[ $(< procsubst_test) == ok ]]
|
|
) 2>/dev/null
|
|
then # Transforming 'times' output requires a process substitution.
|
|
# A regular 'times | ...' pipeline would cause 'times' to be
|
|
# run in a subshell, which would reset all the times to zero.
|
|
times > >(
|
|
t[0]='CPU time' t[1]='user:' t[2]='system:'
|
|
t[3]='main:'; read t[4] t[5]
|
|
t[6]='tests:'; read t[7] t[8]
|
|
printf '%-8s%12s %12s\n' "${t[@]}"
|
|
)
|
|
wait "$!" # process substitutions are executed asynchronously
|
|
else # No pretty-printing.
|
|
times
|
|
fi
|
|
|
|
exit $((total_e > 125 ? 125 : total_e))
|