Module Name:    src
Committed By:   christos
Date:           Tue Mar  8 14:26:54 UTC 2016

Modified Files:
        src/tests/bin/sh: t_expand.sh t_fsplit.sh t_redir.sh

Log Message:
Added more test cases, more exhaustive testing. (from kre)


To generate a diff of this commit:
cvs rdiff -u -r1.5 -r1.6 src/tests/bin/sh/t_expand.sh
cvs rdiff -u -r1.1 -r1.2 src/tests/bin/sh/t_fsplit.sh
cvs rdiff -u -r1.3 -r1.4 src/tests/bin/sh/t_redir.sh

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/tests/bin/sh/t_expand.sh
diff -u src/tests/bin/sh/t_expand.sh:1.5 src/tests/bin/sh/t_expand.sh:1.6
--- src/tests/bin/sh/t_expand.sh:1.5	Mon Feb 22 15:02:29 2016
+++ src/tests/bin/sh/t_expand.sh	Tue Mar  8 09:26:54 2016
@@ -1,4 +1,4 @@
-# $NetBSD: t_expand.sh,v 1.5 2016/02/22 20:02:29 christos Exp $
+# $NetBSD: t_expand.sh,v 1.6 2016/03/08 14:26:54 christos Exp $
 #
 # Copyright (c) 2007, 2009 The NetBSD Foundation, Inc.
 # All rights reserved.
@@ -24,6 +24,8 @@
 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 # POSSIBILITY OF SUCH DAMAGE.
 #
+# the implementation of "sh" to test
+: ${TEST_SH:="/bin/sh"}
 
 #
 # This file tests the functions in expand.c.
