1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2025-10-27 04:40:59 +01:00

zsh-workers/9024

This commit is contained in:
Tanaka Akira 1999-12-13 19:06:59 +00:00
parent 0964ce6185
commit f83b8fe5fc
8 changed files with 487 additions and 125 deletions

View file

@ -47,7 +47,7 @@ Testing
a wide range of human and artificial life, it is very difficult to a wide range of human and artificial life, it is very difficult to
test the shell thoroughly. For this purpose, the Test subdirectory test the shell thoroughly. For this purpose, the Test subdirectory
exists. It consists of a driver script (ztst.zsh) and various test exists. It consists of a driver script (ztst.zsh) and various test
files (*.ztst) in a format which is described in cd.ztst, which acts files (*.ztst) in a format which is described in 50cd.ztst, which acts
as a template. It is designed to make it easy to provide input to as a template. It is designed to make it easy to provide input to
chunks of shell code and to test the corresponding standard output, chunks of shell code and to test the corresponding standard output,
error output and exit status. error output and exit status.

View file

@ -1,5 +1,5 @@
DISTFILES_SRC=' DISTFILES_SRC='
.cvsignore .distfiles Makefile.in .cvsignore .distfiles Makefile.in
ztst.zsh ztst.zsh
cd.ztst 01grammar.ztst 02alias.ztst 03quoting.ztst 50cd.ztst
' '

288
Test/01grammar.ztst Normal file
View file

@ -0,0 +1,288 @@
#
# This file contains tests corresponding to the `Shell Grammar' texinfo node.
#
%prep
mkdir basic.tmp && cd basic.tmp
touch foo bar
%test
#
# Tests for `Simple Commands and Pipelines'
#
echo foo | cat | sed 's/foo/bar/'
0:Basic pipeline handling
>bar
false | true
0:Exit status of pipeline with builtins (true)
true | false
1:Exit status of pipeline with builtins (false)
fn() { local foo; read foo; print $foo; }
coproc fn
print -p coproc test output
read -p bar
print $bar
0:Basic coprocess handling
>coproc test output
true | false && print true || print false
0:Basic sublist (i)
>false
false | true && print true || print false
0:Basic sublist (ii)
>true
(cd /NonExistentDirectory >&/dev/null) || print false
0:Basic subshell list with error
>false
# Can someone convince me the following is really supposed to fail
# without the semicolon present?
{ cd /NonExistentDirectory >&/dev/null; } || print false
0:Basic current shell list with error
>false
#
# Tests for `Precommand Modifiers'
#
- sh -c 'echo $0'
0:`-' precommand modifier
>-sh
echo f*
noglob echo f*
0:`noglob' precommand modifier
>foo
>f*
(exec /bin/sh; echo bar)
0:`exec' precommand modifier
cat() { echo Function cat executed; }
command cat && unfunction cat
0:`command' precommand modifier
<External command cat executed
>External command cat executed
cd() { echo Not cd at all; }
builtin cd . && unfunction cd
0:`builtin' precommand modifier
#
# Tests for `Complex Commands'
#
if true; then
print true-1
elif true; then
print true-2
else
print false
fi
0:`if ...' (i)
>true-1
if false; then
print true-1
elif true; then
print true-2
else
print false
fi
0:`if ...' (ii)
>true-2
if false; then
print true-1
elif false; then
print true-2
else
print false
fi
0:`if ...' (iii)
>false
for name in word to term; do
print $name
done
0:`for' loop
>word
>to
>term
for (( name = 0; name < 3; name++ )); do
print $name
done
0:arithmetic `for' loop
>0
>1
>2
name=0
while (( name < 3 )); do
print $name
(( name++ ))
done
0:`while' loop
>0
>1
>2
name=0
until (( name == 3 )); do
print $name
(( name++ ))
done
0:`until' loop
>0
>1
>2
repeat 3 do
echo over and over
done
0:`repeat' loop
>over and over
>over and over
>over and over
word=Trinity
case $word in
Michaelmas) print 0
;;
Hilary) print 1
;;
Trinity) print 2
;;
*) print 3
;;
esac
0:`case' loop, old syntax
>2
word=Trinity
case $word in
(Michaelmas) print 0
;;
(Hilary) print 1
;;
(Trinity) print 2
;;
(*) print 3
;;
esac
0:`case' loop, new syntax
>2
## This doesn't work, because zsh tries to read from the terminal
## even in a non-interactive shell. The manual implies it always reads
## from stdin, even in an interactive shell.
# PS3="input> "
# select name in one two three; do
# print $name
# done
#0:`select' loop
#<2
#>1) one 2) two 3) three
#>input>
#>two
function name1 name2 () { print This is $0; }
name2
name1 name2() { print This is still $0; }
name2
0:`function' keyword
>This is name2
>This is still name2
(time cat) >&/dev/null
0:`time' keyword (status only)
if [[ -f foo && -d . && -n $ZTST_testdir ]]; then
true
else
false
fi
0:basic [[ ... ]] test
#
# Tests for `Alternate Forms For Complex Commands'
#
## I simply can't get these to work.
## I suspect that the lists which are allowed here are only syntactically
## special tests.
# if true; { print true-1; } elif true; { print true-2; } else { false; }
# if false; { print true-1; } elif true; { print true-2; } else { false; }
# if false; { print true-1; } elif false; { print true-2; } else { false; }
#0:Alternate `if' with braces
## Are all those semicolons necessary? If not, what are the rules?
#>true-1
#>true-2
#>false
if true; print true
0:Short form of `if'
>true
for name ( word1 word2 word3 ) print $name
0:Form of `for' with parentheses.
>word1
>word2
>word3
for name in alpha beta gamma; print $name
0:Short form of `for'
>alpha
>beta
>gamma
for (( val = 2; val < 10; val *= val )) print $val
0:Short arithmetic `for'
>2
>4
foreach name ( verbiage words periphrasis )
print $name
end
0:Csh-like `for'
>verbiage
>words
>periphrasis
# see comment with braces used in if loops
val=0;
while (( val < 2 )) { print $((val++)); }
0:Alternative `while'
>0
>1
val=2;
until (( val == 0 )) { print $((val--)); }
0:Alternative `until'
>2
>1
repeat 3 print Hip hip hooray
0:Short `repeat'
>Hip hip hooray
>Hip hip hooray
>Hip hip hooray
## Why doesn't this one work here? It works from the command line
## or with zsh -fc.
# case bravo {
# (alpha) print schmalpha
# ;;
# (bravo) print schmavo
# ;;
# (charlie) print schmarlie
# ;;
# }
#0:`case' with braces
#>schmavo

