1: ksh regression test harness :
2
3USAGE_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]"
4
5command=shtests
6
7setslocale='*@(locale).sh'
8timesensitive='*@(options|sigchld|subshell).sh'
9valgrindflags='--xml=yes --log-file=/dev/null --track-origins=yes --read-var-info=yes'
10
11USAGE=$'
12[-s8?
13@(#)$Id: shtests (AT&T Research) 2012-05-29 $
14]
15'$USAGE_LICENSE$'
16[+NAME?shtests - ksh regression test harness]
17[+DESCRIPTION?\bshtests\b is the \bksh\b(1) regression test harness for
18    \b$SHELL\b or \bksh\b if \bSHELL\b is not defined and exported. If
19    none of the \b--posix --utf8 --compile\b options are specified then
20    all three are enabled.]
21[+INPUT FILES?\bshtests\b regression test files are shell scripts that
22    run in an environment controlled by \bshtests\b. An identification
23    message is printed before and after each test on the standard output.
24    The default environment settings are:]
25    {
26        [+unset LANG]
27        [+unset LC_ALL]
28        [+LC_NUMERIC=C?\b.\b radix point assumed by all test scripts.]
29        [+VMALLOC_OPTIONS=abort?\bvmalloc\b(1) arena checking enabled
30            with \babort(2)\b on error.]
31    }
32[c:compile?Run test scripts using \bshcomp\b(1).]
33[d:debug?Enable \bshtests\b execution trace.]
34[l:locale?Disable \b--utf8\b and run the \b--posix\b and \b--compile\b
35    tests, if enabled, in the locale of the caller. This may cause invalid
36    regressions, especially for locales where \b.\b is not the radix
37    point.]
38[p:posix?Run the test scripts in the posix/C locale.]
39[t!:time?Include the current date/time in the test identification
40    messages.]
41[u:utf8?Run the test scripts in the ast-specific C.UTF-8 locale.]
42[v!:vmalloc_options?Run tests with \bVMALLOC_OPTIONS=abort\b. Test
43    script names matching \b'$timesensitive$'\b are run with
44    \bVMALLOC_OPTIONS\b unset.]
45[V:valgrind?Set \b--novmalloc_options\b and run the test scripts with
46    \bvalgrind\b(1) on \bksh\b. If \b$SHELL-g\b exists and is executable
47    than it is used instead of \b$SHELL\b.]
48[x:trace?Enable script execution trace.]
49
50[ test.sh ... ] [ name=value ... ]
51
52[+SEE ALSO?\bksh\b(1), \bregress\b(1), \brt\b(1)]
53'
54
55function usage
56{
57	OPTIND=0
58	getopts -a $command "$USAGE" OPT '--??long'
59	exit 2
60}
61
62function valxml
63{
64	typeset state=INIT data dir file fn line what
65	integer errors=0
66
67	#print === $1 ===; cat $1; print === ===
68	while	read data
69	do	case $state in
70		INIT)	case $data in
71			'<error>')
72				state=ERROR
73				;;
74			esac
75			;;
76		ERROR)	case $data in
77			'<kind>'Leak*'</kind>')
78				state=SKIP
79				;;
80			'<kind>'*'</kind>')
81				state=KEEP
82				what=UNKNOWN
83				;;
84			esac
85			;;
86		FRAME)	case $data in
87			'<dir>'*'</dir>')
88				dir=${data#'<dir>'}
89				dir=${dir%'</dir>'}
90				;;
91			'<file>'*'</file>')
92				file=${data#'<file>'}
93				file=${file%'</file>'}
94				;;
95			'<fn>'*'</fn>')
96				fn=${data#'<fn>'}
97				fn=${fn%'</fn>'}
98				;;
99			'<line>'*'</line>')
100				line=${data#'<line>'}
101				line=${line%'</line>'}
102				;;
103			'</frame>')
104				[[ $dir ]] && dir+=/
105				dir+=$file
106				[[ $dir ]] && dir+=:
107				[[ $line ]] && dir+=$line:
108				[[ $fn ]] && dir+=$fn
109				[[ $dir ]] && echo $'\t    '$dir
110				state=KEEP
111				;;
112			esac
113			;;
114		KEEP)	case $data in
115			'<auxwhat>'*'</auxwhat>')
116				what=${data#'<auxwhat>'}
117				what=${what%'</auxwhat>'}
118				echo $'\t'"$what"
119				;;
120			'<frame>')
121				state=FRAME
122				dir=
123				file=
124				fn=
125				line=
126				;;
127			'<what>Syscall param mount(type) points to unaddressable byte(s)</what>')
128				state=SKIP
129				;;
130			'<what>'*'</what>')
131				(( errors++ ))
132				what=${data#'<what>'}
133				what=${what%'</what>'}
134				echo $'\n\t'"$what"
135				;;
136			'<xwhat>')
137				state=WHAT
138				;;
139			'</error>')
140				state=INIT
141				;;
142			esac
143			;;
144		SKIP)	case $data in
145			'</error>')
146				state=INIT
147				;;
148			esac
149			;;
150		WHAT)	case $data in
151			'<text>'*'</text>')
152				(( errors++ ))
153				what=${data#'<text>'}
154				what=${what%'</text>'}
155				echo $'\n\t'"$what"
156				;;
157			'</xwhat>')
158				state=KEEP
159				;;
160			esac
161			;;
162		esac
163	done < "$1"
164	(( errors )) && echo
165	return $errors
166}
167
168unset DISPLAY ENV FIGNORE HISTFILE
169trap + PIPE # unadvertized -- set SIGPIPE to SIG_DFL #
170
171integer compile=-1 posix=-1 utf8=-1
172integer debug=0 locale=0 time=1
173typeset vmalloc_options=abort trace= valgrind=
174vmalloc_options= #XXX# until multi-region vmalloc trace fixed #XXX#
175
176while	getopts -a $command "$USAGE" OPT
177do	case $OPT in
178	c)	if	(( $OPTARG ))
179		then	compile=2
180		else	compile=0
181		fi
182		;;
183	d)	debug=$OPTARG
184		;;
185	l)	locale=$OPTARG
186		;;
187	p)	posix=$OPTARG
188		;;
189	t)	time=$OPTARG
190		;;
191	u)	utf8=$OPTARG
192		;;
193	v)	if	(( OPTARG ))
194		then	vmalloc_options=abort
195		else	vmalloc_options=
196		fi
197		;;
198	V)	valgrind="${VALGRIND:-valgrind} ${VALGRINDFLAGS:-$valgrindflags}"
199		vmalloc_options=
200		;;
201	x)	trace=-x
202		;;
203	*)	usage
204		;;
205	esac
206done
207shift $OPTIND-1
208
209if	(( debug )) || [[ $trace ]]
210then	export PS4=':$LINENO: '
211	if	(( debug ))
212	then	set -x
213	fi
214fi
215
216while	[[ $1 == *=* ]]
217do	eval export "$1"
218	shift
219done
220
221if	(( compile <= 0 && posix <= 0 && utf8 <= 0 ))
222then	(( compile )) && compile=1
223	(( posix )) && posix=1
224	(( utf8 )) && utf8=1
225fi
226(( compile < 0 )) && compile=0
227(( posix < 0 )) && posix=0
228(( utf8 < 0 )) && utf8=0
229if	(( locale ))
230then	utf8=0
231	if	[[ $LC_ALL ]]
232	then	export LANG=$LC_ALL
233	fi
234else	unset LANG LC_ALL
235	export LC_NUMERIC=C
236fi
237if	[[ $VMALLOC_OPTIONS ]]
238then	vmalloc_options=$VMALLOC_OPTIONS
239else	VMALLOC_OPTIONS=$vmalloc_options
240fi
241[[ $VMALLOC_OPTIONS ]] || timesensitive=.
242export PATH PWD SHCOMP SHELL VMALLOC_OPTIONS
243PWD=$(pwd)
244SHELL=${SHELL-ksh}
245case $0 in
246/*)	d=$(dirname $0);;
247*/*)	d=$PWD/$(dirname $0);;
248*)	d=$PWD;;
249esac
250case $SHELL in
251/*)	;;
252*/*)	SHELL=$d/$SHELL;;
253*)	SHELL=$(whence $SHELL);;
254esac
255PATH=/bin:/usr/bin
256if	[[ -d /usr/ucb ]]
257then	PATH=$PATH:/usr/ucb
258fi
259PATH=$PATH:$d
260if	[[ $INSTALLROOT && -r $INSTALLROOT/bin/.paths ]]
261then	PATH=$INSTALLROOT/bin:$PATH
262fi
263if	[[ ${SHELL%/*} != $INSTALLROOT/bin ]]
264then	PATH=${SHELL%/*}:$PATH
265fi
266if	[[ ! $SHCOMP ]]
267then	s=${SHELL:##*sh}
268	s=${SHELL:%/*}/shcomp$s
269	if	[[ -x $s ]]
270	then	SHCOMP=$s
271	elif	[[ -x ${s%-g} ]]
272	then	SHCOMP=${s%-g}
273	else	SHCOMP=shcomp
274	fi
275fi
276if	(( compile ))
277then	if	whence $SHCOMP > /dev/null
278	then	tmp=$(mktemp -dt) || { echo mktemp -dt failed >&2; exit 1; }
279		trap "cd /; rm -rf $tmp" EXIT
280	elif	(( compile > 1 ))
281	then	echo $0: --compile: $SHCOMP not found >&2
282		exit 1
283	else	compile=0
284	fi
285fi
286if	[[ $valgrind ]]
287then	if	[[ -x $SHELL-g ]]
288	then	SHELL=$SHELL-g
289	fi
290	if	[[ ! $tmp ]]
291	then	tmp=$(mktemp -dt) || { echo mktemp -dt failed >&2; exit 1; }
292		trap "cd /; rm -rf $tmp" EXIT
293	fi
294	valxml=$tmp/valgrind.xml
295	valgrind+=" --xml-file=$valxml"
296fi
297typeset -A tests
298for i in ${*-*.sh}
299do	if	[[ ! -r $i ]]
300	then	echo $0: $i: not found >&2
301		continue
302	fi
303	t=$(grep -c err_exit $i)
304	if	(( t > 2 ))
305	then	(( t = t - 2 ))
306	fi
307	tests[$i]=$t
308	T=test
309	if	(( t != 1 ))
310	then	T=${T}s
311	fi
312	u=${i##*/}
313	u=${u%.sh}
314	if	[[ $i == $timesensitive ]]
315	then	VMALLOC_OPTIONS=
316	fi
317	if	(( posix || utf8 ))
318	then	locales=
319		(( posix )) && locales+=" ${LANG:-C}"
320		[[ $utf8 == 0 || $i == $setslocale ]] || locales+=" C.UTF-8"
321		for lang in $locales
322		do	o=$u
323			if	[[ $lang == C ]]
324			then	lang=
325			else	o="$o($lang)"
326				lang=LANG=$lang
327			fi
328			echo test $o begins ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"}
329			E=error
330			eval $lang \$valgrind \$SHELL \$trace \$i
331			e=$?
332			if	[[ $valgrind ]]
333			then	valxml $valxml
334				(( e += $? ))
335			fi
336			if	(( e == 0 ))
337			then	echo test $o passed ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"} "[ $t $T 0 ${E}s ]"
338			else	e=$?
339				if	(( e != 1 ))
340				then	E=${E}s
341				fi
342				echo test $o failed ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"} with exit code $e "[ $t $T $e $E ]"
343			fi
344		done
345	fi
346	if	(( compile ))
347	then	c=$tmp/shcomp-$u.ksh
348		o="$u(shcomp)"
349		echo test $o begins ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"}
350		E=error
351		if	$SHCOMP $i > $c
352		then	if	$valgrind $SHELL $trace $c
353			then	echo test $o passed ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"} "[ $t $T 0 ${E}s ]"
354			else	e=$?
355				if	(( e != 1 ))
356				then	E=${E}s
357				fi
358				echo test $o failed ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"} with exit code $e "[ $t $T $e $E ]"
359			fi
360		else	e=$?
361			t=1
362			T=test
363			echo test $o failed to compile ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"} with exit code $e "[ $t $T 1 $E ]"
364		fi
365		if	[[ $i == $timesensitive ]]
366		then	VMALLOC_OPTIONS=$vmalloc_options
367		fi
368	fi
369done
370