@@ -50,19 +52,15 @@ dollar_at_head() {
 }
 dollar_at_body() {
 	# This one should work everywhere.
-	got=`echo "" "" | sed 's,$,EOL,'`
-	atf_check_equal ' EOL' '$got'
+	atf_check -s exit:0 -o inline:' EOL\n' -e empty \
+		${TEST_SH} -c 'echo "" "" | '" sed 's,\$,EOL,'"
 
 	# This code triggered the bug.
-	set -- "" ""
-	got=`echo "$@" | sed 's,$,EOL,'`
-	atf_check_equal ' EOL' '$got'
-
-	set -- -
-	shift
-	n_arg() { echo $#; }
-	n_args=`n_arg "$@"`
-	atf_check_equal '0' '$n_args'
+	atf_check -s exit:0 -o inline:' EOL\n' -e empty \
+		${TEST_SH} -c 'set -- "" ""; echo "$@" | '" sed 's,\$,EOL,'"
+
+	atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+		'set -- -; shift; n_arg() { echo $#; }; n_arg "$@"'
 }
 
 atf_test_case dollar_at_with_text
@@ -71,27 +69,91 @@ dollar_at_with_text_head() {
 	                "within the quotes.  PR bin/33956."
 }
 dollar_at_with_text_body() {
-	set --
-	atf_check_equal '' "$(delim_argv "$@")"
-	atf_check_equal '>foobar<' "$(delim_argv "foo$@bar")"
-	atf_check_equal '>foo  bar<' "$(delim_argv "foo $@ bar")"
-
-	set -- a b c
-	atf_check_equal '>a< >b< >c<' "$(delim_argv "$@")"
-	atf_check_equal '>fooa< >b< >cbar<' "$(delim_argv "foo$@bar")"
-	atf_check_equal '>foo a< >b< >c bar<' "$(delim_argv "foo $@ bar")"
+
+	cat <<'EOF' > h-f1
+
+delim_argv() {
+	str=
+	while [ $# -gt 0 ]; do
+		if [ -z "${str}" ]; then
+			str=">$1<"
+		else
+			str="${str} >$1<"
+		fi
+		shift
+	done
+	echo "${str}"
+}
+
+EOF
+	cat <<'EOF' > h-f2
+
+delim_argv() {
+	str=
+	while [ $# -gt 0 ]; do
+
+		str="${str}${str:+ }>$1<"
+		shift
+
+	done
+	echo "${str}"
+}
+
+EOF
+
+	chmod +x h-f1 h-f2
+
+	for f in 1 2
+	do
+		atf_check -s exit:0 -o inline:'\n' -e empty ${TEST_SH} -c \
+			". ./h-f${f}; "'set -- ; delim_argv "$@"'
+		atf_check -s exit:0 -o inline:'>foobar<\n' -e empty \
+			${TEST_SH} -c \
+			". ./h-f${f}; "'set -- ; delim_argv "foo$@bar"'
+		atf_check -s exit:0 -o inline:'>foo  bar<\n' -e empty \
+			${TEST_SH} -c \
+			". ./h-f${f}; "'set -- ; delim_argv "foo $@ bar"'
+
+		atf_check -s exit:0 -o inline:'>a< >b< >c<\n' -e empty \
+			${TEST_SH} -c \
+			". ./h-f${f}; "'set -- a b c; delim_argv "$@"'
+		atf_check -s exit:0 -o inline:'>fooa< >b< >cbar<\n' -e empty \
+			${TEST_SH} -c \
+			". ./h-f${f}; "'set -- a b c; delim_argv "foo$@bar"'
+		atf_check -s exit:0 -o inline:'>foo a< >b< >c bar<\n' -e empty \
+			${TEST_SH} -c \
+			". ./h-f${f}; "'set -- a b c; delim_argv "foo $@ bar"'
+	done
 }
 
 atf_test_case strip
 strip_head() {
 	atf_set "descr" "Checks that the %% operator works and strips" \
 	                "the contents of a variable from the given point" \
-			"to the end (PR bin/43469)"
+			"to the end"
 }
 strip_body() {
 	line='#define bindir "/usr/bin" /* comment */'
 	stripped='#define bindir "/usr/bin" '
-	atf_check_equal '$stripped' '${line%%/\**}'
+
+	# atf_expect_fail "PR bin/43469" -- now fixed
+	for exp in 				\
+		'${line%%/\**}'			\
+		'${line%%"/*"*}'		\
+		'${line%%'"'"'/*'"'"'*}'	\
+		'"${line%%/\**}"'		\
+		'"${line%%"/*"*}"'		\
+		'"${line%%'"'"'/*'"'"'*}"'	\
+		'${line%/\**}'			\
+		'${line%"/*"*}'			\
+		'${line%'"'"'/*'"'"'*}'		\
+		'"${line%/\**}"'		\
+		'"${line%"/*"*}"'		\
+		'"${line%'"'"'/*'"'"'*}"'
+	do
+		atf_check -o inline:":$stripped:\n" -e empty ${TEST_SH} -c \
+			"line='${line}'; echo :${exp}:"
+	done
 }
 
 atf_test_case varpattern_backslashes
@@ -102,7 +164,8 @@ varpattern_backslashes_head() {
 varpattern_backslashes_body() {
 	line='/foo/bar/*/baz'
 	stripped='/foo/bar/'
-	atf_check_equal $stripped ${line%%\**}
+	atf_check -o inline:'/foo/bar/\n' -e empty ${TEST_SH} -c \
+		'line="/foo/bar/*/baz"; echo ${line%%\**}'
 }
 
 atf_test_case arithmetic
@@ -113,9 +176,13 @@ arithmetic_head() {
 			"this is true."
 }
 arithmetic_body() {
-	atf_check_equal '3' '$((1 + 2))'
-	atf_check_equal '2147483647' '$((0x7fffffff))'
-	atf_check_equal '9223372036854775807' '$(((1 << 63) - 1))'
+
+	atf_check -o inline:'3' -e empty ${TEST_SH} -c \
+		'printf %s $((1 + 2))'
+	atf_check -o inline:'2147483647' -e empty ${TEST_SH} -c \
+		'printf %s $((0x7fffffff))'
+	atf_check -o inline:'9223372036854775807' -e empty ${TEST_SH} -c \
+		'printf %s $(((1 << 63) - 1))'
 }
 
 atf_test_case iteration_on_null_parameter
@@ -125,10 +192,39 @@ iteration_on_null_parameter_head() {
 	                "PR bin/48202."
 }
 iteration_on_null_parameter_body() {
-	s1=`/bin/sh -uc 'N=; set -- ${N};   for X; do echo "[$X]"; done' 2>&1`
-	s2=`/bin/sh -uc 'N=; set -- ${N:-}; for X; do echo "[$X]"; done' 2>&1`
-	atf_check_equal ''   '$s1'
-	atf_check_equal '[]' '$s2'
+	atf_check -o empty -e empty ${TEST_SH} -c \
+		'N=; set -- ${N};   for X; do echo "[$X]"; done'
+}
+
+atf_test_case iteration_on_quoted_null_parameter
+iteration_on_quoted_null_parameter_head() {
+	atf_set "descr" \
+		'Check iteration of "$@" in for loop when set to null;'
+}
+iteration_on_quoted_null_parameter_body() {
+	atf_check -o inline:'[]\n' -e empty ${TEST_SH} -c \
+		'N=; set -- "${N}"; for X; do echo "[$X]"; done'
+}
+
+atf_test_case iteration_on_null_or_null_parameter
+iteration_on_null_or_null_parameter_head() {
+	atf_set "descr" \
+		'Check expansion of null parameter as default for another null'
+}
+iteration_on_null_or_null_parameter_body() {
+	atf_check -o empty -e empty ${TEST_SH} -c \
+		'N=; E=; set -- ${N:-${E}}; for X; do echo "[$X]"; done'
+}
+
+atf_test_case iteration_on_null_or_missing_parameter
+iteration_on_null_or_missing_parameter_head() {
+	atf_set "descr" \
+	    'Check expansion of missing parameter as default for another null'
+}
+iteration_on_null_or_missing_parameter_body() {
+	# atf_expect_fail 'PR bin/50834'
+	atf_check -o empty -e empty ${TEST_SH} -c \
+		'N=; set -- ${N:-}; for X; do echo "[$X]"; done'
 }
 
 atf_init_test_cases() {
@@ -138,4 +234,7 @@ atf_init_test_cases() {
 	atf_add_test_case varpattern_backslashes
 	atf_add_test_case arithmetic
 	atf_add_test_case iteration_on_null_parameter
+	atf_add_test_case iteration_on_quoted_null_parameter
+	atf_add_test_case iteration_on_null_or_null_parameter
+	atf_add_test_case iteration_on_null_or_missing_parameter
 }

Index: src/tests/bin/sh/t_fsplit.sh
diff -u src/tests/bin/sh/t_fsplit.sh:1.1 src/tests/bin/sh/t_fsplit.sh:1.2
--- src/tests/bin/sh/t_fsplit.sh:1.1	Sat Mar 17 12:33:11 2012
+++ src/tests/bin/sh/t_fsplit.sh	Tue Mar  8 09:26:54 2016
@@ -1,6 +1,6 @@
-# $NetBSD: t_fsplit.sh,v 1.1 2012/03/17 16:33:11 jruoho Exp $
+# $NetBSD: t_fsplit.sh,v 1.2 2016/03/08 14:26:54 christos Exp $
 #
-# Copyright (c) 2007 The NetBSD Foundation, Inc.
+# Copyright (c) 2007-2016 The NetBSD Foundation, Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -33,6 +33,7 @@
 # the "${x-" and "}" were absent from the input line.
 #
 # So: sh -c 'set ${x-a b c}; echo $#' should give 3.
+# and: sh -c 'set -- ${x-}' echo $#' shold give 0
 #
 
 nl='
@@ -40,15 +41,40 @@ nl='
 
 check()
 {
-	result="$(eval $1)"
+	TEST=$((${TEST} + 1))
+
+	case "$#" in
+	(2)	;;
+	(*)	atf_fail "Internal test error, $# args to check test ${TEST}";;
+	esac
+
+	result=$( ${TEST_SH} -c "unset x; $1" )
+	STATUS="$?"
+
 	# Remove newlines
 	oifs="$IFS"
 	IFS="$nl"
 	result="$(echo $result)"
 	IFS="$oifs"
+
+	# trim the test text in case we use it in a message below
+	case "$1" in
+	????????????????*)
+		set -- "$(expr "$1" : '\(............\).*')..." "$2" ;;
+	esac
+
 	if [ "$2" != "$result" ]
 	then
-		atf_fail "expected [$2], found [$result]"
+		if [ "${STATUS}" = "0" ]
+		then
+		  atf_fail "Test ${TEST} '$1': expected [$2], found [$result]"
+		else
+		  atf_fail \
+	  "TEST ${TEST} '$1' failed ($STATUS): expected [$2], found [$result]"
+		fi
+	elif [ "${STATUS}" != 0 ]
+	then
+		  atf_fail "TEST ${TEST} '$1' failed ($STATUS)"
 	fi
 }
 
@@ -59,6 +85,7 @@ for_head() {
 for_body() {
 	unset x
 
+	TEST=0
 	# Since I managed to break this, leave the test in
 	check 'for f in $x; do echo x${f}y; done' ''
 }
@@ -68,17 +95,121 @@ default_val_head() {
 	atf_set "descr" "Checks field splitting in variable default values"
 }
 default_val_body() {
-	unset x
-
+	TEST=0
 	# Check that IFS is applied to text from ${x-...} unless it is inside
 	# any set of "..."
-	check 'set ${x-a b c}; echo $#' 3
-	check 'for i in ${x-a b c};            do echo "z${i}z"; done' 'zaz zbz zcz'
-	check 'for i in ${x-"a b" c};          do echo "z${i}z"; done' 'za bz zcz'
-	check 'for i in ${x-"a ${x-b c}" d};   do echo "z${i}z"; done' 'za b cz zdz'
-	check 'for i in ${x-"a ${x-"b c"}" d}; do echo "z${i}z"; done' 'za b cz zdz'
-	check 'for i in ${x-a ${x-"b c"} d};   do echo "z${i}z"; done' 'zaz zb cz zdz'
-	check 'for i in ${x-a ${x-b c} d};     do echo "z${i}z"; done' 'zaz zbz zcz zdz'
+	check 'set -- ${x-a b c};   echo $#'   3
+
+	check 'set -- ${x-"a b" c}; echo $#'   2
+	check 'set -- ${x-a "b c"}; echo $#'   2
+	check 'set -- ${x-"a b c"}; echo $#'   1
+
+	check "set -- \${x-'a b' c}; echo \$#" 2
+	check "set -- \${x-a 'b c'}; echo \$#" 2
+	check "set -- \${x-'a b c'}; echo \$#" 1
+
+	check 'set -- ${x-a\ b c};  echo $#'   2
+	check 'set -- ${x-a b\ c};  echo $#'   2
+	check 'set -- ${x-a\ b\ c}; echo $#'   1
+
+	check 'set -- ${x};        echo $#' 0
+	check 'set -- ${x-};       echo $#' 0
+	check 'set -- ${x-""};     echo $#' 1
+	check 'set -- ""${x};      echo $#' 1
+	check 'set -- ""${x-};     echo $#' 1
+	check 'set -- ""${x-""};   echo $#' 1
+	check 'set -- ${x}"";      echo $#' 1
+	check 'set -- ${x-}"";     echo $#' 1
+	check 'set -- ${x-""}"";   echo $#' 1
+	check 'set -- ""${x}"";    echo $#' 1
+	check 'set -- ""${x-}"";   echo $#' 1
+	check 'set -- ""${x-""}""; echo $#' 1
+
+	check 'for i in ${x-a b c};            do echo "z${i}z"; done' \
+		'zaz zbz zcz'
+	check 'for i in ${x-"a b" c};          do echo "z${i}z"; done' \
+		'za bz zcz'
+	check 'for i in ${x-"a ${x-b c}" d};   do echo "z${i}z"; done' \
+		'za b cz zdz'
+	check 'for i in ${x-a ${x-b c} d};     do echo "z${i}z"; done' \
+		'zaz zbz zcz zdz'
+
+	# I am not sure these two are correct, the rules on quoting word
+	# in ${var-word} are peculiar, and hard to fathom...
+	# They are what the NetBSD shell does, and bash, not the freebsd shell
+	# (as of Mar 1, 2016)
+
+	check 'for i in ${x-"a ${x-"b c"}" d}; do echo "z${i}z"; done' \
+		'za b cz zdz'
+	check 'for i in ${x-a ${x-"b c"} d};   do echo "z${i}z"; done' \
+		'zaz zb cz zdz'
+}
+
+atf_test_case replacement_val
+replacement_val_head() {
+	atf_set "descr" "Checks field splitting in variable replacement values"
+}
+replacement_val_body() {
+	TEST=0
+
+	# Check that IFS is applied to text from ${x+...} unless it is inside
+	# any set of "...", or whole expansion is quoted, or both...
+
+	check 'x=BOGUS; set -- ${x+a b c};   echo $#'   3
+
+	check 'x=BOGUS; set -- ${x+"a b" c}; echo $#'   2
+	check 'x=BOGUS; set -- ${x+a "b c"}; echo $#'   2
+	check 'x=BOGUS; set -- ${x+"a b c"}; echo $#'   1
+
+	check "x=BOGUS; set -- \${x+'a b' c}; echo \$#" 2
+	check "x=BOGUS; set -- \${x+a 'b c'}; echo \$#" 2
+	check "x=BOGUS; set -- \${x+'a b c'}; echo \$#" 1
+
+	check 'x=BOGUS; set -- ${x+a\ b c};  echo $#'   2
+	check 'x=BOGUS; set -- ${x+a b\ c};  echo $#'   2
+	check 'x=BOGUS; set -- ${x+a\ b\ c}; echo $#'   1
+
+	check 'x=BOGUS; set -- ${x+};       echo $#' 0
+	check 'x=BOGUS; set -- ${x+""};     echo $#' 1
+	check 'x=BOGUS; set -- ""${x+};     echo $#' 1
+	check 'x=BOGUS; set -- ""${x+""};   echo $#' 1
+	check 'x=BOGUS; set -- ${x+}"";     echo $#' 1
+	check 'x=BOGUS; set -- ${x+""}"";   echo $#' 1
+	check 'x=BOGUS; set -- ""${x+}"";   echo $#' 1
+	check 'x=BOGUS; set -- ""${x+""}""; echo $#' 1
+
+	# verify that the value of $x does not affecty the value of ${x+...}
+	check 'x=BOGUS; set -- ${x+};       echo X$1' X
+	check 'x=BOGUS; set -- ${x+""};     echo X$1' X
+	check 'x=BOGUS; set -- ""${x+};     echo X$1' X
+	check 'x=BOGUS; set -- ""${x+""};   echo X$1' X
+	check 'x=BOGUS; set -- ${x+}"";     echo X$1' X
+	check 'x=BOGUS; set -- ${x+""}"";   echo X$1' X
+	check 'x=BOGUS; set -- ""${x+}"";   echo X$1' X
+	check 'x=BOGUS; set -- ""${x+""}""; echo X$1' X
+
+	check 'x=BOGUS; set -- ${x+};       echo X${1-:}X' X:X
+	check 'x=BOGUS; set -- ${x+""};     echo X${1-:}X' XX
+	check 'x=BOGUS; set -- ""${x+};     echo X${1-:}X' XX
+	check 'x=BOGUS; set -- ""${x+""};   echo X${1-:}X' XX
+	check 'x=BOGUS; set -- ${x+}"";     echo X${1-:}X' XX
+	check 'x=BOGUS; set -- ${x+""}"";   echo X${1-:}X' XX
+	check 'x=BOGUS; set -- ""${x+}"";   echo X${1-:}X' XX
+	check 'x=BOGUS; set -- ""${x+""}""; echo X${1-:}X' XX
+
+	# and validate that the replacement can be used as expected
+	check 'x=BOGUS; for i in ${x+a b c};            do echo "z${i}z"; done'\
+		'zaz zbz zcz'
+	check 'x=BOGUS; for i in ${x+"a b" c};          do echo "z${i}z"; done'\
+		'za bz zcz'
+	check 'x=BOGUS; for i in ${x+"a ${x+b c}" d};   do echo "z${i}z"; done'\
+		'za b cz zdz'
+	check 'x=BOGUS; for i in ${x+"a ${x+"b c"}" d}; do echo "z${i}z"; done'\
+		'za b cz zdz'
+	check 'x=BOGUS; for i in ${x+a ${x+"b c"} d};   do echo "z${i}z"; done'\
+		'zaz zb cz zdz'
+	check 'x=BOGUS; for i in ${x+a ${x+b c} d};     do echo "z${i}z"; done'\
+		'zaz zbz zcz zdz'
 }
 
 atf_test_case ifs_alpha
@@ -89,13 +220,19 @@ ifs_alpha_head() {
 ifs_alpha_body() {
 	unset x
 
+	TEST=0
 	# repeat with an alphabetic in IFS
 	check 'IFS=q; set ${x-aqbqc}; echo $#' 3
-	check 'IFS=q; for i in ${x-aqbqc};            do echo "z${i}z"; done' 'zaz zbz zcz'
-	check 'IFS=q; for i in ${x-"aqb"qc};          do echo "z${i}z"; done' 'zaqbz zcz'
-	check 'IFS=q; for i in ${x-"aq${x-bqc}"qd};   do echo "z${i}z"; done' 'zaqbqcz zdz'
-	check 'IFS=q; for i in ${x-"aq${x-"bqc"}"qd}; do echo "z${i}z"; done' 'zaqbqcz zdz'
-	check 'IFS=q; for i in ${x-aq${x-"bqc"}qd};  do echo "z${i}z"; done' 'zaz zbqcz zdz'
+	check 'IFS=q; for i in ${x-aqbqc};            do echo "z${i}z"; done' \
+		'zaz zbz zcz'
+	check 'IFS=q; for i in ${x-"aqb"qc};          do echo "z${i}z"; done' \
+		'zaqbz zcz'
+	check 'IFS=q; for i in ${x-"aq${x-bqc}"qd};   do echo "z${i}z"; done' \
+		'zaqbqcz zdz'
+	check 'IFS=q; for i in ${x-"aq${x-"bqc"}"qd}; do echo "z${i}z"; done' \
+		'zaqbqcz zdz'
+	check 'IFS=q; for i in ${x-aq${x-"bqc"}qd};  do echo "z${i}z"; done' \
+		'zaz zbqcz zdz'
 }
 
 atf_test_case quote
@@ -106,6 +243,7 @@ quote_head() {
 quote_body() {
 	unset x
 
+	TEST=0
 	# Some quote propagation checks
 	check 'set "${x-a b c}";   echo $#' 1
 	check 'set "${x-"a b" c}"; echo $1' 'a b c'
@@ -120,19 +258,39 @@ dollar_at_head() {
 dollar_at_body() {
 	unset x
 
+	TEST=0
 	# Check we get "$@" right
-	check 'set "";        for i;           do echo "z${i}z"; done' 'zz'
-	check 'set "";        for i in "$@";   do echo "z${i}z"; done' 'zz'
-	check 'set "" "";     for i;           do echo "z${i}z"; done' 'zz zz'
-	check 'set "" "";     for i in "$@";   do echo "z${i}z"; done' 'zz zz'
-	check 'set "" "";     for i in $@;     do echo "z${i}z"; done' ''
-	check 'set "a b" c;   for i;           do echo "z${i}z"; done' 'za bz zcz'
-	check 'set "a b" c;   for i in "$@";   do echo "z${i}z"; done' 'za bz zcz'
-	check 'set "a b" c;   for i in $@;     do echo "z${i}z"; done' 'zaz zbz zcz'
-	check 'set " a b " c; for i in "$@";   do echo "z${i}z"; done' 'z a b z zcz'
-	check 'set --;        for i in x"$@"x; do echo "z${i}z"; done' 'zxxz'
-	check 'set a;         for i in x"$@"x; do echo "z${i}z"; done' 'zxaxz'
-	check 'set a b;       for i in x"$@"x; do echo "z${i}z"; done' 'zxaz zbxz'
+
+	check 'set --;        for i in x"$@"x;  do echo "z${i}z"; done' 'zxxz'
+	check 'set a;         for i in x"$@"x;  do echo "z${i}z"; done' 'zxaxz'
+	check 'set a b;       for i in x"$@"x;  do echo "z${i}z"; done' 'zxaz zbxz'
+
+	check 'set --;        for i;            do echo "z${i}z"; done' ''
+	check 'set --;        for i in $@;      do echo "z${i}z"; done' ''
+	check 'set --;        for i in "$@";    do echo "z${i}z"; done' ''
+	# atf_expect_fail "PR bin/50834"
+	check 'set --;        for i in ""$@;    do echo "z${i}z"; done' 'zz'
+	# atf_expect_pass
+	check 'set --;        for i in $@"";    do echo "z${i}z"; done' 'zz'
+	check 'set --;        for i in ""$@"";  do echo "z${i}z"; done' 'zz'
+	check 'set --;        for i in """$@";  do echo "z${i}z"; done' 'zz'
+	check 'set --;        for i in "$@""";  do echo "z${i}z"; done' 'zz'
+	check 'set --;        for i in """$@""";do echo "z${i}z"; done' 'zz'
+
+	check 'set "";        for i;            do echo "z${i}z"; done' 'zz'
+	check 'set "";        for i in "$@";    do echo "z${i}z"; done' 'zz'
+	check 'set "" "";     for i;            do echo "z${i}z"; done' 'zz zz'
+	check 'set "" "";     for i in "$@";    do echo "z${i}z"; done' 'zz zz'
+	check 'set "" "";     for i in $@;      do echo "z${i}z"; done' ''
+
+	check 'set "a b" c;   for i;            do echo "z${i}z"; done' \
+		'za bz zcz'
+	check 'set "a b" c;   for i in "$@";    do echo "z${i}z"; done' \
+		'za bz zcz'
+	check 'set "a b" c;   for i in $@;      do echo "z${i}z"; done' \
+		'zaz zbz zcz'
+	check 'set " a b " c; for i in "$@";    do echo "z${i}z"; done' \
+		'z a b z zcz'
 }
 
 atf_test_case ifs
@@ -143,6 +301,7 @@ ifs_head() {
 ifs_body() {
 	unset x
 
+	TEST=0
 	# Some IFS tests
 	check 't="-- ";    IFS=" ";  set $t; IFS=":"; r="$*"; IFS=; echo $# $r' '0'
 	check 't=" x";     IFS=" x"; set $t; IFS=":"; r="$*"; IFS=; echo $# $r' '1'
@@ -165,19 +324,26 @@ var_length_head() {
 	                "a variable's length"
 }
 var_length_body() {
-	unset x
+	TEST=0
 
-	# Check that we apply IFS to ${#var}
 	long=12345678123456781234567812345678
 	long=$long$long$long$long
-	check 'echo ${#long}; IFS=2; echo ${#long}; set 1 ${#long};echo $#' '128 1 8 3'
-	check 'IFS=2; set ${x-${#long}};   IFS=" "; echo $* $#' '1 8 2'
-	check 'IFS=2; set ${x-"${#long}"}; IFS=" "; echo $* $#' '128 1'
+	export long
+
+	# first test that the test method works...
+	check 'set -u; : ${long}; echo ${#long}' '128'
+
+	# Check that we apply IFS to ${#var}
+	check 'echo ${#long}; IFS=2; echo ${#long}; set 1 ${#long};echo $#' \
+		'128 1 8 3'
+	check 'IFS=2; set ${x-${#long}};   IFS=" "; echo $* $#'   '1 8 2'
+	check 'IFS=2; set ${x-"${#long}"}; IFS=" "; echo $* $#'   '128 1'
 }
 
 atf_init_test_cases() {
 	atf_add_test_case for
 	atf_add_test_case default_val
+	atf_add_test_case replacement_val
 	atf_add_test_case ifs_alpha
 	atf_add_test_case quote
 	atf_add_test_case dollar_at

Index: src/tests/bin/sh/t_redir.sh
diff -u src/tests/bin/sh/t_redir.sh:1.3 src/tests/bin/sh/t_redir.sh:1.4
--- src/tests/bin/sh/t_redir.sh:1.3	Tue Mar  1 07:39:35 2016
+++ src/tests/bin/sh/t_redir.sh	Tue Mar  8 09:26:54 2016
@@ -1,4 +1,4 @@
-# $NetBSD: t_redir.sh,v 1.3 2016/03/01 12:39:35 christos Exp $
+# $NetBSD: t_redir.sh,v 1.4 2016/03/08 14:26:54 christos Exp $
 #
 # Copyright (c) 2016 The NetBSD Foundation, Inc.
 # All rights reserved.
@@ -27,32 +27,440 @@
 # the implementation of "sh" to test
 : ${TEST_SH:="/bin/sh"}
 
+# Any failures in this first test means it is not worth bothering looking
+# for causes of failures in any other tests, make this one work first.
+
+# Problems with this test usually mean inadequate ATF_SHELL used for testing.
+# (though if all pass but the last, it might be a TEST_SH problem.)
+
+atf_test_case basic_test_method_test
+basic_test_method_test_head()
+{
+	atf_set "descr" "Tests that test method works as expected"
+}
+basic_test_method_test_body()
+{
+	cat <<- 'DONE' |
+	DONE
+	atf_check -s exit:0 -o empty -e empty ${TEST_SH}
+	cat <<- 'DONE' |
+	DONE
+	atf_check -s exit:0 -o match:0 -e empty ${TEST_SH} -c 'wc -l'
+
+	cat <<- 'DONE' |
+		echo hello
+	DONE
+	atf_check -s exit:0 -o match:hello -e empty ${TEST_SH} 
+	cat <<- 'DONE' |
+		echo hello
+	DONE
+	atf_check -s exit:0 -o match:1 -e empty ${TEST_SH} -c 'wc -l'
+
+	cat <<- 'DONE' |
+		echo hello\
+					world
+	DONE
+	atf_check -s exit:0 -o match:helloworld -e empty ${TEST_SH} 
+	cat <<- 'DONE' |
+		echo hello\
+					world
+	DONE
+	atf_check -s exit:0 -o match:2 -e empty ${TEST_SH} -c 'wc -l'
+
+	printf '%s\n%s\n%s\n' Line1 Line2 Line3 > File
+	atf_check -s exit:0 -o inline:'Line1\nLine2\nLine3\n' -e empty \
+		${TEST_SH} -c 'cat File'
+
+	cat <<- 'DONE' |
+		set -- X "" '' Y
+		echo ARGS="${#}"
+		echo '' -$1- -$2- -$3- -$4-
+		cat <<EOF
+			X=$1
+		EOF
+		cat <<\EOF
+			Y=$4
+		EOF
+	DONE
+	atf_check -s exit:0 -o match:ARGS=4 -o match:'-X- -- -- -Y-' \
+		-o match:X=X -o match:'Y=\$4' -e empty ${TEST_SH} 
+}
+
+atf_test_case do_input_redirections
+do_input_redirections_head()
+{
+	atf_set "descr" "Tests that simple input redirection works"
+}
+do_input_redirections_body()
+{
+	printf '%s\n%s\n%s\nEND\n' 'First Line' 'Second Line' 'Line 3' >File
+
+	atf_check -s exit:0 -e empty \
+		-o inline:'First Line\nSecond Line\nLine 3\nEND\n' \
+		${TEST_SH} -c 'cat < File'
+	atf_check -s exit:0 -e empty \
+		-o inline:'First Line\nSecond Line\nLine 3\nEND\n' \
+		${TEST_SH} -c 'cat <File'
+	atf_check -s exit:0 -e empty \
+		-o inline:'First Line\nSecond Line\nLine 3\nEND\n' \
+		${TEST_SH} -c 'cat< File'
+	atf_check -s exit:0 -e empty \
+		-o inline:'First Line\nSecond Line\nLine 3\nEND\n' \
+		${TEST_SH} -c 'cat < "File"'
+	atf_check -s exit:0 -e empty \
+		-o inline:'First Line\nSecond Line\nLine 3\nEND\n' \
+		${TEST_SH} -c '< File cat'
+
+	ln File wc
+	atf_check -s exit:0 -e empty \
+		-o inline:'First Line\nSecond Line\nLine 3\nEND\n' \
+		${TEST_SH} -c '< wc cat'
+
+	mv wc cat
+	atf_check -s exit:0 -e empty -o match:4 \
+		${TEST_SH} -c '< cat wc'
+
+
+	cat <<- 'EOF' |
+		i=0
+		while [ "$i" -lt 3 ]; do
+			i=$((i + 1))
+			read line < File
+			echo "$line"
+		done
+	EOF
+	atf_check -s exit:0 -e empty \
+		-o inline:'First Line\nFirst Line\nFirst Line\n' \
+		${TEST_SH}
+
+	cat <<- 'EOF' |
+		i=0
+		while [ "$i" -lt 3 ]; do
+			i=$((i + 1))
+			read line
+			echo "$line"
+		done <File
+	EOF
+	atf_check -s exit:0 -e empty \
+		-o inline:'First Line\nSecond Line\nLine 3\n' \
+		${TEST_SH}
+
+	cat <<- 'EOF' |
+		i=0
+		while [ "$i" -lt 3 ]; do
+			i=$((i + 1))
+			read line < File
+			echo "$line"
+		done <File
+	EOF
+	atf_check -s exit:0 -e empty \
+		-o inline:'First Line\nFirst Line\nFirst Line\n' \
+		${TEST_SH}
+
+	cat <<- 'EOF' |
+		line=
+		while [ "$line" != END ]; do
+			read line || exit 1
+			echo "$line"
+		done <File
+	EOF
+	atf_check -s exit:0 -e empty \
+		-o inline:'First Line\nSecond Line\nLine 3\nEND\n' \
+		${TEST_SH}
+
+	cat <<- 'EOF' |
+		while :; do
+			read line || exit 0
+			echo "$line"
+		done <File
+	EOF
+	atf_check -s exit:0 -e empty \
+		-o inline:'First Line\nSecond Line\nLine 3\nEND\n' \
+		${TEST_SH}
+
+	cat <<- 'EOF' |
+		i=0
+		while read line < File
+		do
+			echo "$line"
+			i=$((i + 1))
+			[ ${i} -ge 3 ] && break
+		done
+		echo DONE
+	EOF
+	atf_check -s exit:0 -e empty \
+		-o inline:'First Line\nFirst Line\nFirst Line\nDONE\n' \
+		${TEST_SH}
+
+	cat <<- 'EOF' |
+		i=0
+		while read line
+		do
+			echo "$line"
+		done <File
+		echo DONE
+	EOF
+	atf_check -s exit:0 -e empty \
+		-o inline:'First Line\nSecond Line\nLine 3\nEND\nDONE\n' \
+		${TEST_SH}
+
+	cat <<- 'EOF' |
+		i=0
+		while read line
+		do
+			echo "$line"
+			i=$((i + 1))
+			[ ${i} -ge 3 ] && break
+		done <File
+		echo DONE
+	EOF
+	atf_check -s exit:0 -e empty \
+		-o inline:'First Line\nSecond Line\nLine 3\nDONE\n' ${TEST_SH}
+
+	cat <<- 'EOF' |
+		i=0
+		while read line1 <File
+		do
+			read line2
+			echo "$line1":"$line2"
+			i=$((i + 1))
+			[ ${i} -ge 2 ] && break
+		done <File
+		echo DONE
+	EOF
+	atf_check -s exit:0 -e empty \
+	    -o inline:'First Line:First Line\nFirst Line:Second Line\nDONE\n' \
+		${TEST_SH}
+}
+
+atf_test_case do_output_redirections
+do_output_redirections_head()
+{
+	atf_set "descr" "Test Output redirections"
+}
+do_output_redirections_body()
+{
+nl='
+'
+	T=0
+	i() { T=$(($T + 1)); }
+
+	rm -f Output 2>/dev/null || :
+	test -f Output && atf_fail "Unable to remove Output file"
+#1
+	i; atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c '> Output'
+	test -f Output || atf_fail "#$T: Did not make Output file"
+#2
+	rm -f Output 2>/dev/null || :
+	i; atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c '>> Output'
+	test -f Output || atf_fail "#$T: Did not make Output file"
+#3
+	rm -f Output 2>/dev/null || :
+	i; atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c '>| Output'
+	test -f Output || atf_fail "#$T: Did not make Output file"
+
+#4
+	rm -f Output 2>/dev/null || :
+	i
+	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c 'echo Hello >Output'
+	test -s Output || atf_fail "#$T: Did not make non-empty Output file"
+	test "$(cat Output)" = "Hello" ||
+	  atf_fail "#$T: Incorrect Output: Should be 'Hello' is '$(cat Output)'"
+#5
+	i
+	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c 'echo Hello>!Output'
+	test -s Output || atf_fail "#$T: Did not make non-empty Output file"
+	test "$(cat Output)" = "Hello" ||
+	  atf_fail "#$T: Incorrect Output: Should be 'Hello' is '$(cat Output)'"
+#6
+	i
+	atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c 'echo Bye >>Output'
+	test -s Output || atf_fail "#$T: Removed Output file"
+	test "$(cat Output)" = "Hello${nl}Bye" || atf_fail \
+	  "#$T: Incorrect Output: Should be 'Hello\\nBye' is '$(cat Output)'"
+#7
+	i; atf_check -s exit:0 -o inline:'line 1\nline 2\n' -e empty \
+		${TEST_SH} -c \
+		'echo line 1 > Output; echo line 2 >> Output; cat Output'
+	test "$(cat Output)" = "line 1${nl}line 2" || atf_fail \
+	 "#$T: Incorrect Output: Should be 'line 1\\nline 2' is '$(cat Output)'"
+#8
+	i; atf_check -s exit:0 -o inline:'line 2\n' -e empty \
+		${TEST_SH} -c 'echo line 1 > Output; echo line 2'
+	test "$(cat Output)" = "line 1" || atf_fail \
+	    "#$T: Incorrect Output: Should be 'line 1' is '$(cat Output)'"
+#9
+	i; atf_check -s exit:0 -o empty -e empty \
+		${TEST_SH} -c '(echo line 1; echo line 2 > Out2) > Out1'
+	test "$(cat Out1)" = "line 1" || atf_fail \
+	    "#$T: Incorrect Out1: Should be 'line 1' is '$(cat Out1)'"
+	test "$(cat Out2)" = "line 2" || atf_fail \
+	    "#$T: Incorrect Out2: Should be 'line 2' is '$(cat Out2)'"
+#10
+	i; atf_check -s exit:0 -o empty -e empty \
+		${TEST_SH} -c '{ echo line 1; echo line 2 > Out2;} > Out1'
+	test "$(cat Out1)" = "line 1" || atf_fail \
+	    "#$T: Incorrect Out1: Should be 'line 1' is '$(cat Out1)'"
+	test "$(cat Out2)" = "line 2" || atf_fail \
+	    "#$T: Incorrect Out2: Should be 'line 2' is '$(cat Out2)'"
+#11
+	i; rm -f Out1 Out2 2>/dev/null || :
+	cat <<- 'EOF' |
+		for arg in 'line 1' 'line 2' 'line 3'
+		do
+			echo "$arg"
+			echo "$arg" > Out1
+		done > Out2
+	EOF
+	atf_check -s exit:0 -o empty -e empty ${TEST_SH} 
+	test "$(cat Out1)" = "line 3" || atf_fail \
+		"#$T:  Incorrect Out1: Should be 'line 3' is '$(cat Out1)'"
+	test "$(cat Out2)" = "line 1${nl}line 2${nl}line 3" || atf_fail \
+    "#$T: Incorrect Out2: Should be 'line 1\\nline 2\\nline 3' is '$(cat Out2)'"
+#12
+	i; rm -f Out1 Out2 2>/dev/null || :
+	cat <<- 'EOF' |
+		for arg in 'line 1' 'line 2' 'line 3'
+		do
+			echo "$arg"
+			echo "$arg" >> Out1
+		done > Out2
+	EOF
+	atf_check -s exit:0 -o empty -e empty ${TEST_SH} 
+	test "$(cat Out1)" = "line 1${nl}line 2${nl}line 3" || atf_fail \
+    "#$T: Incorrect Out1: Should be 'line 1\\nline 2\\nline 3' is '$(cat Out1)'"
+	test "$(cat Out2)" = "line 1${nl}line 2${nl}line 3" || atf_fail \
+    "#$T: Incorrect Out2: Should be 'line 1\\nline 2\\nline 3' is '$(cat Out2)'"
+}
+
+atf_test_case fd_redirections
+fd_redirections_head()
+{
+	atf_set "descr" "Tests redirections to/from specific descriptors"
+}
+fd_redirections_body()
+{
+	# Or it will one day...
+} 
+
+atf_test_case local_redirections
+local_redirections_head()
+{
+	atf_set "descr" \
+	    "Tests that exec can reassign file descriptors in the shell itself"
+}
+local_redirections_body()
+{
+	# Or it will one day...
+}
+
 atf_test_case redir_in_case
-redir_in_case_head() {
-	atf_set "descr" "Tests that sh(1) allows plain redirections " \
+redir_in_case_head()
+{
+	atf_set "descr" "Tests that sh(1) allows just redirections " \
 	                "in case statements. (PR bin/48631)"
 }
-redir_in_case_body() {
+redir_in_case_body()
+{
 	atf_check -s exit:0 -o empty -e empty \
 	    ${TEST_SH} -c 'case x in (whatever) >foo;; esac'
+
+	atf_check -s exit:0 -o empty -e empty \
+	    ${TEST_SH} -c 'case x in (whatever) >foo 2>&1;; esac'
+
+	atf_check -s exit:0 -o empty -e empty \
+	    ${TEST_SH} -c 'case x in (whatever) >foo 2>&1 </dev/null;; esac'
+
+	atf_check -s exit:0 -o empty -e empty \
+	    ${TEST_SH} -c 'case x in (whatever) >${somewhere};; esac'
 }
 
+atf_test_case incorrect_redirections
+incorrect_redirections_head()
+{
+	atf_set "descr" "Tests that sh(1) correctly ignores non-redirections"
+}
+incorrect_redirections_body() {
+
+	atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c 'echo foo>'
+	atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c 'read foo<'
+	atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c 'echo foo<>'
+	atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
+		'echo x > '"$nl"
+	atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
+		'read x < '"$nl"
+	atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
+		'echo x <> '"$nl"
+	atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
+		'echo x >< anything'
+	atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
+		'echo x >>< anything'
+	atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
+		'echo x >|< anything'
+	atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
+		'echo x > ; read x < /dev/null || echo bad'
+	atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
+		'read x < & echo y > /dev/null; wait && echo bad'
+
+	rm -f Output 2>/dev/null || :
+	atf_check -s exit:0 -e empty -o inline:'A Line > Output\n' \
+		${TEST_SH} -c 'echo A Line \> Output'
+	test -f Output && atf_file "File 'Output' appeared and should not have"
+
+	rm -f Output 2>/dev/null || :
+	atf_check -s exit:0 -e empty -o empty \
+		${TEST_SH} -c 'echo A Line \>> Output'
+	test -f Output || atf_file "File 'Output' not created when it should"
+	test "$(cat Output)" = 'A Line >' || atf_fail \
+		"Output file contains '$(cat Output)' instead of '"'A Line >'\'
+
+	rm -f Output \> 2>/dev/null || :
+	atf_check -s exit:0 -e empty -o empty \
+		${TEST_SH} -c 'echo A Line >\> Output'
+	test -f Output && atf_file "File 'Output' appeared and should not have"
+	test -f '>' || atf_file "File '>' not created when it should"
+	test "$(cat '>')" = 'A Line Output' || atf_fail \
+	    "Output file ('>') contains '$(cat '>')' instead of 'A Line Output'"
+}
+
+# Many more tests in t_here, so here we have just rudimentary checks
 atf_test_case redir_here_doc
-redir_here_doc_head() {
+redir_here_doc_head()
+{
 	atf_set "descr" "Tests that sh(1) correctly processes 'here' doc " \
 	                "input redirections"
 }
-redir_here_doc_body() {
-
+redir_here_doc_body()
+{
+	# nb: the printf is not executed, it is data
 	cat <<- 'DONE' |
 		cat <<EOF
 			printf '%s\n' 'hello\n'
 		EOF
 	DONE
-	atf_check -s exit:0 -o match:'hello\\n' -e empty ${TEST_SH} 
+	atf_check -s exit:0 -o match:printf -o match:'hello\\n' \
+		-e empty ${TEST_SH} 
+}
+
+atf_test_case subshell_redirections
+subshell_redirections_head()
+{
+	atf_set "descr" "Tests redirection interactions between shell and " \
+			"its sub-shell(s)"
+}
+subshell_redirections_body()
+{
+	# Or will, one day
 }
 
 atf_init_test_cases() {
-	atf_add_test_case redir_in_case
+	atf_add_test_case basic_test_method_test
+	atf_add_test_case do_input_redirections
+	atf_add_test_case do_output_redirections
+	atf_add_test_case fd_redirections
+	atf_add_test_case local_redirections
+	atf_add_test_case incorrect_redirections
 	atf_add_test_case redir_here_doc
+	atf_add_test_case redir_in_case
+	atf_add_test_case subshell_redirections
 }

Reply via email to