23
Test/02alias.ztst Normal file
View file

@ -0,0 +1,23 @@
%prep
alias foo=echo
alias -g bar=echo
alias '\bar=echo'
%test
foo foo
0:Basic aliasing
>foo
bar bar
0:Global aliasing
>echo
\foo foo
1:Not aliasing
?ZTST_execchunk:2: command not found: foo
\bar \bar
0:Aliasing with a backslash
>bar

26
Test/03quoting.ztst Normal file
View file

@ -0,0 +1,26 @@
%test
print 'single quotes' "double quotes" `echo backquotes`
0:Simple use of quotes
>single quotes double quotes backquotes
foo=text
print -r '$foo\\\' "$foo\$foo\\\"\``echo bar`\`\"" `print -r $foo\\\``
0:Quoting inside quotes
>$foo\\\ text$foo\"`bar`" text`
print -r $'\'ut queant laxis\'\n"resonare fibris"'
0:$'-style quotes
>'ut queant laxis'
>"resonare fibris"
print -r ''''
setopt rcquotes
# We need to set rcquotes here for the next example since it is
# needed while parsing.
0:No RC_QUOTES with single quotes
>
print -r ''''
unsetopt rcquotes
0:Yes RC_QUOTES with single quotes
>'

104
Test/50cd.ztst Normal file
View file

@ -0,0 +1,104 @@
# This file serves as a model for how to write tests, so is more heavily
# commented that the others. All tests are run in the Test subdirectory
# of the distribution, which must be writable. They should end with
# the suffix `.ztst': this is not required by the test harness itself,
# but it is needed by the Makefile to run all the tests.
# Blank lines with no other special meaning (e.g. separating chunks of
# code) and all those with a `#' in the first column are ignored.
# All section names start with a % in the first column. The names
# must be in the expected order, though not all sections are required.
# The sections are %prep (preparatory setup: code executed should return
# status 0, but no other tests are performed), %test (the main tests), and
# %clean (to cleanup: the code is simply unconditionally executed).
#
# Literal shell code to be evaluated must be indented with any number
# of spaces and/or tabs, to differentiate it from tags with a special
# meaning to the test harness. Note that this is true even in sections
# where there are no such tags. Also note that file descriptor 9
# is reserved for input from the test script; if ZTST_verbose is set,
# output is sent to the original stdout via fd 8. Option settings
# are preserved between the execution of different code chunks;
# initially, all standard zsh options (the effect of `emulate -R zsh')
# are set.
%prep
# This optional section prepares the test, creating directories and files
# and so on. Chunks of code are separated by blank lines (which is not
# necessary before the end of the section); each chunk of code is evaluated
# in one go and must return status 0, or the preparation is deemed to have
# failed and the test ends with an appropriate error message. Standard
# output from this section is redirected to /dev/null, but standard error
# is not redirected.
#
# Tests should use subdirectories ending in `.tmp'. These will be
# removed with all the contents even if the test is aborted.
mkdir cdtst.tmp cdtst.tmp/real cdtst.tmp/sub
ln -s ../real cdtst.tmp/sub/fake
mydir=$PWD
%test
# This is where the tests are run. It consists of blocks separated
# by blank lines. Each block has the same format and there may be any
# number of them. It consists of indented code, plus optional sets of lines
# beginning '<', '>' and '?' which may appear in any order. These correspond
# to stdin (fed to the code), stdout (compared with code output) and
# stderr (compared with code error output) respectively. These subblocks
# may occur in any order, but the natural one is: code, stdin, stdout,
# stderr.
#
# The rules for '<', '>' and '?' lines are the same: only the first
# character is stripped, with subsequent whitespace being significant;
# lines are not subject to any substitution unless the `q' flags (see
# below) is set.
#
# Each chunk of indented code is to be evaluated in one go and is to
# be followed by a line starting (in the first column) with
# the expected status returned by the code when run, or - if it is
# irrelevant. An optional set of single-letter flags follows the status
# or -. The following are understood:
# d Don't diff stdout against the expected stdout.
# D Don't diff stderr agsinst the expected stderr.
# q All redirection lines given in the test script (not the lines
# actually produced by the test) are subject to ordinary quoted shell
# expansion (i.e. not globbing).
# This can be followed by a `:' and a message describing the
# test, which will be printed if the test fails, along with a
# description of the failure that occurred. The `:' and message are
# optional, but highly recommended.
# Hence a complete status line looks something like:
# 0dDq:Checking whether the world will end with a bang or a whimper
#
# If either or both of the '>' and '?' sets of lines is absent, it is
# assumed the corresponding output should be empty and it is an error if it
# is not. If '<' is empty, stdin is an empty (but opened) file.
cd cdtst.tmp/sub/fake &&
pwd &&
print $PWD
0q:Preserving symbolic links in the current directory string
>$mydir/cdtst.tmp/sub/fake
>$mydir/cdtst.tmp/sub/fake
cd ../../.. &&
pwd &&
print $PWD
0q:Changing directory up through symbolic links without following them
>$mydir
>$mydir
setopt chaselinks
cd cdtst.tmp/sub/fake &&
pwd &&
print $PWD
0q:Resolving symbolic links with chaselinks set
>$mydir/cdtst.tmp/real
>$mydir/cdtst.tmp/real
%clean
# This optional section cleans up after the test, if necessary,
# e.g. killing processes etc. This is in addition to the removal of *.tmp
# subdirectories. This is essentially like %prep, except that status
# return values are ignored.

