diff options
Diffstat (limited to 'tools/regression/usr.bin')
| -rw-r--r-- | tools/regression/usr.bin/cc/Makefile | 10 | ||||
| -rw-r--r-- | tools/regression/usr.bin/cc/float.c | 269 | ||||
| -rw-r--r-- | tools/regression/usr.bin/cc/float.t | 9 | ||||
| -rw-r--r-- | tools/regression/usr.bin/env/Makefile | 15 | ||||
| -rw-r--r-- | tools/regression/usr.bin/env/regress-env.rgdata | 416 | ||||
| -rw-r--r-- | tools/regression/usr.bin/env/regress-sb.rb | 540 | 
6 files changed, 1259 insertions, 0 deletions
diff --git a/tools/regression/usr.bin/cc/Makefile b/tools/regression/usr.bin/cc/Makefile new file mode 100644 index 000000000000..1f8b5d8f03fd --- /dev/null +++ b/tools/regression/usr.bin/cc/Makefile @@ -0,0 +1,10 @@ +TESTS=	float +CFLAGS+=-lm + +.PHONY: tests +tests: ${TESTS} +	for p in ${TESTS}; do ${.OBJDIR}/$$p; done + +.PHONY: clean +clean: +	-rm -f ${TESTS} diff --git a/tools/regression/usr.bin/cc/float.c b/tools/regression/usr.bin/cc/float.c new file mode 100644 index 000000000000..e08e0f5a6174 --- /dev/null +++ b/tools/regression/usr.bin/cc/float.c @@ -0,0 +1,269 @@ +/*- + * Copyright (c) 2012 David Schultz <das@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Test that floating-point arithmetic works as specified by the C standard. + */ + +#include <sys/cdefs.h> +#include <fenv.h> +#include <float.h> +#include <math.h> +#include <stdio.h> + +#ifdef  __i386__ +#include <ieeefp.h> +#endif + +#define	ALL_STD_EXCEPT	(FE_DIVBYZERO | FE_INEXACT | FE_INVALID | \ +			 FE_OVERFLOW | FE_UNDERFLOW) + +#define	TWICE(x)		((x) + (x)) +#define	test(desc, pass)	test1((desc), (pass), 0) +#define	skiptest(desc, pass)	test1((desc), (pass), 1) + +#pragma STDC FENV_ACCESS ON + +static const float one_f = 1.0 + FLT_EPSILON / 2; +static const double one_d = 1.0 + DBL_EPSILON / 2; +static const long double one_ld = 1.0L + LDBL_EPSILON / 2; + +static int testnum, failures; + +static void +test1(const char *testdesc, int pass, int skip) +{ + +	testnum++; +	printf("%sok %d - %s%s\n", pass || skip ? "" : "not ", testnum,  +	    skip ? "(SKIPPED) " : "", testdesc); +	if (!pass && !skip) +		failures++; +} + +/* + * Compare d1 and d2 using special rules: NaN == NaN and +0 != -0. + */ +static int +fpequal(long double d1, long double d2) +{ + +	if (d1 != d2) +		return (isnan(d1) && isnan(d2)); +	return (copysignl(1.0, d1) == copysignl(1.0, d2)); +} + +void +run_zero_opt_test(double d1, double d2) +{ + +	test("optimizations don't break the sign of 0", +	     fpequal(d1 - d2, 0.0) +	     && fpequal(-d1 + 0.0, 0.0) +	     && fpequal(-d1 - d2, -0.0) +	     && fpequal(-(d1 - d2), -0.0) +	     && fpequal(-d1 - (-d2), 0.0)); +} + +void +run_inf_opt_test(double d) +{ + +	test("optimizations don't break infinities", +	     fpequal(d / d, NAN) && fpequal(0.0 * d, NAN)); +} + +static inline double +todouble(long double ld) +{ + +	return (ld); +} + +static inline float +tofloat(double d) +{ + +	return (d); +} + +void +run_tests(void) +{ +	volatile long double vld; +	long double ld; +	volatile double vd; +	double d; +	volatile float vf; +	float f; +	int x; + +	test("sign bits", fpequal(-0.0, -0.0) && !fpequal(0.0, -0.0)); + +	vd = NAN; +	test("NaN equality", fpequal(NAN, NAN) && NAN != NAN && vd != vd); + +	feclearexcept(ALL_STD_EXCEPT); +	test("NaN comparison returns false", !(vd <= vd)); +	/* +	 * XXX disabled; gcc/amd64 botches this IEEE 754 requirement by +	 * emitting ucomisd instead of comisd. +	 */ +	skiptest("FENV_ACCESS: NaN comparison raises invalid exception", +	    fetestexcept(ALL_STD_EXCEPT) == FE_INVALID); + +	vd = 0.0; +	run_zero_opt_test(vd, vd); + +	vd = INFINITY; +	run_inf_opt_test(vd); + +	feclearexcept(ALL_STD_EXCEPT); +	vd = INFINITY; +	x = (int)vd; +	/* XXX disabled (works with -O0); gcc doesn't support FENV_ACCESS */ +	skiptest("FENV_ACCESS: Inf->int conversion raises invalid exception", +	    fetestexcept(ALL_STD_EXCEPT) == FE_INVALID); + +	/* Raising an inexact exception here is an IEEE-854 requirement. */ +	feclearexcept(ALL_STD_EXCEPT); +	vd = 0.75; +	x = (int)vd; +	test("0.75->int conversion rounds toward 0, raises inexact exception", +	     x == 0 && fetestexcept(ALL_STD_EXCEPT) == FE_INEXACT); + +	feclearexcept(ALL_STD_EXCEPT); +	vd = -42.0; +	x = (int)vd; +	test("-42.0->int conversion is exact, raises no exception", +	     x == -42 && fetestexcept(ALL_STD_EXCEPT) == 0); + +	feclearexcept(ALL_STD_EXCEPT); +	x = (int)INFINITY; +	/* XXX disabled; gcc doesn't support FENV_ACCESS */ +	skiptest("FENV_ACCESS: const Inf->int conversion raises invalid", +	    fetestexcept(ALL_STD_EXCEPT) == FE_INVALID); + +	feclearexcept(ALL_STD_EXCEPT); +	x = (int)0.5; +	/* XXX disabled; gcc doesn't support FENV_ACCESS */ +	skiptest("FENV_ACCESS: const double->int conversion raises inexact", +	     x == 0 && fetestexcept(ALL_STD_EXCEPT) == FE_INEXACT); + +	test("compile-time constants don't have too much precision", +	     one_f == 1.0L && one_d == 1.0L && one_ld == 1.0L); + +	test("const minimum rounding precision", +	     1.0F + FLT_EPSILON != 1.0F && +	     1.0 + DBL_EPSILON != 1.0 && +	     1.0L + LDBL_EPSILON != 1.0L); + +	/* It isn't the compiler's fault if this fails on FreeBSD/i386. */ +	vf = FLT_EPSILON; +	vd = DBL_EPSILON; +	vld = LDBL_EPSILON; +	test("runtime minimum rounding precision", +	     1.0F + vf != 1.0F && 1.0 + vd != 1.0 && 1.0L + vld != 1.0L); + +	test("explicit float to float conversion discards extra precision", +	     (float)(1.0F + FLT_EPSILON * 0.5F) == 1.0F && +	     (float)(1.0F + vf * 0.5F) == 1.0F); +	test("explicit double to float conversion discards extra precision", +	     (float)(1.0 + FLT_EPSILON * 0.5) == 1.0F && +	     (float)(1.0 + vf * 0.5) == 1.0F); +	test("explicit ldouble to float conversion discards extra precision", +	     (float)(1.0L + FLT_EPSILON * 0.5L) == 1.0F && +	     (float)(1.0L + vf * 0.5L) == 1.0F); + +	test("explicit double to double conversion discards extra precision", +	     (double)(1.0 + DBL_EPSILON * 0.5) == 1.0 && +	     (double)(1.0 + vd * 0.5) == 1.0); +	test("explicit ldouble to double conversion discards extra precision", +	     (double)(1.0L + DBL_EPSILON * 0.5L) == 1.0 && +	     (double)(1.0L + vd * 0.5L) == 1.0); + +	/* +	 * FLT_EVAL_METHOD > 1 implies that float expressions are always +	 * evaluated in double precision or higher, but some compilers get +	 * this wrong when registers spill to memory.  The following expression +	 * forces a spill when there are at most 8 FP registers. +	 */ +	test("implicit promption to double or higher precision is consistent", +#if FLT_EVAL_METHOD == 1 || FLT_EVAL_METHOD == 2 || defined(__i386__) +	       TWICE(TWICE(TWICE(TWICE(TWICE( +	           TWICE(TWICE(TWICE(TWICE(1.0F + vf * 0.5F))))))))) +	     == (1.0 + FLT_EPSILON * 0.5) * 512.0 +#else +	     1 +#endif +	    ); + +	f = 1.0 + FLT_EPSILON * 0.5; +	d = 1.0L + DBL_EPSILON * 0.5L; +	test("const assignment discards extra precision", f == 1.0F && d == 1.0); + +	f = 1.0 + vf * 0.5; +	d = 1.0L + vd * 0.5L; +	test("variable assignment discards explicit extra precision", +	     f == 1.0F && d == 1.0); +	f = 1.0F + vf * 0.5F; +	d = 1.0 + vd * 0.5; +	test("variable assignment discards implicit extra precision", +	     f == 1.0F && d == 1.0); + +	test("return discards extra precision", +	     tofloat(1.0 + vf * 0.5) == 1.0F && +	     todouble(1.0L + vd * 0.5L) == 1.0); + +	fesetround(FE_UPWARD); +	/* XXX disabled (works with -frounding-math) */ +	skiptest("FENV_ACCESS: constant arithmetic respects rounding mode", +	    1.0F + FLT_MIN == 1.0F + FLT_EPSILON && +	    1.0 + DBL_MIN == 1.0 + DBL_EPSILON && +	    1.0L + LDBL_MIN == 1.0L + LDBL_EPSILON); +	fesetround(FE_TONEAREST); + +	ld = vld * 0.5; +	test("associativity is respected", +	     1.0L + ld + (LDBL_EPSILON * 0.5) == 1.0L && +	     1.0L + (LDBL_EPSILON * 0.5) + ld == 1.0L && +	     ld + 1.0 + (LDBL_EPSILON * 0.5) == 1.0L && +	     ld + (LDBL_EPSILON * 0.5) + 1.0 == 1.0L + LDBL_EPSILON); +} + +int +main(int argc, char *argv[]) +{ + +	printf("1..26\n"); + +#ifdef  __i386__ +	fpsetprec(FP_PE); +#endif +	run_tests(); + +	return (failures); +} diff --git a/tools/regression/usr.bin/cc/float.t b/tools/regression/usr.bin/cc/float.t new file mode 100644 index 000000000000..74eb8c9c581d --- /dev/null +++ b/tools/regression/usr.bin/cc/float.t @@ -0,0 +1,9 @@ +#!/bin/sh + +cd `dirname $0` + +executable=`basename $0 .t` + +make $executable 2>&1 > /dev/null + +exec ./$executable diff --git a/tools/regression/usr.bin/env/Makefile b/tools/regression/usr.bin/env/Makefile new file mode 100644 index 000000000000..06f1fbe82e23 --- /dev/null +++ b/tools/regression/usr.bin/env/Makefile @@ -0,0 +1,15 @@ +TESTPGM?=TestProgramNotSpecifed + +all: +	@echo "Note that the 'env' command uses its own regression suite," +	@echo "which uses a single data file and a script written in ruby." +	@echo "By default it will test /usr/bin/env" +	@echo +	@ruby regress-sb.rb --rgdata=${.CURDIR}/regress-env.rgdata + +#   A version which allows the user to specify which executable of `env' +#   should be tested, e.g.:    make testenv TESTPROG=/usr/bin/env-rel6 +#   This will probably need a bit more thought... +testenv: +	@ruby regress-sb.rb --rgdata=${.CURDIR}/regress-env.rgdata \ +	 --testpgm=${TESTPGM} diff --git a/tools/regression/usr.bin/env/regress-env.rgdata b/tools/regression/usr.bin/env/regress-env.rgdata new file mode 100644 index 000000000000..490ae1c84089 --- /dev/null +++ b/tools/regression/usr.bin/env/regress-env.rgdata @@ -0,0 +1,416 @@ +#- +# Copyright (c) 2005  - Garance Alistair Drosehn <gad@FreeBSD.org>. +# All rights reserved. +# +#  Redistribution and use in source and binary forms, with or without +#  modification, are permitted provided that the following conditions +#  are met: +#  1. Redistributions of source code must retain the above copyright +#     notice, this list of conditions and the following disclaimer. +#  2. Redistributions in binary form must reproduce the above copyright +#     notice, this list of conditions and the following disclaimer in the +#     documentation and/or other materials provided with the distribution. +# +#  THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +#  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +#  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +#  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +#  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +#  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +#  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +#  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +#  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +#  SUCH DAMAGE. +# +# + +testpgm=/usr/bin/env +gblenv=PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin +gblenv=TESTVAR=Global-TV-Value +gblenv=OUTSIDEVAR=OutsideValue + +#  These first two tests are testing how well the regression-script itself is +#  handling environment-variables, as much as testing the `env' program. +[test] +   sb_args:/bin/sh +   setenv:TESTVAR=a1a +   script:/bin/echo A-${TESTVAR}-Z +   stdout:A-a1a-Z +[run] +[test] +   sb_args:-S /bin/sh +   script:/bin/echo A-${TESTVAR}-Z +   stdout:A-Global-TV-Value-Z +[run] + +[test] +   sb_args:-S TESTVAR=bb22bb /bin/sh +   script:/bin/echo A-${TESTVAR}-Z +   stdout:A-bb22bb-Z +[run] +[test] +   sb_args:-S\_TESTVAR=ab22ab\_/bin/sh +   script:/bin/echo A-${TESTVAR}-Z +   stdout:A-ab22ab-Z +[run] +[test] +   sb_args:-S\_TESTVAR="abc\_33\_abc"\_/bin/sh +   script:/bin/echo A-${TESTVAR}-Z +   stdout:A-abc 33 abc-Z +[run] + +#   First we see that 'sh' can not be found in /usr/sbin, and then +#   we show that it can be found without changing PATH by using -P +#   And then show that it can be NOT found by using -P... +[test] +   sb_args:-S sh +   setenv:PATH=/usr/sbin +   script:/bin/echo A-${PATH}-Z +   $?:127 +   stderr:[%-testpgm.basename-%]: sh: No such file or directory +[run] +[test] +   sb_args:-S -P/bin sh +   setenv:PATH=/usr/sbin +   script:/bin/echo A-${PATH}-Z +   stdout:A-/usr/sbin-Z +[run] +[test] +   sb_args:-S -P/sbin:/usr/sbin sh +   script:/bin/echo A-${PATH}-Z +   $?:127 +   stderr:[%-testpgm.basename-%]: sh: No such file or directory +[run] + +#  Hmm.  I wonder if -P should always set an 'ENV_PATH' variable? +[test] +   sb_args:-S -P/bin:/usr/bin:${PATH} ENV_PATH=/bin:/usr/bin:${PATH} sh +   setenv:PATH=/usr/sbin +   script:/bin/echo A-${PATH}-Z +   script:/bin/echo B-${ENV_PATH}-Y +   stdout:A-/usr/sbin-Z +   stdout:B-/bin:/usr/bin:/usr/sbin-Y +[run] + +#   Show that the comment-characters are working, both for where they are +#   recognized and where they are ignored. +[test] +   sb_args:-STESTVAR="abc44abc" /bin/sh # This is some arbitrary text +   user_args:us11er us22er +   script:/bin/echo A-${TESTVAR}-Z B-$1-Y +   stdout:A-abc44abc-Z B-us11er-Y +[run] +[test] +   sb_args:-STESTVAR="abc55abc" /bin/sh \c This is some arbitrary text +   user_args:us11er us22er +   script:/bin/echo A-${TESTVAR}-Z B-$1-Y +   stdout:A-abc55abc-Z B-us11er-Y +[run] +[test] +   sb_args:-STESTVAR=abc#44#abc /bin/sh +   user_args:us11er us22er +   script:/bin/echo A-${TESTVAR}-Z B-$1-Y +   stdout:A-abc#44#abc-Z B-us11er-Y +[run] +[test] +   sb_args:-STESTVAR='abc\c55\cabc' /bin/sh +   user_args:us11er us22er +   script:/bin/echo A-${TESTVAR}-Z B-$1-Y +   stdout:A-abc\c55\cabc-Z B-us11er-Y +[run] + +#   Test various aspects of quoted strings +[test] +   sb_args:-STESTVAR="abc'def" /bin/sh +   script:/bin/echo A-${TESTVAR}-Z +   stdout:A-abc'def-Z +[run] +[test] +   sb_args:-STESTVAR='abc"def' /bin/sh +   script:/bin/echo A-${TESTVAR}-Z +   stdout:A-abc"def-Z +[run] +[test] +   sb_args:-STESTVAR='ab\'cd\'ef' /bin/sh +   script:/bin/echo A-${TESTVAR}-Z +   stdout:A-ab'cd'ef-Z +[run] +[test] +   sb_args:-STESTVAR='abc\"def\'ghi' /bin/sh +   script:/bin/echo A-${TESTVAR}-Z +   stdout:A-abc\"def'ghi-Z +[run] +[test] +   sb_args:-STESTVAR='abc''def''ghi' /bin/sh +   script:/bin/echo A-${TESTVAR}-Z +   stdout:A-abcdefghi-Z +[run] +[test] +   sb_args:-STESTVAR='abc\ndef\nghi' /bin/sh +   script:/bin/echo "A-${TESTVAR}-Z" +   stdout:A-abc\ndef\nghi-Z +[run] +[test] +   sb_args:-STESTVAR="abc\ndef\nghi" /bin/sh +   script:/bin/echo "A-${TESTVAR}-Z" +   stdout:A-abc +   stdout:def +   stdout:ghi-Z +[run] +[test] +   sb_args:-STESTVAR=""\_OTHERVAR=""\_/bin/sh +   script:/bin/echo A-${TESTVAR}-M-${OTHERVAR}-Z +   stdout:A--M--Z +[run] +[test] +   sb_args:-STESTVAR=no-term-"-dq... /bin/sh +   script:/bin/echo "A-${TESTVAR}-Z" +   $?:1 +   stderr:[%-testpgm.basename-%]: No terminating quote for string: TESTVAR=no-term-"-dq... /bin/sh +[run] +[test] +   sb_args:-STESTVAR=no-term-'-sq... /bin/sh +   script:/bin/echo "A-${TESTVAR}-Z" +   $?:1 +   stderr:[%-testpgm.basename-%]: No terminating quote for string: TESTVAR=no-term-'-sq... /bin/sh +[run] + +# Some tests of variable-substitution. +[test] +   sb_args:-S TESTVAR=${TEST7} /bin/sh +   setenv:TEST7=a23456a +   script:/bin/echo "A-${TESTVAR}-Z" +   stdout:A-a23456a-Z +[run] +[test] +   sb_args:-S TESTVAR=${TEST8} /bin/sh +   setenv:TEST8=b234567b +   script:/bin/echo "A-${TESTVAR}-Z" +   stdout:A-b234567b-Z +[run] +[test] +   sb_args:-S TESTVAR=${TEST9} /bin/sh +   setenv:TEST9=c2345678c +   script:/bin/echo "A-${TESTVAR}-Z" +   stdout:A-c2345678c-Z +[run] +[test] +   sb_args:-S TESTVAR=${TEST8}+${TEST9}+${TEST10} /bin/sh +   setenv:TEST8=a234567z +   setenv:TEST9=a2345678z +   setenv:TEST10=a23456789z +   script:/bin/echo "A-${TESTVAR}-Z" +   stdout:A-a234567z+a2345678z+a23456789z-Z +[run] +[test] +   sb_args:-S TESTVAR=$* /bin/sh +   script:/bin/echo "A-${TESTVAR}-Z" +   $?:1 +   stderr:[%-testpgm.basename-%]: Only ${VARNAME} expansion is supported, error at: $* /bin/sh +[run] +[test] +   sb_args:-S TESTVAR=/usr/bin:$PATH /bin/sh +   script:/bin/echo "A-${TESTVAR}-Z" +   $?:1 +   stderr:[%-testpgm.basename-%]: Only ${VARNAME} expansion is supported, error at: $PATH /bin/sh +[run] + +#  For a short time `env' was changed to recognize 'something=value' as a +#  valid utility name if 'something' begins with a '/'.  However, that was +#  a bad idea, since variable-names with a '/' -- while rare -- are still +#  more blessed by standards than a filename with an '=' in it.  So, this +#  test goes back to expecting an error... +[test] +   symlink:/bin/echo /tmp/envtest=echo +   sb_args:-S/tmp/envtest=echo false +   $?:1 +[run] + +# Show interactions between -i (clear environment), and ${VAR} substitution, +# and that -i will clear the environment at the right point in processing... +[test] +   sb_args:-iS PATH=/bin:/usr/bin:/Not WASPATH=${PATH} WASOUT=${OUTSIDEVAR} TESTVAR=SbValue WASTEST=${TESTVAR} /bin/sh +   script:/bin/echo "=== set ===" +   script:# drop some environment variables that 'sh' itself sets, and +   script:# then have 'set' print out all remaining environment variables. +   script:# (can't unset OPTIND/PWD, so we use grep to get rid of those) +   script:unset -v IFS PS1 PS2 PS4 PPID +   script:set | grep -Ev '^(OPTIND|PWD)=' | sort +   stdout:=== set === +   stdout:PATH=/bin:/usr/bin:/Not +   stdout:TESTVAR=SbValue +   stdout:WASOUT=OutsideValue +   stdout:WASPATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin +   stdout:WASTEST=Global-TV-Value +[run] + +# Had a bug with ${VAR} expansion if the character before the $ was +# one of the argument-separator characters.  So the first of the +# following worked, but the second one failed: +[test] +   sb_args:-Secho Testv:${TESTV} Scriptname: +   setenv:TESTV=ab/ba +   stdout:Testv:ab/ba Scriptname: [%-script.pathname-%] +[run] +[test] +   sb_args:-Secho testV: ${TESTV} scriptname: +   setenv:TESTV=cd/dc +   stdout:testV: cd/dc scriptname: [%-script.pathname-%] +[run] + +#  A "nothing variable" inside a quoted string should produce a zero-length +#  argument, but if it's outside of quotes then it should result in, well, +#  nothing.  Note the tricks we play with [%-script.pathname-%] so that we +#  can supply parameters *to* the script, even though the kernel is always +#  going to stick the script name on as ARG[2] when invoking `env'. +[test] +   sb_args:-S/bin/sh [%-script.pathname-%] userDQ: "" SQ: '' scriptname: +   setenv:TNADA= +   script:printf "list_args.sh with \$# = $#\n" +   script:# Process all parameters. +   script:N=0 +   script:while test $# != 0 ; do +   script:    N=$(($N+1)) +   script:    printf "....\$$N = [%3d] '$1'\n" ${#1} +   script:    shift +   script:done +   stdout:list_args.sh with $# = 6 +   stdout:....$1 = [  7] 'userDQ:' +   stdout:....$2 = [  0] '' +   stdout:....$3 = [  3] 'SQ:' +   stdout:....$4 = [  0] '' +   stdout:....$5 = [ 11] 'scriptname:' +   stdout:....$6 = [ 16] '/tmp/env-regress' +[run] +[test] +   sb_args:-S/bin/sh [%-script.pathname-%] userB "${TNADA}" scriptname: +   setenv:TNADA= +   script:printf "list_args.sh with \$# = $#\n" +   script:# Process all parameters. +   script:N=0 +   script:while test $# != 0 ; do +   script:    N=$(($N+1)) +   script:    printf "....\$$N = [%3d] '$1'\n" ${#1} +   script:    shift +   script:done +   stdout:list_args.sh with $# = 4 +   stdout:....$1 = [  5] 'userB' +   stdout:....$2 = [  0] '' +   stdout:....$3 = [ 11] 'scriptname:' +   stdout:....$4 = [ 16] '/tmp/env-regress' +[run] +[test] +   sb_args:-S/bin/sh [%-script.pathname-%] userA ${TNADA} scriptname: +   setenv:TNADA= +   script:printf "list_args.sh with \$# = $#\n" +   script:# Process all parameters. +   script:N=0 +   script:while test $# != 0 ; do +   script:    N=$(($N+1)) +   script:    printf "....\$$N = [%3d] '$1'\n" ${#1} +   script:    shift +   script:done +   stdout:list_args.sh with $# = 3 +   stdout:....$1 = [  5] 'userA' +   stdout:....$2 = [ 11] 'scriptname:' +   stdout:....$3 = [ 16] '[%-script.pathname-%]' +[run] +[test] +   sb_args:-S/bin/sh [%-script.pathname-%] ${A} ${NB} ${C} ${ND} ${NE} ${F} S: +   setenv:A=A_ThisisAlongstring_A1 +   setenv:NB= +   setenv:C=C_ThisisAlongstring_C1 +   setenv:ND= +   setenv:NE= +   setenv:F=F_ThisisAlongstring_F1 +   script:printf "list_args.sh with \$# = $#\n" +   script:# Process all parameters. +   script:N=0 +   script:while test $# != 0 ; do +   script:    N=$(($N+1)) +   script:    printf "....\$$N = [%3d] '$1'\n" ${#1} +   script:    shift +   script:done +   stdout:list_args.sh with $# = 5 +   stdout:....$1 = [ 22] 'A_ThisisAlongstring_A1' +   stdout:....$2 = [ 22] 'C_ThisisAlongstring_C1' +   stdout:....$3 = [ 22] 'F_ThisisAlongstring_F1' +   stdout:....$4 = [  2] 'S:' +   stdout:....$5 = [ 16] '/tmp/env-regress' +[run] +[test] +   sb_args:-S/bin/sh [%-script.pathname-%] ${A} ${NB} "${NB}" ${NB} ${C} "${ND}" ${NE} ${F} S: +   setenv:A=A_ThisisAlongstring_A1 +   setenv:NB= +   setenv:C=C_ThisisAlongstring_C1 +   setenv:ND= +   setenv:NE= +   setenv:F=F_ThisisAlongstring_F1 +   script:printf "list_args.sh with \$# = $#\n" +   script:# Process all parameters. +   script:N=0 +   script:while test $# != 0 ; do +   script:    N=$(($N+1)) +   script:    printf "....\$$N = [%3d] '$1'\n" ${#1} +   script:    shift +   script:done +   stdout:list_args.sh with $# = 7 +   stdout:....$1 = [ 22] 'A_ThisisAlongstring_A1' +   stdout:....$2 = [  0] '' +   stdout:....$3 = [ 22] 'C_ThisisAlongstring_C1' +   stdout:....$4 = [  0] '' +   stdout:....$5 = [ 22] 'F_ThisisAlongstring_F1' +   stdout:....$6 = [  2] 'S:' +   stdout:....$7 = [ 16] '/tmp/env-regress' +[run] + +[test] +   sb_args:-S/bin/echo ${A} ${B} ${C} ${D} ScriptName: +   setenv:A=A_ThisisAlongstring_A1 +   setenv:B=B_ThisisAlongstring_B1 +   setenv:C=C_ThisisAlongstring_C1 +   setenv:D=D_ThisisAlongstring_D1 +   stdout:A_ThisisAlongstring_A1 B_ThisisAlongstring_B1 C_ThisisAlongstring_C1 D_ThisisAlongstring_D1 ScriptName: [%-script.pathname-%] +[run] +[test] +   sb_args:-S/bin/echo ${A} "${B}" ${C} "${D}" ScriptName: +   setenv:A=A_ThisisAlongstring_A1 +   setenv:B=B_ThisisAlongstring_B1 +   setenv:C=C_ThisisAlongstring_C1 +   setenv:D=D_ThisisAlongstring_D1 +   stdout:A_ThisisAlongstring_A1 B_ThisisAlongstring_B1 C_ThisisAlongstring_C1 D_ThisisAlongstring_D1 ScriptName: [%-script.pathname-%] +[run] + +[test] +   sb_args:sh +   script:[%-testpgm.pathname-%] -S '\c' >/dev/null +[run] +[test] +   sb_args:sh +   script:[%-testpgm.pathname-%] -S'\c' >/dev/null +[run] +[test] +   sb_args:sh +   script:[%-testpgm.pathname-%] -u foo -S '\c' >/dev/null +[run] +[test] +   sb_args:sh +   script:[%-testpgm.pathname-%] -u foo -S'\c' >/dev/null +[run] +[test] +   sb_args:sh +   script:[%-testpgm.pathname-%] -S '-u bar \c' >/dev/null +[run] +[test] +   sb_args:sh +   script:[%-testpgm.pathname-%] -S'-u bar \c' >/dev/null +[run] +[test] +   sb_args:sh +   script:[%-testpgm.pathname-%] -u foo -S '-u bar \c' >/dev/null +[run] +[test] +   sb_args:sh +   script:[%-testpgm.pathname-%] -u foo -S'-u bar \c' >/dev/null +[run] diff --git a/tools/regression/usr.bin/env/regress-sb.rb b/tools/regression/usr.bin/env/regress-sb.rb new file mode 100644 index 000000000000..b784dcec3e50 --- /dev/null +++ b/tools/regression/usr.bin/env/regress-sb.rb @@ -0,0 +1,540 @@ +#!/usr/local/bin/ruby +# -------+---------+---------+-------- + --------+---------+---------+---------+ +# Copyright (c) 2005  - Garance Alistair Drosehn <gad@FreeBSD.org>. +# All rights reserved. +# +#  Redistribution and use in source and binary forms, with or without +#  modification, are permitted provided that the following conditions +#  are met: +#  1. Redistributions of source code must retain the above copyright +#     notice, this list of conditions and the following disclaimer. +#  2. Redistributions in binary form must reproduce the above copyright +#     notice, this list of conditions and the following disclaimer in the +#     documentation and/or other materials provided with the distribution. +# +#  THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +#  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +#  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +#  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +#  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +#  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +#  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +#  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +#  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +#  SUCH DAMAGE. +# -------+---------+---------+-------- + --------+---------+---------+---------+ +# -------+---------+---------+-------- + --------+---------+---------+---------+ +#   This script was written to provide a battery of regression-tests for some +# changes I am making to the `env' command.  I wrote a new script for this +# for several reasons.  1) I needed to test all kinds of special-character +# combinations, and I wanted to be able to type those in exactly as they would +# would be in real-life situations.  2) I wanted to set environment variables +# before executing a test, 3) I had many different details to test, so I wanted +# to write up dozens of tests, without needing to create a hundred separate +# little tiny files, 4) I wanted to test *failure* conditions, where I expected +# the test would fail but I wanted to be sure that it failed the way I intended +# it to fail. +#   This script was written for the special "shebang-line" testing that I +# wanted for my changes to `env', but I expect it could be turned into a +# general-purpose test-suite with a little more work. +#							Garance/June 12/2005 +# -------+---------+---------+-------- + --------+---------+---------+---------+ + + +# -------+---------+---------+-------- + --------+---------+---------+---------+ +class ExpectedResult +    attr_writer :cmdvalue, :shebang_args, :user_args +    @@gbl_envs = Hash.new + +    def ExpectedResult.add_gblenv(avar, avalue) +	@@gbl_envs[avar] = avalue +    end + +    def initialize +	@shebang_args = "" +	@cmdvalue = 0 +	@clear_envs = Hash.new +	@new_envs = Hash.new +	@old_envs = Hash.new +	@script_lines = "" +	@expect_err = Array.new +	@expect_out = Array.new +	@symlinks = Array.new +	@user_args = nil +    end + +    def add_expecterr(aline) +	@expect_err << aline +    end + +    def add_expectout(aline) +	@expect_out << aline +    end + +    def add_script(aline) +	@script_lines += aline +	@script_lines += "\n"	if aline[-1] != "\n" +    end + +    def add_clearenv(avar) +	@clear_envs[avar] = true +    end + +    def add_setenv(avar, avalue) +	@new_envs[avar] = avalue +    end + +    def add_symlink(srcf, newf) +	@symlinks << Array.[](srcf, newf) +    end + +    def check_out(name, fname, expect_arr) +	idx = -1 +	all_matched = true +	extra_lines = 0 +	rdata = File.open(fname) +	rdata.each_line { |rline| +	    rline.chomp! +	    idx += 1 +	    if idx > expect_arr.length - 1 +		if extra_lines == 0 and $verbose >= 1 +		    printf "--   Extra line(s) on %s:\n", name +		end +		printf "--    [%d] > %s\n", idx, rline if $verbose >= 1 +		extra_lines += 1 +	    elsif rline != expect_arr[idx] +		if all_matched and $verbose >= 1 +		    printf "--   Mismatched line(s) on %s:\n", name +		end +		printf "--    [%d] < %s\n", idx, expect_arr[idx] if $verbose >= 2 +		printf "--        > %s\n", rline if $verbose >= 1 +		all_matched = false +	    else +		printf "--    %s[%d] = %s\n", name, idx, rline if $verbose >= 5 +	    end +	} +	rdata.close +	if extra_lines > 0 +	    printf "--   %d extra line(s) found on %s\n", extra_lines, +	      name if $verbose == 0 +	    return false +	end +	if not all_matched +	    printf "--   Mismatched line(s) found on %s\n", +	      name if $verbose == 0 +	    return false +	end +	return true +    end + +    def create_links +	@symlinks.each { |fnames| +	    if $verbose >= 2 +		printf "--  Creating: symlink %s %s\n", fnames[0], fnames[1] +	    end +	    symres = File.symlink(fnames[0], fnames[1]) +	    return false if symres == nil +	    return false unless File.symlink?(fnames[1]) +	} +	return true +    end + +    def destroy_links +	@symlinks.each { |fnames| +	    if $verbose >= 2 +		printf "--  Removing: %s (symlink)\n", fnames[1] +	    end +	    if File.symlink?(fnames[1]) +		if File.delete(fnames[1]) != 1 +		    $stderr.printf "Warning: problem removing symlink '%s'\n", +		      fnames[1] +		end +	    else +		$stderr.printf "Warning: Symlink '%s' does not exist?!?\n", +		  fnames[1] +	    end +	} +	return true +    end + +    def init_io_files +	@stderr = $scriptfile + ".stderr" +	@stdout = $scriptfile + ".stdout" +	File.delete(@stderr)	if File.exists?(@stderr) +	File.delete(@stdout)	if File.exists?(@stdout) +	@stdin = "/dev/null" + +	@redirs = " <" + @stdin +	@redirs += " >" + @stdout +	@redirs += " 2>" + @stderr + +    end + +    def pop_envs +	@new_envs.each_key { |evar| +	    if @old_envs.has_key?(evar) +		ENV[evar] = @old_envs[evar] +	    else +		ENV.delete(evar) +	    end +	} +    end + +    def push_envs +	@@gbl_envs.each_pair { |evar, eval| +	    ENV[evar] = eval +	} +	@new_envs.each_pair { |evar, eval| +	    if ENV.has_key?(evar) +		@old_envs[evar] = ENV[evar] +	    end +	    ENV[evar] = eval +	} +    end + +    def run_test +	tscript = File.open($scriptfile, "w") +	tscript.printf "#!%s", $testpgm +	tscript.printf " %s", @shebang_args if @shebang_args != "" +	tscript.printf "\n" +	tscript.printf "%s", @script_lines if @script_lines != "" +	tscript.close +	File.chmod(0755, $scriptfile) + +	usercmd = $scriptfile +	usercmd += " " + @user_args	if @user_args != nil +	init_io_files + +	push_envs +	return 0 unless create_links +	printf "-  Executing: %s\n", usercmd if $verbose >= 1 +	printf "-----   with: %s\n", @redirs if $verbose >= 6 +	sys_ok = system(usercmd + @redirs) +	if sys_ok +	    @sav_cmdvalue = 0 +	elsif $?.exited? +	    @sav_cmdvalue = $?.exitstatus +	else +	    @sav_cmdvalue = 125 +	end +	destroy_links +	pop_envs +	sys_ok = true +	if @sav_cmdvalue != @cmdvalue +	    printf "--   Expecting cmdvalue of %d, but $? == %d\n", @cmdvalue, +	      @sav_cmdvalue +	    sys_ok = false +	end +	sys_ok = false	unless check_out("stdout", @stdout, @expect_out) +	sys_ok = false	unless check_out("stderr", @stderr, @expect_err) +	return 1	if sys_ok +	return 0 +    end +end + +# -------+---------+---------+-------- + --------+---------+---------+---------+ +#   Processing of the command-line options given to the regress-sb.rb script. +# +class CommandOptions +    def CommandOptions.parse(command_args) +	parse_ok = true +	command_args.each { |userarg| +	    case userarg +	    when /^--rgdata=(\S+)$/ +		parse_ok = false	unless set_rgdatafile($1) +	    when /^--testpgm=(\S+)$/ +		parse_ok = false	unless set_testpgm($1) +		$cmdopt_testpgm = $testpgm +	    when "--stop-on-error", "--stop_on_error" +		$stop_on_error = true +	    when /^--/ +		$stderr.printf "Error: Invalid long option: %s\n", userarg +		parse_ok = false +	    when /^-/ +		userarg = userarg[1...userarg.length] +		userarg.each_byte { |byte| +		    char = byte.chr +		    case char +		    when "v" +			$verbose += 1 +		    else +			$stderr.printf "Error: Invalid short option: -%s\n", char +			parse_ok = false +		    end +		} +	    else +		$stderr.printf "Error: Invalid request: %s\n", userarg +		parse_ok = false +	    end +	} +	if $rgdatafile == nil +	    rgmatch = Dir.glob("regress*.rgdata") +	    if rgmatch.length == 1 +		$rgdatafile = rgmatch[0] +		printf "Assuming --rgdata=%s\n", $rgdatafile +	    else +		$stderr.printf "Error: The --rgdata file was not specified\n" +		parse_ok = false +	    end +	end +	return parse_ok +    end + +    def CommandOptions.set_rgdatafile(fname) +	if not File.exists?(fname) +	    $stderr.printf "Error: Rgdata file '%s' does not exist\n", fname +	    return false +	elsif not File.readable?(fname) +	    $stderr.printf "Error: Rgdata file '%s' is not readable\n", fname +	    return false +	end +	$rgdatafile = File.expand_path(fname) +	return true +    end + +    def CommandOptions.set_testpgm(fname) +	if not File.exists?(fname) +	    $stderr.printf "Error: Testpgm file '%s' does not exist\n", fname +	    return false +	elsif not File.executable?(fname) +	    $stderr.printf "Error: Testpgm file '%s' is not executable\n", fname +	    return false +	end +	$testpgm = File.expand_path(fname) +	return true +    end +end + +# -------+---------+---------+-------- + --------+---------+---------+---------+ +#   Processing of the test-specific options specifed in each [test]/[run] +#   section of the regression-data file.  This will set values in the +#   global $testdata object. +# +class RGTestOptions +    @@rgtest_opts = nil; + +    def RGTestOptions.init_rgtopts +	@@rgtest_opts = Hash.new +	@@rgtest_opts["$?"] = true +	@@rgtest_opts["clearenv"] = true +	@@rgtest_opts["sb_args"] = true +	@@rgtest_opts["script"] = true +	@@rgtest_opts["setenv"] = true +	@@rgtest_opts["stderr"] = true +	@@rgtest_opts["stdout"] = true +	@@rgtest_opts["symlink"] = true +	@@rgtest_opts["user_args"] = true +    end + +    def RGTestOptions.parse(optname, optval) +	init_rgtopts	unless @@rgtest_opts + +	if not @@rgtest_opts.has_key?(optname) +	    $stderr.printf "Error: Invalid test-option in rgdata file: %s\n", +	      optname +	    return false +	end + +	#   Support a few very specific substitutions in values specified +	#   for test data.  Format of all recognized values should be: +	#		[%-object.value-%] +	#   which is hopefully distinctive-enough that they will never +	#   conflict with any naturally-occurring string.  Also note that +	#   we only match the specific values that we recognize, and not +	#   "just anything" that matches the general pattern.  There are +	#   no blanks in the recognized values, but I use an x-tended +	#   regexp and then add blanks to make it more readable. +	optval.gsub!(/\[%- testpgm\.pathname -%\]/x, $testpgm) +	optval.gsub!(/\[%- testpgm\.basename -%\]/x, File.basename($testpgm)) +	optval.gsub!(/\[%- script\.pathname  -%\]/x, $scriptfile) + +	invalid_value = false +	case optname +	when "$?" +	    if optval =~ /^\d+$/ +		$testdata.cmdvalue = optval.to_i +	    else +		invalid_value = true +	    end +	when "clearenv" +	    if optval =~ /^\s*([A-Za-z]\w*)\s*$/ +		$testdata.add_clearenv($1) +	    else +		invalid_value = true +	    end +	when "sb_args" +	    $testdata.shebang_args = optval +	when "script" +	    $testdata.add_script(optval) +	when "setenv" +	    if optval =~ /^\s*([A-Za-z]\w*)=(.*)$/ +		$testdata.add_setenv($1, $2) +	    else +		invalid_value = true +	    end +	when "stderr" +	    $testdata.add_expecterr(optval) +	when "stdout" +	    $testdata.add_expectout(optval) +	when "symlink" +	    if optval =~ /^\s*(\S+)\s+(\S+)\s*$/ +		srcfile = $1 +		newfile = $2 +		if not File.exists?(srcfile) +		    $stderr.printf "Error: source file '%s' does not exist.\n", +			srcfile +		    invalid_value = true +		elsif File.exists?(newfile) +		    $stderr.printf "Error: new file '%s' already exists.\n", +			newfile +		    invalid_value = true +		else +		    $testdata.add_symlink(srcfile, newfile) +		end +	    else +		invalid_value = true +	    end +	when "user_args" +	    $testdata.user_args = optval +	else +	    $stderr.printf "InternalError: Invalid test-option in rgdata file: %s\n", +		optname +	    return false +	end + +	if invalid_value +	    $stderr.printf "Error: Invalid value(s) for %s: %s\n", +	      optname, optval +	    return false +	end +	return true +    end +end + +# -------+---------+---------+-------- + --------+---------+---------+---------+ +#   Here's where the "main" routine begins... +# + +$cmdopt_testpgm = nil +$testpgm = nil +$rgdatafile = nil +$scriptfile = "/tmp/env-regress" +$stop_on_error = false +$verbose = 0 + +exit 1 unless CommandOptions.parse(ARGV) + +errline = nil +test_count = 0 +testok_count = 0 +test_lineno = -1 +max_test = -1 +regress_data = File.open($rgdatafile) +regress_data.each_line { |dline| +    case dline +    when /^\s*#/, /^\s*$/ +	#  Just a comment line, ignore it. +    when /^\s*gblenv=\s*(.+)$/ +	if test_lineno > 0 +	    $stderr.printf "Error: Cannot define a global-value in the middle of a test (#5d)\n", test_lineno +	    errline = regress_data.lineno +	    break; +	end +        tempval = $1 +	if tempval !~ /^([A-Za-z]\w*)=(.*)$/ +	    $stderr.printf "Error: Invalid value for 'gblenv=' request: %s\n", +	      tempval +	    errline = regress_data.lineno +	    break; +	end +	ExpectedResult.add_gblenv($1, $2) +    when /^testpgm=\s*(\S+)\s*/ +	#   Set the location of the program to be tested, if it wasn't set +	#   on the command-line processing. +	if $cmdopt_testpgm == nil +	    if not CommandOptions.set_testpgm($1) +		errline = regress_data.lineno +		break; +	    end +	end +    when /^\[test\]$/ +	if test_lineno > 0 +	    $stderr.printf "Error: Request to define a [test], but we are still defining\n" +	    $stderr.printf "       the [test] at line #%s\n", test_lineno +	    errline = regress_data.lineno +	    break; +	end +	test_lineno = regress_data.lineno +	max_test = test_lineno +	printf "- Defining test at line #%s\n", test_lineno if $verbose >= 6 +	$testdata = ExpectedResult.new +    when /^\[end\]$/ +	#   User wants us to ignore the remainder of the rgdata file... +	break; +    when /^\[run\]$/ +	if test_lineno < 0 +	    $stderr.printf "Error: Request to [run] a test, but no test is presently defined\n" +	    errline = regress_data.lineno +	    break; +	end +	printf "-  Running test at line #%s\n", test_lineno if $verbose >= 1 +	run_result = $testdata.run_test +	test_count += 1 +	printf "[Test #%3d: ", test_count +	case run_result +	when 0 +	    #   Test failed +	    printf "Failed!  (line %4d)]\n", test_lineno +	    break if $stop_on_error +	when 1 +	    #   Test ran as expected +	    testok_count += 1 +	    printf "OK]\n" +	else +	    #   Internal error of some sort +	    printf "InternalError!  (line %4d)]\n", test_lineno +            errline = regress_data.lineno +            break; +	end +	test_lineno = -1 + +    when /^(\s*)([^\s:]+)\s*:(.+)$/ +	blankpfx = $1 +	test_lhs = $2 +	test_rhs = $3 +	if test_lineno < 0 +	    $stderr.printf "Error: No test is presently being defined\n" +	    errline = regress_data.lineno +	    break; +	end +	#   All the real work happens in RGTestOptions.parse +	if not RGTestOptions.parse(test_lhs, test_rhs) +	    errline = regress_data.lineno +	    break; +	end +	if blankpfx.length == 0 +	    $stderr.printf "Note: You should at least one blank before:%s\n", +	      dline.chomp +	    $stderr.printf "      at line %d of rgdata file %s\n", +	      regress_data.lineno, $rgdatafile +	end + +    else +	$stderr.printf "Error: Invalid line: %s\n", dline.chomp +	errline = regress_data.lineno +	break; +    end +} +regress_data.close +if errline != nil +    $stderr.printf "       at line %d of rgdata file %s\n", errline, $rgdatafile +    exit 2 +end +if testok_count != test_count +    printf "%d of %d tests were successful.\n", testok_count, test_count +    exit 1 +end + +printf "All %d tests were successful!\n", testok_count +exit 0  | 
