: 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) 2012-05-29 $
]
'$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.]
[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. This may cause invalid
regressions, especially for locales where \b.\b is not the radix
point.]
[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
than 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 ENV FIGNORE HISTFILE
trap + PIPE # unadvertized -- set SIGPIPE to SIG_DFL #
integer compile=-1 posix=-1 utf8=-1
integer debug=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
;;
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=':$LINENO: '
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
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=/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
if (( compile ))
then if whence $SHCOMP > /dev/null
then tmp=$(mktemp -dt) || { echo mktemp -dt failed >&2; exit 1; }
trap "cd /; rm -rf $tmp" EXIT
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
if [[ ! $tmp ]]
then tmp=$(mktemp -dt) || { echo mktemp -dt failed >&2; exit 1; }
trap "cd /; rm -rf $tmp" EXIT
fi
valxml=$tmp/valgrind.xml
valgrind+=" --xml-file=$valxml"
fi
typeset -A tests
for i in ${*-*.sh}
do if [[ ! -r $i ]]
then echo $0: $i: not found >&2
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
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)"}
E=error
eval $lang \$valgrind \$SHELL \$trace \$i
e=$?
if [[ $valgrind ]]
then valxml $valxml
(( e += $? ))
fi
if (( e == 0 ))
then echo test $o passed ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"} "[ $t $T 0 ${E}s ]"
else e=$?
if (( e != 1 ))
then E=${E}s
fi
echo test $o failed ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"} with exit code $e "[ $t $T $e $E ]"
fi
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)"}
E=error
if $SHCOMP $i > $c
then if $valgrind $SHELL $trace $c
then echo test $o passed ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"} "[ $t $T 0 ${E}s ]"
else e=$?
if (( e != 1 ))
then E=${E}s
fi
echo test $o failed ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"} with exit code $e "[ $t $T $e $E ]"
fi
else e=$?
t=1
T=test
echo test $o failed to compile ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"} with exit code $e "[ $t $T 1 $E ]"
fi
if [[ $i == $timesensitive ]]
then VMALLOC_OPTIONS=$vmalloc_options
fi
fi
done