View file

@ -1,97 +0,0 @@
# This file serves as a model for how to write tests, so is more heavily
# commented that the others. All tests are run in the Test subdirectory
# of the distribution, which must be writable. They should end with
# the suffix `.ztst': this is not required by the test harness itself,
# but it is needed by the Makefile to run all the tests.
# Blank lines with no other special meaning (e.g. separating chunks of
# code) and all those with a `#' in the first column are ignored.
# All section names start with a % in the first column. The names
# must be in the expected order, though not all sections are required.
# The sections are %prep (preparatory setup: code executed should return
# status 0, but no other tests are performed), %test (the main tests), and
# %clean (to cleanup: the code is simply unconditionally executed).
#
# Literal shell code to be evaluated must be indented with any number
# of spaces and/or tabs, to differentiate it from tags with a special
# meaning to the test harness. Note that this is true even in sections
# where there are no such tags. Also note that file descriptor 9
# is reserved for input from the test script; if ZTST_verbose is set,
# output is sent to the original stdout via fd 8. Option settings
# are preserved between the execution of different code chunks;
# initially, all standard zsh options (the effect of `emulate -R zsh')
# are set.
%prep
# This optional section prepares the test, creating directories and files
# and so on. Chunks of code are separated by blank lines (which is not
# necessary before the end of the section); each chunk of code is evaluated
# in one go and must return status 0, or the preparation is deemed to have
# failed and the test ends with an appropriate error message. Standard
# output from this section is redirected to /dev/null, but standard error
# is not redirected.
#
# Tests should use subdirectories ending in `.tmp'. These will be
# removed with all the contents even if the test is aborted.
mkdir cdtst.tmp cdtst.tmp/real cdtst.tmp/sub
ln -s ../real cdtst.tmp/sub/fake
mydir=$PWD
%test
# This is where the tests are run. It consists of blocks separated
# by blank lines. Each block has the same format and there may be any
# number of them. It consists of indented code, plus optional sets of lines
# beginning '<', '>' and '?' which may appear in any order. These correspond
# to stdin (fed to the code), stdout (compared with code output) and
# stderr (compared with code error output) respectively. These subblocks
# may occur in any order, but the natural one is: code, stdin, stdout,
# stderr.
#
# The rules for '<', '>' and '?' lines are the same: only the first
# character is stripped, with subsequent whitespace being significant;
# lines are subject to ordinary quoted shell expansion (i.e. not globbing).
#
# Each chunk of indented code is to be evaluated in one go and is to
# be followed by a line starting (in the first column) with
# the expected status returned by the code when run, or - if it is
# irrelevant. This can be followed by a `:' and a message describing the
# test, which will be printed if the test fails, along with a
# description of the failure that occurred. The `:' and message are
# optional, but highly recommended.
#
# If either or both of the '>' and '?' sets of lines is absent, it is
# assumed the corresponding output should be empty and it is an error if it
# is not. If '<' is empty, stdin is an empty (but opened) file.
#
# TODO: flags to the post-code status line indicating that diffs are
# not to be performed.
cd cdtst.tmp/sub/fake &&
pwd &&
print $PWD
0:Preserving symbolic links in the current directory string
>$mydir/cdtst.tmp/sub/fake
>$mydir/cdtst.tmp/sub/fake
cd ../../.. &&
pwd &&
print $PWD
0:Changing directory up through symbolic links without following them
>$mydir
>$mydir
setopt chaselinks
cd cdtst.tmp/sub/fake &&
pwd &&
print $PWD
0:Resolving symbolic links with chaselinks set
>$mydir/cdtst.tmp/real
>$mydir/cdtst.tmp/real
%clean
# This optional section cleans up after the test, if necessary,
# e.g. killing processes etc. This is in addition to the removal of *.tmp
# subdirectories. This is essentially like %prep, except that status
# return values are ignored.

