summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorJari Aalto <jari.aalto@cante.net>1997-06-05 14:59:13 +0000
committerJari Aalto <jari.aalto@cante.net>2009-09-12 16:46:50 +0000
commitd166f048818e10cf3799aa24a174fb22835f1acc (patch)
tree1ca27f9243900f8b236d0cde6a3862002aea9e19 /tests
parentccc6cda312fea9f0468ee65b8f368e9653e1380b (diff)
downloadbash-d166f048818e10cf3799aa24a174fb22835f1acc.tar.gz
Imported from ../bash-2.01.tar.gz.
Diffstat (limited to 'tests')
-rw-r--r--tests/arith.right26
-rw-r--r--tests/arith.tests57
-rw-r--r--tests/array.right21
-rw-r--r--tests/array.tests82
-rw-r--r--tests/braces-tests4
-rw-r--r--tests/braces.right3
-rw-r--r--tests/builtins.right113
-rw-r--r--tests/builtins.sub114
-rw-r--r--tests/builtins.tests201
-rw-r--r--tests/dirstack.right51
-rw-r--r--tests/dirstack.tests79
-rwxr-xr-xtests/dollar-star.sh8
-rw-r--r--tests/dollar.right2
-rw-r--r--tests/errors.right73
-rw-r--r--tests/errors.tests203
-rw-r--r--tests/execscript78
-rw-r--r--tests/execscript.right36
-rwxr-xr-xtests/execscript.sub1
-rw-r--r--tests/execscript.sub25
-rw-r--r--tests/execscript.sub36
-rw-r--r--tests/execscript.sub48
-rw-r--r--tests/exp-tests32
-rw-r--r--tests/exp.right11
-rw-r--r--tests/func.right28
-rw-r--r--tests/func.tests119
-rw-r--r--tests/getopts.right56
-rw-r--r--tests/getopts.sub1 (renamed from tests/misc/gotest)0
-rw-r--r--tests/getopts.sub226
-rw-r--r--tests/getopts.sub327
-rw-r--r--tests/getopts.sub430
-rw-r--r--tests/getopts.sub550
-rw-r--r--tests/getopts.sub627
-rw-r--r--tests/getopts.sub730
-rw-r--r--tests/getopts.tests38
-rw-r--r--tests/glob-test152
-rw-r--r--tests/glob.right45
-rw-r--r--tests/heredoc.right31
-rw-r--r--tests/heredoc.tests49
-rw-r--r--tests/histexpand.right127
-rw-r--r--tests/histexpand.tests112
-rw-r--r--tests/history.list4
-rw-r--r--tests/history.right104
-rw-r--r--tests/history.tests83
-rw-r--r--tests/jobs.right71
-rw-r--r--tests/jobs.tests145
-rw-r--r--tests/minus-e6
-rw-r--r--tests/minus-e.right1
-rwxr-xr-xtests/misc/chld-trap.sh14
-rw-r--r--tests/misc/dot-test-1.sh3
-rw-r--r--tests/misc/dot-test-1.sub1
-rw-r--r--tests/misc/haertel.perftest9
-rwxr-xr-xtests/misc/redir.t3.sh8
-rw-r--r--tests/misc/redir.t3.sub1
-rw-r--r--tests/misc/redir.t4.sh12
-rwxr-xr-xtests/misc/run.r1.sh1
-rwxr-xr-xtests/misc/run.r3.sh3
-rw-r--r--tests/misc/test-minus-e.13
-rw-r--r--tests/misc/test-minus-e.23
-rw-r--r--tests/new-exp.right168
-rw-r--r--tests/new-exp.sub111
-rw-r--r--tests/new-exp.tests96
-rw-r--r--tests/nquote.right1
-rw-r--r--tests/nquote.tests6
-rw-r--r--tests/read.right12
-rw-r--r--tests/read.tests45
-rw-r--r--tests/redir.right47
-rw-r--r--tests/redir.tests147
-rw-r--r--tests/redir1.sub8
-rw-r--r--tests/redir2.sub1
-rw-r--r--tests/redir3.in12
-rw-r--r--tests/redir3.in22
-rw-r--r--tests/redir3.sub (renamed from tests/misc/redir.t1.sh)2
-rw-r--r--tests/redir4.in11
-rw-r--r--tests/redir4.sub56
-rw-r--r--tests/rsh.right12
-rw-r--r--tests/rsh.tests32
-rw-r--r--tests/run-all14
-rw-r--r--tests/run-builtins2
-rw-r--r--tests/run-dirstack2
-rw-r--r--tests/run-errors2
-rw-r--r--tests/run-execscript7
-rw-r--r--tests/run-func5
-rw-r--r--tests/run-getopts2
-rw-r--r--tests/run-histexpand4
-rw-r--r--tests/run-history4
-rw-r--r--tests/run-jobs5
-rw-r--r--tests/run-minimal33
-rw-r--r--tests/run-minus-e2
-rw-r--r--tests/run-redir6
-rw-r--r--tests/run-rsh2
-rw-r--r--tests/run-test2
-rw-r--r--tests/run-trap2
-rw-r--r--tests/run-type2
-rw-r--r--tests/set-e-test50
-rw-r--r--tests/set-e.right10
-rw-r--r--tests/source.sub11
-rw-r--r--tests/source.sub25
-rw-r--r--tests/source.sub31
-rw-r--r--tests/source.sub41
-rw-r--r--tests/test-tests133
-rw-r--r--tests/test.right68
-rw-r--r--tests/tilde-tests27
-rw-r--r--tests/tilde.right5
-rw-r--r--tests/trap.right51
-rwxr-xr-xtests/trap.sub14
-rw-r--r--tests/trap.tests58
-rw-r--r--tests/type.right41
-rw-r--r--tests/type.tests60
-rw-r--r--tests/varenv.right19
-rw-r--r--tests/varenv.sh64
-rw-r--r--tests/version8
-rw-r--r--tests/version.mini8
112 files changed, 3757 insertions, 135 deletions
diff --git a/tests/arith.right b/tests/arith.right
index a369bd89..54c087d2 100644
--- a/tests/arith.right
+++ b/tests/arith.right
@@ -89,3 +89,29 @@
./arith.tests: let: rv = 7 + (43 * 6: missing `)' (error token is "6")
./arith.tests: 0#4: bad number (error token is "0#4")
./arith.tests: 2#110#11: bad number (error token is "2#110#11")
+abc
+def
+ghi
+ok
+6
+1
+0
+./arith.tests: 4 + : syntax error: operand expected (error token is " ")
+16
+./arith.tests: 4 ? : 3 + 5 : expression expected (error token is ": 3 + 5 ")
+./arith.tests: 1 ? 20 : `:' expected for conditional expression (error token is " ")
+./arith.tests: 4 ? 20 : : expression expected (error token is " ")
+9
+./arith.tests: 0 && B=42 : attempted assignment to non-variable (error token is "=42 ")
+9
+./arith.tests: 1 || B=88 : attempted assignment to non-variable (error token is "=88 ")
+9
+0
+9
+0
+9
+1
+9
+7
+7
+4
diff --git a/tests/arith.tests b/tests/arith.tests
index 6bad3125..5f6298ca 100644
--- a/tests/arith.tests
+++ b/tests/arith.tests
@@ -1,3 +1,4 @@
+set +o posix
declare -i iv jv
iv=$(( 3 + 5 * 32 ))
@@ -156,3 +157,59 @@ let 'rv = 7 + (43 * 6'
declare -i i
i=0#4
i=2#110#11
+
+((echo abc; echo def;); echo ghi)
+
+if (((4+4) + (4 + 7))); then
+ echo ok
+fi
+
+(()) # make sure the null expression works OK
+
+a=(0 2 4 6)
+echo $(( a[1] + a[2] ))
+echo $(( (a[1] + a[2]) == a[3] ))
+(( (a[1] + a[2]) == a[3] )) ; echo $?
+
+# test pushing and popping the expression stack
+unset A
+A="4 + "
+echo $(( ( 4 + A ) + 4 ))
+A="3 + 5"
+echo $(( ( 4 + A ) + 4 ))
+
+# badly-formed conditional expressions
+echo $(( 4 ? : $A ))
+echo $(( 1 ? 20 ))
+echo $(( 4 ? 20 : ))
+
+# precedence and short-circuit evaluation
+B=9
+echo $B
+
+echo $(( 0 && B=42 ))
+echo $B
+
+echo $(( 1 || B=88 ))
+echo $B
+
+echo $(( 0 && (B=42) ))
+echo $B
+
+echo $(( (${$} - $$) && (B=42) ))
+echo $B
+
+echo $(( 1 || (B=88) ))
+echo $B
+
+# until command with (( )) command
+x=7
+
+echo $x
+until (( x == 4 ))
+do
+ echo $x
+ x=4
+done
+
+echo $x
diff --git a/tests/array.right b/tests/array.right
index d4a3398d..e142fdbc 100644
--- a/tests/array.right
+++ b/tests/array.right
@@ -1,4 +1,5 @@
abcde
+abcde
abcde bdef
abcde bdef
declare -a DIRSTACK='()'
@@ -52,12 +53,12 @@ declare -a f='([0]="" [1]="bdef" [2]="hello world" [3]="test" [4]="ninth element
this of
this is a test of read using arrays
declare -a DIRSTACK='()'
-declare -a rv='([0]="this" [1]="is" [2]="a" [3]="test" [4]="of" [5]="read" [6]="using" [7]="arrays")'
declare -ar a='([1]="" [2]="bdef" [5]="hello world" [6]="test expression")'
declare -a b='([0]="this" [1]="is" [2]="a" [3]="test" [4]="" [5]="/etc/passwd")'
declare -ar c='()'
declare -a d='([1]="test test" [2]="bdef" [5]="hello world" [6]="test" [9]="ninth element")'
declare -a f='([0]="" [1]="bdef" [2]="hello world" [3]="test" [4]="ninth element")'
+declare -a rv='([0]="this" [1]="is" [2]="a" [3]="test" [4]="of" [5]="read" [6]="using" [7]="arrays")'
abde
abde
bbb
@@ -76,3 +77,21 @@ b c
d
e f g
h
+/bin /usr/bin /usr/ucb /usr/local/bin . /sbin /usr/sbin
+bin bin ucb bin . sbin sbin
+bin
+/ / / / / /
+/
+\bin \usr/bin \usr/ucb \usr/local/bin . \sbin \usr/sbin
+\bin \usr\bin \usr\ucb \usr\local\bin . \sbin \usr\sbin
+\bin \usr\bin \usr\ucb \usr\local\bin . \sbin \usr\sbin
+4 -- 4
+7 -- 7
+55
+49
+6 -- 6
+42 14 44
+grep [ 123 ] *
+6 7 9
+6 7 9 5
+./array.tests: narray: unbound variable
diff --git a/tests/array.tests b/tests/array.tests
index 2ee376bb..0b030805 100644
--- a/tests/array.tests
+++ b/tests/array.tests
@@ -1,6 +1,17 @@
+# this is needed so that the bad assignments (b[]=bcde, for example) do not
+# cause fatal shell errors when in posix mode
+set +o posix
+
set +a
# The calls to egrep -v are to filter out builtin array variables that are
# automatically set and possibly contain values that vary.
+
+# make sure declare -a converts an existing variable to an array
+unset a
+a=abcde
+declare -a a
+echo ${a[0]}
+
unset a
a=abcde
a[2]=bdef
@@ -23,7 +34,7 @@ echo ${a[@]}
echo ${a[*]}
# this should print out values, too
-declare -a | egrep -v '(BASH_VERSINFO|PIPESTATUS)'
+declare -a | egrep -v '(BASH_VERSINFO|PIPESTATUS|GROUPS)'
unset a[7]
echo ${a[*]}
@@ -51,8 +62,8 @@ echo ${a[@]}
readonly a[5]
readonly a
-readonly -a | egrep -v '(BASH_VERSINFO|PIPESTATUS)'
-declare -ar | egrep -v '(BASH_VERSINFO|PIPESTATUS)'
+readonly -a | egrep -v '(BASH_VERSINFO|PIPESTATUS|GROUPS)'
+declare -ar | egrep -v '(BASH_VERSINFO|PIPESTATUS|GROUPS)'
declare -a d='([1]="" [2]="bdef" [5]="hello world" "test")'
d[9]="ninth element"
@@ -66,7 +77,7 @@ b=([0]=this [1]=is [2]=a [3]=test [4]="$PS1" [5]=$pass)
echo ${b[@]:2:3}
-declare -a | egrep -v '(BASH_VERSINFO|PIPESTATUS)'
+declare -pa | egrep -v '(BASH_VERSINFO|PIPESTATUS|GROUPS)'
a[3]="this is a test"
@@ -84,7 +95,7 @@ d=([]=abcde [1]="test test" [*]=last [-65]=negative )
unset d[12]
unset e[*]
-declare -a | egrep -v '(BASH_VERSINFO|PIPESTATUS)'
+declare -a | egrep -v '(BASH_VERSINFO|PIPESTATUS|GROUPS)'
ps1='hello'
unset ps1[2]
@@ -101,7 +112,7 @@ this is a test of read using arrays
echo ${rv[0]} ${rv[4]}
echo ${rv[@]}
-declare -a | egrep -v '(BASH_VERSINFO|PIPESTATUS)'
+declare -a | egrep -v '(BASH_VERSINFO|PIPESTATUS|GROUPS)'
export rv
#set
@@ -129,3 +140,62 @@ for z in "$@"
do
echo "$z"
done
+
+# do various pattern removal and length tests
+XPATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:.:/sbin:/usr/sbin
+
+xpath=( $( IFS=: ; echo $XPATH ) )
+
+echo ${xpath[@]}
+echo ${xpath[@]##*/}
+echo ${xpath[0]##*/}
+echo ${xpath[@]%%[!/]*}
+echo ${xpath[0]%%[!/]*}
+
+# let's try to make it a DOS-style path
+
+zecho "${xpath[@]/\//\\}"
+zecho "${xpath[@]//\//\\}"
+zecho "${xpath[@]//[\/]/\\}"
+
+# length of the first element of the array, since array without subscript
+# is equivalent to referencing first element
+echo ${#xpath} -- ${#xpath[0]}
+
+# number of elements in the array
+nelem=${#xpath[@]}
+echo ${#xpath[@]} -- $nelem
+
+# total length of all elements in the array, including space separators
+xx="${xpath[*]}"
+echo ${#xx}
+
+# total length of all elements in the array
+xx=$( IFS='' ; echo "${xpath[*]}" )
+echo ${#xx}
+
+unset xpath[nelem-1]
+
+nelem=${#xpath[@]}
+echo ${#xpath[@]} -- $nelem
+
+# arrays and things that look like index assignments
+array=(42 [1]=14 [2]=44)
+
+array2=(grep [ 123 ] \*)
+
+echo ${array[@]}
+echo "${array2[@]}"
+
+# arrays and implicit arithmetic evaluation
+declare -i -a iarray
+
+iarray=( 2+4 1+6 7+2 )
+echo ${iarray[@]}
+
+iarray[4]=4+1
+echo ${iarray[@]}
+
+# make sure the array code behaves correctly with respect to unset variables
+set -u
+( echo ${#narray[4]} )
diff --git a/tests/braces-tests b/tests/braces-tests
index bd8ff822..d31a5e3d 100644
--- a/tests/braces-tests
+++ b/tests/braces-tests
@@ -18,3 +18,7 @@ echo { }
echo }
echo {
echo abcd{efgh
+
+echo foo {1,2} bar
+echo `zecho foo {1,2} bar`
+echo $(zecho foo {1,2} bar)
diff --git a/tests/braces.right b/tests/braces.right
index 52cc6383..d35e08d0 100644
--- a/tests/braces.right
+++ b/tests/braces.right
@@ -14,3 +14,6 @@ XXXXa XXXXb XXXXc
}
{
abcd{efgh
+foo 1 2 bar
+foo 1 2 bar
+foo 1 2 bar
diff --git a/tests/builtins.right b/tests/builtins.right
new file mode 100644
index 00000000..5cf5875e
--- /dev/null
+++ b/tests/builtins.right
@@ -0,0 +1,113 @@
+a
+end-1
+a
+end-2
+a:x
+end-a
+b:x
+end-b
+c:x
+end-c
+end-3
+a:x
+end
+a
+b
+c
+end-1
+a
+b
+c
+end-2
+a:x
+a:y
+a:z
+end-a
+b:x
+b:y
+b:z
+end-b
+c:x
+c:y
+c:z
+end-c
+end-3
+a:x
+b:x
+c:x
+end
+$BVAR
+$BVAR
+$BVAR
+$BVAR
+foo
+bar
+xxx
+022
+u=rwx,g=rx,o=rx
+002
+u=rwx,g=rwx,o=rx
+u=rwx,g=rwx,o=rwx
+enable .
+enable :
+enable break
+enable continue
+enable eval
+enable exec
+enable exit
+enable export
+enable readonly
+enable return
+enable set
+enable shift
+enable source
+enable trap
+enable unset
+enable .
+enable :
+enable break
+enable continue
+enable eval
+enable exec
+enable exit
+enable export
+enable readonly
+enable return
+enable set
+enable shift
+enable source
+enable trap
+enable unset
+enable -n test worked
+enable test worked
+specialname
+FOO=BAR
+FOO=BAR
+hash: hash table empty
+AVAR
+foo
+in source.sub2, calling return
+5
+a b c
+a b c
+x y z
+a b c
+a b c
+m n o p
+a b c
+m n o p
+/tmp/bash-dir-a
+/tmp/bash-dir-a
+/tmp/bash-dir-a
+AVAR
+foo
+foo
+AVAR
+foo
+foo
+AVAR
+foo
+ok
+ok
+./builtins.tests: kill: bad signal number: 4096
+1
diff --git a/tests/builtins.sub1 b/tests/builtins.sub1
new file mode 100644
index 00000000..5b797113
--- /dev/null
+++ b/tests/builtins.sub1
@@ -0,0 +1,14 @@
+unset CDPATH
+
+MYDIR=$(pwd -P)
+FULLDIR=/tmp/bash-dir-a
+DIR=${FULLDIR##*/}
+
+mkdir $FULLDIR
+CDPATH=.:/tmp
+cd $DIR
+pwd
+echo $PWD
+
+cd $MYDIR
+rmdir $FULLDIR
diff --git a/tests/builtins.tests b/tests/builtins.tests
new file mode 100644
index 00000000..0d80239b
--- /dev/null
+++ b/tests/builtins.tests
@@ -0,0 +1,201 @@
+# tests for miscellaneous builtins not tested elsewhere
+set +p
+set +o posix
+
+ulimit -c 0 2>/dev/null
+
+# check that break breaks loops
+for i in a b c; do echo $i; break; echo bad-$i; done
+echo end-1
+for i in a b c; do echo $i; break 1; echo bad-$i; done
+echo end-2
+for i in a b c; do
+ for j in x y z; do
+ echo $i:$j
+ break
+ echo bad-$i
+ done
+ echo end-$i
+done
+echo end-3
+
+# check that break breaks nested loops
+for i in a b c; do
+ for j in x y z; do
+ echo $i:$j
+ break 2
+ echo bad-$i
+ done
+ echo end-$i
+done
+echo end
+
+# check that continue continues loops
+for i in a b c; do echo $i; continue; echo bad-$i ; done
+echo end-1
+for i in a b c; do echo $i; continue 1; echo bad-$i; done
+echo end-2
+for i in a b c; do
+ for j in x y z; do
+ echo $i:$j
+ continue
+ echo bad-$i-$j
+ done
+ echo end-$i
+done
+echo end-3
+
+# check that continue breaks out of nested loops
+for i in a b c; do
+ for j in x y z; do
+ echo $i:$j
+ continue 2
+ echo bad-$i-$j
+ done
+ echo end-$i
+done
+echo end
+
+# check that `eval' re-evaluates arguments, but `builtin' and `command' do not
+AVAR='$BVAR'
+BVAR=foo
+
+echo $AVAR
+builtin echo $AVAR
+command echo $AVAR
+eval echo \$AVAR
+eval echo $AVAR
+
+# test out eval with a temp environment
+AVAR=bar eval echo \$AVAR
+BVAR=xxx eval echo $AVAR
+
+unset -v AVAR BVAR
+
+# test umask
+mask=$(umask)
+umask 022
+umask
+umask -S
+umask -S u=rwx,g=rwx,o=rx >/dev/null # 002
+umask
+umask -S
+umask 0
+umask -S
+umask ${mask} # restore original mask
+
+# builtin/command without arguments should do nothing. maybe someday they will
+builtin
+command
+
+# test enable
+enable -ps
+
+enable -aps ; enable -nps
+
+enable -n test
+case "$(type -t test)" in
+builtin) echo oops -- enable -n test failed ;;
+*) echo enable -n test worked ;;
+esac
+
+enable test
+case "$(type -t test)" in
+builtin) echo enable test worked ;;
+*) echo oops -- enable test failed ;;
+esac
+
+# test options to exec
+(exec -a specialname ${THIS_SH} -c 'echo $0' )
+# test `clean' environment. if /bin/sh is bash, and the script version of
+# printenv is run, there will be variables in the environment that bash
+# sets on startup.
+(export FOO=BAR ; exec -c printenv ) | grep FOO
+(FOO=BAR exec -c printenv ) | grep FOO
+
+(export FOO=BAR ; exec printenv ) | grep FOO
+(FOO=BAR exec printenv ) | grep FOO
+
+# ok, forget everything about hashed commands
+hash -r
+hash
+
+# check out source/.
+
+AVAR=AVAR
+
+. ./source.sub1
+AVAR=foo . ./source.sub1
+
+. ./source.sub2
+echo $?
+
+set -- a b c
+. ./source.sub3
+
+# make sure source with arguments does not change the shell's positional
+# parameters, but that the sourced file sees the arguments as its
+# positional parameters
+echo "$@"
+. ./source.sub3 x y z
+echo "$@"
+
+# but if the sourced script sets the positional parameters explicitly, they
+# should be reflected in the calling shell's positional parameters. this
+# also tests one of the shopt options that controls source using $PATH to
+# find the script
+echo "$@"
+shopt -u sourcepath
+. source.sub4
+echo "$@"
+
+# this is complicated when the sourced scripts gets its own positional
+# parameters from arguments to `.'
+set -- a b c
+echo "$@"
+. source.sub4 x y z
+echo "$@"
+
+# test out cd and $CDPATH
+${THIS_SH} ./builtins.sub1
+
+# in posix mode, assignment statements preceding special builtins are
+# reflected in the shell environment. `.' and `eval' need special-case
+# code.
+set -o posix
+echo $AVAR
+AVAR=foo . ./source.sub1
+echo $AVAR
+
+AVAR=AVAR
+echo $AVAR
+AVAR=foo eval echo \$AVAR
+echo $AVAR
+
+AVAR=AVAR
+echo $AVAR
+AVAR=foo :
+echo $AVAR
+
+# test out kill -l. bash versions prior to 2.01 did `kill -l num' wrong
+set +o posix
+sigone=$(kill -l | sed -n 's:^ 1) *\([^ ]*\)[ ].*$:\1:p')
+
+case "$(kill -l 1)" in
+${sigone/SIG/}) echo ok;;
+*) echo oops -- kill -l failure;;
+esac
+
+# POSIX.2 says that exit statuses > 128 are mapped to signal names by
+# subtracting 128 so you can find out what signal killed a process
+case "$(kill -l $(( 128 + 1)) )" in
+${sigone/SIG/}) echo ok;;
+*) echo oops -- kill -l 129 failure;;
+esac
+
+# out-of-range signal numbers should report the argument in the error
+# message, not 128 less than the argument
+kill -l 4096
+
+# kill -l NAME should return the signal number
+kill -l ${sigone/SIG/}
diff --git a/tests/dirstack.right b/tests/dirstack.right
new file mode 100644
index 00000000..b5803d5e
--- /dev/null
+++ b/tests/dirstack.right
@@ -0,0 +1,51 @@
+./dirstack.tests: pushd: no other directory
+./dirstack.tests: popd: directory stack empty
+./dirstack.tests: pushd: -m: bad argument
+pushd: usage: pushd [dir | +N | -N] [-n]
+./dirstack.tests: popd: -m: bad argument
+popd: usage: popd [+N | -N] [-n]
+./dirstack.tests: dirs: -m: bad argument
+dirs: usage: dirs [-clpv] [+N] [-N]
+ok
+/usr /
+/usr /
+/usr /
+/usr /
+/usr /
+/
+/usr /
+/etc /usr /
+/etc /usr /
+/etc /usr /
+ 0 /etc
+ 1 /usr
+ 2 /
+/usr /etc /
+/etc /usr /
+/tmp /etc /usr /
+/tmp
+/tmp
+/usr
+/usr
+./dirstack.tests: dirs: 9: bad directory stack index
+./dirstack.tests: dirs: 9: bad directory stack index
+./dirstack.tests: pushd: +9: bad directory stack index
+./dirstack.tests: pushd: -9: bad directory stack index
+./dirstack.tests: popd: +9: bad directory stack index
+./dirstack.tests: popd: -9: bad directory stack index
+/tmp /etc /
+/tmp /etc /
+/tmp /etc /
+/tmp /usr /etc /
+/tmp
+/tmp /usr /etc /
+/tmp /usr /etc /
+/tmp
+/tmp /bin /etc /
+/tmp
+/tmp /bin /
+/tmp
+/bin / /tmp
+/bin / /tmp
+/bin
+/bin
diff --git a/tests/dirstack.tests b/tests/dirstack.tests
new file mode 100644
index 00000000..e384615d
--- /dev/null
+++ b/tests/dirstack.tests
@@ -0,0 +1,79 @@
+dirs -c
+# errors -- empty stack
+pushd
+popd
+
+# errors -- bad numeric arguments -- should not cause the script to exit
+pushd -m
+popd -m
+dirs -m
+
+MYDIR=$PWD
+unalias cd 2>/dev/null
+
+unalias -a
+
+command cd -P /
+
+case "$OLDPWD" in
+$MYDIR) echo ok ;;
+*) echo oops -- bad \$OLDPWD ;;
+esac
+
+pushd /usr
+echo $PWD $OLDPWD
+dirs
+echo ${DIRSTACK[@]}
+
+# this should not change the directory stack at all
+pushd -n +0
+dirs
+
+popd
+pushd /usr
+
+pushd /etc
+dirs
+dirs -l
+dirs -v
+
+# two consecutive `pushd's should swap the top two stack elements, then
+# swap them back, leaving the stack intact
+pushd
+pushd
+
+pushd /tmp
+echo ${DIRSTACK[0]} ; dirs +0
+echo ${DIRSTACK[2]} ; dirs +2
+
+# these should be errors, but not affect the directory stack
+dirs +9; dirs -9
+pushd +9 ; pushd -9
+popd +9 ; popd -9
+
+popd -n +2
+dirs
+echo ${DIRSTACK[@]}
+
+pushd -n /usr
+echo $PWD
+dirs
+echo ${DIRSTACK[@]}
+
+builtin pwd
+
+DIRSTACK[1]=/bin
+dirs
+
+builtin pwd
+popd +2
+builtin pwd -L
+pushd -1
+dirs
+echo ${DIRSTACK[0]}
+
+dirs -c
+dirs
+
+# this is for the benefit of pure coverage
+cd $MYDIR
diff --git a/tests/dollar-star.sh b/tests/dollar-star.sh
index 982f04c3..8f8372e4 100755
--- a/tests/dollar-star.sh
+++ b/tests/dollar-star.sh
@@ -1 +1,9 @@
recho "$*"
+
+# If IFS is null, the parameters are joined without separators
+IFS=''
+recho "$*"
+
+# If IFS is unset, the parameters are separated by spaces
+unset IFS
+recho "${*}"
diff --git a/tests/dollar.right b/tests/dollar.right
index 4d9b7467..84609ec6 100644
--- a/tests/dollar.right
+++ b/tests/dollar.right
@@ -1,3 +1,5 @@
argv[1] = <a b>
+argv[1] = <ab>
+argv[1] = <a b>
argv[1] = <a>
argv[2] = <b>
diff --git a/tests/errors.right b/tests/errors.right
new file mode 100644
index 00000000..41da642b
--- /dev/null
+++ b/tests/errors.right
@@ -0,0 +1,73 @@
+./errors.tests: `1': not a valid identifier
+declare -fr func
+./errors.tests: func: readonly function
+./errors.tests: unset: func: cannot unset: readonly function
+./errors.tests: declare: func: readonly function
+./errors.tests: unset: XPATH: cannot unset: readonly variable
+./errors.tests: unset: `/bin/sh': not a valid identifier
+./errors.tests: declare: unknown option: `-z'
+declare: usage: declare [-afFrxi] [-p] name[=value] ...
+./errors.tests: declare: `-z': not a valid identifier
+./errors.tests: declare: `/bin/sh': not a valid identifier
+./errors.tests: declare: cannot use `-f' to make functions
+./errors.tests: export: XPATH: not a function
+./errors.tests: break: only meaningful in a `for', `while', or `until' loop
+./errors.tests: continue: only meaningful in a `for', `while', or `until' loop
+./errors.tests: shift: bad non-numeric arg `label'
+./errors.tests: shift: too many arguments
+./errors.tests: let: expression expected
+./errors.tests: local: can only be used in a function
+./errors.tests: hash: notthere: not found
+./errors.tests: hash: hashing disabled
+./errors.tests: export: `AA[4]': not a valid identifier
+./errors.tests: readonly: `AA[4]': not a valid identifier
+./errors.tests: [-2]: bad array subscript
+./errors.tests: AA: readonly variable
+./errors.tests: shift: shift count must be <= $#
+./errors.tests: shift: shift count must be >= 0
+./errors.tests: shopt: no_such_option: unknown shell option name
+./errors.tests: shopt: no_such_option: unknown shell option name
+./errors.tests: umask: `09' is not an octal number from 000 to 777
+./errors.tests: umask: bad character in symbolic mode: :
+./errors.tests: umask: bad symbolic mode operator: :
+./errors.tests: umask: illegal option: -p
+umask: usage: umask [-S] [mode]
+./errors.tests: VAR: readonly variable
+./errors.tests: declare: VAR: readonly variable
+./errors.tests: declare: VAR: readonly variable
+./errors.tests: declare: unset: not found
+./errors.tests: VAR: readonly variable
+./errors.tests: command substitution: line 2: syntax error: unexpected end of file
+./errors.tests: command substitution: line 1: syntax error near unexpected token `done'
+./errors.tests: command substitution: line 1: ` for z in 1 2 3; done '
+./errors.tests: cd: HOME not set
+./errors.tests: cd: OLDPWD not set
+./errors.tests: .: filename argument required
+.: usage: . filename
+./errors.tests: source: filename argument required
+source: usage: source filename
+./errors.tests: .: illegal option: -i
+.: usage: . filename
+./errors.tests: set: unknown option: q
+./errors.tests: enable: sh: not a shell builtin
+./errors.tests: enable: bash: not a shell builtin
+./errors.tests: shopt: cannot set and unset shell options simultaneously
+./errors.tests: read: `/bin/sh': not a valid identifier
+./errors.tests: VAR: readonly variable
+./errors.tests: eval: illegal option: -i
+eval: usage: eval [arg ...]
+./errors.tests: command: illegal option: -i
+command: usage: command [-pVv] command [arg ...]
+./errors.tests: trap: NOSIG: not a signal specification
+./errors.tests: trap: illegal option: -s
+trap: usage: trap [arg] [signal_spec ...] or trap -l
+./errors.tests: trap: ERR: not a signal specification
+./errors.tests: return: can only `return' from a function or sourced script
+./errors.tests: break: loop count must be > 0
+./errors.tests: continue: loop count must be > 0
+./errors.tests: builtin: bash: not a shell builtin
+./errors.tests: bg: no job control
+./errors.tests: fg: no job control
+./errors.tests: kill: -s requires an argument
+./errors.tests: kill: bad signal spec `S'
+./errors.tests: `!!': not a valid identifier
diff --git a/tests/errors.tests b/tests/errors.tests
new file mode 100644
index 00000000..61751f56
--- /dev/null
+++ b/tests/errors.tests
@@ -0,0 +1,203 @@
+# These should all be safe
+LC_ALL=C
+LC_CTYPE=C
+LC_COLLATE=C
+LC_MESSAGES=C
+
+# these tests should all generate errors
+
+# make sure we don't exit prematurely
+set +e
+set +o posix
+
+# the iteration variable must be a valid identifier
+for 1 in a b c; do echo $1; done
+
+# try to rebind a read-only function
+func()
+{
+ echo func
+}
+readonly -f func
+# make sure `readonly' and `declare' play well together
+declare -Fr
+func()
+{
+ echo bar
+}
+
+# cannot unset readonly functions or variables
+unset -f func
+# or make them not readonly
+declare -fr func
+declare -f +r func
+
+XPATH=$PATH
+declare -r XPATH
+unset -v XPATH
+
+# cannot unset invalid identifiers
+unset /bin/sh
+
+# bad option
+declare -z
+# cannot declare invalid identifiers
+declare -- -z
+declare /bin/sh
+
+# this is the syntax used to export functions in the environment, but
+# it cannot be used with `declare'
+declare -f func='() { echo "this is func"; }'
+
+# try to export -f something that is not a function -- this should be
+# an error, not create an `invisible function'
+export -f XPATH
+
+# this depends on the setting of BREAK_COMPLAINS in config.h.in
+break
+continue
+
+# this should not exit the shell; it did in versions before 2.01
+shift label
+
+# other shells do not complain about the extra arguments; maybe someday
+# we won't either
+set -- a b c
+shift $# label
+# and get rid of the positional parameters
+shift $#
+
+# let without an expression is an error, though maybe it should just return
+# success
+let
+
+# local outside a function is an error
+local
+
+# try to hash a non-existant command
+hash notthere
+
+# turn off hashing, then try to hash something
+set +o hashall
+hash -p ${THIS_SH} ${THIS_SH##*/}
+
+# bad identifiers to declare/readonly/export
+export AA[4]
+readonly AA[4]
+
+declare -a AA
+unset AA[-2]
+
+# try to assign to a readonly array
+declare -r AA
+AA=( one two three )
+
+# bad counts to `shift'
+shopt -s shift_verbose
+shift $(( $# + 5 ))
+shift -2
+
+# bad shell options
+shopt -s no_such_option
+shopt no_such_option
+
+# non-octal digits for umask and other errors
+umask 09
+umask -S u=rwx:g=rwx:o=rx >/dev/null # 002
+umask -S u:rwx,g:rwx,o:rx >/dev/null # 002
+# this may behave identically to umask without arguments in the future,
+# but for now it is an error
+umask -p
+
+# assignment to a readonly variable in environment
+VAR=4
+readonly VAR
+VAR=7 :
+
+# more readonly variable tests
+declare VAR=88
+declare +r VAR
+
+declare -p unset
+
+# iteration variable in a for statement being readonly
+for VAR in 1 2 3 ; do echo $VAR; done
+
+# parser errors
+: $( for z in 1 2 3; do )
+: $( for z in 1 2 3; done )
+
+# various `cd' errors
+( unset HOME ; cd )
+( unset OLDPWD ; cd - )
+
+# various `source/.' errors
+.
+source
+
+# maybe someday this will work like in rc
+. -i /dev/tty
+
+# make sure that this gives an error rather than setting $1
+set -q
+
+# enable non-builtins
+enable sh bash
+
+# try to set and unset shell options simultaneously
+shopt -s -u checkhash
+
+# try to read into an invalid identifier
+read /bin/sh < /dev/null
+
+# try to read into a readonly variable
+read VAR < /dev/null
+
+# someday these may mean something, but for now they're errors
+eval -i "echo $-"
+command -i "echo $-"
+
+# error to list trap for an unknown signal
+trap -p NOSIG
+
+# maybe someday trap will take a -s argument like kill, but not now
+trap -p -s NOSIG
+
+# maybe someday we will have a ksh-like ERR trap, but not yet
+trap 'echo [$LINENO] -- error' ERR
+
+# can only return from a function or sourced script
+return 2
+
+# break and continue with arguments <= 0
+for z in 1 2 3; do
+ break 0
+ echo $x
+done
+for z in 1 2 3; do
+ continue 0
+ echo $x
+done
+
+# builtin with non-builtin
+builtin bash
+
+# maybe someday you will be able to use fg/bg when job control is not really
+# active, but for now they are errors
+bg
+fg
+
+# argument required
+kill -s
+# bad argument
+kill -S
+
+# this must be last!
+# in posix mode, a function name must be a valid identifier
+# this can't go in posix2.tests, since it causes the shell to exit
+# immediately
+set -o posix
+function !! () { fc -s "$@" ; }
+set +o posix
+
+echo end
diff --git a/tests/execscript b/tests/execscript
new file mode 100644
index 00000000..49c4c337
--- /dev/null
+++ b/tests/execscript
@@ -0,0 +1,78 @@
+export LC_ALL=C
+export LANG=C
+
+set -- one two three
+echo before execscript.sub: "$@"
+echo calling execscript.sub
+./execscript.sub aa bb cc dd ee
+echo after execscript.sub with args: $?
+./execscript.sub
+echo after execscript.sub without args: $?
+
+# set up a fixed path so we know notthere will not be found
+PATH=/usr/bin:/bin:/usr/local/bin:
+export PATH
+
+notthere
+echo $?
+
+# this is iffy, since the error messages may vary from system to system
+${THIS_SH} notthere
+echo $?
+
+# /bin/sh should be there on all systems
+${THIS_SH} /bin/sh
+echo $?
+
+# try executing a directory
+/
+echo $?
+
+${THIS_SH} /
+echo $?
+
+# try sourcing a directory
+. /
+echo $?
+
+. ${THIS_SH} 2>/dev/null
+echo $?
+
+. /dev/null
+echo $?
+
+# kill two birds with one test -- test out the BASH_ENV code
+echo echo this is bashenv > /tmp/bashenv
+export BASH_ENV=/tmp/bashenv
+${THIS_SH} ./execscript.sub3
+rm -f /tmp/bashenv
+unset BASH_ENV
+
+# we're resetting the $PATH to empty, so this should be last
+PATH=
+
+notthere
+echo $?
+
+command notthere
+echo $?
+
+command -p notthere
+echo $?
+
+# but -p should guarantee that we find all the standard utilities, even
+# with an empty or unset $PATH
+command -p sh -c 'echo this is $0'
+unset PATH
+command -p sh -c 'echo this is $0'
+
+# a bug in bash before bash-2.01 caused PATH to be set to the empty string
+# when command -p was run with PATH unset
+echo ${PATH-unset}
+
+echo "echo ok" | ${THIS_SH} -t
+
+${THIS_SH} ./execscript.sub2
+echo $?
+
+${THIS_SH} ./execscript.sub4
diff --git a/tests/execscript.right b/tests/execscript.right
new file mode 100644
index 00000000..1b64033d
--- /dev/null
+++ b/tests/execscript.right
@@ -0,0 +1,36 @@
+before execscript.sub: one two three
+calling execscript.sub
+aa bb cc dd ee
+after execscript.sub with args: 0
+
+after execscript.sub without args: 0
+./execscript: notthere: command not found
+127
+notthere: notthere: No such file or directory
+127
+/bin/sh: /bin/sh: cannot execute binary file
+126
+./execscript: /: is a directory
+126
+/: /: cannot execute binary file
+126
+./execscript: .: /: is a directory
+1
+126
+./execscript: .: /dev/null: not a regular file
+1
+this is bashenv
+./execscript.sub3: /tmp/bash-notthere: No such file or directory
+./execscript.sub3: exec: /tmp/bash-notthere: cannot execute: No such file or directory
+126
+./execscript: notthere: No such file or directory
+127
+./execscript: notthere: No such file or directory
+127
+./execscript: notthere: No such file or directory
+127
+this is sh
+this is sh
+unset
+ok
+5
diff --git a/tests/execscript.sub b/tests/execscript.sub
new file mode 100755
index 00000000..4a12501f
--- /dev/null
+++ b/tests/execscript.sub
@@ -0,0 +1 @@
+echo "$@"
diff --git a/tests/execscript.sub2 b/tests/execscript.sub2
new file mode 100644
index 00000000..c1caaead
--- /dev/null
+++ b/tests/execscript.sub2
@@ -0,0 +1,5 @@
+# make sure an exit command in an exit trap sets the shell's exit status
+trap - 0
+trap 'exit 5' 0
+
+exit 0
diff --git a/tests/execscript.sub3 b/tests/execscript.sub3
new file mode 100644
index 00000000..4f2f8e21
--- /dev/null
+++ b/tests/execscript.sub3
@@ -0,0 +1,6 @@
+shopt -s execfail
+
+exec /tmp/bash-notthere
+# make sure we're still around
+echo $?
+
diff --git a/tests/execscript.sub4 b/tests/execscript.sub4
new file mode 100644
index 00000000..a60d8b32
--- /dev/null
+++ b/tests/execscript.sub4
@@ -0,0 +1,8 @@
+# let's test out the noexec code
+set -n
+
+fail
+whoops
+wow
+
+set +n
diff --git a/tests/exp-tests b/tests/exp-tests
index 45fe87c4..f8512c3f 100644
--- a/tests/exp-tests
+++ b/tests/exp-tests
@@ -232,6 +232,19 @@ x=/one/two/three
expect '<three>'
recho ${x##*/}
+# pattern removal of patterns that don't match
+z=abcdef
+
+expect '<abcdef>'
+recho ${z#xyz}
+expect '<abcdef>'
+recho ${z##xyz}
+
+expect '<abcdef>'
+recho ${z%xyz}
+expect '<abcdef>'
+recho ${z%%xyz}
+
# Command substitution and the quirky differences between `` and $()
expect '<\$x>'
@@ -318,8 +331,25 @@ esac
set one two three four five
expect '<one> <three> <five>'
recho $1 $3 ${5} $8 ${9}
+
+# length tests on positional parameters and some special parameters
+
expect '<5> <5>'
recho $# ${#}
+expect '<3>'
+recho ${#1}
+expect '<1>'
+recho ${##}
+expect '<1>'
+recho ${#?}
+expect '<5>'
+recho ${#@}
+expect '<5>'
+recho ${#*}
+expect '<5>'
+recho "${#@}"
+expect '<5>'
+recho "${#*}"
expect '<42>'
recho $((28 + 14))
@@ -334,6 +364,8 @@ recho '~'
expect nothing
recho $!
+expect nothing
+recho ${!}
# test word splitting of assignment statements not preceding a command
a="a b c d e"
diff --git a/tests/exp.right b/tests/exp.right
index b1b1c2d3..747c80ea 100644
--- a/tests/exp.right
+++ b/tests/exp.right
@@ -87,6 +87,10 @@ argv[1] = <file.o>
argv[1] = <posix>
argv[1] = </src/cmd>
argv[1] = <three>
+argv[1] = <abcdef>
+argv[1] = <abcdef>
+argv[1] = <abcdef>
+argv[1] = <abcdef>
argv[1] = <\$x>
argv[1] = <$x>
argv[1] = <\$x>
@@ -123,6 +127,13 @@ argv[2] = <three>
argv[3] = <five>
argv[1] = <5>
argv[2] = <5>
+argv[1] = <3>
+argv[1] = <1>
+argv[1] = <1>
+argv[1] = <5>
+argv[1] = <5>
+argv[1] = <5>
+argv[1] = <5>
argv[1] = <42>
argv[1] = <26>
argv[1] = <\>
diff --git a/tests/func.right b/tests/func.right
new file mode 100644
index 00000000..fcdfe92d
--- /dev/null
+++ b/tests/func.right
@@ -0,0 +1,28 @@
+a returns 5
+b returns 4
+c returns 3
+d returns 2
+in e
+e returned 25
+x is 25
+ZZ
+abcde
+defghi
+ZZ
+5
+0
+AVAR
+AVAR
+foo
+foo
+AVAR
+5
+5
+f1
+f1 ()
+{
+ ( return 5 );
+ status=$?;
+ echo $status;
+ return $status
+}
diff --git a/tests/func.tests b/tests/func.tests
new file mode 100644
index 00000000..8abf4ce0
--- /dev/null
+++ b/tests/func.tests
@@ -0,0 +1,119 @@
+a()
+{
+ x=$((x - 1))
+ return 5
+}
+
+b()
+{
+ x=$((x - 1))
+ a
+ echo a returns $?
+ return 4
+}
+
+c()
+{
+ x=$((x - 1))
+ b
+ echo b returns $?
+ return 3
+}
+
+d()
+{
+ x=$((x - 1))
+ c
+ echo c returns $?
+ return 2
+}
+
+e()
+{
+ d
+ echo d returns $?
+ echo in e
+ x=$((x - 1))
+ return $x
+}
+
+f()
+{
+ e
+ echo e returned $?
+ echo x is $x
+ return 0
+}
+
+x=30
+f
+
+# make sure unsetting a local variable preserves the `local' attribute
+f1()
+{
+ local zz
+ zz=abcde
+ echo $zz
+ unset zz
+ zz=defghi
+ echo $zz
+}
+
+zz=ZZ
+echo $zz
+f1
+echo $zz
+
+unset -f f1
+f1()
+{
+ return 5
+}
+
+( f1 )
+echo $?
+
+unset -f f1
+f1()
+{
+ sleep 5
+ return 5
+}
+
+f1 &
+wait
+echo $?
+
+unset -f f1
+
+f1()
+{
+ echo $AVAR
+ printenv AVAR
+}
+
+AVAR=AVAR
+echo $AVAR
+f1
+AVAR=foo f1
+echo $AVAR
+
+unset -f f1
+# make sure subshells can do a `return' if we're executing in a function
+f1()
+{
+ ( return 5 )
+ status=$?
+ echo $status
+ return $status
+}
+
+f1
+echo $?
+
+declare -F f1 # should print just the name
+declare -f f1 # should print the definition, too
+
+# no functions should be exported, right?
+declare -xF
+declare -xf
diff --git a/tests/getopts.right b/tests/getopts.right
new file mode 100644
index 00000000..b90b6558
--- /dev/null
+++ b/tests/getopts.right
@@ -0,0 +1,56 @@
+getopts: usage: getopts optstring name [arg]
+2
+getopts: usage: getopts optstring name [arg]
+2
+./getopts.tests: getopts: illegal option: -a
+getopts: usage: getopts optstring name [arg]
+-a specified
+-b bval specified
+remaining args: one two three
+-a specified
+-b bval specified
+remaining args: one two three four five six seven eight nine ten eleven twelve
+./getopts.sub1: option requires an argument -- b
+Usage: ./getopts.sub1 [-a] [-b value] args
+-a specified
+-c cval specified
+-d specified
+-a specified
+-b 3 specified
+remaining args: one two three four five
+-a specified
+-b bval specified
+remaining args: one two three
+-a specified
+-b bval specified
+remaining args: one two three
+./getopts.sub4: error: option `b' requires an argument
+Usage: ./getopts.sub4 [-a] [-b value] args
+./getopts.sub4: error: illegal option character `c'
+Usage: ./getopts.sub4 [-a] [-b value] args
+-a specified
+remaining args: -b bval one two three
+OPTERR=0
+a here
+something else here
+OPTIND=3
+getop: OPTERR=1
+a here
+./getopts.sub5: illegal option -- c
+something else here
+./getopts.sub5: illegal option -- d
+something else here
+./getopts.sub5: illegal option -- e
+something else here
+getop: OPTIND=5
+OPTIND=3
+OPTERR=0
+-a specified
+remaining args:
+-a specified
+remaining args:
+-a specified
+remaining args:
+0
+./getopts.sub7: getopts: `opt-var': not a valid identifier
+remaining args:
diff --git a/tests/misc/gotest b/tests/getopts.sub1
index df0a342e..df0a342e 100644
--- a/tests/misc/gotest
+++ b/tests/getopts.sub1
diff --git a/tests/getopts.sub2 b/tests/getopts.sub2
new file mode 100644
index 00000000..d91fd26a
--- /dev/null
+++ b/tests/getopts.sub2
@@ -0,0 +1,26 @@
+aflag=
+bflag=
+
+while getopts ab:c:de name "$@"
+do
+ case $name in
+ a) aflag=1 ;;
+ b) bflag=1
+ bval=$OPTARG;;
+ c) cflag=1
+ cval=$OPTARG ;;
+ d) dflag=1 ;;
+ e) eflag=1;;
+ ?) echo Usage: $0 [-a] [-b value] [-c value] -[de] args
+ exit 2;;
+ esac
+
+done
+
+[ ! -z "$aflag" ] && echo -a specified
+[ ! -z "$bflag" ] && echo -b $bval specified
+[ ! -z "$cflag" ] && echo -c $cval specified
+[ ! -z "$dflag" ] && echo -d specified
+[ ! -z "$eflag" ] && { echo -n - ; echo e specified; }
+
+exit 0
diff --git a/tests/getopts.sub3 b/tests/getopts.sub3
new file mode 100644
index 00000000..2d8b3162
--- /dev/null
+++ b/tests/getopts.sub3
@@ -0,0 +1,27 @@
+aflag=
+bflag=
+
+while getopts ab: name -a -b 1 -a -a -a -b 5 -b 3 -a one two three four five
+do
+ case $name in
+ a) aflag=1 ;;
+ b) bflag=1
+ bval=$OPTARG;;
+ ?) echo Usage: $0 [-a] [-b value] args
+ exit 2;;
+ esac
+
+done
+
+if [ ! -z "$aflag" ] ; then echo -a specified ; fi
+if [ ! -z "$bflag" ] ; then echo -b $bval specified ; fi
+
+set -- -a -b 1 -a -a -a -b 5 -b 3 -a one two three four five
+if [ "$OPTIND" -gt 1 ]
+then
+ shift $(( $OPTIND - 1 ))
+fi
+
+echo remaining args: "$*"
+
+exit 0
diff --git a/tests/getopts.sub4 b/tests/getopts.sub4
new file mode 100644
index 00000000..9cd5aef4
--- /dev/null
+++ b/tests/getopts.sub4
@@ -0,0 +1,30 @@
+aflag=
+bflag=
+
+while getopts :ab: name "$@"
+do
+ case $name in
+ a) aflag=1 ;;
+ b) bflag=1
+ bval=$OPTARG;;
+ :) echo $0: error: option \`$OPTARG\' requires an argument
+ echo Usage: $0 [-a] [-b value] args
+ exit 2;;
+ ?) echo $0: error: illegal option character \`$OPTARG\'
+ echo Usage: $0 [-a] [-b value] args
+ exit 2;;
+ esac
+
+done
+
+if [ ! -z "$aflag" ] ; then echo -a specified ; fi
+if [ ! -z "$bflag" ] ; then echo -b $bval specified ; fi
+
+if [ "$OPTIND" -gt 1 ]
+then
+ shift $(( $OPTIND - 1 ))
+fi
+
+echo remaining args: "$*"
+
+exit 0
diff --git a/tests/getopts.sub5 b/tests/getopts.sub5
new file mode 100644
index 00000000..c6e38881
--- /dev/null
+++ b/tests/getopts.sub5
@@ -0,0 +1,50 @@
+#!/local/bin/bash
+#Time-stamp: <95/06/07 07:40:40 hrue@imf.unit.no>
+
+getop () {
+
+ local OPTIND
+ local OPTERR=1
+
+ echo getop: OPTERR=$OPTERR
+ while getopts ab arg "$@"; do
+ case $arg in
+ a)
+ echo a here
+ ;;
+ b)
+ echo b here
+ ;;
+ :|?|*)
+ echo something else here
+ ;;
+ esac
+ done
+ echo getop: OPTIND=$OPTIND
+}
+
+OPTIND=
+OPTERR=0
+
+echo OPTERR=$OPTERR
+while getopts ab arg; do
+ case $arg in
+ a)
+ echo a here
+ ;;
+ b)
+ echo b here
+ ;;
+ :|?|*)
+
+ echo something else here
+ ;;
+ esac
+done
+
+echo OPTIND=$OPTIND
+
+getop "$@" -d -e
+
+echo OPTIND=$OPTIND
+echo OPTERR=$OPTERR
diff --git a/tests/getopts.sub6 b/tests/getopts.sub6
new file mode 100644
index 00000000..75d768c6
--- /dev/null
+++ b/tests/getopts.sub6
@@ -0,0 +1,27 @@
+aflag=
+bflag=
+
+while getopts :ac name "$@"
+do
+ case $name in
+ a) aflag=1 ;;
+ c) cflag=1 ;;
+ ?) exit 2;;
+ esac
+
+ # this came in in a bug report -- it's really a usage error
+ # but it shouldn't cause the shell to crash
+ shift
+done
+
+if [ ! -z "$aflag" ] ; then echo -a specified ; fi
+if [ ! -z "$cflag" ] ; then echo -c specified ; fi
+
+if [ "$OPTIND" -gt 1 ]
+then
+ shift $(( $OPTIND - 1 ))
+fi
+
+echo remaining args: "$*"
+
+exit 0
diff --git a/tests/getopts.sub7 b/tests/getopts.sub7
new file mode 100644
index 00000000..a20a6df1
--- /dev/null
+++ b/tests/getopts.sub7
@@ -0,0 +1,30 @@
+aflag=
+bflag=
+
+while getopts :ab: opt-var "$@"
+do
+ case $name in
+ a) aflag=1 ;;
+ b) bflag=1
+ bval=$OPTARG;;
+ :) echo $0: error: option \`$OPTARG\' requires an argument
+ echo Usage: $0 [-a] [-b value] args
+ exit 2;;
+ ?) echo $0: error: illegal option character \`$OPTARG\'
+ echo Usage: $0 [-a] [-b value] args
+ exit 2;;
+ esac
+
+done
+
+if [ ! -z "$aflag" ] ; then echo -a specified ; fi
+if [ ! -z "$bflag" ] ; then echo -b $bval specified ; fi
+
+if [ "$OPTIND" -gt 1 ]
+then
+ shift $(( $OPTIND - 1 ))
+fi
+
+echo remaining args: "$*"
+
+exit 0
diff --git a/tests/getopts.tests b/tests/getopts.tests
new file mode 100644
index 00000000..af1ee4fb
--- /dev/null
+++ b/tests/getopts.tests
@@ -0,0 +1,38 @@
+# getopts tests
+# this should fail
+getopts
+echo $?
+getopts opts
+echo $?
+
+# maybe someday we will have a ksh93-like -a argument to set the name
+# used in error messages, but not yet
+getopts -a opts name
+
+${THIS_SH} ./getopts.sub1 -a -b bval one two three
+# make sure getopts works when there are more than 9 positional parameters
+${THIS_SH} ./getopts.sub1 -a -b bval one two three four five six seven eight nine ten eleven twelve
+${THIS_SH} ./getopts.sub1 -a -b
+
+${THIS_SH} ./getopts.sub2 -ad -c cval three four five
+
+${THIS_SH} ./getopts.sub3
+
+# make sure that `-b bval' and `-bbval' are equivalent
+${THIS_SH} ./getopts.sub4 -a -b bval one two three
+${THIS_SH} ./getopts.sub4 -a -bbval one two three
+# this tests `silent' error reporting
+${THIS_SH} ./getopts.sub4 -a -b
+${THIS_SH} ./getopts.sub4 -a -c
+
+# make sure that `--' can be used to end the list of options
+${THIS_SH} ./getopts.sub4 -a -- -b bval one two three
+
+${THIS_SH} ./getopts.sub5 -a -c
+
+${THIS_SH} ./getopts.sub6 -a
+${THIS_SH} ./getopts.sub6 -a -c
+${THIS_SH} ./getopts.sub6 -ac
+echo $? # this should be 2
+
+${THIS_SH} ./getopts.sub7 -a
diff --git a/tests/glob-test b/tests/glob-test
index 00227a6d..492cfb8b 100644
--- a/tests/glob-test
+++ b/tests/glob-test
@@ -1,3 +1,4 @@
+LC_COLLATE=C
#
# test the shell globbing
#
@@ -6,6 +7,8 @@ expect()
echo expect "$@"
}
+MYDIR=$PWD # save where we are
+
TESTDIR=/tmp/glob-test
mkdir $TESTDIR
builtin cd $TESTDIR || { echo $0: cannot cd to $TESTDIR >&2 ; exit 1; }
@@ -119,59 +122,47 @@ recho a[\b]c
expect '<abc>'
recho a?c
-expect '<match>'
+expect '<match 1>'
case abc in
-a"b"c) echo match
- ;;
-*) echo BAD
- ;;
+a"b"c) echo 'match 1' ;;
+*) echo 'BAD match 1' ;;
esac
-expect '<match>'
+expect '<match 2>'
case abc in
-a*c) echo match
- ;;
-*) echo BAD
- ;;
+a*c) echo 'match 2' ;;
+*) echo 'BAD match 2' ;;
esac
-expect '<ok>'
+expect '<ok 1>'
case abc in
-"a?c") echo bad
- ;;
-*) echo ok
- ;;
+"a?c") echo 'bad 1' ;;
+*) echo 'ok 1' ;;
esac
-expect '<ok>'
+expect '<ok 2>'
case abc in
-a\*c) echo bad
- ;;
-*) echo ok
- ;;
+a\*c) echo 'bad 2' ;;
+*) echo 'ok 2' ;;
esac
-expect '<ok>'
+expect '<ok 3>'
case abc in
-a\[b]c) echo bad
- ;;
-*) echo ok
- ;;
+a\[b]c) echo 'bad 3' ;;
+*) echo 'ok 3' ;;
esac
-expect '<ok>'
+expect '<ok 4>'
case "$nosuchvar" in
-"") echo ok ;;
-*) echo bad ;;
+"") echo 'ok 4' ;;
+*) echo 'bad 4' ;;
esac
# This is very odd, but sh and ksh seem to agree
-expect '<ok>'
+expect '<ok 5>'
case abc in
-a["\b"]c) echo ok
- ;;
-*) echo bad
- ;;
+a["\b"]c) echo 'ok 5' ;;
+*) echo 'bad 5' ;;
esac
mkdir man
@@ -253,32 +244,115 @@ case abcdecdhjk in
a****c**?**??*****) echo ok 25;;
esac
+case '-' in
+[-abc]) echo ok 26 ;;
+esac
+
+case '-' in
+[abc-]) echo ok 27 ;;
+esac
+
+case '\' in
+\\) echo ok 28 ;;
+esac
+
+case '\' in
+[\\]) echo ok 29 ;;
+esac
+
+case '\' in
+'\') echo ok 30 ;;
+esac
+
+case '[' in
+[[]) echo ok 31 ;;
+esac
+
+# a `[' without a closing `]' is just another character to match, in the
+# bash implementation
+case '[' in
+[) echo ok 32 ;;
+esac
+
+case '[abc' in
+[*) echo 'ok 33';;
+esac
+
+# a right bracket shall lose its special meaning and represent itself in
+# a bracket expression if it occurs first in the list. -- POSIX.2 2.8.3.2
+case ']' in
+[]]) echo ok 34 ;;
+esac
+
+case '-' in
+[]-]) echo ok 35 ;;
+esac
+
# none of these should output anything
case abc in
-??**********?****?) echo bad ;;
+??**********?****?) echo bad 1;;
esac
case abc in
-??**********?****c) echo bad ;;
+??**********?****c) echo bad 2;;
esac
case abc in
-?************c****?****) echo bad;;
+?************c****?****) echo bad 3;;
esac
case abc in
-*c*?**) echo bad;;
+*c*?**) echo bad 4;;
esac
case abc in
-a*****c*?**) echo bad;;
+a*****c*?**) echo bad 5;;
esac
case abc in
-a********???*******) echo bad;;
+a********???*******) echo bad 6;;
+esac
+
+case 'a' in
+[]) echo bad 7 ;;
+esac
+
+case '[' in
+[abc) echo bad 8;;
esac
+
+# make sure set -f works right
+set -f
+recho *
+set +f
+
+# test out the GLOBIGNORE code
+GLOBIGNORE='.*:*c:*e:?'
+recho *
+
+GLOBIGNORE='.*:*b:*d:?'
+recho *
+
+# see if GLOBIGNORE can substitute for `set -f'
+GLOBIGNORE='.*:*'
+recho *
+
+unset GLOBIGNORE
+expect '<man/man1/bash.1>'
+recho */man*/bash.*
+
+# make sure null values for GLOBIGNORE have no effect
+GLOBIGNORE=
+expect '<man/man1/bash.1>'
+recho */man*/bash.*
+
builtin cd /
rm -rf $TESTDIR
+
+# this is for the benefit of pure coverage, so it writes the pcv file
+# in the right place
+builtin cd $MYDIR
+
exit 0
diff --git a/tests/glob.right b/tests/glob.right
index 2f1dac22..2fcace18 100644
--- a/tests/glob.right
+++ b/tests/glob.right
@@ -54,13 +54,13 @@ argv[1] = <abc>
argv[1] = <abc>
argv[1] = <abc>
argv[1] = <abc>
-match
-match
-ok
-ok
-ok
-ok
-ok
+match 1
+match 2
+ok 1
+ok 2
+ok 3
+ok 4
+ok 5
argv[1] = <man/man1/bash.1>
argv[1] = <man/man1/bash.1>
argv[1] = <man/man1/bash.1>
@@ -81,3 +81,34 @@ ok 22
ok 23
ok 24
ok 25
+ok 26
+ok 27
+ok 28
+ok 29
+ok 30
+ok 31
+ok 32
+ok 33
+ok 34
+ok 35
+argv[1] = <*>
+argv[1] = <a*b>
+argv[2] = <a-b>
+argv[3] = <aXb>
+argv[4] = <abd>
+argv[5] = <bb>
+argv[6] = <bcd>
+argv[7] = <bdir>
+argv[8] = <ca>
+argv[9] = <cb>
+argv[10] = <dd>
+argv[11] = <man>
+argv[1] = <abc>
+argv[2] = <abe>
+argv[3] = <bdir>
+argv[4] = <ca>
+argv[5] = <de>
+argv[6] = <man>
+argv[1] = <*>
+argv[1] = <man/man1/bash.1>
+argv[1] = <man/man1/bash.1>
diff --git a/tests/heredoc.right b/tests/heredoc.right
index bf02e2b0..d71781e8 100644
--- a/tests/heredoc.right
+++ b/tests/heredoc.right
@@ -1,4 +1,7 @@
there
+one - alpha
+two - beta
+three - gamma
hi\
there$a
stuff
@@ -8,5 +11,33 @@ EO\
F
hi
hi
+tab 1
+tab 2
+tab 3
+abc
+def ghi
+jkl mno
+fff is a function
+fff ()
+{
+ ed /tmp/foo >/dev/null <<ENDOFINPUT
+/^name/d
+w
+q
+ENDOFINPUT
+
+ aa=1
+}
+fff is a function
+fff ()
+{
+ ed /tmp/foo >/dev/null <<ENDOFINPUT
+/^name/d
+w
+q
+ENDOFINPUT
+
+ aa=1
+}
hi
there
diff --git a/tests/heredoc.tests b/tests/heredoc.tests
index aa694965..c07ef642 100644
--- a/tests/heredoc.tests
+++ b/tests/heredoc.tests
@@ -6,6 +6,20 @@ EOF1
there
EOF2
+while read line1; do
+ read line2 <&3
+ echo $line1 - $line2
+done <<EOF1 3<<EOF2
+one
+two
+three
+EOF1
+alpha
+beta
+gamma
+EOF2
+
+
# check quoted here-doc is protected
a=foo
@@ -37,6 +51,41 @@ hi
EO\
F
+# check operation of tab removal in here documents
+cat <<- EOF
+ tab 1
+ tab 2
+ tab 3
+ EOF
+
+# check appending of text to file from here document
+rm -f /tmp/bash-zzz
+cat > /tmp/bash-zzz << EOF
+abc
+EOF
+cat >> /tmp/bash-zzz << EOF
+def ghi
+jkl mno
+EOF
+cat /tmp/bash-zzz
+rm -f /tmp/bash-zzz
+
+# make sure command printing puts the here-document as the last redirection
+# on the line, and the function export code preserves syntactic correctness
+fff()
+{
+ ed /tmp/foo <<ENDOFINPUT >/dev/null
+/^name/d
+w
+q
+ENDOFINPUT
+aa=1
+}
+
+type fff
+export -f fff
+${THIS_SH} -c 'type fff'
+
# check that end of file delimits a here-document
# THIS MUST BE LAST!
diff --git a/tests/histexpand.right b/tests/histexpand.right
new file mode 100644
index 00000000..3c20d1c1
--- /dev/null
+++ b/tests/histexpand.right
@@ -0,0 +1,127 @@
+echo $BASH_VERSION
+ 1 for i in one two three; do echo $i; done
+ 2 /bin/sh -c 'echo this is $0'
+ 3 ls
+ 4 echo $BASH_VERSION
+ 1 for i in one two three; do echo $i; done
+ 2 /bin/sh -c 'echo this is $0'
+ 3 ls
+ 4 echo $BASH_VERSION
+ 5 HISTFILE=/tmp/newhistory
+ 6 echo line 2 for history
+echo line 2 for history
+echo line 2 for history
+set -H
+echo line 2 for history
+line 2 for history
+ 1 for i in one two three; do echo $i; done
+ 2 /bin/sh -c 'echo this is $0'
+ 3 ls
+ 4 echo $BASH_VERSION
+ 5 HISTFILE=/tmp/newhistory
+ 6 echo line 2 for history
+ 7 set -H
+ 8 echo line 2 for history
+a b c d e
+echo a b c d e
+a b c d e
+echo line 2 for history
+line 2 for history
+echo line 8 for history
+line 8 for history
+/bin/sh -c 'echo this is $0'
+this is /bin/sh
+echo sh
+sh
+echo /bin
+/bin
+echo e
+e
+a b c d e
+echo b c d e
+b c d e
+echo b c d
+b c d
+echo d e
+d e
+echo d e
+d e
+echo b c d
+b c d
+file.c
+echo file
+file
+echo .c
+.c
+echo 'file'
+file
+bax.c
+echo $file
+bax
+echo .c
+.c
+echo '$file'
+$file
+a b c d e
+echo 'a' 'b' 'c' 'd' 'e'
+a b c d e
+echo 'a b c d e'
+a b c d e
+foo.c foo.o foo.html foo.h
+echo bar.c foo.o foo.html foo.h
+bar.c foo.o foo.html foo.h
+echo bar.c bar.o bar.html bar.h
+bar.c bar.o bar.html bar.h
+echo xbar.c xbar.o xbar.html xbar.h
+xbar.c xbar.o xbar.html xbar.h
+echo xbar.c xbar.o xbar.html xbar.h
+xbar.c xbar.o xbar.html xbar.h
+echo xwhix.c xwhix.o xwhix.html xwhix.h
+xwhix.c xwhix.o xwhix.html xwhix.h
+echo xwhix.c xwhix.o xwhix.html xwhix.h
+echo 'xwhix'
+xwhix
+echo 'xwhix.h'
+xwhix.h
+echo 'xwhix.h'
+xwhix.h
+echo 'xwhix.h'
+xwhix.h
+ 8 echo line 2 for history
+ 9 echo a b c d e
+ 10 echo line 2 for history
+ 11 echo line 8 for history
+ 12 /bin/sh -c 'echo this is $0'
+ 13 echo sh
+ 14 echo /bin
+ 15 echo e
+ 16 echo a b c d e
+ 17 echo b c d e
+ 18 echo b c d
+ 19 echo d e
+ 20 echo b c d
+ 21 echo file.c
+ 22 echo file
+ 23 echo .c
+ 24 echo 'file'
+ 25 echo $file.c
+ 26 echo $file
+ 27 echo .c
+ 28 echo '$file'
+ 29 echo a b c d e
+ 30 echo 'a' 'b' 'c' 'd' 'e'
+ 31 echo 'a b c d e'
+ 32 echo foo.c foo.o foo.html foo.h
+ 33 echo bar.c foo.o foo.html foo.h
+ 34 echo bar.c bar.o bar.html bar.h
+ 35 echo xbar.c xbar.o xbar.html xbar.h
+ 36 echo xwhix.c xwhix.o xwhix.html xwhix.h
+ 37 echo xwhix.c xwhix.o xwhix.html xwhix.h
+ 38 echo 'xwhix'
+ 39 echo 'xwhix.h'
+!!
+!!
+echo '!!' \!\!
+!! !!
+ok 1
+ok 2
diff --git a/tests/histexpand.tests b/tests/histexpand.tests
new file mode 100644
index 00000000..f48c00fe
--- /dev/null
+++ b/tests/histexpand.tests
@@ -0,0 +1,112 @@
+trap 'rm /tmp/newhistory' 0
+
+file=bax
+
+history -c
+
+HISTFILE=history.list
+HISTCONTROL=ignoreboth
+HISTIGNORE='&:#*:history*:fc*'
+# we will end up exercising the history stifling code as a result
+HISTSIZE=32
+
+shopt -s cmdhist
+set -o history
+
+history -p '!!'
+
+history
+
+HISTFILE=/tmp/newhistory
+history -a
+
+history -w
+
+history -s "echo line 2 for history"
+history
+history -p '!e'
+history -p '!!'
+
+set -H
+!!
+!e
+
+history
+
+echo a b c d e
+!?ch?
+!-2
+^2^8
+
+!2
+
+# we're selecting /bin/sh -c ...; we want `sh'
+echo !-1:0:t
+# we're selecting /bin/sh -c ...; we want `/bin'
+echo !-2:0:h
+# we're selecting `echo a b c d e'; we want `e'
+echo !?d?:5
+
+echo a b c d e
+echo !-1:2-$
+echo !-2:2-4
+echo !-2:3*
+echo !!:*
+
+echo !?a?:2-
+
+echo file.c
+echo !!:$:r
+echo !-2:$:e
+echo !-3:$:r:q
+
+echo $file.c
+echo !!:$:r
+echo !-2:^:e
+echo !-3:$:r:q
+
+echo a b c d e
+echo !!:1-$:x
+echo !-2:1-$:q
+
+echo foo.c foo.o foo.html foo.h
+!!:s/foo/bar/
+!-2:gs/foo/bar/
+!!:gs/bar/x&/
+!-2:g&
+
+# make sure we can use any delimiter in the substitution, not just `/'
+!!:gs+bar+whix+
+
+!!:p
+
+# wow
+echo !?.o?:%:r:q
+
+!!:0 !?.h?:%:q
+!!:-$
+!:-$
+
+history
+
+# make sure single quotes inhibit history expansion
+echo '!!'
+
+# make sure backslashes can quote the history expansion character
+echo \!\!
+
+# but other expansions on the line should still be processed
+
+echo '!!' !!:*
+history -c
+unset HISTFILE
+
+# make sure that the special bash cases are not history expanded
+case p in
+[!A-Z]) echo ok 1;;
+esac
+
+var1='ok 2'
+var2=var1
+
+echo ${!var2}
diff --git a/tests/history.list b/tests/history.list
new file mode 100644
index 00000000..2a4c2229
--- /dev/null
+++ b/tests/history.list
@@ -0,0 +1,4 @@
+for i in one two three; do echo $i; done
+/bin/sh -c 'echo this is $0'
+ls
+echo $BASH_VERSION
diff --git a/tests/history.right b/tests/history.right
new file mode 100644
index 00000000..331cc034
--- /dev/null
+++ b/tests/history.right
@@ -0,0 +1,104 @@
+ 1 for i in one two three; do echo $i; done
+ 2 /bin/sh -c 'echo this is $0'
+ 3 ls
+ 4 echo $BASH_VERSION
+1 for i in one two three; do echo $i; done
+2 /bin/sh -c 'echo this is $0'
+3 ls
+4 echo $BASH_VERSION
+ for i in one two three; do echo $i; done
+ /bin/sh -c 'echo this is $0'
+ ls
+ echo $BASH_VERSION
+4 echo $BASH_VERSION
+3 ls
+2 /bin/sh -c 'echo this is $0'
+1 for i in one two three; do echo $i; done
+ echo $BASH_VERSION
+ ls
+ /bin/sh -c 'echo this is $0'
+ for i in one two three; do echo $i; done
+ 1 for i in one two three; do echo $i; done
+ 2 /bin/sh -c 'echo this is $0'
+ 3 ls
+ 4 echo $BASH_VERSION
+ 5 echo line for history
+echo line for history
+ for i in one two three; do echo $i; done
+ /bin/sh -c 'echo this is $0'
+ ls
+ echo $BASH_VERSION
+ echo line for history
+displaying $HISTFILE after history -a
+echo line for history
+HISTFILE=/tmp/newhistory
+ 1 for i in one two three; do echo $i; done
+ 2 /bin/sh -c 'echo this is $0'
+ 3 ls
+ 4 echo $BASH_VERSION
+ 5 echo line for history
+ 6 HISTFILE=/tmp/newhistory
+ 7 echo displaying \$HISTFILE after history -a
+ 8 cat $HISTFILE
+for i in one two three; do echo $i; done
+/bin/sh -c 'echo this is $0'
+ls
+echo $BASH_VERSION
+echo line for history
+HISTFILE=/tmp/newhistory
+echo displaying \$HISTFILE after history -a
+cat $HISTFILE
+ 1 for i in one two three; do echo $i; done
+ 2 /bin/sh -c 'echo this is $0'
+ 3 ls
+ 4 echo $BASH_VERSION
+ 5 echo line for history
+ 6 HISTFILE=/tmp/newhistory
+ 7 echo displaying \$HISTFILE after history -a
+ 8 cat $HISTFILE
+ 9 echo line 2 for history
+echo line 2 for history
+echo line 2 for history
+ 1 for i in one two three; do echo $i; done
+ 2 /bin/sh -c 'echo this is $0'
+ 3 ls
+ 4 echo $BASH_VERSION
+ 5 echo line for history
+ 6 HISTFILE=/tmp/newhistory
+ 7 echo displaying \$HISTFILE after history -a
+ 8 cat $HISTFILE
+ 9 echo line 2 for history
+ 10 # this should show up as one history entry
+ 11 for x in one two three; do :; done
+set -H
+echo line 2 for history
+line 2 for history
+4 echo $BASH_VERSION
+5 echo line for history
+6 HISTFILE=/tmp/newhistory
+7 echo displaying \$HISTFILE after history -a
+8 cat $HISTFILE
+9 echo line 2 for history
+10 # this should show up as one history entry
+11 for x in one two three; do :; done
+12 # just a basic test. a full test suite for history expansion should be
+13 # created
+14 set -H
+15 echo line 2 for history
+16 unset HISTSIZE
+17 unset HISTFILE
+4 echo $BASH_VERSION
+5 echo line for history
+6 HISTFILE=/tmp/newhistory
+7 echo displaying \$HISTFILE after history -a
+8 cat $HISTFILE
+./history.tests: fc: history specification out of range
+ 14 set -H
+ 15 echo line 2 for history
+ 16 unset HISTSIZE
+ 17 unset HISTFILE
+aa ab ac
+echo xx xb xc
+xx xb xc
+./history.tests: fc: no command found
+1
diff --git a/tests/history.tests b/tests/history.tests
new file mode 100644
index 00000000..2bc09b44
--- /dev/null
+++ b/tests/history.tests
@@ -0,0 +1,83 @@
+trap 'rm /tmp/newhistory' 0
+
+history -c
+
+HISTFILE=history.list
+HISTCONTROL=ignoreboth
+HISTIGNORE='&:history*:fc*'
+HISTSIZE=32
+
+shopt -s cmdhist
+set -o history
+
+history
+
+fc -l
+fc -nl
+
+fc -lr
+fc -nlr
+
+history -s "echo line for history"
+history
+
+history -p '!!'
+
+fc -nl
+
+HISTFILE=/tmp/newhistory
+history -a
+echo displaying \$HISTFILE after history -a
+cat $HISTFILE
+
+history
+history -w
+cat $HISTFILE
+
+history -s "echo line 2 for history"
+history
+history -p '!e'
+history -p '!!'
+
+# this should show up as one history entry
+for x in one two three
+do
+ :
+done
+history
+
+# just a basic test. a full test suite for history expansion should be
+# created
+set -H
+!!
+!e
+
+unset HISTSIZE
+unset HISTFILE
+
+fc -l 4
+fc -l 4 8
+
+fc -l 502
+
+history 4
+
+shopt -so history
+shopt -s expand_aliases
+
+alias r="fc -s"
+
+echo aa ab ac
+
+r a=x
+
+# this had better fail with `no command found'
+r cc
+
+unalias -a
+alias
+
+set +o history
+
+shopt -q -o history
+echo $?
diff --git a/tests/jobs.right b/tests/jobs.right
new file mode 100644
index 00000000..f67579d5
--- /dev/null
+++ b/tests/jobs.right
@@ -0,0 +1,71 @@
+0
+wait-for-pid
+wait-errors
+./jobs.tests: wait: `1-1' is not a pid or valid job spec
+./jobs.tests: wait: `-4' is not a pid or valid job spec
+wait-for-background-pids
+async list wait-for-background-pids
+async list wait for child
+forked
+wait-when-no-children
+wait-for-job
+./jobs.tests: wait: %2: no such job
+127
+async list wait-for-job
+forked
+fg-bg 1
+sleep 5
+fg-bg 2
+sleep 5
+fg-bg 3
+sleep 5
+fg-bg 4
+sleep 5
+fg-bg 5
+./jobs.tests: fg: %2: no such job
+./jobs.tests: bg: bg background job?
+fg-bg 6
+./jobs.tests: fg: illegal option: -s
+fg: usage: fg [job_spec]
+./jobs.tests: bg: illegal option: -s
+bg: usage: bg [job_spec]
+./jobs.tests: disown: illegal option: -r
+disown: usage: disown [-h] [jobspec ...]
+./jobs.tests: disown: %1: no such job
+wait-for-non-child
+./jobs.tests: wait: pid 1 is not a child of this shell
+127
+3 -- 1 2 3 -- 1 - 2 - 3
+[1] Running sleep 300 &
+[2]- Running sleep 350 &
+[3]+ Running sleep 400 &
+running jobs:
+[1] Running sleep 300 &
+[2]- Running sleep 350 &
+[3]+ Running sleep 400 &
+./jobs.tests: kill: %4: no such job
+after kill -STOP
+running jobs:
+[1] Running sleep 300 &
+[3]- Running sleep 400 &
+stopped jobs:
+[2]+ Stopped sleep 350
+after disown
+[2]+ Stopped sleep 350
+[3]- Running sleep 400 &
+running jobs:
+[3]- Running sleep 400 &
+stopped jobs:
+[2]+ Stopped sleep 350
+after kill -s CONT
+running jobs:
+[2]+ Running sleep 350 &
+[3]- Running sleep 400 &
+stopped jobs:
+after kill -STOP, backgrounding %3:
+[3]+ sleep 400 &
+killing...
+done
+after KILL -STOP, foregrounding %1
+sleep 10
+done
diff --git a/tests/jobs.tests b/tests/jobs.tests
new file mode 100644
index 00000000..cd044f15
--- /dev/null
+++ b/tests/jobs.tests
@@ -0,0 +1,145 @@
+jobs
+echo $?
+
+echo wait-for-pid
+sleep 10 &
+wait $!
+
+echo wait-errors
+wait 1-1
+wait -- -4
+
+echo wait-for-background-pids
+sleep 5 &
+sleep 8 &
+wait
+
+echo async list wait-for-background-pids
+sleep 5 & sleep 8 &
+wait
+
+echo async list wait for child
+sleep 5 & echo forked
+wait
+
+echo wait-when-no-children
+wait
+
+set -m
+
+echo wait-for-job
+sleep 5 &
+wait %2 # this should be a no-such-job error
+echo $?
+wait %1
+
+echo async list wait-for-job
+sleep 5 & echo forked
+wait %1
+
+echo fg-bg 1
+sleep 5 &
+%1
+
+echo fg-bg 2
+sleep 5 &
+fg %%
+
+echo fg-bg 3
+sleep 5 &
+fg %s
+
+echo fg-bg 4
+sleep 5 &
+fg %?ee
+
+# these next two are error cases
+echo fg-bg 5
+sleep 15 &
+fg %2 # this should be a no-such-job error
+bg %1 # this should be a `bg background job?' error
+wait
+
+# these may someday mean to start the jobs, but not print the line
+# describing the status, but for now they are errors
+echo fg-bg 6
+sleep 5 &
+fg -s %1
+bg -s %1
+wait
+
+# someday this may mean to disown all running jobs, but for now it is
+# an error
+disown -r
+
+# this is an error
+disown %1
+
+echo wait-for-non-child
+wait 1
+echo $?
+
+exit 1 | exit 2 | exit 3
+echo $? -- ${PIPESTATUS[@]} -- ${PIPESTATUS[0]} - ${PIPESTATUS[1]} - ${PIPESTATUS[2]}
+
+sleep 300 &
+sleep 350 &
+sleep 400 &
+
+jobs
+
+echo running jobs:
+jobs -r
+
+# should be an error
+kill -n 1 %4
+
+kill -STOP %2
+sleep 5 # give time for the shell to get the stop notification
+echo after kill -STOP
+echo running jobs:
+jobs -r
+echo stopped jobs:
+jobs -s
+
+disown %1
+
+echo after disown
+jobs
+echo running jobs:
+jobs -r
+echo stopped jobs:
+jobs -s
+
+kill -s CONT %2
+echo after kill -s CONT
+echo running jobs:
+jobs -r
+echo stopped jobs:
+jobs -s
+
+kill -STOP %3
+sleep 5 # give time for the shell to get the stop notification
+echo after kill -STOP, backgrounding %3:
+bg %3
+
+disown -h %2
+
+# make sure the killed processes don't cause a message
+exec 5>&2
+exec 2>/dev/null
+
+echo killing...
+kill -n 9 %2 %3
+wait # make sure we reap the processes while stderr is still redirected
+echo done
+
+exec 2>&5
+
+sleep 10 &
+kill -STOP %1
+sleep 5 # give time for the shell to get the stop notification
+echo after KILL -STOP, foregrounding %1
+fg %1
+
+echo done
diff --git a/tests/minus-e b/tests/minus-e
deleted file mode 100644
index be67ec58..00000000
--- a/tests/minus-e
+++ /dev/null
@@ -1,6 +0,0 @@
-set -e
-if set +e
-then
- false
-fi
-echo hi
diff --git a/tests/minus-e.right b/tests/minus-e.right
deleted file mode 100644
index 45b983be..00000000
--- a/tests/minus-e.right
+++ /dev/null
@@ -1 +0,0 @@
-hi
diff --git a/tests/misc/chld-trap.sh b/tests/misc/chld-trap.sh
deleted file mode 100755
index 89b342dc..00000000
--- a/tests/misc/chld-trap.sh
+++ /dev/null
@@ -1,14 +0,0 @@
-#! /bin/sh
-#
-# show that setting a trap on SIGCHLD is not disastrous.
-#
-
-trap 'echo caught a child death' SIGCHLD
-
-sleep 5 &
-sleep 5 &
-sleep 5 &
-
-wait
-
-exit 0
diff --git a/tests/misc/dot-test-1.sh b/tests/misc/dot-test-1.sh
deleted file mode 100644
index eab465ef..00000000
--- a/tests/misc/dot-test-1.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-echo this is $0
-. ./dot-test-1.sub
-echo after . dot-test-1.sub
diff --git a/tests/misc/dot-test-1.sub b/tests/misc/dot-test-1.sub
deleted file mode 100644
index 58df5f4f..00000000
--- a/tests/misc/dot-test-1.sub
+++ /dev/null
@@ -1 +0,0 @@
-echo this is dot-test-1.sub
diff --git a/tests/misc/haertel.perftest b/tests/misc/haertel.perftest
new file mode 100644
index 00000000..04910c89
--- /dev/null
+++ b/tests/misc/haertel.perftest
@@ -0,0 +1,9 @@
+foo() { case $1 in a*) ;; *) ;; esac ;}
+bar() { case $1 in [abc]*) ;; *);; esac ;}
+baz() { case $1 in xyzzy) ;; *) ;; esac ;}
+for x in /usr/lib/*/*
+do
+ foo $x
+ bar $x
+ baz $x
+done
diff --git a/tests/misc/redir.t3.sh b/tests/misc/redir.t3.sh
deleted file mode 100755
index 9fd42c79..00000000
--- a/tests/misc/redir.t3.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# Test the effect of input buffering on the shell's input
-#
-echo this is redir.t3.sh
-
-exec 0< redir.t3.sub
-
-echo after exec in redir.t3.sh
diff --git a/tests/misc/redir.t3.sub b/tests/misc/redir.t3.sub
deleted file mode 100644
index b32fbaa8..00000000
--- a/tests/misc/redir.t3.sub
+++ /dev/null
@@ -1 +0,0 @@
-echo this is redir-test-3.sub
diff --git a/tests/misc/redir.t4.sh b/tests/misc/redir.t4.sh
deleted file mode 100644
index 78633dc5..00000000
--- a/tests/misc/redir.t4.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-echo "Point 1"
-exec 3</etc/passwd
-exec 4>/tmp/a
-exec 5>/tmp/b
-echo "Point 2"
-echo to a 1>&4
-echo to b 1>&5
-exec 11</etc/printcap
-echo "Point 3"
-echo to a 1>&4
-echo to b 1>&5
-exit 0
diff --git a/tests/misc/run.r1.sh b/tests/misc/run.r1.sh
deleted file mode 100755
index bf22fe32..00000000
--- a/tests/misc/run.r1.sh
+++ /dev/null
@@ -1 +0,0 @@
-../../bash redir.t1.sh
diff --git a/tests/misc/run.r3.sh b/tests/misc/run.r3.sh
deleted file mode 100755
index b4136742..00000000
--- a/tests/misc/run.r3.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-#
-# the `after exec in ...' should not be echoed
-../../bash < redir.t3.sh
diff --git a/tests/misc/test-minus-e.1 b/tests/misc/test-minus-e.1
index 03d7ecfc..77cc3f26 100644
--- a/tests/misc/test-minus-e.1
+++ b/tests/misc/test-minus-e.1
@@ -7,6 +7,3 @@ while set -e ; test -r .file ; do
esac
set +e
done
-
-
-
diff --git a/tests/misc/test-minus-e.2 b/tests/misc/test-minus-e.2
index ad6a0c81..f66966eb 100644
--- a/tests/misc/test-minus-e.2
+++ b/tests/misc/test-minus-e.2
@@ -9,6 +9,3 @@ while set +e ; test -r .file ; do
set -e
done
rm -f .file
-
-
-
diff --git a/tests/new-exp.right b/tests/new-exp.right
index ea4d3278..f7d9b63e 100644
--- a/tests/new-exp.right
+++ b/tests/new-exp.right
@@ -28,9 +28,12 @@ bar foo
bar foo
barfoo
barfoo
+\x
argv[1] = <abcd>
argv[1] = <efg>
argv[2] = <nop>
+argv[1] = <efg>
+argv[2] = <nop>
argv[1] = <hijklmnop>
argv[1] = <abcdefghijklmnop>
argv[1] = <abcdefghijklmnop>
@@ -216,4 +219,169 @@ argv[1] = <oneonetwo>
argv[1] = <onetwo>
argv[1] = <two>
argv[1] = <oneonetwo>
+./new-exp.tests: -2: substring expression < 0
+argv[1] = <defghi>
+argv[1] = <efghi>
+argv[1] = <e*docrine>
+argv[1] = <e*docri*e>
+argv[1] = <endocrine>
+argv[1] = <endocrine>
+argv[1] = </usr/bin>
+argv[2] = </bin>
+argv[3] = </usr/local/bin>
+argv[4] = </usr/gnu/bin>
+argv[5] = </usr/bin/X11>
+argv[6] = </sbin>
+argv[7] = </usr/sbin>
+argv[1] = <r>
+argv[2] = <s>
+argv[3] = <t>
+argv[4] = <u>
+argv[5] = <v>
+argv[6] = <w>
+argv[7] = <x>
+argv[8] = <y>
+argv[9] = <z>
+argv[1] = <r>
+argv[2] = <s>
+argv[3] = <t>
+argv[4] = <u>
+argv[5] = <v>
+argv[6] = <w>
+argv[7] = <x>
+argv[8] = <y>
+argv[9] = <z>
+argv[1] = <r>
+argv[2] = <s>
+argv[3] = <t>
+argv[4] = <u>
+argv[5] = <v>
+argv[6] = <w>
+argv[7] = <x>
+argv[8] = <y>
+argv[9] = <z>
+argv[1] = <r>
+argv[2] = <s>
+argv[3] = <t>
+argv[4] = <u>
+argv[5] = <v>
+argv[6] = <w>
+argv[7] = <x>
+argv[8] = <y>
+argv[9] = <z>
+argv[1] = <a>
+argv[2] = <a>
+argv[3] = <a>
+argv[4] = <a>
+argv[5] = <a>
+argv[6] = <a>
+argv[7] = <a>
+argv[8] = <a>
+argv[9] = <a>
+argv[1] = <a>
+argv[2] = <a>
+argv[3] = <a>
+argv[4] = <a>
+argv[5] = <a>
+argv[6] = <a>
+argv[7] = <a>
+argv[8] = <a>
+argv[9] = <a>
+argv[1] = <r>
+argv[2] = <s>
+argv[3] = <t>
+argv[4] = <u>
+argv[5] = <v>
+argv[6] = <w>
+argv[7] = <x>
+argv[8] = <y>
+argv[9] = <z>
+argv[1] = <r>
+argv[2] = <s>
+argv[3] = <t>
+argv[4] = <u>
+argv[5] = <v>
+argv[6] = <w>
+argv[7] = <x>
+argv[8] = <y>
+argv[9] = <z>
+argv[1] = <r>
+argv[2] = <s>
+argv[3] = <t>
+argv[4] = <u>
+argv[5] = <v>
+argv[6] = <w>
+argv[7] = <x>
+argv[8] = <y>
+argv[9] = <z>
+argv[1] = <r>
+argv[2] = <s>
+argv[3] = <t>
+argv[4] = <u>
+argv[5] = <v>
+argv[6] = <w>
+argv[7] = <x>
+argv[8] = <y>
+argv[9] = <z>
+argv[1] = <r>
+argv[2] = <s>
+argv[3] = <t>
+argv[4] = <u>
+argv[5] = <v>
+argv[6] = <w>
+argv[7] = <x>
+argv[8] = <y>
+argv[9] = <z>
+argv[1] = <r>
+argv[2] = <s>
+argv[3] = <t>
+argv[4] = <u>
+argv[5] = <v>
+argv[6] = <w>
+argv[7] = <x>
+argv[8] = <y>
+argv[9] = <z>
+argv[1] = <a>
+argv[2] = <a>
+argv[3] = <a>
+argv[4] = <a>
+argv[5] = <a>
+argv[6] = <a>
+argv[7] = <a>
+argv[8] = <a>
+argv[9] = <a>
+argv[1] = <a>
+argv[2] = <a>
+argv[3] = <a>
+argv[4] = <a>
+argv[5] = <a>
+argv[6] = <a>
+argv[7] = <a>
+argv[8] = <a>
+argv[9] = <a>
+argv[1] = <r>
+argv[2] = <s>
+argv[3] = <t>
+argv[4] = <u>
+argv[5] = <v>
+argv[6] = <w>
+argv[7] = <x>
+argv[8] = <y>
+argv[9] = <z>
+argv[1] = <r>
+argv[2] = <s>
+argv[3] = <t>
+argv[4] = <u>
+argv[5] = <v>
+argv[6] = <w>
+argv[7] = <x>
+argv[8] = <y>
+argv[9] = <z>
+./new-exp.tests: $9: unbound variable
+./new-exp.tests: 9: unbound variable
+./new-exp.tests: UNSET: unbound variable
+./new-exp.tests: UNSET: unbound variable
+./new-exp.tests: UNSET: unbound variable
+./new-exp.tests: UNSET: unbound variable
+./new-exp.tests: UNSET: unbound variable
./new-exp.tests: ABXD: parameter unset
diff --git a/tests/new-exp.sub1 b/tests/new-exp.sub1
new file mode 100644
index 00000000..c015c223
--- /dev/null
+++ b/tests/new-exp.sub1
@@ -0,0 +1,11 @@
+expect()
+{
+ echo expect "$@"
+}
+
+expect this is a test of proc subst
+cat <(echo this is a test of proc subst)
+echo this is test 2 > /tmp/x
+expect this is test 2
+cat <(cat /tmp/x)
+rm -f /tmp/x
diff --git a/tests/new-exp.tests b/tests/new-exp.tests
index 4ac36d01..cae732e3 100644
--- a/tests/new-exp.tests
+++ b/tests/new-exp.tests
@@ -1,3 +1,7 @@
+# must do this because posix mode causes process substitution to be disabled
+# and flagged as a syntax error, which causes the shell to exit
+set +o posix
+
expect()
{
echo expect "$@"
@@ -83,6 +87,11 @@ echo -e "$foo\c " ; echo foo
expect '<barfoo>'
echo -e $foo"\c " ; echo foo
+# make sure backslashes are preserved in front of characters that are not
+# valid backslash escapes
+expect '<\x>'
+echo -e '\x'
+
# substring tests
z=abcdefghijklmnop
expect '<abcd>'
@@ -91,6 +100,9 @@ recho ${z:0:4}
expect '<efg> <nop>'
recho ${z:4:3} ${z:${#z}-3:3}
+expect '<efg> <nop>'
+recho ${z:4:3} ${z: -3:3}
+
expect '<hijklmnop>'
recho ${z:7:30}
@@ -138,7 +150,7 @@ recho ${!1-$z}
set -u
expect $0: ABX: unbound variable
-recho ${ABX}
+( recho ${ABX} )
set +u
expect $0: '$6: cannot assign in this way'
@@ -222,12 +234,10 @@ recho ${@//%x*/yyy}
expect a newline
echo $abmcde
-expect this is a test of proc subst
-cat <(echo this is a test of proc subst)
-echo this is test 2 > /tmp/x
-expect this is test 2
-cat <(cat /tmp/x)
-rm -f /tmp/x
+# run process substitution tests in a subshell so that syntax errors
+# caused by a shell not implementing process substitution (e.g., one
+# built on a NeXT) will not cause the whole test to exit prematurely
+${THIS_SH} ./new-exp.sub1
expect $0: '${#:-foo}: bad substitution'
echo ${#:-foo}
@@ -367,6 +377,78 @@ recho ${xx/one}
recho ${xx//one}
recho ${xx/\/one}
+# out-of-range substrings
+var=abc
+c=${var:3}
+expect nothing
+recho $c
+c=${var:4}
+expect nothing
+recho $c
+expect '<./new-exp.tests: -2: substring expression < 0>'
+c=${var:0:-2}
+
+var=abcdefghi
+c=${var:3:12}
+recho $c
+c=${var:4:20}
+recho $c
+
+# make sure null patterns work
+xxx=endocrine
+yyy=n
+unset zzz
+
+recho ${xxx/$yyy/*}
+recho ${xxx//$yyy/*}
+
+recho ${xxx/$zzz/*}
+recho ${xxx//$zzz/*}
+
+# another case that caused a core dump in bash-2.0
+XPATH=/usr/bin:/bin:/usr/local/bin:/usr/gnu/bin::/usr/bin/X11:/sbin:/usr/sbin
+
+recho ${XPATH//:/ }
+
+xx=(ar as at au av aw ax ay az)
+
+recho ${xx[@]/a/}
+recho ${xx[@]//a/}
+
+recho ${xx[*]/a/}
+recho ${xx[*]//a/}
+
+recho ${xx[@]%?}
+recho ${xx[*]%?}
+
+recho ${xx[@]#?}
+recho ${xx[*]#?}
+
+set -- ar as at au av aw ax ay az
+
+recho ${@/a/}
+recho ${@//a/}
+
+recho ${*/a/}
+recho ${*//a/}
+
+recho ${@%?}
+recho ${*%?}
+
+recho ${@#?}
+recho ${*#?}
+
+shift $#
+set -u
+( recho $9 ; echo after 1)
+( recho ${9} ; echo after 2)
+( recho $UNSET ; echo after 3)
+( recho ${UNSET} ; echo after 4)
+( recho "$UNSET" ; echo after 5)
+( recho "${UNSET}" ; echo after 6)
+( recho "${#UNSET}" ; echo after 7)
+set +u
+
# this must be last!
expect $0: 'ABXD: parameter unset'
recho ${ABXD:?"parameter unset"}
diff --git a/tests/nquote.right b/tests/nquote.right
index 3a0fc53d..9651f311 100644
--- a/tests/nquote.right
+++ b/tests/nquote.right
@@ -14,3 +14,4 @@ argv[1] = <hello, $"world">
argv[1] = <hello, $"world">
argv[1] = <$hello, chet>
argv[1] = <hello, chet>
+ok
diff --git a/tests/nquote.tests b/tests/nquote.tests
index a2e596b2..6ce89079 100644
--- a/tests/nquote.tests
+++ b/tests/nquote.tests
@@ -55,3 +55,9 @@ recho \$"hello, $world"
expect '<hello, chet>'
recho $"hello, $world"
+
+z=$'\v\f\a\b'
+case "$z" in
+$'\v\f\a\b') echo ok;;
+*) echo bad;;
+esac
diff --git a/tests/read.right b/tests/read.right
index 68ce898a..5a7be60d 100644
--- a/tests/read.right
+++ b/tests/read.right
@@ -12,3 +12,15 @@ a.
1: x[A] y[B] z[]
1a:
2: x[A B]
+[A B ]
+[ A B ]
+==aa==
+====
+====
+argv[1] = < foo>
+argv[1] = < foo>
+argv[1] = <foo>
+argv[1] = < foo>
+argv[1] = <foo>
+argv[1] = <foo>
+argv[1] = < foo>
diff --git a/tests/read.tests b/tests/read.tests
index ad814d6d..fd592846 100644
--- a/tests/read.tests
+++ b/tests/read.tests
@@ -22,3 +22,48 @@ read x < /tmp/IN
echo 2: "x[$x]"
rm /tmp/IN
+# this is where the bash `read' behavior with respect to $REPLY differs
+# from ksh93
+echo "A B " > /tmp/IN
+
+read < /tmp/IN
+echo "[$REPLY]"
+
+rm /tmp/IN
+
+echo " A B " > /tmp/IN
+
+read < /tmp/IN
+echo "[$REPLY]"
+
+rm /tmp/IN
+
+# make sure that read with more variables than words sets the extra
+# variables to the empty string
+
+bvar=bvar
+cvar=cvar
+echo aa > /tmp/IN
+read avar bvar cvar < /tmp/IN
+echo =="$avar"==
+echo =="$bvar"==
+echo =="$cvar"==
+
+rm /tmp/IN
+
+# test behavior of read with various settings of IFS
+
+echo " foo" | { IFS= read line; recho "$line"; }
+
+echo " foo" | { IFS= ; read line; recho "$line"; }
+
+echo " foo" | { unset IFS ; read line; recho "$line"; }
+
+echo " foo" | { IFS=$'\n' ; read line; recho "$line"; }
+
+echo " foo" | { IFS=$' \n' ; read line; recho "$line"; }
+
+echo " foo" | { IFS=$' \t\n' ; read line; recho "$line"; }
+
+echo " foo" | { IFS=$':' ; read line; recho "$line"; }
+
diff --git a/tests/redir.right b/tests/redir.right
new file mode 100644
index 00000000..09272fe3
--- /dev/null
+++ b/tests/redir.right
@@ -0,0 +1,47 @@
+abc
+./redir.tests: /tmp/redir-test: cannot overwrite existing file
+abc
+def
+def
+./redir.tests: $z: ambiguous redirect
+Point 1
+Point 2
+to a
+to b
+Point 3
+to a
+to a
+to b
+to b
+Point 4
+to c
+Point 5
+this is redir1.sub
+this is redir2.sub
+read line1 "ab"
+read line2 "root"
+read line3 "cd"
+read line4 "daemon"
+from stdin: aa
+to stdout
+./redir4.sub: $fd: ambiguous redirect
+./redir4.sub: $fd: ambiguous redirect
+/tmp/err-and-out:
+to stdout
+to stderr
+/tmp/err-and-out:
+to stdout
+to stderr
+0 -- 3 0
+0 -- 4 0
+ab
+cd
+ef
+gh
+ij
+kl
+0
+ab
+cd
+cd
+./redir.tests: redir1.*: No such file or directory
diff --git a/tests/redir.tests b/tests/redir.tests
new file mode 100644
index 00000000..4e58754d
--- /dev/null
+++ b/tests/redir.tests
@@ -0,0 +1,147 @@
+export LC_ALL=C
+export LANG=C
+
+# catch-all for remaining untested redirection stuff
+set +o posix
+
+echo abc > /tmp/redir-test
+cat /tmp/redir-test
+
+set -o noclobber
+
+#this should be an error
+echo def > /tmp/redir-test
+cat /tmp/redir-test
+
+# but this should succeed
+echo def > /tmp/redir-test-2
+cat /tmp/redir-test-2
+
+# and so should this
+echo def >| /tmp/redir-test
+cat /tmp/redir-test
+
+set +o noclobber
+rm /tmp/redir-test /tmp/redir-test-2
+
+# this should be an error
+z="a b"
+cat < $z
+
+echo "Point 1"
+
+exec 3</etc/passwd
+exec 4>/tmp/bash-a
+exec 5>/tmp/bash-b
+echo "Point 2"
+
+echo to a 1>&4
+echo to b 1>&5
+cat /tmp/bash-a
+cat /tmp/bash-b
+exec 11</dev/null
+echo "Point 3"
+
+echo to a 1>&4
+echo to b 1>&5
+cat /tmp/bash-a
+cat /tmp/bash-b
+
+exec 11<&-
+echo "Point 4"
+
+exec 6<>/tmp/bash-c
+echo to c 1>&6
+cat /tmp/bash-c
+echo "Point 5"
+
+rm -f /tmp/bash-a /tmp/bash-b /tmp/bash-c
+
+#
+# Test the effect of input buffering on the shell's input
+#
+${THIS_SH} < redir1.sub
+
+# more open, close, duplicate file descriptors
+${THIS_SH} ./redir3.sub < ./redir3.in1
+
+# still more redirections
+${THIS_SH} ./redir4.sub < redir4.in1
+
+# various forms of null redirection
+testf()
+{
+ if [ -f "$1" ]; then
+ rm -f "$1"
+ else
+ echo oops -- $1 not found
+ fi
+}
+
+> /tmp/null-redir-a
+testf /tmp/null-redir-a
+
+$EXIT > /tmp/null-redir-b
+testf /tmp/null-redir-b
+
+( > /tmp/null-redir-c )
+testf /tmp/null-redir-c
+
+$EXIT > /tmp/null-redir-d &
+wait
+testf /tmp/null-redir-d
+
+exit 3 | $EXIT > /tmp/null-redir-e
+echo $? -- ${PIPESTATUS[@]}
+testf /tmp/null-redir-e
+
+exit 4 | > /tmp/null-redir-f
+echo $? -- ${PIPESTATUS[@]}
+testf /tmp/null-redir-f
+
+> /tmp/null-redir-g &
+wait
+testf /tmp/null-redir-g
+
+exec >/tmp/null-redir-h &
+wait
+testf /tmp/null-redir-h
+
+# make sure async commands don't get /dev/null as stdin when an explicit
+# input redirection is supplied
+for x in 1 2 3; do
+ { read line ; echo $line ; } &
+ wait
+ { read line ; echo $line ; } &
+ wait
+done << EOF
+ab
+cd
+ef
+gh
+ij
+kl
+EOF
+
+# make sure async commands get /dev/null as stdin in the absence of any
+# input redirection
+/bin/cat &
+wait
+echo $?
+
+# make sure that loops work OK with here documents and are not run in
+# subshells
+while read line; do
+ echo $line
+ l2=$line
+done << EOF
+ab
+cd
+EOF
+echo $l2
+
+# in posix mode, non-interactive shells are not allowed to perform
+# filename expansion on input redirections, even if they expand to
+# a single filename
+set -o posix
+cat < redir1.*
diff --git a/tests/redir1.sub b/tests/redir1.sub
new file mode 100644
index 00000000..f1082e9f
--- /dev/null
+++ b/tests/redir1.sub
@@ -0,0 +1,8 @@
+#
+# Test the effect of input buffering on the shell's input
+#
+echo this is redir1.sub
+
+exec 0< redir2.sub
+
+echo BUG: after exec in redir1.sub
diff --git a/tests/redir2.sub b/tests/redir2.sub
new file mode 100644
index 00000000..0820f701
--- /dev/null
+++ b/tests/redir2.sub
@@ -0,0 +1 @@
+echo this is redir2.sub
diff --git a/tests/redir3.in1 b/tests/redir3.in1
new file mode 100644
index 00000000..dbd1fc36
--- /dev/null
+++ b/tests/redir3.in1
@@ -0,0 +1,2 @@
+ab
+cd
diff --git a/tests/redir3.in2 b/tests/redir3.in2
new file mode 100644
index 00000000..5a1c32b0
--- /dev/null
+++ b/tests/redir3.in2
@@ -0,0 +1,2 @@
+root
+daemon
diff --git a/tests/misc/redir.t1.sh b/tests/redir3.sub
index 0ea00f92..c486253e 100644
--- a/tests/misc/redir.t1.sh
+++ b/tests/redir3.sub
@@ -2,7 +2,7 @@ read line1
echo read line1 \"$line1\"
-exec 4</etc/passwd
+exec 4<./redir3.in2
exec 5<&0
exec 0<&4
diff --git a/tests/redir4.in1 b/tests/redir4.in1
new file mode 100644
index 00000000..e61ef7b9
--- /dev/null
+++ b/tests/redir4.in1
@@ -0,0 +1 @@
+aa
diff --git a/tests/redir4.sub b/tests/redir4.sub
new file mode 100644
index 00000000..47344554
--- /dev/null
+++ b/tests/redir4.sub
@@ -0,0 +1,56 @@
+minus=-
+
+# standard input
+fd=0
+
+exec 3<&$fd
+
+read line <&3
+echo from stdin: $line
+
+# close fd 3
+exec 3<&${minus}
+
+# should give `bad fd', but exact error messages vary
+# read line <&3
+
+# standard output
+fd=1
+
+exec 4>&$fd
+
+echo to stdout >&4
+
+exec 4>&$minus
+
+# should give `bad fd', but exact error messages vary
+# echo to stdout >&4
+
+unset fd
+
+# these are ambiguous redirects
+exec 3<&$fd
+exec 4>&$fd
+
+exec 3>&1 4>&2
+
+exec >&/tmp/err-and-out
+echo to stdout
+echo to stderr >&2
+
+exec 1>&3 2>&4
+echo /tmp/err-and-out:
+cat /tmp/err-and-out
+
+rm /tmp/err-and-out
+
+fd=/tmp/err-and-out
+exec >&$fd
+echo to stdout
+echo to stderr >&2
+
+exec 1>&3 2>&4
+echo /tmp/err-and-out:
+cat /tmp/err-and-out
+
+rm /tmp/err-and-out
diff --git a/tests/rsh.right b/tests/rsh.right
new file mode 100644
index 00000000..2c48ef41
--- /dev/null
+++ b/tests/rsh.right
@@ -0,0 +1,12 @@
+./rsh.tests: cd: restricted
+./rsh.tests: PATH: readonly variable
+./rsh.tests: SHELL: readonly variable
+./rsh.tests: /bin/sh: restricted: cannot specify `/' in command names
+./rsh.tests: .: ./source.sub3: restricted
+./rsh.tests: /tmp/restricted: restricted: cannot redirect output
+./rsh.tests: /tmp/restricted: restricted: cannot redirect output
+./rsh.tests: command: restricted: cannot use -p
+./rsh.tests: set: unknown option: +r
+set: usage: set [--abefhkmnptuvxBCHP] [-o option] [arg ...]
+./rsh.tests: exec: restricted
+./rsh.tests: after exec
diff --git a/tests/rsh.tests b/tests/rsh.tests
new file mode 100644
index 00000000..bd22e9f0
--- /dev/null
+++ b/tests/rsh.tests
@@ -0,0 +1,32 @@
+# test restricted shell mode -- these should all be errors
+#
+# things not tested for:
+# adding builtins dynamically with enable -f
+# importing function definitions from environment
+
+set -r
+
+cd /
+PATH=$PATH:/usr/local/bin
+SHELL=/bin/sh
+/bin/sh -c 'echo /bin/sh executed'
+
+. ./source.sub3
+
+rm -f /tmp/restricted
+echo abc > /tmp/restricted
+if [ -f /tmp/restricted ]; then
+ echo oops 1 -- output
+fi
+echo abc >> /tmp/restricted
+if [ -f /tmp/restricted ]; then
+ echo oops 2 -- append
+fi
+
+command -p date
+
+set +r
+
+exec /bin/date
+
+echo $0: after exec
diff --git a/tests/run-all b/tests/run-all
index c4badc6b..8a959a14 100644
--- a/tests/run-all
+++ b/tests/run-all
@@ -1,16 +1,20 @@
#! /bin/sh
-PATH=.:$PATH # just to get the right version of printenv
+PATH=.:$PATH # just to get recho/zecho/printenv if not run via `make tests'
export PATH
-# unset ENV only if it is set
-[ "${ENV+set}" = "set" ] && unset ENV
+# unset BASH_ENV only if it is set
+[ "${BASH_ENV+set}" = "set" ] && unset BASH_ENV
+# ditto for SHELLOPTS
+#[ "${SHELLOPTS+set}" = "set" ] && unset SHELLOPTS
: ${THIS_SH:=../bash}
export THIS_SH
-echo Testing ${THIS_SH}
-echo Any output from any test indicates an anomaly worth investigating
+${THIS_SH} ./version
+
+echo Any output from any test, unless otherwise noted, indicates a possible anomaly
+
for x in run-*
do
case $x in
diff --git a/tests/run-builtins b/tests/run-builtins
new file mode 100644
index 00000000..53d963eb
--- /dev/null
+++ b/tests/run-builtins
@@ -0,0 +1,2 @@
+${THIS_SH} ./builtins.tests > /tmp/xx 2>&1
+diff /tmp/xx builtins.right && rm -f /tmp/xx
diff --git a/tests/run-dirstack b/tests/run-dirstack
new file mode 100644
index 00000000..a2f2761d
--- /dev/null
+++ b/tests/run-dirstack
@@ -0,0 +1,2 @@
+${THIS_SH} ./dirstack.tests > /tmp/xx 2>&1
+diff /tmp/xx dirstack.right && rm -f /tmp/xx
diff --git a/tests/run-errors b/tests/run-errors
new file mode 100644
index 00000000..6be4e0c7
--- /dev/null
+++ b/tests/run-errors
@@ -0,0 +1,2 @@
+${THIS_SH} ./errors.tests > /tmp/xx 2>&1
+diff /tmp/xx errors.right && rm -f /tmp/xx
diff --git a/tests/run-execscript b/tests/run-execscript
new file mode 100644
index 00000000..fdac1eb1
--- /dev/null
+++ b/tests/run-execscript
@@ -0,0 +1,7 @@
+echo "warning: the text of a system error message may vary between systems and" >&2
+echo "warning: produce diff output." >&2
+echo "warning: if the text of the error messages concerning \`notthere' or" >&2
+echo "warning: \`/tmp/bash-notthere' not being found or \`/' being a directory" >&2
+echo "warning: produce diff output, please do not consider this a test failure" >&2
+${THIS_SH} ./execscript > /tmp/xx 2>&1
+diff /tmp/xx execscript.right && rm -f /tmp/xx
diff --git a/tests/run-func b/tests/run-func
new file mode 100644
index 00000000..f449eb86
--- /dev/null
+++ b/tests/run-func
@@ -0,0 +1,5 @@
+echo "warning: if you have exported functions defined in your environment," >&2
+echo "warning: they may show up as diff output." >&2
+echo "warning: if so, please do not consider this a test failure" >&2
+${THIS_SH} ./func.tests > /tmp/xx 2>&1
+diff /tmp/xx func.right && rm -f /tmp/xx
diff --git a/tests/run-getopts b/tests/run-getopts
new file mode 100644
index 00000000..1e8b5fb7
--- /dev/null
+++ b/tests/run-getopts
@@ -0,0 +1,2 @@
+${THIS_SH} ./getopts.tests > /tmp/xx 2>&1
+diff /tmp/xx getopts.right && rm -f /tmp/xx
diff --git a/tests/run-histexpand b/tests/run-histexpand
new file mode 100644
index 00000000..a9d0bcee
--- /dev/null
+++ b/tests/run-histexpand
@@ -0,0 +1,4 @@
+echo "warning: all of these tests will fail if history has not been compiled" >&2
+echo "warning: into the shell" >&2
+${THIS_SH} ./histexpand.tests > /tmp/xx 2>&1
+diff /tmp/xx histexpand.right && rm -f /tmp/xx
diff --git a/tests/run-history b/tests/run-history
new file mode 100644
index 00000000..ea356b19
--- /dev/null
+++ b/tests/run-history
@@ -0,0 +1,4 @@
+echo "warning: all of these tests will fail if history has not been compiled" >&2
+echo "warning: into the shell" >&2
+${THIS_SH} ./history.tests > /tmp/xx 2>&1
+diff /tmp/xx history.right && rm -f /tmp/xx
diff --git a/tests/run-jobs b/tests/run-jobs
new file mode 100644
index 00000000..e53ecd58
--- /dev/null
+++ b/tests/run-jobs
@@ -0,0 +1,5 @@
+echo "warning: some of these tests may fail if job control has not been compiled" >&2
+echo "warning: into the shell" >&2
+
+${THIS_SH} ./jobs.tests > /tmp/xx 2>&1
+diff /tmp/xx jobs.right && rm -f /tmp/xx
diff --git a/tests/run-minimal b/tests/run-minimal
new file mode 100644
index 00000000..dfe392f8
--- /dev/null
+++ b/tests/run-minimal
@@ -0,0 +1,33 @@
+#! /bin/sh
+#
+# run-minimal - a version of run-all for shells configured with
+# --enable-minimal-config
+#
+PATH=.:$PATH # just to get the right version of printenv
+export PATH
+
+# unset BASH_ENV only if it is set
+[ "${BASH_ENV+set}" = "set" ] && unset BASH_ENV
+# ditto for SHELLOPTS
+#[ "${SHELLOPTS+set}" = "set" ] && unset SHELLOPTS
+
+: ${THIS_SH:=../bash}
+export THIS_SH
+
+${THIS_SH} ./version.mini
+
+echo Testing ${THIS_SH}
+echo Any output from any test, unless otherwise noted, indicates a possible anomaly
+for x in run-*
+do
+ case $x in
+ $0) ;;
+ *.orig|*~) ;;
+ run-dollars|run-execscript|run-func|run-getopts|run-heredoc) echo $x ; sh $x ;;
+ run-ifs-tests|run-input-test|run-more-exp|run-nquote|run-posix2) echo $x ; sh $x ;;
+ run-precedence|run-quote|run-read|run-rhs-exp|run-strip|run-tilde) echo $x ; sh $x ;;
+ *) ;;
+ esac
+done
+
+exit 0
diff --git a/tests/run-minus-e b/tests/run-minus-e
deleted file mode 100644
index 2a91a3d2..00000000
--- a/tests/run-minus-e
+++ /dev/null
@@ -1,2 +0,0 @@
-${THIS_SH} ./minus-e > /tmp/xx
-diff /tmp/xx minus-e.right && rm -f /tmp/xx
diff --git a/tests/run-redir b/tests/run-redir
new file mode 100644
index 00000000..c7a54757
--- /dev/null
+++ b/tests/run-redir
@@ -0,0 +1,6 @@
+echo "warning: the text of a system error message may vary between systems and" >&2
+echo "warning: produce diff output." >&2
+echo "warning: if the text of an error message concerning \`redir1.*' not being" >&2
+echo "warning: found produces diff output, please do not consider it a test failure" >&2
+${THIS_SH} ./redir.tests > /tmp/xx 2>&1
+diff /tmp/xx redir.right && rm -f /tmp/xx
diff --git a/tests/run-rsh b/tests/run-rsh
new file mode 100644
index 00000000..ef235837
--- /dev/null
+++ b/tests/run-rsh
@@ -0,0 +1,2 @@
+${THIS_SH} ./rsh.tests > /tmp/xx 2>&1
+diff /tmp/xx rsh.right && rm -f /tmp/xx
diff --git a/tests/run-test b/tests/run-test
index ab13380a..645693f9 100644
--- a/tests/run-test
+++ b/tests/run-test
@@ -1,2 +1,2 @@
-${THIS_SH} ./test-tests 2>&1 > /tmp/xx
+${THIS_SH} ./test-tests >/tmp/xx 2>&1
diff /tmp/xx test.right && rm -f /tmp/xx
diff --git a/tests/run-trap b/tests/run-trap
new file mode 100644
index 00000000..78a164e7
--- /dev/null
+++ b/tests/run-trap
@@ -0,0 +1,2 @@
+${THIS_SH} ./trap.tests > /tmp/xx 2>&1
+diff /tmp/xx trap.right && rm -f /tmp/xx
diff --git a/tests/run-type b/tests/run-type
new file mode 100644
index 00000000..4d195b01
--- /dev/null
+++ b/tests/run-type
@@ -0,0 +1,2 @@
+${THIS_SH} ./type.tests > /tmp/xx 2>&1
+diff /tmp/xx type.right && rm -f /tmp/xx
diff --git a/tests/set-e-test b/tests/set-e-test
index 214ff881..895aff76 100644
--- a/tests/set-e-test
+++ b/tests/set-e-test
@@ -17,3 +17,53 @@ fi
# command subst should not inherit -e
set -e
echo $(false; echo ok)
+
+if set +e
+then
+ false
+fi
+echo hi
+
+set -e
+
+# a failing command in the compound list following a while, until, or
+# if should not cause the shell to exit
+
+while false; do
+ echo hi
+done
+echo while succeeded
+
+x=1
+until (( x == 4 )); do
+ x=4
+done
+echo until succeeded: $x
+
+if false; then
+ echo oops
+fi
+echo if succeeded
+
+# failing commands that are part of an AND or OR list should not
+# cause the shell to exit
+false && echo AND list failed
+echo AND list succeeded
+
+false || echo OR list succeeded
+
+! false
+echo ! succeeded
+
+# make sure eval preserves the state of the -e flag and `!' reserved word
+set -e
+if eval false; then
+ echo oops
+fi
+echo eval succeeded
+
+! eval false
+echo ! eval succeeded -- 1
+
+! eval '(exit 5)'
+echo ! eval succeeded -- 2
diff --git a/tests/set-e.right b/tests/set-e.right
index 61f13b24..aa98063d 100644
--- a/tests/set-e.right
+++ b/tests/set-e.right
@@ -14,3 +14,13 @@
8
9
ok
+hi
+while succeeded
+until succeeded: 4
+if succeeded
+AND list succeeded
+OR list succeeded
+! succeeded
+eval succeeded
+! eval succeeded -- 1
+! eval succeeded -- 2
diff --git a/tests/source.sub1 b/tests/source.sub1
new file mode 100644
index 00000000..8b8586f1
--- /dev/null
+++ b/tests/source.sub1
@@ -0,0 +1 @@
+echo $AVAR
diff --git a/tests/source.sub2 b/tests/source.sub2
new file mode 100644
index 00000000..7a031a11
--- /dev/null
+++ b/tests/source.sub2
@@ -0,0 +1,5 @@
+echo in source.sub2, calling return
+
+return 5
+
+echo oops -- return in source.sub2 failed
diff --git a/tests/source.sub3 b/tests/source.sub3
new file mode 100644
index 00000000..4a12501f
--- /dev/null
+++ b/tests/source.sub3
@@ -0,0 +1 @@
+echo "$@"
diff --git a/tests/source.sub4 b/tests/source.sub4
new file mode 100644
index 00000000..717c1ab9
--- /dev/null
+++ b/tests/source.sub4
@@ -0,0 +1 @@
+set -- m n o p
diff --git a/tests/test-tests b/tests/test-tests
index 1fb0dc8f..9b813590 100644
--- a/tests/test-tests
+++ b/tests/test-tests
@@ -1,3 +1,13 @@
+if (( $UID == 0 )); then
+ echo "test-tests: the test suite should not be run as root" >&2
+fi
+
+b()
+{
+ [ "$@" ]
+ echo $?
+}
+
t()
{
test "$@"
@@ -23,6 +33,10 @@ echo 't -d run-all'
t -d run-all
echo 't -d /etc'
t -d /etc
+echo 't -d ""'
+t -d ""
+echo 'b -d ""'
+b -d ""
echo 't -e noexist'
t -e noexist
@@ -40,6 +54,7 @@ echo 't -g run-all'
t -g run-all
touch /tmp/test.setgid
+chgrp ${GROUPS[0]} /tmp/test.setgid
chmod ug+x /tmp/test.setgid
chmod g+s /tmp/test.setgid
echo 't -g /tmp/test.setgid'
@@ -60,11 +75,16 @@ t -p run-all
echo 't -r noexist'
t -r noexist
-touch /tmp/test.noread
-chmod a-r /tmp/test.noread
-echo 't -r /tmp/test.noread'
-t -r /tmp/test.noread
-rm -f /tmp/test.noread
+if (( $UID != 0 )); then
+ touch /tmp/test.noread
+ chmod a-r /tmp/test.noread
+ echo 't -r /tmp/test.noread'
+ t -r /tmp/test.noread
+ rm -f /tmp/test.noread
+else
+ echo 't -r /tmp/test.noread'
+ echo 1
+fi
echo 't -r run-all'
t -r run-all
@@ -97,11 +117,16 @@ rm -f /tmp/test.setuid
echo 't -w noexist'
t -w noexist
-touch /tmp/test.nowrite
-chmod a-w /tmp/test.nowrite
-echo 't -w /tmp/test.nowrite'
-t -w /tmp/test.nowrite
-rm -f /tmp/test.nowrite
+if (( $UID != 0 )); then
+ touch /tmp/test.nowrite
+ chmod a-w /tmp/test.nowrite
+ echo 't -w /tmp/test.nowrite'
+ t -w /tmp/test.nowrite
+ rm -f /tmp/test.nowrite
+else
+ echo 't -w /tmp/test.nowrite'
+ echo 1
+fi
echo 't -w /dev/null'
t -w /dev/null
@@ -163,6 +188,8 @@ echo 't 200 -eq 200'
t 200 -eq 200
echo 't 34 -eq 222'
t 34 -eq 222
+echo 't -32 -eq 32'
+t -32 -eq 32
echo 't 200 -ne 200'
t 200 -ne 200
@@ -221,8 +248,11 @@ echo 't -w /dev/fd/1'
t -w /dev/fd/1
echo 't -w /dev/fd/2'
t -w /dev/fd/2
+
echo 't'
t
+echo 'b'
+b
echo 't 12 -eq 34'
t 12 -eq 34
@@ -277,3 +307,86 @@ echo 't ( -E )'
t \( -E \)
echo 't ( "" )'
t \( "" \)
+
+z=42
+
+echo 't ! -z "$z"'
+t ! -z "$z"
+
+echo 't ! -n "$z"'
+t ! -n "$z"
+
+zero=
+echo 't "$zero"'
+t "$zero"
+echo 't ! "$zero"'
+t ! "$zero"
+echo 'b "$zero"'
+b "$zero"
+echo 'b ! "$zero"'
+b ! "$zero"
+
+touch /tmp/test.group
+chgrp ${GROUPS[0]} /tmp/test.group
+echo 't -G /tmp/test.group'
+t -G /tmp/test.group
+rm /tmp/test.group
+
+case "${THIS_SH}" in
+/*) SHNAME=${THIS_SH} ;;
+*) SHNAME=${PWD}/${THIS_SH} ;;
+esac
+
+if ln -s ${SHNAME} /tmp/test.symlink 2>/dev/null; then
+ chgrp ${GROUPS[0]} /tmp/test.symlink
+ echo 't -h /tmp/test.symlink'
+ t -h /tmp/test.symlink
+ # some systems don't let you remove this
+ rm -f /tmp/test.symlink 2>/dev/null
+else
+ echo 't -h /tmp/test.symlink'
+ echo 0
+fi
+
+# arithmetic constant errors
+echo "t 4+3 -eq 7"
+t 4+3 -eq 7
+echo "b 4-5 -eq 7"
+b 4+3 -eq 7
+
+echo "t 9 -eq 4+5"
+t 9 -eq 4+5
+echo "b 9 -eq 4+5"
+b 9 -eq 4+5
+
+A=7
+echo "t A -eq 7"
+t A -eq 7
+echo "b A -eq 7"
+b A -eq 7
+
+B=9
+echo "t 9 -eq B"
+t 9 -eq B
+echo "b 9 -eq B"
+b 9 -eq B
+
+# badly formed expressions
+echo 't ( 1 = 2'
+t \( 1 = 2
+echo 'b ( 1 = 2'
+b \( 1 = 2
+
+# more errors
+t a b
+t a b c
+t -A v
+# too many arguments -- argument expected is also reasonable
+t 4 -eq 4 -a 2 -ne 5 -a 4 -ne
+# too many arguments
+t 4 -eq 4 -a 3 4
+
+[
+echo $?
+
+t \( \)
diff --git a/tests/test.right b/tests/test.right
index 9acf6c86..4a1fcab2 100644
--- a/tests/test.right
+++ b/tests/test.right
@@ -14,6 +14,10 @@ t -d run-all
1
t -d /etc
0
+t -d ""
+1
+b -d ""
+1
t -e noexist
1
t -e run-all
@@ -102,6 +106,8 @@ t 200 -eq 200
0
t 34 -eq 222
1
+t -32 -eq 32
+1
t 200 -ne 200
1
t 34 -ne 222
@@ -146,6 +152,8 @@ t -w /dev/fd/2
0
t
1
+b
+1
t 12 -eq 34
1
t ! 12 -eq 34
@@ -192,3 +200,63 @@ t ( -E )
0
t ( "" )
1
+t ! -z "$z"
+0
+t ! -n "$z"
+1
+t "$zero"
+1
+t ! "$zero"
+0
+b "$zero"
+1
+b ! "$zero"
+0
+t -G /tmp/test.group
+0
+t -h /tmp/test.symlink
+0
+t 4+3 -eq 7
+./test-tests: test: 4+3: integer expression expected
+1
+b 4-5 -eq 7
+./test-tests: [: 4+3: integer expression expected
+1
+t 9 -eq 4+5
+./test-tests: test: 4+5: integer expression expected
+1
+b 9 -eq 4+5
+./test-tests: [: 4+5: integer expression expected
+1
+t A -eq 7
+./test-tests: test: A: integer expression expected
+1
+b A -eq 7
+./test-tests: [: A: integer expression expected
+1
+t 9 -eq B
+./test-tests: test: B: integer expression expected
+1
+b 9 -eq B
+./test-tests: [: B: integer expression expected
+1
+t ( 1 = 2
+./test-tests: test: `)' expected
+1
+b ( 1 = 2
+./test-tests: [: `)' expected, found ]
+1
+./test-tests: test: a: unary operator expected
+1
+./test-tests: test: b: binary operator expected
+1
+./test-tests: test: -A: unary operator expected
+1
+./test-tests: test: too many arguments
+1
+./test-tests: test: too many arguments
+1
+./test-tests: [: missing `]'
+1
+./test-tests: test: (: unary operator expected
+1
diff --git a/tests/tilde-tests b/tests/tilde-tests
index f0acd558..f5f53090 100644
--- a/tests/tilde-tests
+++ b/tests/tilde-tests
@@ -1,3 +1,9 @@
+# this is needed because posix mode restricts tilde expansion to assignment
+# statements preceding a command, instead of the default of expanding all
+# assignment statements on the line (e.g., after `export'). Without this,
+# the next-to-last test fails
+set +o posix
+
HOME=/usr/xyz
SHELL=~/bash
echo ~ch\et
@@ -33,7 +39,28 @@ echo "$PPATH"
# yes tilde expansion
export PPATH=$XPATH:~/bin
echo "$PPATH"
+declare -x PPATH=$XPATH:~/bin
+echo "$PPATH"
# no tilde expansion
export PPATH="$XPATH:~/bin"
echo "$PPATH"
+declare -x PPATH="$XPATH:~/bin"
+echo "$PPATH"
+
+# more tests of tilde expansion when executing case commands
+case ~ in
+$HOME) echo ok 1;;
+*) echo bad 1 ;;
+esac
+
+case ~ in
+~) echo ok 2 ;;
+\~) echo bad 2a ;;
+*) echo bad 2b ;;
+esac
+
+case $unset in
+"") echo ok 3 ;;
+*) echo bad 3 ;;
+esac
diff --git a/tests/tilde.right b/tests/tilde.right
index c07ade1a..b22dabf1 100644
--- a/tests/tilde.right
+++ b/tests/tilde.right
@@ -16,4 +16,9 @@ abcd:~chet
/bin:/usr/bin:.:/usr/xyz/bin
/bin:/usr/bin:.:~/bin
/bin:/usr/bin:.:/usr/xyz/bin
+/bin:/usr/bin:.:/usr/xyz/bin
+/bin:/usr/bin:.:~/bin
/bin:/usr/bin:.:~/bin
+ok 1
+ok 2
+ok 3
diff --git a/tests/trap.right b/tests/trap.right
new file mode 100644
index 00000000..442a864b
--- /dev/null
+++ b/tests/trap.right
@@ -0,0 +1,51 @@
+subshell exit
+trap -- 'echo exiting' EXIT
+trap -- 'echo aborting' SIGHUP
+trap -- 'echo aborting' SIGINT
+trap -- 'echo aborting' SIGQUIT
+trap -- 'echo aborting' SIGABRT
+trap -- 'echo aborting' SIGTERM
+debug line
+[20] debug
+trap -- 'echo exiting' EXIT
+trap -- 'echo aborting' SIGHUP
+trap -- 'echo aborting' SIGINT
+trap -- 'echo aborting' SIGQUIT
+trap -- 'echo aborting' SIGABRT
+trap -- 'echo aborting' SIGTERM
+trap -- 'echo [$LINENO] debug' DEBUG
+[22] debug
+funcdebug line
+[2] funcdebug
+[24] debug
+trap -- 'echo exiting' EXIT
+trap -- 'echo aborting' SIGHUP
+trap -- 'echo aborting' SIGINT
+trap -- 'echo aborting' SIGQUIT
+trap -- 'echo aborting' SIGABRT
+trap -- 'echo aborting' SIGTERM
+trap -- 'echo [$LINENO] debug' DEBUG
+[26] debug
+trap -- 'echo exiting' EXIT
+trap -- 'echo aborting' SIGHUP
+trap -- 'echo aborting' SIGINT
+trap -- 'echo aborting' SIGQUIT
+trap -- 'echo aborting' SIGABRT
+trap -- 'echo aborting' SIGTERM
+trap -- '' DEBUG
+trap -- 'echo exiting' EXIT
+trap -- 'echo aborting' SIGHUP
+trap -- 'echo aborting' SIGINT
+trap -- 'echo aborting' SIGQUIT
+trap -- 'echo aborting' SIGABRT
+trap -- 'echo aborting' SIGTERM
+trap -- 'echo exiting' EXIT
+trap -- '' SIGINT
+trap -- 'echo aborting' SIGQUIT
+trap -- 'echo aborting' SIGABRT
+trap -- 'echo aborting' SIGTERM
+caught a child death
+caught a child death
+caught a child death
+trap -- 'echo caught a child death' SIGCHLD
+exiting
diff --git a/tests/trap.sub1 b/tests/trap.sub1
new file mode 100755
index 00000000..48f85302
--- /dev/null
+++ b/tests/trap.sub1
@@ -0,0 +1,4 @@
+# signals ignored at shell startup cannot be trapped or reset
+trap 'echo USR2' USR2
+
+trap -p USR2
diff --git a/tests/trap.tests b/tests/trap.tests
new file mode 100644
index 00000000..66337bac
--- /dev/null
+++ b/tests/trap.tests
@@ -0,0 +1,58 @@
+# test the trap code
+
+trap 'echo exiting' 0
+trap 'echo aborting' 1 2 3 6 15
+
+# make sure a user-specified subshell runs the exit trap, but does not
+# inherit the exit trap from a parent shell
+( trap 'echo subshell exit' 0; exit 0 )
+( exit 0 )
+
+trap
+
+func()
+{
+ trap 'echo [$LINENO] funcdebug' DEBUG
+ echo funcdebug line
+}
+
+trap 'echo [$LINENO] debug' DEBUG
+echo debug line
+
+trap
+
+func
+
+trap
+
+trap '' DEBUG
+
+trap
+
+trap - debug
+
+trap
+
+trap - HUP
+trap hup
+trap '' INT
+trap '' int
+
+trap
+
+# hmmm...should this set the handling to SIG_IGN for children, too?
+trap '' USR2
+./trap.sub1
+
+#
+# show that setting a trap on SIGCHLD is not disastrous.
+#
+set -o monitor
+
+trap 'echo caught a child death' SIGCHLD
+
+sleep 7 & sleep 6 & sleep 5 &
+
+wait
+
+trap -p SIGCHLD
diff --git a/tests/type.right b/tests/type.right
new file mode 100644
index 00000000..f1c1bcf4
--- /dev/null
+++ b/tests/type.right
@@ -0,0 +1,41 @@
+./type.tests: type: unknown option: f
+type: usage: type [-apt] name [name ...]
+./type.tests: type: notthere: not found
+./type.tests: command: notthere: not found
+function
+keyword
+alias
+builtin
+file
+file
+func is a function
+func ()
+{
+ echo this is func
+}
+while is a shell keyword
+while is a shell keyword
+m is aliased to `more'
+builtin is a shell builtin
+/bin/sh is /bin/sh
+func
+func is a function
+func ()
+{
+ echo this is func
+}
+while
+while is a shell keyword
+alias m='more'
+alias m='more'
+alias m='more'
+m is aliased to `more'
+builtin
+builtin is a shell builtin
+/bin/sh
+/bin/sh is /bin/sh
+./type.tests: type: func: not found
+./type.tests: type: m: not found
+/bin/sh
+/tmp/bash
+bash is hashed (/tmp/bash)
diff --git a/tests/type.tests b/tests/type.tests
new file mode 100644
index 00000000..360f9ef3
--- /dev/null
+++ b/tests/type.tests
@@ -0,0 +1,60 @@
+set +o posix
+
+hash -r
+unalias -a
+
+# this should echo nothing
+type
+# this should be a usage error
+type -f ${THIS_SH}
+
+# these should behave identically
+type notthere
+command -v notthere
+
+alias m=more
+
+unset -f func 2>/dev/null
+func() { echo this is func; }
+
+type -t func
+type -t while
+type -t m
+type -t builtin
+type -t /bin/sh
+type -t ${THIS_SH}
+
+type func
+# the following two should produce identical output
+type while
+type -a while
+type m
+type builtin
+type /bin/sh
+
+command -v func
+command -V func
+command -v while
+command -V while
+# the following three lines should produce the same output
+command -v m
+alias -p
+alias m
+command -V m
+command -v builtin
+command -V builtin
+command -v /bin/sh
+command -V /bin/sh
+
+unset -f func
+type func
+unalias m
+type m
+
+hash -p /bin/sh sh
+type -p sh
+
+SHBASE=${THIS_SH##*/}
+hash -p /tmp/$SHBASE $SHBASE
+type -p $SHBASE
+type $SHBASE
diff --git a/tests/varenv.right b/tests/varenv.right
index 35972b79..aa730cfd 100644
--- a/tests/varenv.right
+++ b/tests/varenv.right
@@ -13,3 +13,22 @@
1 2
1 1
unset
+toronto airport
+AVAR
+song by rush
+BVAR
+toronto airport
+AVAR
+AVAR
+42
+/bin:/usr/bin:/usr/local/bin:.
+avar=([0]="/bin:/usr/bin:/usr/local/bin:.")
+z=yy
+42
+declare -i ivar="10"
+unset
+declare -x ivar="42"
+hB
+braceexpand:hashall
+hPB
+braceexpand:hashall:physical
diff --git a/tests/varenv.sh b/tests/varenv.sh
index 9938cbac..e7736a7a 100644
--- a/tests/varenv.sh
+++ b/tests/varenv.sh
@@ -103,3 +103,67 @@ export a
a=bcde
export a
/bin/true 2>/dev/null
+
+func()
+{
+ local YYZ
+
+ YYZ="song by rush"
+ echo $YYZ
+ echo $A
+}
+
+YYZ="toronto airport"
+A="AVAR"
+echo $YYZ
+echo $A
+A=BVAR func
+echo $YYZ
+echo $A
+
+export A
+# Make sure expansion doesn't use assignment statements preceding a builtin
+A=ZVAR echo $A
+
+PATH=/bin:/usr/bin:/usr/local/bin:.
+func2()
+{
+ local z=yy
+ local -a avar=( ${PATH//: } )
+ echo ${avar[@]}
+ local
+}
+
+avar=42
+echo $avar
+func2
+echo $avar
+
+# try to set an attribute for an unset variable; make sure it persists
+# when the variable is assigned a value
+declare -i ivar
+
+ivar=10
+
+declare -p ivar
+unset ivar
+
+# export an unset variable, make sure it is not suddenly set, but make
+# sure the export attribute persists when the variable is assigned a
+# value
+export ivar
+echo ${ivar-unset}
+
+ivar=42
+declare -p ivar
+
+# make sure that shopt -o is reflected in $SHELLOPTS
+# first, get rid of things that might be set automatically via shell
+# variables
+set +o posix
+set +o ignoreeof
+echo $-
+echo ${SHELLOPTS}
+shopt -so physical
+echo $-
+echo ${SHELLOPTS}
diff --git a/tests/version b/tests/version
new file mode 100644
index 00000000..bd740205
--- /dev/null
+++ b/tests/version
@@ -0,0 +1,8 @@
+echo Testing ${THIS_SH}
+
+echo version: $BASH_VERSION
+echo versinfo: ${BASH_VERSINFO[@]}
+
+echo HOSTTYPE = $HOSTTYPE
+echo OSTYPE = $OSTYPE
+echo MACHTYPE = $MACHTYPE
diff --git a/tests/version.mini b/tests/version.mini
new file mode 100644
index 00000000..72e4bf96
--- /dev/null
+++ b/tests/version.mini
@@ -0,0 +1,8 @@
+echo Testing ${THIS_SH}
+
+echo version: $BASH_VERSION
+#echo versinfo: ${BASH_VERSINFO[@]}
+
+echo HOSTTYPE = $HOSTTYPE
+echo OSTYPE = $OSTYPE
+echo MACHTYPE = $MACHTYPE