summaryrefslogtreecommitdiff
path: root/Test
diff options
context:
space:
mode:
Diffstat (limited to 'Test')
-rw-r--r--Test/A01grammar.ztst42
-rw-r--r--Test/A04redirect.ztst16
-rw-r--r--Test/A05execution.ztst23
-rw-r--r--Test/B01cd.ztst25
-rw-r--r--Test/B02typeset.ztst8
-rw-r--r--Test/B03print.ztst10
-rw-r--r--Test/B07emulate.ztst22
-rw-r--r--Test/B10getopts.ztst29
-rw-r--r--Test/B11kill.ztst86
-rw-r--r--Test/B12limit.ztst28
-rw-r--r--Test/B13whence.ztst34
-rw-r--r--Test/C01arith.ztst10
-rw-r--r--Test/C02cond.ztst38
-rw-r--r--Test/C04funcdef.ztst8
-rw-r--r--Test/D01prompt.ztst34
-rw-r--r--Test/D02glob.ztst76
-rw-r--r--Test/D03procsubst.ztst13
-rw-r--r--Test/D04parameter.ztst79
-rw-r--r--Test/D06subscript.ztst5
-rw-r--r--Test/D07multibyte.ztst42
-rw-r--r--Test/E01options.ztst64
-rw-r--r--Test/E02xtrace.ztst115
-rw-r--r--Test/E03posix.ztst161
-rw-r--r--Test/P01privileged.ztst23
-rw-r--r--Test/V01zmodload.ztst48
-rw-r--r--Test/V05styles.ztst22
-rw-r--r--Test/V07pcre.ztst3
-rw-r--r--Test/V08zpty.ztst2
-rw-r--r--Test/V09datetime.ztst4
-rw-r--r--Test/V10private.ztst18
-rw-r--r--Test/V12zparseopts.ztst8
-rw-r--r--Test/V13zformat.ztst91
-rw-r--r--Test/V14system.ztst149
-rw-r--r--Test/W01history.ztst22
-rw-r--r--Test/W02jobs.ztst6
-rw-r--r--Test/W03jobparameters.ztst78
-rw-r--r--Test/X02zlevi.ztst4
-rw-r--r--Test/X03zlebindkey.ztst4
-rw-r--r--Test/X04zlehighlight.ztst57
-rw-r--r--Test/Y01completion.ztst115
-rw-r--r--Test/Y02compmatch.ztst130
-rw-r--r--Test/Y03arguments.ztst69
-rw-r--r--Test/Z01is-at-least.ztst27
-rw-r--r--Test/Z02zmathfunc.ztst58
-rw-r--r--Test/Z03run-help.ztst106
-rw-r--r--Test/comptest40
-rw-r--r--Test/runtests.zsh2
-rwxr-xr-xTest/ztst.zsh20
48 files changed, 1932 insertions, 142 deletions
diff --git a/Test/A01grammar.ztst b/Test/A01grammar.ztst
index 1e0e9a04e..0312fe94e 100644
--- a/Test/A01grammar.ztst
+++ b/Test/A01grammar.ztst
@@ -557,6 +557,13 @@
>Hip hip hooray
>Hip hip hooray
+ repeat 2*2 print yeah
+0:Tokens in repeat argument
+>yeah
+>yeah
+>yeah
+>yeah
+
case bravo {
(alpha) print schmalpha
;;
@@ -915,7 +922,7 @@ F:Note that the behaviour of 'exit' inside try-list inside a function is unspeci
x=1
x=2 | echo $x
echo $x
-0:Assignment-only current shell commands in LHS of pipelin
+0:Assignment-only current shell commands in LHS of pipeline
>1
>1
@@ -930,5 +937,36 @@ F:Note that the behaviour of 'exit' inside try-list inside a function is unspeci
>or false
$ZTST_testdir/../Src/zsh -fc '{ ( ) } always { echo foo }'
--f:exec last command optimization inhibited for try/always
+0:exec last command optimization inhibited for try/always
+>foo
+
+ a='${'
+ if : ${(e)a}; then echo x; fi
+1:Status on bad substitution in if without else
+?(eval):2: bad substitution
+
+ echo 'echo foo # comment
+ echo $(
+ echo bar # comment
+ )' >source_comments.zsh
+ $ZTST_testdir/../Src/zsh -f -o extendedglob -is -c '. ./source_comments.zsh'
+0:Comments should be handled in command subst in interactively sourced files
>foo
+>bar
+
+ function 'ls,/' () {echo success}
+ {ls,/}
+0:workers/47599: current-shell blocks masquerading as brace expansion
+>success
+F:This test was written to ensure the behaviour doesn't change silently.
+F:If this test fails during development, it *might* be appropriate to change
+F:its expectations.
+
+ (
+ export VALUE=first
+ print -l 'echo Value is $VALUE' 'VALUE=second sh' 'echo Value is $VALUE' |
+ $ZTST_testdir/../Src/zsh -f
+ )
+0:Non-interactive shell command input is line buffered
+>Value is first
+>Value is second
diff --git a/Test/A04redirect.ztst b/Test/A04redirect.ztst
index d60519064..17f6dfa29 100644
--- a/Test/A04redirect.ztst
+++ b/Test/A04redirect.ztst
@@ -440,7 +440,7 @@
# This tests the here-string to filename optimisation; we can't
# test that it's actually being optimised, but we can test that it
# still works.
- cat =(<<<$'This string has been replaced\nby a file containing it.\n')
+ cat =(<<<$'This string has been replaced\nby a file containing it.')
0:Optimised here-string to filename
>This string has been replaced
>by a file containing it.
@@ -708,3 +708,17 @@
cat <&$testfd
0:Regression test for here document with fd declarator
> This is, in some sense, a here document.
+
+ (setopt noclobber clobberempty
+ rm -f foo
+ touch foo
+ print Works >foo
+ cat foo
+ print Works not >foo
+ # Make sure the file was not harmed
+ cat foo
+ )
+0:CLOBBER_EMPTY
+>Works
+>Works
+?(eval):6: file exists: foo
diff --git a/Test/A05execution.ztst b/Test/A05execution.ztst
index edc561582..d95ee363c 100644
--- a/Test/A05execution.ztst
+++ b/Test/A05execution.ztst
@@ -258,7 +258,7 @@ F:side of a pipe to block on write after the right side has exited
print -u $ZTST_fd "Skipping pipe leak test, requires MONITOR option"
print "[0] 0 0"
fi
-0:Bug regression: piping to anonymous function; piping to backround function
+0:Bug regression: piping to anonymous function; piping to background function
*>\[<->\] <-> <->
F:This test checks for two different bugs, a parser segfault piping to an
F:anonymous function, and a descriptor leak when backgrounding a pipeline
@@ -326,6 +326,7 @@ F:anonymous function, and a descriptor leak when backgrounding a pipeline
callfromchld() { true && { print CHLD } }
TRAPCHLD() { callfromchld }
sleep 2 & sleep 3; print OK
+ unfunction TRAPCHLD # don't affect future tests
0:Background job exit does not affect reaping foreground job
>CHLD
>OK
@@ -394,3 +395,23 @@ F:anonymous function, and a descriptor leak when backgrounding a pipeline
>127
# TBD: the 0 above is believed to be bogus and should also be turned
# into 127 when the ccorresponding bug is fixed in the main shell.
+
+# Without the outer subshell, the test harness reports the pre-46060 behaviour
+# as "skipped" rather than "failed".
+ (( exit 130 ) | { sleep 1; echo hello })
+0:exit code 130 isn't mistaken for a signal (unit test for workers/46060)
+>hello
+
+ (exit 3); repeat "$?" echo x
+ (exit 3); repeat '?' echo y
+0:'repeat' loop can use lastval in the count
+>x
+>x
+>x
+>y
+>y
+>y
+
+ (exit 4); repeat 0 do done
+0:'repeat 0' resets lastval
+
diff --git a/Test/B01cd.ztst b/Test/B01cd.ztst
index d903b7462..bc6757549 100644
--- a/Test/B01cd.ztst
+++ b/Test/B01cd.ztst
@@ -33,7 +33,7 @@
#
# 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
+ mkdir cdtst.tmp cdtst.tmp/foo cdtst.tmp/real cdtst.tmp/sub
ln -s ../real cdtst.tmp/sub/fake
@@ -70,7 +70,7 @@
# 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 stdout against the expected stdout.
# D Don't diff stderr against 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
@@ -96,8 +96,8 @@
# itself. (The example below isn't particularly useful as errors with
# `cd' are unusual.)
#
-# A couple of features aren't used in this file, but are usefuil in cases
-# where features may not be available so should not be tested. They boh
+# A couple of features aren't used in this file, but are useful in cases
+# where features may not be available so should not be tested. They both
# take the form of variables. Note that to keep the test framework simple
# there is no magic in setting the variables: the chunk of code being
# executed needs to avoid executing any test code by appropriate structure
@@ -149,6 +149,23 @@ F:something is broken. But you already knew that.
-f:(workers/45367) cd -P squashes multiple leading slashes
>/dev
+ chpwd_hook() { hook_pwd=$PWD; }
+ chpwd_functions=(chpwd_hook)
+ cd $mydir/cdtst.tmp/foo &&
+ (cd $mydir && mv $mydir/cdtst.tmp/{foo,bar}) &&
+ print $PWD &&
+ print $hook_pwd &&
+ cd . &&
+ print $PWD &&
+ print $hook_pwd
+ chpwd_functions=()
+ unfunction chpwd_hook
+0q:cd . with moved PWD
+>$mydir/cdtst.tmp/foo
+>$mydir/cdtst.tmp/foo
+>$mydir/cdtst.tmp/bar
+>$mydir/cdtst.tmp/bar
+
%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
diff --git a/Test/B02typeset.ztst b/Test/B02typeset.ztst
index e7bf93794..8b3988151 100644
--- a/Test/B02typeset.ztst
+++ b/Test/B02typeset.ztst
@@ -620,7 +620,7 @@
print ${+pbro} >&2
(typeset -g pbro=3)
(pbro=4)
- readonly -p pbro >&2 # shows up as "readonly" although unset
+ readonly -p >&2 # shows up as "readonly" although unset
typeset -gr pbro # idempotent (no error)...
print ${+pbro} >&2 # ...so still readonly...
typeset -g +r pbro # ...can't turn it off
@@ -1050,23 +1050,21 @@
$ZTST_testdir/../Src/zsh --emulate sh -f -c '
PATH=/bin; export PATH; readonly PATH
- export -p PATH
+ export -p PATH # Should be a no-op, -p ignored
typeset -p PATH
readonly -p'
0: readonly/export output for exported+readonly+special when started as sh
->export PATH=/bin
>export -r PATH=/bin
>readonly PATH=/bin
function {
emulate -L sh
MANPATH=/bin; export MANPATH; readonly MANPATH
- export -p MANPATH
+ export -p MANPATH # Should be a no-op, -p ignored
typeset -p MANPATH
readonly -p
}
0: readonly/export output for exported+readonly+tied+special after switching to sh emulation
->export MANPATH=/bin
>export -rT MANPATH manpath=( /bin )
>readonly MANPATH=/bin
diff --git a/Test/B03print.ztst b/Test/B03print.ztst
index 0ef3743ce..4d2cf9764 100644
--- a/Test/B03print.ztst
+++ b/Test/B03print.ztst
@@ -4,6 +4,7 @@
# Use of print -p to output to coprocess A01grammar
# Prompt expansion with print -P D01prompt
# -l, -r, -R and -n indirectly tested in various places
+# multibyte tests in D07multibyte
# Not yet tested:
# echo and pushln
@@ -303,15 +304,16 @@
foo=$'one\ttwo\tthree\tfour\n'
foo+=$'\tone\ttwo\tthree\tfour\n'
foo+=$'\t\tone\t\ttwo\t\tthree\t\tfour'
- print -x4 $foo
- print -X4 $foo
+ foo+='\0' # regression test for multibyte tab expand
+ print -x4 $foo | tr '\0' Z # avoid raw nul byte in expected output below
+ print -X4 $foo | tr '\0' Z
0:Tab expansion by print
>one two three four
> one two three four
-> one two three four
+> one two three fourZ
>one two three four
> one two three four
-> one two three four
+> one two three fourZ
unset foo
print -v foo once more
diff --git a/Test/B07emulate.ztst b/Test/B07emulate.ztst
index 7b1592fa9..45c39b51d 100644
--- a/Test/B07emulate.ztst
+++ b/Test/B07emulate.ztst
@@ -276,3 +276,25 @@ F:Some reserved tokens are handled in alias expansion
0:--emulate followed by other options
>yes
>no
+
+ emulate sh -c '
+ foo () {
+ VAR=foo &&
+ echo $VAR | bar &&
+ echo "$VAR"
+ }
+ bar () {
+ tr f b &&
+ VAR="$(echo bar | tr r z)" &&
+ echo "$VAR"
+ }
+ foo
+ '
+ emulate sh -c 'func() { echo | local def="abc"; echo $def;}; func'
+ emulate sh -c 'abc="def"; echo | abc="ghi"; echo $abc'
+0:emulate sh uses subshell for last pipe entry
+>boo
+>baz
+>foo
+>
+>def
diff --git a/Test/B10getopts.ztst b/Test/B10getopts.ztst
index 72c9e209e..e50d177c7 100644
--- a/Test/B10getopts.ztst
+++ b/Test/B10getopts.ztst
@@ -96,3 +96,32 @@
done
0:missing option-argument (quiet mode)
>:,x
+
+ # This function is written so it can be easily referenced against other shells
+ t() {
+ local o i=0 n=$1
+ shift
+ while [ $i -lt $n ]; do
+ i=$(( i + 1 ))
+ getopts a: o "$@" 2> /dev/null
+ done
+ printf '<%d>' "$OPTIND"
+ }
+ # Try all these the native way, then the POSIX_BUILTINS way
+ for 1 in no_posix_builtins posix_builtins; do (
+ setopt $1
+ print -rn - "$1: "
+ t 1
+ t 1 foo
+ t 1 -- foo
+ t 1 -a
+ t 1 -b
+ t 2 -a -b
+ t 4 -a -b -c -d -a
+ t 5 -a -b -c -a -b -c
+ t 5 -a -b -c -d -ax -a
+ print
+ ); done
+0:OPTIND calculation with and without POSIX_BUILTINS (workers/42248)
+>no_posix_builtins: <1><1><2><1><1><3><5><7><6>
+>posix_builtins: <1><1><2><2><2><3><6><7><7>
diff --git a/Test/B11kill.ztst b/Test/B11kill.ztst
new file mode 100644
index 000000000..dc6bf9b89
--- /dev/null
+++ b/Test/B11kill.ztst
@@ -0,0 +1,86 @@
+# Tests for the kill builtin.
+#
+# The exit codes 11 and 19 in this file don't mean anything special; they're
+# just exit codes which are specific enough that the failure of `kill` itself
+# can be differentiated from exiting due to executing a trap.
+
+%test
+
+# Correct invocation
+
+ if zmodload zsh/system &>/dev/null; then
+ (
+ trap 'exit 19' TERM
+ kill $sysparams[pid]
+ )
+ else
+ ZTST_skip='Cannot zmodload zsh/system, skipping kill with no sigspec'
+ fi
+19:kill with no sigspec
+
+
+ if zmodload zsh/system &>/dev/null; then
+ (
+ trap 'exit 11' USR1
+ kill -USR1 $sysparams[pid]
+ )
+ else
+ ZTST_skip='Cannot zmodload zsh/system, skipping kill with sigspec'
+ fi
+11:kill with sigspec
+
+# Incorrect invocation
+
+ (
+ kill a b c
+ )
+3:kill with multiple wrong inputs should increment status
+?(eval):kill:2: illegal pid: a
+?(eval):kill:2: illegal pid: b
+?(eval):kill:2: illegal pid: c
+
+ (
+ kill -INT a b c
+ )
+3:kill with sigspec and wrong inputs should increment status
+?(eval):kill:2: illegal pid: a
+?(eval):kill:2: illegal pid: b
+?(eval):kill:2: illegal pid: c
+
+ (
+ kill
+ )
+1:kill with no arguments
+?(eval):kill:2: not enough arguments
+
+ (
+ kill -INT
+ )
+1:kill with sigspec only
+?(eval):kill:2: not enough arguments
+
+# Regression tests: `kill ''` should not result in `kill 0`.
+#
+# We use SIGURG where an explicit sigspec can be provided as:
+#
+# 1. By default it's non-terminal, so even if we regress, we won't kill the
+# test runner and other processes in the process group since we'll stop
+# running this test before we get to the plain kill (and thus SIGTERM)
+# cases;
+# 2. It's also unlikely to be sent for any other reason during the process
+# lifetime, so the test shouldn't be flaky.
+
+ (
+ trap 'exit 11' URG
+ kill -URG ''
+ )
+1:kill with empty pid and sigspec should not send signal to current process group
+?(eval):kill:3: illegal pid:
+
+ (
+ trap 'exit 19' TERM
+ kill ''
+ )
+1:Plain kill with empty pid should not send signal to current process group
+?(eval):kill:3: illegal pid:
+
diff --git a/Test/B12limit.ztst b/Test/B12limit.ztst
new file mode 100644
index 000000000..9dce59824
--- /dev/null
+++ b/Test/B12limit.ztst
@@ -0,0 +1,28 @@
+
+%prep
+
+ if ! zmodload zsh/rlimits 2>/dev/null
+ then
+ ZTST_unimplemented="the zsh/rlimits module was disabled by configure (see config.modules)"
+ return 0
+ fi
+ zmodload zsh/rlimits
+
+%test
+
+ limit | grep UNKNOWN || print OK
+0:Check if there is unknown resource(s) in the system
+>OK
+F:A failure here does not indicate any error in zsh. It just means there
+F:is a resource in your system that is unknown to zsh developers. Please
+F:report this to zsh-workers mailing list.
+
+ () {
+ set -- ${(f)"$(ulimit -a)"}
+ set -- ${@%%:*}
+ typeset -aU unique_options=( "$@" )
+ # The value of $unique_options is, e.g., ( -t -f '-N 2' -s ... ).
+ (( $# == $#unique_options ))
+ }
+0:check if limit option letters are unique
+
diff --git a/Test/B13whence.ztst b/Test/B13whence.ztst
new file mode 100644
index 000000000..3b35835fe
--- /dev/null
+++ b/Test/B13whence.ztst
@@ -0,0 +1,34 @@
+%prep
+
+ mkdir whence.tmp
+ ln -s . whence.tmp/cwd
+ # cd through the symlink in order to test the case that ${prefix} and
+ # ${prefix:P} are different
+ pushd whence.tmp/cwd
+ ln -s real step3
+ ln -s step3 step2
+ ln -s step2 step1
+ ln -s loop loop
+ ln -s flip flop
+ ln -s flop flip
+ touch real
+ chmod +x real
+ prefix=$PWD
+ popd
+
+%test
+
+ (
+ path=( ${PWD:P}/whence.tmp $path )
+ whence -S step1
+ whence -s step1
+ )
+0q:whence symlink resolution
+>${prefix:P}/step1 -> ${prefix:P}/step2 -> ${prefix:P}/step3 -> ${prefix:P}/real
+>${prefix:P}/step1 -> ${prefix:P}/real
+
+ (
+ path=( $PWD/whence.tmp $path )
+ whence -S flip || whence -S loop || whence -s flip || whence -s loop
+ )
+1:whence deals with symlink loops gracefully
diff --git a/Test/C01arith.ztst b/Test/C01arith.ztst
index 419f45292..d0092fefa 100644
--- a/Test/C01arith.ztst
+++ b/Test/C01arith.ztst
@@ -180,9 +180,10 @@
1:bases beyond 36 don't work
?(eval):1: invalid base (must be 2 to 36 inclusive): 37
+ fail=39
print $(( 3 + "fail" ))
-1:parse failure in arithmetic
-?(eval):1: bad math expression: operand expected at `"fail" '
+0:Double quotes are not treated specially in arithmetic
+>42
alias 3=echo
print $(( 3 + "OK"); echo "Worked")
@@ -487,3 +488,8 @@
let noexist==0 )
1:Arithmetic, NO_UNSET part 3
?(eval):2: noexist: parameter not set
+
+ print $(( "6+2" / "1+3" ))
+0:Double quotes are not treated specially in arithmetic (POSIX)
+# and do not do grouping! this is 6 + (2/1) + 3
+>11
diff --git a/Test/C02cond.ztst b/Test/C02cond.ztst
index 4b1ec02f0..4366b4142 100644
--- a/Test/C02cond.ztst
+++ b/Test/C02cond.ztst
@@ -146,39 +146,27 @@
# can't be bothered with -S
- if [[ ${mtab::="$({mount || /sbin/mount || /usr/sbin/mount} 2>/dev/null)"} = *[(]?*[)] ]]; then
- print -u $ZTST_fd 'This test takes two seconds...'
- else
- unmodified_ls="$(ls -lu $unmodified)"
- print -u $ZTST_fd 'This test takes up to 60 seconds...'
- fi
- sleep 2
+ print -ru $ZTST_fd 'This test may take two seconds...'
touch $newnewnew
if [[ $OSTYPE == "cygwin" ]]; then
ZTST_skip="[[ -N file ]] not supported on Cygwin"
elif (( isnfs )); then
ZTST_skip="[[ -N file ]] not supported with NFS"
- elif { (( ! $+unmodified_ls )) &&
- cat $unmodified &&
- { df -k -- ${$(print -r -- "$mtab" |
- awk '/noatime/ {print $1,$3}'):-""} | tr -s ' ' |
- fgrep -- "$(df -k . | tail -1 | tr -s ' ')" } >&/dev/null } ||
- { (( $+unmodified_ls )) && SECONDS=0 &&
- ! until (( SECONDS >= 58 )); do
- ZTST_hashmark; sleep 2; cat $unmodified
- [[ $unmodified_ls != "$(ls -lu $unmodified)" ]] && break
- done }; then
- ZTST_skip="[[ -N file ]] not supported with noatime file system"
+ elif ! zmodload -F zsh/stat b:zstat 2> /dev/null; then
+ ZTST_skip='[[ -N file ]] not tested; zsh/stat not available'
+ elif ! { sleep 2; touch -a $unmodified 2> /dev/null }; then
+ ZTST_skip='[[ -N file ]] not tested; touch failed'
+ elif [[ "$(zstat +atime $unmodified)" == "$(zstat +mtime $unmodified)" ]]; then
+ ZTST_skip='[[ -N file ]] not supported on this file system'
else
[[ -N $newnewnew && ! -N $unmodified ]]
fi
0:-N cond
-F:This test can fail on NFS-mounted filesystems as the access and
-F:modification times are not updated separately. The test will fail
-F:on HFS+ (Apple Mac OS X default) filesystems because access times
-F:are not recorded. Also, Linux ext3 filesystems may be mounted
-F:with the noatime option which does not update access times.
-F:Failures in these cases do not indicate a problem in the shell.
+F:This test relies on the file system supporting atime updates. It
+F:should automatically detect whether this is the case, and skip
+F:without failing if it isn't, but it's possible that some
+F:configurations may elude this detection. Please report this
+F:scenario if you encounter it.
[[ $newnewnew -nt $zlnfs && ! ($unmodified -nt $zlnfs) ]]
0:-nt cond
@@ -392,7 +380,7 @@ F:Failures in these cases do not indicate a problem in the shell.
>0
>0
>1
->0
+>1
>0
>0
>1
diff --git a/Test/C04funcdef.ztst b/Test/C04funcdef.ztst
index 407fc471f..af469c527 100644
--- a/Test/C04funcdef.ztst
+++ b/Test/C04funcdef.ztst
@@ -307,7 +307,7 @@
# lsfoo should not be expanded as an anonymous function argument
alias lsfoo='This is not ls.'
() (echo anon func; echo "$@") lsfoo
-0:Anonmous function with arguments in a form nobody sane would ever use but unfortunately we have to support anyway
+0:Anonymous function with arguments in a form nobody sane would ever use but unfortunately we have to support anyway
>anon func
>lsfoo
@@ -508,7 +508,8 @@
# keep spec from getting loaded in parent shell for simplicity
(
- if whence spec; then print spec already loaded >&2; exit 1; fi
+ if [[ $(whence -v spec) = 'spec is a shell function from '$PWD/* ]]
+ then print spec already loaded >&2; exit 1; fi
autoload -Uz $PWD/spec
autoload -Uz $PWD/extra/spec
spec
@@ -517,7 +518,8 @@
>I have been loaded by explicit path.
(
- if whence spec; then print spec already loaded >&2; exit 1; fi
+ if [[ $(whence -v spec) = 'spec is a shell function from '$PWD/* ]]
+ then print spec already loaded >&2; exit 1; fi
autoload -Uz $PWD/extra/spec
autoload spec
spec
diff --git a/Test/D01prompt.ztst b/Test/D01prompt.ztst
index 7ff478e68..6879e6fd1 100644
--- a/Test/D01prompt.ztst
+++ b/Test/D01prompt.ztst
@@ -229,3 +229,37 @@
Ffoo=${(%):-'%F{foo}'} # Unrecognised
[[ $f == $Fdefault && $Fdefault == $Freset && $Freset == $Ffoo ]]
0:Regression test for workers/44029
+
+ if
+ zmodload zsh/terminfo >& /dev/null &&
+ (( terminfo[colors] >= 8 ))
+ then
+ F1=$(echoti setaf 2)
+ F2=${(%):-%2F}
+ F3=${(%):-%F{2}}
+ F4=${(%):-%F{green}}
+ [[ -n $F1 && $F1 = $F2 && $F2 = $F3 && $F3 = $F4 ]]
+ else
+ ZTST_skip='Missing terminfo module or non-colour terminal'
+ fi
+0:Equivalence of terminal colour settings (foreground colour)
+
+ if
+ zmodload zsh/terminfo >& /dev/null &&
+ (( terminfo[colors] >= 8 ))
+ then
+ K1=$(echoti setab 2)
+ K2=${(%):-%2K}
+ K3=${(%):-%K{2}}
+ K4=${(%):-%K{green}}
+ [[ -n $K1 && $K1 = $K2 && $K2 = $K3 && $K3 = $K4 ]]
+ else
+ ZTST_skip='Missing terminfo module or non-colour terminal'
+ fi
+0:Equivalence of terminal colour settings (background colour)
+
+ (RPS1=foo; echo $RPS1 $RPROMPT)
+ (RPS2=bar; echo $RPS2 $RPROMPT2)
+-fD:RPS1 and RPROMPT are aliases (regression from 5.0.6) (workers/49600)
+>foo foo
+>bar bar
diff --git a/Test/D02glob.ztst b/Test/D02glob.ztst
index b0650c8c8..72891a2a7 100644
--- a/Test/D02glob.ztst
+++ b/Test/D02glob.ztst
@@ -690,10 +690,9 @@
# This is a bit brittle as it depends on PATH_MAX.
# We could use sysconf..
bad_pwd="/${(l:16000:: :):-}"
- print ${bad_pwd:P}
+ print ${#${bad_pwd:P}}
0:modifier ':P' with path too long
-?(eval):4: path expansion failed, using root directory
->/
+>16001
foo=a
value="ac"
@@ -734,7 +733,7 @@
mkdir -m 444 glob.tmp/secret-d444
for 1 in 000 111 444 ; do ln -s secret-d$1 glob.tmp/secret-s$1; done
print -rC 2 -- glob.tmp/secret-*/ glob.tmp/secret-*(-/)
--f:unreadable directories can be globbed (users/24619, users/24626)
+0:unreadable directories can be globbed (users/24619, users/24626)
>glob.tmp/secret-d000/ glob.tmp/secret-d000
>glob.tmp/secret-d111/ glob.tmp/secret-d111
>glob.tmp/secret-d444/ glob.tmp/secret-d444
@@ -742,10 +741,79 @@
>glob.tmp/secret-s111/ glob.tmp/secret-s111
>glob.tmp/secret-s444/ glob.tmp/secret-s444
+ for 1 in 000 111 444 ; do
+ chmod 777 glob.tmp/secret-d$1
+ touch glob.tmp/secret-d$1/file
+ mkdir -m 777 glob.tmp/secret-d$1/dir
+ touch glob.tmp/secret-d$1/dir/file
+ chmod $1 glob.tmp/secret-d$1
+ done
+ print -raC 2 -- glob.tmp/secret-*/* glob.tmp/secret-*/file
+0:names inside unreadable directories can be globbed if searchable
+>glob.tmp/secret-d444/dir glob.tmp/secret-d444/file
+>glob.tmp/secret-s444/dir glob.tmp/secret-s444/file
+>glob.tmp/secret-d111/file glob.tmp/secret-s111/file
+
+ print -rC 2 -- glob.tmp/secret-*/dir/*
+0:glob files in readable directories inside unreadable directories
+>glob.tmp/secret-d111/dir/file glob.tmp/secret-s111/dir/file
+
+ # On macOS, stat(2) allows files to be treated as directories if the calling
+ # process has super-user privileges. e.g., stat() on /my/regular/file/. will
+ # succeed as root but (correctly) fail otherwise. This can produce strange
+ # results when globbing, depending on how it's implemented. This test should,
+ # when run with privileges, confirm that the implementation avoids this
+ # problem. See workers/42891 and workers/45291
+ : > glob.tmp/not-a-directory
+ print -r - glob.tmp/not-a-dir*(N) , glob.tmp/not-a-dir*/(N)
+0:non-directories not globbed as directories
+>glob.tmp/not-a-directory ,
+
() { echo $1:P } ////dev
-f:(workers/45367) modifier ':P' squashes multiple slashes
>/dev
+ ln -s loop glob.tmp/loop
+ ln -s loop glob.tmp/trap
+ {
+ (set -- glob.tmp/trap; echo $1:P)
+ (set -- glob.tmp/loop; echo $1:P)
+ } always {
+ rm -f glob.tmp/trap glob.tmp/loop
+ }
+0:the ':P' modifier handles symlink loops in the last path component
+*>*/(trap|loop)
+*>*/(trap|loop)
+
+ ln -s loop glob.tmp/loop
+ ln -s loop glob.tmp/trap
+ {
+ (set -- glob.tmp/loop/trailing/components; echo $1:P)
+ (set -- glob.tmp/trap/trailing/components; echo $1:P)
+ } always {
+ rm -f glob.tmp/trap glob.tmp/loop
+ }
+0:the ':P' modifier handles symlink loops before the last path component
+*>*/glob.tmp/loop/trailing/components
+*>*/glob.tmp/(loop|trap)/trailing/components
+
+ ln -s flip glob.tmp/flop
+ ln -s flop glob.tmp/flip
+ {
+ (set -- glob.tmp/flip; echo $1:P)
+ (set -- glob.tmp/flip/trailing/components; echo $1:P)
+ } always {
+ rm -f glob.tmp/flip glob.tmp/flop
+ }
+0:the ':P' modifier handles symlink loops other than the trivial case
+*>*/glob.tmp/(flip|flop)
+*>*/glob.tmp/(flip|flop)/trailing/components
+
+ unsetopt extendedglob
+ print -r -- ${(*)=${(@s.+.):-A+B}/(#b)(?)/-${(L)match[1]} ${match[1]}}
+0:the '*' qualfier enables extended_glob for pattern matching
+>-a A -b B
+
%clean
# Fix unreadable-directory permissions so ztst can clean up properly
diff --git a/Test/D03procsubst.ztst b/Test/D03procsubst.ztst
index 8cf4e2a7f..1e5cd9f6c 100644
--- a/Test/D03procsubst.ztst
+++ b/Test/D03procsubst.ztst
@@ -156,3 +156,16 @@
procfunc <(echo argument)
0:With /proc/self file descriptors must not be tidied up too early
>argument
+
+ $ZTST_testdir/../Src/zsh -df -o shfileexpansion -c 'cat =(echo hi)'
+0:EQUALS expansion followed by =(...) (sh ordering) should work
+>hi
+
+ () {
+ local TMPPREFIX=$PWD/tmp
+ command true =(true) =(true) | :
+ print -rC1 -- $TMPPREFIX*(N)
+ }
+0f:external command with =(...) on LHS of pipeline cleans up its tempfiles
+# (Expected result: no output.)
+
diff --git a/Test/D04parameter.ztst b/Test/D04parameter.ztst
index 76f3e77a1..6bf55b4db 100644
--- a/Test/D04parameter.ztst
+++ b/Test/D04parameter.ztst
@@ -1398,6 +1398,13 @@
>a6 a17 a117 b6 b17 b117
>b117 b17 b6 a117 a17 a6
+ foo=(a-6 a117 a-17 a-34 b6 b-117 b17 b-2)
+ print ${(-)foo}
+ print ${(O-)foo}
+0:Numeric sorting of signed integers
+>a-34 a-17 a-6 a117 b-117 b-2 b6 b17
+>b17 b6 b-2 b-117 a117 a-6 a-17 a-34
+
x=sprodj
x[-10]=scrumf
print $x
@@ -1615,6 +1622,8 @@
print ${foo: -1}
print ${foo: -10}
print ${foo:5:-2}
+ print ${foo::3}
+ print ${foo: }
0:Bash-style offsets, scalar
>456789
>56789
@@ -1627,6 +1636,8 @@
>9
>123456789
>67
+>123
+>123456789
foo=(1 2 3 4 5 6 7 8 9)
print ${foo:3}
@@ -1682,14 +1693,48 @@
>b
>c
+ () {
+ emulate -L sh
+ local a=( one two three )
+ printf '<%s><%s>\n' ${a[*]:0:2}
+ printf '<%s><%s>\n' "${a[*]:0:2}"
+ printf '<%s><%s>\n' ${a[@]:0:2}
+ printf '<%s><%s>\n' "${a[@]:0:2}"
+ printf '<%s><%s>\n' "${a:0:2}"
+ printf '<%s><%s>\n' ${*:1:2}
+ printf '<%s><%s>\n' "${*:1:2}"
+ printf '<%s><%s>\n' ${@:1:2}
+ printf '<%s><%s>\n' "${@:1:2}"
+ printf '<%s><%s>\n' ${*:0:2}
+ printf '<%s><%s>\n' "${*:0:2}"
+ printf '<%s><%s>\n' ${@:0:2}
+ printf '<%s><%s>\n' "${@:0:2}"
+ } one two three
+0:Bash-style offsets, quoted array
+><one><two>
+><one two><>
+><one><two>
+><one><two>
+><on><>
+><one><two>
+><one two><>
+><one><two>
+><one><two>
+><(anon)><one>
+><(anon) one><>
+><(anon)><one>
+><(anon)><one>
+
printf "%n" '[0]'
1:Regression test for identifier test
?(eval):1: not an identifier: [0]
str=rts
+ print ${str:0: }
print ${str:0:}
1:Regression test for missing length after offset
-?(eval):2: unrecognized modifier
+>
+?(eval):3: unrecognized modifier
foo="123456789"
print ${foo:5:-6}
@@ -2650,3 +2695,35 @@ F:behavior, see http://austingroupbugs.net/view.php?id=888
>1: pws
>3: pw
>4: pw
+
+ : "${foo:0:${\"}}"
+1:broken length in ${name:offset:length} (workers/45843#1)
+?(eval):1: unrecognized modifier `$'
+
+ $ZTST_testdir/../Src/zsh -fc $'$\\\n('
+1:regression test for workers/45843#2: escaped newline in command substitution start token
+?zsh:2: parse error near `$('
+
+# `
+
+ eval $'echo $\\\n(printf "%d\\n" $(( 4 + 2 )) )'
+0:Normal command substitution with escaped newline
+>6
+
+ eval $'echo $\\\n(( 14 / 2 ))'
+0:Normal math eval with escaped newline after $
+>7
+
+ eval $'echo $(\\\n( 15 / 3 ))'
+0:Normal math eval with escaped newline after $(
+>5
+
+ function '*' { echo What a star; }
+ eval 'echo $(\*)'
+0:Backslash character other than newline is normal after $(
+>What a star
+
+ : ${(zZ+x+):-}
+1:parameter expansion flags parsing error gives a clue
+?(eval):1: error in flags near position 7 in '${(zZ+x+):-}'
+
diff --git a/Test/D06subscript.ztst b/Test/D06subscript.ztst
index c1a8d79cf..adbd398c4 100644
--- a/Test/D06subscript.ztst
+++ b/Test/D06subscript.ztst
@@ -289,3 +289,8 @@ F:Regression test for workers/42297
>14 24
>b b
>b?rbaz foob?r
+
+ i=1,3
+ [[ ${a[$i]} = ${a[i]} ]]
+0f:Math evaluation of commas in array subscripts
+F:In math, (($i)) should be the same as ((i)), see workers/47748.
diff --git a/Test/D07multibyte.ztst b/Test/D07multibyte.ztst
index e20315340..cbd802f23 100644
--- a/Test/D07multibyte.ztst
+++ b/Test/D07multibyte.ztst
@@ -178,6 +178,13 @@
>3
?(eval):1: command not found: hähä=3
+ expr='[[ é = [[:IDENT:]] ]]'
+ ( unsetopt posix_identifiers; eval $expr && echo ok unset )
+ ( setopt posix_identifiers; eval $expr || echo ok set )
+0:Regression test for workers/47745
+>ok unset
+>ok set
+
foo="Ølaf«Ødd«øpénëd«ån«àpple"
print -l ${(s.«.)foo}
ioh="Ἐν ἀρχῇ ἦν ὁ λόγος, καὶ ὁ λόγος ἦν πρὸς τὸν θεόν, καὶ θεὸς ἦν ὁ λόγος."
@@ -340,6 +347,18 @@
0:Multibyte characters in printf widths
> főo
+# TODO?: POSIX requires that printf should always compute width and
+# precision of '%s' conversion in bytes, while zsh computes them in
+# characters if multi-byte locale is in use.
+ ARGV0=sh $ZTST_testdir/../Src/zsh -c "printf '<%10s>\n' St$'\M-C\M-)'phane"
+0f:POSIX: width in %s should be computed in bytes, not in characters
+F:This is considered a bugfix in zsh
+>< Stéphane>
+
+ ARGV0=sh $ZTST_testdir/../Src/zsh -c "printf '<%7.5s>\n' St$'\M-C\M-)'phane"
+0f:POSIX: precision should also be computed in bytes, not in characers
+>< Stép>
+
# We ask for case-insensitive sorting here (and supply upper case
# characters) so that we exercise the logic in the shell that lowers the
# case of the string for case-insensitive sorting.
@@ -570,6 +589,15 @@
0:printf %q and quotestring and general metafy / token madness
>你你
+ typeset foo
+ print -v foo 'ÖÓŐ'
+ echo $foo
+ printf -v foo 'ÖÓŐ'
+ echo $foo
+0:print and printf into a variable with multibyte text
+>ÖÓŐ
+>ÖÓŐ
+
# This test is kept last as it introduces an additional
# dependency on the system regex library.
if zmodload zsh/regex 2>/dev/null; then
@@ -585,3 +613,17 @@
>OK
F:A failure here may indicate the system regex library does not
F:support character sets outside the portable 7-bit range.
+
+ (
+ locale=$LANG
+ unset -m 'LC_*|LANG'
+ export LC_CTYPE=$locale
+ echo '\u276F' # this works
+ () {
+ local LC_ALL=C
+ }
+ echo '\u276F' # this doesn't work
+ )
+0:locale gets restored when locale parameters go out of scope (regression test for 45772)
+>❯
+>❯
diff --git a/Test/E01options.ztst b/Test/E01options.ztst
index cfe2c75cc..72749e6ab 100644
--- a/Test/E01options.ztst
+++ b/Test/E01options.ztst
@@ -57,7 +57,6 @@
# PROMPT_CR
# PUSHD_SILENT
# REC_EXACT
-# RM_STAR_SILENT
# RM_STAR_WAIT
# SHARE_HISTORY
# SINGLE_LINE_ZLE
@@ -92,6 +91,9 @@
catpath=$(which cat)
lspath==ls
+ # If the module fails to load, individual test points will skip.
+ zmodload zsh/zpty 2>/dev/null || true
+
%test
# setopt should move on to the next operation in the face of an error, but
@@ -1109,15 +1111,22 @@ F:Regression test for workers/41811
eval 'for f (word1 word2) print $f'
eval 'repeat 3 print nonsense'
}
- unsetopt shortloops
- print option unset
+ unsetopt shortloops shortrepeat
+ print shortloops and shortrepeat unset
+ fn
+ setopt shortrepeat
+ print shortrepeat set
fn
setopt shortloops
- print option set
+ print shortloops set
fn
0:SHORT_LOOPS option
->option unset
->option set
+>shortloops and shortrepeat unset
+>shortrepeat set
+>nonsense
+>nonsense
+>nonsense
+>shortloops set
>foo
>bar
>word1
@@ -1128,6 +1137,8 @@ F:Regression test for workers/41811
?(eval):1: parse error near `print'
?(eval):1: parse error near `print'
?(eval):1: parse error near `print'
+?(eval):1: parse error near `print'
+?(eval):1: parse error near `print'
fn() { print -l $*; }
setopt shwordsplit
@@ -1414,3 +1425,44 @@ F:If this test fails at the first unsetopt, refer to P01privileged.ztst.
(( UID == EUID ))
fi
0:PRIVILEGED sanity check: default value is correct
+
+ if zmodload -e zsh/zpty 2>/dev/null; then
+ for target_dir target_pattern in \
+ '.' '*' \
+ '/' '/*'
+ do
+ before=`ls -a -- $target_dir`
+ zpty subshell $ZTST_testdir/../Src/zsh -f +Z
+ [[ $PWD == */options.tmp ]] || return 1 # Sanity check before calling rm(1).
+ zpty -w subshell 'PS1=PROMPT'
+ zpty -r -m subshell REPLY $'*PROMPT'
+ zpty -w subshell "rm $target_pattern"
+ zpty -w -n subshell 'n'
+ sleep 1
+ zpty -rt subshell REPLY && print -r -- ${REPLY%%$'\r\n'}
+ zpty -d subshell
+ after=`ls -a -- $target_dir`
+ [[ $before == $after ]] || return 1
+ done
+ else
+ ZTST_skip="the zsh/zpty module is not available"
+ fi
+ BEL=$'\a'
+0q:RM_STAR_SILENT
+*>zsh: sure you want to delete all 15 files in ${PWD:h}/options.tmp \[yn\]\? ${BEL}(|n)
+*>zsh: sure you want to delete (all <->|more than <->) files in / \[yn\]\? ${BEL}(|n)
+
+ () {
+ local var
+ print ${(t)var}
+ }
+0:(t) returns correct type
+>scalar-local
+
+ () {
+ readonly var
+ typeset -p var
+ }
+0:readonly with typeset -p
+F:compare E03posix.ztst
+>typeset -r var=''
diff --git a/Test/E02xtrace.ztst b/Test/E02xtrace.ztst
index da6191cd0..56bc20f1a 100644
--- a/Test/E02xtrace.ztst
+++ b/Test/E02xtrace.ztst
@@ -146,3 +146,118 @@
?+(anon):0> '(anon)'
?+(anon):0> true
?+fn:0> gn
+
+ test_cases=(
+ f # baseline
+ foo-bar # Dash
+ ヌ # Meta (the UTF-8 representation of this character has an 0x83 byte)
+ \$\'ba\\0z\' # Nul, escaped as though by ${(qqqq)}
+ )
+ for 1 in "$test_cases[@]"; do
+ eval "
+ ${1}() {
+ ${1}() { echo inner }
+ }
+ functions -T ${1}
+ ${1}
+ LC_ALL=C which ${1}
+ "
+ done
+0:a function that redefines itself preserves tracing
+>f () {
+> # traced
+> echo inner
+>}
+>foo-bar () {
+> # traced
+> echo inner
+>}
+>$'\M-c\M-\C-C\M-\C-L' () {
+> # traced
+> echo inner
+>}
+>$'ba\C-@z' () {
+> # traced
+> echo inner
+>}
+
+ function -T { echo traced anonymous function }
+ functions -- -T # no output
+1:define traced function: anonymous function
+?+(anon):0> echo traced anonymous function
+>traced anonymous function
+
+ function -T f { echo traced named function }
+ functions -- -T # no output
+ functions f
+ f
+0:define traced function: named function
+>f () {
+> # traced
+> echo traced named function
+>}
+?+f:0> echo traced named function
+>traced named function
+
+ function -T -- -T { echo trace function literally named "-T" }
+ -T
+ function -T -- { echo trace anonymous function }
+ functions -- -- # no output
+1:define traced function: parse test
+?+-T:0> echo trace function literally named -T
+>trace function literally named -T
+?+(anon):0> echo trace anonymous function
+>trace anonymous function
+
+ function -- g { echo g }
+ g
+ function -- { echo anonymous }
+ functions -- -- # no output
+1:function end-of-"options" syntax, #1
+>g
+>anonymous
+
+ function -- -T { echo runs }
+ functions -- -- # no output
+ echo the definition didn\'t execute it
+ -T
+0:function end-of-"options" syntax, #2
+>the definition didn't execute it
+>runs
+
+ f() g
+ g() :
+ functions -t f
+ f
+0:functions -t smoke test #1
+?+f:4> g
+?+g:4> :
+F:The `4' on the second line is incorrect; see workers/48594.
+
+ f() g
+ g() { () : }
+ functions -t f
+ f
+0:functions -t smoke test #2
+?+f:4> g
+?+g:0> '(anon)'
+?+(anon):0> :
+
+ f() g
+ g() :
+ (
+ functions -T f
+ functions -t f
+ f
+ )
+ (
+ functions -t f
+ functions -T f
+ f
+ )
+0:ensure the behaviour of 'functions -Tt f' doesn't change surreptitiously
+?+f:6> g
+?+f:11> g
+F:If this test fails, the new behaviour may be
+F:workers/48591.
+
diff --git a/Test/E03posix.ztst b/Test/E03posix.ztst
new file mode 100644
index 000000000..caab97ab6
--- /dev/null
+++ b/Test/E03posix.ztst
@@ -0,0 +1,161 @@
+# Test POSIX-specific behavior
+# Currently this covers only POSIXBUILTINS, other behaviors are in their
+# more directly related sections
+#
+
+%prep
+ setopt POSIX_BUILTINS TYPESET_TO_UNSET
+
+%test
+
+ local parentenv=preserved
+ fn() {
+ typeset -h +g -m \*
+ unset -m \*
+ integer i=9
+ float -H f=9
+ declare -t scalar
+ declare -H -a array
+ typeset
+ typeset +
+ }
+ fn
+ echo $parentenv
+0:Parameter hiding and tagging, printing types and values
+>array local array
+>float local f
+>integer local i=9
+>local tagged scalar
+>array local array
+>float local f
+>integer local i
+>local tagged scalar
+>preserved
+
+ readonly foo=bar novalue
+ readonly -p
+0:readonly -p output (no readonly specials)
+>readonly foo=bar
+>readonly novalue
+
+ local -a myarray
+ typeset -p1 myarray
+ myarray=("&" sand '""' "" plugh)
+ typeset -p1 myarray
+0:typeset -p1 output for array
+>typeset -a myarray
+>typeset -a myarray=(
+> '&'
+> sand
+> '""'
+> ''
+> plugh
+>)
+
+ local -A myhash
+ typeset -p1 myhash
+ myhash=([one]=two [three]= [four]="[]")
+ typeset -p1 myhash
+0:typeset -p1 output for associative array
+>typeset -A myhash
+>typeset -A myhash=(
+> [four]='[]'
+> [one]=two
+> [three]=''
+>)
+
+ str=s
+ arr=(a)
+ typeset -A ass
+ ass=(a a)
+ integer i=0
+ float f=0
+ print ${(t)str} ${(t)arr} ${(t)ass} ${(t)i} ${(t)f}
+0:${(t)...}
+>scalar array association-local integer-local float-local
+
+ print $empty[(i)] $empty[(I)]
+0:(i) and (I) return nothing for empty array
+>
+
+ (
+ # reserved words are handled during parsing,
+ # hence eval...
+ disable -r typeset
+ eval '
+ setopt kshtypeset
+ ktvars=(ktv1 ktv2)
+ typeset ktfoo=`echo arg1 arg2` $ktvars
+ () {
+ local ktfoo
+ print $+ktv1 $+ktv2 $+ktv3 $+ktfoo
+ }
+ print $ktfoo
+ unsetopt kshtypeset
+ typeset noktfoo=`echo noktarg1 noktarg2`
+ print $noktfoo
+ print $+noktarg1 $+noktarg2
+ unset ktfoo ktv1 ktv2 noktfoo noktarg2
+ '
+ )
+0:KSH_TYPESET option
+>0 0 0 0
+>arg1 arg2
+>noktarg1
+>0 0
+
+ () {
+ local var
+ print ${(t)var}
+ }
+0:(t) returns correct type
+>scalar-local
+
+ () {
+ readonly var
+ typeset -p var
+ }
+0:readonly with typeset -p
+>typeset -g -r var
+
+# Tests expected to fail
+
+ echo -
+0f:A single "-" for echo does not end the arguments
+F:POSIX requires a solitary "-" to be a plain argument
+>-
+
+ ARGV0=sh $ZTST_testdir/../Src/zsh -c 'foreach() { true; }'
+-f:"foreach" is not a reserved word
+
+ ARGV0=sh $ZTST_testdir/../Src/zsh -c 'end() { true; }
+-f:"end" is not a reserved word
+
+ a='a:b:' ARGV0=sh $ZTST_testdir/../Src/zsh -c 'IFS=:; printf "<%s>\n" $a'
+0f:IFS is a separator, not a delimiter
+><a>
+><b>
+
+ a=$'\ra\r\rb' ARGV0=sh $ZTST_testdir/../Src/zsh -c 'IFS=:; printf "<%s>\n" $a'
+0f:All whitespace characters are "IFS whitespace"
+F:isspace('\r') is true so \r should behave like space, \t, \n
+F:This may also need to apply to multibyte whitespace
+><a>
+><b>
+
+ ARGV0=sh $ZTST_testdir/../Src/zsh -c 'IFS=2; printf "<%s>\n" $((11*11))'
+0f:IFS applies to math results (numbers treated as strings)
+><1>
+><1>
+
+ ARGV0=sh $ZTST_testdir/../Src/zsh -c 'inf=42; echo $((inf))'
+0:All identifiers are variable references in POSIX arithmetic
+F:POSIX has neither math functions nor floating point
+>42
+
+ ARGV0=sh $ZTST_testdir/../Src/zsh -c 'EUID=10; echo "$EUID"'
+-f:EUID is not a special variable
+>10
+
+ PPID=foo
+-f:PPID is not a readonly variable
diff --git a/Test/P01privileged.ztst b/Test/P01privileged.ztst
index c54112bb6..7c4a1be35 100644
--- a/Test/P01privileged.ztst
+++ b/Test/P01privileged.ztst
@@ -13,8 +13,13 @@
# same requirements here.)
#
# If either of the aforementioned environment variables is not set, the test
-# script will try to pick the first two >0 IDs from the passwd/group databases
-# on the current system.
+# script will try to use the UID/GID of the test directory, if not 0, for the
+# two effective IDs. (This is intended to work around issues that might occur
+# when e.g. the test directory lives under a home directory with mode 0700.
+# Unfortunately, if this is the case, it will not be possible to use anything
+# besides the directory owner or root as the test shell's EUID -- maintainers
+# take note.) Otherwise, the script will pick the first >0 ID(s) from the
+# passwd/group databases on the current system.
#
# If either variable is set, the tests will run, but they will likely fail
# without super-user privileges.
@@ -45,10 +50,12 @@
euid=${ZSH_TEST_UNPRIVILEGED_UID##*:}
else
print -ru$ZTST_fd 'Selecting unprivileged UID:EUID pair automatically'
+ # See above for why we do this
+ zmodload -sF zsh/stat b:zstat && euid=${"$( zstat +uid -- $ZTST_testdir )":#0}
local tmp=$( getent passwd 2> /dev/null || < /etc/passwd )
# Note: Some awks require -v and its argument to be separate
- ruid=$( awk -F: '$3 > 0 { print $3; exit; }' <<< $tmp )
- euid=$( awk -F: -v u=$ruid '$3 > u { print $3; exit; }' <<< $tmp )
+ ruid=$( awk -F: -v u=${euid:-0} '$3 > 0 && $3 != u { print $3; exit; }' <<< $tmp )
+ euid=${euid:-"$( awk -F: -v u=$ruid '$3 > u { print $3; exit; }' <<< $tmp )"}
fi
#
if [[ -n $ZSH_TEST_UNPRIVILEGED_GID ]]; then
@@ -56,10 +63,12 @@
egid=${ZSH_TEST_UNPRIVILEGED_GID##*:}
else
print -ru$ZTST_fd 'Selecting unprivileged GID:EGID pair automatically'
+ # See above again -- this shouldn't have the same impact as the UID, though
+ zmodload -sF zsh/stat b:zstat && egid=${"$( zstat +gid -- $ZTST_testdir )":#0}
local tmp=$( getent group 2> /dev/null || < /etc/group )
# Note: Some awks require -v and its argument to be separate
- rgid=$( awk -F: '$3 > 0 { print $3; exit; }' <<< $tmp )
- egid=$( awk -F: -v g=$rgid '$3 > g { print $3; exit; }' <<< $tmp )
+ rgid=$( awk -F: -v g=${egid:-0} '$3 > 0 && $3 != g { print $3; exit; }' <<< $tmp )
+ egid=${egid:="$( awk -F: -v g=$rgid '$3 > g { print $3; exit; }' <<< $tmp )"}
fi
#
[[ $ruid/$euid == <1->/<1-> && $ruid != $euid ]] || ruid= euid=
@@ -134,11 +143,9 @@
%test
- re_zsh $ruid $ruid -1 -1 'echo $UID/$EUID $options[privileged]'
re_zsh $euid $euid -1 -1 'echo $UID/$EUID $options[privileged]'
re_zsh $ruid $euid -1 -1 'echo $UID/$EUID $options[privileged]'
0q:PRIVILEGED automatically enabled when RUID != EUID
->$ruid/$ruid off
>$euid/$euid off
>$ruid/$euid on
diff --git a/Test/V01zmodload.ztst b/Test/V01zmodload.ztst
index 55c3c314b..daf49cd72 100644
--- a/Test/V01zmodload.ztst
+++ b/Test/V01zmodload.ztst
@@ -64,7 +64,7 @@
for m in $mods
do
- zmodload $m || mods[(r)$m]=()
+ zmodload $m || return $?
done
0d:Test loading of all compiled modules
@@ -349,6 +349,52 @@
?(eval):9: file descriptor out of range
$ZTST_testdir/../Src/zsh -fc "
+ MODULE_PATH=${(q)MODULE_PATH}
+ if zmodload -e zsh/parameter; then zmodload -u zsh/parameter; fi
+ unset options
+ zmodload zsh/parameter
+ echo \$+options
+ "
+-f:can unset a non-readonly autoloadable parameter before loading the module
+>0
+# Currently prints '1'.
+
+ $ZTST_testdir/../Src/zsh -fc "
+ MODULE_PATH=${(q)MODULE_PATH}
+ zmodload zsh/parameter
+ unset options
+ echo \$+options
+ "
+0:can unset a non-readonly autoloadable parameter after loading the module
+>0
+
+ $ZTST_testdir/../Src/zsh -fc "
+ MODULE_PATH=${(q)MODULE_PATH}
+ if zmodload -e zsh/parameter; then zmodload -u zsh/parameter; fi
+ unset builtins
+ "
+-f:can't unset a readonly autoloadable parameter before loading the module
+*?zsh:?: read-only variable: builtins
+# Currently, the 'unset' succeeds.
+
+ $ZTST_testdir/../Src/zsh -fc "
+ MODULE_PATH=${(q)MODULE_PATH}
+ zmodload zsh/parameter
+ unset builtins
+ "
+1:can't unset a readonly autoloadable parameter after loading the module
+*?zsh:?: read-only variable: builtins
+
+ $ZTST_testdir/../Src/zsh -fc "
+ MODULE_PATH=${(q)MODULE_PATH}
+ zmodload zsh/parameter
+ zmodload -u zsh/parameter
+ echo \$options
+ "
+0:unloading a module doesn't implicitly unset autoloadable parameters
+*>(on|off) *
+
+ $ZTST_testdir/../Src/zsh -fc "
MODULE_PATH=${(q)MODULE_PATH}
#
zmodload zsh/zutil
diff --git a/Test/V05styles.ztst b/Test/V05styles.ztst
index c221d9db8..61d2cdb0a 100644
--- a/Test/V05styles.ztst
+++ b/Test/V05styles.ztst
@@ -151,3 +151,25 @@
>one
>two
+ (
+ zstyle ':weather:*:Sunday:*' preferred-precipitation snow
+ zstyle ':weather:europe:*' preferred-precipitation rain
+ zstyle -s ':weather:europe:Sunday:foo' preferred-precipitation REPLY && print $REPLY
+ )
+ (
+ zstyle ':weather:europe:*' preferred-precipitation rain
+ zstyle ':weather:*:Sunday:*' preferred-precipitation snow
+ zstyle -s ':weather:europe:Sunday:foo' preferred-precipitation REPLY && print $REPLY
+ )
+0:the example in the documentation remains correct
+>snow
+>snow
+
+ (
+ zstyle $'con\x00text' $'ke\x00y' $'val\x00u' $'e'
+ a=( ${(f)"$(zstyle -L)"} )
+ a=( ${(M)a:#*con*text*ke*y*val*u*e} )
+ print -r -- "$a"
+ )
+0:zstyle -L escapes the key (regression: workers/48424)
+>zstyle $'con\C-@text' $'ke\C-@y' $'val\C-@u' e
diff --git a/Test/V07pcre.ztst b/Test/V07pcre.ztst
index ab67f3d80..c9c844d2a 100644
--- a/Test/V07pcre.ztst
+++ b/Test/V07pcre.ztst
@@ -1,11 +1,10 @@
%prep
- if grep '^name=zsh/pcre .* link=no ' $ZTST_testdir/../config.modules >/dev/null
+ if ! zmodload zsh/pcre 2>/dev/null
then
ZTST_unimplemented="the zsh/pcre module was disabled by configure (see config.modules)"
return 0
fi
- zmodload zsh/pcre
setopt rematch_pcre
# Find a UTF-8 locale.
setopt multibyte
diff --git a/Test/V08zpty.ztst b/Test/V08zpty.ztst
index b0cbfa050..057db2e18 100644
--- a/Test/V08zpty.ztst
+++ b/Test/V08zpty.ztst
@@ -6,8 +6,6 @@
if ! zmodload zsh/zpty 2>/dev/null
then
ZTST_unimplemented="the zsh/zpty module is not available"
- elif [[ $OSTYPE = cygwin ]]; then
- ZTST_unimplemented="the zsh/zpty module does not work on Cygwin"
fi
%test
diff --git a/Test/V09datetime.ztst b/Test/V09datetime.ztst
index 9f67ecec3..622bdf6ed 100644
--- a/Test/V09datetime.ztst
+++ b/Test/V09datetime.ztst
@@ -130,3 +130,7 @@
>%6. 2002-02-02 02:02:02.999999
>%9. 2002-02-02 02:02:02.999999999
>%12. 2002-02-02 02:02:02.999999999
+
+ strftime -n 'one line%n' 2> /dev/null
+0:-n option
+>one line
diff --git a/Test/V10private.ztst b/Test/V10private.ztst
index a3a63867b..56ffbc5b4 100644
--- a/Test/V10private.ztst
+++ b/Test/V10private.ztst
@@ -19,14 +19,14 @@
() {
print $scalar_test
private scalar_test
- print $+scalar_test
+ typeset +m scalar_test
unset scalar_test
print $+scalar_test
}
print $scalar_test
0:basic scope hiding
>toplevel
->1
+>local scalar_test
>0
>toplevel
@@ -45,14 +45,14 @@
print $+unset_test
() {
private unset_test
- print $+unset_test
+ typeset +m unset_test
unset_test=setme
print $unset_test
}
print $+unset_test
0:variable defined only in scope
>0
->1
+>local unset_test
>setme
>0
@@ -62,13 +62,13 @@
local -Pa array_test=(in function)
() {
private array_test
- print $+array_test
+ typeset +m array_test
}
print $array_test
}
print $array_test
0:nested scope with different type, correctly restored
->1
+>local array_test
>in function
>top level
@@ -116,14 +116,14 @@
}
outer () {
local -PA hash_test=(in function)
- typeset -p hash_test
+ private + hash_test
inner
}
outer
print ${(kv)hash_test}
0:private hides value from surrounding scope in nested scope
>typeset -a hash_test=( top level )
->typeset -A hash_test=( [in]=function )
+>hash_test=( [in]=function )
>typeset -g -a hash_test=( top level )
>array-local top level
>top level
@@ -246,7 +246,7 @@ F:note "typeset" rather than "private" in output from outer
1:privates are not visible in anonymous functions, part 3
>X top level
>array_test not set
-?(anon):4: array_test: attempt to assign private in nested scope
+?(anon):4: array_test: can't change parameter attribute
F:future revision will create a global with this assignment
typeset -a array_test
diff --git a/Test/V12zparseopts.ztst b/Test/V12zparseopts.ztst
index d7fc33f72..816e1d041 100644
--- a/Test/V12zparseopts.ztst
+++ b/Test/V12zparseopts.ztst
@@ -65,11 +65,11 @@
} $=1
done
0:zparseopts -F
-?(anon):zparseopts:2: bad option: x
+?(anon):zparseopts:2: bad option: -x
>ret: 1, optv: , argv: -a -x -z
-?(anon):zparseopts:2: bad option: x
+?(anon):zparseopts:2: bad option: -x
>ret: 1, optv: , argv: -ax -z
-?(anon):zparseopts:2: bad option: -
+?(anon):zparseopts:2: bad option: --x
>ret: 1, optv: , argv: -a --x -z
for 1 in '-a 1 2 3' '1 2 3'; do
@@ -168,5 +168,5 @@
print -r - ret: $?, optv: $optv, argv: $argv
} -ab1 -c
0:missing optarg
-?(anon):zparseopts:2: missing argument for option: c
+?(anon):zparseopts:2: missing argument for option: -c
>ret: 1, optv: , argv: -ab1 -c
diff --git a/Test/V13zformat.ztst b/Test/V13zformat.ztst
new file mode 100644
index 000000000..035a0a495
--- /dev/null
+++ b/Test/V13zformat.ztst
@@ -0,0 +1,91 @@
+# Test the use of zformat, if the zsh/zutil module is available.
+
+%prep
+
+ if ! zmodload zsh/zutil 2>/dev/null; then
+ ZTST_unimplemented="can't load the zsh/zutil module for testing"
+ fi
+
+ # Helper function. Expects a single format using %s and a value for it.
+ zformat_and_print_s() {
+ zformat -f REPLY "$1" "s:$2"
+ print -r - ${(qq)REPLY}
+ }
+
+%test
+
+ zformat_and_print_s '%s' foo
+ zformat_and_print_s '%5s' min
+ zformat_and_print_s '%-5s' neg
+ zformat_and_print_s '%5.s' empty
+ zformat_and_print_s '%.5s' max
+ zformat_and_print_s '%.5s' truncated
+0:basic zformat test
+>'foo'
+>'min '
+>' neg'
+>'empty'
+>'max'
+>'trunc'
+
+ # There may be a set of digits either before or after the opening parenthesis.
+ zformat_and_print_s 'The answer is "%3(s.yes.no)".' 3
+ zformat_and_print_s 'The answer is "%(3s.yes.no)".' 3
+ # The test number defaults to zero.
+ zformat_and_print_s '%(s.equal.unequal)' -1
+ zformat_and_print_s '%(s.equal.unequal)' 0
+ zformat_and_print_s '%(s.equal.unequal)' 1
+ # Negative numbers are allowed
+ # The delimiter is arbitrary
+ zformat_and_print_s '%-4(s.minus four.)' -4
+ zformat_and_print_s '%(-4s//minus four)' -4
+ # The argument is evaluated as a math expression
+ zformat_and_print_s '%18(s.math.)' '6*3'
+0:basic conditionals test
+>'The answer is "yes".'
+>'The answer is "yes".'
+>'unequal'
+>'equal'
+>'unequal'
+>'minus four'
+>''
+>'math'
+
+ () {
+ zformat -f 1 '%(8n.%(5j.yes.no).no)' 'n:8' 'j:5'
+ echo $1
+ }
+0:nested conditionals test
+>yes
+
+ () {
+ zformat -f 1 '%(w.zero.fail) %(x.fail.present) %(y.empty.fail) %(z.missing.fail)' w:0 x:1 y:
+ zformat -F 2 '%(w.zero.fail) %(x.present.fail) %(y.fail.empty) %(z.fail.missing)' w:0 x:1 y:
+ echo $1
+ echo $2
+ }
+0:conditionals with empty and missing values
+>zero present empty missing
+>zero present empty missing
+
+ () {
+ local l
+ for l in 0 1 2 3; do
+ zformat -F 1 "%$l(a.a.A)%$l(b.b.B)%$l(c.c.C)%$l(d.d.D)" a: b:1 c:12 d:123
+ zformat -F 2 "%-$l(a.a.A)%-$l(b.b.B)%-$l(c.c.C)%-$l(d.d.D)" a: b:1 c:12 d:123
+ print - $1 $2
+ done
+ }
+0:minimum and maximum widths
+>Abcd aBCD
+>ABcd abCD
+>ABCd abcD
+>ABCD abcd
+
+ zformat -a argv . foo:lorem ipsum:bar bazbaz '\\esc\:ape'
+ print -rl -- "$@"
+0:basic -a test
+>foo .lorem
+>ipsum.bar
+>bazbaz
+>\esc:ape
diff --git a/Test/V14system.ztst b/Test/V14system.ztst
new file mode 100644
index 000000000..100daab08
--- /dev/null
+++ b/Test/V14system.ztst
@@ -0,0 +1,149 @@
+# Test zsh/system module
+
+%prep
+
+ if zmodload -s zsh/system && zmodload -s zsh/zselect; then
+ tst_dir=V14.tmp
+ mkdir -p -- $tst_dir
+ else
+ ZTST_unimplemented='the zsh/system and zsh/zselect modules are not available'
+ fi
+ : > $tst_dir/file # File on which to acquire flock.
+
+%test
+
+ (
+ zsystem flock -t 0 -i 0.000001 $tst_dir/file &&
+ zsystem flock -t 0.1 -i 0.000001 $tst_dir/file &&
+ zsystem flock -t 0.1 -i 0.0000001 $tst_dir/file &&
+ zsystem flock -t 1 -i 0.000001 $tst_dir/file
+ )
+0:zsystem flock valid time arguments
+
+ (
+ zsystem flock -t 1073741824 $tst_dir/file ||
+ zsystem flock -t 1e100 $tst_dir/file ||
+ zsystem flock -i -1 $tst_dir/file ||
+ zsystem flock -i 0 $tst_dir/file ||
+ zsystem flock -i 1e100 $tst_dir/file
+ )
+1:zsystem flock invalid time arguments
+?(eval):zsystem:2: flock: invalid timeout value: '1073741824'
+?(eval):zsystem:3: flock: invalid timeout value: '1e100'
+?(eval):zsystem:4: flock: invalid interval value: '-1'
+?(eval):zsystem:5: flock: invalid interval value: '0'
+?(eval):zsystem:6: flock: invalid interval value: '1e100'
+
+ (
+ # Lock file for 1 second in the background.
+ lock_flag=$tst_dir/locked1
+ (zsystem flock $tst_dir/file \
+ && touch $lock_flag \
+ && zselect -t 100
+ mv $lock_flag $lock_flag.done) &
+ # Wait until sub-shell above has started.
+ while ! [[ -f $lock_flag || -f $lock_flag.done ]]; do
+ zselect -t 1
+ done
+ if [[ -f $lock_flag.done ]]; then
+ echo "Background shell should not have completed already." 1>&2
+ else
+ # Attempt to lock file with 0.5 second timeout: must fail.
+ zsystem flock -t 0.5 $tst_dir/file
+ fi
+ )
+2:zsystem flock unsuccessful wait test
+F:This timing test might fail due to process scheduling issues unrelated to zsh.
+
+ (
+ # Lock file for 0.5 second in the background.
+ lock_flag=$tst_dir/locked2
+ (zsystem flock $tst_dir/file \
+ && touch $lock_flag \
+ && zselect -t 50
+ mv $lock_flag $lock_flag.done) &
+ # Wait until sub-shell above has started.
+ while ! [[ -f $lock_flag || -f $lock_flag.done ]]; do
+ zselect -t 1
+ done
+ if [[ -f $lock_flag.done ]]; then
+ echo "Background shell should not have completed already." 1>&2
+ fi
+ typeset -F SECONDS
+ start=$SECONDS
+ # Attempt to lock file without a timeout:
+ # must succeed after sub-shell above releases it (0.5 second).
+ if zsystem flock $tst_dir/file; then
+ elapsed=$[ $SECONDS - $start ]
+ if [[ $elapsed -ge 0.3 && $elapsed -le 0.7 ]]; then
+ echo "elapsed time seems OK" 1>&2
+ else
+ echo "elapsed time $elapsed should be ~ 0.5 second" 1>&2
+ fi
+ fi
+ )
+0:zsystem flock successful wait test, no timeout
+?elapsed time seems OK
+F:This timing test might fail due to process scheduling issues unrelated to zsh.
+
+ (
+ # Lock file for 0.5 second in the background.
+ lock_flag=$tst_dir/locked3
+ (zsystem flock $tst_dir/file \
+ && touch $lock_flag \
+ && zselect -t 50
+ mv $lock_flag $lock_flag.done) &
+ # Wait until sub-shell above has started.
+ while ! [[ -f $lock_flag || -f $lock_flag.done ]]; do
+ zselect -t 1
+ done
+ if [[ -f $lock_flag.done ]]; then
+ echo "Background shell should not have completed already." 1>&2
+ fi
+ typeset -F SECONDS
+ start=$SECONDS
+ # Attempt to lock file with 1-second timeout:
+ # must succeed 1 second after start because we retry every 1 second.
+ if zsystem flock -t 1 $tst_dir/file; then
+ elapsed=$[ $SECONDS - $start ]
+ if [[ $elapsed -ge 0.8 && $elapsed -le 1.2 ]]; then
+ echo "elapsed time seems OK" 1>&2
+ else
+ echo "elapsed time $elapsed should be ~ 1 second" 1>&2
+ fi
+ fi
+ )
+0:zsystem flock successful wait test, integral seconds
+?elapsed time seems OK
+F:This timing test might fail due to process scheduling issues unrelated to zsh.
+
+ (
+ # Lock file for 0.25 second in the background.
+ lock_flag=$tst_dir/locked4
+ (zsystem flock $tst_dir/file \
+ && touch $lock_flag \
+ && zselect -t 25
+ mv $lock_flag $lock_flag.done) &
+ # Wait until sub-shell above has started.
+ while ! [[ -f $lock_flag || -f $lock_flag.done ]]; do
+ zselect -t 1
+ done
+ if [[ -f $lock_flag.done ]]; then
+ echo "Background shell should not have completed already." 1>&2
+ fi
+ typeset -F SECONDS
+ start=$SECONDS
+ # Attempt to lock file with 0.4-second timeout, retrying every 0.1 second:
+ # must succeed 0.3 second after start.
+ if zsystem flock -t 0.4 -i 0.1 $tst_dir/file; then
+ elapsed=$[ $SECONDS - $start ]
+ if [[ $elapsed -ge 0.2 && $elapsed -le 0.5 ]]; then
+ echo "elapsed time seems OK" 1>&2
+ else
+ echo "elapsed time $elapsed should be ~ 0.3 second" 1>&2
+ fi
+ fi
+ )
+0:zsystem flock successful wait test, fractional seconds
+?elapsed time seems OK
+F:This timing test might fail due to process scheduling issues unrelated to zsh.
diff --git a/Test/W01history.ztst b/Test/W01history.ztst
index 0b2f60d1e..1d3f3cf6f 100644
--- a/Test/W01history.ztst
+++ b/Test/W01history.ztst
@@ -88,3 +88,25 @@ F:Check that a history bug introduced by workers/34160 is working again.
0:Modifier :P
>/my/path/for/testing
>/my/path/for/testing
+
+ $ZTST_testdir/../Src/zsh -fgis <<<'
+ SAVEHIST=7
+ print -rs "one\\"
+ print -rs "two\\\\"
+ print -rs "three\\\\\\"
+ print -rs "four\\\\\\\\"
+ print -rs "five\\\\\\\\\\"
+ print -s "while false\ndo\ntrue\\\\\n && break\ndone"
+ print -s "echo one\\\\\ntwo"
+ fc -W hist
+ fc -p -R hist
+ fc -l
+ rm hist' 2>/dev/null
+0:Lines ending in backslash saved and restored to history
+> 1 one\
+> 2 two\\
+> 3 three\\\
+> 4 four\\\\
+> 5 five\\\\\
+> 6 while false\ndo\ntrue\\n && break\ndone
+> 7 echo one\\ntwo
diff --git a/Test/W02jobs.ztst b/Test/W02jobs.ztst
index fe12f979d..d52888dd9 100644
--- a/Test/W02jobs.ztst
+++ b/Test/W02jobs.ztst
@@ -2,9 +2,7 @@
%prep
- if [[ $OSTYPE == cygwin ]]; then
- ZTST_unimplemented='the zsh/zpty module does not work on Cygwin'
- elif zmodload zsh/zpty 2> /dev/null; then
+ if zmodload zsh/zpty 2> /dev/null; then
zpty_start() {
export PS1= PS2=
zpty -d
@@ -146,12 +144,14 @@
zpty_start
zpty_input 'sleep 3 &'
zpty_input 'jobs -r'
+ zpty_input '(jobs -r)'
zpty_input 'print -- -'
zpty_input 'jobs -s'
zpty_stop
0:`jobs -r` and `jobs -s` with running job
*>\[1] [0-9]##
*>\[1] + running*sleep*
+*>\[1] + running*sleep*
*>-
*>zsh:*SIGHUPed*
diff --git a/Test/W03jobparameters.ztst b/Test/W03jobparameters.ztst
new file mode 100644
index 000000000..a6f7a09b1
--- /dev/null
+++ b/Test/W03jobparameters.ztst
@@ -0,0 +1,78 @@
+# Tests for interactive job control with parameter state
+
+%prep
+
+ if zmodload zsh/zpty 2> /dev/null; then
+ zpty_start() {
+ export PS1= PS2=
+ zpty -d
+ zpty zsh "${(q)ZTST_testdir}/../Src/zsh -fiV +Z"
+ }
+ zpty_input() {
+ zpty -w zsh "${(F)@}" $'\n'
+ }
+ zpty_line() {
+ local REPLY
+ integer i
+ for (( i = 0; i < ${1:-1}; ++i )); do
+ zpty -r zsh REPLY
+ print -r -- ${REPLY%%($'\r\n'|$'\n')}
+ done
+ }
+ zpty_stop() {
+ # exit twice in case of check_jobs
+ zpty -w zsh $'exit\nexit\n'
+ # zpty gives no output when piped without these braces (?)
+ { zpty -r zsh } | sed $'/[^[:space:]]/!d; s/\r$//;'
+ zpty -d
+ :
+ }
+ if ! zmodload zsh/parameter 2> /dev/null; then
+ ZTST_unimplemented='the zsh/parameter module is not available'
+ fi
+ else
+ ZTST_unimplemented='the zsh/zpty module is not available'
+ fi
+
+%test
+
+ zpty_start
+ zpty_input "MODULE_PATH=${(q)MODULE_PATH}"
+ zpty_input 'sleep 3 &'
+ zpty_input 'print $jobstates'
+ zpty_input '(print $jobstates)'
+ zpty_input 'jobs -s'
+ zpty_stop
+0:$jobstate for running job in main shell and subshell
+*>\[1] [0-9]##
+*>running:+:*=running
+*>running:+:*=running
+*>zsh:*SIGHUPed*
+
+# $jobstates refers to a job started in the main shell unless
+# one has been started in the subshell. In the latter case,
+# the subshell has no job control so the job is not marked as current.
+ zpty_start
+ zpty_input "MODULE_PATH=${(q)MODULE_PATH}"
+ zpty_input 'sleep 3 &'
+ zpty_input '(print main; print $jobstates; sleep 2& print sub; print $jobstates)'
+ zpty_input 'jobs -s'
+ zpty_stop
+0:$jobstate shows one job started in main shell or one started in subshell
+*>\[1] [0-9]##
+>main
+*>running:+:*=running
+>sub
+*>running::*=running
+*>zsh:*SIGHUPed*
+
+# output from zpty removes empty lines
+ zpty_start
+ zpty_input "MODULE_PATH=${(q)MODULE_PATH}"
+ zpty_input '(print main; print $jobstates; sleep 2& print sub; print $jobstates)'
+ zpty_input 'jobs -s'
+ zpty_stop
+0:$jobstate shows no job started in main shell but one started in subshell
+>main
+>sub
+*>running::*=running
diff --git a/Test/X02zlevi.ztst b/Test/X02zlevi.ztst
index 4e7966e12..8146d6752 100644
--- a/Test/X02zlevi.ztst
+++ b/Test/X02zlevi.ztst
@@ -11,9 +11,7 @@
break;
fi
done
- if [[ $OSTYPE = cygwin ]]; then
- ZTST_unimplemented="the zsh/zpty module does not work on Cygwin"
- elif ( zmodload zsh/zpty 2>/dev/null ); then
+ if ( zmodload zsh/zpty 2>/dev/null ); then
. $ZTST_srcdir/comptest
comptestinit -v -z $ZTST_testdir/../Src/zsh
else
diff --git a/Test/X03zlebindkey.ztst b/Test/X03zlebindkey.ztst
index e5aac7379..3e299a337 100644
--- a/Test/X03zlebindkey.ztst
+++ b/Test/X03zlebindkey.ztst
@@ -12,9 +12,7 @@
break;
fi
done
- if [[ $OSTYPE = cygwin ]]; then
- ZTST_unimplemented="the zsh/zpty module does not work on Cygwin"
- elif ( zmodload zsh/zpty 2>/dev/null ); then
+ if ( zmodload zsh/zpty 2>/dev/null ); then
. $ZTST_srcdir/comptest
comptestinit -z $ZTST_testdir/../Src/zsh
else
diff --git a/Test/X04zlehighlight.ztst b/Test/X04zlehighlight.ztst
index 475a2e309..f84c02505 100644
--- a/Test/X04zlehighlight.ztst
+++ b/Test/X04zlehighlight.ztst
@@ -5,8 +5,6 @@
export TERM=xterm-256color
if [[ ${+termcap} != 1 || ${termcap[Co]} != <-> || ${termcap[Co]} -lt 256 ]]; then
ZTST_unimplemented="no termcap module OR termcap doesn't support 256 or more colors"
- elif [[ $OSTYPE == cygwin ]]; then
- ZTST_unimplemented='the zsh/zpty module does not work on Cygwin'
elif zmodload zsh/zpty 2> /dev/null; then
zpty_start() {
export PS1= PS2=
@@ -95,6 +93,50 @@
>0m27m24mCDE|32|trueCDE|39|
zpty_start
+ zpty_input 'rh_widget() { region_highlight+=( "0 4 fg=green memo=someplugin" ); typeset -p region_highlight }'
+ zpty_input 'zle -N rh_widget'
+ zpty_input 'bindkey "\C-a" rh_widget'
+ zpty_enable_zle
+ zpty_input $'\C-a'
+ zpty_line
+ zpty_stop
+0:region_highlight memo information round trips
+>typeset -a region_highlight=( '0 4 fg=green memo=someplugin' )
+
+ zpty_start
+ zpty_input 'rh_widget() { region_highlight+=( "0 4 fg=green memo=someplugin,futureattribute=futurevalue" ); typeset -p region_highlight }'
+ zpty_input 'zle -N rh_widget'
+ zpty_input 'bindkey "\C-a" rh_widget'
+ zpty_enable_zle
+ zpty_input $'\C-a'
+ zpty_line
+ zpty_stop
+0:region_highlight memo information forward compatibility, #1
+>typeset -a region_highlight=( '0 4 fg=green memo=someplugin' )
+
+ zpty_start
+ zpty_input 'rh_widget() { region_highlight+=( "0 4 fg=green memo=someplugin futurefifthfield" ); typeset -p region_highlight }'
+ zpty_input 'zle -N rh_widget'
+ zpty_input 'bindkey "\C-a" rh_widget'
+ zpty_enable_zle
+ zpty_input $'\C-a'
+ zpty_line
+ zpty_stop
+0:region_highlight memo information forward compatibility, #2
+>typeset -a region_highlight=( '0 4 fg=green memo=someplugin' )
+
+ zpty_start
+ zpty_input 'rh_widget() { region_highlight+=( "0 4 fg=green memo=some'$'\0''plugin" ); typeset -p region_highlight }'
+ zpty_input 'zle -N rh_widget'
+ zpty_input 'bindkey "\C-a" rh_widget'
+ zpty_enable_zle
+ zpty_input $'\C-a'
+ zpty_line
+ zpty_stop
+0:region_highlight memo information forward compatibility, #3: NULs
+>typeset -a region_highlight=( '0 4 fg=green memo=some' )
+
+ zpty_start
zpty_input 'rh_widget() { BUFFER="true"; region_highlight+=( "0 4 fg=#040810" ); }'
zpty_input 'zle -N rh_widget'
zpty_input 'bindkey "\C-a" rh_widget'
@@ -154,6 +196,17 @@
0:overlapping region_highlight with near-color (hex-triplets at input)
>0m27m24mCDE|340|tCDE|3160|rCDE|39|CDE|340|ueCDE|39|
+ zpty_start
+ zpty_input 'f () { zle clear-screen; zle g -f nolast; BUFFER=": ${(q)LASTWIDGET}" }; zle -N f'
+ zpty_input 'g () { }; zle -N g'
+ zpty_input 'bindkey "\C-a" f'
+ zpty_enable_zle
+ zpty_input $'\C-a'
+ zpty_line 1 p
+ zpty_stop
+0:zle $widgetname -f nolast
+>0m27m24m0m27m24m: clear-screen
+
%clean
zmodload -ui zsh/zpty
diff --git a/Test/Y01completion.ztst b/Test/Y01completion.ztst
index 51f604bcf..6af0efc6d 100644
--- a/Test/Y01completion.ztst
+++ b/Test/Y01completion.ztst
@@ -11,9 +11,7 @@
break;
fi
done
- if [[ $OSTYPE = cygwin ]]; then
- ZTST_unimplemented="the zsh/zpty module does not work on Cygwin"
- elif ( zmodload zsh/zpty 2>/dev/null ); then
+ if ( zmodload zsh/zpty 2>/dev/null ); then
. $ZTST_srcdir/comptest
mkdir comp.tmp
cd comp.tmp
@@ -46,6 +44,35 @@
>line: {: dir1/}{}
>line: {: dir2/}{}
+ comptest $': *\t\t\t\t\t\t'
+0:_expand shows file types
+>line: {: dir1/}{}
+>DESCRIPTION:{expansions}
+>DI:{dir1}
+>DI:{dir2}
+>FI:{file1}
+>FI:{file2}
+>DESCRIPTION:{all expansions}
+>NO:{dir1 dir2 file1 file2}
+>DESCRIPTION:{original}
+>NO:{*}
+>line: {: dir2/}{}
+>line: {: file1 }{}
+>line: {: file2 }{}
+>line: {: dir1 dir2 file1 file2 }{}
+>line: {: *}{}
+
+ comptesteval $'zstyle \'*\' glob no'
+ comptesteval $'typeset -g tst=(*)'
+ comptest $': $tst\C-D'
+0:_expand preserves array form
+>DESCRIPTION:{expansions}
+>NO:{dir1}
+>NO:{dir2}
+>NO:{file1}
+>NO:{file2}
+
+ comptesteval $'zstyle -d \'*\' glob'
comptesteval '_users () { compadd user1 user2 }'
comptest $': ~\t\t\t\t\t'
0:tilde
@@ -156,6 +183,9 @@ F:regression test workers/31611
>line: {tst word:/}{}
# Test for regression introduced by workers/41242, raised in workers/43842
+ if [[ $OSTYPE = cygwin ]]; then
+ ZTST_skip="\\ is equivalent to / in pathname on cygwin"
+ else
{
mkdir sortnobslash
touch sortnobslash/{'!foo','#foo','\foo','|foo','~foo',Afoo,bfoo}
@@ -165,6 +195,7 @@ F:regression test workers/31611
comptesteval 'LC_ALL=$old_LC_ALL'
rm -rf sortnobslash
}
+ fi
0:ignore backslashes when sorting completion matches
>line: {: sortnobslash/}{}
>DESCRIPTION:{file}
@@ -216,6 +247,16 @@ F:regression test workers/31611
>NO:{3pm}
>NO:{10pm}
+ comptesteval "_tst() { _arguments ':desc:_sequence compadd - 1 2 3' }"
+ comptesteval "zstyle ':completion:*:tst:*' ignored-patterns 2"
+ comptest $'tst 1,\t'
+ comptesteval "zstyle -d ':completion:*:tst:*' ignored-patterns"
+0:-F does not break _sequence
+>line: {tst 1,}{}
+>DESCRIPTION:{desc}
+>NO:{2}
+>NO:{3}
+
comptest $'a=() b=(\t'
0:multiple envarrays
>line: {a=() b=(}{}
@@ -225,6 +266,74 @@ F:regression test workers/31611
>FI:{file1}
>FI:{file2}
+ comptesteval "typeset -a bar=({$'\\0'..$'\\C-?'})"
+ comptesteval 'typeset -A bat=( "$bar[@]" )'
+ comptesteval 'typeset bay="$bar"'
+ comptesteval 'zstyle ":completion:*:parameters" extra-verbose yes'
+ comptesteval 'zstyle ":completion:*" fake-parameters bar bat bay'
+ comptest $': $ba\t'
+0:extra-verbose shows parameter values
+>line: {: $ba}{}
+>DESCRIPTION:{parameter}
+>NO:{bar -- ( '^@' '^A' '^B' '^C' '^D' '^E' '^F' '^G' '^H' '\t' '\n' '^K' '^L' '}
+>NO:{bat -- ( [' ']='!' ['"']='#' ['$']=% ['&']=\' ['(']=')' ['*']=+ [,]=- [.]=/}
+>NO:{bay -- '^@ ^A ^B ^C ^D ^E ^F ^G ^H \t \n ^K ^L ^M ^N ^O ^P ^Q ^R ^S ^T ^U ^}
+
+ comptesteval "path=( $ZTST_srcdir:A )"
+ comptesteval 'typeset -H paths=HIDDEN'
+ comptest $': $path\t'
+0:extra-verbose doesn't show special or hidden parameter values
+>line: {: $path}{}
+>DESCRIPTION:{parameter}
+>NO:{path}
+>NO:{paths}
+
+ comptesteval 'zstyle -d ":completion:*:parameters" extra-verbose'
+ comptest $': $ba\t'
+0:parameter values not shown without extra-verbose
+>line: {: $ba}{}
+>DESCRIPTION:{parameter}
+>NO:{bar}
+>NO:{bat}
+>NO:{bay}
+
+ comptesteval '_tst() { local disp=( {a..z} ); compadd -ld disp $disp[@]; comppostfuncs=( _pst ) }'
+ comptesteval '_pst() { local disp=( "<INSERT>$compstate[insert]</INSERT>" ); compadd -Qld disp $disp }'
+ comptesteval "zstyle ':completion:*' menu select=long-list"
+ # This test is sensitive to sorting differences across platforms
+ comptesteval 'export LC_ALL=C'
+ comptest $'tst \C-d'
+ comptesteval "export LC_ALL=${(q)ZSH_TEST_LANG}"
+0: menu select=long-list starts menu selection for list widgets
+>NO:{<INSERT>menu</INSERT>}
+>NO:{a}
+>NO:{b}
+>NO:{c}
+>NO:{d}
+>NO:{e}
+>NO:{f}
+>NO:{g}
+>NO:{h}
+>NO:{i}
+>NO:{j}
+>NO:{k}
+>NO:{l}
+>NO:{m}
+>NO:{n}
+>NO:{o}
+>NO:{p}
+>NO:{q}
+>NO:{r}
+>NO:{s}
+>NO:{t}
+>NO:{u}
+>NO:{v}
+>NO:{w}
+>NO:{x}
+>NO:{y}
+>NO:{z}
+
+
%clean
zmodload -ui zsh/zpty
diff --git a/Test/Y02compmatch.ztst b/Test/Y02compmatch.ztst
index e2f8e1a61..f28913867 100644
--- a/Test/Y02compmatch.ztst
+++ b/Test/Y02compmatch.ztst
@@ -11,9 +11,7 @@
# contains the compadd output.
%prep
- if [[ $OSTYPE = cygwin ]]; then
- ZTST_unimplemented="the zsh/zpty module does not work on Cygwin"
- elif ( zmodload zsh/zpty 2>/dev/null ); then
+ if ( zmodload zsh/zpty 2>/dev/null ); then
. $ZTST_srcdir/comptest
mkdir match.tmp
cd match.tmp
@@ -380,15 +378,26 @@
comp.graphics.rendering.misc comp.graphics.rendering.raytracing
comp.graphics.rendering.renderman)
test_code $example4_matcher example4_list
- comptest $'tst c.s.u\t'
-0:Documentation example using input c.s.u
+ comptest $'tst .s.u\t'
+0:r:|.=* should complete .s.u
+>line: {tst comp.sources.unix }{}
+>COMPADD:{}
+>INSERT_POSITIONS:{21}
+
+ example4b_matcher='r:[^.]||.=* r:|=*'
+ test_code $example4b_matcher example4_list
+ comptest $'tst .s.u\t^[bc\t'
+0f:r:[^.]||.=* should not complete .s.u, but should complete c.s.u
+>line: {tst .s.u}{}
+>COMPADD:{}
+>INSERT_POSITIONS:{}
>line: {tst comp.sources.unix }{}
>COMPADD:{}
>INSERT_POSITIONS:{21}
test_code $example4_matcher example4_list
- comptest $'tst c.g.\ta\t.\tp\ta\tg\t'
-0:Documentation example using input c.g.\ta\t.\tp\ta\tg\t
+ comptest $'tst .g.\ta\t.\tp\ta\tg\t'
+0:r:|.=* should complete .g.
>line: {tst comp.graphics.}{}
>COMPADD:{}
>INSERT_POSITIONS:{18}
@@ -426,9 +435,32 @@
>COMPADD:{}
>INSERT_POSITIONS:{32}
+ test_code $example4b_matcher example4_list
+ comptest $'tst .g.\t^[bc\t'
+0f:r:[^.]||.=* should not complete .g., but should complete c.g.
+>line: {tst .g.}{}
+>COMPADD:{}
+>INSERT_POSITIONS:{}
+>line: {tst comp.graphics.}{}
+>COMPADD:{}
+>INSERT_POSITIONS:{18}
+
test_code $example4_matcher example4_list
- comptest $'tst c...pag\t'
-0:Documentation example using input c...pag\t
+ comptest $'tst ...pag\t'
+0:r:|.=* should complete ...pag
+>line: {tst comp.graphics.apps.pagemaker }{}
+>COMPADD:{}
+>INSERT_POSITIONS:{32}
+
+ test_code $example4b_matcher example4_list
+ comptest $'tst ...pag\t^[bc\t^Fg^F^Fa\t'
+0f:r:[^.]||.=* should not complete ...pag or c...pag, but should complete c.g.a.p
+>line: {tst ...pag}{}
+>COMPADD:{}
+>INSERT_POSITIONS:{}
+>line: {tst c...pag}{}
+>COMPADD:{}
+>INSERT_POSITIONS:{}
>line: {tst comp.graphics.apps.pagemaker }{}
>COMPADD:{}
>INSERT_POSITIONS:{32}
@@ -446,8 +478,8 @@
example5_matcher='r:|[.,_-]=* r:|=*'
example5_list=(veryverylongfile.c veryverylongheader.h)
test_code $example5_matcher example5_list
- comptest $'tst v.c\tv.h\t'
-0:Documentation example using input v.c\t
+ comptest $'tst .c\t.h\t'
+0:r:|[.,_-]=* should complete .c and .h
>line: {tst veryverylongfile.c }{}
>COMPADD:{}
>INSERT_POSITIONS:{23}
@@ -455,6 +487,23 @@
>COMPADD:{}
>INSERT_POSITIONS:{44}
+ example5b_matcher='r:[^.,_-]||[.,_-]=* r:|=*'
+ test_code $example5b_matcher example5_list
+ comptest $'tst .c\t^[bv\t.h\t^[bv\t'
+0f:r:[^.,_-]||[.,_-]=* should not complete .c or .h, but should complete v.c and v.h
+>line: {tst .c}{}
+>COMPADD:{}
+>INSERT_POSITIONS:{}
+>line: {tst veryverylongfile.c }{}
+>COMPADD:{}
+>INSERT_POSITIONS:{23}
+>line: {tst veryverylongfile.c .h}{}
+>COMPADD:{}
+>INSERT_POSITIONS:{}
+>line: {tst veryverylongfile.c veryverylongheader.h }{}
+>COMPADD:{}
+>INSERT_POSITIONS:{44}
+
example6_list=(LikeTHIS FooHoo 5foo123 5bar234)
test_code 'r:|[A-Z0-9]=* r:|=*' example6_list
@@ -495,16 +544,57 @@
example7_matcher="r:[^A-Z0-9]||[A-Z0-9]=** r:|=*"
example7_list=($example6_list)
test_code $example7_matcher example7_list
- comptest $'tst H\t2\t'
-0:Documentation example using "r:[^A-Z0-9]||[A-Z0-9]=** r:|=*"
+ comptest $'tst H\t^BF\to\t2\t^B5\tb\t'
+0f:r:[^A-Z0-9]||[A-Z0-9]=** should not complete H, FH, 2 or 52, but should complete FoH and 5b2.
+>line: {tst H}{}
+>COMPADD:{}
+>INSERT_POSITIONS:{}
+>line: {tst F}{H}
+>COMPADD:{}
+>INSERT_POSITIONS:{}
>line: {tst FooHoo }{}
>COMPADD:{}
>INSERT_POSITIONS:{10}
+>line: {tst FooHoo 2}{}
+>COMPADD:{}
+>INSERT_POSITIONS:{}
+>line: {tst FooHoo 5}{2}
+>COMPADD:{}
+>INSERT_POSITIONS:{}
+>line: {tst FooHoo 5bar234 }{}
+>COMPADD:{}
+>INSERT_POSITIONS:{18}
+
+ example7b_matcher="r:?||[A-Z0-9]=* r:|=*"
+ test_code $example7b_matcher example7_list
+ comptest $'tst H\t^BF2\t^B5\t'
+0f:r:?||[A-Z0-9]=* r:|=* should not complete H or 2, but should complete FH and 52.
+>line: {tst H}{}
+>COMPADD:{}
+>INSERT_POSITIONS:{}
+>line: {tst FooHoo }{}
+>COMPADD:{}
+>INSERT_POSITIONS:{10}
+>line: {tst FooHoo 2}{}
+>COMPADD:{}
+>INSERT_POSITIONS:{}
>line: {tst FooHoo 5bar234 }{}
>COMPADD:{}
>INSERT_POSITIONS:{18}
+ example8_list=(passwd.byname)
+ test_code 'r:[^.]||.=* l:.||[^.]=*'
+ comptest $'tst .^B\tpass^Fname\t'
+0f:r:[^.]||.=* and l:.||[^.]=* should work symmetrically.
+>line: {tst }{.}
+>COMPADD:{}
+>INSERT_POSITIONS:{}
+>line: {tst passwd.byname }{}
+>COMPADD:{}
+>INSERT_POSITIONS:{17}
+
+
workers_7311_matcher="m:{a-z}={A-Z} r:|[.,_-]=* r:|=*"
workers_7311_list=(Abc-Def-Ghij.txt Abc-def.ghi.jkl_mno.pqr.txt Abc_def_ghi_jkl_mno_pqr.txt)
test_code $workers_7311_matcher workers_7311_list
@@ -539,11 +629,11 @@
>COMPADD:{}
>INSERT_POSITIONS:{5}
- workers_11081_matcher='m:{a-zA-Z}={A-Za-z} r:|[.,_-]=* r:[^A-Z0-9]||[A-Z0-9]=* r:[A-Z0-9]||[^A-Z0-9]=* r:[^0-9]||[0-9]=* r:|=*'
+ workers_11081_matcher='m:{a-zA-Z}={A-Za-z} r:|[.,_-]=* r:|=*'
workers_11081_list=(build.out build.out1 build.out2)
test_code $workers_11081_matcher workers_11081_list
comptest $'tst bui\t\t\t'
-0:Bug from workers 11081
+0:Erratic completion bug from workers 11081: bui > build.out[] > build[.]out > build.out[] > build.out1[] > build.out2[]
>line: {tst build.out}{}
>COMPADD:{}
>INSERT_POSITIONS:{13}
@@ -580,7 +670,7 @@
workers_11586_list=(c00.abc c01.abc.def.00.0)
test_code $workers_11586_matcher workers_11586_list
comptest $'tst c00\t.\ta\t'
-0:Bug from workers 11586
+0:Disappearing characters bug from workers 11586: c00\t -> c0[], c00\t -> c0.abc[], c00.\t -> c0.abc[]
>line: {tst c00}{}
>COMPADD:{}
>INSERT_POSITIONS:{6}
@@ -613,12 +703,12 @@
>COMPADD:{}
>INSERT_POSITIONS:{22}
- workers_13320_matcher='r:|[.,_-]=** r:[^0-9]||[0-9]=**'
+ workers_13320_matcher='r:|[.,_-]=**'
workers_13320_list=(glibc-2.1.94-3.i386.rpm glibc-devel-2.1.94-3.i386.rpm)
workers_13320_list=($workers_13320_list glibc-profile-2.1.94-3.i386.rpm)
test_code $workers_13320_matcher workers_13320_list
comptest $'tst glibc-2.1\t'
-0:Test from workers 13320
+0:Incorrect cursor position bug from workers 13320: glibc-2.1\t -> glibc-2[.]1.94-3.i386.rpm
>line: {tst glibc}{-2.1.94-3.i386.rpm}
>COMPADD:{}
>INSERT_POSITIONS:{9:27}
@@ -643,11 +733,11 @@
>NO:{A.C}
- workers_13345b_matcher='r:|[.,_-]=** r:[^0-9]||[0-9]=**'
+ workers_13345b_matcher='r:|[.,_-]=** r:|[0-9]=**'
workers_13345b_list=(a-b_1_2_2 a-b_2_0.gz a-b_2_0.zip)
test_code $workers_13345b_matcher workers_13345b_list
comptest $'tst a-b_2\t'
-0:Second test from workers 13345
+0:Disappearing character bug from workers 13345: a-b_2\t -> a-b__
>line: {tst a-b_2_}{}
>COMPADD:{}
>INSERT_POSITIONS:{8:10}
diff --git a/Test/Y03arguments.ztst b/Test/Y03arguments.ztst
index fa4589374..200c83e8c 100644
--- a/Test/Y03arguments.ztst
+++ b/Test/Y03arguments.ztst
@@ -1,9 +1,7 @@
# Tests for _arguments.
%prep
- if [[ $OSTYPE = cygwin ]]; then
- ZTST_unimplemented="the zsh/zpty module does not work on Cygwin"
- elif ( zmodload zsh/zpty 2>/dev/null ); then
+ if ( zmodload zsh/zpty 2>/dev/null ); then
. $ZTST_srcdir/comptest
mkdir comp.tmp
cd comp.tmp
@@ -104,6 +102,28 @@
>NO:{+o}
>NO:{-o}
+ tst_arguments -s -{a,b,c} \!-{d,e,f} \!+{d,e,f}
+ comptest $'tst -ad\t\024\t\bef\t'
+0:mix of + and - and exclusion of stacked options
+>line: {tst -ad}{}
+>DESCRIPTION:{option}
+>NO:{-b}
+>NO:{-c}
+>line: {tst -da}{}
+>DESCRIPTION:{option}
+>NO:{-b}
+>NO:{-c}
+>line: {tst -def}{}
+>DESCRIPTION:{option}
+>NO:{-a}
+>NO:{-b}
+>NO:{-c}
+
+ tst_arguments -s -{a,b,c} +{a,b,c}
+ comptest $'tst -a +b +c\t'
+0:mix of + and - and exclusion of stacked options
+>line: {tst -a +b +ca}{}
+
tst_arguments '-o:1:(a):2:(b)'
comptest $'tst \t\t\t'
0:two option arguments
@@ -231,9 +251,15 @@
tst_arguments '-a:one: :two' ':descr:{compadd -Q - $opt_args[-a]}'
comptest $'tst -a 1:x \\2 \t'
-0:opt_args with multiple arguments and quoting of colons and backslashes
+0:opt_args with multiple arguments and quoting of colons and backslashes, part #1: default behaviour
>line: {tst -a 1:x \2 1\:x:\\2 }{}
+ # Same as previous test, except with -0 and (qqqq) added
+ tst_arguments -0 : '-a:one: :two' ':descr:{compadd -Q - ${(qqqq)opt_args[-a]}}'
+ comptest $'tst -a 1:x \\2 \t'
+0:opt_args with multiple arguments and quoting of colons and backslashes, part #2: NUL escaping
+>line: {tst -a 1:x \2 $'1:x\0\\2' }{}
+
tst_arguments -a -b
comptest $'tst rest -\t\C-w\eb\C-b-\t'
0:option completion with rest arguments on the line but not in the specs
@@ -355,6 +381,12 @@
0:allowed option before --
>line: {tst -x }{ --}
+ tst_arguments -S '1:one' '2:two'
+ comptest $'tst -- -- \t'
+0:only first of duplicate -- is ignored
+>line: {tst -- -- }{}
+>DESCRIPTION:{two}
+
tst_arguments -x :word
comptest $'tst word -\t'
0:option after a word
@@ -386,6 +418,25 @@
0:continue completion after rest argument that looks like an option
>line: {tst -a -x more }{}
+ tst_arguments -A '-*' -a -b '*: :(words)'
+ comptest $'tst -x -\t'
+0:word matching -A pattern doesn't exclude options
+>line: {tst -x -}{}
+>DESCRIPTION:{option}
+>NO:{-a}
+>NO:{-b}
+
+ tst_arguments -A '-*' -a -b '1:word:(word)'
+ comptest $'tst -x \t'
+0:unrecognised word matching -A pattern not treated as a rest argument
+>line: {tst -x word }{}
+
+ tst_arguments -A "-*" '(3)-a' '1:one' '2:two' '3:three' '4:four' '*:extra'
+ comptest $'tst x -a \t'
+0:exclusion from option following word matching -A pattern should not apply
+>line: {tst x -a }{}
+>DESCRIPTION:{three}
+
tst_arguments '*-v'
comptest $'tst -v -\t'
0:repeatable options
@@ -474,6 +525,16 @@
>NO:{-b}
>NO:{-v}
+ tst_arguments -a -b -c '(-a)1:one' '(-b)2:two' '(-c)*:extra'
+ comptest $'tst x y z\e6\C-b-\t'
+0:exclude option from normal argument to the right of the cursor
+>line: {tst -}{ x y z}
+>DESCRIPTION:{one}
+>DESCRIPTION:{option}
+>NO:{-a}
+>NO:{-b}
+>NO:{-c}
+
tst_arguments -a - set1 -d - set2 '(set2)-m' -n -o ':arg:(x)' - set2 -x
comptest $'tst -m \t'
0:exclude own set from an option
diff --git a/Test/Z01is-at-least.ztst b/Test/Z01is-at-least.ztst
new file mode 100644
index 000000000..039b3e737
--- /dev/null
+++ b/Test/Z01is-at-least.ztst
@@ -0,0 +1,27 @@
+%prep
+ autoload -Uz is-at-least
+
+%test
+
+ versions=(
+ 1 1.1 1.1.1 1.2 1.2.1
+ 2 2.1 2.1.1 2.2 2.2.1
+ 3 3.1 3.1.1 3.2 3.2.1
+ )
+ for (( i = 1; i <= $#versions; ++i)); do
+ for (( j = i+1; j <= $#versions; ++j)); do
+ is-at-least $versions[i] $versions[j] || echo "$versions[i] ≰ $versions[j]"
+ { ! is-at-least $versions[j] $versions[i] } || echo "$versions[j] ≤ $versions[i]"
+ done
+ done
+0:is-at-least smoke test
+
+ is-at-least 5.8.0.2 5.8
+1f:regression test: Two trailing zeroes are filled in
+# TODO: When fixing this, extend the smoke test to cover this.
+
+ is-at-least 5.8.0.2 5.8.0.0
+1:regression test: Two trailing zeroes are filled in
+# TODO: Extend the smoke test to cover this.
+
+%clean
diff --git a/Test/Z02zmathfunc.ztst b/Test/Z02zmathfunc.ztst
new file mode 100644
index 000000000..2be770a13
--- /dev/null
+++ b/Test/Z02zmathfunc.ztst
@@ -0,0 +1,58 @@
+%prep
+ autoload -Uz zmathfunc && zmathfunc
+
+%test
+
+ echo $(( min(42, 43) )) $(( max(42, 43) )) $(( sum(42, 43) ))
+ echo $(( min(42) )) $(( max(42) )) $(( sum(42) ))
+ echo $(( sum() ))
+0:basic functionality test
+>42 43 85
+>42 42 42
+>0
+
+
+ (set -e; echo $(( min(0, 42) )))
+ (set -e; echo $(( max(0, -42) )))
+ (set -e; echo $(( sum(42, -42) )))
+0:regression test for ERR_EXIT
+>0
+>0
+>0
+
+ echo $(( min(42, 43, 44) ))
+ echo $(( min(44, 42, 43) ))
+ echo $(( min(43, 44, 42) ))
+ #
+ echo $(( max(42, 43, 44) ))
+ echo $(( max(44, 42, 43) ))
+ echo $(( max(43, 44, 42) ))
+0:min() and max() with three arguments
+>42
+>42
+>42
+>44
+>44
+>44
+
+ echo $(( min() ))
+1:error test for min()
+?(eval):1: wrong number of arguments: min()
+
+ echo $(( max() ))
+1:error test for max()
+?(eval):1: wrong number of arguments: max()
+
+ zsh_math_func_min "foo bar" x y z
+2d:check errors from an unsupported use-case (workers/48156)
+# We expect one non-empty line of stderr, but don't care about the specific
+# error message; thus, the expectation is a pattern (*), for stderr (?), which
+# matches any non-empty string (?*).
+#
+# Sorry, Perl, but I had to give you a run for your money.
+*??*
+F:Calling zsh_math_func_min directly isn't a supported use-case, but if it
+F:returns zero, something's probably wrong.
+
+
+%clean
diff --git a/Test/Z03run-help.ztst b/Test/Z03run-help.ztst
new file mode 100644
index 000000000..ca8ba4d04
--- /dev/null
+++ b/Test/Z03run-help.ztst
@@ -0,0 +1,106 @@
+%prep
+ PAGER=cat
+ unalias run-help
+ autoload +X -Uz ${^fpath}/run-help*(N)
+ builtin() {
+ case "$1 $2" in
+ ( 'getln cmd_args' )
+ cmd_args="$BUFFER_STACK"
+ ;;
+ ( 'print -z' )
+ ;;
+ ( 'whence -va' )
+ print -l "$3 is WHENCE:{$3}"
+ ;;
+ ( * )
+ eval $@
+ ;;
+ esac
+ }
+ man() {
+ [[ $1 == -w && -n $NO_SUBCMD_MANUALS ]] &&
+ return 1
+ print "MAN:{${(qq)@}}"
+ }
+ git svn () {
+ print "${(U)0}:{${(qq)@}}"
+ }
+
+
+%test
+
+ BUFFER_STACK='btrfs --help'
+ run-help btrfs
+0:btrfs with option flag, no subcmd
+>btrfs is WHENCE:{btrfs}
+>MAN:{'btrfs'}
+
+ BUFFER_STACK='btrfs subvolume snapshot –r /btrfs/SV1 /btrfs/SV1-rosnap'
+ run-help btrfs
+0:btrfs with subcmd
+>btrfs is WHENCE:{btrfs}
+>MAN:{'btrfs-subvolume'}
+
+ BUFFER_STACK="sudo $BUFFER_STACK"
+ run-help btrfs
+0:sudo btrfs with subcmd
+>btrfs is WHENCE:{btrfs}
+>MAN:{'btrfs-subvolume'}
+
+ BUFFER_STACK='ip addr add 192.168.50.5 dev eth1'
+ run-help ip
+0:ip with subcmd
+>ip is WHENCE:{ip}
+>MAN:{'ip-address'}
+
+ NO_SUBCMD_MANUALS=1
+ run-help ip
+ unset NO_SUBCMD_MANUALS
+0:ip with subcmd, but no subcmd manuals
+>ip is WHENCE:{ip}
+>MAN:{'ip'}
+
+ BUFFER_STACK='ip -s -s link ls up'
+ run-help ip
+0:ip with options and subcmd
+>ip is WHENCE:{ip}
+>MAN:{'ip-link'}
+
+ BUFFER_STACK="sudo $BUFFER_STACK"
+ run-help ip
+0:sudo ip with options and subcmd
+>ip is WHENCE:{ip}
+>MAN:{'ip-link'}
+
+ BUFFER_STACK='svn -vq'
+ run-help svn
+0:svn with options
+>svn is WHENCE:{svn}
+>SVN:{'help'}
+
+ BUFFER_STACK+=' commit -m "log messages"'
+ run-help svn
+0:svn with options and subcmd
+>svn is WHENCE:{svn}
+>SVN:{'help' 'commit'}
+
+ BUFFER_STACK='git --exec-path'
+ run-help git
+0:git with option
+>git is WHENCE:{git}
+>GIT:{'help' 'git'}
+
+ BUFFER_STACK='git -C $PWD/.. difftool --no-prompt --tool opendiff --dir-diff'
+ run-help git
+0:git with option, file & subcmd
+>git is WHENCE:{git}
+>GIT:{'help' 'difftool'}
+
+ BUFFER_STACK='git -c http.proxy=someproxy clone https://github.com/user/repo.git'
+ run-help git
+0:git with option, assignment & subcmd
+>git is WHENCE:{git}
+>GIT:{'help' 'clone'}
+
+
+%clean
diff --git a/Test/comptest b/Test/comptest
index 166d0b404..79c69979a 100644
--- a/Test/comptest
+++ b/Test/comptest
@@ -40,6 +40,7 @@ KEYTIMEOUT=1
setopt zle
autoload -U compinit
compinit -u
+zstyle ":completion:*" completer _expand _complete _ignored
zstyle ":completion:*:default" list-colors "no=<NO>" "fi=<FI>" "di=<DI>" "ln=<LN>" "pi=<PI>" "so=<SO>" "bd=<BD>" "cd=<CD>" "ex=<EX>" "mi=<MI>" "tc=<TC>" "sp=<SP>" "lc=<LC>" "ec=<EC>\n" "rc=<RC>"
zstyle ":completion:*" group-name ""
zstyle ":completion:*:messages" format "<MESSAGE>%d</MESSAGE>
@@ -50,9 +51,9 @@ zstyle ":completion:*:options" verbose yes
zstyle ":completion:*:values" verbose yes
setopt noalwayslastprompt listrowsfirst completeinword
zmodload zsh/complist
-expand-or-complete-with-report () {
- print -lr "<WIDGET><expand-or-complete>"
- zle expand-or-complete
+complete-word-with-report () {
+ print -lr "<WIDGET><complete-word>"
+ zle complete-word
print -lr - "<LBUFFER>$LBUFFER</LBUFFER>" "<RBUFFER>$RBUFFER</RBUFFER>"
zle clear-screen
zle -R
@@ -80,11 +81,11 @@ zle-finish () {
(( $+mark )) && print -lr "MARK: $mark"
zle accept-line
}
-zle -N expand-or-complete-with-report
+zle -N complete-word-with-report
zle -N list-choices-with-report
zle -N comp-finish
zle -N zle-finish
-bindkey "^I" expand-or-complete-with-report
+bindkey "^I" complete-word-with-report
bindkey "^D" list-choices-with-report
bindkey "^Z" comp-finish
bindkey "^X" zle-finish
@@ -112,17 +113,26 @@ zpty_run() {
}
comptesteval () {
- local tmp=/tmp/comptest.$$
+ {
+ # Avoid symlink attacks on the predictable filename
+ # TODO: either use =(:) or create this file in the tests' workdir
+ local tmp=/tmp/comptest.$$
+ () {
+ setopt localoptions NO_CLOBBER ERR_EXIT
+ print -lr - "$@" > $tmp
+ } "$@"
- print -lr - "$@" > $tmp
- # zpty_flush Before comptesteval
- zpty -w zsh ". $tmp"
- zpty -r -m zsh log_eval "*<PROMPT>*" || {
- print "prompt hasn't appeared."
- return 1
- }
- zpty_flush After comptesteval
- rm $tmp
+ # zpty_flush Before comptesteval
+ zpty -w zsh ". ${(q)tmp}"
+ zpty -r -m zsh log_eval "*<PROMPT>*" || {
+ print "prompt hasn't appeared."
+ return 1
+ }
+ zpty_flush After comptesteval
+ : Suppress error from zpty_flush
+ } always {
+ rm $tmp
+ }
}
comptest () {
diff --git a/Test/runtests.zsh b/Test/runtests.zsh
index 562234d91..b66d579b6 100644
--- a/Test/runtests.zsh
+++ b/Test/runtests.zsh
@@ -7,7 +7,7 @@ emulate zsh
# protect from catastrophic failure of an individual test.
# We could probably do that with subshells instead.
-integer success failure skipped retval
+integer success=0 failure=0 skipped=0 retval
for file in "${(f)ZTST_testlist}"; do
$ZTST_exe +Z -f $ZTST_srcdir/ztst.zsh $file
retval=$?
diff --git a/Test/ztst.zsh b/Test/ztst.zsh
index 375efd16c..89fe69b5b 100755
--- a/Test/ztst.zsh
+++ b/Test/ztst.zsh
@@ -25,6 +25,7 @@ emulate -R zsh
# Ensure the locale does not screw up sorting. Don't supply a locale
# unless there's one set, to minimise problems.
[[ -n $LC_ALL ]] && LC_ALL=C
+[[ -n $LC_CTYPE ]] && LC_CTYPE=C
[[ -n $LC_COLLATE ]] && LC_COLLATE=C
[[ -n $LC_NUMERIC ]] && LC_NUMERIC=C
[[ -n $LC_MESSAGES ]] && LC_MESSAGES=C
@@ -36,8 +37,6 @@ typeset +x WORDCHARS
# Set the module load path to correspond to this build of zsh.
# This Modules directory should have been created by "make check".
[[ -d Modules/zsh ]] && module_path=( $PWD/Modules )
-# Allow this to be passed down.
-export MODULE_PATH
# We need to be able to save and restore the options used in the test.
# We use the $options variable of the parameter module for this.
@@ -60,7 +59,7 @@ ZTST_mainopts=(${(kv)options})
ZTST_testdir=$PWD
ZTST_testname=$1
-integer ZTST_testfailed
+integer ZTST_testfailed=0
# This is POSIX nonsense. Because of the vague feeling someone, somewhere
# may one day need to examine the arguments of "tail" using a standard
@@ -146,6 +145,19 @@ $ZTST_failmsg"
ZTST_testfailed=1
return 1
}
+ZTST_testxpassed() {
+ print -r "Test $ZTST_testname was expected to fail, but passed."
+ if [[ -n $ZTST_message ]]; then
+ print -r "Was testing: $ZTST_message"
+ fi
+ print -r "$ZTST_testname: test XPassed."
+ if [[ -n $ZTST_failmsg ]]; then
+ print -r "The following may (or may not) help identifying the cause:
+$ZTST_failmsg"
+ fi
+ ZTST_testfailed=1
+ return 1
+}
# Print messages if $ZTST_verbose is non-empty
ZTST_verbose() {
@@ -520,7 +532,7 @@ $ZTST_code"
return 1
fi
if (( expected_to_fail )); then
- ZTST_testfailed "test was expected to fail, but passed."
+ ZTST_testxpassed
return 1
fi
fi