View file

@ -14,7 +14,8 @@
# Produce verbose messages if non-zero. # Produce verbose messages if non-zero.
# If 1, produce reports of tests executed; if 2, also report on progress. # If 1, produce reports of tests executed; if 2, also report on progress.
ZTST_verbose=0 # Defined in such a way that any value from the environment is used.
: ${ZTST_verbose:=0}
# We require all options to be reset, not just emulation options. # We require all options to be reset, not just emulation options.
# Unfortunately, due to the crud which may be in /etc/zshenv this might # Unfortunately, due to the crud which may be in /etc/zshenv this might
@ -42,19 +43,19 @@ ZTST_mainopts=(${(kv)options})
ZTST_testdir=$PWD ZTST_testdir=$PWD
ZTST_testname=$1 ZTST_testname=$1
: ${TMPPREFIX:=/tmp/zsh}
# Temporary files for redirection inside tests. # Temporary files for redirection inside tests.
ZTST_in=${TMPPREFIX-:/tmp/zsh}.ztst.in.$$ ZTST_in=${TMPPREFIX}.ztst.in.$$
# hold the expected output # hold the expected output
ZTST_out=${TMPPREFIX-:/tmp/zsh}.ztst.out.$$ ZTST_out=${TMPPREFIX}.ztst.out.$$
ZTST_err=${TMPPREFIX-:/tmp/zsh}.ztst.err.$$ ZTST_err=${TMPPREFIX}.ztst.err.$$
# hold the actual output from the test # hold the actual output from the test
ZTST_tout=${TMPPREFIX-:/tmp/zsh}.ztst.tout.$$ ZTST_tout=${TMPPREFIX}.ztst.tout.$$
ZTST_terr=${TMPPREFIX-:/tmp/zsh}.ztst.terr.$$ ZTST_terr=${TMPPREFIX}.ztst.terr.$$
ZTST_cleanup() { ZTST_cleanup() {
cd $ZTST_testdir cd $ZTST_testdir
rm -rf $ZTST_testdir/dummy.tmp $ZTST_testdir/*.tmp \ rm -rf $ZTST_testdir/dummy.tmp $ZTST_testdir/*.tmp ${TMPPREFIX}.ztst*$$
$ZTST_in $ZTST_out $ZTST_err $ZTST_tout $ZTST_terr
} }
# This cleanup always gets performed, even if we abort. Later, # This cleanup always gets performed, even if we abort. Later,
@ -72,6 +73,7 @@ ZTST_testfailed() {
if [[ -n $ZTST_message ]]; then if [[ -n $ZTST_message ]]; then
print "Was testing: $ZTST_message" print "Was testing: $ZTST_message"
fi fi
print "$ZTST_testname: test failed."
ZTST_cleanup ZTST_cleanup
exit 1 exit 1
} }
@ -80,7 +82,7 @@ ZTST_testfailed() {
ZTST_verbose() { ZTST_verbose() {
local lev=$1 local lev=$1
shift shift
[[ -n $ZTST_verbose && $ZTST_verbose -ge $lev ]] && print $* >&8 [[ -n $ZTST_verbose && $ZTST_verbose -ge $lev ]] && print -- $* >&8
} }
[[ ! -r $ZTST_testname ]] && ZTST_testfailed "can't read test file." [[ ! -r $ZTST_testname ]] && ZTST_testfailed "can't read test file."
@ -98,7 +100,7 @@ ZTST_cursect=''
ZTST_getline() { ZTST_getline() {
local IFS= local IFS=
while true; do while true; do
read ZTST_curline <&9 || return 1 read -r ZTST_curline <&9 || return 1
[[ $ZTST_curline == \#* ]] || return 0 [[ $ZTST_curline == \#* ]] || return 0
done done
} }
@ -145,7 +147,7 @@ $ZTST_code"
# Read in a piece for redirection. # Read in a piece for redirection.
ZTST_getredir() { ZTST_getredir() {
local char=${ZTST_curline[1]} local char=${ZTST_curline[1]} fn
ZTST_redir=${ZTST_curline[2,-1]} ZTST_redir=${ZTST_curline[2,-1]}
while ZTST_getline; do while ZTST_getline; do
[[ $ZTST_curline[1] = $char ]] || break [[ $ZTST_curline[1] = $char ]] || break
@ -154,6 +156,22 @@ ${ZTST_curline[2,-1]}"
done done
ZTST_verbose 2 "ZTST_getredir: read redir for '$char': ZTST_verbose 2 "ZTST_getredir: read redir for '$char':
$ZTST_redir" $ZTST_redir"
case $char in
'<') fn=$ZTST_in
;;
'>') fn=$ZTST_out
;;
'?') fn=$ZTST_err
;;
*) ZTST_testfailed "bad redir operator: $char"
;;
esac
if [[ $ZTST_flags = *q* ]]; then
print -r -- "${(e)ZTST_redir}" >>$fn
else
print -r -- "$ZTST_redir" >>$fn
fi
} }
# Execute an indented chunk. Redirections will already have # Execute an indented chunk. Redirections will already have
@ -210,27 +228,24 @@ $ZTST_curline"
fi fi
;; ;;
[[:space:]]##[^[:space:]]*) ZTST_getchunk [[:space:]]##[^[:space:]]*) ZTST_getchunk
[[ $ZTST_curline != [-0-9]* ]] && if [[ $ZTST_curline == (#b)([-0-9]##)([[:alpha:]]#)(:*)# ]]; then
ZTST_testfailed "expecting test status at:
$ZTST_curline"
ZTST_xstatus=$ZTST_curline
if [[ $ZTST_curline == (#b)([^:]##):(*) ]]; then
ZTST_xstatus=$match[1] ZTST_xstatus=$match[1]
ZTST_message=$match[2] ZTST_flags=$match[2]
ZTST_message=${match[3]:+${match[3][2,-1]}}
else
ZTST_testfailed "expecting test status at:
$ZTST_curline"
fi fi
ZTST_getline ZTST_getline
found=1 found=1
;; ;;
'<'*) ZTST_getredir '<'*) ZTST_getredir
print -r "${(e)ZTST_redir}" >>$ZTST_in
found=1 found=1
;; ;;
'>'*) ZTST_getredir '>'*) ZTST_getredir
print -r "${(e)ZTST_redir}" >>$ZTST_out
found=1 found=1
;; ;;
'?'*) ZTST_getredir '?'*) ZTST_getredir
print -r "${(e)ZTST_redir}" >>$ZTST_err
found=1 found=1
;; ;;
*) ZTST_testfailed "bad line in test block: *) ZTST_testfailed "bad line in test block:
@ -241,8 +256,7 @@ $ZTST_curline"
# If we found some code to execute... # If we found some code to execute...
if [[ -n $ZTST_code ]]; then if [[ -n $ZTST_code ]]; then
ZTST_verbose 1 "Running test: ZTST_verbose 1 "Running test: $ZTST_message"
$ZTST_message"
ZTST_verbose 2 "ZTST_test: expecting status: $ZTST_xstatus" ZTST_verbose 2 "ZTST_test: expecting status: $ZTST_xstatus"
ZTST_execchunk <$ZTST_in >$ZTST_tout 2>$ZTST_terr ZTST_execchunk <$ZTST_in >$ZTST_tout 2>$ZTST_terr
@ -250,7 +264,9 @@ $ZTST_message"
# First check we got the right status, if specified. # First check we got the right status, if specified.
if [[ $ZTST_xstatus != - && $ZTST_xstatus != $ZTST_status ]]; then if [[ $ZTST_xstatus != - && $ZTST_xstatus != $ZTST_status ]]; then
ZTST_testfailed "bad status $ZTST_status, expected $ZTST_xstatus from: ZTST_testfailed "bad status $ZTST_status, expected $ZTST_xstatus from:
$ZTST_code" $ZTST_code${$(<$ZTST_terr):+
Error output:
$(<$ZTST_terr)}"
fi fi
ZTST_verbose 2 "ZTST_test: test produced standard output: ZTST_verbose 2 "ZTST_test: test produced standard output:
@ -259,11 +275,13 @@ ZTST_test: and standard error:
$(<$ZTST_terr)" $(<$ZTST_terr)"
# Now check output and error. # Now check output and error.
if ! diff -c $ZTST_out $ZTST_tout; then if [[ $ZTST_flags != *d* ]] && ! diff -c $ZTST_out $ZTST_tout; then
ZTST_testfailed "output differs from expected as shown above for: ZTST_testfailed "output differs from expected as shown above for:
$ZTST_code" $ZTST_code${$(<$ZTST_terr):+
Error output:
$(<$ZTST_terr)}"
fi fi
if ! diff -c $ZTST_err $ZTST_terr; then if [[ $ZTST_flags != *D* ]] && ! diff -c $ZTST_err $ZTST_terr; then
ZTST_testfailed "error output differs from expected as shown above for: ZTST_testfailed "error output differs from expected as shown above for:
$ZTST_code" $ZTST_code"
fi fi