summaryrefslogtreecommitdiffstats
path: root/contrib/netbsd-tests/bin
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/netbsd-tests/bin')
-rw-r--r--contrib/netbsd-tests/bin/cat/d_align.in2
-rw-r--r--contrib/netbsd-tests/bin/cat/d_align.out2
-rw-r--r--contrib/netbsd-tests/bin/cat/d_se_output.in3
-rw-r--r--contrib/netbsd-tests/bin/cat/d_se_output.out3
-rwxr-xr-xcontrib/netbsd-tests/bin/cat/t_cat.sh14
-rwxr-xr-xcontrib/netbsd-tests/bin/sh/dotcmd/scoped_command25
-rwxr-xr-xcontrib/netbsd-tests/bin/sh/dotcmd/t_dotcmd.sh6
-rwxr-xr-xcontrib/netbsd-tests/bin/sh/t_arith.sh1035
-rwxr-xr-xcontrib/netbsd-tests/bin/sh/t_cmdsub.sh783
-rwxr-xr-xcontrib/netbsd-tests/bin/sh/t_compexit.sh63
-rwxr-xr-xcontrib/netbsd-tests/bin/sh/t_evaltested.sh6
-rwxr-xr-xcontrib/netbsd-tests/bin/sh/t_exit.sh120
-rwxr-xr-xcontrib/netbsd-tests/bin/sh/t_expand.sh296
-rwxr-xr-xcontrib/netbsd-tests/bin/sh/t_fsplit.sh244
-rwxr-xr-xcontrib/netbsd-tests/bin/sh/t_here.sh536
-rwxr-xr-xcontrib/netbsd-tests/bin/sh/t_option.sh674
-rwxr-xr-xcontrib/netbsd-tests/bin/sh/t_redir.sh903
-rwxr-xr-xcontrib/netbsd-tests/bin/sh/t_redircloexec.sh178
-rwxr-xr-xcontrib/netbsd-tests/bin/sh/t_set_e.sh42
-rwxr-xr-xcontrib/netbsd-tests/bin/sh/t_shift.sh181
-rwxr-xr-xcontrib/netbsd-tests/bin/sh/t_ulimit.sh23
-rwxr-xr-xcontrib/netbsd-tests/bin/sh/t_varquote.sh95
-rwxr-xr-xcontrib/netbsd-tests/bin/sh/t_varval.sh251
-rwxr-xr-xcontrib/netbsd-tests/bin/sh/t_wait.sh152
24 files changed, 5400 insertions, 237 deletions
diff --git a/contrib/netbsd-tests/bin/cat/d_align.in b/contrib/netbsd-tests/bin/cat/d_align.in
index 31bf4a7..37d30c7 100644
--- a/contrib/netbsd-tests/bin/cat/d_align.in
+++ b/contrib/netbsd-tests/bin/cat/d_align.in
@@ -1,3 +1,5 @@
a b c
+
1 2 3
+
x y z
diff --git a/contrib/netbsd-tests/bin/cat/d_align.out b/contrib/netbsd-tests/bin/cat/d_align.out
index fd32469..4f44c00 100644
--- a/contrib/netbsd-tests/bin/cat/d_align.out
+++ b/contrib/netbsd-tests/bin/cat/d_align.out
@@ -1,3 +1,5 @@
1 a b c$
+ $
2 1 2 3$
+ $
3 x y z$
diff --git a/contrib/netbsd-tests/bin/cat/d_se_output.in b/contrib/netbsd-tests/bin/cat/d_se_output.in
new file mode 100644
index 0000000..0d3c8c1
--- /dev/null
+++ b/contrib/netbsd-tests/bin/cat/d_se_output.in
@@ -0,0 +1,3 @@
+
+Of course it runs NetBSD
+
diff --git a/contrib/netbsd-tests/bin/cat/d_se_output.out b/contrib/netbsd-tests/bin/cat/d_se_output.out
new file mode 100644
index 0000000..c4767c3
--- /dev/null
+++ b/contrib/netbsd-tests/bin/cat/d_se_output.out
@@ -0,0 +1,3 @@
+$
+Of course it runs NetBSD$
+$
diff --git a/contrib/netbsd-tests/bin/cat/t_cat.sh b/contrib/netbsd-tests/bin/cat/t_cat.sh
index 1b7a930..799a748 100755
--- a/contrib/netbsd-tests/bin/cat/t_cat.sh
+++ b/contrib/netbsd-tests/bin/cat/t_cat.sh
@@ -1,4 +1,4 @@
-# $NetBSD: t_cat.sh,v 1.2 2012/03/27 17:57:02 jruoho Exp $
+# $NetBSD: t_cat.sh,v 1.3 2016/06/16 01:04:58 sevan Exp $
#
# Copyright (c) 2012 The NetBSD Foundation, Inc.
# All rights reserved.
@@ -52,8 +52,20 @@ nonexistent_body() {
-x "cat /some/name/that/does/not/exist"
}
+atf_test_case se_output
+se_output_head() {
+ atf_set "descr" "Test that cat(1) prints a $ sign " \
+ "on blank lines with options '-se' (PR bin/51250)"
+}
+
+se_output_body() {
+ atf_check -s ignore -o file:$(atf_get_srcdir)/d_se_output.out \
+ -x "cat -se $(atf_get_srcdir)/d_se_output.in"
+}
+
atf_init_test_cases()
{
atf_add_test_case align
atf_add_test_case nonexistent
+ atf_add_test_case se_output
}
diff --git a/contrib/netbsd-tests/bin/sh/dotcmd/scoped_command b/contrib/netbsd-tests/bin/sh/dotcmd/scoped_command
index fda4e53..36e712b 100755
--- a/contrib/netbsd-tests/bin/sh/dotcmd/scoped_command
+++ b/contrib/netbsd-tests/bin/sh/dotcmd/scoped_command
@@ -1,6 +1,6 @@
#!/bin/sh
#
-# $NetBSD: scoped_command,v 1.1 2014/05/31 14:29:06 christos Exp $
+# $NetBSD: scoped_command,v 1.2 2016/03/27 14:57:50 christos Exp $
#
# Copyright (c) 2014 The NetBSD Foundation, Inc.
# All rights reserved.
@@ -30,6 +30,27 @@
# POSSIBILITY OF SUCH DAMAGE.
#
+: ${TEST_SH:=/bin/sh}
+
+sane_sh()
+{
+ set -- ${TEST_SH}
+ case "$#" in
+ (0) set /bin/sh;;
+ (1|2) ;;
+ (*) set "$1";; # Just ignore options if we cannot make them work
+ esac
+
+ case "$1" in
+ /*) TEST_SH="$1${2+ }$2";;
+ ./*) TEST_SH="${PWD}${1#.}${2+ }$2";;
+ */*) TEST_SH="${PWD}/$1${2+ }$2";;
+ *) TEST_SH="$( command -v "$1" )${2+ }$2";;
+ esac
+}
+
+sane_sh
+
set -e
# USAGE:
@@ -52,7 +73,7 @@ cmd="echo 'before ${3}'
${2}
echo 'after ${3}, return value:' ${?}"
-echo "#!/bin/sh"
+echo "#!${TEST_SH}"
[ 'func' = "${1}" ] && cat <<EOF
func()
diff --git a/contrib/netbsd-tests/bin/sh/dotcmd/t_dotcmd.sh b/contrib/netbsd-tests/bin/sh/dotcmd/t_dotcmd.sh
index b365b1d..8e9b277 100755
--- a/contrib/netbsd-tests/bin/sh/dotcmd/t_dotcmd.sh
+++ b/contrib/netbsd-tests/bin/sh/dotcmd/t_dotcmd.sh
@@ -1,4 +1,4 @@
-# $NetBSD: t_dotcmd.sh,v 1.1 2014/05/31 14:29:06 christos Exp $
+# $NetBSD: t_dotcmd.sh,v 1.2 2016/03/27 14:57:50 christos Exp $
#
# Copyright (c) 2014 The NetBSD Foundation, Inc.
# All rights reserved.
@@ -33,6 +33,10 @@
# in C/C++ so, for example, if the dotcmd is in a loop's body, a break in
# the sourced file can be used to break out of that loop.
+# Note that the standard does not require this, and allows lexically
+# scoped interpretation of break/continue (and permits dynamic scope
+# as an optional extension.)
+
cmds='return break continue'
scopes='case compound file for func subshell until while'
diff --git a/contrib/netbsd-tests/bin/sh/t_arith.sh b/contrib/netbsd-tests/bin/sh/t_arith.sh
new file mode 100755
index 0000000..d7b5083
--- /dev/null
+++ b/contrib/netbsd-tests/bin/sh/t_arith.sh
@@ -0,0 +1,1035 @@
+# $NetBSD: t_arith.sh,v 1.5 2016/05/12 14:25:11 kre Exp $
+#
+# Copyright (c) 2016 The NetBSD Foundation, Inc.
+# 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+#
+# the implementation of "sh" to test
+: ${TEST_SH:="/bin/sh"}
+
+# Requirement is to support at least "signed long" whatever that means
+# (number of bits in "long" is not specified - but should be at least 32).
+
+# These tests use -o inline:"..." rather than -o match:'...' as we have
+# only digits to examine, and it is good to be sure that 1 + 1 really gives 2
+# and that 42 or 123 don't look like success because there is a 2 in them.
+
+ARITH_BITS='?'
+discover_range()
+{
+ # cannot use arithmetic "test" operators, range of test in
+ # ATF_SHELL (or even TEST_SH) might not be as big as that
+ # supported by $(( )) in TEST_SH
+
+ if ! ${TEST_SH} -c ': $(( 0x10000 ))' 2>/dev/null
+ then
+ # 16 bits or less, or hex unsupported, just give up...
+ return
+ fi
+ test $( ${TEST_SH} -c 'echo $(( 0x1FFFF ))' ) = 131071 || return
+
+ # when attempting to exceed the number of available bits
+ # the shell may react in any of 3 (rational) ways
+ # 1. syntax error (maybe even core dump...) and fail
+ # 2. represent a positive number input as negative value
+ # 3. keep the number positive, but not the value expected
+ # (perhaps pegged at the max possible value)
+ # any of those may be accompanied by a message to stderr
+
+ # Must check all 3 possibilities for each plausible size
+ # Tests do not use 0x8000... because that value can have weird
+ # other side effects that are not relevant to discover here.
+ # But we do want to try and force the sign bit set.
+
+ if ! ${TEST_SH} -c ': $(( 0xC0000000 ))' 2>/dev/null
+ then
+ # proobably shell detected overflow and complained
+ ARITH_BITS=32
+ return
+ fi
+ if ${TEST_SH} 2>/dev/null \
+ -c 'case $(( 0xC0000000 )); in (-*) exit 0;; esac; exit 1'
+ then
+ ARITH_BITS=32
+ return
+ fi
+ if ${TEST_SH} -c '[ $(( 0xC0000000 )) != 3221225472 ]' 2>/dev/null
+ then
+ ARITH_BITS=32
+ return
+ fi
+
+ if ! ${TEST_SH} -c ': $(( 0xC000000000000000 ))' 2>/dev/null
+ then
+ ARITH_BITS=64
+ return
+ fi
+ if ${TEST_SH} 2>/dev/null \
+ -c 'case $(( 0xC000000000000000 )); in (-*) exit 0;; esac; exit 1'
+ then
+ ARITH_BITS=64
+ return
+ fi
+ if ${TEST_SH} 2>/dev/null \
+ -c '[ $((0xC000000000000000)) != 13835058055282163712 ]'
+ then
+ ARITH_BITS=64
+ return
+ fi
+
+ if ${TEST_SH} 2>/dev/null -c \
+ '[ $((0x123456781234567812345678)) = 5634002657842756053938493048 ]'
+ then
+ # just assume... (for now anyway, revisit when it happens...)
+ ARITH_BITS=96
+ return
+ fi
+}
+
+atf_test_case constants
+constants_head()
+{
+ atf_set "descr" "Tests that arithmetic expansion can handle constants"
+}
+constants_body()
+{
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 1 ))'
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0 ))'
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $((0x0))'
+
+ # atf_expect_fail "PR bin/50959"
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $((0X0))'
+ # atf_expect_pass
+
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $((000))'
+
+ atf_check -s exit:0 -o inline:'1\n' -e empty \
+ ${TEST_SH} -c 'echo $(( 000000001 ))'
+ atf_check -s exit:0 -o inline:'0\n' -e empty \
+ ${TEST_SH} -c 'echo $(( 0x000000 ))'
+
+ atf_check -s exit:0 -o inline:'99999\n' -e empty \
+ ${TEST_SH} -c 'echo $((99999))'
+
+ [ ${ARITH_BITS} -gt 44 ] &&
+ atf_check -s exit:0 -o inline:'9191919191919\n' -e empty \
+ ${TEST_SH} -c 'echo $((9191919191919))'
+
+ atf_check -s exit:0 -o inline:'13\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0xD ))'
+ atf_check -s exit:0 -o inline:'11\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 013 ))'
+ atf_check -s exit:0 -o inline:'7\n' -e empty ${TEST_SH} -c \
+ 'x=7;echo $(($x))'
+ atf_check -s exit:0 -o inline:'9\n' -e empty ${TEST_SH} -c \
+ 'x=9;echo $((x))'
+
+ atf_check -s exit:0 -o inline:'11\n' -e empty \
+ ${TEST_SH} -c 'x=0xB; echo $(( $x ))'
+ atf_check -s exit:0 -o inline:'27\n' -e empty \
+ ${TEST_SH} -c 'x=0X1B; echo $(( x ))'
+ atf_check -s exit:0 -o inline:'27\n' -e empty \
+ ${TEST_SH} -c 'X=033; echo $(( $X ))'
+ atf_check -s exit:0 -o inline:'219\n' -e empty \
+ ${TEST_SH} -c 'X=0333; echo $(( X ))'
+ atf_check -s exit:0 -o inline:'0\n' -e empty \
+ ${TEST_SH} -c 'NULL=; echo $(( NULL ))'
+
+ # Not clear if this is 0, nothing, or an error, so omit for now
+ # atf_check -s exit:0 -o inline:'0\n' -e empty \
+ # ${TEST_SH} -c 'echo $(( ))'
+
+ # not clear whether this should return 0 or an error, so omit for now
+ # atf_check -s exit:0 -o inline:'0\n' -e empty \
+ # ${TEST_SH} -c 'echo $(( UNDEFINED_VAR ))'
+}
+
+
+atf_test_case do_unary_plus
+do_unary_plus_head()
+{
+ atf_set "descr" "Tests that unary plus works as expected"
+}
+do_unary_plus_body()
+{
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( +0 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( +1 ))'
+ atf_check -s exit:0 -o inline:'6\n' -e empty ${TEST_SH} -c \
+ 'echo $(( + 6 ))'
+ atf_check -s exit:0 -o inline:'4321\n' -e empty ${TEST_SH} -c \
+ 'echo $(( + 4321 ))'
+ atf_check -s exit:0 -o inline:'17185\n' -e empty ${TEST_SH} -c \
+ 'echo $(( + 0x4321 ))'
+}
+
+atf_test_case do_unary_minus
+do_unary_minus_head()
+{
+ atf_set "descr" "Tests that unary minus works as expected"
+}
+do_unary_minus_body()
+{
+ atf_check -s exit:0 -o inline:'-1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( -1 ))'
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( - 0 ))'
+ atf_check -s exit:0 -o inline:'-1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( - 1 ))'
+ atf_check -s exit:0 -o inline:'-6\n' -e empty ${TEST_SH} -c \
+ 'echo $(( - 6 ))'
+ atf_check -s exit:0 -o inline:'-4321\n' -e empty ${TEST_SH} -c \
+ 'echo $(( - 4321 ))'
+ atf_check -s exit:0 -o inline:'-2257\n' -e empty ${TEST_SH} -c \
+ 'echo $(( - 04321 ))'
+ atf_check -s exit:0 -o inline:'-7\n' -e empty ${TEST_SH} -c \
+ 'echo $((-7))'
+}
+
+atf_test_case do_unary_not
+do_unary_not_head()
+{
+ atf_set "descr" "Tests that unary not (boolean) works as expected"
+}
+do_unary_not_body()
+{
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( ! 1 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( ! 0 ))'
+
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( !1234 ))'
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( !0xFFFF ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( ! 000000 ))'
+}
+
+atf_test_case do_unary_tilde
+do_unary_tilde_head()
+{
+ atf_set "descr" "Tests that unary not (bitwise) works as expected"
+}
+do_unary_tilde_body()
+{
+ # definitely 2's complement arithmetic here...
+
+ atf_check -s exit:0 -o inline:'-1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( ~ 0 ))'
+ atf_check -s exit:0 -o inline:'-2\n' -e empty ${TEST_SH} -c \
+ 'echo $(( ~ 1 ))'
+
+ atf_check -s exit:0 -o inline:'-1235\n' -e empty ${TEST_SH} -c \
+ 'echo $(( ~1234 ))'
+ atf_check -s exit:0 -o inline:'-256\n' -e empty ${TEST_SH} -c \
+ 'echo $(( ~0xFF ))'
+}
+
+atf_test_case elementary_add
+elementary_add_head()
+{
+ atf_set "descr" "Tests that simple addition works as expected"
+}
+elementary_add_body()
+{
+ # some of these tests actually test unary ops & op precedence...
+
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0 + 0 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 1 + 0 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0 + 1 ))'
+ atf_check -s exit:0 -o inline:'2\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 1 + 1 ))'
+ atf_check -s exit:0 -o inline:'10\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 4 + 6 ))'
+ atf_check -s exit:0 -o inline:'10\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 6 + 4 ))'
+ atf_check -s exit:0 -o inline:'5555\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 1234 + 4321 ))'
+ atf_check -s exit:0 -o inline:'3333\n' -e empty ${TEST_SH} -c \
+ 'echo $((1111+2222))'
+ atf_check -s exit:0 -o inline:'5555\n' -e empty ${TEST_SH} -c \
+ 'echo $((+3333+2222))'
+ atf_check -s exit:0 -o inline:'7777\n' -e empty ${TEST_SH} -c \
+ 'echo $((+3333 + +4444))'
+ atf_check -s exit:0 -o inline:'-7777\n' -e empty ${TEST_SH} -c \
+ 'echo -$((+4125+ +3652))'
+}
+
+atf_test_case elementary_sub
+elementary_sub_head()
+{
+ atf_set "descr" "Tests that simple subtraction works as expected"
+}
+elementary_sub_body()
+{
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0 - 0 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 1 - 0 ))'
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 1 - 1 ))'
+ atf_check -s exit:0 -o inline:'-1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0 - 1 ))'
+ atf_check -s exit:0 -o inline:'488\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 1066 - 578 ))'
+ atf_check -s exit:0 -o inline:'-3662\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 2016-5678 ))'
+ atf_check -s exit:0 -o inline:'-3662\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 2016+-5678 ))'
+ atf_check -s exit:0 -o inline:'-3662\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 2016-+5678 ))'
+ atf_check -s exit:0 -o inline:'-7694\n' -e empty ${TEST_SH} -c \
+ 'echo $(( -2016-5678 ))'
+ atf_check -s exit:0 -o inline:'--1\n' -e empty ${TEST_SH} -c \
+ 'echo -$(( -1018 - -1017 ))'
+}
+
+atf_test_case elementary_mul
+elementary_mul_head()
+{
+ atf_set "descr" "Tests that simple multiplication works as expected"
+}
+elementary_mul_body()
+{
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0 * 0 ))'
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 1 * 0 ))'
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0 * 1 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 1 * 1 ))'
+ atf_check -s exit:0 -o inline:'-1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( -1 * 1 ))'
+ atf_check -s exit:0 -o inline:'-1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 1 * -1 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( -1 * -1 ))'
+ atf_check -s exit:0 -o inline:'391\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 17 * 23 ))'
+ atf_check -s exit:0 -o inline:'169\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 13*13 ))'
+ atf_check -s exit:0 -o inline:'-11264\n' -e empty ${TEST_SH} -c \
+ 'echo $(( -11 *1024 ))'
+ atf_check -s exit:0 -o inline:'-16983\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 17* -999 ))'
+ atf_check -s exit:0 -o inline:'9309\n' -e empty ${TEST_SH} -c \
+ 'echo $(( -29*-321 ))'
+}
+
+atf_test_case elementary_div
+elementary_div_head()
+{
+ atf_set "descr" "Tests that simple division works as expected"
+}
+elementary_div_body()
+{
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0 / 1 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 1 / 1 ))'
+ test ${ARITH_BITS} -ge 38 &&
+ atf_check -s exit:0 -o inline:'99999999999\n' -e empty \
+ ${TEST_SH} -c 'echo $(( 99999999999 / 1 ))'
+ atf_check -s exit:0 -o inline:'2\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 2 / 1 ))'
+
+ atf_check -s exit:0 -o inline:'3\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 3 / 1 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 3 / 2 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 3 / 3 ))'
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 3 / 4 ))'
+
+ atf_check -s exit:0 -o inline:'173\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 123456 / 713 ))'
+ atf_check -s exit:0 -o inline:'13\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 169 / 13 ))'
+}
+
+atf_test_case elementary_rem
+elementary_rem_head()
+{
+ atf_set "descr" "Tests that simple modulus works as expected"
+}
+elementary_rem_body()
+{
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0 % 1 ))'
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 1 % 1 ))'
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 2 % 1 ))'
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 9999 % 1 ))'
+
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0 % 2 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 1 % 2 ))'
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 2 % 2 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0xFFFF % 2 ))'
+
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0 % 3 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 1 % 3 ))'
+ atf_check -s exit:0 -o inline:'2\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 2 % 3 ))'
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 3 % 3 ))'
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 3123 % 3 ))'
+
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 9999 % 2 ))'
+
+ atf_check -s exit:0 -o inline:'107\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 123456%173 ))'
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $((169%13))'
+}
+
+atf_test_case elementary_shl
+elementary_shl_head()
+{
+ atf_set "descr" "Tests that simple shift left works as expected"
+}
+elementary_shl_body()
+{
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0 << 0 ))'
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0 << 1 ))'
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0 << 17 ))'
+
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 1 << 0 ))'
+ atf_check -s exit:0 -o inline:'2\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 1 << 1 ))'
+ atf_check -s exit:0 -o inline:'131072\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 1 << 17 ))'
+
+ atf_check -s exit:0 -o inline:'2021161080\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0x3C3C3C3C << 1 ))'
+
+ test "${ARITH_BITS}" -ge 40 &&
+ atf_check -s exit:0 -o inline:'129354309120\n' -e empty \
+ ${TEST_SH} -c 'echo $(( 0x3C3C3C3C << 7 ))'
+ test "${ARITH_BITS}" -ge 72 &&
+ atf_check -s exit:0 -o inline:'1111145054534149079040\n' \
+ -e empty ${TEST_SH} -c 'echo $(( 0x3C3C3C3C << 40 ))'
+
+ return 0
+}
+
+atf_test_case elementary_shr
+elementary_shr_head()
+{
+ atf_set "descr" "Tests that simple shift right works as expected"
+}
+elementary_shr_body()
+{
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0 >> 0 ))'
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0 >> 1 ))'
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0 >> 17 ))'
+
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 1 >> 0 ))'
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 1 >> 1 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 2 >> 1 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 3 >> 1 ))'
+
+ atf_check -s exit:0 -o inline:'4\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0x10 >> 2 ))'
+ atf_check -s exit:0 -o inline:'4\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 022 >> 2 ))'
+
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 131072 >> 17 ))'
+
+ test ${ARITH_BITS} -ge 40 &&
+ atf_check -s exit:0 -o inline:'8\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0x4000000000 >> 35 ))'
+ test ${ARITH_BITS} -ge 80 &&
+ atf_check -s exit:0 -o inline:'4464\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0x93400FACE005C871000 >> 64 ))'
+
+ return 0
+}
+
+atf_test_case elementary_eq
+elementary_eq_head()
+{
+ atf_set "descr" "Tests that simple equality test works as expected"
+}
+elementary_eq_body()
+{
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0 == 0 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0 == 0000 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0 == 0x00 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 1 == 1 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'X=30; Y=0x1E; echo $(( X == Y ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0x1234 == 4660 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0x1234 == 011064 ))'
+
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0 == 1 ))'
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0 == 0000000000000001 ))'
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0 == 0x10000000000000 ))'
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 1 == 2 ))'
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'X=3; Y=7; echo $(( X == Y ))'
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 1234 == 0x4660 ))'
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 01234 == 0x11064 ))'
+}
+atf_test_case elementary_ne
+elementary_ne_head()
+{
+ atf_set "descr" "Tests that simple inequality test works as expected"
+}
+elementary_ne_body()
+{
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 1 != 0 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0x71 != 17 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 1234 != 01234 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0x1234 != 01234 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'X=3; echo $(( X != 0 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'X=3; Y=0x11; echo $(( X != Y ))'
+
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 3 != 3 ))'
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0 != 0x0 ))'
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0xA != 012 ))'
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'X=1; echo $(( X != 1 ))'
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'X=0xC; Y=014; echo $(( X != Y ))'
+}
+atf_test_case elementary_lt
+elementary_lt_head()
+{
+ atf_set "descr" "Tests that simple less than test works as expected"
+}
+elementary_lt_body()
+{
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0 < 1 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( -1 < 0 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0 < 10 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 100 < 101 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0xA1 < 200 ))'
+
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0 < 0 ))'
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 1 < 0 ))'
+
+ test ${ARITH_BITS} -ge 40 &&
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0x1BEEFF00D < 0x1FACECAFE ))'
+
+ return 0
+}
+atf_test_case elementary_le
+elementary_le_head()
+{
+ atf_set "descr" "Tests that simple less or equal test works as expected"
+}
+elementary_le_body()
+{
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0 <= 1 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( -1 <= 0 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0 <= 0 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0 <= 10 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 100 <= 101 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0xA1 <= 161 ))'
+
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 1 <= 0 ))'
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( -100 <= -200 ))'
+
+ test ${ARITH_BITS} -ge 40 &&
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'cost=; AUD=; echo $(( $cost 0x2FEEDBABE <= $AUD 12866927294 ))'
+
+ return 0
+}
+atf_test_case elementary_gt
+elementary_gt_head()
+{
+ atf_set "descr" "Tests that simple greater than works as expected"
+}
+elementary_gt_body()
+{
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 1 > 0 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 1 > -1 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 11 > 012 ))'
+
+ # atf_expect_fail "PR bin/50959"
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 2147483647 > 0X7FFFFF0 ))'
+ # atf_expect_pass
+
+ test ${ARITH_BITS} -gt 32 &&
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0x80000000 > 0x7FFFFFFF ))'
+
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0 > 0 ))'
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0 > 1 ))'
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( -1 > 0 ))'
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0 > 10 ))'
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 2015 > 2016 ))'
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0xA1 > 200 ))'
+
+ test ${ARITH_BITS} -ge 44 &&
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0x7F07F07F0 > 34099628014 ))'
+
+ return 0
+}
+atf_test_case elementary_ge
+elementary_ge_head()
+{
+ atf_set "descr" "Tests that simple greater or equal works as expected"
+}
+elementary_ge_body()
+{
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0 >= 0 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 1 >= 0 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( -100 >= -101 ))'
+
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( -1 >= 0 ))'
+}
+
+atf_test_case fiddle_bits_and
+fiddle_bits_and_head()
+{
+ atf_set "descr" "Test bitwise and operations in arithmetic expressions"
+}
+fiddle_bits_and_body()
+{
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0 & 0 ))'
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 1 & 0 ))'
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0 & 1 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 1 & 1 ))'
+
+ atf_check -s exit:0 -o inline:'255\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0xFF & 0xFF ))'
+ atf_check -s exit:0 -o inline:'255\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0xFFFF & 0377 ))'
+
+ test "${ARITH_BITS}" -ge 48 &&
+ atf_check -s exit:0 -o inline:'70377641607203\n' -e empty \
+ ${TEST_SH} -c 'echo $(( 0x5432FEDC0123 & 0x42871357BAB3 ))'
+
+ return 0
+}
+atf_test_case fiddle_bits_or
+fiddle_bits_or_head()
+{
+ atf_set "descr" "Test bitwise or operations in arithmetic expressions"
+}
+fiddle_bits_or_body()
+{
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0 | 0 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 1 | 0 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0 | 1 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 1 | 1 ))'
+
+ atf_check -s exit:0 -o inline:'4369\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0x1111 | 0x1111 ))'
+ atf_check -s exit:0 -o inline:'255\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0xAA | 0125 ))'
+
+ test "${ARITH_BITS}" -ge 48 &&
+ atf_check -s exit:0 -o inline:'95348271856563\n' -e empty \
+ ${TEST_SH} -c 'echo $(( 0x5432FEDC0123 | 0x42871357BAB3 ))'
+
+ return 0
+}
+atf_test_case fiddle_bits_xor
+fiddle_bits_xor_head()
+{
+ atf_set "descr" "Test bitwise xor operations in arithmetic expressions"
+}
+fiddle_bits_xor_body()
+{
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0 ^ 0 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 1 ^ 0 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0 ^ 1 ))'
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 1 ^ 1 ))'
+
+ atf_check -s exit:0 -o inline:'255\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0xF0 ^ 0x0F ))'
+ atf_check -s exit:0 -o inline:'15\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0xF0 ^ 0xFF ))'
+
+ test "${ARITH_BITS}" -ge 48 &&
+ atf_check -s exit:0 -o inline:'24970630249360\n' -e empty \
+ ${TEST_SH} -c 'echo $(( 0x5432FEDC0123 ^ 0x42871357BAB3 ))'
+
+ return 0
+}
+
+atf_test_case logical_and
+logical_and_head()
+{
+ atf_set "descr" "Test logical and operations in arithmetic expressions"
+}
+logical_and_body()
+{
+ # cannot test short-circuit eval until sh implements side effects...
+
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0 && 0 ))'
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 1 && 0 ))'
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0 && 1 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 1 && 1 ))'
+
+ # atf_expect_fail "PR bin/50960"
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0x1111 && 01234 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0xFFFF && 0xF0F0 ))'
+}
+atf_test_case logical_or
+logical_or_head()
+{
+ atf_set "descr" "Test logical or operations in arithmetic expressions"
+}
+logical_or_body()
+{
+ # cannot test short-circuit eval until sh implements side effects...
+
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0 || 0 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 1 || 0 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0 || 1 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 1 || 1 ))'
+
+ # atf_expect_fail "PR bin/50960"
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0x1111 || 01234 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0x33 || 0xF0F0 ))'
+}
+
+atf_test_case make_selection
+make_selection_head()
+{
+ atf_set "descr" "Test ?: operator in arithmetic expressions"
+}
+make_selection_body()
+{
+ # atf_expect_fail "PR bin/50958"
+
+ atf_check -s exit:0 -o inline:'3\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0 ? 2 : 3 ))'
+ atf_check -s exit:0 -o inline:'2\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 1 ? 2 : 3 ))'
+
+ atf_check -s exit:0 -o inline:'111\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0x1234 ? 111 : 222 ))'
+
+ atf_check -s exit:0 -o inline:'-1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 1 < 2 ? -1 : 1 > 2 ? 1 : 0 ))'
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 1 < 1 ? -1 : 1 > 1 ? 1 : 0 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 2 < 1 ? -1 : 2 > 1 ? 1 : 0 ))'
+}
+
+atf_test_case operator_precedence
+operator_precedence_head()
+{
+ atf_set "descr" "Test operator precedence without parentheses"
+}
+operator_precedence_body()
+{
+ # NB: apart from $(( )) ** NO ** parentheses in the expressions.
+
+ atf_check -s exit:0 -o inline:'6\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 1 + 2 + 3 ))'
+ atf_check -s exit:0 -o inline:'2\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 1 - 2 + 3 ))'
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 3 - 2 - 1 ))'
+ atf_check -s exit:0 -o inline:'2\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 3 - 2 + 1 ))'
+
+ atf_check -s exit:0 -o inline:'-1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( - 2 + 1 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 2 + -1 ))'
+
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( ! 2 + 1 ))'
+ atf_check -s exit:0 -o inline:'2\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 2 + !1 ))'
+
+ atf_check -s exit:0 -o inline:'8\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 3 * 2 + 2 ))'
+ atf_check -s exit:0 -o inline:'7\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 3 + 2 * 2 ))'
+ atf_check -s exit:0 -o inline:'12\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 3 * 2 * 2 ))'
+
+ atf_check -s exit:0 -o inline:'5\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 9 / 3 + 2 ))'
+ atf_check -s exit:0 -o inline:'10\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 9 + 3 / 2 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 9 / 3 / 2 ))'
+
+ atf_check -s exit:0 -o inline:'72\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 9 << 1 + 2 ))'
+ atf_check -s exit:0 -o inline:'48\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 9 + 3 << 2 ))'
+ atf_check -s exit:0 -o inline:'288\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 9 << 3 << 2 ))'
+
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 9 >> 1 + 2 ))'
+ atf_check -s exit:0 -o inline:'3\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 9 + 3 >> 2 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 19 >> 3 >> 1 ))'
+
+ atf_check -s exit:0 -o inline:'4\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 19 >> 3 << 1 ))'
+ atf_check -s exit:0 -o inline:'76\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 19 << 3 >> 1 ))'
+
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 2 + 3 < 3 * 2 ))'
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 2 << 3 >= 3 << 2 ))'
+
+ # sh inherits C's crazy operator precedence...
+
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 0xfD & 0xF == 0xF ))'
+}
+
+parentheses_head()
+{
+ atf_set "descr" "Test use of () to group sub-expressions"
+}
+parentheses_body()
+{
+ atf_check -s exit:0 -o inline:'6\n' -e empty ${TEST_SH} -c \
+ 'echo $(( (1 + 2) + 3 ))'
+ atf_check -s exit:0 -o inline:'-4\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 1 - (2 + 3) ))'
+ atf_check -s exit:0 -o inline:'2\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 3 - (2 - 1) ))'
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 3 - ( 2 + 1 ) ))'
+
+ atf_check -s exit:0 -o inline:'-3\n' -e empty ${TEST_SH} -c \
+ 'echo $(( - (2 + 1) ))'
+
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( ! (2 + 1) ))'
+
+ atf_check -s exit:0 -o inline:'12\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 3 * (2 + 2) ))'
+ atf_check -s exit:0 -o inline:'10\n' -e empty ${TEST_SH} -c \
+ 'echo $(( (3 + 2) * 2 ))'
+ atf_check -s exit:0 -o inline:'12\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 3 * (2 * 2) ))'
+
+ atf_check -s exit:0 -o inline:'1\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 9 / (3 + 2) ))'
+ atf_check -s exit:0 -o inline:'6\n' -e empty ${TEST_SH} -c \
+ 'echo $(( ( 9 + 3 ) / 2 ))'
+ atf_check -s exit:0 -o inline:'9\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 9 / ( 3 / 2 ) ))'
+
+ atf_check -s exit:0 -o inline:'20\n' -e empty ${TEST_SH} -c \
+ 'echo $(( ( 9 << 1 ) + 2 ))'
+ atf_check -s exit:0 -o inline:'21\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 9 + (3 << 2) ))'
+ atf_check -s exit:0 -o inline:'36864\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 9 << (3 << 2) ))'
+
+ atf_check -s exit:0 -o inline:'6\n' -e empty ${TEST_SH} -c \
+ 'echo $(( (9 >> 1) + 2 ))'
+ atf_check -s exit:0 -o inline:'9\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 9 + (3 >> 2) ))'
+ atf_check -s exit:0 -o inline:'9\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 19 >> (3 >> 1) ))'
+
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 19 >> (3 << 1) ))'
+ atf_check -s exit:0 -o inline:'38\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 19 << (3 >> 1) ))'
+
+ atf_check -s exit:0 -o inline:'2\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 2 + (3 < 3) * 2 ))'
+ atf_check -s exit:0 -o inline:'32\n' -e empty ${TEST_SH} -c \
+ 'echo $(( 2 << ((3 >= 3) << 2) ))'
+
+ # sh inherits C's crazy operator precedence...
+
+ atf_check -s exit:0 -o inline:'0\n' -e empty ${TEST_SH} -c \
+ 'echo $(( (0xfD & 0xF) == 0xF ))'
+}
+
+atf_test_case arithmetic_fails
+arithmetic_fails_head()
+{
+ atf_set "descr" "Dummy test to force failure"
+}
+arithmetic_fails_body()
+{
+ atf_fail "Cannot estimate number of bits supported by $(( ))"
+}
+
+atf_init_test_cases() {
+
+ discover_range
+
+ test "${ARITH_BITS}" = '?' && {
+ atf_add_test_case arithmetic_fails
+ return 0
+ }
+
+ # odd names are to get atf's sort order semi-rational
+
+ atf_add_test_case constants
+ atf_add_test_case do_unary_plus
+ atf_add_test_case do_unary_minus
+ atf_add_test_case do_unary_not
+ atf_add_test_case do_unary_tilde
+ atf_add_test_case elementary_add
+ atf_add_test_case elementary_sub
+ atf_add_test_case elementary_mul
+ atf_add_test_case elementary_div
+ atf_add_test_case elementary_rem
+ atf_add_test_case elementary_shl
+ atf_add_test_case elementary_shr
+ atf_add_test_case elementary_eq
+ atf_add_test_case elementary_ne
+ atf_add_test_case elementary_lt
+ atf_add_test_case elementary_le
+ atf_add_test_case elementary_gt
+ atf_add_test_case elementary_ge
+ atf_add_test_case fiddle_bits_and
+ atf_add_test_case fiddle_bits_or
+ atf_add_test_case fiddle_bits_xor
+ atf_add_test_case logical_and
+ atf_add_test_case logical_or
+ atf_add_test_case make_selection
+ atf_add_test_case operator_precedence
+ atf_add_test_case parentheses
+ # atf_add_test_case progressive # build up big expr
+ # atf_add_test_case test_errors # erroneous input
+ # atf_add_test_case torture # hard stuff (if there is any)
+ # atf_add_test_case var_assign # assignment ops
+ # atf_add_test_case vulgarity # truly evil inputs (syntax in vars...)
+}
diff --git a/contrib/netbsd-tests/bin/sh/t_cmdsub.sh b/contrib/netbsd-tests/bin/sh/t_cmdsub.sh
new file mode 100755
index 0000000..f3ee210
--- /dev/null
+++ b/contrib/netbsd-tests/bin/sh/t_cmdsub.sh
@@ -0,0 +1,783 @@
+# $NetBSD: t_cmdsub.sh,v 1.4 2016/04/04 12:40:13 christos Exp $
+#
+# Copyright (c) 2016 The NetBSD Foundation, Inc.
+# 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+#
+# the implementation of "sh" to test
+: ${TEST_SH:="/bin/sh"}
+
+#
+# This file tests command substitutions ( `...` and $( ... ) )
+#
+# CAUTION:
+# Be careful attempting running these tests outside the ATF environment
+# Some of the tests run "rm *" in the current directory to clean up
+# An ATF test directory should be empty already, outside ATF, anything
+
+atf_test_case a_basic_cmdsub
+a_basic_cmdsub_head() {
+ atf_set "descr" 'Test operation of simple $( ) substitutions'
+}
+a_basic_cmdsub_body() {
+ atf_check -s exit:0 -o match:'Result is true today' -e empty \
+ ${TEST_SH} -c \
+ 'echo Result is $( true && echo true || echo false ) today'
+
+ atf_check -s exit:0 -o match:'Result is false today' -e empty \
+ ${TEST_SH} -c \
+ 'echo Result is $( false && echo true || echo false ) today'
+
+ atf_check -s exit:0 -o match:'aaabbbccc' -e empty \
+ ${TEST_SH} -c 'echo aaa$( echo bbb )ccc'
+ atf_check -s exit:0 -o match:'aaabbb cccddd' -e empty \
+ ${TEST_SH} -c 'echo aaa$( echo bbb ccc )ddd'
+ atf_check -s exit:0 -o inline:'aaabbb cccddd\n' -e empty \
+ ${TEST_SH} -c 'echo aaa$( echo bbb; echo ccc )ddd'
+ atf_check -s exit:0 -o inline:'aaabbb\ncccddd\n' -e empty \
+ ${TEST_SH} -c 'echo "aaa$( echo bbb; echo ccc )ddd"'
+
+ atf_check -s exit:0 -o inline:'some string\n' -e empty \
+ ${TEST_SH} -c 'X=$( echo some string ); echo "$X"'
+ atf_check -s exit:0 -o inline:'weird; string *\n' -e empty \
+ ${TEST_SH} -c 'X=$( echo "weird; string *" ); echo "$X"'
+
+ rm -f * 2>/dev/null || :
+ for f in file-1 file-2
+ do
+ cp /dev/null "$f"
+ done
+
+ atf_check -s exit:0 -o match:'Found file-1 file-2' -e empty \
+ ${TEST_SH} -c 'echo Found $( echo * )'
+ atf_check -s exit:0 -o match:'Found file-1 file-2' -e empty \
+ ${TEST_SH} -c 'echo Found "$( echo * )"'
+ atf_check -s exit:0 -o match:'Found file-1 file-2' -e empty \
+ ${TEST_SH} -c 'echo Found $('" echo '*' )"
+ atf_check -s exit:0 -o match:'Found \*' -e empty \
+ ${TEST_SH} -c 'echo Found "$('" echo '*' "')"'
+ atf_check -s exit:0 -o match:'Found file-1 file-2' -e empty \
+ ${TEST_SH} -c 'echo Found $('" echo \\* )"
+ atf_check -s exit:0 -o match:'Found \*' -e empty \
+ ${TEST_SH} -c 'echo Found "$('" echo \\* )"\"
+}
+
+atf_test_case b_basic_backticks
+b_basic_backticks_head() {
+ atf_set "descr" 'Test operation of old style ` ` substitutions'
+}
+b_basic_backticks_body() {
+ atf_check -s exit:0 -o match:'Result is true today' -e empty \
+ ${TEST_SH} -c \
+ 'echo Result is `true && echo true || echo false` today'
+
+ atf_check -s exit:0 -o match:'Result is false today' -e empty \
+ ${TEST_SH} -c \
+ 'echo Result is `false && echo true || echo false` today'
+
+ atf_check -s exit:0 -o match:'aaabbbccc' -e empty \
+ ${TEST_SH} -c 'echo aaa` echo bbb `ccc'
+ atf_check -s exit:0 -o match:'aaabbb cccddd' -e empty \
+ ${TEST_SH} -c 'echo aaa` echo bbb ccc `ddd'
+ atf_check -s exit:0 -o inline:'aaabbb cccddd\n' -e empty \
+ ${TEST_SH} -c 'echo aaa` echo bbb; echo ccc `ddd'
+ atf_check -s exit:0 -o inline:'aaabbb\ncccddd\n' -e empty \
+ ${TEST_SH} -c 'echo "aaa` echo bbb; echo ccc `ddd"'
+
+ atf_check -s exit:0 -o inline:'some string\n' -e empty \
+ ${TEST_SH} -c 'X=` echo some string `; echo "$X"'
+ atf_check -s exit:0 -o inline:'weird; string *\n' -e empty \
+ ${TEST_SH} -c 'X=` echo "weird; string *" `; echo "$X"'
+
+ rm -f * 2>/dev/null || :
+ for f in file-1 file-2
+ do
+ cp /dev/null "$f"
+ done
+
+ atf_check -s exit:0 -o match:'Found file-1 file-2' -e empty \
+ ${TEST_SH} -c 'echo Found ` echo * `'
+ atf_check -s exit:0 -o match:'Found file-1 file-2' -e empty \
+ ${TEST_SH} -c 'echo Found "` echo * `"'
+ atf_check -s exit:0 -o match:'Found file-1 file-2' -e empty \
+ ${TEST_SH} -c 'echo Found `'" echo '*' "'`'
+ atf_check -s exit:0 -o match:'Found \*' -e empty \
+ ${TEST_SH} -c 'echo Found "`'" echo '*' "'`"'
+ atf_check -s exit:0 -o match:'Found file-1 file-2' -e empty \
+ ${TEST_SH} -c 'echo Found `'" echo \\* "'`'
+ atf_check -s exit:0 -o match:'Found \*' -e empty \
+ ${TEST_SH} -c 'echo Found "`'" echo \\* "'`"'
+}
+
+atf_test_case c_nested_cmdsub
+c_nested_cmdsub_head() {
+ atf_set "descr" "Test that cmd substitutions can be nested"
+}
+c_nested_cmdsub_body() {
+ atf_check -s exit:0 -o match:'__foobarbletch__' -e empty \
+ ${TEST_SH} -c 'echo __$( echo foo$(echo bar)bletch )__'
+ atf_check -s exit:0 -o match:'_abcde_' -e empty \
+ ${TEST_SH} -c 'echo _$(echo a$(echo $(echo b)c$(echo d))e )_'
+ atf_check -s exit:0 -o match:'123454321' -e empty \
+ ${TEST_SH} -c 'echo 1$(echo 2$(echo 3$(echo 4$(echo 5)4)3)2)1'
+}
+
+atf_test_case d_nested_backticks
+d_nested_backticks_head() {
+ atf_set "descr" "Tests that old style backtick cmd subs can be nested"
+}
+d_nested_backticks_body() {
+ atf_check -s exit:0 -o match:'__foobarbletch__' -e empty \
+ ${TEST_SH} -c 'echo __` echo foo\`echo bar\`bletch `__'
+ atf_check -s exit:0 -o match:'_abcde_' -e empty \
+ ${TEST_SH} -c \
+ 'echo _`echo a\`echo \\\`echo b\\\`c\\\`echo d\\\`\`e `_'
+ atf_check -s exit:0 -o match:'123454321' -e empty \
+ ${TEST_SH} -c \
+ 'echo 1`echo 2\`echo 3\\\`echo 4\\\\\\\`echo 5\\\\\\\`4\\\`3\`2`1'
+}
+
+atf_test_case e_perverse_mixing
+e_perverse_mixing_head() {
+ atf_set "descr" \
+ "Checks various mixed new and old style cmd substitutions"
+}
+e_perverse_mixing_body() {
+ atf_check -s exit:0 -o match:'__foobarbletch__' -e empty \
+ ${TEST_SH} -c 'echo __$( echo foo`echo bar`bletch )__'
+ atf_check -s exit:0 -o match:'__foobarbletch__' -e empty \
+ ${TEST_SH} -c 'echo __` echo foo$(echo bar)bletch `__'
+ atf_check -s exit:0 -o match:'_abcde_' -e empty \
+ ${TEST_SH} -c 'echo _$(echo a`echo $(echo b)c$(echo d)`e )_'
+ atf_check -s exit:0 -o match:'_abcde_' -e empty \
+ ${TEST_SH} -c 'echo _`echo a$(echo \`echo b\`c\`echo d\`)e `_'
+ atf_check -s exit:0 -o match:'12345654321' -e empty \
+ ${TEST_SH} -c \
+ 'echo 1`echo 2$(echo 3\`echo 4\\\`echo 5$(echo 6)5\\\`4\`3)2`1'
+}
+
+atf_test_case f_redirect_in_cmdsub
+f_redirect_in_cmdsub_head() {
+ atf_set "descr" "Checks that redirects work in command substitutions"
+}
+f_redirect_in_cmdsub_body() {
+ atf_require_prog cat
+ atf_require_prog rm
+
+ rm -f file 2>/dev/null || :
+ atf_check -s exit:0 -o match:'_aa_' -e empty \
+ ${TEST_SH} -c 'echo _$( echo a$( echo b > file )a)_'
+ atf_check -s exit:0 -o match:b -e empty ${TEST_SH} -c 'cat file'
+ atf_check -s exit:0 -o match:'_aba_' -e empty \
+ ${TEST_SH} -c 'echo _$( echo a$( cat < file )a)_'
+ atf_check -s exit:0 -o match:'_aa_' -e empty \
+ ${TEST_SH} -c 'echo _$( echo a$( echo d >> file )a)_'
+ atf_check -s exit:0 -o inline:'b\nd\n' -e empty ${TEST_SH} -c 'cat file'
+ atf_check -s exit:0 -o match:'_aa_' -e match:'not error' \
+ ${TEST_SH} -c 'echo _$( echo a$( echo not error >&2 )a)_'
+}
+
+atf_test_case g_redirect_in_backticks
+g_redirect_in_backticks_head() {
+ atf_set "descr" "Checks that redirects work in old style cmd sub"
+}
+g_redirect_in_backticks_body() {
+ atf_require_prog cat
+ atf_require_prog rm
+
+ rm -f file 2>/dev/null || :
+ atf_check -s exit:0 -o match:'_aa_' -e empty \
+ ${TEST_SH} -c 'echo _` echo a\` echo b > file \`a`_'
+ atf_check -s exit:0 -o match:b -e empty ${TEST_SH} -c 'cat file'
+ atf_check -s exit:0 -o match:'_aba_' -e empty \
+ ${TEST_SH} -c 'echo _` echo a\` cat < file \`a`_'
+ atf_check -s exit:0 -o match:'_aa_' -e empty \
+ ${TEST_SH} -c 'echo _` echo a\` echo d >> file \`a`_'
+ atf_check -s exit:0 -o inline:'b\nd\n' -e empty ${TEST_SH} -c 'cat file'
+ atf_check -s exit:0 -o match:'_aa_' -e match:'not error' \
+ ${TEST_SH} -c 'echo _` echo a\` echo not error >&2 \`a`_'
+}
+
+atf_test_case h_vars_in_cmdsub
+h_vars_in_cmdsub_head() {
+ atf_set "descr" "Check that variables work in command substitutions"
+}
+h_vars_in_cmdsub_body() {
+ atf_check -s exit:0 -o match:'__abc__' -e empty \
+ ${TEST_SH} -c 'X=abc; echo __$( echo ${X} )__'
+ atf_check -s exit:0 -o match:'__abc__' -e empty \
+ ${TEST_SH} -c 'X=abc; echo __$( echo "${X}" )__'
+ atf_check -s exit:0 -o match:'__abc__' -e empty \
+ ${TEST_SH} -c 'X=abc; echo "__$( echo ${X} )__"'
+ atf_check -s exit:0 -o match:'__abc__' -e empty \
+ ${TEST_SH} -c 'X=abc; echo "__$( echo "${X}" )__"'
+
+ atf_check -s exit:0 -o inline:'a\n\nb\n\nc\n' -e empty \
+ ${TEST_SH} -c "for X in a '' b '' c"'; do echo $( echo "$X" ); done'
+
+ atf_check -s exit:0 -o match:'__acd__' -e empty \
+ ${TEST_SH} -c 'X=; unset Y; echo "__$( echo a${X-b}${Y-c}d)__"'
+ atf_check -s exit:0 -o match:'__abcd__' -e empty \
+ ${TEST_SH} -c 'X=; unset Y; echo "__$( echo a${X:-b}${Y:-c}d)__"'
+ atf_check -s exit:0 -o match:'__XYX__' -e empty \
+ ${TEST_SH} -c 'X=X; echo "__${X}$( X=Y; echo ${X} )${X}__"'
+ atf_check -s exit:0 -o match:'__def__' -e empty \
+ ${TEST_SH} -c 'X=abc; echo "__$(X=def; echo "${X}" )__"'
+ atf_check -s exit:0 -o inline:'abcdef\nabc\n' -e empty \
+ ${TEST_SH} -c 'X=abc; echo "$X$(X=def; echo ${X} )"; echo $X'
+}
+
+atf_test_case i_vars_in_backticks
+i_vars_in_backticks_head() {
+ atf_set "descr" "Checks that variables work in old style cmd sub"
+}
+i_vars_in_backticks_body() {
+ atf_check -s exit:0 -o match:'__abc__' -e empty \
+ ${TEST_SH} -c 'X=abc; echo __` echo ${X} `__'
+ atf_check -s exit:0 -o match:'__abc__' -e empty \
+ ${TEST_SH} -c 'X=abc; echo __` echo "${X}" `__'
+ atf_check -s exit:0 -o match:'__abc__' -e empty \
+ ${TEST_SH} -c 'X=abc; echo "__` echo ${X} `__"'
+ atf_check -s exit:0 -o match:'__abc__' -e empty \
+ ${TEST_SH} -c 'X=abc; echo "__` echo \"${X}\" `__"'
+
+ atf_check -s exit:0 -o inline:'a\n\nb\n\nc\n' -e empty \
+ ${TEST_SH} -c "for X in a '' b '' c"'; do echo $( echo "$X" ); done'
+
+ atf_check -s exit:0 -o match:'__acd__' -e empty \
+ ${TEST_SH} -c 'X=; unset Y; echo "__$( echo a${X-b}${Y-c}d)__"'
+ atf_check -s exit:0 -o match:'__abcd__' -e empty \
+ ${TEST_SH} -c 'X=; unset Y; echo "__$( echo a${X:-b}${Y:-c}d)__"'
+ atf_check -s exit:0 -o match:'__XYX__' -e empty \
+ ${TEST_SH} -c 'X=X; echo "__${X}$( X=Y; echo ${X} )${X}__"'
+ atf_check -s exit:0 -o inline:'abcdef\nabc\n' -e empty \
+ ${TEST_SH} -c 'X=abc; echo "$X`X=def; echo \"${X}\" `";echo $X'
+
+ # The following is nonsense, so is not included ...
+ # atf_check -s exit:0 -o match:'__abc__' -e empty \
+ # oV cV oV cV
+ # ${TEST_SH} -c 'X=abc; echo "__`X=def echo "${X}" `__"'
+ # `start in " ^ " ends, ` not yet
+}
+
+atf_test_case j_cmdsub_in_varexpand
+j_cmdsub_in_varexpand_head() {
+ atf_set "descr" "Checks that command sub can be used in var expansion"
+}
+j_cmdsub_in_varexpand_body() {
+ atf_check -s exit:0 -o match:'foo' -e empty \
+ ${TEST_SH} -c 'X=set; echo ${X+$(echo foo)}'
+ atf_check -s exit:0 -o match:'set' -e empty \
+ ${TEST_SH} -c 'X=set; echo ${X-$(echo foo)}'
+ rm -f bar 2>/dev/null || :
+ atf_check -s exit:0 -o match:'set' -e empty \
+ ${TEST_SH} -c 'X=set; echo ${X-$(echo foo > bar)}'
+ test -f bar && atf_fail "bar should not exist, but does"
+ atf_check -s exit:0 -o inline:'\n' -e empty \
+ ${TEST_SH} -c 'X=set; echo ${X+$(echo foo > bar)}'
+ test -f bar || atf_fail "bar should exist, but does not"
+}
+
+atf_test_case k_backticks_in_varexpand
+k_backticks_in_varexpand_head() {
+ atf_set "descr" "Checks that old style cmd sub works in var expansion"
+}
+k_backticks_in_varexpand_body() {
+ atf_check -s exit:0 -o match:'foo' -e empty \
+ ${TEST_SH} -c 'X=set; echo ${X+`echo foo`}'
+ atf_check -s exit:0 -o match:'set' -e empty \
+ ${TEST_SH} -c 'X=set; echo ${X-`echo foo`}'
+ rm -f bar 2>/dev/null || :
+ atf_check -s exit:0 -o match:'set' -e empty \
+ ${TEST_SH} -c 'X=set; echo ${X-`echo foo > bar`}'
+ test -f bar && atf_fail "bar should not exist, but does"
+ atf_check -s exit:0 -o inline:'\n' -e empty \
+ ${TEST_SH} -c 'X=set; echo ${X+`echo foo > bar`}'
+ test -f bar || atf_fail "bar should exist, but does not"
+}
+
+atf_test_case l_arithmetic_in_cmdsub
+l_arithmetic_in_cmdsub_head() {
+ atf_set "descr" "Checks that arithmetic works in cmd substitutions"
+}
+l_arithmetic_in_cmdsub_body() {
+ atf_check -s exit:0 -o inline:'1 + 1 = 2\n' -e empty \
+ ${TEST_SH} -c 'echo 1 + 1 = $( echo $(( 1 + 1 )) )'
+ atf_check -s exit:0 -o inline:'X * Y = 6\n' -e empty \
+ ${TEST_SH} -c 'X=2; Y=3; echo X \* Y = $( echo $(( X * Y )) )'
+ atf_check -s exit:0 -o inline:'Y % X = 1\n' -e empty \
+ ${TEST_SH} -c 'X=2; Y=3; echo Y % X = $( echo $(( $Y % $X )) )'
+}
+
+atf_test_case m_arithmetic_in_backticks
+m_arithmetic_in_backticks_head() {
+ atf_set "descr" "Checks that arithmetic works in old style cmd sub"
+}
+m_arithmetic_in_backticks_body() {
+ atf_check -s exit:0 -o inline:'2 + 3 = 5\n' -e empty \
+ ${TEST_SH} -c 'echo 2 + 3 = ` echo $(( 2 + 3 )) `'
+ atf_check -s exit:0 -o inline:'X * Y = 6\n' -e empty \
+ ${TEST_SH} -c 'X=2; Y=3; echo X \* Y = ` echo $(( X * Y )) `'
+ atf_check -s exit:0 -o inline:'Y % X = 1\n' -e empty \
+ ${TEST_SH} -c 'X=2; Y=3; echo Y % X = ` echo $(( $Y % $X )) `'
+}
+
+atf_test_case n_cmdsub_in_arithmetic
+n_cmdsub_in_arithmetic_head() {
+ atf_set "descr" "Tests uses of command substitutions in arithmetic"
+}
+n_cmdsub_in_arithmetic_body() {
+ atf_check -s exit:0 -o inline:'7\n' -e empty \
+ ${TEST_SH} -c 'echo $(( $( echo 3 ) $( echo + ) $( echo 4 ) ))'
+ atf_check -s exit:0 -o inline:'11\n7\n18\n4\n1\n' -e empty \
+ ${TEST_SH} -c \
+ 'for op in + - \* / %
+ do
+ echo $(( $( echo 9 ) $( echo "${op}" ) $( echo 2 ) ))
+ done'
+}
+
+atf_test_case o_backticks_in_arithmetic
+o_backticks_in_arithmetic_head() {
+ atf_set "descr" "Tests old style cmd sub used in arithmetic"
+}
+o_backticks_in_arithmetic_body() {
+ atf_check -s exit:0 -o inline:'33\n' -e empty \
+ ${TEST_SH} -c 'echo $(( `echo 77` `echo -` `echo 44`))'
+ atf_check -s exit:0 -o inline:'14\n8\n33\n3\n2\n' -e empty \
+ ${TEST_SH} -c \
+ 'for op in + - \* / %
+ do
+ echo $((`echo 11``echo "${op}"``echo 3`))
+ done'
+}
+
+atf_test_case p_cmdsub_in_heredoc
+p_cmdsub_in_heredoc_head() {
+ atf_set "descr" "Checks that cmdsubs work inside a here document"
+}
+p_cmdsub_in_heredoc_body() {
+ atf_require_prog cat
+
+ atf_check -s exit:0 -o inline:'line 1+1\nline 2\nline 3\n' -e empty \
+ ${TEST_SH} -c \
+ 'cat <<- EOF
+ $( echo line 1 )$( echo +1 )
+ $( echo line 2;echo line 3 )
+ EOF'
+}
+
+atf_test_case q_backticks_in_heredoc
+q_backticks_in_heredoc_head() {
+ atf_set "descr" "Checks that old style cmdsubs work in here docs"
+}
+q_backticks_in_heredoc_body() {
+ atf_require_prog cat
+
+ atf_check -s exit:0 -o inline:'Mary had a\nlittle\nlamb\n' -e empty \
+ ${TEST_SH} -c \
+ 'cat <<- EOF
+ `echo Mary ` `echo had a `
+ ` echo little; echo lamb `
+ EOF'
+}
+
+atf_test_case r_heredoc_in_cmdsub
+r_heredoc_in_cmdsub_head() {
+ atf_set "descr" "Checks that here docs work inside cmd subs"
+}
+r_heredoc_in_cmdsub_body() {
+ atf_require_prog cat
+
+ atf_check -s exit:0 -o inline:'Mary had a\nlittle\nlamb\n' -e empty \
+ ${TEST_SH} -c 'echo "$( cat <<- \EOF
+ Mary had a
+ little
+ lamb
+ EOF
+ )"'
+
+ atf_check -s exit:0 -e empty \
+ -o inline:'Mary had 1\nlittle\nlamb\nMary had 4\nlittle\nlambs\n' \
+ ${TEST_SH} -c 'for N in 1 4; do echo "$( cat <<- EOF
+ Mary had ${N}
+ little
+ lamb$( [ $N -gt 1 ] && echo s )
+ EOF
+ )"; done'
+
+
+ atf_check -s exit:0 -o inline:'A Calculation:\n2 * 7 = 14\n' -e empty \
+ ${TEST_SH} -c 'echo "$( cat <<- EOF
+ A Calculation:
+ 2 * 7 = $(( 2 * 7 ))
+ EOF
+ )"'
+}
+
+atf_test_case s_heredoc_in_backticks
+s_heredoc_in_backticks_head() {
+ atf_set "descr" "Checks that here docs work inside old style cmd subs"
+}
+s_heredoc_in_backticks_body() {
+ atf_require_prog cat
+
+ atf_check -s exit:0 -o inline:'Mary had a little lamb\n' -e empty \
+ ${TEST_SH} -c 'echo ` cat <<- \EOF
+ Mary had a
+ little
+ lamb
+ EOF
+ `'
+
+ atf_check -s exit:0 -o inline:'A Calculation:\n17 / 3 = 5\n' -e empty \
+ ${TEST_SH} -c 'echo "` cat <<- EOF
+ A Calculation:
+ 17 / 3 = $(( 17 / 3 ))
+ EOF
+ `"'
+}
+
+atf_test_case t_nested_cmdsubs_in_heredoc
+t_nested_cmdsubs_in_heredoc_head() {
+ atf_set "descr" "Checks nested command substitutions in here docs"
+}
+t_nested_cmdsubs_in_heredoc_body() {
+ atf_require_prog cat
+ atf_require_prog rm
+
+ rm -f * 2>/dev/null || :
+ echo "Hello" > File
+
+ atf_check -s exit:0 -o inline:'Hello U\nHelp me!\n' -e empty \
+ ${TEST_SH} -c 'cat <<- EOF
+ $(cat File) U
+ $( V=$(cat File); echo "${V%lo}p" ) me!
+ EOF'
+
+ rm -f * 2>/dev/null || :
+ echo V>V ; echo A>A; echo R>R
+ echo Value>VAR
+
+ atf_check -s exit:0 -o inline:'$2.50\n' -e empty \
+ ${TEST_SH} -c 'cat <<- EOF
+ $(Value='\''$2.50'\'';eval echo $(eval $(cat V)$(cat A)$(cat R)=\'\''\$$(cat $(cat V)$(cat A)$(cat R))\'\''; eval echo \$$(set -- *;echo ${3}${1}${2})))
+ EOF'
+}
+
+atf_test_case u_nested_backticks_in_heredoc
+u_nested_backticks_in_heredoc_head() {
+ atf_set "descr" "Checks nested old style cmd subs in here docs"
+}
+u_nested_backticks_in_heredoc_body() {
+ atf_require_prog cat
+ atf_require_prog rm
+
+ rm -f * 2>/dev/null || :
+ echo "Hello" > File
+
+ atf_check -s exit:0 -o inline:'Hello U\nHelp me!\n' -e empty \
+ ${TEST_SH} -c 'cat <<- EOF
+ `cat File` U
+ `V=\`cat File\`; echo "${V%lo}p" ` me!
+ EOF'
+
+ rm -f * 2>/dev/null || :
+ echo V>V ; echo A>A; echo R>R
+ echo Value>VAR
+
+ atf_check -s exit:0 -o inline:'$5.20\n' -e empty \
+ ${TEST_SH} -c 'cat <<- EOF
+ `Value='\''$5.20'\'';eval echo \`eval \\\`cat V\\\`\\\`cat A\\\`\\\`cat R\\\`=\\\'\''\\\$\\\`cat \\\\\\\`cat V\\\\\\\`\\\\\\\`cat A\\\\\\\`\\\\\\\`cat R\\\\\\\`\\\`\\\'\''; eval echo \\\$\\\`set -- *;echo \\\\\${3}\\\\\${1}\\\\\${2}\\\`\``
+ EOF'
+}
+
+atf_test_case v_cmdsub_paren_tests
+v_cmdsub__paren_tests_head() {
+ atf_set "descr" "tests with cmdsubs containing embedded ')'"
+}
+v_cmdsub_paren_tests_body() {
+
+ # Tests from:
+ # http://www.in-ulm.de/~mascheck/various/cmd-subst/
+ # (slightly modified.)
+
+ atf_check -s exit:0 -o inline:'A.1\n' -e empty ${TEST_SH} -c \
+ 'echo $(
+ case x in x) echo A.1;; esac
+ )'
+
+ atf_check -s exit:0 -o inline:'A.2\n' -e empty ${TEST_SH} -c \
+ 'echo $(
+ case x in x) echo A.2;; esac # comment
+ )'
+
+ atf_check -s exit:0 -o inline:'A.3\n' -e empty ${TEST_SH} -c \
+ 'echo $(
+ case x in (x) echo A.3;; esac
+ )'
+
+ atf_check -s exit:0 -o inline:'A.4\n' -e empty ${TEST_SH} -c \
+ 'echo $(
+ case x in (x) echo A.4;; esac # comment
+ )'
+
+ atf_check -s exit:0 -o inline:'A.5\n' -e empty ${TEST_SH} -c \
+ 'echo $(
+ case x in (x) echo A.5
+ esac
+ )'
+
+ atf_check -s exit:0 -o inline:'B: quoted )\n' -e empty ${TEST_SH} -c \
+ 'echo $(
+ echo '\''B: quoted )'\''
+ )'
+
+ atf_check -s exit:0 -o inline:'C: comment then closing paren\n' \
+ -e empty ${TEST_SH} -c \
+ 'echo $(
+ echo C: comment then closing paren # )
+ )'
+
+ atf_check -s exit:0 -o inline:'D.1: here-doc with )\n' \
+ -e empty ${TEST_SH} -c \
+ 'echo $(
+ cat <<-\eof
+ D.1: here-doc with )
+ eof
+ )'
+
+ # D.2 is a bogus test.
+
+ atf_check -s exit:0 -o inline:'D.3: here-doc with \()\n' \
+ -e empty ${TEST_SH} -c \
+ 'echo $(
+ cat <<-\eof
+ D.3: here-doc with \()
+ eof
+ )'
+
+ atf_check -s exit:0 -e empty \
+ -o inline:'E: here-doc terminated with a parenthesis ("academic")\n' \
+ ${TEST_SH} -c \
+ 'echo $(
+ cat <<-\)
+ E: here-doc terminated with a parenthesis ("academic")
+ )
+ )'
+
+ atf_check -s exit:0 -e empty \
+-o inline:'F.1: here-doc embed with unbal single, back- or doublequote '\''\n' \
+ ${TEST_SH} -c \
+ 'echo $(
+ cat <<-"eof"
+ F.1: here-doc embed with unbal single, back- or doublequote '\''
+ eof
+ )'
+ atf_check -s exit:0 -e empty \
+ -o inline:'F.2: here-doc embed with unbal single, back- or doublequote "\n' \
+ ${TEST_SH} -c \
+ 'echo $(
+ cat <<-"eof"
+ F.2: here-doc embed with unbal single, back- or doublequote "
+ eof
+ )'
+ atf_check -s exit:0 -e empty \
+ -o inline:'F.3: here-doc embed with unbal single, back- or doublequote `\n' \
+ ${TEST_SH} -c \
+ 'echo $(
+ cat <<-"eof"
+ F.3: here-doc embed with unbal single, back- or doublequote `
+ eof
+ )'
+
+ atf_check -s exit:0 -e empty -o inline:'G: backslash at end of line\n' \
+ ${TEST_SH} -c \
+ 'echo $(
+ echo G: backslash at end of line # \
+ )'
+
+ atf_check -s exit:0 -e empty \
+ -o inline:'H: empty command-substitution\n' \
+ ${TEST_SH} -c 'echo H: empty command-substitution $( )'
+}
+
+atf_test_case w_heredoc_outside_cmdsub
+w_heredoc_outside_cmdsub_head() {
+ atf_set "descr" "Checks that here docs work inside cmd subs"
+}
+w_heredoc_outside_cmdsub_body() {
+ atf_require_prog cat
+
+ atf_check -s exit:0 -o inline:'Mary had a\nlittle\nlamb\n' -e empty \
+ ${TEST_SH} -c 'echo "$( cat <<- \EOF )"
+ Mary had a
+ little
+ lamb
+ EOF
+ '
+
+ atf_check -s exit:0 -e empty \
+ -o inline:'Mary had 1\nlittle\nlamb\nMary had 4\nlittle\nlambs\n' \
+ ${TEST_SH} -c 'for N in 1 4; do echo "$( cat <<- EOF )"
+ Mary had ${N}
+ little
+ lamb$( [ $N -gt 1 ] && echo s )
+ EOF
+ done'
+
+
+ atf_check -s exit:0 -o inline:'A Calculation:\n2 * 7 = 14\n' -e empty \
+ ${TEST_SH} -c 'echo "$( cat <<- EOF)"
+ A Calculation:
+ 2 * 7 = $(( 2 * 7 ))
+ EOF
+ '
+}
+
+atf_test_case x_heredoc_outside_backticks
+x_heredoc_outside_backticks_head() {
+ atf_set "descr" "Checks that here docs work inside old style cmd subs"
+}
+x_heredoc_outside_backticks_body() {
+ atf_require_prog cat
+
+ atf_check -s exit:0 -o inline:'Mary had a little lamb\n' -e empty \
+ ${TEST_SH} -c 'echo ` cat <<- \EOF `
+ Mary had a
+ little
+ lamb
+ EOF
+ '
+
+ atf_check -s exit:0 -o inline:'A Calculation:\n17 / 3 = 5\n' -e empty \
+ ${TEST_SH} -c 'echo "` cat <<- EOF `"
+ A Calculation:
+ 17 / 3 = $(( 17 / 3 ))
+ EOF
+ '
+}
+
+atf_test_case t_nested_cmdsubs_in_heredoc
+t_nested_cmdsubs_in_heredoc_head() {
+ atf_set "descr" "Checks nested command substitutions in here docs"
+}
+t_nested_cmdsubs_in_heredoc_body() {
+ atf_require_prog cat
+ atf_require_prog rm
+
+ rm -f * 2>/dev/null || :
+ echo "Hello" > File
+
+ atf_check -s exit:0 -o inline:'Hello U\nHelp me!\n' -e empty \
+ ${TEST_SH} -c 'cat <<- EOF
+ $(cat File) U
+ $( V=$(cat File); echo "${V%lo}p" ) me!
+ EOF'
+
+ rm -f * 2>/dev/null || :
+ echo V>V ; echo A>A; echo R>R
+ echo Value>VAR
+
+ atf_check -s exit:0 -o inline:'$2.50\n' -e empty \
+ ${TEST_SH} -c 'cat <<- EOF
+ $(Value='\''$2.50'\'';eval echo $(eval $(cat V)$(cat A)$(cat R)=\'\''\$$(cat $(cat V)$(cat A)$(cat R))\'\''; eval echo \$$(set -- *;echo ${3}${1}${2})))
+ EOF'
+}
+
+atf_test_case z_absurd_heredoc_cmdsub_combos
+z_absurd_heredoc_cmdsub_combos_head() {
+ atf_set "descr" "perverse and unusual cmd substitutions & more"
+}
+z_absurd_heredoc_cmdsub_combos_body() {
+
+ echo "Help!" > help
+
+ # This version works in NetBSD (& FreeBSD)'s sh (and most others)
+ atf_check -s exit:0 -o inline:'Help!\nMe 2\n' -e empty ${TEST_SH} -c '
+ cat <<- EOF
+ $(
+ cat <<- STOP
+ $(
+ cat `echo help`
+ )
+ STOP
+ )
+ $(
+ cat <<- END 4<<-TRASH
+ Me $(( 1 + 1 ))
+ END
+ This is unused noise!
+ TRASH
+ )
+ EOF
+ '
+
+ # atf_expect_fail "PR bin/50993 - heredoc parsing done incorrectly"
+ atf_check -s exit:0 -o inline:'Help!\nMe 2\n' -e empty ${TEST_SH} -c '
+ cat <<- EOF
+ $(
+ cat << STOP
+ $(
+ cat `echo help`
+ )
+ STOP
+ )
+ $(
+ cat <<- END 4<<TRASH
+ Me $(( 1 + 1 ))
+ END
+ This is unused noise!
+ TRASH
+ )
+ EOF
+ '
+}
+
+atf_init_test_cases() {
+ atf_add_test_case a_basic_cmdsub
+ atf_add_test_case b_basic_backticks
+ atf_add_test_case c_nested_cmdsub
+ atf_add_test_case d_nested_backticks
+ atf_add_test_case e_perverse_mixing
+ atf_add_test_case f_redirect_in_cmdsub
+ atf_add_test_case g_redirect_in_backticks
+ atf_add_test_case h_vars_in_cmdsub
+ atf_add_test_case i_vars_in_backticks
+ atf_add_test_case j_cmdsub_in_varexpand
+ atf_add_test_case k_backticks_in_varexpand
+ atf_add_test_case l_arithmetic_in_cmdsub
+ atf_add_test_case m_arithmetic_in_backticks
+ atf_add_test_case n_cmdsub_in_arithmetic
+ atf_add_test_case o_backticks_in_arithmetic
+ atf_add_test_case p_cmdsub_in_heredoc
+ atf_add_test_case q_backticks_in_heredoc
+ atf_add_test_case r_heredoc_in_cmdsub
+ atf_add_test_case s_heredoc_in_backticks
+ atf_add_test_case t_nested_cmdsubs_in_heredoc
+ atf_add_test_case u_nested_backticks_in_heredoc
+ atf_add_test_case v_cmdsub_paren_tests
+ atf_add_test_case w_heredoc_outside_cmdsub
+ atf_add_test_case x_heredoc_outside_backticks
+ atf_add_test_case z_absurd_heredoc_cmdsub_combos
+}
diff --git a/contrib/netbsd-tests/bin/sh/t_compexit.sh b/contrib/netbsd-tests/bin/sh/t_compexit.sh
deleted file mode 100755
index 019b740..0000000
--- a/contrib/netbsd-tests/bin/sh/t_compexit.sh
+++ /dev/null
@@ -1,63 +0,0 @@
-# $NetBSD: t_compexit.sh,v 1.1 2012/03/17 16:33:11 jruoho Exp $
-#
-# Copyright (c) 2007 The NetBSD Foundation, Inc.
-# 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
-#
-
-# The standard
-# http://www.opengroup.org/onlinepubs/007904975/utilities/set.html
-# says:
-#
-# -e
-#
-# When this option is on, if a simple command fails for any of the
-# reasons listed in Consequences of Shell Errors or returns an exit
-# status value >0, and is not part of the compound list following a
-# while, until, or if keyword, and is not a part of an AND or OR list,
-# and is not a pipeline preceded by the ! reserved word, then the shell
-# shall immediately exit.
-
-crud() {
- set -e
- for x in a
- do
- BAR="foo"
- false && echo true
- echo mumble
- done
-}
-
-atf_test_case set_e
-set_e_head() {
- atf_set "descr" "Tests that 'set -e' turns on error detection" \
- "and that it behaves as defined by the standard"
-}
-set_e_body() {
- foo=`crud`
- atf_check_equal 'x$foo' 'xmumble'
-}
-
-atf_init_test_cases() {
- atf_add_test_case set_e
-}
diff --git a/contrib/netbsd-tests/bin/sh/t_evaltested.sh b/contrib/netbsd-tests/bin/sh/t_evaltested.sh
index e40f8bd..128a55c 100755
--- a/contrib/netbsd-tests/bin/sh/t_evaltested.sh
+++ b/contrib/netbsd-tests/bin/sh/t_evaltested.sh
@@ -1,4 +1,4 @@
-# $NetBSD: t_evaltested.sh,v 1.1 2012/03/17 16:33:11 jruoho Exp $
+# $NetBSD: t_evaltested.sh,v 1.2 2016/03/27 14:50:01 christos Exp $
#
# Copyright (c) 2011 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"}
atf_test_case evaltested
@@ -43,7 +45,7 @@ fi
echo "passed"
exit 0
EOF
- output="$(/bin/sh helper.sh)"
+ output="$($TEST_SH helper.sh)"
[ $? = 0 ] && return
if [ -n "$output" ]
diff --git a/contrib/netbsd-tests/bin/sh/t_exit.sh b/contrib/netbsd-tests/bin/sh/t_exit.sh
index 62c5869..17ed230 100755
--- a/contrib/netbsd-tests/bin/sh/t_exit.sh
+++ b/contrib/netbsd-tests/bin/sh/t_exit.sh
@@ -1,4 +1,4 @@
-# $NetBSD: t_exit.sh,v 1.3 2012/04/13 06:12:32 jruoho Exp $
+# $NetBSD: t_exit.sh,v 1.6 2016/05/07 23:51:30 kre Exp $
#
# Copyright (c) 2007 The NetBSD Foundation, Inc.
# All rights reserved.
@@ -24,74 +24,124 @@
# 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"}
-crud() {
- test yes = no
-
- cat <<EOF
-$?
-EOF
-}
atf_test_case background
background_head() {
atf_set "descr" "Tests that sh(1) sets '$?' properly when running " \
- "a command in the background (PR bin/46327)"
+ "a command in the background (PR bin/46327)"
}
background_body() {
- atf_check -s exit:0 -o ignore -e ignore -x "true; true & echo $?"
- atf_check -s exit:0 -o ignore -e ignore -x "false; true & echo $?"
+ atf_check -o match:0 -e empty ${TEST_SH} -c 'true; true & echo $?'
+ # atf_expect_fail "PR bin/46327" (now fixed?)
+ atf_check -o match:0 -e empty ${TEST_SH} -c 'false; true & echo $?'
}
atf_test_case function
function_head() {
- atf_set "descr" "Tests that \$? is correctly updated inside" \
- "a function"
+ atf_set "descr" "Tests that \$? is correctly updated inside " \
+ "a function"
}
function_body() {
- foo=`crud`
- atf_check_equal 'x$foo' 'x1'
+ atf_check -s exit:0 -o match:STATUS=1-0 -e empty \
+ ${TEST_SH} -c '
+ crud() {
+ test yes = no
+
+ cat <<-EOF
+ STATUS=$?
+ EOF
+ }
+ foo=$(crud)
+ echo "${foo}-$?"
+ '
}
atf_test_case readout
readout_head() {
- atf_set "descr" "Tests that \$? is correctly updated in a" \
- "compound expression"
+ atf_set "descr" "Tests that \$? is correctly updated in a " \
+ "compound expression"
}
readout_body() {
- atf_check_equal '$( true && ! true | false; echo $? )' '0'
+ atf_check -s exit:0 -o match:0 -e empty \
+ ${TEST_SH} -c 'true && ! true | false; echo $?'
}
atf_test_case trap_subshell
trap_subshell_head() {
- atf_set "descr" "Tests that the trap statement in a subshell" \
- "works when the subshell exits"
+ atf_set "descr" "Tests that the trap statement in a subshell " \
+ "works when the subshell exits"
}
trap_subshell_body() {
- atf_check -s eq:0 -o inline:'exiting\n' -x \
- '( trap "echo exiting" EXIT; /usr/bin/true )'
+ atf_check -s exit:0 -o inline:'exiting\n' -e empty \
+ ${TEST_SH} -c '( trap "echo exiting" EXIT; /usr/bin/true )'
}
atf_test_case trap_zero__implicit_exit
+trap_zero__implicit_exit_head() {
+ atf_set "descr" "Tests that the trap statement in a subshell in a " \
+ "script works when the subshell simply runs out of commands"
+}
trap_zero__implicit_exit_body() {
- # PR bin/6764: sh works but ksh does not"
+ # PR bin/6764: sh works but ksh does not
echo '( trap "echo exiting" 0 )' >helper.sh
- atf_check -s eq:0 -o match:exiting -e empty /bin/sh helper.sh
- atf_check -s eq:0 -o match:exiting -e empty /bin/ksh helper.sh
+ atf_check -s exit:0 -o match:exiting -e empty ${TEST_SH} helper.sh
+ # test ksh by setting TEST_SH to /bin/ksh and run the entire set...
+ # atf_check -s exit:0 -o match:exiting -e empty /bin/ksh helper.sh
}
atf_test_case trap_zero__explicit_exit
+trap_zero__explicit_exit_head() {
+ atf_set "descr" "Tests that the trap statement in a subshell in a " \
+ "script works when the subshell executes an explicit exit"
+}
trap_zero__explicit_exit_body() {
- echo '( trap "echo exiting" 0; exit )' >helper.sh
- atf_check -s eq:0 -o match:exiting -e empty /bin/sh helper.sh
- atf_check -s eq:0 -o match:exiting -e empty /bin/ksh helper.sh
+ echo '( trap "echo exiting" 0; exit; echo NO_NO_NO )' >helper.sh
+ atf_check -s exit:0 -o match:exiting -o not-match:NO_NO -e empty \
+ ${TEST_SH} helper.sh
+ # test ksh by setting TEST_SH to /bin/ksh and run the entire set...
+ # atf_check -s exit:0 -o match:exiting -e empty /bin/ksh helper.sh
}
-atf_test_case trap_zero__explicit_return
-trap_zero__explicit_return_body() {
- echo '( trap "echo exiting" 0; return )' >helper.sh
- atf_check -s eq:0 -o match:exiting -e empty /bin/sh helper.sh
- atf_check -s eq:0 -o match:exiting -e empty /bin/ksh helper.sh
+atf_test_case simple_exit
+simple_exit_head() {
+ atf_set "descr" "Tests that various values for exit status work"
+}
+# Note: ATF will not allow tests of exit values > 255, even if they would work
+simple_exit_body() {
+ for N in 0 1 2 3 4 5 6 42 99 101 125 126 127 128 129 200 254 255
+ do
+ atf_check -s exit:$N -o empty -e empty \
+ ${TEST_SH} -c "exit $N; echo FOO; echo BAR >&2"
+ done
+}
+
+atf_test_case subshell_exit
+subshell_exit_head() {
+ atf_set "descr" "Tests that subshell exit status works and \$? gets it"
+}
+# Note: ATF will not allow tests of exit values > 255, even if they would work
+subshell_exit_body() {
+ for N in 0 1 2 3 4 5 6 42 99 101 125 126 127 128 129 200 254 255
+ do
+ atf_check -s exit:0 -o empty -e empty \
+ ${TEST_SH} -c "(exit $N); test \$? -eq $N"
+ done
+}
+
+atf_test_case subshell_background
+subshell_background_head() {
+ atf_set "descr" "Tests that sh(1) sets '$?' properly when running " \
+ "a subshell in the background"
+}
+subshell_background_body() {
+ atf_check -o match:0 -e empty \
+ ${TEST_SH} -c 'true; (false || true) & echo $?'
+ # atf_expect_fail "PR bin/46327" (now fixed?)
+ atf_check -o match:0 -e empty \
+ ${TEST_SH} -c 'false; (false || true) & echo $?'
}
atf_init_test_cases() {
@@ -101,5 +151,7 @@ atf_init_test_cases() {
atf_add_test_case trap_subshell
atf_add_test_case trap_zero__implicit_exit
atf_add_test_case trap_zero__explicit_exit
- atf_add_test_case trap_zero__explicit_return
+ atf_add_test_case simple_exit
+ atf_add_test_case subshell_exit
+ atf_add_test_case subshell_background
}
diff --git a/contrib/netbsd-tests/bin/sh/t_expand.sh b/contrib/netbsd-tests/bin/sh/t_expand.sh
index eeaad5f..e785e1f 100755
--- a/contrib/netbsd-tests/bin/sh/t_expand.sh
+++ b/contrib/netbsd-tests/bin/sh/t_expand.sh
@@ -1,4 +1,4 @@
-# $NetBSD: t_expand.sh,v 1.2 2013/10/06 21:05:50 ast Exp $
+# $NetBSD: t_expand.sh,v 1.8 2016/04/29 18:29:17 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'
+ atf_check -s exit:0 -o inline:' EOL\n' -e empty \
+ ${TEST_SH} -c 'set -- "" ""; echo "$@" | '" sed 's,\$,EOL,'"
- set -- -
- shift
- n_arg() { echo $#; }
- n_args=`n_arg "$@"`
- atf_check_equal '0' '$n_args'
+ 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,15 +69,61 @@ 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
@@ -91,8 +135,25 @@ strip_head() {
strip_body() {
line='#define bindir "/usr/bin" /* comment */'
stripped='#define bindir "/usr/bin" '
- atf_expect_fail "PR bin/43469"
- 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
@@ -103,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
@@ -114,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
@@ -126,10 +192,178 @@ 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'
+}
+
+nl='
+'
+reset()
+{
+ TEST_NUM=0
+ TEST_FAILURES=''
+ TEST_FAIL_COUNT=0
+ TEST_ID="$1"
+}
+
+check()
+{
+ fail=false
+ TEMP_FILE=$( mktemp OUT.XXXXXX )
+ TEST_NUM=$(( $TEST_NUM + 1 ))
+ MSG=
+
+ # our local shell (ATF_SHELL) better do quoting correctly...
+ # some of the tests expect us to expand $nl internally...
+ CMD="$1"
+
+ result="$( ${TEST_SH} -c "${CMD}" 2>"${TEMP_FILE}" )"
+ STATUS=$?
+
+ if [ "${STATUS}" -ne "$3" ]; then
+ MSG="${MSG}${MSG:+${nl}}[$TEST_NUM]"
+ MSG="${MSG} expected exit code $3, got ${STATUS}"
+
+ # don't actually fail just because of wrong exit code
+ # unless we either expected, or received "good"
+ case "$3/${STATUS}" in
+ (*/0|0/*) fail=true;;
+ esac
+ fi
+
+ if [ "$3" -eq 0 ]; then
+ if [ -s "${TEMP_FILE}" ]; then
+ MSG="${MSG}${MSG:+${nl}}[$TEST_NUM]"
+ MSG="${MSG} Messages produced on stderr unexpected..."
+ MSG="${MSG}${nl}$( cat "${TEMP_FILE}" )"
+ fail=true
+ fi
+ else
+ if ! [ -s "${TEMP_FILE}" ]; then
+ MSG="${MSG}${MSG:+${nl}}[$TEST_NUM]"
+ MSG="${MSG} Expected messages on stderr,"
+ MSG="${MSG} nothing produced"
+ fail=true
+ fi
+ fi
+ rm -f "${TEMP_FILE}"
+
+ # Remove newlines (use local shell for this)
+ oifs="$IFS"
+ IFS="$nl"
+ result="$(echo $result)"
+ IFS="$oifs"
+ if [ "$2" != "$result" ]
+ then
+ MSG="${MSG}${MSG:+${nl}}[$TEST_NUM]"
+ MSG="${MSG} Expected output '$2', received '$result'"
+ fail=true
+ fi
+
+ if $fail
+ then
+ MSG="${MSG}${MSG:+${nl}}[$TEST_NUM]"
+ MSG="${MSG} Full command: <<${CMD}>>"
+ fi
+
+ $fail && test -n "$TEST_ID" && {
+ TEST_FAILURES="${TEST_FAILURES}${TEST_FAILURES:+${nl}}"
+ TEST_FAILURES="${TEST_FAILURES}${TEST_ID}[$TEST_NUM]:"
+ TEST_FAILURES="${TEST_FAILURES} Test of '$1' failed.";
+ TEST_FAILURES="${TEST_FAILURES}${nl}${MSG}"
+ TEST_FAIL_COUNT=$(( $TEST_FAIL_COUNT + 1 ))
+ return 0
+ }
+ $fail && atf_fail "Test[$TEST_NUM] of '$1' failed${nl}${MSG}"
+ return 0
+}
+
+results()
+{
+ test -z "${TEST_ID}" && return 0
+ test -z "${TEST_FAILURES}" && return 0
+
+ echo >&2 "=========================================="
+ echo >&2 "While testing '${TEST_ID}'"
+ echo >&2 " - - - - - - - - - - - - - - - - -"
+ echo >&2 "${TEST_FAILURES}"
+ atf_fail \
+ "Test ${TEST_ID}: $TEST_FAIL_COUNT subtests (of $TEST_NUM) failed - see stderr"
+}
+
+atf_test_case shell_params
+shell_params_head() {
+ atf_set "descr" "Test correct operation of the numeric parameters"
+}
+shell_params_body() {
+ atf_require_prog mktemp
+
+ reset shell_params
+
+ check 'set -- a b c; echo "$#: $1 $2 $3"' '3: a b c' 0
+ check 'set -- a b c d e f g h i j k l m; echo "$#: ${1}0 ${10} $10"' \
+ '13: a0 j a0' 0
+ check 'x="$0"; set -- a b; y="$0";
+ [ "x${x}y" = "x${y}y" ] && echo OK || echo x="$x" y="$y"' \
+ 'OK' 0
+ check "${TEST_SH} -c 'echo 0=\$0 1=\$1 2=\$2' a b c" '0=a 1=b 2=c' 0
+
+ echo 'echo 0="$0" 1="$1" 2="$2"' > helper.sh
+ check "${TEST_SH} helper.sh a b c" '0=helper.sh 1=a 2=b' 0
+
+ check 'set -- a bb ccc dddd eeeee ffffff ggggggg hhhhhhhh \
+ iiiiiiiii jjjjjjjjjj kkkkkkkkkkk
+ echo "${#}: ${#1} ${#2} ${#3} ${#4} ... ${#9} ${#10} ${#11}"' \
+ '11: 1 2 3 4 ... 9 10 11' 0
+
+ check 'set -- a b c; echo "$#: ${1-A} ${2-B} ${3-C} ${4-D} ${5-E}"' \
+ '3: a b c D E' 0
+ check 'set -- a "" c "" e
+ echo "$#: ${1:-A} ${2:-B} ${3:-C} ${4:-D} ${5:-E}"' \
+ '5: a B c D e' 0
+ check 'set -- a "" c "" e
+ echo "$#: ${1:+A} ${2:+B} ${3:+C} ${4:+D} ${5:+E}"' \
+ '5: A C E' 0
+ check 'set -- "abab*cbb"
+ echo "${1} ${1#a} ${1%b} ${1##ab} ${1%%b} ${1#*\*} ${1%\**}"' \
+ 'abab*cbb bab*cbb abab*cb ab*cbb abab*cb cbb abab' 0
+ check 'set -- "abab?cbb"
+ echo "${1}:${1#*a}+${1%b*}-${1##*a}_${1%%b*}%${1#[ab]}=${1%?*}/${1%\?*}"' \
+ 'abab?cbb:bab?cbb+abab?cb-b?cbb_a%bab?cbb=abab?cb/abab' 0
+ check 'set -- a "" c "" e; echo "${2:=b}"' '' 1
+
+ results
}
atf_init_test_cases() {
@@ -139,4 +373,8 @@ 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
+ atf_add_test_case shell_params
}
diff --git a/contrib/netbsd-tests/bin/sh/t_fsplit.sh b/contrib/netbsd-tests/bin/sh/t_fsplit.sh
index 2c3dbae..a37804b 100755
--- a/contrib/netbsd-tests/bin/sh/t_fsplit.sh
+++ b/contrib/netbsd-tests/bin/sh/t_fsplit.sh
@@ -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.4 2016/03/27 14:50:01 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,22 +33,51 @@
# 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
#
+# the implementation of "sh" to test
+: ${TEST_SH:="/bin/sh"}
+
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 +88,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 +98,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 +223,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 +246,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 +261,44 @@ 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'
+
+ check 'set a b c; for i in "$@$@"; do echo "z${i}z"; done' \
+ 'zaz zbz zcaz zbz zcz'
+ check 'set a b c; for i in "$@""$@";do echo "z${i}z"; done' \
+ 'zaz zbz zcaz zbz zcz'
}
atf_test_case ifs
@@ -143,6 +309,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 +332,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
diff --git a/contrib/netbsd-tests/bin/sh/t_here.sh b/contrib/netbsd-tests/bin/sh/t_here.sh
index 250c686..27307f5 100755
--- a/contrib/netbsd-tests/bin/sh/t_here.sh
+++ b/contrib/netbsd-tests/bin/sh/t_here.sh
@@ -1,4 +1,4 @@
-# $NetBSD: t_here.sh,v 1.1 2012/03/17 16:33:11 jruoho Exp $
+# $NetBSD: t_here.sh,v 1.6 2016/03/31 16:21:52 christos Exp $
#
# Copyright (c) 2007 The NetBSD Foundation, Inc.
# All rights reserved.
@@ -24,50 +24,542 @@
# 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"}
nl='
'
+reset()
+{
+ TEST_NUM=0
+ TEST_FAILURES=''
+ TEST_FAIL_COUNT=0
+ TEST_ID="$1"
+}
+
check()
{
- SVIFS="$IFS"
- result="$(eval $1)"
- # Remove newlines
+ fail=false
+ TEMP_FILE=$( mktemp OUT.XXXXXX )
+ TEST_NUM=$(( $TEST_NUM + 1 ))
+
+ # our local shell (ATF_SHELL) better do quoting correctly...
+ # some of the tests expect us to expand $nl internally...
+ CMD="nl='${nl}'; $1"
+
+ result="$( ${TEST_SH} -c "${CMD}" 2>"${TEMP_FILE}" )"
+ STATUS=$?
+
+ if [ "${STATUS}" -ne "$3" ]; then
+ echo >&2 "[$TEST_NUM] expected exit code $3, got ${STATUS}"
+
+ # don't actually fail just because of wrong exit code
+ # unless we either expected, or received "good"
+ case "$3/${STATUS}" in
+ (*/0|0/*) fail=true;;
+ esac
+ fi
+
+ if [ "$3" -eq 0 ]; then
+ if [ -s "${TEMP_FILE}" ]; then
+ echo >&2 \
+ "[$TEST_NUM] Messages produced on stderr unexpected..."
+ cat "${TEMP_FILE}" >&2
+ fail=true
+ fi
+ else
+ if ! [ -s "${TEMP_FILE}" ]; then
+ echo >&2 \
+ "[$TEST_NUM] Expected messages on stderr, nothing produced"
+ fail=true
+ fi
+ fi
+ rm -f "${TEMP_FILE}"
+
+ # Remove newlines (use local shell for this)
oifs="$IFS"
IFS="$nl"
result="$(echo $result)"
IFS="$oifs"
if [ "$2" != "$result" ]
then
- atf_fail "expected [$2], found [$result]"
+ echo >&2 "[$TEST_NUM] Expected output '$2', received '$result'"
+ fail=true
fi
- IFS="$SVIFS"
+
+ if $fail
+ then
+ echo >&2 "[$TEST_NUM] Full command: <<${CMD}>>"
+ fi
+
+ $fail && test -n "$TEST_ID" && {
+ TEST_FAILURES="${TEST_FAILURES}${TEST_FAILURES:+
+}${TEST_ID}[$TEST_NUM]: test of '$1' failed";
+ TEST_FAIL_COUNT=$(( $TEST_FAIL_COUNT + 1 ))
+ return 0
+ }
+ $fail && atf_fail "Test[$TEST_NUM] of '$1' failed"
+ return 0
}
-atf_test_case all
-all_head() {
+results()
+{
+ test -z "${TEST_ID}" && return 0
+ test -z "${TEST_FAILURES}" && return 0
+
+ echo >&2 "=========================================="
+ echo >&2 "While testing '${TEST_ID}'"
+ echo >&2 " - - - - - - - - - - - - - - - - -"
+ echo >&2 "${TEST_FAILURES}"
+ atf_fail \
+ "Test ${TEST_ID}: $TEST_FAIL_COUNT subtests (of $TEST_NUM) failed - see stderr"
+}
+
+atf_test_case do_simple
+do_simple_head() {
atf_set "descr" "Basic tests for here documents"
}
-all_body() {
+do_simple_body() {
y=x
- IFS=
- check 'x=`cat <<EOF'$nl'text'${nl}EOF$nl'`; echo $x' 'text'
- check 'x=`cat <<\EOF'$nl'text'${nl}EOF$nl'`; echo $x' 'text'
+ reset 'simple'
+ IFS=' '
+ check 'x=`cat <<EOF'$nl'text'${nl}EOF$nl'`; echo $x' 'text' 0
+ check 'x=`cat <<\EOF'$nl'text'${nl}EOF$nl'`; echo $x' 'text' 0
+
+ check "y=${y};"'x=`cat <<EOF'$nl'te${y}t'${nl}EOF$nl'`; echo $x' \
+ 'text' 0
+ check "y=${y};"'x=`cat <<\EOF'$nl'te${y}t'${nl}EOF$nl'`; echo $x' \
+ 'te${y}t' 0
+ check "y=${y};"'x=`cat <<"EOF"'$nl'te${y}t'${nl}EOF$nl'`; echo $x' \
+ 'te${y}t' 0
+ check "y=${y};"'x=`cat <<'"'EOF'"$nl'te${y}t'${nl}EOF$nl'`; echo $x' \
+ 'te${y}t' 0
+
+ # check that quotes in the here doc survive and cause no problems
+ check "cat <<EOF${nl}te'xt${nl}EOF$nl" "te'xt" 0
+ check "cat <<\EOF${nl}te'xt${nl}EOF$nl" "te'xt" 0
+ check "cat <<'EOF'${nl}te'xt${nl}EOF$nl" "te'xt" 0
+ check "cat <<EOF${nl}te\"xt${nl}EOF$nl" 'te"xt' 0
+ check "cat <<\EOF${nl}te\"xt${nl}EOF$nl" 'te"xt' 0
+ check "cat <<'EOF'${nl}te\"xt${nl}EOF$nl" 'te"xt' 0
+ check "cat <<'EO'F${nl}te\"xt${nl}EOF$nl" 'te"xt' 0
+
+ check "y=${y};"'x=`cat <<EOF'$nl'te'"'"'${y}t'${nl}EOF$nl'`; echo $x' \
+ 'te'"'"'xt' 0
+ check "y=${y};"'x=`cat <<EOF'$nl'te'"''"'${y}t'${nl}EOF$nl'`; echo $x' \
+ 'te'"''"'xt' 0
+
+ # note that the blocks of empty space in the following must
+ # be entirely tab characters, no spaces.
+
+ check 'x=`cat <<EOF'"$nl text${nl}EOF$nl"'`; echo "$x"' \
+ ' text' 0
+ check 'x=`cat <<-EOF'"$nl text${nl}EOF$nl"'`; echo $x' \
+ 'text' 0
+ check 'x=`cat <<-EOF'"${nl}text${nl} EOF$nl"'`; echo $x' \
+ 'text' 0
+ check 'x=`cat <<-\EOF'"$nl text${nl} EOF$nl"'`; echo $x' \
+ 'text' 0
+ check 'x=`cat <<- "EOF"'"$nl text${nl}EOF$nl"'`; echo $x' \
+ 'text' 0
+ check 'x=`cat <<- '"'EOF'${nl}text${nl} EOF$nl"'`; echo $x' \
+ 'text' 0
+ results
+}
+
+atf_test_case end_markers
+end_markers_head() {
+ atf_set "descr" "Tests for various end markers of here documents"
+}
+end_markers_body() {
+
+ reset 'end_markers'
+ for end in EOF 1 \! '$$$' "string " a\\\ a\\\ \ '&' '' ' ' ' ' \
+ --STRING-- . '~~~' ')' '(' '#' '()' '(\)' '(\/)' '--' '\' '{' '}' \
+VERYVERYVERYVERYLONGLONGLONGin_fact_absurdly_LONG_LONG_HERE_DOCUMENT_TERMINATING_MARKER_THAT_goes_On_forever_and_ever_and_ever...
+ do
+ # check unquoted end markers
+ case "${end}" in
+ ('' | *[' ()\$&#*~']* ) ;; # skip unquoted endmark test for these
+ (*) check \
+ 'x=$(cat << '"${end}${nl}text${nl}${end}${nl}"'); printf %s "$x"' 'text' 0
+ ;;
+ esac
+
+ # and quoted end markers
+ check \
+ 'x=$(cat <<'"'${end}'${nl}text${nl}${end}${nl}"'); printf %s "$x"' 'text' 0
+
+ # and see what happens if we encounter "almost" an end marker
+ case "${#end}" in
+ (0|1) ;; # too short to try truncation tests
+ (*) check \
+ 'x=$(cat <<'"'${end}'${nl}text${nl}${end%?}${nl}${end}${nl}"'); printf %s "$x"' \
+ "text ${end%?}" 0
+ check \
+ 'x=$(cat <<'"'${end}'${nl}text${nl}${end#?}${nl}${end}${nl}"'); printf %s "$x"' \
+ "text ${end#?}" 0
+ check \
+ 'x=$(cat <<'"'${end}'${nl}text${nl}${end%?}+${nl}${end}${nl}"');printf %s "$x"' \
+ "text ${end%?}+" 0
+ ;;
+ esac
+
+ # or something that is a little longer
+ check \
+ 'x=$(cat <<'"'${end}'${nl}text${nl}${end}x${nl}${end}${nl}"'); printf %s "$x"' \
+ "text ${end}x" 0
+ check \
+ 'x=$(cat <<'"'${end}'${nl}text${nl}!${end}${nl}${end}${nl}"'); printf %s "$x"' \
+ "text !${end}" 0
+
+ # or which does not begin at start of line
+ check \
+ 'x=$(cat <<'"'${end}'${nl}text${nl} ${end}${nl}${end}${nl}"'); printf %s "$x"' \
+ "text ${end}" 0
+ check \
+ 'x=$(cat <<'"'${end}'${nl}text${nl} ${end}${nl}${end}${nl}"'); printf %s "$x"' \
+ "text ${end}" 0
+
+ # or end at end of line
+ check \
+ 'x=$(cat <<'"'${end}'${nl}text${nl}${end} ${nl}${end}${nl}"'); printf %s "$x"' \
+ "text ${end} " 0
+
+ # or something that is correct much of the way, but then...
+
+ case "${#end}" in
+ (0) ;; # cannot test this one
+ (1) check \
+ 'x=$(cat <<'"'${end}'${nl}text${nl}${end}${end}${nl}${end}${nl}"'); printf %s "$x"' \
+ "text ${end}${end}" 0
+ ;;
+ (2-7) pfx="${end%?}"
+ check \
+ 'x=$(cat <<'"'${end}'${nl}text${nl}${end}${pfx}${nl}${end}${nl}"'); printf %s "$x"' \
+ "text ${end}${pfx}" 0
+ check \
+ 'x=$(cat <<'"'${end}'${nl}text${nl}${pfx}${end}${nl}${end}${nl}"'); printf %s "$x"' \
+ "text ${pfx}${end}" 0
+ ;;
+ (*) pfx=${end%??????}; sfx=${end#??????}
+ check \
+ 'x=$(cat <<'"'${end}'${nl}text${nl}${end}${sfx}${nl}${end}${nl}"'); printf %s "$x"' \
+ "text ${end}${sfx}" 0
+ check \
+ 'x=$(cat <<'"'${end}'${nl}text${nl}${pfx}${end}${nl}${end}${nl}"'); printf %s "$x"' \
+ "text ${pfx}${end}" 0
+ check \
+ 'x=$(cat <<'"'${end}'${nl}text${nl}${pfx}${sfx}${nl}${end}${nl}"'); printf %s "$x"' \
+ "text ${pfx}${sfx}" 0
+ ;;
+ esac
+ done
+
+ # Add striptabs tests (in similar way) here one day...
+
+ results
+}
+
+atf_test_case incomplete
+incomplete_head() {
+ atf_set "descr" "Basic tests for incomplete here documents"
+}
+incomplete_body() {
+ reset incomplete
+
+ check 'cat <<EOF' '' 2
+ check 'cat <<- EOF' '' 2
+ check 'cat <<\EOF' '' 2
+ check 'cat <<- \EOF' '' 2
+
+ check 'cat <<EOF'"${nl}" '' 2
+ check 'cat <<- EOF'"${nl}" '' 2
+ check 'cat <<'"'EOF'${nl}" '' 2
+ check 'cat <<- "EOF"'"${nl}" '' 2
+
+ check 'cat << EOF'"${nl}${nl}" '' 2
+ check 'cat <<-EOF'"${nl}${nl}" '' 2
+ check 'cat << '"'EOF'${nl}${nl}" '' 2
+ check 'cat <<-"EOF"'"${nl}${nl}" '' 2
+
+ check 'cat << EOF'"${nl}"'line 1'"${nl}" '' 2
+ check 'cat <<-EOF'"${nl}"' line 1'"${nl}" '' 2
+ check 'cat << EOF'"${nl}"'line 1'"${nl}"' line 2'"${nl}" '' 2
+ check 'cat <<-EOF'"${nl}"' line 1'"${nl}"'line 2'"${nl}" '' 2
+
+ check 'cat << EOF'"${nl}line 1${nl}${nl}line3${nl}${nl}5!${nl}" '' 2
+
+ results
+}
+
+atf_test_case lineends
+lineends_head() {
+ atf_set "descr" "Tests for line endings in here documents"
+}
+lineends_body() {
+ reset lineends
+
+ # note that "check" removes newlines from stdout before comparing.
+ # (they become blanks, provided there is something before & after)
+
+ check 'cat << \echo'"${nl}"'\'"${nl}echo${nl}echo${nl}" '\' 0
+ check 'cat << echo'"${nl}"'\'"${nl}echo${nl}echo${nl}" 'echo' 0
+ check 'cat << echo'"${nl}"'\\'"${nl}echo${nl}echo${nl}" '\' 0
+
+ check 'X=3; cat << ec\ho'"${nl}"'$X\'"${nl}echo${nl}echo${nl}" \
+ '$X\' 0
+ check 'X=3; cat << echo'"${nl}"'$X'"${nl}echo${nl}echo${nl}" \
+ '3' 0
+ check 'X=3; cat << echo'"${nl}"'$X\'"${nl}echo${nl}echo${nl}" \
+ '' 0
+ check 'X=3; cat << echo'"${nl}"'${X}\'"${nl}echo${nl}echo${nl}" \
+ '3echo' 0
+ check 'X=3; cat << echo'"${nl}"'\$X\'"${nl}echo${nl}echo${nl}" \
+ '$Xecho' 0
+ check 'X=3; cat << echo'"${nl}"'\\$X \'"${nl}echo${nl}echo${nl}" \
+ '\3 echo' 0
+
+ check \
+ 'cat << "echo"'"${nl}"'line1\'"${nl}"'line2\'"${nl}echo${nl}echo${nl}" \
+ 'line1\ line2\' 0
+ check \
+ 'cat << echo'"${nl}"'line1\'"${nl}"'line2\'"${nl}echo${nl}echo${nl}" \
+ 'line1line2echo' 0
+
+ results
+}
+
+atf_test_case multiple
+multiple_head() {
+ atf_set "descr" "Tests for multiple here documents on one cmd line"
+}
+multiple_body() {
+ reset multiple
+
+ check \
+ "(cat ; cat <&3) <<EOF0 3<<EOF3${nl}STDIN${nl}EOF0${nl}-3-${nl}EOF3${nl}" \
+ 'STDIN -3-' 0
+
+ check "(read line; echo \"\$line\"; cat <<EOF1; echo \"\$line\") <<EOF2
+The File
+EOF1
+The Line
+EOF2
+" 'The Line The File The Line' 0
+
+ check "(read line; echo \"\$line\"; cat <<EOF; echo \"\$line\") <<EOF
+The File
+EOF
+The Line
+EOF
+" 'The Line The File The Line' 0
+
+ check "V=1; W=2; cat <<-1; cat <<2; cat <<- 3; cat <<'4';"' cat <<\5
+ $V
+ $W
+ 3
+ 4
+ 5
+ 1
+2
+ 5
+ 4*$W+\$V
+ 3
+$W
+1
+2
+3
+4
+7+$V
+$W+6
+5
+' '1 2 3 4 5 5 4*2+$V $W 1 2 3 7+$V $W+6' 0
+
+ results
+}
+
+atf_test_case nested
+nested_head() {
+ atf_set "descr" "Tests for nested here documents for one cmd"
+}
+nested_body() {
+ reset nested
+
+ check \
+'cat << EOF1'"${nl}"'$(cat << EOF2'"${nl}LINE${nl}EOF2${nl}"')'"${nl}EOF1${nl}"\
+ 'LINE' 0
+
+# This next one fails ... and correctly, so we will omit it (bad test)
+# Reasoning is that the correct data "$(cat << EOF2)\nLINE\nEOF2\n" is
+# collected for the outer (EOF1) heredoc, when that is parsed, it looks
+# like
+# $(cat <<EOF2)
+# LINE
+# EOF2
+# which looks like a good command - except it is being parsed in "heredoc"
+# syntax, which means it is enclosed in double quotes, which means that
+# the newline after the ')' in the first line is not a newline token, but
+# just a character. The EOF2 heredoc cannot start until after the next
+# newline token, of which there are none here... LINE and EOF2 are just
+# more data in the outer EOF1 heredoc for its "cat" command to read & write.
+#
+# The previous sub-test works because there the \n comes inside the
+# $( ), and in there, the outside quoting rules are suspended, and it
+# all starts again - so that \n is a newline token, and the EOF2 heredoc
+# is processed.
+#
+# check \
+# 'cat << EOF1'"${nl}"'$(cat << EOF2 )'"${nl}LINE${nl}EOF2${nl}EOF1${nl}" \
+# 'LINE' 0
+
+ L='cat << EOF1'"${nl}"'LINE1$(cat << EOF2'"${nl}"
+ L="${L}"'LINE2$(cat << EOF3'"${nl}"
+ L="${L}"'LINE3$(cat << EOF4'"${nl}"
+ L="${L}"'LINE4$(cat << EOF5'"${nl}"
+ L="${L}LINE5${nl}EOF5${nl})4${nl}EOF4${nl})3${nl}"
+ L="${L}EOF3${nl})2${nl}EOF2${nl})1${nl}EOF1${nl}"
+
+ # That mess is ...
+ #
+ # cat <<EOF1
+ # LINE1$(cat << EOF2
+ # LINE2$(cat << EOF3
+ # LINE3$(cat << EOF4
+ # LINE4$(cat << EOF5
+ # LINE5
+ # EOF5
+ # )4
+ # EOF4
+ # )3
+ # EOF3
+ # )2
+ # EOF2
+ # )1
+ # EOF1
+
+ check "${L}" 'LINE1LINE2LINE3LINE4LINE54321' 0
+
+ results
+}
+
+atf_test_case quoting
+quoting_head() {
+ atf_set "descr" "Tests for use of quotes inside here documents"
+}
+quoting_body() {
+ reset quoting
+
+ check 'X=!; cat <<- E\0F
+ <'\''"'\'' \\$X\$X "'\''" \\>
+ E0F
+ ' '<'\''"'\'' \\$X\$X "'\''" \\>' 0
+
+ check 'X=!; cat <<- E0F
+ <'\''"'\'' \\$X\$X "'\''" \\>
+ E0F
+ ' '<'\''"'\'' \!$X "'\''" \>' 0
+
+ check 'cat <<- END
+ $( echo "'\''" ) $( echo '\''"'\'' ) $( echo \\ )
+ END
+ ' "' \" \\" 0
+
+ check 'X=12345; Y="string1 line1?-line2"; Z=; unset W; cat <<-EOF
+ ${#X}${Z:-${Y}}${W+junk}${Y%%l*}${Y#*\?}
+ "$Z"'\''$W'\'' ${Y%" "*} $(( X + 54321 ))
+ EOF
+ ' '5string1 line1?-line2string1 -line2 ""'\'\'' string1 66666' 0
+
+ results
+}
+
+atf_test_case side_effects
+side_effects_head() {
+ atf_set "descr" "Tests how side effects in here documents are handled"
+}
+side_effects_body() {
+
+ atf_check -s exit:0 -o inline:'2\n1\n' -e empty ${TEST_SH} -c '
+ unset X
+ cat <<-EOF
+ ${X=2}
+ EOF
+ echo "${X-1}"
+ '
+}
+
+atf_test_case vicious
+vicious_head() {
+ atf_set "descr" "Tests for obscure and obnoxious uses of here docs"
+}
+vicious_body() {
+ reset
+
+ cat <<- \END_SCRIPT > script
+ cat <<ONE && cat \
+ <<TWO
+ a
+ ONE
+ b
+ TWO
+ END_SCRIPT
+
+ atf_check -s exit:0 -o inline:'a\nb\n' -e empty ${TEST_SH} script
+
+ # This next one is causing discussion currently (late Feb 2016)
+ # amongst stds writers & implementors. Consequently we
+ # will not check what it produces. The eventual result
+ # seems unlikely to be what we currently output, which
+ # is:
+ # A:echo line 1
+ # B:echo line 2)" && prefix DASH_CODE <<DASH_CODE
+ # B:echo line 3
+ # line 4
+ # line 5
+ #
+ # The likely intended output is ...
+ #
+ # A:echo line 3
+ # B:echo line 1
+ # line 2
+ # DASH_CODE:echo line 4)"
+ # DASH_CODE:echo line 5
+ #
+ # The difference is explained by differing opinions on just
+ # when processing of a here doc should start
+
+ cat <<- \END_SCRIPT > script
+ prefix() { sed -e "s/^/$1:/"; }
+ DASH_CODE() { :; }
- check 'x=`cat <<EOF'$nl'te${y}t'${nl}EOF$nl'`; echo $x' 'text'
- check 'x=`cat <<\EOF'$nl'te${y}t'${nl}EOF$nl'`; echo $x' 'te${y}t'
- check 'x=`cat <<"EOF"'$nl'te${y}t'${nl}EOF$nl'`; echo $x' 'te${y}t'
- check 'x=`cat <<'"'EOF'"$nl'te${y}t'${nl}EOF$nl'`; echo $x' 'te${y}t'
+ prefix A <<XXX && echo "$(prefix B <<XXX
+ echo line 1
+ XXX
+ echo line 2)" && prefix DASH_CODE <<DASH_CODE
+ echo line 3
+ XXX
+ echo line 4)"
+ echo line 5
+ DASH_CODE
+ END_SCRIPT
- check 'x=`cat <<EOF'$nl'te'"'"'xt'${nl}EOF$nl'`; echo $x' 'te'"'"'xt'
- check 'x=`cat <<\EOF'$nl'te'"'"'xt'${nl}EOF$nl'`; echo $x' 'te'"'"'xt'
- check 'x=`cat <<"EOF"'$nl'te'"'"'xt'${nl}EOF$nl'`; echo $x' 'te'"'"'xt'
+ # we will just verify that the shell can parse the
+ # script somehow, and doesn't fall over completely...
- check 'x=`cat <<EOF'$nl'te'"'"'${y}t'${nl}EOF$nl'`; echo $x' 'te'"'"'xt'
- check 'x=`cat <<EOF'$nl'te'"''"'${y}t'${nl}EOF$nl'`; echo $x' 'te'"''"'xt'
+ atf_check -s exit:0 -o ignore -e empty ${TEST_SH} script
}
atf_init_test_cases() {
- atf_add_test_case all
+ atf_add_test_case do_simple # not worthy of a comment
+ atf_add_test_case end_markers # the mundane, the weird, the bizarre
+ atf_add_test_case incomplete # where the end marker isn't...
+ atf_add_test_case lineends # test weird line endings in heredocs
+ atf_add_test_case multiple # multiple << operators on one cmd
+ atf_add_test_case nested # here docs inside here docs
+ atf_add_test_case quoting # stuff quoted inside
+ atf_add_test_case side_effects # here docs that modify environment
+ atf_add_test_case vicious # evil test from the austin-l list...
}
diff --git a/contrib/netbsd-tests/bin/sh/t_option.sh b/contrib/netbsd-tests/bin/sh/t_option.sh
new file mode 100755
index 0000000..eae2110
--- /dev/null
+++ b/contrib/netbsd-tests/bin/sh/t_option.sh
@@ -0,0 +1,674 @@
+# $NetBSD: t_option.sh,v 1.3 2016/03/08 14:19:28 christos Exp $
+#
+# Copyright (c) 2016 The NetBSD Foundation, Inc.
+# 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+#
+# the implementation of "sh" to test
+: ${TEST_SH:="/bin/sh"}
+
+# The standard
+# http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
+# says:
+# ...[lots]
+
+test_option_on_off()
+{
+ atf_require_prog tr
+
+ for opt
+ do
+ # t is needed, as inside $()` $- appears to lose
+ # the 'e' option if it happened to already be
+ # set. Must check if that is what should
+ # happen, but that is a different issue.
+
+ test -z "${opt}" && continue
+
+ # if we are playing with more that one option at a
+ # time, the code below requires that we start with no
+ # options set, or it will mis-diagnose the situation
+ CLEAR=''
+ test "${#opt}" -gt 1 &&
+ CLEAR='xx="$-" && xx=$(echo "$xx" | tr -d cs) && test -n "$xx" && set +"$xx";'
+
+ atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
+ "opt=${opt}"'
+ x() {
+ echo "ERROR: Unable to $1 option $2" >&2
+ exit 1
+ }
+ s() {
+ set -"$1"
+ t="$-"
+ x=$(echo "$t" | tr -d "$1")
+ test "$t" = "$x" && x set "$1"
+ return 0
+ }
+ c() {
+ set +"$1"
+ t="$-"
+ x=$(echo "$t" | tr -d "$1")
+ test "$t" != "$x" && x clear "$1"
+ return 0
+ }
+ '"${CLEAR}"'
+
+ # if we do not do this, -x tracing splatters stderr
+ # for some shells, -v does as well (is that correct?)
+ case "${opt}" in
+ (*[xv]*) exec 2>/dev/null;;
+ esac
+
+ o="$-"
+ x=$(echo "$o" | tr -d "$opt")
+
+ if [ "$o" = "$x" ]; then # option was off
+ s "${opt}"
+ c "${opt}"
+ else
+ c "${opt}"
+ s "${opt}"
+ fi
+ '
+ done
+}
+
+test_optional_on_off()
+{
+ RET=0
+ OPTS=
+ for opt
+ do
+ test "${opt}" = n && continue
+ ${TEST_SH} -c "set -${opt}" 2>/dev/null &&
+ OPTS="${OPTS} ${opt}" || RET=1
+ done
+
+ test -n "${OPTS}" && test_option_on_off ${OPTS}
+
+ return "${RET}"
+}
+
+atf_test_case set_a
+set_a_head() {
+ atf_set "descr" "Tests that 'set -a' turns on all var export " \
+ "and that it behaves as defined by the standard"
+}
+set_a_body() {
+ atf_require_prog env
+ atf_require_prog grep
+
+ test_option_on_off a
+
+ # without -a, new variables should not be exported (so grep "fails")
+ atf_check -s exit:1 -o empty -e empty ${TEST_SH} -ce \
+ 'unset VAR; set +a; VAR=value; env | grep "^VAR="'
+
+ # with -a, they should be
+ atf_check -s exit:0 -o match:VAR=value -e empty ${TEST_SH} -ce \
+ 'unset VAR; set -a; VAR=value; env | grep "^VAR="'
+}
+
+atf_test_case set_C
+set_C_head() {
+ atf_set "descr" "Tests that 'set -C' turns on no clobber mode " \
+ "and that it behaves as defined by the standard"
+}
+set_C_body() {
+ atf_require_prog ls
+
+ test_option_on_off C
+
+ # Check that the environment to use for the tests is sane ...
+ # we assume current dir is a new tempory directory & is empty
+
+ test -z "$(ls)" || atf_skip "Test execution directory not clean"
+ test -c "/dev/null" || atf_skip "Problem with /dev/null"
+
+ echo Dummy_Content > Junk_File
+ echo Precious_Content > Important_File
+
+ # Check that we can redirect onto file when -C is not set
+ atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
+ '
+ D=$(ls -l Junk_File) || exit 1
+ set +C
+ echo "Overwrite it now" > Junk_File
+ A=$(ls -l Junk_File) || exit 1
+ test "${A}" != "${D}"
+ '
+
+ # Check that we cannot redirect onto file when -C is set
+ atf_check -s exit:0 -o empty -e not-empty ${TEST_SH} -c \
+ '
+ D=$(ls -l Important_File) || exit 1
+ set -C
+ echo "Fail to Overwrite it now" > Important_File
+ A=$(ls -l Important_File) || exit 1
+ test "${A}" = "${D}"
+ '
+
+ # Check that we can append to file, even when -C is set
+ atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
+ '
+ D=$(ls -l Junk_File) || exit 1
+ set -C
+ echo "Append to it now" >> Junk_File
+ A=$(ls -l Junk_File) || exit 1
+ test "${A}" != "${D}"
+ '
+
+ # Check that we abort on attempt to redirect onto file when -Ce is set
+ atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
+ '
+ set -Ce
+ echo "Fail to Overwrite it now" > Important_File
+ echo "Should not reach this point"
+ '
+
+ # Last check that we can override -C for when we really need to
+ atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
+ '
+ D=$(ls -l Junk_File) || exit 1
+ set -C
+ echo "Change the poor bugger again" >| Junk_File
+ A=$(ls -l Junk_File) || exit 1
+ test "${A}" != "${D}"
+ '
+}
+
+atf_test_case set_e
+set_e_head() {
+ atf_set "descr" "Tests that 'set -e' turns on error detection " \
+ "and that a simple case behaves as defined by the standard"
+}
+set_e_body() {
+ test_option_on_off e
+
+ # Check that -e does nothing if no commands fail
+ atf_check -s exit:0 -o match:I_am_OK -e empty \
+ ${TEST_SH} -c \
+ 'false; printf "%s" I_am; set -e; true; printf "%s\n" _OK'
+
+ # and that it (silently, but with exit status) aborts if cmd fails
+ atf_check -s not-exit:0 -o match:I_am -o not-match:Broken -e empty \
+ ${TEST_SH} -c \
+ 'false; printf "%s" I_am; set -e; false; printf "%s\n" _Broken'
+
+ # same, except -e this time is on from the beginning
+ atf_check -s not-exit:0 -o match:I_am -o not-match:Broken -e empty \
+ ${TEST_SH} -ec 'printf "%s" I_am; false; printf "%s\n" _Broken'
+
+ # More checking of -e in other places, there is lots to deal with.
+}
+
+atf_test_case set_f
+set_f_head() {
+ atf_set "descr" "Tests that 'set -f' turns off pathname expansion " \
+ "and that it behaves as defined by the standard"
+}
+set_f_body() {
+ atf_require_prog ls
+
+ test_option_on_off f
+
+ # Check that the environment to use for the tests is sane ...
+ # we assume current dir is a new tempory directory & is empty
+
+ test -z "$(ls)" || atf_skip "Test execution directory not clean"
+
+ # we will assume that atf will clean up this junk directory
+ # when we are done. But for testing pathname expansion
+ # we need files
+
+ for f in a b c d e f aa ab ac ad ae aaa aab aac aad aba abc bbb ccc
+ do
+ echo "$f" > "$f"
+ done
+
+ atf_check -s exit:0 -o empty -e empty ${TEST_SH} -ec \
+ 'X=$(echo b*); Y=$(echo b*); test "${X}" != "a*";
+ test "${X}" = "${Y}"'
+
+ # now test expansion is different when -f is set
+ atf_check -s exit:0 -o empty -e empty ${TEST_SH} -ec \
+ 'X=$(echo b*); Y=$(set -f; echo b*); test "${X}" != "${Y}"'
+}
+
+atf_test_case set_n
+set_n_head() {
+ atf_set "descr" "Tests that 'set -n' supresses command execution " \
+ "and that it behaves as defined by the standard"
+}
+set_n_body() {
+ # pointless to test this, if it turns on, it stays on...
+ # test_option_on_off n
+ # so just allow the tests below to verify it can be turned on
+
+ # nothing should be executed, hence no output...
+ atf_check -s exit:0 -o empty -e empty \
+ ${TEST_SH} -enc 'echo ABANDON HOPE; echo ALL YE; echo ...'
+
+ # this is true even when the "commands" do not exist
+ atf_check -s exit:0 -o empty -e empty \
+ ${TEST_SH} -enc 'ERR; FAIL; ABANDON HOPE'
+
+ # but if there is a syntax error, it should be detected (w or w/o -e)
+ atf_check -s not-exit:0 -o empty -e not-empty \
+ ${TEST_SH} -enc 'echo JUMP; for frogs swim; echo in puddles'
+ atf_check -s not-exit:0 -o empty -e not-empty \
+ ${TEST_SH} -nc 'echo ABANDON HOPE; echo "ALL YE; echo ...'
+ atf_check -s not-exit:0 -o empty -e not-empty \
+ ${TEST_SH} -enc 'echo ABANDON HOPE;; echo ALL YE; echo ...'
+ atf_check -s not-exit:0 -o empty -e not-empty \
+ ${TEST_SH} -nc 'do YOU ABANDON HOPE; for all eternity?'
+
+ # now test enabling -n in the middle of a script
+ # note that once turned on, it cannot be turned off again.
+ #
+ # omit more complex cases, as those can send some shells
+ # into infinite loops, and believe it or not, that might be OK!
+
+ atf_check -s exit:0 -o match:first -o not-match:second -e empty \
+ ${TEST_SH} -c 'echo first; set -n; echo second'
+ atf_check -s exit:0 -o match:first -o not-match:third -e empty \
+ ${TEST_SH} -c 'echo first; set -n; echo second; set +n; echo third'
+ atf_check -s exit:0 -o inline:'a\nb\n' -e empty \
+ ${TEST_SH} -c 'for x in a b c d
+ do
+ case "$x" in
+ a);; b);; c) set -n;; d);;
+ esac
+ printf "%s\n" "$x"
+ done'
+
+ # This last one is a bit more complex to explain, so I will not try
+
+ # First, we need to know what signal number is used for SIGUSR1 on
+ # the local (testing) system (signal number is $(( $XIT - 128 )) )
+
+ # this will take slightly over 1 second elapsed time (the sleep 1)
+ # The "10" for the first sleep just needs to be something big enough
+ # that the rest of the commands have time to complete, even on
+ # very slow testing systems. 10 should be enough. Otherwise irrelevant
+
+ # The shell will usually blather to stderr about the sleep 10 being
+ # killed, but it affects nothing, so just allow it to cry.
+
+ (sleep 10 & sleep 1; kill -USR1 $!; wait $!)
+ XIT="$?"
+
+ # The exit value should be an integer > 128 and < 256 (often 158)
+ # If it is not just skip the test
+
+ # If we do run the test, it should take (slightly over) either 1 or 2
+ # seconds to complete, depending upon the shell being tested.
+
+ case "${XIT}" in
+ ( 129 | 1[3-9][0-9] | 2[0-4][0-9] | 25[0-5] )
+
+ # The script below should exit with the same code - no output
+
+ # Or that is the result that seems best explanable.
+ # "set -n" in uses like this is not exactly well defined...
+
+ # This script comes from a member of the austin group
+ # (they author changes to the posix shell spec - and more.)
+ # The author is also an (occasional?) NetBSD user.
+ atf_check -s exit:${XIT} -o empty -e empty ${TEST_SH} -c '
+ trap "set -n" USR1
+ { sleep 1; kill -USR1 $$; sleep 1; } &
+ false
+ wait && echo t || echo f
+ wait
+ echo foo
+ '
+ ;;
+ esac
+}
+
+atf_test_case set_u
+set_u_head() {
+ atf_set "descr" "Tests that 'set -u' turns on unset var detection " \
+ "and that it behaves as defined by the standard"
+}
+set_u_body() {
+ test_option_on_off u
+
+ # first make sure it is OK to unset an unset variable
+ atf_check -s exit:0 -o match:OK -e empty ${TEST_SH} -ce \
+ 'unset _UNSET_VARIABLE_; echo OK'
+ # even if -u is set
+ atf_check -s exit:0 -o match:OK -e empty ${TEST_SH} -cue \
+ 'unset _UNSET_VARIABLE_; echo OK'
+
+ # and that without -u accessing an unset variable is harmless
+ atf_check -s exit:0 -o match:OK -e empty ${TEST_SH} -ce \
+ 'unset X; echo ${X}; echo OK'
+ # and that the unset variable test expansion works properly
+ atf_check -s exit:0 -o match:OKOK -e empty ${TEST_SH} -ce \
+ 'unset X; printf "%s" ${X-OK}; echo OK'
+
+ # Next test that with -u set, the shell aborts on access to unset var
+ # do not use -e, want to make sure it is -u that causes abort
+ atf_check -s not-exit:0 -o not-match:ERR -e not-empty ${TEST_SH} -c \
+ 'unset X; set -u; echo ${X}; echo ERR'
+ # quoting should make no difference...
+ atf_check -s not-exit:0 -o not-match:ERR -e not-empty ${TEST_SH} -c \
+ 'unset X; set -u; echo "${X}"; echo ERR'
+
+ # Now a bunch of accesses to unset vars, with -u, in ways that are OK
+ atf_check -s exit:0 -o match:OK -e empty ${TEST_SH} -ce \
+ 'unset X; set -u; echo ${X-GOOD}; echo OK'
+ atf_check -s exit:0 -o match:OK -e empty ${TEST_SH} -ce \
+ 'unset X; set -u; echo ${X-OK}'
+ atf_check -s exit:0 -o not-match:ERR -o match:OK -e empty \
+ ${TEST_SH} -ce 'unset X; set -u; echo ${X+ERR}; echo OK'
+
+ # and some more ways that are not OK
+ atf_check -s not-exit:0 -o not-match:ERR -e not-empty ${TEST_SH} -c \
+ 'unset X; set -u; echo ${X#foo}; echo ERR'
+ atf_check -s not-exit:0 -o not-match:ERR -e not-empty ${TEST_SH} -c \
+ 'unset X; set -u; echo ${X%%bar}; echo ERR'
+
+ # lastly, just while we are checking unset vars, test aborts w/o -u
+ atf_check -s not-exit:0 -o not-match:ERR -e not-empty ${TEST_SH} -c \
+ 'unset X; echo ${X?}; echo ERR'
+ atf_check -s not-exit:0 -o not-match:ERR -e match:X_NOT_SET \
+ ${TEST_SH} -c 'unset X; echo ${X?X_NOT_SET}; echo ERR'
+}
+
+atf_test_case set_v
+set_v_head() {
+ atf_set "descr" "Tests that 'set -v' turns on input read echoing " \
+ "and that it behaves as defined by the standard"
+}
+set_v_body() {
+ test_option_on_off v
+
+ # check that -v does nothing if no later input line is read
+ atf_check -s exit:0 \
+ -o match:OKOK -o not-match:echo -o not-match:printf \
+ -e empty \
+ ${TEST_SH} -ec 'printf "%s" OK; set -v; echo OK; exit 0'
+
+ # but that it does when there are multiple lines
+ cat <<- 'EOF' |
+ set -v
+ printf %s OK
+ echo OK
+ exit 0
+ EOF
+ atf_check -s exit:0 \
+ -o match:OKOK -o not-match:echo -o not-match:printf \
+ -e match:printf -e match:OK -e match:echo \
+ -e not-match:set ${TEST_SH}
+
+ # and that it can be disabled again
+ cat <<- 'EOF' |
+ set -v
+ printf %s OK
+ set +v
+ echo OK
+ exit 0
+ EOF
+ atf_check -s exit:0 \
+ -o match:OKOK -o not-match:echo -o not-match:printf \
+ -e match:printf -e match:OK -e not-match:echo \
+ ${TEST_SH}
+
+ # and lastly, that shell keywords do get output when "read"
+ cat <<- 'EOF' |
+ set -v
+ for i in 111 222 333
+ do
+ printf %s $i
+ done
+ exit 0
+ EOF
+ atf_check -s exit:0 \
+ -o match:111222333 -o not-match:printf \
+ -o not-match:for -o not-match:do -o not-match:done \
+ -e match:printf -e match:111 -e not-match:111222 \
+ -e match:for -e match:do -e match:done \
+ ${TEST_SH}
+}
+
+atf_test_case set_x
+set_x_head() {
+ atf_set "descr" "Tests that 'set -x' turns on command exec logging " \
+ "and that it behaves as defined by the standard"
+}
+set_x_body() {
+ test_option_on_off x
+
+ # check that cmd output appears after -x is enabled
+ atf_check -s exit:0 \
+ -o match:OKOK -o not-match:echo -o not-match:printf \
+ -e not-match:printf -e match:OK -e match:echo \
+ ${TEST_SH} -ec 'printf "%s" OK; set -x; echo OK; exit 0'
+
+ # and that it stops again afer -x is disabled
+ atf_check -s exit:0 \
+ -o match:OKOK -o not-match:echo -o not-match:printf \
+ -e match:printf -e match:OK -e not-match:echo \
+ ${TEST_SH} -ec 'set -x; printf "%s" OK; set +x; echo OK; exit 0'
+
+ # also check that PS4 is output correctly
+ atf_check -s exit:0 \
+ -o match:OK -o not-match:echo \
+ -e match:OK -e match:Run:echo \
+ ${TEST_SH} -ec 'PS4=Run:; set -x; echo OK; exit 0'
+
+ return 0
+
+ # This one seems controversial... I suspect it is NetBSD's sh
+ # that is wrong to not output "for" "while" "if" ... etc
+
+ # and lastly, that shell keywords do not get output when "executed"
+ atf_check -s exit:0 \
+ -o match:111222333 -o not-match:printf \
+ -o not-match:for \
+ -e match:printf -e match:111 -e not-match:111222 \
+ -e not-match:for -e not-match:do -e not-match:done \
+ ${TEST_SH} -ec \
+ 'set -x; for i in 111 222 333; do printf "%s" $i; done; echo; exit 0'
+}
+
+opt_test_setup()
+{
+ test -n "$1" || { echo >&2 "Internal error"; exit 1; }
+
+ cat > "$1" << 'END_OF_FUNCTIONS'
+local_opt_check()
+{
+ local -
+}
+
+instr()
+{
+ expr "$2" : "\(.*$1\)" >/dev/null
+}
+
+save_opts()
+{
+ local -
+
+ set -e
+ set -u
+
+ instr e "$-" && instr u "$-" && return 0
+ echo ERR
+}
+
+fiddle_opts()
+{
+ set -e
+ set -u
+
+ instr e "$-" && instr u "$-" && return 0
+ echo ERR
+}
+
+local_test()
+{
+ set +eu
+
+ save_opts
+ instr '[eu]' "$-" || printf %s "OK"
+
+ fiddle_opts
+ instr e "$-" && instr u "$-" && printf %s "OK"
+
+ set +eu
+}
+END_OF_FUNCTIONS
+}
+
+atf_test_case restore_local_opts
+restore_local_opts_head() {
+ atf_set "descr" "Tests that 'local -' saves and restores options. " \
+ "Note that "local" is a local shell addition"
+}
+restore_local_opts_body() {
+ atf_require_prog cat
+ atf_require_prog expr
+
+ FN="test-funcs.$$"
+ opt_test_setup "${FN}" || atf_skip "Cannot setup test environment"
+
+ ${TEST_SH} -ec ". './${FN}'; local_opt_check" 2>/dev/null ||
+ atf_skip "sh extension 'local -' not supported by ${TEST_SH}"
+
+ atf_check -s exit:0 -o match:OKOK -o not-match:ERR -e empty \
+ ${TEST_SH} -ec ". './${FN}'; local_test"
+}
+
+atf_test_case vi_emacs_VE_toggle
+vi_emacs_VE_toggle_head() {
+ atf_set "descr" "Tests enabling vi disables emacs (and v.v - but why?)"\
+ " Note that -V and -E are local shell additions"
+}
+vi_emacs_VE_toggle_body() {
+
+ test_optional_on_off V E ||
+ atf_skip "One or both V & E opts unsupported by ${TEST_SH}"
+
+ atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c '
+ q() {
+ eval "case \"$-\" in
+ (*${2}*) return 1;;
+ (*${1}*) return 0;;
+ esac"
+ return 1
+ }
+ x() {
+ echo >&2 "Option set or toggle failure:" \
+ " on=$1 off=$2 set=$-"
+ exit 1
+ }
+ set -V; q V E || x V E
+ set -E; q E V || x E V
+ set -V; q V E || x V E
+ set +EV; q "" "[VE]" || x "" VE
+ exit 0
+ '
+}
+
+atf_test_case xx_bogus
+xx_bogus_head() {
+ atf_set "descr" "Tests that attempting to set a nonsense option fails."
+}
+xx_bogus_body() {
+ # Biggest problem here is picking a "nonsense option" that is
+ # not implemented by any shell, anywhere. Hopefully this will do.
+
+ # 'set' is a special builtin, so a conforming shell should exit
+ # on an arg error, and the ERR should not be printed.
+ atf_check -s not-exit:0 -o empty -e not-empty \
+ ${TEST_SH} -c 'set -% ; echo ERR'
+}
+
+atf_test_case Option_switching
+Option_switching_head() {
+ atf_set "descr" "options can be enabled and disabled"
+}
+Option_switching_body() {
+
+ # Cannot test -m, setting it causes test shell to fail...
+ # (test shell gets SIGKILL!) Wonder why ... something related to atf
+ # That is, it works if just run as "sh -c 'echo $-; set -m; echo $-'"
+
+ # Don't bother testing toggling -n, once on, it stays on...
+ # (and because the test fn refuses to allow us to try)
+
+ # Cannot test -o or -c here, or the extension -s
+ # they can only be used, not switched
+
+ # these are the posix options, that all shells should implement
+ test_option_on_off a b C e f h u v x # m
+
+ # and these are extensions that might not exist (non-fatal to test)
+ # -i and -s (and -c) are posix options, but are not required to
+ # be accessable via the "set" command, just the command line.
+ # We allow for -i to work with set, as that makes some sense,
+ # -c and -s do not.
+ test_optional_on_off E i I p q V || true
+
+ # Also test (some) option combinations ...
+ # only testing posix options here, because it is easier...
+ test_option_on_off aeu vx Ca aCefux
+}
+
+atf_init_test_cases() {
+ # tests are run in order sort of names produces, so choose names wisely
+
+ # this one tests turning on/off all the mandatory. and extra flags
+ atf_add_test_case Option_switching
+ # and this tests the NetBSD "local -" functionality in functions.
+ atf_add_test_case restore_local_opts
+
+ # no tests for -m (no idea how to do that one)
+ # -I (no easy way to generate the EOF it ignores)
+ # -i (not sure how to test that one at the minute)
+ # -p (because we aren't going to run tests setuid)
+ # -V/-E (too much effort, and a real test would be huge)
+ # -c (because almost all the other tests test it anyway)
+ # -q (because, for now, I am lazy)
+ # -s (coming soon, hopefully)
+ # -o (really +o: again, hopefully soon)
+ # -o longname (again, just laziness, don't wait...)
+ # -h/-b (because NetBSD doesn't implement them)
+ atf_add_test_case set_a
+ atf_add_test_case set_C
+ atf_add_test_case set_e
+ atf_add_test_case set_f
+ atf_add_test_case set_n
+ atf_add_test_case set_u
+ atf_add_test_case set_v
+ atf_add_test_case set_x
+
+ atf_add_test_case vi_emacs_VE_toggle
+ atf_add_test_case xx_bogus
+}
diff --git a/contrib/netbsd-tests/bin/sh/t_redir.sh b/contrib/netbsd-tests/bin/sh/t_redir.sh
new file mode 100755
index 0000000..580de88
--- /dev/null
+++ b/contrib/netbsd-tests/bin/sh/t_redir.sh
@@ -0,0 +1,903 @@
+# $NetBSD: t_redir.sh,v 1.9 2016/05/14 00:33:02 kre Exp $
+#
+# Copyright (c) 2016 The NetBSD Foundation, Inc.
+# 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+#
+# 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' |
+ for l in 1 2 3; do
+ 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' |
+ for l in 1 2 3; do
+ 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' |
+ for l in 1 2 3; do
+ 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' |
+ l=''
+ while read line < File
+ do
+ echo "$line"
+ l="${l}x"
+ [ ${#l} -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' |
+ 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' |
+ l=''
+ while read line
+ do
+ echo "$line"
+ l="${l}x"
+ [ ${#l} -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' |
+ l=''
+ while read line1 <File
+ do
+ read line2
+ echo "$line1":"$line2"
+ l="${l}x"
+ [ ${#l} -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=$(expr "$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()
+{
+ atf_require_prog /bin/echo
+
+ cat <<- 'DONE' > helper.sh
+ f() {
+ /bin/echo nothing "$1" >& "$1"
+ }
+ for n
+ do
+ eval "f $n $n"'> file-$n'
+ done
+ DONE
+ cat <<- 'DONE' > reread.sh
+ f() {
+ (read -r var; echo "${var}") <&"$1"
+ }
+ for n
+ do
+ x=$( eval "f $n $n"'< file-$n' )
+ test "${x}" = "nothing $n" || echo "$n"
+ done
+ DONE
+
+ validate()
+ {
+ for n
+ do
+ test -e "file-$n" || atf_fail "file-$n not created"
+ C=$(cat file-"$n")
+ test "$C" = "nothing $n" ||
+ atf_fail "file-$n contains '$C' not 'nothing $n'"
+ done
+ }
+
+ atf_check -s exit:0 -e empty -o empty \
+ ${TEST_SH} helper.sh 1 2 3 4 5 6 7 8 9
+ validate 1 2 3 4 5 6 7 8 9
+ atf_check -s exit:0 -e empty -o empty \
+ ${TEST_SH} reread.sh 3 4 5 6 7 8 9
+
+ L=$(ulimit -n)
+ if [ "$L" -ge 30 ]
+ then
+ atf_check -s exit:0 -e empty -o empty \
+ ${TEST_SH} helper.sh 10 15 19 20 25 29
+ validate 10 15 19 20 25 29
+ atf_check -s exit:0 -e empty -o empty \
+ ${TEST_SH} reread.sh 10 15 19 20 25 29
+ fi
+ if [ "$L" -ge 100 ]
+ then
+ atf_check -s exit:0 -e empty -o empty \
+ ${TEST_SH} helper.sh 32 33 49 50 51 63 64 65 77 88 99
+ validate 32 33 49 50 51 63 64 65 77 88 99
+ atf_check -s exit:0 -e empty -o empty \
+ ${TEST_SH} reread.sh 32 33 49 50 51 63 64 65 77 88 99
+ fi
+ if [ "$L" -ge 500 ]
+ then
+ atf_check -s exit:0 -e empty -o empty \
+ ${TEST_SH} helper.sh 100 101 199 200 222 333 444 499
+ validate 100 101 199 200 222 333 444 499
+ atf_check -s exit:0 -e empty -o empty \
+ ${TEST_SH} reread.sh 100 101 199 200 222 333 444 499
+ fi
+ if [ "$L" -gt 1005 ]
+ then
+ atf_check -s exit:0 -e empty -o empty \
+ ${TEST_SH} helper.sh 1000 1001 1002 1003 1004 1005
+ validate 1000 1001 1002 1003 1004 1005
+ atf_check -s exit:0 -e empty -o empty \
+ ${TEST_SH} reread.sh 1000 1001 1002 1003 1004 1005
+ fi
+}
+
+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()
+{
+ cat <<- 'DONE' > helper.sh
+ for f
+ do
+ eval "exec $f"'> file-$f'
+ done
+
+ for f
+ do
+ printf '%s\n' "Hello $f" >&"$f"
+ done
+
+ for f
+ do
+ eval "exec $f"'>&-'
+ done
+
+ for f
+ do
+ eval "exec $f"'< file-$f'
+ done
+
+ for f
+ do
+ exec <& "$f"
+ read -r var || echo >&2 "No data in file-$f"
+ read -r x && echo >&2 "Too much data in file-${f}: $x"
+ test "${var}" = "Hello $f" ||
+ echo >&2 "file-$f contains '${var}' not 'Hello $f'"
+ done
+ DONE
+
+ atf_check -s exit:0 -o empty -e empty \
+ ${TEST_SH} helper.sh 3 4 5 6 7 8 9
+
+ L=$(ulimit -n)
+ if [ "$L" -ge 30 ]
+ then
+ atf_check -s exit:0 -o empty -e empty \
+ ${TEST_SH} helper.sh 10 11 13 15 16 19 20 28 29
+ fi
+ if [ "$L" -ge 100 ]
+ then
+ atf_check -s exit:0 -o empty -e empty \
+ ${TEST_SH} helper.sh 30 31 32 63 64 65 77 88 99
+ fi
+ if [ "$L" -ge 500 ]
+ then
+ atf_check -s exit:0 -o empty -e empty \
+ ${TEST_SH} helper.sh 100 101 111 199 200 201 222 333 499
+ fi
+ if [ "$L" -ge 1005 ]
+ then
+ atf_check -s exit:0 -o empty -e empty \
+ ${TEST_SH} helper.sh 1000 1001 1002 1003 1004 1005
+ fi
+}
+
+atf_test_case named_fd_redirections
+named_fd_redirections_head()
+{
+ atf_set "descr" "Tests redirections to /dev/stdout (etc)"
+
+}
+named_fd_redirections_body()
+{
+ if test -c /dev/stdout
+ then
+ atf_check -s exit:0 -o inline:'OK\n' -e empty \
+ ${TEST_SH} -c 'echo OK >/dev/stdout'
+ atf_check -s exit:0 -o inline:'OK\n' -e empty \
+ ${TEST_SH} -c '/bin/echo OK >/dev/stdout'
+ fi
+
+ if test -c /dev/stdin
+ then
+ atf_require_prog cat
+
+ echo GOOD | atf_check -s exit:0 -o inline:'GOOD\n' -e empty \
+ ${TEST_SH} -c 'read var </dev/stdin; echo $var'
+ echo GOOD | atf_check -s exit:0 -o inline:'GOOD\n' -e empty \
+ ${TEST_SH} -c 'cat </dev/stdin'
+ fi
+
+ if test -c /dev/stderr
+ then
+ atf_check -s exit:0 -e inline:'OK\n' -o empty \
+ ${TEST_SH} -c 'echo OK 2>/dev/stderr >&2'
+ atf_check -s exit:0 -e inline:'OK\n' -o empty \
+ ${TEST_SH} -c '/bin/echo OK 2>/dev/stderr >&2'
+ fi
+
+ if test -c /dev/fd/8 && test -c /dev/fd/9
+ then
+ atf_check -s exit:0 -o inline:'EIGHT\n' -e empty \
+ ${TEST_SH} -c 'printf "%s\n" EIGHT 8>&1 >/dev/fd/8 |
+ cat 9<&0 </dev/fd/9'
+ fi
+
+ return 0
+}
+
+atf_test_case redir_in_case
+redir_in_case_head()
+{
+ atf_set "descr" "Tests that sh(1) allows just redirections " \
+ "in case statements. (PR bin/48631)"
+}
+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()
+{
+ atf_set "descr" "Tests that sh(1) correctly processes 'here' doc " \
+ "input redirections"
+}
+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: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()
+{
+ atf_require_prog cat
+
+ LIM=$(ulimit -n)
+
+ cat <<- 'DONE' |
+ exec 6>output-file
+
+ ( printf "hello\n" >&6 )
+
+ exec 8<output-file
+
+ ( read hello <&8 ; test hello = "$hello" || echo >&2 Hello )
+
+ ( printf "bye-bye\n" >&6 )
+
+ ( exec 8<&- )
+ read bye <&8 || echo >&2 "Closed?"
+ echo Bye="$bye"
+ DONE
+ atf_check -s exit:0 -o match:Bye=bye-bye -e empty \
+ ${TEST_SH}
+
+ cat <<- 'DONE' |
+ for arg in one-4 two-24 three-14
+ do
+ fd=${arg#*-}
+ file=${arg%-*}
+ eval "exec ${fd}>${file}"
+ done
+
+ for arg in one-5 two-7 three-19
+ do
+ fd=${arg#*-}
+ file=${arg%-*}
+ eval "exec ${fd}<${file}"
+ done
+
+ (
+ echo line-1 >&4
+ echo line-2 >&24
+ echo line-3 >&14
+ echo go
+ ) | (
+ read go
+ read x <&5
+ read y <&7
+ read z <&19
+
+ printf "%s\n" "${x}" "${y}" "${z}"
+ )
+ DONE
+ atf_check -s exit:0 -o inline:'line-1\nline-2\nline-3\n' \
+ -e empty ${TEST_SH}
+
+ cat <<- 'DONE' |
+ for arg in one-4-5 two-6-7 three-8-9 four-11-10 five-3-12
+ do
+ ofd=${arg##*-}
+ file=${arg%-*}
+ ifd=${file#*-}
+ file=${file%-*}
+ eval "exec ${ofd}>${file}"
+ eval "exec ${ifd}<${file}"
+ done
+
+ ( ( ( echo line-1 >& 13 ) 13>&12 ) 12>&5 ) >stdout 2>errout
+ ( ( ( echo line-2 >& 4) 13>&12 ) 4>&7 ) >>stdout 2>>errout
+ ( ( ( echo line-3 >& 6) 8>&1 6>&11 >&12) 11>&9 >&7 ) >>stdout
+
+ ( ( ( cat <&13 >&12 ) 13<&8 12>&10 ) 10>&1 8<&6 ) 6<&4
+ ( ( ( cat <&4 ) <&4 6<&8 8<&11 )
+ <&4 4<&6 6<&8 8<&11 ) <&4 4<&6 6<&8 8<&11 11<&3
+ ( ( ( cat <&7 >&1 ) 7<&6 >&10 ) 10>&2 6<&8 ) 2>&1
+ DONE
+ atf_check -s exit:0 -o inline:'line-1\nline-2\nline-3\n' \
+ -e empty ${TEST_SH}
+}
+
+atf_test_case ulimit_redirection_interaction
+ulimit_redirection_interaction_head()
+{
+ atf_set "descr" "Tests interactions between redirect and ulimit -n "
+}
+ulimit_redirection_interaction_body()
+{
+ atf_require_prog ls
+
+ cat <<- 'DONE' > helper.sh
+ oLIM=$(ulimit -n)
+ HRD=$(ulimit -H -n)
+ test "${oLIM}" -lt "${HRD}" && ulimit -n "${HRD}"
+ LIM=$(ulimit -n)
+
+ FDs=
+ LFD=-1
+ while [ ${LIM} -gt 16 ]
+ do
+ FD=$(( ${LIM} - 1 ))
+ if [ "${FD}" -eq "${LFD}" ]; then
+ echo >&2 "Infinite loop... (busted $(( )) ??)"
+ exit 1
+ fi
+ LFD="${FD}"
+
+ eval "exec ${FD}"'> /dev/null'
+ FDs="${FD}${FDs:+ }${FDs}"
+
+ (
+ FD=$(( ${LIM} + 1 ))
+ eval "exec ${FD}"'> /dev/null'
+ echo "Reached unreachable command"
+ ) 2>/dev/null && echo >&2 "Opened beyond limit!"
+
+ (eval 'ls 2>&1 3>&1 4>&1 5>&1 '"${FD}"'>&1') >&"${FD}"
+
+ LIM=$(( ${LIM} / 2 ))
+ ulimit -S -n "${LIM}"
+ done
+
+ # Even though ulimit has been reduced, open fds should work
+ for FD in ${FDs}
+ do
+ echo ${FD} in ${FDs} >&"${FD}" || exit 1
+ done
+
+ ulimit -S -n "${oLIM}"
+
+ # maybe more later...
+
+ DONE
+
+ atf_check -s exit:0 -o empty -e empty ${TEST_SH} helper.sh
+}
+
+atf_test_case validate_fn_redirects
+validate_fn_redirects_head()
+{
+ # These test cases inspired by PR bin/48875 and the sh
+ # changes that were required to fix it.
+
+ atf_set "descr" "Tests various redirections applied to functions " \
+ "See PR bin/48875"
+}
+validate_fn_redirects_body()
+{
+ cat <<- 'DONE' > f-def
+ f() {
+ printf '%s\n' In-Func
+ }
+ DONE
+
+ atf_check -s exit:0 -o inline:'In-Func\nsuccess1\n' -e empty \
+ ${TEST_SH} -c ". ./f-def; f ; printf '%s\n' success1"
+ atf_check -s exit:0 -o inline:'success2\n' -e empty \
+ ${TEST_SH} -c ". ./f-def; f >/dev/null; printf '%s\n' success2"
+ atf_check -s exit:0 -o inline:'success3\n' -e empty \
+ ${TEST_SH} -c ". ./f-def; f >&- ; printf '%s\n' success3"
+ atf_check -s exit:0 -o inline:'In-Func\nsuccess4\n' -e empty \
+ ${TEST_SH} -c ". ./f-def; f & wait; printf '%s\n' success4"
+ atf_check -s exit:0 -o inline:'success5\n' -e empty \
+ ${TEST_SH} -c ". ./f-def; f >&- & wait; printf '%s\n' success5"
+ atf_check -s exit:0 -o inline:'In-Func\nIn-Func\nsuccess6\n' -e empty \
+ ${TEST_SH} -c ". ./f-def; f;f; printf '%s\n' success6"
+ atf_check -s exit:0 -o inline:'In-Func\nIn-Func\nsuccess7\n' -e empty \
+ ${TEST_SH} -c ". ./f-def; { f;f;}; printf '%s\n' success7"
+ atf_check -s exit:0 -o inline:'In-Func\nIn-Func\nsuccess8\n' -e empty \
+ ${TEST_SH} -c ". ./f-def; { f;f;}& wait; printf '%s\n' success8"
+ atf_check -s exit:0 -o inline:'In-Func\nsuccess9\n' -e empty \
+ ${TEST_SH} -c \
+ ". ./f-def; { f>/dev/null;f;}& wait; printf '%s\n' success9"
+ atf_check -s exit:0 -o inline:'In-Func\nsuccess10\n' -e empty \
+ ${TEST_SH} -c \
+ ". ./f-def; { f;f>/dev/null;}& wait; printf '%s\n' success10"
+
+ # This one tests the issue etcupdate had with the original 48875 fix
+ atf_check -s exit:0 -o inline:'Func a\nFunc b\nFunc c\n' -e empty \
+ ${TEST_SH} -c '
+ f() {
+ echo Func "$1"
+ }
+ exec 3<&0 4>&1
+ ( echo x-a; echo y-b; echo z-c ) |
+ while read A
+ do
+ B=${A#?-}
+ f "$B" <&3 >&4
+ done >&2'
+
+ # And this tests a similar condition with that same fix
+ cat <<- 'DONE' >Script
+ f() {
+ printf '%s' " hello $1"
+ }
+ exec 3>&1
+ echo $( for i in a b c
+ do printf '%s' @$i; f $i >&3; done >foo
+ )
+ printf '%s\n' foo=$(cat foo)
+ DONE
+ atf_check -s exit:0 -e empty \
+ -o inline:' hello a hello b hello c\nfoo=@a@b@c\n' \
+ ${TEST_SH} Script
+
+ # Tests with sh reading stdin, which is not quite the same internal
+ # mechanism.
+ echo ". ./f-def || echo >&2 FAIL
+ f
+ printf '%s\n' stdin1
+ "| atf_check -s exit:0 -o inline:'In-Func\nstdin1\n' -e empty ${TEST_SH}
+
+ echo '
+ . ./f-def || echo >&2 FAIL
+ f >&-
+ printf "%s\n" stdin2
+ ' | atf_check -s exit:0 -o inline:'stdin2\n' -e empty ${TEST_SH}
+
+ cat <<- 'DONE' > fgh.def
+ f() {
+ echo -n f >&3
+ sleep 4
+ echo -n F >&3
+ }
+ g() {
+ echo -n g >&3
+ sleep 2
+ echo -n G >&3
+ }
+ h() {
+ echo -n h >&3
+ }
+ DONE
+
+ atf_check -s exit:0 -o inline:'fFgGh' -e empty \
+ ${TEST_SH} -c '. ./fgh.def || echo >&2 FAIL
+ exec 3>&1
+ f; g; h'
+
+ atf_check -s exit:0 -o inline:'fghGF' -e empty \
+ ${TEST_SH} -c '. ./fgh.def || echo >&2 FAIL
+ exec 3>&1
+ f & sleep 1; g & sleep 1; h; wait'
+
+ atf_check -s exit:0 -o inline:'fFgGhX Y\n' -e empty \
+ ${TEST_SH} -c '. ./fgh.def || echo >&2 FAIL
+ exec 3>&1
+ echo X $( f ; g ; h ) Y'
+
+ # This one is the real test for PR bin/48875. If the
+ # cmdsub does not complete before f g (and h) exit,
+ # then the 'F' & 'G' will precede 'X Y' in the output.
+ # If the cmdsub finishes while f & g are still running,
+ # then the X Y will appear before the F and G.
+ # The trailing "sleep 3" is just so we catch all the
+ # output (otherwise atf_check will be finished while
+ # f & g are still sleeping).
+
+ atf_check -s exit:0 -o inline:'fghX Y\nGF' -e empty \
+ ${TEST_SH} -c '. ./fgh.def || echo >&2 FAIL
+ exec 3>&1
+ echo X $( f >&- & sleep 1; g >&- & sleep 1 ; h ) Y
+ sleep 3
+ exec 4>&1 || echo FD_FAIL
+ '
+
+ # Do the test again to verify it also all works reading stdin
+ # (which is a slightly different path through the shell)
+ echo '
+ . ./fgh.def || echo >&2 FAIL
+ exec 3>&1
+ echo X $( f >&- & sleep 1; g >&- & sleep 1 ; h ) Y
+ sleep 3
+ exec 4>&1 || echo FD_FAIL
+ ' | atf_check -s exit:0 -o inline:'fghX Y\nGF' -e empty ${TEST_SH}
+}
+
+atf_init_test_cases() {
+ 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 named_fd_redirections
+ atf_add_test_case redir_here_doc
+ atf_add_test_case redir_in_case
+ atf_add_test_case subshell_redirections
+ atf_add_test_case ulimit_redirection_interaction
+ atf_add_test_case validate_fn_redirects
+}
diff --git a/contrib/netbsd-tests/bin/sh/t_redircloexec.sh b/contrib/netbsd-tests/bin/sh/t_redircloexec.sh
new file mode 100755
index 0000000..7659606
--- /dev/null
+++ b/contrib/netbsd-tests/bin/sh/t_redircloexec.sh
@@ -0,0 +1,178 @@
+# $NetBSD: t_redircloexec.sh,v 1.3 2016/05/15 15:44:43 kre Exp $
+#
+# Copyright (c) 2016 The NetBSD Foundation, Inc.
+# All rights reserved.
+#
+# This code is derived from software contributed to The NetBSD Foundation
+# by Christos Zoulas.
+#
+# 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+#
+# the implementation of "sh" to test
+: ${TEST_SH:="/bin/sh"}
+
+mkhelper() {
+ name=$1
+ fd=$2
+ shift 2
+
+ echo "$@" > ./"${name}1"
+ echo "echo ${name}2" ">&${fd}" > ./"${name}2"
+}
+
+runhelper() {
+ ${TEST_SH} "./${1}1"
+}
+
+cleanhelper() {
+ # not really needed, atf cleans up...
+ rm -f ./"${1}1" ./"${1}2" out
+}
+
+atf_test_case exec_redir_closed
+exec_redir_closed_head() {
+ atf_set "descr" "Tests that redirections created by exec are closed on exec"
+}
+exec_redir_closed_body() {
+
+ mkhelper exec 6 \
+ "exec 6> out; echo exec1 >&6; ${TEST_SH} exec2; exec 6>&-"
+
+ atf_check -s exit:0 -o empty -e not-empty ${TEST_SH} ./exec1
+ atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -e ./exec1
+
+ mkhelper exec 9 \
+ "exec 9> out; echo exec1 >&9; ${TEST_SH} exec2"
+
+ atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} ./exec1
+
+ mkhelper exec 8 \
+ "exec 8> out; printf OK; echo exec1 >&8;" \
+ "printf OK; ${TEST_SH} exec2; printf ERR"
+
+ atf_check -s not-exit:0 -o match:OKOK -o not-match:ERR -e not-empty \
+ ${TEST_SH} -e ./exec1
+
+ mkhelper exec 7 \
+ "exec 7> out; printf OK; echo exec1 >&7;" \
+ "printf OK; ${TEST_SH} exec2 || printf ERR"
+
+ atf_check -s exit:0 -o match:OKOKERR -e not-empty \
+ ${TEST_SH} ./exec1
+
+ cleanhelper exec
+}
+
+atf_test_case exec_redir_open
+exec_redir_open_head() {
+ atf_set "descr" "Tests that redirections created by exec can remain open"
+}
+exec_redir_open_body() {
+
+ mkhelper exec 6 \
+ "exec 6> out 6>&6; echo exec1 >&6; ${TEST_SH} exec2; exec 6>&-"
+
+ atf_check -s exit:0 -o empty -e empty ${TEST_SH} ./exec1
+ atf_check -s exit:0 -o empty -e empty ${TEST_SH} -e ./exec1
+
+ mkhelper exec 9 \
+ "exec 9> out ; echo exec1 >&9; ${TEST_SH} exec2 9>&9"
+
+ atf_check -s exit:0 -o empty -e empty ${TEST_SH} ./exec1
+
+ mkhelper exec 8 \
+ "exec 8> out; printf OK; exec 8>&8; echo exec1 >&8;" \
+ "printf OK; ${TEST_SH} exec2; printf OK"
+
+ atf_check -s exit:0 -o match:OKOKOK -e empty \
+ ${TEST_SH} -e ./exec1
+
+ mkhelper exec 7 \
+ "exec 7> out; printf OK; echo exec1 >&7;" \
+ "printf OK; ${TEST_SH} 7>&7 exec2; printf OK"
+
+ atf_check -s exit:0 -o match:OKOKOK -e empty \
+ ${TEST_SH} -e ./exec1
+
+ cleanhelper exec
+}
+
+atf_test_case loop_redir_open
+loop_redir_open_head() {
+ atf_set "descr" "Tests that redirections in loops don't close on exec"
+}
+loop_redir_open_body() {
+ mkhelper for 3 "for x in x; do ${TEST_SH} ./for2; done 3>out"
+ atf_check -s exit:0 \
+ -o empty \
+ -e empty \
+ ${TEST_SH} ./for1
+ cleanhelper for
+}
+
+atf_test_case compound_redir_open
+compound_redir_open_head() {
+ atf_set "descr" "Tests that redirections in compound statements don't close on exec"
+}
+compound_redir_open_body() {
+ mkhelper comp 3 "{ ${TEST_SH} ./comp2; } 3>out"
+ atf_check -s exit:0 \
+ -o empty \
+ -e empty \
+ ${TEST_SH} ./comp1
+ cleanhelper comp
+}
+
+atf_test_case simple_redir_open
+simple_redir_open_head() {
+ atf_set "descr" "Tests that redirections in simple commands don't close on exec"
+}
+simple_redir_open_body() {
+ mkhelper simp 4 "${TEST_SH} ./simp2 4>out"
+ atf_check -s exit:0 \
+ -o empty \
+ -e empty \
+ ${TEST_SH} ./simp1
+ cleanhelper simp
+}
+
+atf_test_case subshell_redir_open
+subshell_redir_open_head() {
+ atf_set "descr" "Tests that redirections on subshells don't close on exec"
+}
+subshell_redir_open_body() {
+ mkhelper comp 5 "( ${TEST_SH} ./comp2; ${TEST_SH} ./comp2 ) 5>out"
+ atf_check -s exit:0 \
+ -o empty \
+ -e empty \
+ ${TEST_SH} ./comp1
+ cleanhelper comp
+}
+
+atf_init_test_cases() {
+ atf_add_test_case exec_redir_closed
+ atf_add_test_case exec_redir_open
+ atf_add_test_case loop_redir_open
+ atf_add_test_case compound_redir_open
+ atf_add_test_case simple_redir_open
+ atf_add_test_case subshell_redir_open
+}
diff --git a/contrib/netbsd-tests/bin/sh/t_set_e.sh b/contrib/netbsd-tests/bin/sh/t_set_e.sh
index 8dfe6e4..b56ab22 100755
--- a/contrib/netbsd-tests/bin/sh/t_set_e.sh
+++ b/contrib/netbsd-tests/bin/sh/t_set_e.sh
@@ -1,4 +1,4 @@
-# $NetBSD: t_set_e.sh,v 1.1 2012/03/17 16:33:11 jruoho Exp $
+# $NetBSD: t_set_e.sh,v 1.4 2016/03/31 16:22:27 christos Exp $
#
# Copyright (c) 2007 The NetBSD Foundation, Inc.
# All rights reserved.
@@ -30,7 +30,7 @@
# http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html
# the implementation of "sh" to test
-: ${TEST_SH:="sh"}
+: ${TEST_SH:="/bin/sh"}
failwith()
{
@@ -63,7 +63,7 @@ dcheck()
# is thus important to test. (PR bin/29861)
echeck()
{
- check1 'eval '"'($1)'" "$2" "eval '($1)'"
+ check1 'eval '"'( $1 )'" "$2" "eval '($1)'"
}
atf_test_case all
@@ -81,8 +81,8 @@ all_body() {
# first, check basic functioning.
# The ERR shouldn't print; the result of the () should be 1.
# Henceforth we'll assume that we don't need to check $?.
- dcheck '(set -e; false; echo ERR$?); echo -n OK$?' 'OK1'
- echeck '(set -e; false; echo ERR$?); echo -n OK$?' 'OK1'
+ dcheck '(set -e; false; echo ERR$?); echo OK$?' 'OK1'
+ echeck '(set -e; false; echo ERR$?); echo OK$?' 'OK1'
# these cases should be equivalent to the preceding.
dcheck '(set -e; /nonexistent; echo ERR); echo OK' 'OK'
@@ -205,6 +205,9 @@ all_body() {
# According to dsl@ in PR bin/32282, () is not defined as a
# subshell, only as a grouping operator [and a scope, I guess]
+
+ # (This is incorrect. () is definitely a sub-shell)
+
# so the nested false ought to cause the whole shell to exit,
# not just the subshell. dholland@ would like to see C&V,
# because that seems like a bad idea. (Among other things, it
@@ -215,8 +218,10 @@ all_body() {
#
# XXX: the second set has been disabled in the name of making
# all tests "pass".
+ #
+ # As they should be, they are utter nonsense.
- # 1. error if the whole shell exits (current behavior)
+ # 1. error if the whole shell exits (current correct behavior)
dcheck 'echo OK; (set -e; false); echo OK' 'OK OK'
echeck 'echo OK; (set -e; false); echo OK' 'OK OK'
# 2. error if the whole shell does not exit (dsl's suggested behavior)
@@ -232,29 +237,32 @@ all_body() {
# backquote expansion (PR bin/17514)
- # correct
+ # (in-)correct
#dcheck '(set -e; echo ERR `false`; echo ERR); echo OK' 'OK'
#dcheck '(set -e; echo ERR $(false); echo ERR); echo OK' 'OK'
#dcheck '(set -e; echo ERR `exit 3`; echo ERR); echo OK' 'OK'
#dcheck '(set -e; echo ERR $(exit 3); echo ERR); echo OK' 'OK'
- # wrong current behavior
+ # Not-wrong current behavior
+ # the exit status of ommand substitution is ignored in most cases
+ # None of these should be causing the shell to exit.
dcheck '(set -e; echo ERR `false`; echo ERR); echo OK' 'ERR ERR OK'
dcheck '(set -e; echo ERR $(false); echo ERR); echo OK' 'ERR ERR OK'
dcheck '(set -e; echo ERR `exit 3`; echo ERR); echo OK' 'ERR ERR OK'
dcheck '(set -e; echo ERR $(exit 3); echo ERR); echo OK' 'ERR ERR OK'
+ # This is testing one case (the case?) where the exit status is used
dcheck '(set -e; x=`false`; echo ERR); echo OK' 'OK'
dcheck '(set -e; x=$(false); echo ERR); echo OK' 'OK'
dcheck '(set -e; x=`exit 3`; echo ERR); echo OK' 'OK'
dcheck '(set -e; x=$(exit 3); echo ERR); echo OK' 'OK'
- # correct
+ # correct (really just commented out incorrect nonsense)
#echeck '(set -e; echo ERR `false`; echo ERR); echo OK' 'OK'
#echeck '(set -e; echo ERR $(false); echo ERR); echo OK' 'OK'
#echeck '(set -e; echo ERR `exit 3`; echo ERR); echo OK' 'OK'
#echeck '(set -e; echo ERR $(exit 3); echo ERR); echo OK' 'OK'
- # wrong current behavior
+ # not-wrong current behavior (as above)
echeck '(set -e; echo ERR `false`; echo ERR); echo OK' 'ERR ERR OK'
echeck '(set -e; echo ERR $(false); echo ERR); echo OK' 'ERR ERR OK'
echeck '(set -e; echo ERR `exit 3`; echo ERR); echo OK' 'ERR ERR OK'
@@ -267,11 +275,19 @@ all_body() {
# shift (PR bin/37493)
# correct
+ # Actually, both ways are correct, both are permitted
#dcheck '(set -e; shift || true; echo OK); echo OK' 'OK OK'
#echeck '(set -e; shift || true; echo OK); echo OK' 'OK OK'
- # wrong current behavior
- dcheck '(set -e; shift || true; echo OK); echo OK' 'OK'
- echeck '(set -e; shift || true; echo OK); echo OK' 'OK'
+ # (not-) wrong current behavior
+ #dcheck '(set -e; shift || true; echo OK); echo OK' 'OK'
+ #echeck '(set -e; shift || true; echo OK); echo OK' 'OK'
+
+ # what is wrong is this test assuming one behaviour or the other
+ # (and incidentally this has nothing whatever to do with "-e",
+ # the test should really be moved elsewhere...)
+ # But for now, leave it here, and correct it:
+ dcheck '(set -e; shift && echo OK); echo OK' 'OK'
+ echeck '(set -e; shift && echo OK); echo OK' 'OK'
# Done.
diff --git a/contrib/netbsd-tests/bin/sh/t_shift.sh b/contrib/netbsd-tests/bin/sh/t_shift.sh
new file mode 100755
index 0000000..f65c6c2
--- /dev/null
+++ b/contrib/netbsd-tests/bin/sh/t_shift.sh
@@ -0,0 +1,181 @@
+# $NetBSD: t_shift.sh,v 1.2 2016/05/17 09:05:14 kre Exp $
+#
+# Copyright (c) 2016 The NetBSD Foundation, Inc.
+# 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+#
+# the implementation of "sh" to test
+: ${TEST_SH:="/bin/sh"}
+
+atf_test_case basic_shift_test
+basic_shift_test_head() {
+ atf_set "descr" "Test correct operation of valid shifts"
+}
+basic_shift_test_body() {
+
+ for a in \
+ "one-arg::0:one-arg" \
+ "one-arg:1:0:one-arg" \
+ "one-arg:0:1 one-arg" \
+ "a b c::2 b c:a" \
+ "a b c:1:2 b c:a" \
+ "a b c:2:1 c:a:b" \
+ "a b c:3:0:a:b:c" \
+ "a b c:0:3 a b c" \
+ "a b c d e f g h i j k l m n o p:1:15 b c d e f g h i j k l m n o p"\
+ "a b c d e f g h i j k l m n o p:9:7 j k l m n o p:a:b:c:g:h:i" \
+ "a b c d e f g h i j k l m n o p:13:3 n o p:a:b:c:d:k:l:m" \
+ "a b c d e f g h i j k l m n o p:16:0:a:b:c:d:e:f:g:h:i:j:k:l:m:n:o:p"
+ do
+ oIFS="${IFS}"
+ IFS=:; set -- $a
+ IFS="${oIFS}"
+
+ init="$1"; n="$2"; res="$3"; shift 3
+
+ not=
+ for b
+ do
+ not="${not} -o not-match:$b"
+ done
+
+ atf_check -s exit:0 -o "match:${res}" ${not} -e empty \
+ ${TEST_SH} -c "set -- ${init}; shift $n;"' echo "$# $*"'
+ done
+
+ atf_check -s exit:0 -o match:complete -o not-match:ERR -e empty \
+ ${TEST_SH} -c \
+ 'set -- a b c d e;while [ $# -gt 0 ];do shift||echo ERR;done;echo complete'
+}
+
+atf_test_case excessive_shift
+excessive_shift_head() {
+ atf_set "descr" "Test acceptable operation of shift too many"
+}
+# In:
+#
+# http://pubs.opengroup.org/onlinepubs/9699919799
+# /utilities/V3_chap02.html#tag_18_26_01
+#
+# (that URL should be one line, with the /util... immediately after ...9799)
+#
+# POSIX says of shift (in the "EXIT STATUS" paragraph):
+#
+# If the n operand is invalid or is greater than "$#", this may be considered
+# a syntax error and a non-interactive shell may exit; if the shell does not
+# exit in this case, a non-zero exit status shall be returned.
+# Otherwise, zero shall be returned.
+#
+# NetBSD's sh treats it as an error and exits (if non-interactive, as here),
+# other shells do not.
+#
+# Either behaviour is acceptable - so the test allows for both
+# (and checks that if the shell does not exit, "shift" returns status != 0)
+
+excessive_shift_body() {
+ for a in \
+ "one-arg:2" \
+ "one-arg:4" \
+ "one-arg:13" \
+ "one two:3" \
+ "one two:7" \
+ "one two three four five:6" \
+ "I II III IV V VI VII VIII IX X XI XII XIII XIV XV:16" \
+ "I II III IV V VI VII VIII IX X XI XII XIII XIV XV:17" \
+ "I II III IV V VI VII VIII IX X XI XII XIII XIV XV:30" \
+ "I II III IV V VI VII VIII IX X XI XII XIII XIV XV:9999"
+ do
+ oIFS="${IFS}"
+ IFS=:; set -- $a
+ IFS="${oIFS}"
+
+ atf_check -s not-exit:0 -o match:OK -o not-match:ERR \
+ -e ignore ${TEST_SH} -c \
+ "set -- $1 ;"'echo OK:$#-'"$2;shift $2 && echo ERR"
+ done
+}
+
+atf_test_case function_shift
+function_shift_head() {
+ atf_set "descr" "Test that shift in a function does not affect outside"
+}
+function_shift_body() {
+ : # later...
+}
+
+atf_test_case non_numeric_shift
+non_numeric_shift_head() {
+ atf_set "descr" "Test that non-numeric args to shift are detected"
+}
+
+# from the DESCRIPTION section at the URL mentioned with the excessive_shift
+# test:
+#
+# The value n shall be an unsigned decimal integer ...
+#
+# That is not hex (octal will be treated as if it were decimal, a leading 0
+# will simply be ignored - we test for this by giving an "octal" value that
+# would be OK if parsed as octal, but not if parsed (correctly) as decimal)
+#
+# Obviously total trash like roman numerals or alphabetic strings are out.
+#
+# Also no signed values (no + or -) and not a string that looks kind of like
+# a number, but only if you're generous
+#
+# But as the EXIT STATUS section quoted above says, with an invalid 'n'
+# the shell has the option of exiting, or returning status != 0, so
+# again this test allows both.
+
+non_numeric_shift_body() {
+
+ # there are 9 args set, 010 is 8 if parsed octal, 10 decimal
+ for a in a I 0x12 010 5V -1 ' ' '' +1 ' 1'
+ do
+ atf_check -s not-exit:0 -o empty -e ignore ${TEST_SH} -c \
+ "set -- a b c d e f g h i; shift '$a' && echo ERROR"
+ done
+}
+
+atf_test_case too_many_args
+too_many_args_head() {
+ # See PR bin/50896
+ atf_set "descr" "Test that sh detects invalid extraneous args to shift"
+}
+# This is a syntax error, a non-interactive shell (us) must exit $? != 0
+too_many_args_body() {
+ # This tests the bug in PR bin/50896 is fixed
+
+ for a in "1 1" "1 0" "1 2 3" "1 foo" "1 --" "-- 1"
+ do
+ atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
+ " set -- a b c d; shift ${a} ; echo FAILED "
+ done
+}
+
+atf_init_test_cases() {
+ atf_add_test_case basic_shift_test
+ atf_add_test_case excessive_shift
+ atf_add_test_case function_shift
+ atf_add_test_case non_numeric_shift
+ atf_add_test_case too_many_args
+}
diff --git a/contrib/netbsd-tests/bin/sh/t_ulimit.sh b/contrib/netbsd-tests/bin/sh/t_ulimit.sh
index 3e7c0a6..094a2ee 100755
--- a/contrib/netbsd-tests/bin/sh/t_ulimit.sh
+++ b/contrib/netbsd-tests/bin/sh/t_ulimit.sh
@@ -1,4 +1,4 @@
-# $NetBSD: t_ulimit.sh,v 1.1 2012/06/11 18:32:59 njoly Exp $
+# $NetBSD: t_ulimit.sh,v 1.3 2016/03/27 14:50:01 christos Exp $
#
# Copyright (c) 2012 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"}
# ulimit builtin test.
@@ -31,13 +33,22 @@ atf_test_case limits
limits_head() {
atf_set "descr" "Checks for limits flags"
}
+
+get_ulimits() {
+ local limits=$(${TEST_SH} -c 'ulimit -a' |
+ sed -e 's/.*\(-[A-Za-z0-9]\)[^A-Za-z0-9].*/\1/' | sort -u)
+ if [ -z "$limits" ]; then
+ # grr ksh
+ limits="-a -b -c -d -f -l -m -n -p -r -s -t -v"
+ fi
+ echo "$limits"
+}
+
limits_body() {
- atf_check -s eq:0 -o ignore -e empty \
- /bin/sh -c "ulimit -a"
- for l in $(ulimit -a | sed 's,^.*(,,;s, .*$,,');
+ atf_check -s eq:0 -o ignore -e empty ${TEST_SH} -c "ulimit -a"
+ for l in $(get_ulimits)
do
- atf_check -s eq:0 -o ignore -e empty \
- /bin/sh -c "ulimit $l"
+ atf_check -s eq:0 -o ignore -e empty ${TEST_SH} -c "ulimit $l"
done
}
diff --git a/contrib/netbsd-tests/bin/sh/t_varquote.sh b/contrib/netbsd-tests/bin/sh/t_varquote.sh
index 1768777..3811d85 100755
--- a/contrib/netbsd-tests/bin/sh/t_varquote.sh
+++ b/contrib/netbsd-tests/bin/sh/t_varquote.sh
@@ -1,4 +1,4 @@
-# $NetBSD: t_varquote.sh,v 1.2 2012/03/25 18:50:19 christos Exp $
+# $NetBSD: t_varquote.sh,v 1.5 2016/03/27 14:50:01 christos Exp $
#
# Copyright (c) 2007 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"}
# Variable quoting test.
@@ -39,30 +41,70 @@ all_head() {
atf_set "descr" "Basic checks for variable quoting"
}
all_body() {
- foo='${a:-foo}'
- check "$foo" '${a:-foo}'
- foo="${a:-foo}"
- check "$foo" "foo"
+ cat <<-'EOF' > script.sh
+ T=0
+ check() {
+ T=$((${T} + 1))
- foo=${a:-"'{}'"}
- check "$foo" "'{}'"
+ if [ "$1" != "$2" ]
+ then
+ printf '%s\n' "T${T}: expected [$2], found [$1]"
+ exit 1
+ fi
+ }
- foo=${a:-${b:-"'{}'"}}
- check "$foo" "'{}'"
+ #1
+ foo='${a:-foo}'
+ check "$foo" '${a:-foo}'
+ #2
+ foo="${a:-foo}"
+ check "$foo" "foo"
+ #3
+ foo=${a:-"'{}'"}
+ check "$foo" "'{}'"
+ #4
+ foo=${a:-${b:-"'{}'"}}
+ check "$foo" "'{}'"
+ #5
+ # ${ } The ' are inside ".." so are literal (not quotes).
+ foo="${a-'}'}"
+ check "$foo" "''}"
+ #6
+ # The rules for quoting in ${var-word} expressions are somewhat
+ # weird, in the following there is not one quoted string being
+ # assigned to foo (with internally quoted sub-strings), rather
+ # it is a mixed quoted/unquoted string, with parts that are
+ # quoted, separated by 2 unquoted sections...
+ # qqqqqqqqqq uuuuuuuuuu qq uuuu qqqq
+ foo="${a:-${b:-"${c:-${d:-"x}"}}y}"}}z}"
+ # " z*"
+ # ${a:- }
+ # ${b:- }
+ # " y*"
+ # ${c:- }
+ # ${d:- }
+ # "x*"
+ check "$foo" "x}y}z}"
+ #7
+ # And believe it or not, this is the one that gives
+ # most problems, with 3 different observed outputs...
+ # qqqqq qq q is one interpretation
+ # qqqqq QQQQ q is another (most common)
+ # (the third is syntax error...)
+ foo="${a:-"'{}'"}"
+ check "$foo" "'{}'"
- foo="${a:-"'{}'"}"
- check "$foo" "'{}'"
+ EOF
- foo="${a:-${b:-"${c:-${d:-"x}"}}y}"}}z}"
- # " z*"
- # ${a:- }
- # ${b:- }
- # " y*"
- # ${c:- }
- # ${d:- }
- # "x*"
- check "$foo" "x}y}z}"
+ OUT=$( ${TEST_SH} script.sh 2>&1 )
+ if [ $? -ne 0 ]
+ then
+ atf_fail "${OUT}"
+ elif [ -n "${OUT}" ]
+ then
+ atf_fail "script.sh unexpectedly said: ${OUT}"
+ fi
}
atf_test_case nested_quotes_multiword
@@ -72,10 +114,21 @@ nested_quotes_multiword_head() {
}
nested_quotes_multiword_body() {
atf_check -s eq:0 -o match:"first-word second-word" -e empty \
- /bin/sh -c 'echo "${foo:="first-word"} second-word"'
+ ${TEST_SH} -c 'echo "${foo:="first-word"} second-word"'
+}
+
+atf_test_case default_assignment_with_arith
+default_assignment_with_arith_head() {
+ atf_set "descr" "Tests default variable assignment with arithmetic" \
+ "string works (PR bin/50827)"
+}
+default_assignment_with_arith_body() {
+ atf_check -s eq:0 -o empty -e empty ${TEST_SH} -c ': "${x=$((1))}"'
+ atf_check -s eq:0 -o match:1 -e empty ${TEST_SH} -c 'echo "${x=$((1))}"'
}
atf_init_test_cases() {
atf_add_test_case all
atf_add_test_case nested_quotes_multiword
+ atf_add_test_case default_assignment_with_arith
}
diff --git a/contrib/netbsd-tests/bin/sh/t_varval.sh b/contrib/netbsd-tests/bin/sh/t_varval.sh
new file mode 100755
index 0000000..94e306b
--- /dev/null
+++ b/contrib/netbsd-tests/bin/sh/t_varval.sh
@@ -0,0 +1,251 @@
+# $NetBSD: t_varval.sh,v 1.1 2016/03/16 15:49:19 christos Exp $
+#
+# Copyright (c) 2016 The NetBSD Foundation, Inc.
+# 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+#
+# the implementation of "sh" to test
+: ${TEST_SH:="/bin/sh"}
+
+# Test all kinds of weird values in various ways to use shell $... expansions
+
+oneline()
+{
+ q="'"
+ test $# -eq 4 && q=""
+
+ v=$( printf '\\%3.3o' $(( $2 & 0xFF )) )
+ printf "%s" "$1"
+ if [ $2 != 39 ]; then
+ printf "%sprefix${v}suffix%s" "$q" "$q"
+ elif [ $# -ne 4 ]; then
+ printf %s prefix\"\'\"suffix
+ else
+ printf %s prefix\'suffix
+ fi
+ printf "%s\n" "$3"
+}
+
+mkdata() {
+ quote= pfx=
+ while [ $# -gt 0 ]
+ do
+ case "$1" in
+ --) shift; break;;
+ -q) quote=no; shift; continue;;
+ esac
+
+ pfx="${pfx}${pfx:+ }${1}"
+ shift
+ done
+
+ sfx=
+ while [ $# -gt 0 ]
+ do
+ sfx="${sfx}${sfx:+ }${1}"
+ shift
+ done
+
+ i=1 # '\0' is not expected to work, anywhere...
+ while [ $i -lt 256 ]
+ do
+ oneline "${pfx}" "$i" "${sfx}" $quote
+ i=$(( $i + 1 ))
+ done
+}
+
+atf_test_case aaa
+aaa_head() {
+ atf_set "descr" "Check that this test has a hope of working. " \
+ "Just give up on these tests if the aaa test fails".
+}
+aaa_body() {
+ oneline "echo " 9 '' |
+ atf_check -s exit:0 -o inline:'prefix\tsuffix\n' -e empty \
+ ${TEST_SH}
+
+ oneline "VAR=" 65 '; echo "${#VAR}:${VAR}"' |
+ atf_check -s exit:0 -o inline:'13:prefixAsuffix\n' -e empty \
+ ${TEST_SH}
+
+ oneline "VAR=" 1 '; echo "${#VAR}:${VAR}"' |
+ atf_check -s exit:0 -o inline:'13:prefixsuffix\n' -e empty \
+ ${TEST_SH}
+
+ oneline "VAR=" 10 '; echo "${#VAR}:${VAR}"' |
+ atf_check -s exit:0 -o inline:'13:prefix\nsuffix\n' -e empty \
+ ${TEST_SH}
+
+ rm -f prefix* 2>/dev/null || :
+ oneline "echo hello >" 45 "" |
+ atf_check -s exit:0 -o empty -e empty ${TEST_SH}
+ test -f "prefix-suffix" ||
+ atf_fail "failed to create prefix-suffix (45)"
+ test -s "prefix-suffix" ||
+ atf_fail "no data in prefix-suffix (45)"
+ test "$(cat prefix-suffix)" = "hello" ||
+ atf_fail "incorrect data in prefix-suffix (45)"
+
+ return 0
+}
+
+atf_test_case assignment
+assignment_head() {
+ atf_set "descr" "Check that all chars can be assigned to vars"
+}
+assignment_body() {
+ atf_require_prog grep
+ atf_require_prog rm
+
+ rm -f results || :
+ mkdata "VAR=" -- '; echo ${#VAR}' |
+ atf_check -s exit:0 -o save:results -e empty ${TEST_SH}
+ test -z $( grep -v "^13$" results ) ||
+ atf_fail "Incorrect lengths: $(grep -nv '^13$' results)"
+
+ return 0
+}
+
+atf_test_case cmdline
+cmdline_head() {
+ atf_set "descr" "Check vars containing all chars can be used"
+}
+cmdline_body() {
+ atf_require_prog rm
+ atf_require_prog wc
+
+ rm -f results || :
+ mkdata "VAR=" -- '; echo "${VAR}"' |
+ atf_check -s exit:0 -o save:results -e empty ${TEST_SH}
+
+ # 256 because one output line contains a \n ...
+ test $( wc -l < results ) -eq 256 ||
+ atf_fail "incorrect line count in results"
+ test $(wc -c < results) -eq $(( 255 * 14 )) ||
+ atf_fail "incorrect character count in results"
+
+ return 0
+}
+
+atf_test_case redirect
+redirect_head() {
+ atf_set "descr" "Check vars containing all chars can be used"
+}
+redirect_body() {
+ atf_require_prog ls
+ atf_require_prog wc
+ atf_require_prog rm
+ atf_require_prog mkdir
+ atf_require_prog rmdir
+
+ nl='
+'
+
+ rm -f prefix* suffix || :
+
+ mkdir prefix # one of the files will be prefix/suffix
+ mkdata "VAR=" -- '; echo "${VAR}" > "${VAR}"' |
+ atf_check -s exit:0 -o empty -e empty ${TEST_SH}
+
+ test -f "prefix/suffix" ||
+ atf_fail "Failed to create file in subdirectory"
+ test $( wc -l < "prefix/suffix" ) -eq 1 ||
+ atf_fail "Not exactly one line in prefix/suffix file"
+
+ atf_check -s exit:0 -o empty -e empty rm "prefix/suffix"
+ atf_check -s exit:0 -o empty -e empty rmdir "prefix"
+
+ test -f "prefix${nl}suffix" ||
+ atf_fail "Failed to create file with newline in its name"
+ test $( wc -l < "prefix${nl}suffix" ) -eq 2 ||
+ atf_fail "NewLine file did not contain embedded newline"
+
+ atf_check -s exit:0 -o empty -e empty rm "prefix${nl}suffix"
+
+ # Now there should be 253 files left...
+ test $( ls | wc -l ) -eq 253 ||
+ atf_fail \
+ "Did not create all expected files: wanted: 253, found ($( ls | wc -l ))"
+
+ # and each of them should have a name that is 13 chars long (+ \n)
+ test $( ls | wc -c ) -eq $(( 253 * 14 )) ||
+ atf_fail "File names do not appear to be as expected"
+
+ return 0
+}
+
+atf_test_case read
+read_head() {
+ atf_set "descr" "Check vars containing all chars can be used"
+}
+read_body() {
+ atf_require_prog ls
+ atf_require_prog wc
+ atf_require_prog rm
+ atf_require_prog mkdir
+ atf_require_prog rmdir
+
+ nl='
+'
+
+ rm -f prefix* suffix || :
+
+ mkdir prefix # one of the files will be prefix/suffix
+ mkdata -q |
+ atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c '
+ while read -r VAR
+ do
+ # skip the mess made by embedded newline
+ case "${VAR}" in
+ (prefix | suffix) continue;;
+ esac
+ echo "${VAR}" > "${VAR}"
+ done'
+
+ test -f "prefix/suffix" ||
+ atf_fail "Failed to create file in subdirectory"
+ test $( wc -l < "prefix/suffix" ) -eq 1 ||
+ atf_fail "Not exactly one line in prefix/suffix file"
+
+ atf_check -s exit:0 -o empty -e empty rm "prefix/suffix"
+ atf_check -s exit:0 -o empty -e empty rmdir "prefix"
+
+ # Now there should be 253 files left...
+ test $( ls | wc -l ) -eq 253 ||
+ atf_fail \
+ "Did not create all expected files: wanted: 253, found ($( ls | wc -l ))"
+
+ # and each of them should have a name that is 13 chars long (+ \n)
+ test $( ls | wc -c ) -eq $(( 253 * 14 )) ||
+ atf_fail "File names do not appear to be as expected"
+
+ return 0
+}
+
+atf_init_test_cases() {
+ atf_add_test_case aaa
+ atf_add_test_case assignment
+ atf_add_test_case cmdline
+ atf_add_test_case redirect
+ atf_add_test_case read
+}
diff --git a/contrib/netbsd-tests/bin/sh/t_wait.sh b/contrib/netbsd-tests/bin/sh/t_wait.sh
index 99b47df..eaad7e0 100755
--- a/contrib/netbsd-tests/bin/sh/t_wait.sh
+++ b/contrib/netbsd-tests/bin/sh/t_wait.sh
@@ -1,4 +1,4 @@
-# $NetBSD: t_wait.sh,v 1.1 2012/03/17 16:33:11 jruoho Exp $
+# $NetBSD: t_wait.sh,v 1.8 2016/03/31 16:22:54 christos Exp $
#
# Copyright (c) 2008, 2009, 2010 The NetBSD Foundation, Inc.
# All rights reserved.
@@ -24,36 +24,172 @@
# 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"}
+
+atf_test_case basic_wait
+basic_wait_head() {
+ atf_set "descr" "Tests simple uses of wait"
+}
+basic_wait_body() {
+ atf_require_prog sleep
+
+ atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
+ '(echo nothing >/dev/null) & wait'
+
+ atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
+ '(exit 3) & wait $!; S=$?; test $S -eq 3 || {
+ echo "status: $S"; exit 1; }'
+
+ atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
+ 'sleep 3 & sleep 2 & sleep 1 & wait'
+
+ atf_check -s exit:0 -o empty -e empty ${TEST_SH} -c \
+ 'sleep 3 & (exit 2) & sleep 1 & wait'
+}
atf_test_case individual
individual_head() {
- atf_set "descr" "Tests that waiting for individual jobs works"
+ atf_set "descr" "Tests that waiting for individual processes works"
}
individual_body() {
+ atf_require_prog sleep
+
+ cat >individualhelper.sh <<\EOF
+sleep 3 & P1=$!
+sleep 1 & P2=$!
+
+wait ${P1}
+S=$?
+if [ $S -ne 0 ]; then
+ echo "Waiting for first process failed: $S"
+ exit 1
+fi
+
+wait ${P2}
+S=$?
+if [ $? -ne 0 ]; then
+ echo "Waiting for second process failed"
+ exit 1
+fi
+
+exit 0
+EOF
+ output=$(${TEST_SH} individualhelper.sh 2>&1)
+ [ $? -eq 0 ] || atf_fail "${output}"
+}
+
+atf_test_case jobs
+jobs_head() {
+ atf_set "descr" "Tests that waiting for individual jobs works"
+}
+jobs_body() {
# atf-sh confuses wait for some reason; work it around by creating
# a helper script that executes /bin/sh directly.
- cat >helper.sh <<EOF
+
+ if ! ${TEST_SH} -c 'sleep 1 & wait %1' 2>/dev/null
+ then
+ atf_skip "No job control support in this shell"
+ fi
+
+ cat >individualhelper.sh <<\EOF
sleep 3 &
sleep 1 &
wait %1
-if [ \$? -ne 0 ]; then
- echo "Waiting of first job failed"
+if [ $? -ne 0 ]; then
+ echo "Waiting for first job failed"
+ exit 1
+fi
+
+wait %2
+if [ $? -ne 0 ]; then
+ echo "Waiting for second job failed"
+ exit 1
+fi
+
+exit 0
+EOF
+ output=$(${TEST_SH} individualhelper.sh 2>&1)
+ [ $? -eq 0 ] || atf_fail "${output}"
+
+ cat >individualhelper.sh <<\EOF
+{ sleep 3; exit 3; } &
+{ sleep 1; exit 7; } &
+
+wait %1
+S=$?
+if [ $S -ne 3 ]; then
+ echo "Waiting for first job failed - status: $S != 3 (expected)"
exit 1
fi
wait %2
-if [ \$? -ne 0 ]; then
- echo "Waiting of second job failed"
+S=$?
+if [ $S -ne 7 ]; then
+ echo "Waiting for second job failed - status: $S != 7 (expected)"
exit 1
fi
exit 0
EOF
- output=$(/bin/sh helper.sh)
+
+ output=$(${TEST_SH} individualhelper.sh 2>&1)
[ $? -eq 0 ] || atf_fail "${output}"
}
+atf_test_case kill
+kill_head() {
+ atf_set "descr" "Tests that killing the shell while in wait calls trap"
+}
+kill_body() {
+ atf_require_prog sleep
+ atf_require_prog kill
+
+ s=killhelper.sh
+ z=killhelper.$$
+ pid=
+
+ # waiting for a specific process that is not a child
+ # should return exit status of 127 according to the spec
+ # This test is here before the next, to avoid that one
+ # entering an infinite loop should the shell have a bug here.
+
+ atf_check -s exit:127 -o empty -e ignore ${TEST_SH} -c 'wait 1'
+
+ cat > "${s}" <<'EOF'
+
+trap "echo SIGHUP" 1
+(sleep 5; exit 3) &
+sl=$!
+wait
+S=$?
+echo $S
+LS=9999
+while [ $S -ne 0 ] && [ $S != 127 ]; do
+ wait $sl; S=$?; echo $S
+ test $S = $LS && { echo "wait repeats..."; exit 2; }
+ LS=$S
+ done
+EOF
+
+ ${TEST_SH} $s > $z &
+ pid=$!
+ sleep 1
+
+ kill -HUP "${pid}"
+ wait
+
+ output="$(cat $z | tr '\n' ' ')"
+
+ if [ "$output" != "SIGHUP 129 3 127 " ]; then
+ atf_fail "${output} != 'SIGHUP 129 3 127 '"
+ fi
+}
+
atf_init_test_cases() {
+ atf_add_test_case basic_wait
atf_add_test_case individual
+ atf_add_test_case jobs
+ atf_add_test_case kill
}
OpenPOWER on IntegriCloud