diff options
author | Jari Aalto <jari.aalto@cante.net> | 1997-06-05 14:59:13 +0000 |
---|---|---|
committer | Jari Aalto <jari.aalto@cante.net> | 2009-09-12 16:46:50 +0000 |
commit | d166f048818e10cf3799aa24a174fb22835f1acc (patch) | |
tree | 1ca27f9243900f8b236d0cde6a3862002aea9e19 /tests | |
parent | ccc6cda312fea9f0468ee65b8f368e9653e1380b (diff) | |
download | bash-d166f048818e10cf3799aa24a174fb22835f1acc.tar.gz |
Imported from ../bash-2.01.tar.gz.
Diffstat (limited to 'tests')
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 |