summaryrefslogtreecommitdiff
path: root/dotfiles/system/.zsh/modules/Test
diff options
context:
space:
mode:
Diffstat (limited to 'dotfiles/system/.zsh/modules/Test')
-rw-r--r--dotfiles/system/.zsh/modules/Test/.cvsignore3
-rw-r--r--dotfiles/system/.zsh/modules/Test/.distfiles2
-rw-r--r--dotfiles/system/.zsh/modules/Test/A01grammar.ztst790
-rw-r--r--dotfiles/system/.zsh/modules/Test/A02alias.ztst139
-rw-r--r--dotfiles/system/.zsh/modules/Test/A03quoting.ztst80
-rw-r--r--dotfiles/system/.zsh/modules/Test/A04redirect.ztst588
-rw-r--r--dotfiles/system/.zsh/modules/Test/A05execution.ztst312
-rw-r--r--dotfiles/system/.zsh/modules/Test/A06assign.ztst631
-rw-r--r--dotfiles/system/.zsh/modules/Test/A07control.ztst165
-rw-r--r--dotfiles/system/.zsh/modules/Test/B01cd.ztst144
-rw-r--r--dotfiles/system/.zsh/modules/Test/B02typeset.ztst723
-rw-r--r--dotfiles/system/.zsh/modules/Test/B03print.ztst336
-rw-r--r--dotfiles/system/.zsh/modules/Test/B04read.ztst112
-rw-r--r--dotfiles/system/.zsh/modules/Test/B05eval.ztst34
-rw-r--r--dotfiles/system/.zsh/modules/Test/B06fc.ztst25
-rw-r--r--dotfiles/system/.zsh/modules/Test/B07emulate.ztst253
-rw-r--r--dotfiles/system/.zsh/modules/Test/B08shift.ztst33
-rw-r--r--dotfiles/system/.zsh/modules/Test/B09hash.ztst79
-rw-r--r--dotfiles/system/.zsh/modules/Test/C01arith.ztst422
-rw-r--r--dotfiles/system/.zsh/modules/Test/C02cond.ztst448
-rw-r--r--dotfiles/system/.zsh/modules/Test/C03traps.ztst761
-rw-r--r--dotfiles/system/.zsh/modules/Test/C04funcdef.ztst502
-rw-r--r--dotfiles/system/.zsh/modules/Test/C05debug.ztst159
-rw-r--r--dotfiles/system/.zsh/modules/Test/D01prompt.ztst203
-rw-r--r--dotfiles/system/.zsh/modules/Test/D02glob.ztst688
-rw-r--r--dotfiles/system/.zsh/modules/Test/D03procsubst.ztst151
-rw-r--r--dotfiles/system/.zsh/modules/Test/D04parameter.ztst2058
-rw-r--r--dotfiles/system/.zsh/modules/Test/D05array.ztst112
-rw-r--r--dotfiles/system/.zsh/modules/Test/D06subscript.ztst268
-rw-r--r--dotfiles/system/.zsh/modules/Test/D07multibyte.ztst587
-rw-r--r--dotfiles/system/.zsh/modules/Test/D08cmdsubst.ztst169
-rw-r--r--dotfiles/system/.zsh/modules/Test/D09brace.ztst114
-rw-r--r--dotfiles/system/.zsh/modules/Test/E01options.ztst1313
-rw-r--r--dotfiles/system/.zsh/modules/Test/E02xtrace.ztst148
-rw-r--r--dotfiles/system/.zsh/modules/Test/Makefile.in75
-rw-r--r--dotfiles/system/.zsh/modules/Test/README30
-rw-r--r--dotfiles/system/.zsh/modules/Test/V02zregexparse.ztst382
-rw-r--r--dotfiles/system/.zsh/modules/Test/V03mathfunc.ztst141
-rw-r--r--dotfiles/system/.zsh/modules/Test/V04features.ztst172
-rw-r--r--dotfiles/system/.zsh/modules/Test/V05styles.ztst143
-rw-r--r--dotfiles/system/.zsh/modules/Test/V07pcre.ztst139
-rw-r--r--dotfiles/system/.zsh/modules/Test/V08zpty.ztst29
-rw-r--r--dotfiles/system/.zsh/modules/Test/V09datetime.ztst74
-rw-r--r--dotfiles/system/.zsh/modules/Test/V10private.ztst304
-rw-r--r--dotfiles/system/.zsh/modules/Test/W01history.ztst60
-rw-r--r--dotfiles/system/.zsh/modules/Test/comptest177
-rw-r--r--dotfiles/system/.zsh/modules/Test/runtests.zsh27
-rwxr-xr-xdotfiles/system/.zsh/modules/Test/ztst.zsh547
48 files changed, 14852 insertions, 0 deletions
diff --git a/dotfiles/system/.zsh/modules/Test/.cvsignore b/dotfiles/system/.zsh/modules/Test/.cvsignore
new file mode 100644
index 0000000..855d729
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/.cvsignore
@@ -0,0 +1,3 @@
+Makefile
+*.tmp
+*.swp
diff --git a/dotfiles/system/.zsh/modules/Test/.distfiles b/dotfiles/system/.zsh/modules/Test/.distfiles
new file mode 100644
index 0000000..f03668b
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/.distfiles
@@ -0,0 +1,2 @@
+DISTFILES_SRC='
+'
diff --git a/dotfiles/system/.zsh/modules/Test/A01grammar.ztst b/dotfiles/system/.zsh/modules/Test/A01grammar.ztst
new file mode 100644
index 0000000..e4b6870
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/A01grammar.ztst
@@ -0,0 +1,790 @@
+#
+# This file contains tests corresponding to the `Shell Grammar' texinfo node.
+#
+
+%prep
+
+ mkdir basic.tmp && cd basic.tmp
+
+ touch foo bar
+ echo "'" >unmatched_quote.txt
+
+%test
+#
+# Tests for `Simple Commands and Pipelines'
+#
+
+ # Test skipping early to ensure we run the remainder...
+ if [[ -n $ZTST_test_skip ]]; then
+ ZTST_skip="Test system verification for skipping"
+ else
+ print "This is standard output"
+ print "This is standard error" >&2
+ false
+ fi
+1:Test skipping if ZTST_test_skip is set
+>This is standard output
+?This is standard error
+
+ 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)
+
+ false
+ $nonexistent_variable
+0:Executing command that evaluates to empty resets status
+
+ false
+ sleep 1 &
+ print $?
+ # a tidy test is a happy test
+ wait $!
+0:Starting background command resets status
+>0
+
+ false
+ . /dev/null
+0:Sourcing empty file resets status
+
+ 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
+
+ { cd /NonExistentDirectory >&/dev/null } || print false
+0:Basic current shell list with error
+>false
+
+#
+# Tests for `Precommand Modifiers'
+#
+ - $ZTST_testdir/../Src/zsh -fc "[[ \$0 = \"-$ZTST_testdir/../Src/zsh\" ]]"
+0:`-' precommand modifier
+
+ echo f*
+ noglob echo f*
+0:`noglob' precommand modifier
+>foo
+>f*
+
+ (exec /bin/sh; echo bar)
+0:`exec' precommand modifier
+
+ (exec -l $ZTST_testdir/../Src/zsh -fc 'echo $0' | sed 's%/.*/%%' )
+0:`exec' with -l option
+>-zsh
+
+ (exec -a /bin/SPLATTER /bin/sh -c 'echo $0')
+0:`exec' with -a option
+>/bin/SPLATTER
+
+ (exec -a/bin/SPLOOSH /bin/sh -c 'echo $0')
+0:`exec' with -a option, no space
+>/bin/SPLOOSH
+
+ (export FOO=bar; exec -c /bin/sh -c 'echo x${FOO}x')
+0:`exec' with -c option
+>xx
+
+ cat() { echo Function cat executed; }
+ command cat && unfunction cat
+0:`command' precommand modifier
+<External command cat executed
+>External command cat executed
+
+ command -pv cat
+ command -pv echo
+ command -p -V cat
+ command -p -V -- echo
+0:command -p in combination
+*>*/cat
+>echo
+>cat is /*/cat
+>echo is a shell builtin
+
+ 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
+
+ if true;
+ :
+ fi
+1d:`if ...' (iv)
+?(eval):3: parse error near `fi'
+
+ for name in word to term; do
+ print $name
+ done
+0:`for' loop
+>word
+>to
+>term
+
+ for name
+ in word to term; do
+ print $name
+ done
+0:`for' loop with newline before in keyword
+>word
+>to
+>term
+
+ for (( name = 0; name < 3; name++ )); do
+ print $name
+ done
+0:arithmetic `for' loop
+>0
+>1
+>2
+
+ for (( $(true); ; )); do break; done
+ for (( ; $(true); )); do break; done
+ for (( ; ; $(true) )); do break; done
+ for (( ; $((1)); )); do break; done
+0:regression test, nested cmdsubst in arithmetic `for' loop
+
+ for keyvar valvar in key1 val1 key2 val2; do
+ print key=$keyvar val=$valvar
+ done
+0:enhanced `for' syntax with two loop variables
+>key=key1 val=val1
+>key=key2 val=val2
+
+ for keyvar valvar stuffvar in keyA valA stuffA keyB valB stuffB; do
+ print key=$keyvar val=$valvar stuff=$stuffvar
+ done
+0:enhanced `for' syntax with three loop variables
+>key=keyA val=valA stuff=stuffA
+>key=keyB val=valB stuff=stuffB
+
+ for in in in in in stop; do
+ print in=$in
+ done
+0:compatibility of enhanced `for' syntax with standard syntax
+>in=in
+>in=in
+>in=in
+>in=stop
+
+ 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', old syntax
+>2
+
+ word=Trinity
+ case $word in
+ (Michaelmas) print 0
+ ;;
+ (Hilary) print 1
+ ;;
+ (Trinity) print 2
+ ;;
+ (*) print 3
+ ;;
+ esac
+0:`case', new syntax
+>2
+
+ word=Hilary
+ case $word in
+ (Michaelmas) print 0
+ ;;
+ (Hilary) print 1
+ ;&
+ (Trinity) print 2
+ ;&
+ (*) print 3
+ ;;
+ esac
+0:`case', new syntax, cascaded
+>1
+>2
+>3
+
+ case whatever in
+ (*) print yeah, right ;&
+ esac
+ print but well
+0:'case', redundant final ";&"
+>yeah, right
+>but well
+
+## Select now reads from stdin if the shell is not interactive.
+## Its own output goes to stderr.
+ (COLUMNS=80 LINES=3
+ PS3="input> "
+ select name in one two three; do
+ print $name
+ done)
+0:`select' loop
+<2
+?1) one 2) two 3) three
+?input> 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
+
+#
+# Current shell execution with try/always form.
+# We put those with errors in subshells so that any unhandled error doesn't
+# propagate.
+#
+
+ {
+ print The try block.
+ } always {
+ print The always block.
+ }
+ print After the always block.
+0:Basic `always' syntax
+>The try block.
+>The always block.
+>After the always block.
+
+ ({
+ print Position one.
+ print ${*this is an error*}
+ print Position two.
+ } always {
+ if (( TRY_BLOCK_ERROR )); then
+ print An error occurred.
+ else
+ print No error occurred.
+ fi
+ }
+ print Position three)
+1:Always block with error not reset
+>Position one.
+>An error occurred.
+?(eval):3: bad substitution
+
+ ({
+ print Stelle eins.
+ print ${*voici une erreur}
+ print Posizione due.
+ } always {
+ if (( TRY_BLOCK_ERROR )); then
+ print Erratum factum est. Retro ponetur.
+ (( TRY_BLOCK_ERROR = 0 ))
+ else
+ print unray touay foay anguageslay
+ fi
+ }
+ print Status after always block is $?.)
+0:Always block with error reset
+>Stelle eins.
+>Erratum factum est. Retro ponetur.
+>Status after always block is 1.
+?(eval):3: bad substitution
+
+ fn() { { return } always { echo always 1 }; echo not executed }
+ fn
+ fn() { { echo try 2 } always { return }; echo not executed }
+ fn
+0:Always block interaction with return
+>always 1
+>try 2
+
+# Outputting of structures from the wordcode is distinctly non-trivial,
+# we probably ought to have more like the following...
+ fn1() { { echo foo; } }
+ fn2() { { echo foo; } always { echo bar; } }
+ fn3() { ( echo foo; ) }
+ functions fn1 fn2 fn3
+0:Output of syntactic structures with and without always blocks
+>fn1 () {
+> {
+> echo foo
+> }
+>}
+>fn2 () {
+> {
+> echo foo
+> } always {
+> echo bar
+> }
+>}
+>fn3 () {
+> (
+> echo foo
+> )
+>}
+
+
+#
+# Tests for `Alternate Forms For Complex Commands'
+#
+
+ if (true) { print true-1 } elif (true) { print true-2 } else { print false }
+ if (false) { print true-1 } elif (true) { print true-2 } else { print false }
+ if (false) { print true-1 } elif (false) { print true-2 } else { print false }
+0:Alternate `if' with braces
+>true-1
+>true-2
+>false
+
+ if { true } print true
+ if { false } print false
+0:Short form of `if'
+>true
+
+ eval "if"
+1:Short form of `if' can't be too short
+?(eval):1: parse error near `if'
+
+ 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
+
+ case bravo {
+ (alpha) print schmalpha
+ ;;
+ (bravo) print schmavo
+ ;;
+ (charlie) print schmarlie
+ ;;
+ }
+0:`case' with braces
+>schmavo
+
+ for word in artichoke bladderwort chrysanthemum Zanzibar
+ case $word in
+ (*der*) print $word contains the forbidden incantation der
+ ;;
+ (a*) print $word begins with a
+ ;&
+ ([[:upper:]]*) print $word either begins with a or an upper case letter
+ ;|
+ ([[:lower:]]*) print $word begins with a lower case letter
+ ;|
+ (*e*) print $word contains an e
+ ;;
+ esac
+0:`case' with mixed ;& and ;|
+>artichoke begins with a
+>artichoke either begins with a or an upper case letter
+>artichoke begins with a lower case letter
+>artichoke contains an e
+>bladderwort contains the forbidden incantation der
+>chrysanthemum begins with a lower case letter
+>chrysanthemum contains an e
+>Zanzibar either begins with a or an upper case letter
+
+ print -u $ZTST_fd 'This test hangs the shell when it fails...'
+ name=0
+# The number 4375 here is chosen to produce more than 16384 bytes of output
+ while (( name < 4375 )); do
+ print -n $name
+ (( name++ ))
+ done < /dev/null | { read name; print done }
+0:Bug regression: `while' loop with redirection and pipeline
+>done
+
+# This used to be buggy and print X at the end of each iteration.
+ for f in 1 2 3 4; do
+ print $f || break
+ done && print X
+0:Handling of ||'s and &&'s with a for loop in between
+>1
+>2
+>3
+>4
+>X
+
+# Same bug for &&, used to print `no' at the end of each iteration
+ for f in 1 2 3 4; do
+ false && print strange
+ done || print no
+0:Handling of &&'s and ||'s with a for loop in between
+>no
+
+ $ZTST_testdir/../Src/zsh -f unmatched_quote.txt
+1:Parse error with file causes non-zero exit status
+?unmatched_quote.txt:2: unmatched '
+
+ $ZTST_testdir/../Src/zsh -f <unmatched_quote.txt
+1:Parse error on standard input causes non-zero exit status
+?zsh: unmatched '
+
+ $ZTST_testdir/../Src/zsh -f -c "'"
+1:Parse error on inline command causes non-zero exit status
+?zsh:1: unmatched '
+
+ $ZTST_testdir/../Src/zsh -f NonExistentScript
+127q:Non-existent script causes exit status 127
+?$ZTST_testdir/../Src/zsh: can't open input file: NonExistentScript
+
+ (setopt nonomatch
+ # use this to get stuff at start of line
+ contents=$'# comment \'\necho value #with " stuff\n# comment\n#comment
+ echo not#comment\n'
+ eval 'VAR=$('"$contents"')'
+ print -l $VAR)
+0:comments within $(...)
+>value
+>not#comment
+
+ . ./nonexistent
+127: Attempt to "." non-existent file.
+?(eval):.:1: no such file or directory: ./nonexistent
+
+ echo '[[' >bad_syntax
+ . ./bad_syntax
+126: Attempt to "." file with bad syntax.
+?./bad_syntax:2: parse error near `\n'
+# `
+
+ echo 'false' >dot_false
+ . ./dot_false
+ print $?
+ echo 'true' >dot_true
+ . ./dot_true
+ print $?
+0:Last status of successfully executed "." file is retained
+>1
+>0
+
+ echo 'echo $?' >dot_status
+ false
+ . ./dot_status
+0:"." file sees status from previous command
+>1
+
+ mkdir test_path_script
+ print "#!/bin/sh\necho Found the script." >test_path_script/myscript
+ chmod u+x test_path_script/myscript
+ path=($PWD/test_path_script $path)
+ export PATH
+ $ZTST_testdir/../Src/zsh -f -o pathscript myscript
+0:PATHSCRIPT option
+>Found the script.
+
+ $ZTST_testdir/../Src/zsh -f myscript
+127q:PATHSCRIPT option not used.
+?$ZTST_testdir/../Src/zsh: can't open input file: myscript
+# '
+
+ $ZTST_testdir/../Src/zsh -fc 'echo $0; echo $1' myargzero myargone
+0:$0 is traditionally if bizarrely set to the first argument with -c
+>myargzero
+>myargone
+
+ (setopt shglob
+ eval '
+ if ! (echo success1); then echo failure1; fi
+ if !(echo success2); then echo failure2; fi
+ print -l one two | while(read foo)do(print read it)done
+ ')
+0:Parentheses in shglob
+>success1
+>success2
+>read it
+>read it
+
+ (
+ mywrap() { echo BEGIN; true; echo END }
+ mytest() { { exit 3 } always { mywrap }; print Exited before this }
+ mytest
+ print Exited before this, too
+ )
+3:Exit and always block with functions: simple
+>BEGIN
+>END
+
+ (
+ mytrue() { echo mytrue; return 0 }
+ mywrap() { echo BEGIN; mytrue; echo END }
+ mytest() { { exit 4 } always { mywrap }; print Exited before this }
+ mytest
+ print Exited before this, too
+ )
+4:Exit and always block with functions: nested
+>BEGIN
+>mytrue
+>END
+
+ (emulate sh -c '
+ fn() {
+ case $1 in
+ ( one | two | three )
+ print Matched $1
+ ;;
+ ( fo* | fi* | si* )
+ print Pattern matched $1
+ ;;
+ ( []x | a[b]* )
+ print Character class matched $1
+ ;;
+ esac
+ }
+ '
+ which fn
+ fn one
+ fn two
+ fn three
+ fn four
+ fn five
+ fn six
+ fn abecedinarian
+ fn xylophone)
+0: case word handling in sh emulation (SH_GLOB parentheses)
+>fn () {
+> case $1 in
+> (one | two | three) print Matched $1 ;;
+> (fo* | fi* | si*) print Pattern matched $1 ;;
+> ([]x | a[b]*) print Character class matched $1 ;;
+> esac
+>}
+>Matched one
+>Matched two
+>Matched three
+>Pattern matched four
+>Pattern matched five
+>Pattern matched six
+>Character class matched abecedinarian
+
+ case grumph in
+ ( no | (grumph) )
+ print 1 OK
+ ;;
+ esac
+ case snruf in
+ ( fleer | (|snr(|[au]f)) )
+ print 2 OK
+ ;;
+ esac
+0: case patterns within words
+>1 OK
+>2 OK
+
+ case horrible in
+ ([a-m])(|[n-z])rr(|ib(um|le|ah)))
+ print It worked
+ ;;
+ esac
+ case "a string with separate words" in
+ (*with separate*))
+ print That worked, too
+ ;;
+ esac
+0:Unbalanced parentheses and spaces with zsh pattern
+>It worked
+>That worked, too
+
+ case horrible in
+ (([a-m])(|[n-z])rr(|ib(um|le|ah)))
+ print It worked
+ ;;
+ esac
+ case "a string with separate words" in
+ (*with separate*)
+ print That worked, too
+ ;;
+ esac
+0:Balanced parentheses and spaces with zsh pattern
+>It worked
+>That worked, too
+
+ fn() {
+ typeset ac_file="the else branch"
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ *.* ) break;;
+ *)
+ ;;
+ esac
+ print Stuff here
+ }
+ which fn
+ fn
+0:Long case with parsed alternatives turned back into text
+>fn () {
+> typeset ac_file="the else branch"
+> case $ac_file in
+> (*.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj) ;;
+> (*.*) break ;;
+> (*) ;;
+> esac
+> print Stuff here
+>}
+>Stuff here
+
+ (exit 37)
+ case $? in
+ (37) echo $?
+ ;;
+ esac
+0:case retains exit status for execution of cases
+>37
+
+ false
+ case stuff in
+ (nomatch) foo
+ ;;
+ esac
+ echo $?
+0:case sets exit status to zero if no patterns are matched
+>0
+
+ case match in
+ (match) true; false; (exit 37)
+ ;;
+ esac
+ echo $?
+0:case keeps exit status of last command executed in compound-list
+>37
+
+ x=1
+ x=2 | echo $x
+ echo $x
+0:Assignment-only current shell commands in LHS of pipelin
+>1
+>1
diff --git a/dotfiles/system/.zsh/modules/Test/A02alias.ztst b/dotfiles/system/.zsh/modules/Test/A02alias.ztst
new file mode 100644
index 0000000..e68e93e
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/A02alias.ztst
@@ -0,0 +1,139 @@
+# To get the "command not found" message when aliasing is suppressed
+# we need, er, a command that isn't found.
+# The other aliases are only ever used as aliases.
+
+%prep
+ alias ThisCommandDefinitelyDoesNotExist=echo
+
+ alias -g bar=echo
+
+ alias '\bar=echo'
+
+%test
+ ThisCommandDefinitelyDoesNotExist ThisCommandDefinitelyDoesNotExist
+0:Basic aliasing
+>ThisCommandDefinitelyDoesNotExist
+
+ bar bar
+0:Global aliasing
+>echo
+
+ \ThisCommandDefinitelyDoesNotExist ThisCommandDefinitelyDoesNotExist
+127:Not aliasing
+?(eval):1: command not found: ThisCommandDefinitelyDoesNotExist
+
+ \bar \bar
+0:Aliasing with a backslash
+>bar
+
+ (alias '!=echo This command has the argument'
+ eval 'print Without
+ ! true'
+ setopt posixaliases
+ eval 'print With
+ ! true')
+1:POSIX_ALIASES option
+>Without
+>This command has the argument true
+>With
+
+ print -u $ZTST_fd 'This test hangs the shell when it fails...'
+ alias cat='LC_ALL=C cat'
+ cat <(echo foo | cat)
+0:Alias expansion works at the end of parsed strings
+>foo
+
+ alias -g '&&=(){ return $?; } && '
+ alias not_the_print_command=print
+ eval 'print This is output
+ && print And so is this
+ && { print And this too; false; }
+ && print But not this
+ && print Nor this
+ true
+ && not_the_print_command And aliases are expanded'
+0:We can now alias special tokens. Woo hoo.
+>This is output
+>And so is this
+>And this too
+>And aliases are expanded
+
+ $ZTST_testdir/../Src/zsh -fis <<<'
+ unsetopt PROMPT_SP
+ PROMPT="" PS2="" PS3="" PS4="" RPS1="" RPS2=""
+ exec 2>&1
+ alias \{=echo
+ { begin
+ {end
+ fc -l -2' 2>/dev/null
+0:Aliasing reserved tokens
+>begin
+>end
+*>*5*{ begin
+*>*6*{end
+
+ $ZTST_testdir/../Src/zsh -fis <<<'
+ unsetopt PROMPT_SP
+ PROMPT="" PS2="" PS3="" PS4="" RPS1="" RPS2=""
+ exec 2>&1
+ alias -g S=\"
+ echo S a string S "
+ fc -l -1' 2>/dev/null
+0:Global aliasing quotes
+> a string S
+*>*5*echo S a string S "
+# "
+# Note there is a trailing space on the "> a string S " line
+
+ (
+ unalias -a
+ alias
+ )
+0:unalias -a
+
+ alias -s foo=print
+ type bar.foo; type -w bar.foo
+ unalias -as
+0:unalias -as
+>foo is a suffix alias for print
+>foo: suffix alias
+
+ aliases[x=y]=z
+ alias -L | grep x=y
+ echo $pipestatus[1]
+0:printing invalid aliases warns
+>0
+?(eval):2: invalid alias 'x=y' encountered while printing aliases
+# Currently, 'alias -L' returns 0 in this case. Perhaps it should return 1.
+
+ alias -s mysuff='print -r "You said it.";'
+ eval 'thingummy.mysuff'
+127:No endless loop with suffix alias in command position
+>You said it.
+?(eval):1: command not found: thingummy.mysuff
+
+ alias +x; alias -z
+1:error message has the correct sign
+?(eval):alias:1: bad option: +x
+?(eval):alias:1: bad option: -z
+
+ # Usual issue that aliases aren't expanded until we
+ # trigger a new parse...
+ (alias badalias=notacommand
+ eval 'badalias() { print does not work; }')
+1:ALIAS_FUNC_DEF off by default.
+?(eval):1: defining function based on alias `badalias'
+?(eval):1: parse error near `()'
+
+ (alias goodalias=isafunc
+ setopt ALIAS_FUNC_DEF
+ eval 'goodalias() { print does now work; }'
+ isafunc)
+0:ALIAS_FUNC_DEF causes the icky behaviour to be avaliable
+>does now work
+
+ (alias thisisokthough='thisworks() { print That worked; }'
+ eval thisisokthough
+ thisworks)
+0:NO_ALIAS_FUNC_DEF works if the alias is a complete definition
+>That worked
diff --git a/dotfiles/system/.zsh/modules/Test/A03quoting.ztst b/dotfiles/system/.zsh/modules/Test/A03quoting.ztst
new file mode 100644
index 0000000..da3ce35
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/A03quoting.ztst
@@ -0,0 +1,80 @@
+%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 $'\'a \\\' is \'a backslash\' is \'a \\\''
+0:$'-style quotes with backslashed backslashes
+>'a \' is 'a backslash' is 'a \'
+
+ chars=$(print -r $'BS\\MBS\M-\\')
+ for (( i = 1; i <= $#chars; i++ )); do
+ char=$chars[$i]
+ print $(( [#16] #char ))
+ done
+0:$'-style quote with metafied backslash
+>16#42
+>16#53
+>16#5C
+>16#4D
+>16#42
+>16#53
+>16#DC
+
+ 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
+>'
+# ' Deconfuse Emacs quoting rules
+
+ print '<\u0041>'
+ printf '%s\n' $'<\u0042>'
+ print '<\u0043>'
+ printf '%s\n' $'<\u0044>'
+0:\u in both print and printf
+><A>
+><B>
+><C>
+><D>
+
+ null1="$(print -r a$'b\0c'd)"
+ null2="$(setopt posixstrings; print -r a$'b\0c'd)"
+ for string in $null1 $null2; do
+ print ":"
+ for (( i = 1; i <= $#string; i++ )); do
+ char=$string[$i]
+ print $(( [#16] #char ))
+ done
+ done
+0:Embedded null characters in $'...' strings.
+>:
+>16#61
+>16#62
+>16#0
+>16#63
+>16#64
+>:
+>16#61
+>16#62
+>16#64
+
+ () { print $# } '' "" $''
+0:$'' should not be elided, in common with other empty quotes
+>3
diff --git a/dotfiles/system/.zsh/modules/Test/A04redirect.ztst b/dotfiles/system/.zsh/modules/Test/A04redirect.ztst
new file mode 100644
index 0000000..d7fe22f
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/A04redirect.ztst
@@ -0,0 +1,588 @@
+# Tests corresponding to the `Redirection' texinfo node.
+
+%prep
+ mkdir redir.tmp && cd redir.tmp
+
+ myfd=99
+ (echo >&$myfd) 2>msg
+ bad_fd_msg="${$(<msg)##*:}"
+
+%test
+
+ print 'This is file redir' >redir && cat redir
+0:'>' and '<' redirection
+>This is file redir
+
+ rm -f redir
+ print 'This is still file redir' <>redir >&0 && cat <>redir
+0:'<>' redirection
+>This is still file redir
+
+ rm -f redir
+ print 'With a bar' >|redir && cat redir
+0:'>|' redirection
+>With a bar
+
+ rm -f redir
+ print 'With a bang' >!redir && cat redir
+0:'>!' redirection
+>With a bang
+
+ rm -f redir
+ print 'Line 1' >>redir && print 'Line 2' >>redir && cat redir
+0:'>>' redirection
+>Line 1
+>Line 2
+
+ rm -f redir
+ print 'Line a' >>|redir && print 'Line b' >>!redir
+0:'>>|' and '>>!' redirection
+
+ foo=bar
+ cat <<' HERE'
+ $foo
+ HERE
+ eval "$(print 'cat <<HERE\n$foo\nHERE')"
+0:Here-documents
+> $foo
+>bar
+
+ cat <<-HERE
+# note tabs at the start of the following lines
+ $foo$foo
+ HERE
+0:Here-documents stripping tabs
+>barbar
+
+ cat <<-$'$HERE '`$(THERE) `'$((AND)) '"\EVERYWHERE" #
+# tabs again. sorry about the max miller.
+ Here's a funny thing. Here is a funny thing.
+ I went home last night. There's a funny thing.
+ Man walks into a $foo. Ouch, it's an iron $foo.
+ $HERE `$(THERE) `$((AND)) \EVERYWHERE
+0:Here-documents don't perform shell expansion on the initial word
+>Here's a funny thing. Here is a funny thing.
+>I went home last night. There's a funny thing.
+>Man walks into a $foo. Ouch, it's an iron $foo.
+
+ cat <<-$'\x45\x4e\x44\t\x44\x4f\x43'
+# tabs again
+ This message is unfathomable.
+ END DOC
+0:Here-documents do perform $'...' expansion on the initial word
+>This message is unfathomable.
+
+ cat <<<"This is a line with a $foo in it"
+0:'<<<' redirection
+>This is a line with a bar in it
+
+ cat <<<$'a\nb\nc'
+0:here-strings with $'...' quoting
+>a
+>b
+>c
+
+# The following tests check that output of parsed here-documents works.
+# This isn't completely trivial because we convert the here-documents
+# internally to here-strings. So we check again that we can output
+# the reevaluated here-strings correctly. Hence there are three slightly
+# different stages. We don't care how the output actually looks, so
+# we don't test that.
+ heretest() {
+ print First line
+ cat <<-HERE
+ $foo$foo met celeste 'but with extra' "stuff to test quoting"
+ HERE
+ print Last line
+ }
+ heretest
+ eval "$(functions heretest)"
+ heretest
+ eval "$(functions heretest)"
+ heretest
+0:Re-evaluation of function output with here document, unquoted
+>First line
+>barbar met celeste 'but with extra' "stuff to test quoting"
+>Last line
+>First line
+>barbar met celeste 'but with extra' "stuff to test quoting"
+>Last line
+>First line
+>barbar met celeste 'but with extra' "stuff to test quoting"
+>Last line
+
+ heretest() {
+ print First line
+ cat <<' HERE'
+ $foo$foo met celeste 'but with extra' "stuff to test quoting"
+ HERE
+ print Last line
+ }
+ heretest
+ eval "$(functions heretest)"
+ heretest
+ eval "$(functions heretest)"
+ heretest
+0:Re-evaluation of function output with here document, quoted
+>First line
+> $foo$foo met celeste 'but with extra' "stuff to test quoting"
+>Last line
+>First line
+> $foo$foo met celeste 'but with extra' "stuff to test quoting"
+>Last line
+>First line
+> $foo$foo met celeste 'but with extra' "stuff to test quoting"
+>Last line
+
+ read -r line <<' HERE'
+ HERE
+1:No input, not even newline, from empty here document.
+
+ #
+ # exec tests: perform these in subshells so if they fail the
+ # shell won't exit.
+ #
+ (exec 3>redir && print hello >&3 && print goodbye >&3 && cat redir)
+0:'>&' redirection
+>hello
+>goodbye
+
+ (exec 3<redir && read foo <&3 && print $foo && read foo <&3 && print $foo)
+0:'<&' redirection
+>hello
+>goodbye
+
+ ({exec 3<&- } 2>/dev/null
+ exec 3<&-
+ read foo <&-)
+1:'<&-' redirection with numeric fd (no error message on failure)
+
+ (exec {varid}<&0
+ exec {varid}<&-
+ print About to close a second time >&2
+ read {varid}<&-)
+1:'<&-' redirection with fd in variable (error message on failure)
+?About to close a second time
+*?\(eval\):*: failed to close file descriptor *
+
+ print foo >&-
+0:'>&-' redirection
+
+ (exec >&-
+ print foo)
+0:'>&-' with attempt to use closed fd
+*?\(eval\):2: write error:*
+
+ fn() { local foo; read foo; print $foo; }
+ coproc fn
+ print test output >&p
+ read bar <&p
+ print $bar
+0:'>&p' and '<&p' redirection
+>test output
+
+ ( print Output; print Error >& 2 ) >&errout && cat errout
+0:'>&FILE' handling
+>Output
+>Error
+
+ rm -f errout
+ ( print Output2; print Error2 >& 2 ) &>errout && cat errout
+0:'&>FILE' handling
+>Output2
+>Error2
+
+ rm -f errout
+ ( print Output3; print Error3 >& 2 ) >&|errout && cat errout
+ ( print Output4; print Error4 >& 2 ) >&!errout && cat errout
+ ( print Output5; print Error5 >& 2 ) &>|errout && cat errout
+ ( print Output6; print Error6 >& 2 ) &>!errout &&
+ ( print Output7; print Error7 >& 2 ) >>&errout &&
+ ( print Output8; print Error8 >& 2 ) &>>errout &&
+ ( print Output9; print Error9 >& 2 ) >>&|errout &&
+ ( print Output10; print Error10 >& 2 ) &>>|errout &&
+ ( print Output11; print Error11 >& 2 ) >>&!errout &&
+ ( print Output12; print Error12 >& 2 ) &>>!errout && cat errout
+0:'>&|', '>&!', '&>|', '&>!' redirection
+>Output3
+>Error3
+>Output4
+>Error4
+>Output5
+>Error5
+>Output6
+>Error6
+>Output7
+>Error7
+>Output8
+>Error8
+>Output9
+>Error9
+>Output10
+>Error10
+>Output11
+>Error11
+>Output12
+>Error12
+
+ rm -f errout
+ ( print Output; print Error 1>&2 ) 1>errout 2>&1 && cat errout
+0:'Combining > with >& (1)'
+>Output
+>Error
+
+ rm -f errout
+ ( print Output; print Error 1>&2 ) 2>&1 1>errout && print errout: &&
+ cat errout
+0:'Combining > with >& (2)'
+>Error
+>errout:
+>Output
+
+ rm -f errout
+ print doo be doo be doo >foo >bar
+ print "foo: $(<foo)\nbar: $(<bar)"
+0:2-file multio
+>foo: doo be doo be doo
+>bar: doo be doo be doo
+
+ rm -f foo bar
+ print dont be dont be dont >foo | sed 's/dont/wont/g' >bar
+0:setup file+pipe multio
+
+ print "foo: $(<foo)\nbar: $(<bar)"
+0:read file+pipe multio
+>foo: dont be dont be dont
+>bar: wont be wont be wont
+
+ rm -f *
+ touch out1 out2
+ print All files >*
+ print *
+ print "out1: $(<out1)\nout2: $(<out2)"
+0:multio with globbing
+>out1 out2
+>out1: All files
+>out2: All files
+
+ print This is out1 >out1
+ print This is out2 >out2
+0:setup multio for input
+
+# Currently, <out{1,2} doesn't work: this is a bug.
+ cat <out*
+0:read multio input
+>This is out1
+>This is out2
+
+ cat out1 | sed s/out/bout/ <out2
+0:read multio input with pipe
+>This is bout1
+>This is bout2
+
+ unset NULLCMD
+ >out1
+1:null redir with NULLCMD unset
+?(eval):2: redirection with no command
+
+ echo this should still work >out1
+ print "$(<out1)"
+0:null redir in $(...) with NULLCMD unset
+>this should still work
+
+ READNULLCMD=cat
+ print cat input >out1
+ <out1
+1:READNULLCMD with NULLCMD unset
+?(eval):3: redirection with no command
+
+ NULLCMD=:
+ >out1
+ [[ ! -s out1 ]] || print out1 is not empty
+0:null redir with NULLCMD=:
+<input
+
+ print cat input >out1
+ <out1
+0:READNULLCMD
+>cat input
+
+ NULLCMD=cat
+ >out1
+ cat out1
+0:null redir with NULLCMD=cat
+<input
+>input
+
+ (myfd=
+ exec {myfd}>logfile
+ if [[ -z $myfd ]]; then
+ print "Ooops, failed to set myfd to a file descriptor." >&2
+ else
+ print This is my logfile. >&$myfd
+ print Examining contents of logfile...
+ cat logfile
+ fi)
+0:Using {fdvar}> syntax to open a new file descriptor
+>Examining contents of logfile...
+>This is my logfile.
+
+ (setopt noclobber
+ exec {myfd}>logfile2
+ echo $myfd
+ exec {myfd}>logfile3) | read myfd
+ (( ! ${pipestatus[1]} ))
+1q:NO_CLOBBER prevents overwriting parameter with allocated fd
+?(eval):4: can't clobber parameter myfd containing file descriptor $myfd
+
+ (setopt noclobber
+ exec {myfd}>logfile2b
+ print First open >&$myfd
+ rm -f logfile2b # prevent normal file no_clobberation
+ myotherfd="${myfd}+0"
+ exec {myotherfd}>logfile2b
+ print Overwritten >&$myotherfd)
+ cat logfile2b
+0:NO_CLOBBER doesn't complain about any other expression
+>Overwritten
+
+ (exec {myfd}>logfile4
+ echo $myfd
+ exec {myfd}>&-
+ print This message should disappear >&$myfd) | read myfd
+ (( ! ${pipestatus[1]} ))
+1q:Closing file descriptor using brace syntax
+?(eval):4: $myfd:$bad_fd_msg
+
+ typeset -r myfd
+ echo This should not appear {myfd}>nologfile
+1:Error opening file descriptor using readonly variable
+?(eval):2: can't allocate file descriptor to readonly parameter myfd
+
+ (typeset +r myfd
+ exec {myfd}>newlogfile
+ typeset -r myfd
+ exec {myfd}>&-)
+1:Error closing file descriptor using readonly variable
+?(eval):4: can't close file descriptor from readonly parameter myfd
+
+# 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')
+0:Optimised here-string to filename
+>This string has been replaced
+>by a file containing it.
+
+ print This f$'\x69'le contains d$'\x61'ta. >redirfile
+ print redirection:
+ cat<redirfile>outfile
+ print output:
+ cat outfile
+ print append:
+ cat>>outfile<redirfile
+ print more output:
+ cat outfile
+0:Parsing of redirection operators (no space required before operators)
+>redirection:
+>output:
+>This file contains data.
+>append:
+>more output:
+>This file contains data.
+>This file contains data.
+
+ $ZTST_testdir/../Src/zsh -fc 'exec >/nonexistent/nonexistent
+ echo output'
+0:failed exec redir, no POSIX_BUILTINS
+>output
+?zsh:1: no such file or directory: /nonexistent/nonexistent
+
+ $ZTST_testdir/../Src/zsh -f -o POSIX_BUILTINS -c '
+ exec >/nonexistent/nonexistent
+ echo output'
+1:failed exec redir, POSIX_BUILTINS
+?zsh:2: no such file or directory: /nonexistent/nonexistent
+
+ $ZTST_testdir/../Src/zsh -f -o POSIX_BUILTINS -c '
+ set >/nonexistent/nonexistent
+ echo output'
+1:failed special builtin redir, POSIX_BUILTINS
+?zsh:2: no such file or directory: /nonexistent/nonexistent
+
+ $ZTST_testdir/../Src/zsh -f -o POSIX_BUILTINS -c '
+ command set >/nonexistent/nonexistent
+ echo output'
+0:failed special builtin redir with command prefix, POSIX_BUILTINS
+>output
+?zsh:2: no such file or directory: /nonexistent/nonexistent
+
+ $ZTST_testdir/../Src/zsh -f -o POSIX_BUILTINS -c '
+ echo >/nonexistent/nonexistent
+ echo output'
+0:failed unspecial builtin redir, POSIX_BUILTINS
+>output
+?zsh:2: no such file or directory: /nonexistent/nonexistent
+
+ $ZTST_testdir/../Src/zsh -f -o POSIX_BUILTINS -c '
+ . /nonexistent/nonexistent
+ echo output'
+1:failed dot, POSIX_BUILTINS
+?zsh:.:2: no such file or directory: /nonexistent/nonexistent
+
+ $ZTST_testdir/../Src/zsh -f -c '
+ . /nonexistent/nonexistent
+ echo output'
+0:failed dot, NO_POSIX_BUILTINS
+>output
+?zsh:.:2: no such file or directory: /nonexistent/nonexistent
+
+ $ZTST_testdir/../Src/zsh -f -o CONTINUE_ON_ERROR <<<'
+ readonly foo
+ foo=bar set output
+ echo output'
+0:failed assignment on posix special, CONTINUE_ON_ERROR
+>output
+?zsh: read-only variable: foo
+
+ $ZTST_testdir/../Src/zsh -f <<<'
+ readonly foo
+ foo=bar set output
+ echo output'
+1:failed assignment on posix special, NO_CONTINUE_ON_ERROR
+?zsh: read-only variable: foo
+
+ $ZTST_testdir/../Src/zsh -f -o CONTINUE_ON_ERROR <<<'
+ readonly foo
+ foo=bar echo output
+ echo output'
+0:failed assignment on non-posix-special, CONTINUE_ON_ERROR
+>output
+?zsh: read-only variable: foo
+
+ [</dev/null ]
+1:check behaviour with square brackets
+
+ print any old rubbish >input1
+ () {
+ local var
+ read var
+ print I just read $var
+ } <input1 >output1
+ print Nothing output yet
+ cat output1
+0:anonymous function redirections are applied immediately
+>Nothing output yet
+>I just read any old rubbish
+
+ redirfn() {
+ local var
+ read var
+ print I want to tell you about $var
+ print Also, this might be an error >&2
+ } <input2 >output2 2>&1
+ print something I heard on the radio >input2
+ redirfn
+ print No output until after this
+ cat output2
+0:redirections with normal function definition
+>No output until after this
+>I want to tell you about something I heard on the radio
+>Also, this might be an error
+
+ which redirfn
+0:text output of function with redirections
+>redirfn () {
+> local var
+> read var
+> print I want to tell you about $var
+> print Also, this might be an error >&2
+>} < input2 > output2 2>&1
+
+ 1func 2func 3func() { print Ich heisse $0 } >output3
+ for i in 1 2 3; do
+ f=${i}func
+ print Running $f
+ $f
+ cat output3
+ unfunction $f
+ done
+0:multiply named functions with redirection
+>Running 1func
+>Ich heisse 1func
+>Running 2func
+>Ich heisse 2func
+>Running 3func
+>Ich heisse 3func
+
+ redirfn2() { print The latest output; } >&3
+ redirfn2 3>output4
+ print No output yet
+ cat output4
+0:Redirections in both function definition and command line
+>No output yet
+>The latest output
+
+# This relies on the fact that the test harness always loads
+# the zsh/parameter module.
+ print $functions[redirfn]
+0:Output from $functions[] for definition with redirection
+>{
+> local var
+> read var
+> print I want to tell you about $var
+> print Also, this might be an error >&2
+>} < input2 > output2 2>&1
+
+ noredirfn() { print This rather boring function has no redirection.; }
+ print $functions[noredirfn]
+0:Output from $functions[] for definition with no redirection
+> print This rather boring function has no redirection.
+
+ (x=43
+ x=$(print This should appear, really >&2; print Not used) exec >test.log
+ print x=$x)
+ cat test.log
+0:Assignment with exec used for redirection: no POSIX_BUILTINS
+>x=43
+?This should appear, really
+
+ (setopt POSIX_BUILTINS
+ x=45
+ x=$(print This should appear, too >&2; print And this) exec >test.log
+ print x=$x)
+ cat test.log
+0:Assignment with exec used for redirection: POSIX_BUILTINS
+>x=And this
+?This should appear, too
+
+ fn-two-heres() {
+# tabs below
+ cat <<-x <<-y
+ foo
+ x
+ bar
+ y
+ }
+ which -x2 fn-two-heres
+ fn-two-heres
+ eval "$(which -x2 fn-two-heres)"
+ fn-two-heres
+ print $functions[fn-two-heres]
+0:Two here-documents in a line are shown correctly.
+>fn-two-heres () {
+> cat <<x <<y
+>foo
+>x
+>bar
+>y
+>}
+>foo
+>bar
+>foo
+>bar
+> cat <<x <<y
+>foo
+>x
+>bar
+>y
diff --git a/dotfiles/system/.zsh/modules/Test/A05execution.ztst b/dotfiles/system/.zsh/modules/Test/A05execution.ztst
new file mode 100644
index 0000000..0804691
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/A05execution.ztst
@@ -0,0 +1,312 @@
+%prep
+
+ storepath=($path)
+
+ mkdir command.tmp command.tmp/dir1 command.tmp/dir2
+
+ cd command.tmp
+
+ print '#!/bin/sh\necho This is top' >tstcmd
+
+ print '#!/bin/sh\necho This is dir1' >dir1/tstcmd
+
+ print '#!/bin/sh\necho This is dir2' >dir2/tstcmd
+
+ chmod 755 tstcmd dir1/tstcmd dir2/tstcmd
+
+%test
+ ./tstcmd
+0:./prog execution
+>This is top
+
+ path=($ZTST_testdir/command.tmp/dir1
+ $ZTST_testdir/command.tmp/dir2
+ .)
+ tstcmd
+ path=($storepath)
+0:path (1)
+>This is dir1
+
+ path=(. command.tmp/dir{1,2})
+ tstcmd
+ path=($storepath)
+0:path (2)
+>This is top
+
+ functst() { print $# arguments:; print -l $*; }
+ functst "Eines Morgens" "als Gregor Samsa"
+ functst ""
+ functst "aus unrhigen Trumen erwachte"
+ foo="fand er sich in seinem Bett"
+ bar=
+ rod="zu einem ungeheuren Ungeziefer verwandelt."
+ functst $foo $bar $rod
+# set up alias for next test
+ alias foo='print This is alias one'
+0:function argument passing
+>2 arguments:
+>Eines Morgens
+>als Gregor Samsa
+>1 arguments:
+>
+>1 arguments:
+>aus unrhigen Trumen erwachte
+>2 arguments:
+>fand er sich in seinem Bett
+>zu einem ungeheuren Ungeziefer verwandelt.
+
+ alias foo='print This is alias two'
+ fn() { foo; }
+ fn
+0:Aliases in functions
+>This is alias one
+
+ foo='Global foo'
+ traptst() { local foo="Local foo"; trap 'print $foo' EXIT; }
+ traptst
+0:EXIT trap environment
+>Global foo
+
+ functst() { return 0; print Ha ha; return 1; }
+ functst
+0:return (1)
+
+ functst() { return 1; print Ho ho; return 0; }
+ functst
+1:return (2)
+
+ unfunction functst
+ fpath=(.)
+ print "print This is functst." >functst
+ autoload functst
+ functst
+0:autoloading (1)
+>This is functst.
+
+ unfunction functst
+ print "functst() { print This, too, is functst; }; print Hello." >functst
+ typeset -fu functst
+ functst
+ functst
+0:autoloading with initialization
+>Hello.
+>This, too, is functst
+
+ unfunction functst
+ print "print Yet another version" >functst
+ functst() { autoload -X; }
+ functst
+0:autoloading via -X
+>Yet another version
+
+ chpwd() { print Changed to $PWD; }
+ cd .
+ unfunction chpwd
+0q:chpwd
+>Changed to $ZTST_testdir/command.tmp
+
+ chpwd() { print chpwd: changed to $PWD; }
+ chpwdfn1() { print chpwdfn1: changed to $PWD; }
+ chpwdfn2() { print chpwdfn2: changed to $PWD; }
+ chpwd_functions=(chpwdfn1 '' chpwdnonexistentfn chpwdfn2)
+ cd .
+ unfunction chpwd
+ unset chpwd_functions
+0q:chpwd_functions
+>chpwd: changed to $ZTST_testdir/command.tmp
+>chpwdfn1: changed to $ZTST_testdir/command.tmp
+>chpwdfn2: changed to $ZTST_testdir/command.tmp
+
+# Hard to test periodic, precmd and preexec non-interactively.
+
+ fn() { TRAPEXIT() { print Exit; }; }
+ fn
+0:TRAPEXIT
+>Exit
+
+ unsetopt DEBUG_BEFORE_CMD
+ unfunction fn
+ print 'TRAPDEBUG() {
+ print Line $LINENO
+ }
+ :
+ unfunction TRAPDEBUG
+ ' > fn
+ autoload fn
+ fn
+ rm fn
+0:TRAPDEBUG
+>Line 1
+>Line 1
+
+ unsetopt DEBUG_BEFORE_CMD
+ unfunction fn
+ print 'trap '\''print Line $LINENO'\'' DEBUG
+ :
+ trap - DEBUG
+ ' > fn
+ autoload fn
+ fn
+ rm fn
+0:trap DEBUG
+>Line 1
+>Line 2
+
+ TRAPZERR() { print Command failed; }
+ true
+ false
+ true
+ false
+ unfunction TRAPZERR
+0:TRAPZERR
+>Command failed
+>Command failed
+
+ trap 'print Command failed again.' ZERR
+ true
+ false
+ true
+ false
+ trap - ZERR
+0:trap ZERR
+>Command failed again.
+>Command failed again.
+
+ false
+ sleep 1000 &
+ print $?
+ kill $!
+0:Status reset by starting a backgrounded command
+>0
+
+ { setopt MONITOR } 2>/dev/null
+ [[ -o MONITOR ]] || print -u $ZTST_fd 'Unable to change MONITOR option'
+ repeat 2048; do (return 2 |
+ return 1 |
+ while true; do
+ false
+ break
+ done;
+ print "${pipestatus[@]}")
+ ZTST_hashmark
+ done | sort | uniq -c | sed 's/^ *//'
+0:Check whether '$pipestatus[]' behaves.
+>2048 2 1 0
+F:This test checks for a bug in '$pipestatus[]' handling. If it breaks then
+F:the bug is still there or it reappeared. See workers-29973 for details.
+
+ { setopt MONITOR } 2>/dev/null
+ externFunc() { awk >/dev/null 2>&1; true; }
+ false | true | false | true | externFunc
+ echo $pipestatus
+0:Check $pipestatus with a known difficult case
+>1 0 1 0 0
+F:This similar test was triggering a reproducible failure with pipestatus.
+
+ { unsetopt MONITOR } 2>/dev/null
+ coproc { read -et 5 || { print -u $ZTST_fd KILLED; kill -HUP -$$ } }
+ print -u $ZTST_fd 'This test takes 5 seconds to fail...'
+ { printf "%d\n" {1..20000} } 2>/dev/null | ( read -e )
+ hang(){ printf "%d\n" {2..20000} | cat }; hang 2>/dev/null | ( read -e )
+ print -p done
+ read -et 6 -p
+0:Bug regression: piping a shell construct to an external process may hang
+>1
+>2
+>done
+F:This test checks for a file descriptor leak that could cause the left
+F:side of a pipe to block on write after the right side has exited
+
+ { setopt MONITOR } 2>/dev/null
+ if [[ -o MONITOR ]]
+ then
+ ( while :; do print "This is a line"; done ) | () : &
+ sleep 1
+ jobs -l
+ else
+ 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
+*>\[<->\] <-> <->
+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
+
+ print "autoload_redir() { print Autoloaded ksh style; } >autoload.log" >autoload_redir
+ autoload -Uk autoload_redir
+ autoload_redir
+ print No output yet
+ cat autoload.log
+ functions autoload_redir
+0:
+>No output yet
+>Autoloaded ksh style
+>autoload_redir () {
+> print Autoloaded ksh style
+>} > autoload.log
+
+# This tests that we record the status of processes that have already exited
+# for when we wait for them.
+#
+# Actually, we don't guarantee here that the jobs have already exited, but
+# the order of the waits means it's highly likely we do need to recall a
+# previous status, barring accidents which shouldn't happen very often. In
+# other words, we rely on the test working repeatedly rather than just
+# once. The monitor option is irrelevant to the logic, so we'll make
+# our job easier by turning it off.
+ { unsetopt MONITOR } 2>/dev/null
+ (exit 1) &
+ one=$!
+ (exit 2) &
+ two=$!
+ (exit 3) &
+ three=$!
+ wait $three
+ print $?
+ wait $two
+ print $?
+ wait $one
+ print $?
+0:The status of recently exited background jobs is recorded
+>3
+>2
+>1
+
+# Regression test for workers/34060 (patch in 34065)
+ setopt ERR_EXIT NULL_GLOB
+ if false; then :; else echo if:$?; fi
+ if false; then :; else for x in _*_; do :; done; echo for:$?; fi
+0:False "if" condition handled correctly by "for" loops with ERR_EXIT
+>if:1
+>for:0
+
+# Regression test for workers/34065 (uses setopt from preceding test)
+ select x; do :; done; echo $?
+ select x in; do :; done; echo $?
+ select x in _*_; do :; done; echo $?
+ unsetopt ERR_EXIT NULL_GLOB
+0:The status of "select" is zero when the loop body does not execute
+>0
+>0
+>0
+
+# Regression test for workers/36392
+ print -u $ZTST_fd 'This test takes 3 seconds and hangs the shell when it fails...'
+ callfromchld() { true && { print CHLD } }
+ TRAPCHLD() { callfromchld }
+ sleep 2 & sleep 3; print OK
+0:Background job exit does not affect reaping foreground job
+>CHLD
+>OK
+
+# Regression test for workers/39839 and workers/39844
+ () { if return 11; then :; fi }; echo $?
+ () { while return 13; do :; done }; echo $?
+ () { until return 17; do :; done }; echo $?
+ () { until false; do return 19; done }; echo $?
+0:"return" in "if" or "while" conditional
+>11
+>13
+>17
+>19
+
diff --git a/dotfiles/system/.zsh/modules/Test/A06assign.ztst b/dotfiles/system/.zsh/modules/Test/A06assign.ztst
new file mode 100644
index 0000000..bf39aee
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/A06assign.ztst
@@ -0,0 +1,631 @@
+# Tests of parameter assignments
+
+%prep
+ mkdir assign.tmp && cd assign.tmp
+
+ touch tmpfile1 tmpfile2
+
+%test
+
+ typeset -A assoc
+ assoc=(one 1 two 2 odd)
+1:assign to association with odd no. of values
+?(eval):2: bad set of key/value pairs for associative array
+
+# tests of array element assignment
+
+ array=(1 2 3 4 5)
+ array[1]=42
+ print $array
+0:Replacement of array element
+>42 2 3 4 5
+
+ array=(1 2 3 4 5)
+ array[1]=(42 43)
+ print $array
+0:Replacement of array element with array
+>42 43 2 3 4 5
+
+ array=(1 2 3 4 5)
+ array[1,2]=(42 43)
+ print $array
+0:Replacement of start of array
+>42 43 3 4 5
+
+ array=(1 2 3 4 5)
+ array[1,4]=(42 43)
+ print $array
+0:Replacement of start of array with shorter slice
+>42 43 5
+
+ array=(1 2 3 4 5)
+ array[1,6]=(42 43)
+ print $array
+0:Replacement of array by extending slice
+>42 43
+
+ array=(1 2 3 4 5)
+ array[3]=(42 43)
+ print $array
+0:Replacement of middle element with array
+>1 2 42 43 4 5
+
+ array=(1 2 3 4 5)
+ array[3,4]=(42 43 44)
+ print $array
+0:Replacement of slice in middle
+>1 2 42 43 44 5
+
+ array=(1 2 3 4 5)
+ array[7,8]=(42 43)
+ print $array
+ # check that [6] was left empty...
+ array[6]=41
+ print $array
+0:Appending by replacing elements off the end
+>1 2 3 4 5 42 43
+>1 2 3 4 5 41 42 43
+
+ array=(1 2 3 4 5)
+ array[-1]=42
+ print $array
+0:Replacement of last element of array, negative indices
+>1 2 3 4 42
+
+ array=(1 2 3 4 5)
+ array[-1]=(42 43)
+ print $array
+0:Replacement of last element of array with array, negative indices
+>1 2 3 4 42 43
+
+ array=(1 2 3 4 5)
+ array[-3,-2]=(42 43 44)
+ print $array
+0:Replacement of middle of array, negative indices
+>1 2 42 43 44 5
+
+ array=(1 2 3 4 5)
+ array[-5,-1]=(42 43)
+ print $array
+0:Replacement of entire array, negative indices
+>42 43
+
+ array=(1 2 3 4 5)
+ array[-7,-1]=(42 43)
+ print $array
+0:Replacement of more than entire array, negative indices
+>42 43
+
+ array=(1 2 3 4 5)
+ array[-7]=42
+ print $array
+0:Replacement of element off start of array.
+>42 1 2 3 4 5
+
+ array=(1 2 3 4 5)
+ array[-7]=42
+ array[-6]=43
+ print $array
+0:Replacement off start doesn't leave gaps. Hope this is right.
+>43 1 2 3 4 5
+
+ array=(1 2 3 4 5)
+ array[1,-1]=(42 43)
+ print $array
+ array[-3,3]=(1 2 3 4 5)
+ print $array
+0:Replacement of entire array, mixed indices
+>42 43
+>1 2 3 4 5
+
+ array=(1 2 3 4 5)
+ array[-7,7]=(42 43)
+ print $array
+0:Replacement of more than entire array, mixed indices
+>42 43
+
+ array=(1 2 3 4 5)
+ array[3,-2]=(42 43 44)
+ print $array
+ array[-3,5]=(100 99)
+ print $array
+0:Replacement of slice in middle, mixed indices
+>1 2 42 43 44 5
+>1 2 42 100 99 5
+
+# tests of var+=scalar
+
+ s+=foo
+ echo $s
+0:append scalar to unset scalar
+>foo
+
+ s=foo
+ s+=bar
+ echo $s
+0:append to scalar
+>foobar
+
+ set -- a b c
+ 2+=end
+ echo $2
+0:append to positional parameter
+>bend
+
+ a=(first second)
+ a+=last
+ print -l $a
+0:add scalar to array
+>first
+>second
+>last
+
+ setopt ksharrays
+ a=(first second)
+ a+=last
+ print -l $a
+ unsetopt ksharrays
+0:add scalar to array with ksharrays set
+>firstlast
+
+ a=(1 2)
+ a[@]+=3
+ print -l $a
+0:add scalar to array with alternate syntax
+>1
+>2
+>3
+
+ integer i=10
+ i+=20
+ (( i == 30 ))
+0:add to integer
+
+ float f=3.4
+ f+=2.3
+ printf "%g\n" f
+0:add to float
+>5.7
+
+ typeset -A hash
+ hash=(one 1)
+ hash+=string
+ [[ $hash[@] == string ]]
+0:add scalar to association
+
+# tests of var+=(array)
+
+ unset a
+ a+=(1 2 3)
+ print -l $a
+0:add array to unset parameter
+>1
+>2
+>3
+
+ a=(a)
+ a+=(b)
+ print -l $a
+0:add array to existing array
+>a
+>b
+
+ s=foo
+ s+=(bar)
+ print -l $s
+0:add array to scalar
+>foo
+>bar
+
+ integer i=1
+ i+=(2 3)
+ print -l $i
+0:add array to integer
+>1
+>2
+>3
+
+ float f=2.5
+ f+=(3.5 4.5)
+ printf '%g\n' $f
+0:add array to float
+>2.5
+>3.5
+>4.5
+
+ typeset -A h
+ h+=(a 1 b 2)
+ print -l $h
+0:add to empty association
+>1
+>2
+
+ typeset -A h
+ h=(a 1)
+ h+=(b 2 c 3)
+ print -l $h
+0:add to association
+>1
+>2
+>3
+
+ typeset -A h
+ h=(a 1 b 2)
+ h+=()
+ print -l $h
+0:add empty array to association
+>1
+>2
+
+# tests of var[range]+=scalar
+
+ s=sting
+ s[2]+=art
+ echo $s
+0:insert scalar inside another
+>starting
+
+ s=inert
+ s[-4]+=s
+ echo $s
+0:insert scalar inside another with negative index
+>insert
+
+ s=append
+ s[2,6]+=age
+ echo $s
+0:append scalar to scalar using a range
+>appendage
+
+ s=123456789
+ s[3,-5]+=X
+ echo $s
+0:insert scalar inside another, specifying a slice
+>12345X6789
+
+ a=(a b c)
+ a[2]+=oo
+ echo $a
+0:append to array element
+>a boo c
+
+ a=(a b c d)
+ a[-2]+=ool
+ echo $a
+0:append to array element with negative index
+>a b cool d
+
+ a=(a b c d)
+ a[2,-1]+=oom
+ echo $a
+0:append to array element, specifying a slice
+>a b c doom
+
+ setopt ksharrays
+ a=(a b c d)
+ a[0]+=0
+ echo $a
+ unsetopt ksharrays
+0:append to array element with ksharrays set
+>a0
+
+ typeset -A h
+ h=(one foo)
+ h[one]+=bar
+ echo $h
+0:append to association element
+>foobar
+
+ typeset -A h
+ h[foo]+=bar
+ echo ${(kv)h}
+0:append to non-existent association element
+>foo bar
+
+ typeset -A h
+ h=(one a two b three c four d)
+ h[(I)*o*]+=append
+1:attempt to append to slice of association
+?(eval):3: h: attempt to set slice of associative array
+
+ integer i=123
+ i[2]+=6
+1:attempt to add to indexed integer variable
+?(eval):2: attempt to add to slice of a numeric variable
+
+ float f=1234.5
+ f[2,4]+=3
+1:attempt to add to slice of float variable
+?(eval):2: attempt to add to slice of a numeric variable
+
+ unset u
+ u[3]+=third
+ echo $u[1]:$u[3]
+0:append to unset variable with index
+>:third
+
+# tests of var[range]+=(array)
+
+ a=(1 2 3)
+ a[2]+=(a b)
+ echo $a
+0:insert array inside another
+>1 2 a b 3
+
+ a=(a b c)
+ a[-1]+=(d)
+ echo $a
+0:append to array using negative index
+>a b c d
+
+ a=(1 2 3 4)
+ a[-1,-3]+=(x)
+ echo $a
+0:insert array using negative range
+>1 2 x 3 4
+
+ s=string
+ s[2]+=(a b)
+1:attempt to insert array into string
+?(eval):2: s: attempt to assign array value to non-array
+
+ integer i=365
+ i[2]+=(1 2)
+1:attempt to insert array into string
+?(eval):2: i: attempt to assign array value to non-array
+
+ typeset -A h
+ h=(a 1)
+ h[a]+=(b 2)
+1:attempt to append array to hash element
+?(eval):3: h: attempt to set slice of associative array
+
+ unset u
+ u[-34,-2]+=(a z)
+ echo $u
+0:add array to indexed unset variable
+>a z
+
+ repeat 10 PATH=. echo hello
+0:saving and restoring of exported special parameters
+>hello
+>hello
+>hello
+>hello
+>hello
+>hello
+>hello
+>hello
+>hello
+>hello
+
+ repeat 10 FOO=BAR BAR=FOO echo $FOO $BAR
+0:save and restore multiple variables around builtin
+>
+>
+>
+>
+>
+>
+>
+>
+>
+>
+
+ call() { print $HELLO; }
+ export HELLO=world
+ call
+ HELLO=universe call
+ call
+ HELLO=${HELLO}liness call
+ call
+ unset HELLO
+0:save and restore when using original value in temporary
+>world
+>universe
+>world
+>worldliness
+>world
+
+ (integer i n x
+ float f
+ setopt globassign
+ i=tmpfile1
+ n=tmpf*
+ x=*2
+ f=2+2
+ typeset -p i n x f)
+0:GLOB_ASSIGN with numeric types
+>typeset -i i=0
+>typeset -a n=( tmpfile1 tmpfile2 )
+>typeset x=tmpfile2
+>typeset -E f=4.000000000e+00
+
+ setopt globassign
+ foo=tmpf*
+ print $foo
+ unsetopt globassign
+ foo=tmpf*
+ print $foo
+0:GLOB_ASSIGN option
+>tmpfile1 tmpfile2
+>tmpf*
+
+ (setopt globassign
+ typeset -A foo
+ touch gatest1 gatest2
+ foo=(gatest*)
+ print ${(t)foo}
+ rm -rf gatest*)
+0:GLOB_ASSIGN doesn't monkey with type if not scalar assignment.
+>association-local
+
+ A=(first second)
+ A="${A[*]}" /bin/sh -c 'echo $A'
+ print -l "${A[@]}"
+0:command execution with assignments shadowing array parameter
+>first second
+>first
+>second
+
+ setopt ksharrays
+ A=(first second)
+ A="${A[*]}" /bin/sh -c 'echo $A'
+ print -l "${A[@]}"
+ unsetopt ksharrays
+0:command execution with assignments shadowing array parameter with ksharrays
+>first second
+>first
+>second
+
+ typeset -aU unique_array=(first second)
+ unique_array[1]=second
+ print $unique_array
+0:assignment to unique array
+>second
+
+ typeset -a array=(first)
+ array[1,3]=(FIRST)
+ print $array
+0:slice beyond length of array
+>FIRST
+
+# tests of string assignments
+
+ a="abc"
+ a[1]=x
+ print $a
+0:overwrite first character in string
+>xbc
+
+ a="abc"
+ a[2]="x"
+ print $a
+0:overwrite middle character in string
+>axc
+
+ a="abc"
+ a[3]="x"
+ print $a
+0:overwrite last character in string
+>abx
+
+ a="abc"
+ a[-1]="x"
+ print $a
+0:overwrite -1 character in string
+>abx
+
+ a="abc"
+ a[-2]="x"
+ print $a
+0:overwrite -2 character (middle) in string
+>axc
+
+ a="ab"
+ a[-2]="x"
+ print $a
+0:overwrite -2 character (first) in string
+>xb
+
+ a="abc"
+ a[-3]="x"
+ print $a
+0:overwrite -3 character (first) in string
+>xbc
+
+ a="abc"
+ a[-4]="x"
+ print $a
+0:overwrite -4 character (before first) in string
+>xabc
+
+ a="abc"
+ a[-5]="x"
+ print $a
+0:overwrite -5 character (before-before first) in string
+>xabc
+
+ a="abc"
+ a[-4,0]="x"
+ print $a
+0:overwrite [-4,0] characters (before first) in string
+>xabc
+
+ a="abc"
+ a[-4,-4]="x"
+ print $a
+0:overwrite [-4,-4] character (before first) in string
+>xabc
+
+ a="abc"
+ a[-40,-30]="x"
+ print $a
+0:overwrite [-40,-30] characters (far before first) in string
+>xabc
+
+ a="abc"
+ a[-40,1]="x"
+ print $a
+0:overwrite [-40,1] characters in short string
+>xbc
+
+ a="abc"
+ a[-40,40]="x"
+ print $a
+0:overwrite [-40,40] characters in short string
+>x
+
+ a="abc"
+ a[2,40]="x"
+ print $a
+0:overwrite [2,40] characters in short string
+>ax
+
+ a="abc"
+ a[2,-1]="x"
+ print $a
+0:overwrite [2,-1] characters in short string
+>ax
+
+ a="abc"
+ a[-2,-1]="x"
+ print $a
+0:overwrite [-2,-1] characters in short string
+>ax
+
+ a="a"
+ a[-1]="xx"
+ print $a
+0:overwrite [-1] character with "xx"
+>xx
+
+ a="a"
+ a[-2]="xx"
+ print $a
+0:overwrite [-2] character (before first) with "xx"
+>xxa
+
+ a="a"
+ a[2]="xx"
+ print $a
+0:overwrite [2] character (after last) with "xx"
+>axx
+
+ a=""
+ a[1]="xx"
+ print $a
+0:overwrite [1] character (string: "") with "xx"
+>xx
+
+ a=""
+ a[-1]="xx"
+ print $a
+0:overwrite [-1] character (string: "") with "xx"
+>xx
+
+ a=""
+ a[2]="xx"
+ print $a
+0:overwrite [2] character (string: "") with "xx"
+>xx
diff --git a/dotfiles/system/.zsh/modules/Test/A07control.ztst b/dotfiles/system/.zsh/modules/Test/A07control.ztst
new file mode 100644
index 0000000..b1a2487
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/A07control.ztst
@@ -0,0 +1,165 @@
+# Test control commands for loops and functions.
+
+%test
+
+ fn3() { return $1; print Error }
+ fn2() { fn3 $1 }
+ fn() {
+ print start $1
+ fn2 $1
+ return
+ print Error
+ }
+ for val in -1 0 1 255; do
+ fn $val; print $?
+ done
+0:Passing of return values back through functions
+>start -1
+>-1
+>start 0
+>0
+>start 1
+>1
+>start 255
+>255
+
+ $ZTST_testdir/../Src/zsh -fc 'fn() {
+ continue
+ }
+ fn'
+1:continue outside loop
+?fn:continue:1: not in while, until, select, or repeat loop
+
+ for outer in 0 1 2 3; do
+ print outer $outer
+ for inner in 0 1 2 3; do
+ print inner $inner
+ continue $(( (outer & 1) ? 2 : 1 ))
+ print error
+ done
+ print outer end
+ done
+0:continue with valid argument
+>outer 0
+>inner 0
+>inner 1
+>inner 2
+>inner 3
+>outer end
+>outer 1
+>inner 0
+>outer 2
+>inner 0
+>inner 1
+>inner 2
+>inner 3
+>outer end
+>outer 3
+>inner 0
+
+ for outer in 0 1; do
+ continue 0
+ print -- $outer got here, status $?
+ done
+1:continue error case 0
+?(eval):continue:2: argument is not positive: 0
+
+ for outer in 0 1; do
+ continue -1
+ print -- $outer got here, status $?
+ done
+1:continue error case -1
+?(eval):continue:2: argument is not positive: -1
+
+ fn() {
+ break
+ }
+ for outer in 0 1; do
+ print $outer
+ fn
+ done
+0:break from within function (this is a feature, I disovered)
+>0
+
+ for outer in 0 1 2 3; do
+ print outer $outer
+ for inner in 0 1 2 3; do
+ print inner $inner
+ break $(( (outer & 1) ? 2 : 1 ))
+ print error
+ done
+ print outer end
+ done
+0:break with valid argument
+>outer 0
+>inner 0
+>outer end
+>outer 1
+>inner 0
+
+ for outer in 0 1; do
+ break 0
+ print -- $outer got here, status $?
+ done
+1:break error case 0
+?(eval):break:2: argument is not positive: 0
+
+ for outer in 0 1; do
+ break -1
+ print -- $outer got here, status $?
+ done
+1:break error case -1
+?(eval):break:2: argument is not positive: -1
+
+ false
+ for x in; do
+ print nothing executed
+ done
+0:Status 0 from for with explicit empty list
+
+ set --
+ false
+ for x; do
+ print nothing executed
+ done
+0:Status 0 from for with implicit empty list
+
+ (exit 2)
+ for x in 1 2; do
+ print $?
+ done
+0:Status from previous command propagated into for loop
+>2
+>0
+
+ false
+ for x in $(echo 1 2; (exit 3)); do
+ print $?
+ done
+0:Status from expansion propagated into for loop
+>3
+>0
+
+ false
+ for x in $(exit 4); do
+ print not executed
+ done
+0:Status from expansion not propagated after unexecuted for loop
+
+ false
+ for x in NonExistentFilePrefix*(N); do
+ print not executed, either
+ done
+0:Status from before for loop not propagated if empty after expansion
+
+ for x in $(echo 1; false); do
+ done
+0:Status reset by empty list in for loop
+
+ false
+ for x in $(echo 1; false); do
+ echo $?
+ (exit 4)
+ done
+4:Last status from loop body is kept even with other funny business going on
+>1
diff --git a/dotfiles/system/.zsh/modules/Test/B01cd.ztst b/dotfiles/system/.zsh/modules/Test/B01cd.ztst
new file mode 100644
index 0000000..94447e7
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/B01cd.ztst
@@ -0,0 +1,144 @@
+# This file serves as a model for how to write tests, so is more heavily
+# commented than 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, and file descriptor 8
+# preserves the original stdout. 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
+
+ setopt chaselinks
+ cd .
+ unsetopt chaselinks
+ 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 the excpetion for '*' noted below), with
+# subsequent whitespace being significant; lines are not subject to any
+# substitution unless the `q' flag (see below) is set.
+#
+# Each line of a '>' and '?' chunk may be preceded by a '*', so the line
+# starts '*>' or '*?'. This signifies that for any line with '*' in front
+# the actual output should be pattern matched against the corresponding
+# lines in the test output. Each line following '>' or '?' must be a
+# valid pattern, so characters special to patterns such as parentheses
+# must be quoted with a backslash. The EXTENDED_GLOB option is used for
+# all such patterns.
+#
+# 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 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
+# 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.
+#
+# It is also possible to add lines in the redirection section beginning
+# with `F:'. The remaining text on all such lines will be concatenated
+# (with newlines in between) and displayed in the event of an error.
+# This text is useful for explaining certain frequent errors, for example
+# ones which may arise from the environment rather than from the shell
+# 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
+# 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
+# (typically "if"). In both cases, the value of the variable is output
+# as a warning that the test was skipped.
+# ZTST_unimplemented: Set this in the %prep phase if the entire test file
+# is to be skipped.
+# ZTST_skip: Set this in any test case if that single test case is to be
+# skipped. Testing resumes at the next test case in the same 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
+F:This test shouldn't really fail. The fact that it has indicates
+F:something is broken. But you already knew that.
+
+ 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
+
+ ln -s nonexistent link_to_nonexistent
+ pwd1=$(pwd -P)
+ cd -s link_to_nonexistent
+ pwd2=$(pwd -P)
+ [[ $pwd1 = $pwd2 ]] || print "Ooops, changed to directory '$pwd2'"
+0:
+?(eval):cd:3: not a directory: link_to_nonexistent
+
+%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.
diff --git a/dotfiles/system/.zsh/modules/Test/B02typeset.ztst b/dotfiles/system/.zsh/modules/Test/B02typeset.ztst
new file mode 100644
index 0000000..b27bb4f
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/B02typeset.ztst
@@ -0,0 +1,723 @@
+# There are certain usages of typeset and its synonyms that it is not
+# possible to test here, because they must appear at the top level and
+# everything that follows is processed by an "eval" within a function.
+
+# Equivalences:
+# declare typeset
+# export typeset -xg
+# float typeset -E
+# functions typeset -f
+# integer typeset -i
+# local typeset +g -m approximately
+# readonly typeset -r
+
+# Tested elsewhere:
+# Equivalence of autoload and typeset -fu A05execution
+# Associative array creation & assignment D04parameter, D06subscript
+# Effects of GLOBAL_EXPORT E01options
+# Function tracing (typeset -ft) E02xtrace
+
+# Not yet tested:
+# Assorted illegal flag combinations
+
+%prep
+ ## Do not remove the next line, it's used by V10private.ztst
+ # test_zsh_param_private
+
+ mkdir typeset.tmp && cd typeset.tmp
+
+ setopt noglob
+
+ scalar=scalar
+ array=(a r r a y)
+
+ scope00() {
+ typeset scalar
+ scalar=local
+ typeset -a array
+ array=(l o c a l)
+ print $scalar $array
+ }
+ scope01() {
+ local scalar
+ scalar=local
+ local -a array
+ array=(l o c a l)
+ print $scalar $array
+ }
+ scope02() {
+ declare scalar
+ scalar=local
+ declare -a array
+ array=(l o c a l)
+ print $scalar $array
+ }
+ scope10() {
+ export outer=outer
+ /bin/sh -fc 'echo $outer'
+ }
+ scope11() {
+ typeset -x outer=outer
+ /bin/sh -fc 'echo $outer'
+ }
+ scope12() {
+ local -x outer=inner
+ /bin/sh -fc 'echo $outer'
+ }
+ scope13() {
+ local -xT OUTER outer
+ outer=(i n n e r)
+ /bin/sh -fc 'echo $OUTER'
+ }
+
+ # Bug? `typeset -h' complains that ! # $ * - ? @ are not identifiers.
+ stress00() {
+ typeset -h +g -m [[:alpha:]_]*
+ unset -m [[:alpha:]_]*
+ typeset +m [[:alpha:]_]*
+ }
+
+%test
+
+ typeset +m scalar array
+0:Report types of parameters with typeset +m
+>scalar
+>array array
+
+ scope00
+ print $scalar $array
+0:Simple local declarations
+>local l o c a l
+>scalar a r r a y
+
+ scope01
+ print $scalar $array
+0:Equivalence of local and typeset in functions
+>local l o c a l
+>scalar a r r a y
+
+ scope02
+ print $scalar $array
+0:Basic equivalence of declare and typeset
+>local l o c a l
+>scalar a r r a y
+
+ declare +m scalar
+0:declare previously lacked -m/+m options
+>scalar
+
+ scope10
+ print $outer
+0:Global export
+>outer
+>outer
+
+ scope11
+ print $outer
+0:Equivalence of export and typeset -x
+>outer
+>outer
+
+ scope12
+ print $outer
+0:Local export
+>inner
+>outer
+
+ float f=3.14159
+ typeset +m f
+ float -E3 f
+ print $f
+ float -F f
+ print $f
+0:Floating point, adding a precision, and fixed point
+>float local f
+>3.14e+00
+>3.142
+
+ integer i=3.141
+ typeset +m i
+ integer -i2 i
+ print $i
+0:Integer and changing the base
+>integer local i
+>2#11
+
+ float -E3 f=3.141
+ typeset +m f
+ integer -i2 f
+ typeset +m f
+ print $f
+0:Conversion of floating point to integer
+>float local f
+>integer 2 local f
+>2#11
+
+ typeset -f
+0q:Equivalence of functions and typeset -f
+>$(functions)
+
+ readonly r=success
+ print $r
+ r=failure
+1:Readonly declaration
+>success
+?(eval):3: read-only variable: r
+
+ typeset r=success
+ readonly r
+ print $r
+ r=failure
+1:Convert to readonly
+>success
+?(eval):4: read-only variable: r
+
+ typeset -gU array
+ print $array
+0:Uniquified arrays and non-local scope
+>a r y
+
+ typeset -T SCALAR=l:o:c:a:l array
+ print $array
+ typeset -U SCALAR
+ print $SCALAR $array
+0:Tied parameters and uniquified colon-arrays
+>l o c a l
+>l:o:c:a l o c a
+
+ (setopt NO_multibyte cbases
+ LC_ALL=C 2>/dev/null
+ typeset -T SCALAR=$'l\x83o\x83c\x83a\x83l' array $'\x83'
+ print $array
+ typeset -U SCALAR
+ for (( i = 1; i <= ${#SCALAR}; i++ )); do
+ char=$SCALAR[i]
+ print $(( [#16] #char ))
+ done
+ print $array)
+0:Tied parameters and uniquified arrays with meta-character as separator
+>l o c a l
+>0x6C
+>0x83
+>0x6F
+>0x83
+>0x63
+>0x83
+>0x61
+>l o c a
+
+ typeset -T SCALAR=$'l\000o\000c\000a\000l' array $'\000'
+ typeset -U SCALAR
+ print $array
+ [[ $SCALAR == $'l\000o\000c\000a' ]]
+0:Tied parameters and uniquified arrays with NUL-character as separator
+>l o c a
+
+ typeset -T SCALAR array
+ typeset +T SCALAR
+1:Untying is prohibited
+?(eval):typeset:2: use unset to remove tied variables
+
+ OUTER=outer
+ scope13
+ print $OUTER
+0:Export of tied parameters
+>i:n:n:e:r
+>outer
+
+ typeset -TU MORESTUFF=here-we-go-go-again morestuff '-'
+ print -l $morestuff
+0:Tied arrays with separator specified
+>here
+>we
+>go
+>again
+
+ typeset -T THIS will not work
+1:Tied array syntax
+?(eval):typeset:1: too many arguments for -T
+
+ local array[2]=x
+1:Illegal local array element assignment
+?(eval):local:1: array[2]: can't create local array elements
+
+ local -a array
+ typeset array[1]=a array[2]=b array[3]=c
+ print $array
+0:Legal local array element assignment
+>a b c
+
+ local -A assoc
+ local b=1 ;: to stomp assoc[1] if assoc[b] is broken
+ typeset assoc[1]=a assoc[b]=2 assoc[3]=c
+ print $assoc[1] $assoc[b] $assoc[3]
+0:Legal local associative array element assignment
+>a 2 c
+
+ local scalar scalar[1]=a scalar[2]=b scalar[3]=c
+ print $scalar
+0:Local scalar subscript assignment
+>abc
+
+ typeset -L 10 fools
+ for fools in " once" "twice" " thrice" " oops too long here"; do
+ print "'$fools'"
+ done
+0:Left justification of scalars
+>'once '
+>'twice '
+>'thrice '
+>'oops too l'
+
+ typeset -L 10 -F 3 foolf
+ for foolf in 1.3 4.6 -2.987 -4.91031; do
+ print "'$foolf'"
+ done
+0:Left justification of floating point
+>'1.300 '
+>'4.600 '
+>'-2.987 '
+>'-4.910 '
+
+ typeset -L 10 -Z foolzs
+ for foolzs in 001.3 04.6 -2.987 -04.91231; do
+ print "'$foolzs'"
+ done
+0:Left justification of scalars with zero suppression
+>'1.3 '
+>'4.6 '
+>'-2.987 '
+>'-04.91231 '
+
+ typeset -R 10 foors
+ for foors in short longer even-longer; do
+ print "'$foors'"
+ done
+0:Right justification of scalars
+>' short'
+>' longer'
+>'ven-longer'
+
+ typeset -Z 10 foozs
+ for foozs in 42 -42 " 43" " -43"; do
+ print "'$foozs'"
+ done
+0:Right justification of scalars with zeroes
+>'0000000042'
+>' -42'
+>' 000000043'
+>' -43'
+
+ integer -Z 10 foozi
+ for foozi in 42 -42 " 43" " -43"; do
+ print "'$foozi'"
+ done
+0:Right justification of integers with zero, no initial base
+>'0000000042'
+>'-000000042'
+>'0000000043'
+>'-000000043'
+# In case you hadn't twigged, the spaces are absorbed in the initial
+# math evaluation, so don't get through.
+
+ unsetopt cbases
+ integer -Z 10 -i 16 foozi16
+ for foozi16 in 42 -42 " 43" " -43"; do
+ print "'$foozi16'"
+ done
+0:Right justification of integers with zero, base 16, C_BASES off
+>'16#000002A'
+>'-16#00002A'
+>'16#000002B'
+>'-16#00002B'
+
+ setopt cbases
+ integer -Z 10 -i 16 foozi16c
+ for foozi16c in 42 -42 " 43" " -43"; do
+ print "'$foozi16c'"
+ done
+0:Right justification of integers with zero, base 16, C_BASES on
+>'0x0000002A'
+>'-0x000002A'
+>'0x0000002B'
+>'-0x000002B'
+
+ setopt cbases
+ integer -Z 10 -i 16 foozi16c
+ for foozi16c in 0x1234 -0x1234; do
+ for (( i = 1; i <= 5; i++ )); do
+ print "'${foozi16c[i,11-i]}'"
+ done
+ print "'${foozi16c[-2]}'"
+ done
+0:Extracting substrings from padded integers
+>'0x00001234'
+>'x0000123'
+>'000012'
+>'0001'
+>'00'
+>'3'
+>'-0x0001234'
+>'0x000123'
+>'x00012'
+>'0001'
+>'00'
+>'3'
+
+ typeset -F 3 -Z 10 foozf
+ for foozf in 3.14159 -3.14159 4 -4; do
+ print "'$foozf'"
+ done
+0:Right justification of fixed point numbers with zero
+>'000003.142'
+>'-00003.142'
+>'000004.000'
+>'-00004.000'
+
+ stress00
+ print $scalar $array
+0q:Stress test: all parameters are local and unset, using -m
+>scalar a r y
+
+ 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
+
+ export ENVFOO=bar
+ print ENVFOO in environment
+ env | grep '^ENVFOO'
+ print Changing ENVFOO
+ ENVFOO="not bar any more"
+ env | grep '^ENVFOO'
+ unset ENVFOO
+ print ENVFOO no longer in environment
+ env | grep '^ENVFOO'
+1:Adding and removing values to and from the environment
+>ENVFOO in environment
+>ENVFOO=bar
+>Changing ENVFOO
+>ENVFOO=not bar any more
+>ENVFOO no longer in environment
+
+ (export FOOENV=BAR
+ env | grep '^FOOENV'
+ print Exec
+ exec $ZTST_testdir/../Src/zsh -fc '
+ print Unset
+ unset FOOENV
+ env | grep "^FOOENV"')
+1:Can unset environment variables after exec
+>FOOENV=BAR
+>Exec
+>Unset
+
+ local case1=upper
+ typeset -u case1
+ print $case1
+ upper="VALUE OF \$UPPER"
+ print ${(P)case1}
+0:Upper case conversion, does not apply to values used internally
+>UPPER
+>VALUE OF $UPPER
+
+ local case2=LOWER
+ typeset -l case2
+ print $case2
+ LOWER="value of \$lower"
+ print ${(P)case2}
+0:Lower case conversion, does not apply to values used internally
+>lower
+>value of $lower
+
+ typeset -a array
+ array=(foo bar)
+ fn() { typeset -p array nonexistent; }
+ fn
+1:declare -p shouldn't create scoped values
+>typeset -g -a array=( foo bar )
+?fn:typeset: no such variable: nonexistent
+
+ unsetopt typesetsilent
+ silent1(){ typeset -g silence; }
+ silent2(){ local silence; silent1; }
+ silent2
+0:typeset -g should be silent even without TYPESET_SILENT
+
+ typeset -T TIED_SCALAR tied_array
+ TIED_SCALAR=foo:bar
+ print $tied_array
+ typeset -T TIED_SCALAR=goo:car tied_array
+ print $tied_array
+ typeset -T TIED_SCALAR tied_array=(poo par)
+ print $TIED_SCALAR
+0:retying arrays to same array works
+>foo bar
+>goo car
+>poo:par
+
+ (
+ setopt POSIXBUILTINS
+ readonly pbro
+ print ${+pbro} >&2
+ (typeset -g pbro=3)
+ (pbro=4)
+ readonly -p pbro >&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
+ )
+1:readonly with POSIX_BUILTINS
+?0
+?(eval):5: read-only variable: pbro
+?(eval):6: read-only variable: pbro
+?typeset -g -r pbro
+?0
+?(eval):10: read-only variable: pbro
+
+ readonly foo=bar novalue
+ readonly -p
+0:readonly -p output (no readonly specials)
+>typeset -r foo=bar
+>typeset -r novalue=''
+
+ local -a a1 a2
+ local -r r1=yes r2=no
+ a1=(one two) a2=(three four)
+ readonly a1
+ typeset -pm 'a[12]'
+ typeset -pm 'r[12]'
+0:readonly -p output
+>typeset -ar a1=( one two )
+>typeset -a a2=( three four )
+>typeset -r r1=yes
+>typeset -r r2=no
+
+ one=hidden two=hidden three=hidden four=hidden five=hidden
+ fn() {
+ local bleugh="four=vier"
+ typeset -R10 one=eins two=(zwei dio) three $bleugh five=(cinq cinque)
+ three=drei
+ print -l $one $two $three $four $five
+ }
+ fn
+ print -l $one $two $three $four $five
+0:typeset reserved word interface: basic
+> eins
+>zwei
+>dio
+> drei
+> vier
+>cinq
+>cinque
+>hidden
+>hidden
+>hidden
+>hidden
+>hidden
+
+ (
+ setopt glob
+ mkdir -p arrayglob
+ touch arrayglob/{one,two,three,four,five,six,seven}
+ fn() {
+ typeset array=(arrayglob/[tf]*)
+ print -l ${array:t}
+ #
+ typeset {first,second,third}=the_same_value array=(
+ extends
+ over
+ multiple
+ lines
+ )
+ print -l $first $second $third "$array"
+ #
+ integer i=$(echo 1 + 2 + 3 + 4)
+ print $i
+ #
+ # only noted by accident this was broken..
+ # we need to turn off special recognition
+ # of assignments within assignments...
+ typeset careful=( i=1 j=2 k=3 )
+ print -l $careful
+ }
+ fn
+ )
+0:typeset reserved word, more complicated cases
+>five
+>four
+>three
+>two
+>the_same_value
+>the_same_value
+>the_same_value
+>extends over multiple lines
+>10
+>i=1
+>j=2
+>k=3
+
+ (
+ # reserved word is recognised at parsing.
+ # yes, this is documented.
+ # anyway, that means we need to
+ # re-eval the function...
+ fn='
+ fn() {
+ typeset foo=`echo one word=two`
+ print $foo
+ print $word
+ }
+ '
+ print reserved
+ eval $fn; fn
+ print builtin
+ disable -r typeset
+ eval $fn; fn
+ enable -r typeset
+ disable typeset
+ print reserved
+ eval $fn; fn
+ )
+0:reserved word and builtin interfaces
+>reserved
+>one word=two
+>
+>builtin
+>one
+>two
+>reserved
+>one word=two
+>
+
+ fn() {
+ emulate -L zsh
+ setopt typeset_silent
+ local k
+ typeset -A hash=(k1 v1 k2 v2)
+ typeset foo=word array=(more than one word)
+ for k in ${(ko)hash}; do
+ print $k $hash[$k]
+ done
+ print -l $foo $array
+ typeset -A hash
+ typeset foo array
+ for k in ${(ko)hash}; do
+ print $k $hash[$k]
+ done
+ print -l $foo $array
+ typeset hash=(k3 v3 k4 v4) array=(odd number here)
+ for k in ${(ko)hash}; do
+ print $k $hash[$k]
+ done
+ print -l $array
+ }
+ fn
+0:typeset preserves existing variable types
+>k1 v1
+>k2 v2
+>word
+>more
+>than
+>one
+>word
+>k1 v1
+>k2 v2
+>word
+>more
+>than
+>one
+>word
+>k3 v3
+>k4 v4
+>odd
+>number
+>here
+
+ fn() { typeset foo bar thing=this stuff=(that other) more=woevva; }
+ which -x2 fn
+ fn2() { typeset assignfirst=(why not); }
+ which -x2 fn2
+0:text output from typeset
+>fn () {
+> typeset foo bar thing=this stuff=(that other) more=woevva
+>}
+>fn2 () {
+> typeset assignfirst=(why not)
+>}
+
+ fn() {
+ typeset array=()
+ print ${(t)array} ${#array}
+ typeset gnothergarray=() gnothergarray[1]=yes gnothergarray[2]=no
+ print -l ${(t)gnothergarray} $gnothergarray
+ }
+ fn
+0:can set empty array
+>array-local 0
+>array-local
+>yes
+>no
+
+ array=(nothing to see here)
+ fn() {
+ typeset array=(one two three four five)
+ typeset array[2,4]=(umm er)
+ print ${#array} $array
+ typeset array[2,3]=()
+ print ${#array} $array
+ }
+ fn
+ print ${#array} $array
+0:can update array slices in typeset
+>4 one umm er five
+>2 one five
+>4 nothing to see here
+
+ array=(no really nothing here)
+ fn() {
+ typeset array=() array[2]=two array[4]=four
+ typeset -p array
+ typeset array=() array[3]=three array[1]=one
+ typeset -p array
+ }
+ fn
+ print $array
+0:setting empty array in typeset
+>typeset -a array=( '' two '' four )
+>typeset -a array=( one '' three )
+>no really nothing here
+
+ readonly isreadonly=yes
+ typeset isreadonly=still
+1:typeset returns status 1 if setting readonly variable
+?(eval):2: read-only variable: isreadonly
+
+ if (( UID )); then
+ UID=$((UID+1)) date; echo "Status is printed, $?"
+ else
+ ZTST_skip="cannot test setuid error when tests run as superuser"
+ fi
+0:when cannot change UID, the command isn't run
+# 'date' did not run.
+>Status is printed, 1
+*?*: failed to change user ID: *
diff --git a/dotfiles/system/.zsh/modules/Test/B03print.ztst b/dotfiles/system/.zsh/modules/Test/B03print.ztst
new file mode 100644
index 0000000..c65568a
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/B03print.ztst
@@ -0,0 +1,336 @@
+# Tests for the echo, print, printf and pushln builtins
+
+# Tested elsewhere:
+# 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
+
+# Not yet tested:
+# echo and pushln
+# print's -b -c -s -z -N options
+
+
+%test
+
+ print -D "${HOME:-~}"
+0:replace directory name
+>~
+
+ print -u2 'error message'
+0:output to file-descriptor
+?error message
+
+ print -o foo bar Baz
+0:argument sorting
+>Baz bar foo
+
+ print -f
+1:print -f needs a format specified
+?(eval):print:1: argument expected: -f
+
+ print -Of '%s\n' foo bar baz
+0:reverse argument sorting
+>foo
+>baz
+>bar
+
+# some locales force case-insensitive sorting
+ (LC_ALL=C; print -o a B c)
+0:case-sensitive argument sorting
+>B a c
+
+ (LC_ALL=C; print -io a B c)
+0:case-insensitive argument sorting
+>a B c
+
+ print -m '[0-9]' one 2 three 4 five 6
+0:removal of non-matching arguments
+>2 4 6
+
+ printf '%s\n' string
+0:test s format specifier
+>string
+
+ printf '%b' '\t\\\n'
+0:test b format specifier
+> \
+
+ printf '%q\n' '=a=b \ c!'
+0: test q format specifier
+>\=a=b\ \\\ c!
+
+ printf '%c\n' char
+0:test c format specifier
+>c
+
+ printf '%.10e%n\n' 1 count >/dev/null
+ printf '%d\n' $count
+0:test n format specifier
+>16
+
+ printf '%5b%n\n' abc count >/dev/null; echo $count
+0:check count of width-specified %b
+>5
+
+ printf '%s!%5b!\n' abc
+0:ensure width is applied to empty param
+>abc! !
+
+ printf '%d %d\n' 123.45 678 90.1
+0:test d format specifier
+>123 678
+>90 0
+
+ printf '%g %g\n' 123.45 678 90.1
+0:test g format specifier
+>123.45 678
+>90.1 0
+
+ print -f 'arg: %b\n' -C2 '\x41' '\x42' '\x43'
+0:override -C when -f was given
+>arg: A
+>arg: B
+>arg: C
+
+# Is anyone not using ASCII
+ printf '%d\n' \'A
+0:initial quote to get numeric value of character with int
+>65
+
+ printf '%.1E\n' \'B
+0:initial quote to get numeric value of character with double
+>6.6E+01
+
+ printf '%x\n' $(printf '"\xf0')
+0:numeric value of high numbered character
+>f0
+
+ printf '\x25s\n' arg
+0:using \x25 to print a literal % in format
+>%s
+
+ printf '%3c\n' c
+0:width specified in format specifier
+> c
+
+ printf '%.4s\n' chopped
+0:precision specified in format specifier
+>chop
+
+ printf '%*.*f\n' 6 2 10.2
+0:width/precision specified in arguments
+> 10.20
+
+ printf '%z'
+1:use of invalid directive
+?(eval):printf:1: %z: invalid directive
+
+ printf '%d\n' 3a
+1:bad arithmetic expression
+?(eval):1: bad math expression: operator expected at `a'
+>0
+
+ printf '%12$s' 1 2 3
+1:out of range argument specifier
+?(eval):printf:1: 12: argument specifier out of range
+
+ printf '%2$s\n' 1 2 3
+1:out of range argument specifier on format reuse
+?(eval):printf:1: 2: argument specifier out of range
+>2
+
+ printf '%*0$d'
+1:out of range argument specifier on width
+?(eval):printf:1: 0: argument specifier out of range
+
+ print -m -f 'format - %s.\n' 'z' a b c
+0:format not printed if no arguments left after -m removal
+
+ print -f 'format - %s%b.\n'
+0:format printed despite lack of arguments
+>format - .
+
+ printf 'x%4sx\n'
+0:with no arguments empty string where string needed
+>x x
+
+ printf '%d\n'
+0:with no arguments, zero used where number needed
+>0
+
+ printf '%s\t%c:%#x%%\n' one a 1 two b 2 three c 3
+0:multiple arguments with format reused
+>one a:0x1%
+>two b:0x2%
+>three c:0x3%
+
+ printf '%d%n' 123 val val val > /dev/null
+ printf '%d\n' val
+0:%n count zeroed on format reuse
+>1
+
+# this may fill spec string with '%0'+- #*.*lld\0' - 14 characters
+ printf '%1$0'"'+- #-08.5dx\n" 123
+0:maximal length format specification
+>+00123 x
+
+ printf "x:%-20s:y\n" fubar
+0:left-justification of string
+>x:fubar :y
+
+ printf '%*smorning\n' -5 good
+0:negative width specified
+>good morning
+
+ printf '%.*g\n' -1 .1
+0:negative precision specified
+>0.1
+
+ printf '%2$s %1$d\n' 1 2
+0:specify argument to output explicitly
+>2 1
+
+ printf '%3$.*1$d\n' 4 0 3
+0:specify output and precision arguments explicitly
+>0003
+
+ printf '%2$d%1$d\n' 1 2 3 4
+0:reuse format where arguments are explicitly specified
+>21
+>43
+
+ printf '%1$*2$d' 1 2 3 4 5 6 7 8 9 10; echo .EoL.
+0:reuse of specified arguments
+> 1 3 5 7 9.EoL.
+
+ echo -n 'Now is the time'; echo .EoL.
+0:testing -n with echo
+>Now is the time.EoL.
+
+ printf '%1$0+.3d\n' 3
+0:flags mixed with specified argument
+>+003
+
+# Test the parsing of the \c escape.
+
+ echo '1 2!\c3 4' a b c d; echo .EoL.
+0:Truncating first echo arg using backslash-c
+>1 2!.EoL.
+
+ echo a b '1 2?\c5 6' c d; echo .EoL.
+0:Truncating third echo arg using backslash-c
+>a b 1 2?.EoL.
+
+ printf '1 2!\c3 4'; echo .EoL.
+0:Truncating printf literal using backslash-c
+>1 2!.EoL.
+
+ printf '%s %b!\c%s %s' 1 2 3 4 5 6 7 8 9; echo .EoL.
+0:Truncating printf format using backslash-c
+>1 2!.EoL.
+
+ printf '%s %b!\c%s %s' '1\c' '2\n\c' 3 4 5 6 7 8 9
+0:Truncating printf early %b arg using backslash-c
+>1\c 2
+
+ printf '%b %b\n' 1 2 3 4 '5\c' 6 7 8 9; echo .EoL.
+0:Truncating printf late %b arg using backslash-c
+>1 2
+>3 4
+>5.EoL.
+
+# The following usage, as stated in the manual, is not recommended and the
+# results are undefined. Tests are here anyway to ensure some form of
+# half-sane behaviour.
+
+ printf '%2$s %s %3$s\n' Morning Good World
+0:mixed style of argument selection
+>Good Morning World
+
+ printf '%*1$.*d\n' 1 2
+0:argument specified for width only
+>00
+
+ print -f '%*.*1$d\n' 1 2 3
+0:argument specified for precision only
+>2
+>000
+
+ printf -- '%s\n' str
+0:initial `--' ignored to satisfy POSIX
+>str
+
+ printf '%'
+1:nothing after % in format specifier
+?(eval):printf:1: %: invalid directive
+
+ printf $'%\0'
+1:explicit null after % in format specifier
+?(eval):printf:1: %: invalid directive
+
+ printf '%b\n' '\0123'
+0:printf handles \0... octal escapes in replacement text
+>S
+
+ print -lO $'a' $'a\0' $'a\0b' $'a\0b\0' $'a\0b\0a' $'a\0b\0b' $'a\0c' |
+ while read -r line; do
+ for (( i = 1; i <= ${#line}; i++ )); do
+ foo=$line[i]
+ printf "%02x" $(( #foo ))
+ done
+ print
+ done
+0:sorting with embedded nulls
+>610063
+>6100620062
+>6100620061
+>61006200
+>610062
+>6100
+>61
+
+ 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
+0:Tab expansion by print
+>one two three four
+> one two three four
+> one two three four
+>one two three four
+> one two three four
+> one two three four
+
+ unset foo
+ print -v foo once more
+ typeset -p foo
+ printf -v foo "%s\0%s-" into the breach
+ typeset -p foo
+0:print and printf into a variable
+>typeset -g foo='once more'
+>typeset -g foo=$'into\C-@the-breach\C-@-'
+
+ typeset -a foo
+ print -f '%2$d %4s' -v foo one 1 two 2 three 3
+ typeset -p foo
+0:printf into an array variable
+>typeset -a foo=( '1 one' '2 two' '3 three' )
+
+ typeset -a foo
+ print -f '%s' -v foo string
+ typeset -p foo
+0:printf to an array variable without format string reuse
+>typeset foo=string
+
+ printf -
+ printf - -
+ printf --
+ printf -- -
+ printf -- --
+ printf -x -v foo
+ # Final print for newline on stdout
+ print
+0:regression test of printf with assorted ambiguous options or formats
+>------x
+?(eval):printf:3: not enough arguments
diff --git a/dotfiles/system/.zsh/modules/Test/B04read.ztst b/dotfiles/system/.zsh/modules/Test/B04read.ztst
new file mode 100644
index 0000000..25c3d41
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/B04read.ztst
@@ -0,0 +1,112 @@
+# Tests for the read builtin
+
+# Tested elsewhere:
+# reading from a coprocess A01grammar, A04redirect
+
+# Not tested:
+# -c/-l/-n (options for compctl functions)
+# -q/-s (needs a tty)
+
+%test
+
+ read <<<'hello world'
+ print $REPLY
+0:basic read command
+>hello world
+
+ read -A <<<'hello world'
+ print $reply[2]
+0:array read
+>world
+
+ read -k3 -u0 <<<foo:bar
+ print $REPLY
+0:read specified number of chars
+>foo
+
+ for char in y Y n N X $'\n'; do
+ read -q -u0 <<<$char
+ print $?
+ done
+0:read yes or no, default no
+>0
+>0
+>1
+>1
+>1
+>1
+
+ read -d: <<<foo:bar
+ print $REPLY
+0:read up to delimiter
+>foo
+
+ print foo:bar|IFS=: read -A
+ print $reply
+0:use different, IFS separator to array
+>foo bar
+
+ print -z hello world; read -z
+ print $REPLY
+0:read from editor buffer stack
+>hello world
+
+ unset REPLY
+ read -E <<<hello
+ print $REPLY
+0:read with echoing and assigning
+>hello
+>hello
+
+ unset REPLY
+ read -e <<<hello
+ print $REPLY
+0:read with echoing but assigning disabled
+>hello
+>
+
+ read -e -t <<<hello
+0:read with test first
+>hello
+
+ SECONDS=0
+ read -e -t 5 <<<hello
+ print $SECONDS
+0:read with timeout (no waiting should occur)
+>hello
+>0
+
+ print -n 'Testing the\0null hypothesis\0' |
+ while read -d $'\0' line; do print $line; done
+0:read with null delimiter
+>Testing the
+>null hypothesis
+
+# Note that trailing NULLs are not stripped even if they are in
+# $IFS; only whitespace characters contained in $IFS are stripped.
+ print -n $'Aaargh, I hate nulls.\0\0\0' | read line
+ print ${#line}
+0:read with trailing metafied characters
+>24
+
+ (typeset -r foo
+ read foo) <<<bar
+1:return status on failing to set parameter
+?(eval):2: read-only variable: foo
+
+ read -AE array <<<'one two three'
+ print ${(j.:.)array}
+0:Behaviour of -A and -E combination
+>one
+>two
+>three
+>one:two:three
+
+ array=()
+ read -Ae array <<<'four five six'
+ print ${(j.:.)array}
+0:Behaviour of -A and -e combination
+>four
+>five
+>six
+>
diff --git a/dotfiles/system/.zsh/modules/Test/B05eval.ztst b/dotfiles/system/.zsh/modules/Test/B05eval.ztst
new file mode 100644
index 0000000..6427d6f
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/B05eval.ztst
@@ -0,0 +1,34 @@
+# Tests for the eval builtin.
+# This is quite short; eval is widely tested throughout the test suite
+# and its basic behaviour is fairly straightforward.
+
+%prep
+
+ cmd='print $?'
+
+%test
+
+ false
+ eval $cmd
+0:eval retains value of $?
+>1
+
+ # no point getting worked up over what the error message is...
+ ./command_not_found 2>/dev/null
+ eval $cmd
+0:eval after command not found
+>127
+
+ # trick the test system
+ sp=
+ false
+ eval "
+ $sp
+ $sp
+ $sp
+ "
+0:eval with empty command resets the status
+
+ false
+ eval
+0:eval with empty command resets the status
diff --git a/dotfiles/system/.zsh/modules/Test/B06fc.ztst b/dotfiles/system/.zsh/modules/Test/B06fc.ztst
new file mode 100644
index 0000000..922b001
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/B06fc.ztst
@@ -0,0 +1,25 @@
+# Tests of fc command
+%prep
+
+ mkdir fc.tmp
+ cd fc.tmp
+ print 'fc -l foo' >fcl
+
+%test
+ $ZTST_testdir/../Src/zsh -f ./fcl
+1:Checking that fc -l foo doesn't core dump when history is empty
+?./fcl:fc:1: event not found: foo
+
+ PS1='%% ' $ZTST_testdir/../Src/zsh +Z -fsi <<< $'fc -p /dev/null 0 0\n:'
+0:Checking that fc -p doesn't core dump when history size is zero
+*?*%*
+
+ PS1='%% ' $ZTST_testdir/../Src/zsh +Z -fsi <<< 'fc -p /dev/null a 0'
+1:Checking that fc -p rejects non-integer history size
+*?*% fc: HISTSIZE must be an integer
+*?*%*
+
+ PS1='%% ' $ZTST_testdir/../Src/zsh +Z -fsi <<< 'fc -p /dev/null 0 a'
+1:Checking that fc -p rejects non-integer history save size
+*?*% fc: SAVEHIST must be an integer
+*?*%*
diff --git a/dotfiles/system/.zsh/modules/Test/B07emulate.ztst b/dotfiles/system/.zsh/modules/Test/B07emulate.ztst
new file mode 100644
index 0000000..2de097e
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/B07emulate.ztst
@@ -0,0 +1,253 @@
+# Test the "emulate" builtin and related functions.
+
+%prep
+
+ isset() {
+ print -n "${1}: "
+ if [[ -o $1 ]]; then print yes; else print no; fi
+ }
+ showopts() {
+ # Set for Bourne shell emulation
+ isset shwordsplit
+ # Set in native mode and unless "emulate -R" is in use
+ isset banghist
+ }
+ cshowopts() {
+ showopts
+ # Show a csh option, too
+ isset cshnullglob
+ }
+
+%test
+
+ (print Before
+ showopts
+ fn() {
+ emulate sh
+ }
+ fn
+ print After
+ showopts)
+0:Basic use of emulate
+>Before
+>shwordsplit: no
+>banghist: yes
+>After
+>shwordsplit: yes
+>banghist: yes
+
+ fn() {
+ emulate -L sh
+ print During
+ showopts
+ }
+ print Before
+ showopts
+ fn
+ print After
+ showopts
+0:Use of emulate -L
+>Before
+>shwordsplit: no
+>banghist: yes
+>During
+>shwordsplit: yes
+>banghist: yes
+>After
+>shwordsplit: no
+>banghist: yes
+
+ (print Before
+ showopts
+ emulate -R sh
+ print After
+ showopts)
+0:Use of emulate -R
+>Before
+>shwordsplit: no
+>banghist: yes
+>After
+>shwordsplit: yes
+>banghist: no
+
+ print Before
+ showopts
+ emulate sh -c 'print During; showopts'
+ print After
+ showopts
+0:Use of emulate -c
+>Before
+>shwordsplit: no
+>banghist: yes
+>During
+>shwordsplit: yes
+>banghist: yes
+>After
+>shwordsplit: no
+>banghist: yes
+
+ print Before
+ showopts
+ emulate -R sh -c 'print During; showopts'
+ print After
+ showopts
+0:Use of emulate -R -c
+>Before
+>shwordsplit: no
+>banghist: yes
+>During
+>shwordsplit: yes
+>banghist: no
+>After
+>shwordsplit: no
+>banghist: yes
+
+ print Before
+ showopts
+ emulate -R sh -c 'shshowopts() { showopts; }'
+ print After definition
+ showopts
+ print In sticky emulation
+ shshowopts
+ print After sticky emulation
+ showopts
+0:Basic sticky function emulation
+>Before
+>shwordsplit: no
+>banghist: yes
+>After definition
+>shwordsplit: no
+>banghist: yes
+>In sticky emulation
+>shwordsplit: yes
+>banghist: no
+>After sticky emulation
+>shwordsplit: no
+>banghist: yes
+
+ print Before
+ cshowopts
+ emulate -R sh -c 'shshowopts() { cshowopts; }'
+ emulate csh -c 'cshshowopts() {
+ cshowopts
+ print In nested sh emulation
+ shshowopts
+ }'
+ print After definition
+ cshowopts
+ print In sticky csh emulation
+ cshshowopts
+ print After sticky emulation
+ cshowopts
+0:Basic sticky function emulation
+>Before
+>shwordsplit: no
+>banghist: yes
+>cshnullglob: no
+>After definition
+>shwordsplit: no
+>banghist: yes
+>cshnullglob: no
+>In sticky csh emulation
+>shwordsplit: no
+>banghist: yes
+>cshnullglob: yes
+>In nested sh emulation
+>shwordsplit: yes
+>banghist: no
+>cshnullglob: no
+>After sticky emulation
+>shwordsplit: no
+>banghist: yes
+>cshnullglob: no
+
+ isalp() { if [[ -o alwayslastprompt ]]; then print on; else print off; fi; }
+ emulate sh -c 'shfunc_inner() { setopt alwayslastprompt; }'
+ emulate csh -c 'cshfunc_inner() { setopt alwayslastprompt; }'
+ emulate sh -c 'shfunc_outer() {
+ unsetopt alwayslastprompt;
+ shfunc_inner;
+ isalp
+ unsetopt alwayslastprompt
+ cshfunc_inner
+ isalp
+ }'
+ shfunc_outer
+0:Sticky emulation not triggered if sticky emulation unchanged
+>on
+>off
+
+ (
+ setopt ignorebraces
+ emulate zsh -o extendedglob -c '
+ [[ -o ignorebraces ]] || print "Yay, ignorebraces was reset"
+ [[ -o extendedglob ]] && print "Yay, extendedglob is set"
+ '
+ )
+0:emulate -c with options
+>Yay, ignorebraces was reset
+>Yay, extendedglob is set
+
+ (
+ setopt ignorebraces
+ emulate zsh -o extendedglob
+ [[ -o ignorebraces ]] || print "Yay, ignorebraces is no longer set"
+ [[ -o extendedglob ]] && print "Yay, extendedglob is set"
+ )
+0:emulate with options but no -c
+>Yay, ignorebraces is no longer set
+>Yay, extendedglob is set
+
+ emulate zsh -o fixallmybugs 'print This was executed, bad'
+1:emulate -c with incorrect options
+?(eval):emulate:1: no such option: fixallmybugs
+
+ emulate zsh -c '
+ func() { [[ -o extendedglob ]] || print extendedglob is off }
+ '
+ func
+ emulate zsh -o extendedglob -c '
+ func() { [[ -o extendedglob ]] && print extendedglob is on }
+ '
+ func
+0:options specified alongside emulation are also sticky
+>extendedglob is off
+>extendedglob is on
+
+ emulate zsh -o extendedglob -c '
+ func_inner() { setopt nobareglobqual }
+ '
+ emulate zsh -o extendedglob -c '
+ func_outer() {
+ func_inner
+ [[ -o bareglobqual ]] || print bareglobqual was turned off
+ [[ -o extendedglob ]] && print extendedglob is on, though
+ }
+ '
+ [[ -o extendedglob ]] || print extendedglob is initially off
+ func_outer
+0:options propagate between identical emulations
+>extendedglob is initially off
+>bareglobqual was turned off
+>extendedglob is on, though
+
+ emulate zsh -o extendedglob -c '
+ func_inner() { setopt nobareglobqual }
+ '
+ emulate zsh -o extendedglob -o cbases -c '
+ func_outer() {
+ func_inner
+ [[ -o bareglobqual ]] && print bareglobqual is still on
+ [[ -o extendedglob ]] && print extendedglob is on, too
+ }
+ '
+ [[ -o extendedglob ]] || print extendedglob is initially off
+ func_outer
+0:options do not propagate between different emulations
+>extendedglob is initially off
+>bareglobqual is still on
+>extendedglob is on, too
+
+ emulate sh -c '[[ a == a ]]'
+0:regression test for POSIX_ALIASES reserved words
+F:Some reserved tokens are handled in alias expansion
diff --git a/dotfiles/system/.zsh/modules/Test/B08shift.ztst b/dotfiles/system/.zsh/modules/Test/B08shift.ztst
new file mode 100644
index 0000000..0aa9226
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/B08shift.ztst
@@ -0,0 +1,33 @@
+# Test the shift builtin.
+
+%test
+
+ set -- one two three four five six seven eight nine ten
+ shift
+ print $*
+ shift 2
+ print $*
+ shift -p 3
+ print $*
+ shift -p
+ print $*
+0:shifting positional parameters
+>two three four five six seven eight nine ten
+>four five six seven eight nine ten
+>four five six seven
+>four five six
+
+ array=(yan tan tether mether pip azer sezar akker conter dick)
+ shift 2 array
+ print $array
+ shift array
+ print $array
+ shift -p 3 array
+ print $array
+ shift -p array
+ print $array
+0:shifting array
+>tether mether pip azer sezar akker conter dick
+>mether pip azer sezar akker conter dick
+>mether pip azer sezar
+>mether pip azer
diff --git a/dotfiles/system/.zsh/modules/Test/B09hash.ztst b/dotfiles/system/.zsh/modules/Test/B09hash.ztst
new file mode 100644
index 0000000..7b5dfb4
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/B09hash.ztst
@@ -0,0 +1,79 @@
+# The hash builtin is most used for the command hash table, which is
+# populated automatically. This is therefore highly system specific,
+# so mostly we'll test with the directory hash table: the logic is
+# virtually identical but with the different table, and furthermore
+# the shell doesn't care whether the directory exists unless you refer
+# to it in a context that needs one.
+
+%prep
+ populate_hash() {
+ hash -d one=/first/directory
+ hash -d two=/directory/the/second
+ hash -d three=/noch/ein/verzeichnis
+ hash -d four=/bored/with/this/now
+ }
+
+%test
+
+ hash -d
+0:Directory hash initially empty
+
+ populate_hash
+ hash -d
+0:Populating directory hash and output with sort
+>four=/bored/with/this/now
+>one=/first/directory
+>three=/noch/ein/verzeichnis
+>two=/directory/the/second
+
+ hash -rd
+ hash -d
+0:Empty hash
+
+ populate_hash
+ hash -d
+0:Refill hash
+>four=/bored/with/this/now
+>one=/first/directory
+>three=/noch/ein/verzeichnis
+>two=/directory/the/second
+
+ hash -dL
+0:hash -L option
+>hash -d four=/bored/with/this/now
+>hash -d one=/first/directory
+>hash -d three=/noch/ein/verzeichnis
+>hash -d two=/directory/the/second
+
+ hash -dm 't*'
+0:hash -m option
+>three=/noch/ein/verzeichnis
+>two=/directory/the/second
+
+ hash -d five=/yet/more six=/here/we/go seven=/not/yet/eight
+ hash -d
+0:Multiple assignments
+>five=/yet/more
+>four=/bored/with/this/now
+>one=/first/directory
+>seven=/not/yet/eight
+>six=/here/we/go
+>three=/noch/ein/verzeichnis
+>two=/directory/the/second
+
+ hash -d one two three
+0:Multiple arguments with no assignment not in verbose mode
+
+ hash -vd one two three
+0:Multiple arguments with no assignment in verbose mode
+>one=/first/directory
+>two=/directory/the/second
+>three=/noch/ein/verzeichnis
+
+ hash -d t-t=/foo
+ i="~t-t"
+ print ~t-t/bar
+ print ${~i}/rab
+0:Dashes are untokenized in directory hash names
+>/foo/bar
+>/foo/rab
diff --git a/dotfiles/system/.zsh/modules/Test/C01arith.ztst b/dotfiles/system/.zsh/modules/Test/C01arith.ztst
new file mode 100644
index 0000000..61da763
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/C01arith.ztst
@@ -0,0 +1,422 @@
+# Tests corresponding to the texinfo node `Arithmetic Evaluation'
+
+%test
+
+ integer light there
+ (( light = 42 )) &&
+ let 'there = light' &&
+ print $(( there ))
+0:basic integer arithmetic
+>42
+
+ float light there
+ integer rnd
+ (( light = 3.1415 )) &&
+ let 'there = light' &&
+ print -- $(( rnd = there * 10000 ))
+# save rounding problems by converting to integer
+0:basic floating point arithmetic
+>31415
+
+ integer rnd
+ (( rnd = ((29.1 % 13.0 * 10) + 0.5) ))
+ print $rnd
+0:Test floating point modulo function
+>31
+
+ print $(( 0x10 + 0X01 + 2#1010 ))
+0:base input
+>27
+
+ float light
+ (( light = 4 ))
+ print $light
+ typeset -F light
+ print $light
+0:conversion to float
+>4.000000000e+00
+>4.0000000000
+
+ integer i
+ (( i = 32.5 ))
+ print $i
+0:conversion to int
+>32
+
+ integer i
+ (( i = 4 - - 3 * 7 << 1 & 7 ^ 1 | 16 ** 2 ))
+ print $i
+0:precedence (arithmetic)
+>1591
+
+ fn() {
+ setopt localoptions c_precedences
+ integer i
+ (( i = 4 - - 3 * 7 << 1 & 7 ^ 1 | 16 ** 2 ))
+ print $i
+ }
+ fn
+0:precedence (arithmetic, with C_PRECEDENCES)
+>259
+
+ print $(( 1 < 2 || 2 < 2 && 3 > 4 ))
+0:precedence (logical)
+>1
+
+ print $(( 1 + 4 ? 3 + 2 ? 4 + 3 ? 5 + 6 ? 4 * 8 : 0 : 0 : 0 : 0 ))
+0:precedence (ternary)
+>32
+
+ print $(( 3 ? 2 ))
+1:parsing ternary (1)
+?(eval):1: bad math expression: ':' expected
+
+ print $(( 3 ? 2 : 1 : 4 ))
+1:parsing ternary (2)
+?(eval):1: bad math expression: ':' without '?'
+
+ print $(( 0, 4 ? 3 : 1, 5 ))
+0:comma operator
+>5
+
+ foo=000
+ print $(( ##A + ##\C-a + #foo + $#foo ))
+0:#, ## and $#
+>117
+
+ print $((##))
+1:## without following character
+?(eval):1: bad math expression: character missing after ##
+
+ print $((## ))
+0:## followed by a space
+>32
+
+ integer i
+ (( i = 3 + 5 * 1.75 ))
+ print $i
+0:promotion to float
+>11
+
+ typeset x &&
+ (( x = 3.5 )) &&
+ print $x &&
+ (( x = 4 )) &&
+ print $x
+0:use of scalars to store integers and floats
+>3.5
+>4
+
+ (( newarray[unsetvar] = 1 ))
+2:error using unset variable as index
+?(eval):1: newarray: assignment to invalid subscript range
+
+ integer setvar=1
+ (( newarray[setvar]++ ))
+ (( newarray[setvar]++ ))
+ print ${(t)newarray} ${#newarray} ${newarray[1]}
+0:setting array elements in math context
+>array 1 2
+
+ xarr=()
+ (( xarr = 3 ))
+ print ${(t)xarr} $xarr
+0:converting type from array
+>integer 3
+
+ print $(( 13 = 42 ))
+1:bad lvalue
+?(eval):1: bad math expression: lvalue required
+
+ x=/bar
+ (( x = 32 ))
+ print $x
+0:assigning to scalar which contains non-math string
+>32
+
+ print $(( ))
+0:empty math parse e.g. $(( )) acts like a zero
+>0
+
+ print $(( a = ))
+1:empty assignment
+?(eval):1: bad math expression: operand expected at end of string
+
+ print $(( 3, ))
+1:empty right hand of comma
+?(eval):1: bad math expression: operand expected at end of string
+
+ print $(( 3,,4 ))
+1:empty middle of comma
+?(eval):1: bad math expression: operand expected at `,4 '
+
+ print $(( (3 + 7, 4), 5 ))
+0:commas and parentheses, part 1
+>5
+
+ print $(( 5, (3 + 7, 4) ))
+0:commas and parentheses, part 1
+>4
+
+ print $(( 07.5 ))
+ (setopt octalzeroes; print $(( 09.5 )))
+0:leading zero doesn't affect floating point
+>7.5
+>9.5
+
+ (setopt octalzeroes; print $(( 09 )))
+1:octalzeroes rejects invalid constants
+?(eval):1: bad math expression: operator expected at `9 '
+
+ (setopt octalzeroes; print $(( 08#77 )))
+0:octalzeroes doesn't affect bases
+>63
+
+ print $(( 36#z ))
+0:bases up to 36 work
+>35
+
+ print $(( 37#z ))
+1:bases beyond 36 don't work
+?(eval):1: invalid base (must be 2 to 36 inclusive): 37
+
+ print $(( 3 + "fail" ))
+1:parse failure in arithmetic
+?(eval):1: bad math expression: operand expected at `"fail" '
+
+ alias 3=echo
+ print $(( 3 + "OK"); echo "Worked")
+0:not a parse failure because not arithmetic
+>+ OK Worked
+
+ fn() {
+ emulate -L zsh
+ print $(( [#16] 255 ))
+ print $(( [##16] 255 ))
+ setopt cbases
+ print $(( [#16] 255 ))
+ print $(( [##16] 255 ))
+ }
+ fn
+0:doubled # in base removes radix
+>16#FF
+>FF
+>0xFF
+>FF
+
+ array=(1)
+ x=0
+ (( array[++x]++ ))
+ print $x
+ print $#array
+ print $array
+0:no double increment for subscript
+>1
+>1
+>2
+
+ # This is a bit naughty... the value of array
+ # isn't well defined since there's no sequence point
+ # between the increments of x, however we just want
+ # to be sure that in this case, unlike the above,
+ # x does get incremented twice.
+ x=0
+ array=(1 2)
+ (( array[++x] = array[++x] + 1 ))
+ print $x
+0:double increment for repeated expression
+>2
+
+ # Floating point. Default precision should take care of rounding errors.
+ print $(( 1_0.000_000e0_1 ))
+ # Integer.
+ print $(( 0x_ff_ff_ ))
+ # _ are parts of variable names that don't start with a digit
+ __myvar__=42
+ print $(( __myvar__ + $__myvar__ ))
+ # _ is not part of variable name that does start with a digit
+ # (which are substituted before math eval)
+ set -- 6
+ print $(( $1_000_000 ))
+ # Underscores in expressions with no whitespace
+ print $(( 3_000_+4_000_/2 ))
+ # Underscores may appear in the base descriptor, for what it's worth...
+ print $(( 1_6_#f_f_ ))
+0:underscores in math constants
+>100.
+>65535
+>84
+>6000000
+>5000
+>255
+
+ # Force floating point.
+ for expr in "3/4" "0x100/0x200" "0x30/0x10"; do
+ print $(( $expr ))
+ setopt force_float
+ print $(( $expr ))
+ unsetopt force_float
+ done
+0:Forcing floating point constant evaluation, or not.
+>0
+>0.75
+>0
+>0.5
+>3
+>3.
+
+ print $(( 0x30 + 0.5 ))
+ print $(( 077 + 0.5 ))
+ (setopt octalzeroes; print $(( 077 + 0.5 )) )
+0:Mixed float and non-decimal integer constants
+>48.5
+>77.5
+>63.5
+
+ underscore_integer() {
+ setopt cbases localoptions
+ print $(( [#_] 1000000 ))
+ print $(( [#16_] 65536 ))
+ print $(( [#16_4] 65536 * 32768 ))
+ }
+ underscore_integer
+0:Grouping output with underscores: integers
+>1_000_000
+>0x10_000
+>0x8000_0000
+
+ print $(( [#_] (5. ** 10) / 16. ))
+0:Grouping output with underscores: floating point
+>610_351.562_5
+
+ env SHLVL=1+RANDOM $ZTST_testdir/../Src/zsh -f -c 'print $SHLVL'
+0:Imported integer functions are not evaluated
+>2
+
+ print $(( 0b0 + 0b1 + 0b11 + 0b110 ))
+0:Binary input
+>10
+
+ print $(( 0b2 ))
+1:Binary numbers don't tend to have 2's in
+?(eval):1: bad math expression: operator expected at `2 '
+# ` for emacs shell mode
+
+ integer varassi
+ print $(( varassi = 5.5 / 2.0 ))
+ print $varassi
+0:Integer variable assignment converts result to integer
+>2
+>2
+# It's hard to test for integer to float.
+
+ integer ff1=3 ff2=4
+ print $(( ff1/ff2 ))
+ setopt force_float
+ print $(( ff1/ff2 ))
+ unsetopt force_float
+0:Variables are forced to floating point where necessary
+# 0.75 is exactly representable, don't expect rounding error.
+>0
+>0.75
+
+ # The following tests for a bug that only happens when
+ # backing up over input read a line at a time, so we'll
+ # read the input from stdin.
+ $ZTST_testdir/../Src/zsh -f <<<'
+ print $((echo first command
+ ); echo second command)
+ print third command
+ '
+0:Backing up a line of input when finding out it's not arithmetic
+>first command second command
+>third command
+
+ $ZTST_testdir/../Src/zsh -f <<<'
+ print $((3 +
+ 4))
+ print next line
+ '
+0:Not needing to back up a line when reading multiline arithmetic
+>7
+>next line
+
+ $ZTST_testdir/../Src/zsh -f <<<'
+ print $((case foo in
+ bar)
+ echo not this no, no
+ ;;
+ foo)
+ echo yes, this one
+ ;;
+ esac)
+ print after case in subshell)
+ '
+0:Non-arithmetic subst with command subsitution parse from hell
+>yes, this one after case in subshell
+
+ print "a$((echo one subst)
+ (echo two subst))b"
+0:Another tricky case that is actually a command substitution
+>aone subst
+>two substb
+
+ print "x$((echo one frob); (echo two frob))y"
+0:Same on a single line
+>xone frob
+>two froby
+
+ # This case actually only works by accident: if it wasn't for the
+ # unbalanced parenthesis this would be a valid math substitution.
+ # Hence it's definitely not recommended code. However, it does give
+ # the algorithm an extra check.
+ print $((case foo in
+ foo)
+ print Worked OK
+ ;;
+ esac))
+0:Would-be math expansion with extra parenthesis making it a cmd subst
+>Worked OK
+
+ (setopt extendedglob
+ set -- 32.463
+ print ${$(( $1 * 100 ))%%.[0-9]#})
+0:Arithmetic substitution nested in parameter substitution
+>3246
+
+ print $((`:`))
+0:Null string in arithmetic evaluation after command substitution
+>0
+
+ print $(( 1 + $(( 2 + 3 )) ))
+ print $(($((3+4))))
+ print $((1*$((2*$((3))*4))*5))
+0:Nested math substitutions. Yes, I know, very useful.
+>6
+>7
+>120
+
+ foo="(1)"
+ print $((foo))
+ print $(($foo))
+ print $(((2)))
+ foo="3)"
+ (print $((foo))) 2>&1
+ (print $(($foo))) 2>&1
+1: Good and bad trailing parentheses
+>1
+>1
+>2
+>(eval):6: bad math expression: unexpected ')'
+>(eval):7: bad math expression: unexpected ')'
+
+ unset number
+ (( number = 3 ))
+ print ${(t)number}
+ unset number
+ (setopt posix_identifiers
+ (( number = 3 ))
+ print ${(t)number})
+0:type of variable when created in arithmetic context
+>integer
+>scalar
diff --git a/dotfiles/system/.zsh/modules/Test/C02cond.ztst b/dotfiles/system/.zsh/modules/Test/C02cond.ztst
new file mode 100644
index 0000000..3852501
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/C02cond.ztst
@@ -0,0 +1,448 @@
+# Tests corresponding to the texinfo node `Conditional Expressions'
+
+%prep
+
+ umask 077
+
+ mkdir cond.tmp
+
+ cd cond.tmp
+
+ typeset -gi isnfs
+ [[ "$(find . -prune -fstype nfs 2>/dev/null)" == "." ]] && isnfs=1
+ if (( isnfs )) &&
+ (cd -q ${ZTST_tmp} >/dev/null 2>&1 &&
+ [[ "$(find . -prune -fstype nfs 2>/dev/null)" != "." ]]); then
+ filetmpprefix=${ZTST_tmp}/condtest-$$-
+ isnfs=0
+ else
+ filetmpprefix=
+ fi
+ newnewnew=${filetmpprefix}newnewnew
+ unmodified=${filetmpprefix}unmodified
+ zlnfs=${filetmpprefix}zlnfs
+
+ touch $unmodified
+
+ touch zerolength
+ chgrp $EGID zerolength
+
+ touch $zlnfs
+ chgrp $EGID $zlnfs
+
+ print 'Garbuglio' >nonzerolength
+
+ mkdir modish
+ chgrp $EGID modish
+
+ chmod 7710 modish # g+xs,u+s,+t
+ chmod g+s modish # two lines combined work around chmod bugs
+
+ touch unmodish
+ chmod 000 unmodish
+
+ print 'MZ' > cmd.exe
+ chmod +x cmd.exe
+%test
+
+ [[ -a zerolength && ! -a nonexistent ]]
+0:-a cond
+
+ # Find a block special file system. This is a little tricky.
+ block=$(find /dev(|ices)/ -type b -print)
+ if [[ -n $block ]]; then
+ [[ -b $block[(f)1] && ! -b zerolength ]]
+ else
+ print -u$ZTST_fd 'Warning: Not testing [[ -b blockdevice ]] (no devices found)'
+ [[ ! -b zerolength ]]
+ fi
+0D:-b cond
+
+ # Use hardcoded /dev/tty because globbing inside /dev fails on Cygwin
+ char=/dev/tty
+ [[ -c $char && ! -c $zerolength ]]
+0:-c cond
+
+ [[ -d . && ! -d zerolength ]]
+0:-d cond
+
+ [[ -e zerolength && ! -e nonexistent ]]
+0:-e cond
+
+ if [[ -n $block ]]; then
+ [[ -f zerolength && ! -f cond && ! -f $char && ! -f $block[(f)1] && ! -f . ]]
+ else
+ print -u$ZTST_fd 'Warning: Not testing [[ -f blockdevice ]] (no devices found)'
+ [[ -f zerolength && ! -f cond && ! -f $char && ! -f . ]]
+ fi
+0:-f cond
+
+ [[ -g modish && ! -g zerolength ]]
+0:-g cond
+
+ ln -s zerolength link
+ [[ -h link && ! -h zerolength ]]
+0:-h cond
+
+ [[ -k modish && ! -k zerolength ]]
+0:-k cond
+
+ foo=foo
+ bar=
+ [[ -n $foo && ! -n $bar && ! -n '' ]]
+0:-n cond
+
+ [[ -o rcs && ! -o norcs && -o noerrexit && ! -o errexit ]]
+0:-o cond
+
+ if ! grep '#define HAVE_FIFOS' $ZTST_testdir/../config.h; then
+ print -u$ZTST_fd 'Warning: Not testing [[ -p pipe ]] (FIFOs not supported)'
+ [[ ! -p zerolength ]]
+ else
+ if whence mkfifo && mkfifo pipe || mknod pipe p; then
+ [[ -p pipe && ! -p zerolength ]]
+ else
+ print -u$ZTST_fd 'Warning: Not testing [[ -p pipe ]] (cannot create FIFO)'
+ [[ ! -p zerolength ]]
+ fi
+ fi
+0dD:-p cond
+
+ if (( EUID == 0 )); then
+ print -u$ZTST_fd 'Warning: Not testing [[ ! -r file ]] (root reads anything)'
+ [[ -r zerolength && -r unmodish ]]
+ elif [[ $OSTYPE = cygwin ]]; then
+ print -u$ZTST_fd 'Warning: Not testing [[ ! -r file ]]
+ (all files created by user may be readable)'
+ [[ -r zerolength ]]
+ else
+ [[ -r zerolength && ! -r unmodish ]]
+ fi
+0:-r cond
+
+ [[ -s nonzerolength && ! -s zerolength ]]
+0:-s cond
+
+# no simple way of guaranteeing test for -t
+
+ [[ -u modish && ! -u zerolength ]]
+0:-u cond
+
+ [[ -x cmd.exe && ! -x zerolength ]]
+0:-x cond
+
+ [[ -z $bar && -z '' && ! -z $foo ]]
+0:-z cond
+
+ [[ -L link && ! -L zerolength ]]
+0:-L cond
+
+# hard to guarantee a file not owned by current uid
+ [[ -O zerolength ]]
+0:-O cond
+
+ [[ -G zerolength ]]
+0:-G cond
+
+# 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
+ 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"
+ 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.
+
+ [[ $newnewnew -nt $zlnfs && ! ($unmodified -nt $zlnfs) ]]
+0:-nt cond
+
+ [[ $zlnfs -ot $newnewnew && ! ($zlnfs -ot $unmodified) ]]
+0:-ot cond
+
+ [[ link -ef zerolength && ! (link -ef nonzerolength) ]]
+0:-ef cond
+
+ [[ foo = foo && foo != bar && foo == foo && foo != '' ]]
+0:=, == and != conds
+
+ [[ bar < foo && foo > bar ]]
+0:< and > conds
+
+ [[ $(( 3 + 4 )) -eq 0x07 && $(( 5 * 2 )) -ne 0x10 ]]
+0:-eq and -ne conds
+
+ [[ 3 -lt 04 && 05 -gt 2 ]]
+0:-lt and -gt conds
+
+ [[ 3 -le 3 && ! (4 -le 3) ]]
+0:-le cond
+
+ [[ 3 -ge 3 && ! (3 -ge 4) ]]
+0:-ge cond
+
+ [[ 1 -lt 2 || 2 -lt 2 && 3 -gt 4 ]]
+0:|| and && in conds
+
+ if ! grep '#define PATH_DEV_FD' $ZTST_testdir/../config.h; then
+ print -u$ZTST_fd "Warning: not testing [[ -e /dev/fd/0 ]] (/dev/fd not supported)"
+ true
+ else
+ [[ -e /dev/fd/0 ]]
+ fi
+0dD:/dev/fd support in conds handled by access
+
+ if ! grep '#define PATH_DEV_FD' $ZTST_testdir/../config.h; then
+ print -u$ZTST_fd "Warning: not testing [[ -O /dev/fd/0 ]] (/dev/fd not supported)"
+ true
+ else
+ [[ -O /dev/fd/0 ]]
+ fi
+0dD:/dev/fd support in conds handled by stat
+
+ [[ ( -z foo && -z foo ) || -z foo ]]
+1:complex conds with skipping
+
+ [ '' != bar -a '' = '' ]
+0:strings with `[' builtin
+
+ [ `echo 0` -lt `echo 1` ]
+0:substitution in `[' builtin
+
+ [ -n foo scrimble ]
+2:argument checking for [ builtin
+?(eval):[:1: too many arguments
+
+ test -n foo scramble
+2:argument checking for test builtin
+?(eval):test:1: too many arguments
+
+ [ -n foo scrimble scromble ]
+2:argument checking for [ builtin
+?(eval):[:1: too many arguments
+
+ test -n foo scramble scrumble
+2:argument checking for test builtin
+?(eval):test:1: too many arguments
+
+ [ -n foo -a -n bar scrimble ]
+2:argument checking for [ builtin
+?(eval):[:1: too many arguments
+
+ test -n foo -a -z "" scramble
+2:argument checking for test builtin
+?(eval):test:1: too many arguments
+
+ fn() {
+ # careful: first file must exist to trigger bug
+ [[ -e $unmodified ]] || print Where\'s my file\?
+ [[ $unmodified -nt NonExistentFile ]]
+ print status = $?
+ }
+ fn
+0:-nt shouldn't abort on non-existent files
+>status = 1
+
+ str='string' empty=''
+ [[ -v IFS && -v str && -v empty && ! -v str[3] && ! -v not_a_variable ]]
+0:-v cond
+
+ arr=( 1 2 3 4 ) empty=()
+ [[ -v arr && -v arr[1,4] && -v arr[1] && -v arr[4] && -v arr[-4] &&
+ -v arr[(i)3] && ! -v arr[(i)x] &&
+ ! -v arr[0] && ! -v arr[5] && ! -v arr[-5] && ! -v arr[2][1] &&
+ ! -v arr[3]extra && -v empty && ! -v empty[1] ]]
+0:-v cond with array
+
+ typeset -A assoc=( key val num 4 )
+ [[ -v assoc && -v assoc[key] && -v assoc[(i)*] && -v assoc[(I)*] &&
+ ! -v assoc[x] && ! -v assoc[key][1] ]]
+0:-v cond with association
+
+ () { [[ -v 0 && -v 1 && -v 2 && ! -v 3 ]] } arg ''
+0:-v cond with positional parameters
+
+# core dumps on failure
+ if zmodload zsh/regex 2>/dev/null; then
+ echo >regex_test.sh 'if [[ $# = 1 ]]; then
+ if [[ $1 =~ /?[^/]+:[0-9]+:$ ]]; then
+ :
+ fi
+ fi
+ exit 0'
+ $ZTST_testdir/../Src/zsh -f ./regex_test.sh
+ fi
+0:regex tests shouldn't crash
+
+ if zmodload zsh/regex 2>/dev/null; then
+ ( # subshell in case coredump test failed
+ string="this has stuff in it"
+ bad_regex=0
+ if [[ $string =~ "h([a-z]*) s([a-z]*) " ]]; then
+ if [[ "$MATCH $MBEGIN $MEND" != "has stuff 6 15" ]]; then
+ print -r "regex variables MATCH MBEGIN MEND:
+ '$MATCH $MBEGIN $MEND'
+ should be:
+ 'has stuff 6 15'"
+ bad_regex=1
+ else
+ results=("as 7 8" "tuff 11 14")
+ for i in 1 2; do
+ if [[ "$match[$i] $mbegin[$i] $mend[$i]" != $results[i] ]]; then
+ print -r "regex variables match[$i] mbegin[$i] mend[$i]:
+ '$match[$i] $mbegin[$i] $mend[$i]'
+ should be
+ '$results[$i]'"
+ bad_regex=1
+ break
+ fi
+ done
+ fi
+ (( bad_regex )) || print OK
+ else
+ print -r "regex failed to match '$string'"
+ fi
+ )
+ else
+ # if it didn't load, tough, but not a test error
+ ZTST_skip="regexp library not found."
+ fi
+0:MATCH, MBEGIN, MEND, match, mbegin, mend
+>OK
+
+ if zmodload zsh/regex 2>/dev/null; then
+ ( # subshell because regex module may dump core, see above
+ if [[ a =~ a && b == b ]]; then
+ print OK
+ else
+ print "regex =~ inverted following test"
+ fi
+ )
+ else
+ # not a test error
+ ZTST_skip="regexp library not found."
+ fi
+0:regex infix operator should not invert following conditions
+>OK
+
+ [[ -fail badly ]]
+2:Error message for unknown prefix condition
+?(eval):1: unknown condition: -fail
+
+ [[ really -fail badly ]]
+2:Error message for unknown infix condition
+?(eval):1: unknown condition: -fail
+
+ crashme() {
+ if [[ $1 =~ ^http:* ]]
+ then
+ url=${1#*=}
+ fi
+ }
+ which crashme
+0:Regression test for examining code with regular expression match
+>crashme () {
+> if [[ $1 =~ ^http:* ]]
+> then
+> url=${1#*=}
+> fi
+>}
+
+ weirdies=(
+ '! -a !'
+ '! -o !'
+ '! -a'
+ '! -o'
+ '! -a ! -a !'
+ '! = !'
+ '! !'
+ '= -a o'
+ '! = -a o')
+ for w in $weirdies; do
+ eval test $w
+ print $?
+ done
+0:test compatability weirdness: treat ! as a string sometimes
+>0
+>0
+>1
+>0
+>0
+>0
+>1
+>0
+>1
+
+ foo=''
+ [[ $foo ]] || print foo is empty
+ foo=full
+ [[ $foo ]] && print foo is full
+0:bash compatibility with single [[ ... ]] argument
+>foo is empty
+>foo is full
+
+ test -z \( || print Not zero 1
+ test -z \< || print Not zero 2
+ test -n \( && print Not zero 3
+ test -n \) && print Not zero 4
+ [ -n \> ] && print Not zero 5
+ [ -n \! ] && print Not zero 6
+0:test with two arguments and a token
+>Not zero 1
+>Not zero 2
+>Not zero 3
+>Not zero 4
+>Not zero 5
+>Not zero 6
+
+ [ '(' = ')' ] || print OK 1
+ [ '((' = '))' ] || print OK 2
+ [ '(' = '(' ] && print OK 3
+ [ '(' non-empty-string ')' ] && echo OK 4
+ [ '(' '' ')' ] || echo OK 5
+0:yet more old-fashioned test fix ups: prefer comparison to parentheses
+>OK 1
+>OK 2
+>OK 3
+>OK 4
+>OK 5
+
+ fn() { [[ 'a' == 'b' || 'b' = 'c' || 'c' != 'd' ]] }
+ which -x2 fn
+0: = and == appear as input
+>fn () {
+> [[ 'a' == 'b' || 'b' = 'c' || 'c' != 'd' ]]
+>}
+
+%clean
+ # This works around a bug in rm -f in some versions of Cygwin
+ chmod 644 unmodish
+ for tmpfile in $newnewnew $unmodified $zlnfs; do
+ [[ -f $tmpfile ]] && rm -f $tmpfile
+ done
diff --git a/dotfiles/system/.zsh/modules/Test/C03traps.ztst b/dotfiles/system/.zsh/modules/Test/C03traps.ztst
new file mode 100644
index 0000000..7bc0b48
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/C03traps.ztst
@@ -0,0 +1,761 @@
+# Tests for both trap builtin and TRAP* functions.
+
+%prep
+
+ setopt localtraps
+ mkdir traps.tmp && cd traps.tmp
+
+%test
+
+ fn1() {
+ trap 'print EXIT1' EXIT
+ fn2() { trap 'print EXIT2' EXIT; }
+ fn2
+ }
+ fn1
+0:Nested `trap ... EXIT'
+>EXIT2
+>EXIT1
+
+ fn1() {
+ TRAPEXIT() { print EXIT1; }
+ fn2() { TRAPEXIT() { print EXIT2; }; }
+ fn2
+ }
+ fn1
+0: Nested TRAPEXIT
+>EXIT2
+>EXIT1
+
+ fn1() {
+ trap 'print EXIT1' EXIT
+ fn2() { trap - EXIT; }
+ fn2
+ }
+ fn1
+0:Nested `trap - EXIT' on `trap ... EXIT'
+>EXIT1
+
+ fn1() {
+ TRAPEXIT() { print EXIT1; }
+ fn2() { trap - EXIT; }
+ fn2
+ }
+ fn1
+0:Nested `trap - EXIT' on `TRAPEXIT'
+>EXIT1
+
+# We can't test an EXIT trap for the shell as a whole, because
+# we're inside a function scope which we don't leave when the
+# subshell exits. Not sure if that's the correct behaviour, but
+# it's sort of consistent.
+ ( fn1() { trap 'print Function 1 going' EXIT; exit; print Not reached; }
+ fn2() { trap 'print Function 2 going' EXIT; fn1; print Not reached; }
+ fn2
+ )
+0:EXIT traps on functions when exiting from function
+>Function 1 going
+>Function 2 going
+
+# $ZTST_exe is relative to the parent directory.
+# We ought to fix this in ztst.zsh...
+ (cd ..
+ $ZTST_exe -fc 'TRAPEXIT() { print Exited.; }')
+0:EXIT traps on a script
+>Exited.
+
+ trap -
+ trap
+ trap int INT
+ trap sigterm SIGTERM
+ trap quit 3
+ trap
+0: Outputting traps correctly
+>trap -- int INT
+>trap -- quit QUIT
+>trap -- sigterm TERM
+
+ fn1() {
+ trap -
+ trap
+ trap 'print INT1' INT
+ fn2() { trap 'print INT2' INT; trap; }
+ trap
+ fn2
+ trap
+ }
+ fn1
+0: Nested `trap ... INT', not triggered
+>trap -- 'print INT1' INT
+>trap -- 'print INT2' INT
+>trap -- 'print INT1' INT
+
+ fn1() {
+ trap -
+ trap
+ TRAPINT() { print INT1; }
+ fn2() { TRAPINT() { print INT2; }; trap; }
+ trap
+ fn2
+ trap
+ }
+ fn1
+0: Nested TRAPINT, not triggered
+>TRAPINT () {
+> print INT1
+>}
+>TRAPINT () {
+> print INT2
+>}
+>TRAPINT () {
+> print INT1
+>}
+
+ fn1() {
+ trap -
+ trap 'print INT1' INT
+ fn2() { trap - INT; trap; }
+ trap
+ fn2
+ trap
+ }
+ fn1
+0: Nested `trap - INT' on untriggered `trap ... INT'
+>trap -- 'print INT1' INT
+>trap -- 'print INT1' INT
+
+# Testing the triggering of traps here is very unpleasant.
+# The delays are attempts to avoid race conditions, though there is
+# no guarantee that they will work. Note the subtlety that the
+# `sleep' in the function which receives the trap does *not* get the
+# signal, only the parent shell, which is waiting for a SIGCHILD.
+# (At least, that's what I think is happening.) Thus we have to wait at
+# least the full two seconds to make sure we have got the output from the
+# execution of the trap.
+
+ print -u $ZTST_fd 'This test takes at least three seconds...'
+ fn1() {
+ trap 'print TERM1' TERM
+ fn2() { trap 'print TERM2; return 1' TERM; sleep 2; }
+ fn2 &
+ sleep 1
+ kill -TERM $!
+ sleep 2
+ }
+ fn1
+0: Nested `trap ... TERM', triggered on inner loop
+>TERM2
+
+ print -u $ZTST_fd 'This test, too, takes at least three seconds...'
+ fn1() {
+ trap 'print TERM1; return 1' TERM
+ fn2() { trap 'print TERM2; return 1' TERM; }
+ fn2
+ sleep 2
+ }
+ fn1 &
+ sleep 1
+ kill -TERM $!
+ sleep 2
+0: Nested `trap ... TERM', triggered on outer loop
+>TERM1
+
+ TRAPZERR() { print error activated; }
+ fn() { print start of fn; false; print end of fn; }
+ fn
+ fn() {
+ setopt localoptions localtraps
+ unfunction TRAPZERR
+ print start of fn
+ false
+ print end of fn
+ }
+ fn
+ unfunction TRAPZERR
+ print finish
+0: basic localtraps handling
+>start of fn
+>error activated
+>end of fn
+>start of fn
+>end of fn
+>finish
+
+ TRAPZERR() { print 'ERR-or!'; }
+ f() { print f; false; }
+ t() { print t; }
+ f
+ f && t
+ t && f && true
+ t && f
+ testunset() {
+ setopt localtraps
+ unset -f TRAPZERR
+ print testunset
+ false
+ true
+ }
+ testunset
+ f
+ print status $?
+ unfunction TRAPZERR
+0: more sophisticated error trapping
+>f
+>ERR-or!
+>f
+>t
+>f
+>t
+>f
+>ERR-or!
+>testunset
+>f
+>ERR-or!
+>status 1
+
+ f() {
+ setopt localtraps
+ TRAPWINCH() { print "Window changed. That wrecked the test."; }
+ }
+ f
+ f
+ functions TRAPWINCH
+1:Unsetting ordinary traps with localtraps.
+
+#
+# Returns from within traps are a perennial problem.
+# The following two apply to returns in and around standard
+# ksh-style traps. The intention is that a return value from
+# within the function is preserved (i.e. statuses set by the trap
+# are ignored) unless the trap explicitly executes `return', which makes
+# it return from the enclosing function.
+#
+ fn() { trap 'true' EXIT; return 1; }
+ fn
+1: ksh-style EXIT traps preserve return value
+
+ inner() { trap 'return 3' EXIT; return 2; }
+ outer() { inner; return 1; }
+ outer
+3: ksh-style EXIT traps can force return status of enclosing function
+
+# Autoloaded traps are horrid, but unfortunately people expect
+# them to work if we support them.
+ echo "print Running exit trap" >TRAPEXIT
+ ${${ZTST_exe##[^/]*}:-$ZTST_testdir/$ZTST_exe} -fc '
+ fpath=(. $fpath)
+ autoload TRAPEXIT
+ print "Exiting, attempt 1"
+ exit
+ print "What?"
+ '
+ ${${ZTST_exe##[^/]*}:-$ZTST_testdir/$ZTST_exe} -fc '
+ fpath=(. $fpath)
+ autoload TRAPEXIT;
+ fn() { print Some function }
+ fn
+ print "Exiting, attempt 2"
+ exit
+ '
+0: autoloaded TRAPEXIT (exit status > 128 indicates an old bug is back)
+>Exiting, attempt 1
+>Running exit trap
+>Some function
+>Exiting, attempt 2
+>Running exit trap
+
+ print -u $ZTST_fd Another test that takes three seconds
+ gotsig=0
+ signal_handler() {
+ echo "parent received signal"
+ gotsig=1
+ }
+ child() {
+ sleep 1
+ echo "child sending signal"
+ kill -15 $parentpid
+ sleep 2
+ echo "child exiting"
+ exit 33
+ }
+ parentpid=$$
+ child &
+ childpid=$!
+ trap signal_handler 15
+ echo "parent waiting"
+ wait $childpid
+ cstatus=$?
+ echo "wait #1 finished, gotsig=$gotsig, status=$cstatus"
+ gotsig=0
+ wait $childpid
+ cstatus=$?
+ echo "wait #2 finished, gotsig=$gotsig, status=$cstatus"
+0:waiting for trapped signal
+>parent waiting
+>child sending signal
+>parent received signal
+>wait #1 finished, gotsig=1, status=143
+>child exiting
+>wait #2 finished, gotsig=0, status=33
+
+ fn1() {
+ setopt errexit
+ trap 'echo error1' ZERR
+ false
+ print Shouldn\'t get here 1a
+ }
+ fn2() {
+ setopt errexit
+ trap 'echo error2' ZERR
+ return 1
+ print Shouldn\'t get here 2a
+ }
+ fn3() {
+ setopt errexit
+ TRAPZERR() { echo error3; }
+ false
+ print Shouldn\'t get here 3a
+ }
+ fn4() {
+ setopt errexit
+ TRAPZERR() { echo error4; }
+ return 1
+ print Shouldn\'t get here 4a
+ }
+ (fn1; print Shouldn\'t get here 1b)
+ (fn2; print Shouldn\'t get here 2b)
+ (fn3; print Shouldn\'t get here 3b)
+ (fn4; print Shouldn\'t get here 4b)
+1: Combination of ERR_EXIT and ZERR trap
+>error1
+>error2
+>error3
+>error4
+
+ fn1() { TRAPZERR() { print trap; return 42; }; false; print Broken; }
+ (fn1)
+ print Working $?
+0: Force return of containing function from TRAPZERR.
+>trap
+>Working 42
+
+ fn2() { trap 'print trap; return 42' ZERR; false; print Broken }
+ (fn2)
+ print Working $?
+0: Return with non-zero status triggered from within trap '...' ZERR.
+>trap
+>Working 42
+
+ fn3() { TRAPZERR() { print trap; return 0; }; false; print OK this time; }
+ (fn3)
+ print Working $?
+0: Normal return from TRAPZERR.
+>trap
+>OK this time
+>Working 0
+
+ fn4() { trap 'print trap; return 0' ZERR; false; print Broken; }
+ (fn4)
+ print Working $?
+0: Return with zero status triggered from within trap '...' ZERR.
+>trap
+>Working 0
+
+ { trap 'echo This subshell is exiting' EXIT; } | cat
+0: EXIT trap set in current shell at left of pipeline
+>This subshell is exiting
+
+ ( trap 'echo This subshell is also exiting' EXIT; ) | cat
+0: EXIT trap set in subshell at left of pipeline
+>This subshell is also exiting
+
+ ( trap 'echo Should only appear once at the end' EXIT
+ ( : trap reset here ) | cat
+ : trap not reset but not part of shell command list | cat
+ echo nothing after this should appear $( : trap reset here too)
+ )
+0: EXIT trap set in subshell reset in subsubshell
+>nothing after this should appear
+>Should only appear once at the end
+
+ echo $( trap 'echo command substitution exited' EXIT )
+0: EXIT trap set in command substitution
+>command substitution exited
+
+ (cd ..; $ZTST_exe -fc 'setopt posixtraps;
+ TRAPEXIT() { print Exited; }
+ fn1() { trap; }
+ setopt localtraps # should be ignored by EXIT
+ fn2() { TRAPEXIT() { print No, really exited; } }
+ fn1
+ fn2
+ fn1')
+0:POSIX_TRAPS option
+>TRAPEXIT () {
+> print Exited
+>}
+>TRAPEXIT () {
+> print No, really exited
+>}
+>No, really exited
+
+ (cd ..; $ZTST_exe -fc 'unsetopt posixtraps;
+ echo start program
+ emulate sh -c '\''testfn() {
+ echo start function
+ set -o | grep posixtraps
+ trap "echo EXIT TRAP TRIGGERED" EXIT
+ echo end function
+ }'\''
+ testfn
+ echo program continuing
+ echo end of program')
+0:POSIX_TRAPS effect on EXIT trap is sticky
+>start program
+>start function
+>noposixtraps off
+>end function
+>program continuing
+>end of program
+>EXIT TRAP TRIGGERED
+
+ (cd ..; $ZTST_exe -fc '
+ echo entering program
+ emulate sh -c '\''trap "echo POSIX exit trap triggered" EXIT'\''
+ fn() {
+ trap "echo native zsh function-local exit trap triggered" EXIT
+ echo entering native zsh function
+ }
+ fn
+ echo exiting program
+ ')
+0:POSIX EXIT trap can have nested native mode EXIT trap
+>entering program
+>entering native zsh function
+>native zsh function-local exit trap triggered
+>exiting program
+>POSIX exit trap triggered
+
+ (cd ..; $ZTST_exe -fc '
+ echo entering program
+ emulate sh -c '\''spt() { trap "echo POSIX exit trap triggered" EXIT; }'\''
+ fn() {
+ trap "echo native zsh function-local exit trap triggered" EXIT
+ echo entering native zsh function
+ }
+ spt
+ fn
+ echo exiting program
+ ')
+0:POSIX EXIT trap not replaced if defined within function
+>entering program
+>entering native zsh function
+>native zsh function-local exit trap triggered
+>exiting program
+>POSIX exit trap triggered
+
+ (set -e
+ printf "a\nb\n" | while read line
+ do
+ [[ $line = a* ]] || continue
+ ((ctr++))
+ [[ $line = foo ]]
+ done
+ echo "ctr = $ctr"
+ )
+1:ERREXIT in loop with simple commands
+
+ fn() {
+ emulate -L zsh
+ setopt errreturn
+ if false; then
+ false
+ print No.
+ else
+ print Oh, yes
+ fi
+ }
+ fn
+0:ERR_RETURN not triggered in if condition
+>Oh, yes
+
+ fn() {
+ emulate -L zsh
+ setopt errreturn
+ if true; then
+ false
+ print No.
+ else
+ print No, no.
+ fi
+ }
+ fn
+1:ERR_RETURN in "if"
+
+ fn() {
+ emulate -L zsh
+ setopt errreturn
+ if false; then
+ print No.
+ else
+ false
+ print No, no.
+ fi
+ }
+ fn
+1:ERR_RETURN in "else" branch (regression test)
+
+ $ZTST_testdir/../Src/zsh -f =(<<<"
+ if false; then
+ :
+ else
+ if [[ -n '' ]]; then
+ a=2
+ fi
+ print Yes
+ fi
+ ")
+0:ERR_RETURN when false "if" is the first statement in an "else" (regression)
+>Yes
+F:Must be tested with a top-level script rather than source or function
+
+ fn() {
+ emulate -L zsh
+ setopt errreturn
+ print before
+ false
+ print after
+ }
+ fn
+1:ERR_RETURN, basic case
+>before
+
+ fn() {
+ emulate -L zsh
+ setopt errreturn
+ print before
+ ! true
+ ! false
+ print after
+ }
+ fn
+0:ERR_RETURN with "!"
+>before
+>after
+
+ fn() {
+ emulate -L zsh
+ setopt errreturn
+ print before
+ ! true
+ ! false
+ false
+ print after
+ }
+ fn
+1:ERR_RETURN with "!" and a following false
+>before
+
+ fn() {
+ emulate -L zsh
+ setopt errreturn
+ print before
+ ! if true; then
+ false
+ fi
+ print after
+ }
+ fn
+0:ERR_RETURN with "!" suppressed inside complex structure
+>before
+>after
+
+ fn() {
+ emulate -L zsh
+ setopt errreturn
+ print before
+ if true; then
+ false
+ fi
+ print after
+ }
+ fn
+1:ERR_RETURN with no "!" suppression (control case)
+>before
+
+ (setopt err_return
+ fn() {
+ print before-in
+ false && false
+ }
+ print before-out
+ fn
+ print after-out
+ )
+1:ERR_RETURN with "&&" in function (regression test)
+>before-out
+>before-in
+
+ (setopt err_return
+ fn() {
+ print before-in
+ false && false
+ print after-in
+ }
+ print before-out
+ fn
+ print after-out
+ )
+0:ERR_RETURN not triggered on LHS of "&&" in function
+>before-out
+>before-in
+>after-in
+>after-out
+
+ (setopt err_return
+ fn() {
+ print before-in
+ true && false
+ print after-in
+ }
+ print before-out
+ fn
+ print after-out
+ )
+1:ERR_RETURN triggered on RHS of "&&" in function
+>before-out
+>before-in
+
+ (setopt err_exit
+ for x in y; do
+ false && true
+ done
+ print OK
+ )
+0:ERR_EXIT not triggered by status 1 at end of for
+>OK
+
+ (setopt err_exit
+ integer x=0
+ while (( ! x++ )); do
+ false && true
+ done
+ print OK
+ )
+0:ERR_EXIT not triggered by status 1 at end of while
+>OK
+
+ (setopt err_exit
+ repeat 1; do
+ false && true
+ done
+ print OK
+ )
+0:ERR_EXIT not triggered by status 1 at end of repeat
+>OK
+
+ (setopt err_exit
+ if true; then
+ false && true
+ fi
+ print OK
+ )
+0:ERR_EXIT not triggered by status 1 at end of if
+>OK
+
+ (setopt err_exit
+ {
+ false && true
+ }
+ print OK
+ )
+0:ERR_EXIT not triggered by status 1 at end of { }
+>OK
+
+ (setopt err_exit
+ for x in y; do
+ false
+ done
+ print OK
+ )
+1:ERR_EXIT triggered by status 1 within for
+
+ (setopt err_exit
+ integer x=0
+ while (( ! x++ )); do
+ false
+ done
+ print OK
+ )
+1:ERR_EXIT triggered by status 1 within while
+
+ (setopt err_exit
+ repeat 1; do
+ false
+ done
+ print OK
+ )
+1:ERR_EXIT triggered by status 1 within repeat
+
+ (setopt err_exit
+ if true; then
+ false
+ fi
+ print OK
+ )
+1:ERR_EXIT triggered by status 1 within if
+
+ (setopt err_exit
+ {
+ false
+ }
+ print OK
+ )
+1:ERR_EXIT triggered by status 1 within { }
+
+ (setopt err_exit
+ () {
+ false && true
+ print Still functioning
+ false && true
+ }
+ print OK
+ )
+1:ERR_EXIT triggered by status 1 at end of anon func
+>Still functioning
+
+ if zmodload zsh/system 2>/dev/null; then
+ (
+ trap 'echo TERM; exit 2' TERM
+ trap 'echo EXIT' EXIT
+ kill -s TERM "$sysparams[pid]"
+ echo 'FATAL: we should never get here!' 1>&2
+ exit 1
+ )
+ else
+ ZTST_skip="zsh/system library not found."
+ fi
+2:EXIT trap from TERM trap
+>TERM
+>EXIT
+
+ # Should not get "hello" in the single quotes.
+ (
+ trap "echo hello" EXIT;
+ { :; } | { read line; print "'$line'"; }
+ )
+0:EXIT trap not called in LHS of pipeline: Shell construct on LHS
+>''
+>hello
+
+ (
+ trap "echo hello" EXIT;
+ cat </dev/null | { read line; print "'$line'"; }
+ )
+0:EXIT trap not called in LHS of pipeline: External command on LHS
+>''
+>hello
+
+%clean
+
+ rm -f TRAPEXIT
diff --git a/dotfiles/system/.zsh/modules/Test/C04funcdef.ztst b/dotfiles/system/.zsh/modules/Test/C04funcdef.ztst
new file mode 100644
index 0000000..0cf2b58
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/C04funcdef.ztst
@@ -0,0 +1,502 @@
+%prep
+
+ mkdir funcdef.tmp
+ cd funcdef.tmp
+ setopt chaselinks
+ cd .
+ unsetopt chaselinks
+ mydir=$PWD
+
+%test
+
+ fn1() { return 1; }
+ fn2() {
+ fn1
+ print $?
+ return 2
+ }
+ fn2
+2:Basic status returns from functions
+>1
+
+ fnz() { }
+ false
+ fnz
+0:Empty function body resets status
+
+ fn3() { return 3; }
+ fnstat() { print $?; }
+ fn3
+ fnstat
+0:Status is not reset on non-empty function body
+>3
+
+ function f$$ () {
+ print regress expansion of function names
+ }
+ f$$
+0:Regression test: 'function f$$ () { ... }'
+>regress expansion of function names
+
+ function foo () print bar
+ foo
+0:Function definition without braces
+>bar
+
+ functions -M m1
+ m1() { (( $# )) }
+ print $(( m1() ))
+ print $(( m1(1) ))
+ print $(( m1(1,2) ))
+0:User-defined math functions, argument handling
+>0
+>1
+>2
+
+ functions -M m2
+ m2() {
+ integer sum
+ local val
+ for val in $*; do
+ (( sum += $val ))
+ done
+ }
+ print $(( m2(1) ))
+ print $(( m2(1,3+3,4**2) ))
+0:User-defined math functions, complex argument handling
+>1
+>23
+
+ functions -M m3 1 2
+ m3() { (( 1 )) }
+ print zero
+ (print $(( m3() )))
+ print one
+ print $(( m3(1) ))
+ print two
+ print $(( m3(1,2) ))
+ print three
+ (print $(( m3(1,2,3) )))
+1:User-defined math functions, argument checking
+>zero
+>one
+>1
+>two
+>1
+>three
+?(eval):4: wrong number of arguments: m3()
+?(eval):10: wrong number of arguments: m3(1,2,3)
+
+ functions -M m4 0 0 testmathfunc
+ functions -M m5 0 0 testmathfunc
+ testmathfunc() {
+ if [[ $0 = m4 ]]; then
+ (( 4 ))
+ else
+ (( 5 ))
+ fi
+ }
+ print $(( m4() ))
+ print $(( m5() ))
+0:User-defined math functions, multiple interfaces
+>4
+>5
+
+ command_not_found_handler() {
+ print "Great News! I've handled the command:"
+ print "$1"
+ print "with arguments:"
+ print -l ${argv[2,-1]}
+ }
+ ACommandWhichHadBetterNotExistOnTheSystem and some "really useful" args
+0:Command not found handler, success
+>Great News! I've handled the command:
+>ACommandWhichHadBetterNotExistOnTheSystem
+>with arguments:
+>and
+>some
+>really useful
+>args
+
+# ' deconfuse emacs
+
+ command_not_found_handler() {
+ print "Your command:" >&2
+ print "$1" >&2
+ print "has gone down the tubes. Sorry." >&2
+ return 42
+ }
+ ThisCommandDoesNotExistEither
+42:Command not found handler, failure
+?Your command:
+?ThisCommandDoesNotExistEither
+?has gone down the tubes. Sorry.
+
+ local variable=outside
+ print "I am $variable"
+ function {
+ local variable=inside
+ print "I am $variable"
+ }
+ print "I am $variable"
+ () {
+ local variable="inside again"
+ print "I am $variable"
+ }
+ print "I am $variable"
+0:Anonymous function scope
+>I am outside
+>I am inside
+>I am outside
+>I am inside again
+>I am outside
+
+ integer i
+ for (( i = 0; i < 10; i++ )); do function {
+ case $i in
+ ([13579])
+ print $i is odd
+ ;|
+ ([2468])
+ print $i is even
+ ;|
+ ([2357])
+ print $i is prime
+ ;;
+ esac
+ }; done
+0:Anonymous function with patterns in loop
+>1 is odd
+>2 is even
+>2 is prime
+>3 is odd
+>3 is prime
+>4 is even
+>5 is odd
+>5 is prime
+>6 is even
+>7 is odd
+>7 is prime
+>8 is even
+>9 is odd
+
+ echo stuff in file >file.in
+ function {
+ sed 's/stuff/rubbish/'
+ } <file.in >file.out
+ cat file.out
+0:Anonymous function redirection
+>rubbish in file
+
+ variable="Do be do"
+ print $variable
+ function {
+ print $variable
+ local variable="Da de da"
+ print $variable
+ function {
+ print $variable
+ local variable="Dum da dum"
+ print $variable
+ }
+ print $variable
+ }
+ print $variable
+0:Nested anonymous functions
+>Do be do
+>Do be do
+>Da de da
+>Da de da
+>Dum da dum
+>Da de da
+>Do be do
+
+ () (cat $1 $2) <(print process expanded) =(print expanded to file)
+0:Process substitution with anonymous functions
+>process expanded
+>expanded to file
+
+ () { print This has arguments $*; } of all sorts; print After the function
+ function { print More stuff $*; } and why not; print Yet more
+0:Anonymous function with arguments
+>This has arguments of all sorts
+>After the function
+>More stuff and why not
+>Yet more
+
+ fn() {
+ (){ print Anonymous function 1 $*; } with args
+ function { print Anonymous function 2 $*; } with more args
+ print Following bit
+ }
+ functions fn
+0:Text representation of anonymous function with arguments
+>fn () {
+> () {
+> print Anonymous function 1 $*
+> } with args
+> () {
+> print Anonymous function 2 $*
+> } with more args
+> print Following bit
+>}
+
+ touch yes no
+ () { echo $1 } (y|z)*
+ (echo here)
+ () { echo $* } some (y|z)*
+ () { echo empty };(echo here)
+0:Anonymous function arguments and command arguments
+>yes
+>here
+>some yes
+>empty
+>here
+
+ if true; then f() { echo foo1; } else f() { echo bar1; } fi; f
+ if false; then f() { echo foo2; } else f() { echo bar2; } fi; f
+0:Compatibility with other shells when not anonymous functions
+>foo1
+>bar2
+
+ (
+ setopt ignorebraces
+ fpath=(.)
+ print "{ echo OK }\n[[ -o ignorebraces ]] || print 'ignorebraces is off'" \
+ >emufunctest
+ (autoload -z emufunctest; emufunctest) 2>&1
+ emulate zsh -c 'autoload -Uz emufunctest'
+ emufunctest
+ [[ -o ignorebraces ]] && print 'ignorebraces is still on here'
+ )
+0:sticky emulation applies to autoloads and autoloaded function execution
+>emufunctest:3: parse error near `\n'
+>OK
+>ignorebraces is off
+>ignorebraces is still on here
+#` (matching error message for editors parsing the file)
+
+# 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
+>anon func
+>lsfoo
+
+ print foo | () cat
+0:Simple anonymous function should not simplify enclosing pipeline
+>foo
+
+ alias fooalias=barexpansion
+ funcwithalias() { echo $(fooalias); }
+ functions funcwithalias
+ barexpansion() { print This is the correct output.; }
+ funcwithalias
+0:Alias expanded in command substitution does not appear expanded in text
+>funcwithalias () {
+> echo $(fooalias)
+>}
+>This is the correct output.
+
+ unfunction command_not_found_handler # amusing but unhelpful
+ alias first='firstfn1 firstfn2' second='secondfn1 secondfn2'
+ function first second { print This is function $0; }
+ first
+ second
+ firstfn1
+ secondfn1
+127:No alias expansion after "function" keyword
+>This is function first
+>This is function second
+?(eval):6: command not found: firstfn1
+?(eval):7: command not found: secondfn1
+
+ (
+ fpath=(.)
+ print "print oops was successfully autoloaded" >oops
+ oops() { eval autoload -X }
+ oops
+ which -x2 oops
+ )
+0:autoload containing eval
+>oops was successfully autoloaded
+>oops () {
+> print oops was successfully autoloaded
+>}
+
+ (
+ fpath=(.)
+ printf '%s\n' 'oops(){}' 'ninjas-earring(){}' 'oops "$@"' >oops
+ autoload oops
+ oops
+ whence -v oops
+ )
+0q:whence -v of zsh-style autoload
+>oops is a shell function from $mydir/oops
+
+ (
+ fpath=(.)
+ mkdir extra
+ print 'print "I have been loaded by explicit path."' >extra/spec
+ autoload -Uz $PWD/extra/spec
+ spec
+ )
+0:autoload with explicit path
+>I have been loaded by explicit path.
+
+ (
+ fpath=(.)
+ print 'print "I have been loaded by default path."' >def
+ autoload -Uz $PWD/extra/def
+ def
+ )
+1:autoload with explicit path with function in normal path, no -d
+?(eval):5: def: function definition file not found
+
+ (
+ fpath=(.)
+ autoload -dUz $PWD/extra/def
+ def
+ )
+0:autoload with explicit path with function in normal path, with -d
+>I have been loaded by default path.
+
+ (
+ cd extra
+ fpath=(.)
+ autoload -r spec
+ cd ..
+ spec
+ )
+0:autoload -r
+>I have been loaded by explicit path.
+
+ (
+ cd extra
+ fpath=(.)
+ autoload -r def
+ cd ..
+ def
+ )
+0:autoload -r is permissive
+>I have been loaded by default path.
+
+ (
+ cd extra
+ fpath=(.)
+ autoload -R def
+ )
+1:autoload -R is not permissive
+?(eval):4: def: function definition file not found
+
+ (
+ spec() { autoload -XUz $PWD/extra; }
+ spec
+ )
+0:autoload -X with path
+>I have been loaded by explicit path.
+
+# The line number 1 here and in the next test seems suspect,
+# but this example proves it's not down to the new features
+# being tested here.
+ (
+ fpath=(.)
+ cod() { autoload -XUz; }
+ cod
+ )
+1:autoload -X with no path, failure
+?(eval):1: cod: function definition file not found
+
+ (
+ fpath=(.)
+ def() { autoload -XUz $PWD/extra; }
+ def
+ )
+1:autoload -X with wrong path and no -d
+?(eval):1: def: function definition file not found
+
+ (
+ fpath=(.)
+ def() { autoload -dXUz $PWD/extra; }
+ def
+ )
+0:autoload -dX with path
+>I have been loaded by default path.
+
+ (
+ fpath=(.)
+ print 'loadthisfunc() { autoload -X }' >loadthisfunc_sourceme
+ print 'print Function was loaded correctly.' >loadthisfunc
+ source $PWD/loadthisfunc_sourceme
+ loadthisfunc
+ )
+0: autoload -X interaction with absolute filename used for source location
+>Function was loaded correctly.
+
+ (
+ fpath=()
+ mkdir extra2
+ for f in fun2a fun2b; do
+ print "print $f" >extra2/$f
+ done
+ repeat 3; do
+ autoload $PWD/extra2/fun2{a,b} $PWD/extra/spec
+ fun2a
+ fun2b
+ spec
+ unfunction fun2a fun2b spec
+ autoload $PWD/extra2/fun2{a,b} $PWD/extra/spec
+ spec
+ fun2b
+ fun2a
+ unfunction fun2a fun2b spec
+ done
+ )
+0: Exercise the directory name cache for autoloads
+>fun2a
+>fun2b
+>I have been loaded by explicit path.
+>I have been loaded by explicit path.
+>fun2b
+>fun2a
+>fun2a
+>fun2b
+>I have been loaded by explicit path.
+>I have been loaded by explicit path.
+>fun2b
+>fun2a
+>fun2a
+>fun2b
+>I have been loaded by explicit path.
+>I have been loaded by explicit path.
+>fun2b
+>fun2a
+
+ not_trashed() { print This function was not trashed; }
+ autoload -Uz /foo/bar/not_trashed
+ not_trashed
+0:autoload with absolute path doesn't trash loaded function
+>This function was not trashed
+
+ # keep spec from getting loaded in parent shell for simplicity
+ (
+ if whence spec; then print spec already loaded >&2; exit 1; fi
+ autoload -Uz $PWD/spec
+ autoload -Uz $PWD/extra/spec
+ spec
+ )
+0:autoload with absolute path can be overridden if not yet loaded
+>I have been loaded by explicit path.
+
+ (
+ if whence spec; then print spec already loaded >&2; exit 1; fi
+ autoload -Uz $PWD/extra/spec
+ autoload spec
+ spec
+ )
+0:autoload with absolute path not cancelled by bare autoload
+>I have been loaded by explicit path.
+
+%clean
+
+ rm -f file.in file.out
diff --git a/dotfiles/system/.zsh/modules/Test/C05debug.ztst b/dotfiles/system/.zsh/modules/Test/C05debug.ztst
new file mode 100644
index 0000000..9a8df1d
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/C05debug.ztst
@@ -0,0 +1,159 @@
+%prep
+
+ setopt localtraps
+
+%test
+
+ unsetopt DEBUG_BEFORE_CMD
+ debug-trap-bug1() {
+ setopt localtraps
+ print "print bug file here" >bug-file
+ print "print this is line one
+ print this is line two
+ print this is line three
+ print and this is line fifty-nine." >bug-file2
+ function debug_trap_handler {
+ print $functrace[1]
+ do_bug
+ }
+ function do_bug {
+ . ./bug-file
+ }
+ trap 'echo EXIT hit' EXIT
+ trap 'debug_trap_handler' DEBUG
+ . ./bug-file2
+ }
+ debug-trap-bug1
+0: Relationship between traps and sources
+>debug-trap-bug1:15
+>bug file here
+>this is line one
+>./bug-file2:1
+>bug file here
+>this is line two
+>./bug-file2:2
+>bug file here
+>this is line three
+>./bug-file2:3
+>bug file here
+>and this is line fifty-nine.
+>./bug-file2:4
+>bug file here
+>debug-trap-bug1:16
+>bug file here
+>EXIT hit
+
+ cat >zsh-trapreturn-bug2 <<-'HERE'
+ cmd='./fdasfsdafd'
+ [[ -x $cmd ]] && rm $cmd
+ set -o DEBUG_BEFORE_CMD
+ trap '[[ $? -ne 0 ]] && exit 0' DEBUG
+ $cmd # invalid command
+ # Failure
+ exit 10
+ HERE
+ $ZTST_testdir/../Src/zsh -f ./zsh-trapreturn-bug2 2>erroutput.dif
+ mystat=$?
+ (
+ setopt extendedglob
+ print ${"$(< erroutput.dif)"%%:[^:]#: ./fdasfsdafd}
+ )
+ (( mystat == 0 ))
+0: trapreturn handling bug is properly fixed
+>./zsh-trapreturn-bug2:5
+
+ fn() {
+ setopt localtraps localoptions debugbeforecmd
+ trap '(( LINENO == 4 )) && setopt errexit' DEBUG
+ print $LINENO three
+ print $LINENO four
+ print $LINENO five
+ [[ -o errexit ]] && print "Hey, ERREXIT is set!"
+ }
+ fn
+1:Skip line from DEBUG trap
+>3 three
+>5 five
+
+ # Assignments are a special case, since they use a simpler
+ # wordcode type, so we need to test skipping them separately.
+ fn() {
+ setopt localtraps localoptions debugbeforecmd
+ trap '(( LINENO == 4 )) && setopt errexit' DEBUG
+ x=three
+ x=four
+ print $LINENO $x
+ [[ -o errexit ]] && print "Hey, ERREXIT is set!"
+ }
+ fn
+1:Skip assignment from DEBUG trap
+>5 three
+
+ fn() {
+ setopt localtraps localoptions debugbeforecmd
+ trap 'print $LINENO' DEBUG
+ [[ a = a ]] && print a is ok
+ }
+ fn
+0:line numbers of complex sublists
+>3
+>a is ok
+
+ fn() {
+ setopt localtraps localoptions debugbeforecmd
+ trap 'print $LINENO' DEBUG
+ print before
+ x=' first
+ second
+ third'
+ print $x
+ }
+ fn
+0:line numbers of multiline assignments
+>3
+>before
+>4
+>7
+> first
+> second
+> third
+
+ fn() {
+ emulate -L zsh; setopt debugbeforecmd
+ trap 'print "$LINENO: '\''$ZSH_DEBUG_CMD'\''"' DEBUG
+ print foo &&
+ print bar ||
+ print rod
+ x=y
+ print $x
+ fn2() { echo wow }
+ fn2
+ }
+ fn
+0:ZSH_DEBUG_CMD in debug traps
+>3: 'print foo && print bar || print rod'
+>foo
+>bar
+>6: 'x=y '
+>7: 'print $x'
+>y
+>8: 'fn2 () {
+> echo wow
+>}'
+>9: 'fn2'
+>0: 'echo wow'
+>wow
+
+ foo() {
+ emulate -L zsh; setopt debugbeforecmd
+ trap '[[ $ZSH_DEBUG_CMD == *bar* ]] && return 2' DEBUG
+ echo foo
+ echo bar
+ }
+ foo
+2:Status of forced return from eval-style DEBUG trap
+>foo
+
+%clean
+
+ rm -f bug-file bug-file2 erroutput.dif zsh-trapreturn-bug2
diff --git a/dotfiles/system/.zsh/modules/Test/D01prompt.ztst b/dotfiles/system/.zsh/modules/Test/D01prompt.ztst
new file mode 100644
index 0000000..607ffb6
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/D01prompt.ztst
@@ -0,0 +1,203 @@
+%prep
+
+ mkdir prompt.tmp
+ cd prompt.tmp
+ mydir=$PWD
+ SHLVL=2
+ setopt extendedglob
+
+%test
+
+ hash -d mydir=$mydir
+ print -P ' %%%): %)
+ %%~: %~
+ %%d: %d
+ %%1/: %1/
+ %%h: %h
+ %%L: %L
+ %%M: %M
+ %%m: %m
+ %%n: %n
+ %%N: %N
+ %%i: %i
+ a%%{...%%}b: a%{%}b
+ '
+0q:Basic prompt escapes as shown.
+> %): )
+> %~: ~mydir
+> %d: $mydir
+> %1/: ${mydir:t}
+> %h: 0
+> %L: 2
+> %M: $HOST
+> %m: ${HOST%%.*}
+> %n: $USERNAME
+> %N: (eval)
+> %i: 2
+> a%{...%}b: ab
+>
+
+ true
+ print -P '%?'
+ false
+ print -P '%?'
+0:`%?' prompt escape
+>0
+>1
+
+ PS4="%_> "
+ setopt xtrace
+ if true; then true; else false; fi
+ unsetopt xtrace
+0:`%_' prompt escape
+?if> true
+?then> true
+?> unsetopt xtrace
+
+ diff =(print -P '%#') =(print -P '%(!.#.%%)')
+0:`%#' prompt escape and its equivalent
+
+ psvar=(caesar adsum jam forte)
+ print -P '%v' '%4v'
+0:`%v' prompt escape
+>caesar forte
+
+ true
+ print -P '%(?.true.false)'
+ false
+ print -P '%(?.true.false)'
+0:ternary prompt escapes
+>true
+>false
+
+ print -P 'start %10<...<truncated at 10%<< Not truncated%3< ...<Not shown'
+ print -P 'start %10>...>truncated at 10%>> Not truncated%3> ...>Not shown'
+0:prompt truncation
+>start ...d at 10 Not truncated ...
+>start truncat... Not truncated ...
+
+# It's hard to check the time and date as they are moving targets.
+# We therefore just check that various forms of the date are consistent.
+# In fact, if you perform this at midnight it can still fail.
+# We could test for that, but we can't be bothered.
+# I hope LC_ALL is enough to make the format what's expected.
+
+ LC_ALL=C
+ date1=$(print -P %w)
+ date2=$(print -P %W)
+ date3=$(print -P %D)
+ if [[ $date1 != [A-Z][a-z][a-z][[:blank:]]##[0-9]## ]]; then
+ print "Date \`$date1' is not in the form \`Day DD' (e.g. \`Mon 1'"
+ fi
+ if [[ $date2 != [0-9][0-9]/[0-9][0-9]/[0-9][0-9] ]]; then
+ print "Date \`$date2' is not in the form \`DD/MM/YYYY'"
+ fi
+ if [[ $date3 != [0-9][0-9]-[0-9][0-9]-[0-9][0-9] ]]; then
+ print "Date \`$date3' is not in the form \`YY-MM-DD'"
+ fi
+ if (( $date1[5,-1] != $date2[4,5] )) || (( $date2[4,5] != $date3[7,8] ))
+ then
+ print "Days of month do not agree in $date1, $date2, $date3"
+ fi
+ if (( $date2[1,2] != $date3[4,5] )); then
+ print "Months do not agree in $date2, $date3"
+ fi
+ if (( $date2[7,8] != $date3[1,2] )); then
+ print "Years do not agree in $date2, $date3"
+ fi
+0:Dates produced by prompt escapes
+
+ mkdir foo
+ mkdir foo/bar
+ mkdir foo/bar/rod
+ (zsh_directory_name() {
+ emulate -L zsh
+ setopt extendedglob
+ local -a match mbegin mend
+ if [[ $1 = d ]]; then
+ if [[ $2 = (#b)(*bar)/rod ]]; then
+ reply=(barmy ${#match[1]})
+ else
+ return 1
+ fi
+ else
+ if [[ $2 = barmy ]]; then
+ reply=($mydir/foo/bar)
+ else
+ return 1
+ fi
+ fi
+ }
+ # success
+ print ~[barmy]/anything
+ cd foo/bar/rod
+ print -P %~
+ # failure
+ setopt nonomatch
+ print ~[scuzzy]/rubbish
+ cd ../..
+ print -P %~
+ # catastrophic failure
+ unsetopt nonomatch
+ print ~[scuzzy]/rubbish
+ )
+1q:Dynamic named directories
+>$mydir/foo/bar/anything
+>~[barmy]/rod
+>~[scuzzy]/rubbish
+>~mydir/foo
+?(eval):33: no directory expansion: ~[scuzzy]
+
+ (
+ zsh_directory_name() {
+ emulate -L zsh
+ setopt extendedglob
+ local -a match mbegin mend
+ if [[ $1 = n ]]; then
+ if [[ $2 = *:l ]]; then
+ reply=(${2%%:l}/very_long_directory_name)
+ return 0
+ else
+ return 1
+ fi
+ else
+ if [[ $2 = (#b)(*)/very_long_directory_name ]]; then
+ reply=(${match[1]}:l ${#2})
+ return 0
+ else
+ return 1
+ fi
+ fi
+ }
+ parent=$PWD
+ dir=$parent/very_long_directory_name
+ mkdir $dir
+ cd $dir
+ fn() {
+ PS4='+%N:%i> '
+ setopt localoptions xtrace
+ # The following is the key to the test.
+ # It invokes zsh_directory_name which does PS4 output stuff
+ # while we're doing prompt handling for the parameter
+ # substitution. This checks recursion works OK.
+ local d=${(%):-%~}
+ print ${d//$parent/\<parent\>}
+ }
+ fn 2>stderr
+ # post process error to remove variable contents
+ while read line; do
+ # tricky: reply is set to include directory length which is variable
+ [[ $line = *reply* ]] && continue
+ print ${line//$parent/\<parent\>}
+ done <stderr >&2
+ )
+0:Recursive use of prompts
+>~[<parent>:l]
+?+zsh_directory_name:1> emulate -L zsh
+?+zsh_directory_name:2> setopt extendedglob
+?+zsh_directory_name:3> local -a match mbegin mend
+?+zsh_directory_name:4> [[ d = n ]]
+?+zsh_directory_name:12> [[ <parent>/very_long_directory_name = (#b)(*)/very_long_directory_name ]]
+?+zsh_directory_name:14> return 0
+?+fn:7> local d='~[<parent>:l]'
+?+fn:8> print '~[<parent>:l]'
diff --git a/dotfiles/system/.zsh/modules/Test/D02glob.ztst b/dotfiles/system/.zsh/modules/Test/D02glob.ztst
new file mode 100644
index 0000000..1385d57
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/D02glob.ztst
@@ -0,0 +1,688 @@
+# Tests for globbing
+
+%prep
+ mkdir glob.tmp
+ mkdir glob.tmp/dir{1,2,3,4}
+ mkdir glob.tmp/dir3/subdir
+ : >glob.tmp/{,{dir1,dir2}/}{a,b,c}
+
+ globtest () {
+ $ZTST_testdir/../Src/zsh -f $ZTST_srcdir/../Misc/$1
+ }
+
+ regress_absolute_path_and_core_dump() {
+ local absolute_dir=$(cd glob.tmp && pwd -P)
+ [[ -n $absolute_dir ]] || return 1
+ setopt localoptions extendedglob nullglob
+ print $absolute_dir/**/*~/*
+ setopt nonullglob nomatch
+ print glob.tmp/**/*~(.)#
+ }
+
+%test
+
+ globtest globtests
+0:zsh globbing
+>0: [[ foo~ = foo~ ]]
+>0: [[ foo~ = (foo~) ]]
+>0: [[ foo~ = (foo~|) ]]
+>0: [[ foo.c = *.c~boo* ]]
+>1: [[ foo.c = *.c~boo*~foo* ]]
+>0: [[ fofo = (fo#)# ]]
+>0: [[ ffo = (fo#)# ]]
+>0: [[ foooofo = (fo#)# ]]
+>0: [[ foooofof = (fo#)# ]]
+>0: [[ fooofoofofooo = (fo#)# ]]
+>1: [[ foooofof = (fo##)# ]]
+>1: [[ xfoooofof = (fo#)# ]]
+>1: [[ foooofofx = (fo#)# ]]
+>0: [[ ofxoofxo = ((ofo#x)#o)# ]]
+>1: [[ ofooofoofofooo = (fo#)# ]]
+>0: [[ foooxfooxfoxfooox = (fo#x)# ]]
+>1: [[ foooxfooxofoxfooox = (fo#x)# ]]
+>0: [[ foooxfooxfxfooox = (fo#x)# ]]
+>0: [[ ofxoofxo = ((ofo#x)#o)# ]]
+>0: [[ ofoooxoofxo = ((ofo#x)#o)# ]]
+>0: [[ ofoooxoofxoofoooxoofxo = ((ofo#x)#o)# ]]
+>0: [[ ofoooxoofxoofoooxoofxoo = ((ofo#x)#o)# ]]
+>1: [[ ofoooxoofxoofoooxoofxofo = ((ofo#x)#o)# ]]
+>0: [[ ofoooxoofxoofoooxoofxooofxofxo = ((ofo#x)#o)# ]]
+>0: [[ aac = ((a))#a(c) ]]
+>0: [[ ac = ((a))#a(c) ]]
+>1: [[ c = ((a))#a(c) ]]
+>0: [[ aaac = ((a))#a(c) ]]
+>1: [[ baaac = ((a))#a(c) ]]
+>0: [[ abcd = ?(a|b)c#d ]]
+>0: [[ abcd = (ab|ab#)c#d ]]
+>0: [[ acd = (ab|ab#)c#d ]]
+>0: [[ abbcd = (ab|ab#)c#d ]]
+>0: [[ effgz = (bc##d|ef#g?|(h|)i(j|k)) ]]
+>0: [[ efgz = (bc##d|ef#g?|(h|)i(j|k)) ]]
+>0: [[ egz = (bc##d|ef#g?|(h|)i(j|k)) ]]
+>0: [[ egzefffgzbcdij = (bc##d|ef#g?|(h|)i(j|k))# ]]
+>1: [[ egz = (bc##d|ef##g?|(h|)i(j|k)) ]]
+>0: [[ ofoofo = (ofo##)# ]]
+>0: [[ oxfoxoxfox = (oxf(ox)##)# ]]
+>1: [[ oxfoxfox = (oxf(ox)##)# ]]
+>0: [[ ofoofo = (ofo##|f)# ]]
+>0: [[ foofoofo = (foo|f|fo)(f|ofo##)# ]]
+>0: [[ oofooofo = (of|oofo##)# ]]
+>0: [[ fffooofoooooffoofffooofff = (f#o#)# ]]
+>1: [[ fffooofoooooffoofffooofffx = (f#o#)# ]]
+>0: [[ fofoofoofofoo = (fo|foo)# ]]
+>0: [[ foo = ((^x)) ]]
+>0: [[ foo = ((^x)*) ]]
+>1: [[ foo = ((^foo)) ]]
+>0: [[ foo = ((^foo)*) ]]
+>0: [[ foobar = ((^foo)) ]]
+>0: [[ foobar = ((^foo)*) ]]
+>1: [[ foot = z*~*x ]]
+>0: [[ zoot = z*~*x ]]
+>1: [[ foox = z*~*x ]]
+>1: [[ zoox = z*~*x ]]
+>0: [[ moo.cow = (*~*.*).(*~*.*) ]]
+>1: [[ mad.moo.cow = (*~*.*).(*~*.*) ]]
+>0: [[ moo.cow = (^*.*).(^*.*) ]]
+>1: [[ sane.moo.cow = (^*.*).(^*.*) ]]
+>1: [[ mucca.pazza = mu(^c#)?.pa(^z#)? ]]
+>1: [[ _foo~ = _(|*[^~]) ]]
+>0: [[ fff = ((^f)) ]]
+>0: [[ fff = ((^f)#) ]]
+>0: [[ fff = ((^f)##) ]]
+>0: [[ ooo = ((^f)) ]]
+>0: [[ ooo = ((^f)#) ]]
+>0: [[ ooo = ((^f)##) ]]
+>0: [[ foo = ((^f)) ]]
+>0: [[ foo = ((^f)#) ]]
+>0: [[ foo = ((^f)##) ]]
+>1: [[ f = ((^f)) ]]
+>1: [[ f = ((^f)#) ]]
+>1: [[ f = ((^f)##) ]]
+>0: [[ foot = (^z*|*x) ]]
+>1: [[ zoot = (^z*|*x) ]]
+>0: [[ foox = (^z*|*x) ]]
+>0: [[ zoox = (^z*|*x) ]]
+>0: [[ foo = (^foo)# ]]
+>1: [[ foob = (^foo)b* ]]
+>0: [[ foobb = (^foo)b* ]]
+>1: [[ foob = (*~foo)b* ]]
+>0: [[ foobb = (*~foo)b* ]]
+>1: [[ zsh = ^z* ]]
+>0: [[ a%1X = [[:alpha:][:punct:]]#[[:digit:]][^[:lower:]] ]]
+>1: [[ a%1 = [[:alpha:][:punct:]]#[[:digit:]][^[:lower:]] ]]
+>0: [[ [: = [[:]# ]]
+>0: [[ :] = []:]# ]]
+>0: [[ :] = [:]]# ]]
+>0: [[ [ = [[] ]]
+>0: [[ ] = []] ]]
+>0: [[ [] = [^]]] ]]
+>0: [[ fooxx = (#i)FOOXX ]]
+>1: [[ fooxx = (#l)FOOXX ]]
+>0: [[ FOOXX = (#l)fooxx ]]
+>1: [[ fooxx = (#i)FOO(#I)X(#i)X ]]
+>0: [[ fooXx = (#i)FOO(#I)X(#i)X ]]
+>0: [[ fooxx = ((#i)FOOX)x ]]
+>1: [[ fooxx = ((#i)FOOX)X ]]
+>1: [[ BAR = (bar|(#i)foo) ]]
+>0: [[ FOO = (bar|(#i)foo) ]]
+>0: [[ Modules = (#i)*m* ]]
+>0: [[ fooGRUD = (#i)(bar|(#I)foo|(#i)rod)grud ]]
+>1: [[ FOOGRUD = (#i)(bar|(#I)foo|(#i)rod)grud ]]
+>0: [[ readme = (#i)readme~README|readme ]]
+>0: [[ readme = (#i)readme~README|readme~README ]]
+>0: [[ 633 = <1-1000>33 ]]
+>0: [[ 633 = <-1000>33 ]]
+>0: [[ 633 = <1->33 ]]
+>0: [[ 633 = <->33 ]]
+>0: [[ 12345678901234567890123456789012345678901234567890123456789012345678901234567890foo = <42->foo ]]
+>0: [[ READ.ME = (#ia1)readme ]]
+>1: [[ READ..ME = (#ia1)readme ]]
+>0: [[ README = (#ia1)readm ]]
+>0: [[ READM = (#ia1)readme ]]
+>0: [[ README = (#ia1)eadme ]]
+>0: [[ EADME = (#ia1)readme ]]
+>0: [[ READEM = (#ia1)readme ]]
+>1: [[ ADME = (#ia1)readme ]]
+>1: [[ README = (#ia1)read ]]
+>0: [[ bob = (#a1)[b][b] ]]
+>1: [[ bob = (#a1)[b][b]a ]]
+>0: [[ bob = (#a1)[b]o[b]a ]]
+>1: [[ bob = (#a1)[c]o[b] ]]
+>0: [[ abcd = (#a2)XbcX ]]
+>0: [[ abcd = (#a2)ad ]]
+>0: [[ ad = (#a2)abcd ]]
+>0: [[ abcd = (#a2)bd ]]
+>0: [[ bd = (#a2)abcd ]]
+>0: [[ badc = (#a2)abcd ]]
+>0: [[ adbc = (#a2)abcd ]]
+>1: [[ dcba = (#a2)abcd ]]
+>0: [[ dcba = (#a3)abcd ]]
+>0: [[ aabaXaaabY = (#a1)(a#b)#Y ]]
+>0: [[ aabaXaaabY = (#a1)(a#b)(a#b)Y ]]
+>0: [[ aaXaaaaabY = (#a1)(a#b)(a#b)Y ]]
+>0: [[ aaaXaaabY = (#a1)(a##b)##Y ]]
+>0: [[ aaaXbaabY = (#a1)(a##b)##Y ]]
+>1: [[ read.me = (#ia1)README~READ.ME ]]
+>0: [[ read.me = (#ia1)README~READ_ME ]]
+>1: [[ read.me = (#ia1)README~(#a1)READ_ME ]]
+>0: [[ test = *((#s)|/)test((#e)|/)* ]]
+>0: [[ test/path = *((#s)|/)test((#e)|/)* ]]
+>0: [[ path/test = *((#s)|/)test((#e)|/)* ]]
+>0: [[ path/test/ohyes = *((#s)|/)test((#e)|/)* ]]
+>1: [[ atest = *((#s)|/)test((#e)|/)* ]]
+>1: [[ testy = *((#s)|/)test((#e)|/)* ]]
+>1: [[ testy/path = *((#s)|/)test((#e)|/)* ]]
+>1: [[ path/atest = *((#s)|/)test((#e)|/)* ]]
+>1: [[ atest/path = *((#s)|/)test((#e)|/)* ]]
+>1: [[ path/testy = *((#s)|/)test((#e)|/)* ]]
+>1: [[ path/testy/ohyes = *((#s)|/)test((#e)|/)* ]]
+>1: [[ path/atest/ohyes = *((#s)|/)test((#e)|/)* ]]
+>0: [[ XabcdabcY = X(ab|c|d)(#c5)Y ]]
+>0: [[ XabcdabcY = X(ab|c|d)(#c1,5)Y ]]
+>0: [[ XabcdabcY = X(ab|c|d)(#c5,8)Y ]]
+>0: [[ XabcdabcY = X(ab|c|d)(#c4,)Y ]]
+>1: [[ XabcdabcY = X(ab|c|d)(#c6,)Y ]]
+>1: [[ XabcdabcY = X(ab|c|d)(#c1,4)Y ]]
+>0: [[ ZX = Z(|)(#c1)X ]]
+>0: [[ froofroo = (fro(#c2))(#c2) ]]
+>1: [[ froofroofroo = (fro(#c2))(#c2) ]]
+>1: [[ froofro = (fro(#c2))(#c2) ]]
+>0: [[ ax = ?(#c1,2)x ]]
+>0: [[ ax = ?(#c1,)x ]]
+>0: [[ ax = ?(#c0,1)x ]]
+>1: [[ ax = ?(#c0,0)x ]]
+>1: [[ ax = ?(#c2,)x ]]
+>0: [[ aa = a(#c1,2)a ]]
+>0: [[ aa = a(#c1,)a ]]
+>0: [[ aa = a(#c0,1)a ]]
+>1: [[ aa = a(#c0,0)a ]]
+>1: [[ aa = a(#c2,)a ]]
+>0: [[ test.zsh = *.?(#c1)sh ]]
+>0: [[ test.bash = *.?(#c2)sh ]]
+>0: [[ test.bash = *.?(#c1,2)sh ]]
+>0: [[ test.bash = *.?(#c1,)sh ]]
+>0: [[ test.zsh = *.?(#c1,)sh ]]
+>0 tests failed.
+
+ globtest globtests.ksh
+0:ksh compatibility
+>0: [[ fofo = *(f*(o)) ]]
+>0: [[ ffo = *(f*(o)) ]]
+>0: [[ foooofo = *(f*(o)) ]]
+>0: [[ foooofof = *(f*(o)) ]]
+>0: [[ fooofoofofooo = *(f*(o)) ]]
+>1: [[ foooofof = *(f+(o)) ]]
+>1: [[ xfoooofof = *(f*(o)) ]]
+>1: [[ foooofofx = *(f*(o)) ]]
+>0: [[ ofxoofxo = *(*(of*(o)x)o) ]]
+>1: [[ ofooofoofofooo = *(f*(o)) ]]
+>0: [[ foooxfooxfoxfooox = *(f*(o)x) ]]
+>1: [[ foooxfooxofoxfooox = *(f*(o)x) ]]
+>0: [[ foooxfooxfxfooox = *(f*(o)x) ]]
+>0: [[ ofxoofxo = *(*(of*(o)x)o) ]]
+>0: [[ ofoooxoofxo = *(*(of*(o)x)o) ]]
+>0: [[ ofoooxoofxoofoooxoofxo = *(*(of*(o)x)o) ]]
+>0: [[ ofoooxoofxoofoooxoofxoo = *(*(of*(o)x)o) ]]
+>1: [[ ofoooxoofxoofoooxoofxofo = *(*(of*(o)x)o) ]]
+>0: [[ ofoooxoofxoofoooxoofxooofxofxo = *(*(of*(o)x)o) ]]
+>0: [[ aac = *(@(a))a@(c) ]]
+>0: [[ ac = *(@(a))a@(c) ]]
+>1: [[ c = *(@(a))a@(c) ]]
+>0: [[ aaac = *(@(a))a@(c) ]]
+>1: [[ baaac = *(@(a))a@(c) ]]
+>0: [[ abcd = ?@(a|b)*@(c)d ]]
+>0: [[ abcd = @(ab|a*@(b))*(c)d ]]
+>0: [[ acd = @(ab|a*(b))*(c)d ]]
+>0: [[ abbcd = @(ab|a*(b))*(c)d ]]
+>0: [[ effgz = @(b+(c)d|e*(f)g?|?(h)i@(j|k)) ]]
+>0: [[ efgz = @(b+(c)d|e*(f)g?|?(h)i@(j|k)) ]]
+>0: [[ egz = @(b+(c)d|e*(f)g?|?(h)i@(j|k)) ]]
+>0: [[ egzefffgzbcdij = *(b+(c)d|e*(f)g?|?(h)i@(j|k)) ]]
+>1: [[ egz = @(b+(c)d|e+(f)g?|?(h)i@(j|k)) ]]
+>0: [[ ofoofo = *(of+(o)) ]]
+>0: [[ oxfoxoxfox = *(oxf+(ox)) ]]
+>1: [[ oxfoxfox = *(oxf+(ox)) ]]
+>0: [[ ofoofo = *(of+(o)|f) ]]
+>0: [[ foofoofo = @(foo|f|fo)*(f|of+(o)) ]]
+>0: [[ oofooofo = *(of|oof+(o)) ]]
+>0: [[ fffooofoooooffoofffooofff = *(*(f)*(o)) ]]
+>1: [[ fffooofoooooffoofffooofffx = *(*(f)*(o)) ]]
+>0: [[ fofoofoofofoo = *(fo|foo) ]]
+>0: [[ foo = !(x) ]]
+>0: [[ foo = !(x)* ]]
+>1: [[ foo = !(foo) ]]
+>0: [[ foo = !(foo)* ]]
+>0: [[ foobar = !(foo) ]]
+>0: [[ foobar = !(foo)* ]]
+>0: [[ moo.cow = !(*.*).!(*.*) ]]
+>1: [[ mad.moo.cow = !(*.*).!(*.*) ]]
+>1: [[ mucca.pazza = mu!(*(c))?.pa!(*(z))? ]]
+>1: [[ _foo~ = _?(*[^~]) ]]
+>0: [[ fff = !(f) ]]
+>0: [[ fff = *(!(f)) ]]
+>0: [[ fff = +(!(f)) ]]
+>0: [[ ooo = !(f) ]]
+>0: [[ ooo = *(!(f)) ]]
+>0: [[ ooo = +(!(f)) ]]
+>0: [[ foo = !(f) ]]
+>0: [[ foo = *(!(f)) ]]
+>0: [[ foo = +(!(f)) ]]
+>1: [[ f = !(f) ]]
+>1: [[ f = *(!(f)) ]]
+>1: [[ f = +(!(f)) ]]
+>0: [[ foot = @(!(z*)|*x) ]]
+>1: [[ zoot = @(!(z*)|*x) ]]
+>0: [[ foox = @(!(z*)|*x) ]]
+>0: [[ zoox = @(!(z*)|*x) ]]
+>0: [[ foo = *(!(foo)) ]]
+>1: [[ foob = !(foo)b* ]]
+>0: [[ foobb = !(foo)b* ]]
+>0: [[ fooxx = (#i)FOOXX ]]
+>1: [[ fooxx = (#l)FOOXX ]]
+>0: [[ FOOXX = (#l)fooxx ]]
+>1: [[ fooxx = (#i)FOO@(#I)X@(#i)X ]]
+>0: [[ fooXx = (#i)FOO@(#I)X@(#i)X ]]
+>0: [[ fooxx = @((#i)FOOX)x ]]
+>1: [[ fooxx = @((#i)FOOX)X ]]
+>1: [[ BAR = @(bar|(#i)foo) ]]
+>0: [[ FOO = @(bar|(#i)foo) ]]
+>0: [[ Modules = (#i)*m* ]]
+>0 tests failed.
+
+ (unsetopt multibyte
+ [[ bjrn = *[]* ]])
+0:single byte match with top bit set
+
+ ( regress_absolute_path_and_core_dump )
+0:exclusions regression test
+>
+>glob.tmp/a glob.tmp/b glob.tmp/c glob.tmp/dir1 glob.tmp/dir1/a glob.tmp/dir1/b glob.tmp/dir1/c glob.tmp/dir2 glob.tmp/dir2/a glob.tmp/dir2/b glob.tmp/dir2/c glob.tmp/dir3 glob.tmp/dir3/subdir glob.tmp/dir4
+
+ print glob.tmp/*(/)
+0:Just directories
+>glob.tmp/dir1 glob.tmp/dir2 glob.tmp/dir3 glob.tmp/dir4
+
+ print glob.tmp/*(.)
+0:Just files
+>glob.tmp/a glob.tmp/b glob.tmp/c
+
+ print glob.tmp/*(.e^'reply=( glob.tmp/*/${REPLY:t} )'^:t)
+0:Globbing used recursively (inside e glob qualifier)
+>a a b b c c
+
+ print glob.tmp/*/*(e:'reply=( glob.tmp/**/*([1]) )'::t)
+0:Recursive globbing used recursively (inside e glob qualifier)
+>a a a a a a a
+
+ print glob.tmp/**/(:h)
+0:Head modifier
+>. glob.tmp glob.tmp glob.tmp glob.tmp glob.tmp/dir3
+
+ print glob.tmp(:r)
+0:Remove extension modifier
+>glob
+
+ print glob.tmp/*(:s/./_/)
+0:Substitute modifier
+>glob_tmp/a glob_tmp/b glob_tmp/c glob_tmp/dir1 glob_tmp/dir2 glob_tmp/dir3 glob_tmp/dir4
+
+ print glob.tmp/*(F)
+0:Just full dirs
+>glob.tmp/dir1 glob.tmp/dir2 glob.tmp/dir3
+
+ print glob.tmp/*(^F)
+0:Omit full dirs
+>glob.tmp/a glob.tmp/b glob.tmp/c glob.tmp/dir4
+
+ print glob.tmp/*(/^F)
+0:Just empty dirs
+>glob.tmp/dir4
+
+ setopt extendedglob
+ print glob.tmp/**/*~*/dir3(/*|(#e))(/)
+0:Exclusions with complicated path specifications
+>glob.tmp/dir1 glob.tmp/dir2 glob.tmp/dir4
+
+ print -l -- glob.tmp/*(P:-f:)
+0:Prepending words to each argument
+>-f
+>glob.tmp/a
+>-f
+>glob.tmp/b
+>-f
+>glob.tmp/c
+>-f
+>glob.tmp/dir1
+>-f
+>glob.tmp/dir2
+>-f
+>glob.tmp/dir3
+>-f
+>glob.tmp/dir4
+
+ print -l -- glob.tmp/*(P:one word:P:another word:)
+0:Prepending two words to each argument
+>one word
+>another word
+>glob.tmp/a
+>one word
+>another word
+>glob.tmp/b
+>one word
+>another word
+>glob.tmp/c
+>one word
+>another word
+>glob.tmp/dir1
+>one word
+>another word
+>glob.tmp/dir2
+>one word
+>another word
+>glob.tmp/dir3
+>one word
+>another word
+>glob.tmp/dir4
+
+ [[ "" = "" ]] && echo OK
+0:Empty strings
+>OK
+
+ foo="this string has a : colon in it"
+ print ${foo%% #:*}
+0:Must-match arguments in complex patterns
+>this string has a
+
+ mkdir glob.tmp/ra=1.0_et=3.5
+ touch glob.tmp/ra=1.0_et=3.5/foo
+ print glob.tmp/ra=1.0_et=3.5/???
+0:Bug with intermediate paths with plain strings but tokenized characters
+>glob.tmp/ra=1.0_et=3.5/foo
+
+ doesmatch() {
+ setopt localoptions extendedglob
+ print -n $1 $2\
+ if [[ $1 = $~2 ]]; then print yes; else print no; fi;
+ }
+ doesmatch MY_IDENTIFIER '[[:IDENT:]]##'
+ doesmatch YOUR:IDENTIFIER '[[:IDENT:]]##'
+ IFS=$'\n' doesmatch $'\n' '[[:IFS:]]'
+ IFS=' ' doesmatch $'\n' '[[:IFS:]]'
+ IFS=':' doesmatch : '[[:IFSSPACE:]]'
+ IFS=' ' doesmatch ' ' '[[:IFSSPACE:]]'
+ WORDCHARS="" doesmatch / '[[:WORD:]]'
+ WORDCHARS="/" doesmatch / '[[:WORD:]]'
+0:Named character sets handled internally
+>MY_IDENTIFIER [[:IDENT:]]## yes
+>YOUR:IDENTIFIER [[:IDENT:]]## no
+>
+> [[:IFS:]] yes
+>
+> [[:IFS:]] no
+>: [[:IFSSPACE:]] no
+> [[:IFSSPACE:]] yes
+>/ [[:WORD:]] no
+>/ [[:WORD:]] yes
+
+ [[ foo = (#c0)foo ]]
+2:Misplaced (#c...) flag
+?(eval):1: bad pattern: (#c0)foo
+
+ mkdir glob.tmp/dir5
+ touch glob.tmp/dir5/N123
+ print glob.tmp/dir5/N<->(N)
+ rm -rf glob.tmp/dir5
+0:Numeric glob is not usurped by process substitution.
+>glob.tmp/dir5/N123
+
+ tpd() {
+ [[ $1 = $~2 ]]
+ print -r "$1, $2: $?"
+ }
+ test_pattern_disables() {
+ emulate -L zsh
+ tpd 'forthcoming' 'f*g'
+ disable -p '*'
+ tpd 'forthcoming' 'f*g'
+ tpd 'f*g' 'f*g'
+ tpd '[frog]' '[frog]'
+ tpd '[frog]' '\[[f]rog\]'
+ disable -p '['
+ tpd '[frog]' '[frog]'
+ tpd '[frog]' '\[[f]rog\]'
+ setopt extendedglob
+ tpd 'foo' '^bar'
+ disable -p '^'
+ tpd 'foo' '^bar'
+ tpd '^bar' '^bar'
+ tpd 'rumble' '(rumble|bluster)'
+ tpd '(thunder)' '(thunder)'
+ disable -p '('
+ tpd 'rumble' '(rumble|bluster)'
+ tpd '(thunder)' '(thunder)'
+ setopt kshglob
+ tpd 'scramble' '@(panic|frenzy|scramble)'
+ tpd '@(scrimf)' '@(scrimf)'
+ disable -p '@('
+ tpd 'scramble' '@(panic|frenzy|scramble)'
+ tpd '@(scrimf)' '@(scrimf)'
+ disable -p
+ }
+ test_pattern_disables
+ print Nothing should be disabled.
+ disable -p
+0:disable -p
+>forthcoming, f*g: 0
+>forthcoming, f*g: 1
+>f*g, f*g: 0
+>[frog], [frog]: 1
+>[frog], \[[f]rog\]: 0
+>[frog], [frog]: 0
+>[frog], \[[f]rog\]: 1
+>foo, ^bar: 0
+>foo, ^bar: 1
+>^bar, ^bar: 0
+>rumble, (rumble|bluster): 0
+>(thunder), (thunder): 1
+>rumble, (rumble|bluster): 1
+>(thunder), (thunder): 0
+>scramble, @(panic|frenzy|scramble): 0
+>@(scrimf), @(scrimf): 1
+>scramble, @(panic|frenzy|scramble): 1
+>@(scrimf), @(scrimf): 0
+>'(' '*' '[' '^' '@('
+>Nothing should be disabled.
+
+ (
+ setopt nomatch
+ x=( '' )
+ print $^x(N)
+ )
+0:No error with empty null glob with (N).
+>
+
+ (setopt kshglob
+ test_array=(
+ '+fours' '+*'
+ '@titude' '@*'
+ '!bang' '!*'
+ # and check they work in the real kshglob cases too...
+ '+bus+bus' '+(+bus|-car)'
+ '@sinhats' '@(@sinhats|wrensinfens)'
+ '!kerror' '!(!somethingelse)'
+ # and these don't match, to be sure
+ '+more' '+(+less)'
+ '@all@all' '@(@all)'
+ '!goesitall' '!(!goesitall)'
+ )
+ for str pat in $test_array; do
+ eval "[[ $str = $pat ]]" && print "$str matches $pat"
+ done
+ true
+ )
+0:kshglob option does not break +, @, ! without following open parenthesis
+>+fours matches +*
+>@titude matches @*
+>!bang matches !*
+>+bus+bus matches +(+bus|-car)
+>@sinhats matches @(@sinhats|wrensinfens)
+>!kerror matches !(!somethingelse)
+
+ (
+ setopt extendedglob
+ cd glob.tmp
+ [[ -n a*(#qN) ]] && print File beginning with a
+ [[ -z z*(#qN) ]] && print No file beginning with z
+ setopt nonomatch
+ [[ -n z*(#q) ]] && print Normal string if nullglob not set
+ )
+0:Force glob expansion in conditions using (#q)
+>File beginning with a
+>No file beginning with z
+>Normal string if nullglob not set
+
+ (){ print $#@ } glob.tmp/dir*(Y1)
+ (){ print $#@ } glob.tmp/file*(NY1)
+ (){ [[ "$*" == */dir?\ */dir? ]] && print Returns matching filenames } glob.tmp/dir*(Y2)
+ (){ print "Limit is upper bound:" ${(o)@:t} } glob.tmp/dir*(Y5)
+ (){ print "Negated:" $@:t } glob.tmp/dir*(Y1^Y)
+ (){ print "Sorting:" $@:t } glob.tmp/dir*(Y4On)
+ (){ [[ $#@ -eq 1 ]] && print Globs before last path component } glob.tmp/dir?/subdir(NY1)
+ (){ [[ $1 == glob.tmp/a ]] } glob.tmp/**/a(Y1) && print Breadth first
+ (){ [[ $#@ -eq 0 ]] && print Respects qualifiers } glob.tmp/dir*(NY1.)
+ (print -- *(Y)) 2>/dev/null || print "Argument required"
+0:short-circuit modifier
+>1
+>0
+>Returns matching filenames
+>Limit is upper bound: dir1 dir2 dir3 dir4
+>Negated: dir1 dir2 dir3 dir4
+>Sorting: dir4 dir3 dir2 dir1
+>Globs before last path component
+>Breadth first
+>Respects qualifiers
+>Argument required
+
+ [[ "ce fichier n'existe pas" = (#b)ce\ (f[^ ]#)\ *s(#q./) ]]
+ print $match[1]
+0:(#q) is ignored completely in conditional pattern matching
+>fichier
+
+# The following should not cause excessive slowdown.
+ print glob.tmp/*.*
+ print glob.tmp/**************************.*************************
+0:Optimisation to squeeze multiple *'s used as ordinary glob wildcards.
+>glob.tmp/ra=1.0_et=3.5
+>glob.tmp/ra=1.0_et=3.5
+
+ [[ 1_2_ = (*_)(#c1) ]] && print 1 OK # because * matches 1_2
+ [[ 1_2_ = (*_)(#c2) ]] && print 2 OK
+ [[ 1_2_ = (*_)(#c3) ]] || print 3 OK
+0:Some more complicated backtracking with match counts.
+>1 OK
+>2 OK
+>3 OK
+
+ [[ foo = 'f'\o"o" ]]
+0:Stripping of quotes from patterns (1)
+
+ [[ foo = 'f'('o'|'a')('o'|'b') ]]
+0:Stripping of quotes from patterns (2)
+
+ [[ fob = 'f'('o'|'a')('o'|'b') ]]
+0:Stripping of quotes from patterns (3)
+
+ [[ fab = 'f'('o'|'a')('o'|'b') ]]
+0:Stripping of quotes from patterns (4)
+
+ [[ fib != 'f'('o'|'a')('o'|'b') ]]
+0:Stripping of quotes from patterns (4)
+
+ [[ - != [a-z] ]]
+0:- is a special character in ranges
+
+ [[ - = ['a-z'] ]]
+0:- is not a special character in ranges if quoted
+
+ [[ b-1 = [a-z]-[0-9] ]]
+0:- untokenized following a bracketed subexpression
+
+ [[ b-1 = []a-z]-[]0-9] ]]
+0:- "]" after "[" is normal range character and - still works
+
+ headremove="bcdef"
+ print ${headremove#[a-z]}
+0:active - works in pattern in parameter
+>cdef
+
+ headremove="bcdef"
+ print ${headremove#['a-z']}
+ headremove="-cdef"
+ print ${headremove#['a-z']}
+0:quoted - works in pattern in parameter
+>bcdef
+>cdef
+
+ [[ a != [^a] ]]
+0:^ active in character class if not quoted
+
+ [[ a = ['^a'] ]]
+0:^ not active in character class if quoted
+
+ [[ a != [!a] ]]
+0:! active in character class if not quoted
+
+ [[ a = ['!a'] ]]
+0:! not active in character class if quoted
+
+ # Actually, we don't need the quoting here,
+ # c.f. the next test. This just makes it look
+ # more standard.
+ cset="^a-z"
+ [[ "^" = ["$cset"] ]] || print Fail 1
+ [[ "a" = ["$cset"] ]] || print Fail 2
+ [[ "-" = ["$cset"] ]] || print Fail 3
+ [[ "z" = ["$cset"] ]] || print Fail 4
+ [[ "1" != ["$cset"] ]] || print Fail 5
+ [[ "b" != ["$cset"] ]] || print Fail 6
+0:character set specified as quoted variable
+
+ cset="^a-z"
+ [[ "^" = [$~cset] ]] || print Fail 1
+ [[ "a" != [$~cset] ]] || print Fail 2
+ [[ "-" = [$~cset] ]] || print Fail 3
+ [[ "z" != [$~cset] ]] || print Fail 4
+ [[ "1" = [$~cset] ]] || print Fail 5
+ [[ "b" != [$~cset] ]] || print Fail 6
+0:character set specified as active variable
+
+ () { print -l -- $@:a } / /..{,/} /1 /nonexistent/..{,/} /deeper/nonexistent/..{,/}
+0:modifier ':a' doesn't require existence
+>/
+>/
+>/
+>/1
+>/
+>/
+>/deeper
+>/deeper
+
+ () { set -- ${PWD}/$^@; print -l -- $@:A } glob.tmp/nonexistent/foo/bar/baz
+0:modifier ':A' doesn't require existence
+*>*/glob.tmp/nonexistent/foo/bar/baz
+
+ ln -s dir3/subdir glob.tmp/link
+ () {
+ print ${1:A} | grep glob.tmp
+ } glob.tmp/link/../../hello
+ rm glob.tmp/link
+0:modifier ':A' resolves '..' components before symlinks
+# There should be no output
+
+ ln -s dir3/subdir glob.tmp/link
+ () {
+ print ${1:P}
+ } glob.tmp/link/../../hello/world
+ rm glob.tmp/link
+0:modifier ':P' resolves symlinks before '..' components
+*>*glob.tmp/hello/world
diff --git a/dotfiles/system/.zsh/modules/Test/D03procsubst.ztst b/dotfiles/system/.zsh/modules/Test/D03procsubst.ztst
new file mode 100644
index 0000000..ca8d56f
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/D03procsubst.ztst
@@ -0,0 +1,151 @@
+# Tests for process substitution: <(...), >(...) and =(...).
+
+%prep
+ if grep '#define PATH_DEV_FD' $ZTST_testdir/../config.h > /dev/null 2>&1 ||
+ grep '#define HAVE_FIFOS' $ZTST_testdir/../config.h > /dev/null 2>&1; then
+ mkdir procsubst.tmp
+ cd procsubst.tmp
+ print 'First\tSecond\tThird\tFourth' >FILE1
+ print 'Erste\tZweite\tDritte\tVierte' >FILE2
+ else
+ ZTST_unimplemented="process substitution is not supported"
+ true
+ fi
+
+ function copycat { cat "$@" }
+
+%test
+ paste <(cut -f1 FILE1) <(cut -f3 FILE2)
+0:<(...) substitution
+>First Dritte
+
+# slightly desperate hack to force >(...) to be synchronous
+ { paste <(cut -f2 FILE1) <(cut -f4 FILE2) } > >(sed 's/e/E/g' >OUTFILE)
+ cat OUTFILE
+0:>(...) substitution
+>SEcond ViErtE
+
+ diff =(cat FILE1) =(cat FILE2)
+1:=(...) substituion
+>1c1
+>< First Second Third Fourth
+>---
+>> Erste Zweite Dritte Vierte
+
+ copycat <(print First) <(print Zweite)
+0:FDs remain open for external commands called from functions
+>First
+>Zweite
+
+ catfield2() {
+ local -a args
+ args=(${(s.,.)1})
+ print $args[1]
+ cat $args[2]
+ print $args[3]
+ }
+ catfield2 up,<(print $'\x64'own),sideways
+0:<(...) when embedded within an argument
+>up
+>down
+>sideways
+
+ outputfield2() {
+ local -a args
+ args=(${(s.,.)1})
+ print $args[1]
+ echo 'How sweet the moonlight sits upon the bank' >$args[2]
+ print $args[3]
+ }
+ outputfield2 muddy,>(sed -e s/s/th/g >outputfield2.txt),vesture
+ # yuk
+ while [[ ! -e outputfield2.txt || ! -s outputfield2.txt ]]; do :; done
+ cat outputfield2.txt
+0:>(...) when embedded within an argument
+>muddy
+>vesture
+>How thweet the moonlight thitth upon the bank
+
+ catfield1() {
+ local -a args
+ args=(${(s.,.)1})
+ cat $args[1]
+ print $args[2]
+ }
+ catfield1 =(echo s$'\x69't),jessica
+0:=(...) followed by something else without a break
+>sit
+>jessica
+
+ (
+ setopt nonomatch
+ # er... why is this treated as a glob?
+ print everything,=(here is left),alone
+ )
+0:=(...) preceded by other stuff has no special effect
+>everything,=(here is left),alone
+
+ print something=${:-=(echo 'C,D),(F,G)'}
+1: Graceful handling of bad substitution in enclosed context
+?(eval):1: unterminated `=(...)'
+# '`
+
+ () {
+ print -n "first: "
+ cat $1
+ print -n "second: "
+ cat $2
+ } =(echo This becomes argument one) =(echo and this argument two)
+ function {
+ print -n "third: "
+ cat $1
+ print -n "fourth: "
+ cat $2
+ } =(echo This becomes argument three) =(echo and this argument four)
+0:Process environment of anonymous functions
+>first: This becomes argument one
+>second: and this argument two
+>third: This becomes argument three
+>fourth: and this argument four
+
+ () {
+ # Make sure we don't close the file descriptor too early
+ eval 'print "Execute a complicated command first" | sed s/command/order/'
+ cat $1
+ } <(echo This line was brought to you by the letters F and D)
+0:Process substitution as anonymous function argument
+>Execute a complicated order first
+>This line was brought to you by the letters F and D
+
+ alias foo='cat <('
+ eval 'foo echo this is bound to work)'
+0:backtacking within command string parsing with alias still pending
+>this is bound to work
+
+ alias foo='cat <( print'
+ eval 'foo here is some output)'
+0:full alias expanded when substitution starts in alias
+>here is some output
+
+ if ! (mkfifo test_pipe >/dev/null 2>&1); then
+ ZTST_skip="mkfifo not available"
+ else
+ echo 1 | tee >(cat > test_pipe) | (){
+ local pipein
+ read pipein <test_pipe
+ print $pipein
+ read pipein
+ print $pipein
+ }
+ fi
+0:proc subst fd in forked subshell closed in parent
+>1
+>1
+
+ if [[ ! -e test_pipe ]]; then
+ ZTST_skip="mkfifo not available"
+ else
+ echo 1 | tee >(cat > test_pipe) | paste - test_pipe
+ fi
+0:proc subst fd in forked subshell closed in parent (external command)
+>1 1
diff --git a/dotfiles/system/.zsh/modules/Test/D04parameter.ztst b/dotfiles/system/.zsh/modules/Test/D04parameter.ztst
new file mode 100644
index 0000000..9128c3c
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/D04parameter.ztst
@@ -0,0 +1,2058 @@
+# Test parameter expansion. Phew.
+# (By the way, did I say "phew"?)
+
+%prep
+
+ mkdir parameter.tmp
+
+ cd parameter.tmp
+
+ touch boringfile evenmoreboringfile
+
+%test
+
+ foo='the first parameter'
+ bar='the second parameter'
+ print -l $foo ${bar}
+0:Basic scalar parameter substitution
+>the first parameter
+>the second parameter
+
+ array1=(the first array)
+ array2=(the second array)
+ print -l $array1 ${array2}
+0:Basic array parameter substitution
+>the
+>first
+>array
+>the
+>second
+>array
+
+ setopt ksharrays
+ print -l $array1 ${array2}
+ unsetopt ksharrays
+0:Basic ksharray substitution
+>the
+>the
+
+ setopt shwordsplit
+ print -l $foo ${bar}
+ print -l ${==bar}
+ unsetopt shwordsplit
+0:Basic shwordsplit option handling
+>the
+>first
+>parameter
+>the
+>second
+>parameter
+>the second parameter
+
+ print $+foo ${+foo} $+notappearinginthistest ${+notappearinginthistest}
+0:$+...
+>1 1 0 0
+
+ x=()
+ print ${+x} ${+x[1]} ${+x[(r)foo]} ${+x[(r)bar]}
+ x=(foo)
+ print ${+x} ${+x[1]} ${+x[(r)foo]} ${+x[(r)bar]}
+0:$+... with arrays
+>1 0 0 0
+>1 1 1 0
+
+ set1=set1v
+ null1=
+ print ${set1:-set1d} ${set1-set2d} ${null1:-null1d} ${null1-null2d} x
+ print ${unset1:-unset1d} ${unset1-unset2d} x
+0:${...:-...} and ${...-...}
+>set1v set1v null1d x
+>unset1d unset2d x
+
+ set2=irrelevant
+ print ${set1:=set1d} ${set2::=set2d}
+ print $set2
+ wasnull1=
+ wasnull2=
+ print ${wasnull1=wasnull1d} ${wasnull2:=wasnull2d}
+ print $wasnull1 $wasnull2
+0:${...:=...}, ${...::=...}, ${...=...}
+>set1v set2d
+>set2d
+>wasnull2d
+>wasnull2d
+
+ unset array
+ print ${#${(A)=array=word}}
+0:${#${(A)=array=word}} counts array elements
+>1
+
+ (print ${set1:?okhere}; print ${unset1:?exiting1}; print not reached;)
+ (print ${null1?okhere}; print ${null1:?exiting2}; print not reached;)
+1:${...:?...}, ${...?...}
+>set1v
+>
+?(eval):1: unset1: exiting1
+?(eval):2: null1: exiting2
+
+ PROMPT="" $ZTST_testdir/../Src/zsh -fis <<<'
+ unsetopt PROMPT_SP
+ PS1="" PS2="" PS3="" PS4="" RPS1="" RPS2=""
+ exec 2>&1
+ foo() {
+ print ${1:?no arguments given}
+ print not reached
+ }
+ foo
+ print reached
+ ' 2>/dev/null
+0:interactive shell returns to top level on ${...?...} error
+*>*foo:1: 1: no arguments given
+>reached
+
+ print ${set1:+word1} ${set1+word2} ${null1:+word3} ${null1+word4}
+ print ${unset1:+word5} ${unset1+word6}
+0:${...:+...}, ${...+...}
+>word1 word2 word4
+>
+
+ str1='This is very boring indeed.'
+ print ${str1#*s}
+ print ${str1##*s}
+ print $str1##s
+0:${...#...}, ${...##...}
+> is very boring indeed.
+> very boring indeed.
+>This is very boring indeed.##s
+
+ str2='If you'\''re reading this you should go and fix some bugs instead.'
+ print ${str2%d*}
+ print ${str2%%d*}
+0:${...%...}, ${...%%...}
+>If you're reading this you should go and fix some bugs instea
+>If you're rea
+
+ str1='does match'
+ str2='does not match'
+ print ${str1:#does * match}
+ print ${str2:#does * match}
+0:${...:#...}
+>does match
+>
+
+ array1=(arthur boldly claws dogs every fight)
+ print ${array1:#[aeiou]*}
+ print ${(M)array1:#[aeiou]*}
+0:${...:#...}, ${(M)...:#...} with array
+>boldly claws dogs fight
+>arthur every
+
+ str1="$array1"
+ print ${str1/[aeiou]*g/a braw bricht moonlicht nicht the nic}
+ print ${(S)str1/[aeiou]*g/relishe}
+0:scalar ${.../.../...}, ${(S).../.../...}
+>a braw bricht moonlicht nicht the nicht
+>relishes every fight
+
+ print ${array1/[aeiou]*/Y}
+ print ${(S)array1/[aeiou]*/Y}
+0:array ${.../.../...}, ${(S).../.../...}
+>Y bY clY dY Y fY
+>Yrthur bYldly clYws dYgs Yvery fYght
+
+ str1='o this is so, so so very dull'
+ print ${str1//o*/Please no}
+ print ${(S)str1//o*/Please no}
+0:scalar ${...//.../...}, ${(S)...//.../...}
+>Please no
+>Please no this is sPlease no, sPlease no sPlease no very dull
+
+ print ${array1//[aeiou]*/Y}
+ print ${(S)array1//[aeiou]*/Y}
+0:array ${...//.../...}, ${(S)...//.../...}
+>Y bY clY dY Y fY
+>YrthYr bYldly clYws dYgs YvYry fYght
+
+ print ${array1:/[aeiou]*/expletive deleted}
+0:array ${...:/...}
+>expletive deleted boldly claws dogs expletive deleted fight
+
+ str1='a\string\with\backslashes'
+ str2='a/string/with/slashes'
+ print "${str1//\\/-}"
+ print ${str1//\\/-}
+ print "${str2//\//-}"
+ print ${str2//\//-}
+0:use of backslashes in //-substitutions
+>a-string-with-backslashes
+>a-string-with-backslashes
+>a-string-with-slashes
+>a-string-with-slashes
+
+ args=('one' '#foo' '(bar' "'three'" two)
+ mod=('#foo' '(bar' "'three'" sir_not_appearing_in_this_film)
+ print ${args:|mod}
+ print ${args:*mod}
+ print "${(@)args:|mod}"
+ print "${(@)args:*mod}"
+ args=(two words)
+ mod=('one word' 'two words')
+ print "${args:|mod}"
+ print "${args:*mod}"
+ scalar='two words'
+ print ${scalar:|mod}
+ print ${scalar:*mod}
+ print ${args:*nonexistent}
+ empty=
+ print ${args:*empty}
+0:"|" array exclusion and "*" array intersection
+>one two
+>#foo (bar 'three'
+>one two
+>#foo (bar 'three'
+>
+>two words
+>
+>two words
+>
+>
+
+ str1='twocubed'
+ array=(the number of protons in an oxygen nucleus)
+ print $#str1 ${#str1} "$#str1 ${#str1}" $#array ${#array} "$#array ${#array}"
+0:${#...}, $#...
+>8 8 8 8 8 8 8 8
+
+ set 1 2 3 4 5 6 7 8 9
+ print ${##}
+ set 1 2 3 4 5 6 7 8 9 10
+ print ${##}
+ print ${##""}
+ print ${##1}
+ print ${##2}
+ print ${###<->} # oh, for pete's sake...
+0:${##} is length of $#, and other tales of hash horror
+>1
+>2
+>10
+>0
+>10
+>
+
+ array=(once bitten twice shy)
+ print IF${array}THEN
+ print IF${^array}THEN
+0:basic ${^...}
+>IFonce bitten twice shyTHEN
+>IFonceTHEN IFbittenTHEN IFtwiceTHEN IFshyTHEN
+
+ # Quote ${array} here because {...,...} doesn't like unquoted spaces.
+ print IF{"${array}",THEN}ELSE
+ print IF{${^array},THEN}ELSE
+0:combined ${^...} and {...,...}
+>IFonce bitten twice shyELSE IFTHENELSE
+>IFonceELSE IFTHENELSE IFbittenELSE IFTHENELSE IFtwiceELSE IFTHENELSE IFshyELSE IFTHENELSE
+
+ str1='one word'
+ print -l $str1 ${=str1} "split ${=str1}wise"
+0:${=...}
+>one word
+>one
+>word
+>split one
+>wordwise
+
+ str1='*'
+ print $str1 ${~str1} $~str1
+ setopt globsubst
+ print $str1
+ unsetopt globsubst
+0:${~...} and globsubst
+>* boringfile evenmoreboringfile boringfile evenmoreboringfile
+>boringfile evenmoreboringfile
+
+# The following tests a bug where globsubst didn't preserve
+# backslashes when printing out the original string.
+ str1='\\*\\'
+ (
+ setopt globsubst nonomatch
+ [[ \\\\ = $str1 ]] && print -r '\\ matched by' $str1
+ [[ \\foo\\ = $str1 ]] && print -r '\\foo matched by' $str1
+ [[ a\\b\\ = $str1 ]] || print -r 'a\\b not matched by' $str1
+ )
+0:globsubst with backslashes
+>\\ matched by \\*\\
+>\\foo matched by \\*\\
+>a\\b not matched by \\*\\
+
+ (
+ setopt globsubst
+ foo="boring*"
+ print ${foo+$foo}
+ print ${foo+"$foo"}
+ print ${~foo+"$foo"}
+ )
+0:globsubst together with nested quoted expansion
+>boringfile
+>boring*
+>boringfile
+
+ print -l "${$(print one word)}" "${=$(print two words)}"
+0:splitting of $(...) inside ${...}
+>one word
+>two
+>words
+
+ (setopt shwordsplit # ensure this doesn't get set in main shell...
+ test_splitting ()
+ {
+ array="one two three"
+ for e in $array; do
+ echo "'$e'"
+ done
+ }
+ test_split_var=
+ echo _${test_split_var:=$(test_splitting)}_
+ echo "_${test_split_var}_")
+0:SH_WORD_SPLIT inside $(...) inside ${...}
+>_'one' 'two' 'three'_
+>_'one'
+>'two'
+>'three'_
+
+ print -l "${(f)$(print first line\\nsecond line\\nthird line)}"
+0:${(f)$(...)}
+>first line
+>second line
+>third line
+
+ array1=( uno )
+ print -l ${(A)newarray=splitting by numbers}
+ print -l ${(t)newarray}
+ print -l ${(A)=newarray::=splitting by spaces, actually}
+ print -l ${(t)newarray}
+ print -l ${(A)newarray::=$array1}
+ print -l ${(t)newarray}
+ print -l ${newarray::=$array1}
+ print -l ${(t)newarray}
+ print -l ${newarray::=$array2}
+ print -l ${(t)newarray}
+0:${(A)...=...}, ${(A)...::=...}, ${scalar=$array}
+>splitting by numbers
+>array
+>splitting
+>by
+>spaces,
+>actually
+>array
+>uno
+>array
+>uno
+>scalar
+>the second array
+>scalar
+
+ newarray=("split me" "split me" "I\'m yours")
+ print -l "${(@)newarray}"
+0:"${(@)...}"
+>split me
+>split me
+>I'm yours
+
+ foo='$(print Howzat usay)'
+ print -l ${(e)foo}
+0:${(e)...}
+>Howzat
+>usay
+
+ foo='`print Howzat usay`'
+ print -l ${(e)foo}
+0:Regress ${(e)...} with backticks (see zsh-workers/15871)
+>Howzat
+>usay
+
+ foo='\u65\123'
+ print -r ${(g:o:)foo}
+ foo='\u65\0123^X\C-x'
+ print -r ${(g::)foo}
+ foo='^X'
+ bar='\C-\130'
+ [[ ${(g:c:)foo} == ${(g:oe:)bar} ]]
+ echo $?
+0:${(g)...}
+>eS
+>eS^X\C-x
+>0
+
+ foo='I'\''m nearly out of my mind with tedium'
+ bar=foo
+ print ${(P)bar}
+0:${(P)...}
+>I'm nearly out of my mind with tedium
+#' deconfuse emacs
+
+ foo=(I could be watching that programme I recorded)
+ print ${(o)foo}
+ print ${(oi)foo}
+ print ${(O)foo}
+ print ${(Oi)foo}
+0:${(o)...}, ${(O)...}
+>I I be could programme recorded that watching
+>be could I I programme recorded that watching
+>watching that recorded programme could be I I
+>watching that recorded programme I I could be
+
+ foo=(yOU KNOW, THE ONE WITH wILLIAM dALRYMPLE)
+ bar=(doing that tour of India.)
+ print ${(L)foo}
+ print ${(U)bar}
+0:${(L)...}, ${(U)...}
+>you know, the one with william dalrymple
+>DOING THAT TOUR OF INDIA.
+
+ foo='instead here I am stuck by the computer'
+ print ${(C)foo}
+0:${(C)...}
+>Instead Here I Am Stuck By The Computer
+
+ foo=$'\x7f\x00'
+ print -r -- ${(V)foo}
+0:${(V)...}
+>^?^@
+
+ foo='playing '\''stupid'\'' "games" \w\i\t\h $quoting.'
+ print -r ${(q)foo}
+ print -r ${(qq)foo}
+ print -r ${(qqq)foo}
+ print -r ${(qqqq)foo}
+ print -r ${(q-)foo}
+0:${(q...)...}
+>playing\ \'stupid\'\ \"games\"\ \\w\\i\\t\\h\ \$quoting.
+>'playing '\''stupid'\'' "games" \w\i\t\h $quoting.'
+>"playing 'stupid' \"games\" \\w\\i\\t\\h \$quoting."
+>$'playing \'stupid\' "games" \\w\\i\\t\\h $quoting.'
+>'playing '\'stupid\'' "games" \w\i\t\h $quoting.'
+
+ print -r ${(qqqq):-""}
+0:workers/36551: literal empty string in ${(qqqq)...}
+>$''
+
+ x=( a '' '\b' 'c d' '$e' )
+ print -r ${(q)x}
+ print -r ${(q-)x}
+0:Another ${(q...)...} test
+>a '' \\b c\ d \$e
+>a '' '\b' 'c d' '$e'
+
+ print -r -- ${(q-):-foo}
+ print -r -- ${(q-):-foo bar}
+ print -r -- ${(q-):-"*(.)"}
+ print -r -- ${(q-):-"wow 'this is cool' or is it?"}
+ print -r -- ${(q-):-"no-it's-not"}
+0:${(q-)...} minimal single quoting
+>foo
+>'foo bar'
+>'*(.)'
+>'wow '\''this is cool'\'' or is it?'
+>no-it\'s-not
+
+ foo="'and now' \"even the pubs\" \\a\\r\\e shut."
+ print -r ${(Q)foo}
+0:${(Q)...}
+>and now even the pubs are shut.
+
+ foo="X$'\x41'$'\x42'Y"
+ print -r ${(Q)foo}
+0:${(Q)...} with handling of $'...'
+>XABY
+
+ # The following may look a bit random.
+ # For the split we are checking that anything that
+ # would normally be followed by a different word has
+ # an argument break after it and anything that wouldn't doesn't.
+ # For the (Q) we are simply checking that nothing disappears
+ # in the parsing.
+ foo='<five> {six} (seven) >eight< }nine{ |forty-two| $many$ )ten( more'
+ array=(${(z)foo})
+ print -l ${(Q)array}
+0:${(z)...} and ${(Q)...} for some hard to parse cases
+><
+>five
+>>
+>{six}
+>(
+>seven
+>)
+>>
+>eight
+><
+>}nine{
+>|
+>forty-two
+>|
+>$many$
+>)
+>ten( more
+
+ strings=(
+ 'foo=(1 2 3)'
+ '(( 3 + 1 == 8 / 2 ))'
+ 'for (( i = 1 ; i < 10 ; i++ ))'
+ '((0.25542 * 60) - 15)*60'
+ 'repeat 3 (x)'
+ 'repeat 3 (echo foo; echo bar)'
+ 'repeat $(( 2 + 4 )) (x)'
+ 'repeat $( : foo bar; echo 4) (x)'
+ 'repeat "1"'\''2'\''$(( 3 + 0 ))$((echo 4);)\ 5 (x)'
+ )
+ for string in $strings; do
+ array=(${(z)string})
+ for (( i = 1; i <= ${#array}; i++ )); do
+ print -r -- "${i}:${array[i]}:"
+ done
+ done
+0:Some syntactical expressions that are hard to split into words with (z).
+>1:foo=(:
+>2:1:
+>3:2:
+>4:3:
+>5:):
+>1:(( 3 + 1 == 8 / 2 )):
+>1:for:
+>2:((:
+# Leading whitespace is removed, because the word proper hasn't started;
+# trailing whitespace is left because the word is terminated by the
+# semicolon or double parentheses. Bit confusing but sort of consistent.
+>3:i = 1 ;:
+>4:i < 10 ;:
+>5:i++ :
+>6:)):
+# This one needs resolving between a math expression and
+# a command, which causes interesting effects internally.
+>1:(:
+>2:(:
+>3:0.25542:
+>4:*:
+>5:60:
+>6:):
+>7:-:
+>8:15:
+>9:):
+>10:*60:
+>1:repeat:
+>2:3:
+>3:(:
+>4:x:
+>5:):
+>1:repeat:
+>2:3:
+>3:(:
+>4:echo:
+>5:foo:
+>6:;:
+>7:echo:
+>8:bar:
+>9:):
+>1:repeat:
+>2:$(( 2 + 4 )):
+>3:(:
+>4:x:
+>5:):
+>1:repeat:
+>2:$( : foo bar; echo 4):
+>3:(:
+>4:x:
+>5:):
+>1:repeat:
+>2:"1"'2'$(( 3 + 0 ))$((echo 4);)\ 5:
+>3:(:
+>4:x:
+>5:):
+
+
+ line=$'A line with # someone\'s comment\nanother line # (1 more\nanother one'
+ print "*** Normal ***"
+ print -l ${(z)line}
+ print "*** Kept ***"
+ print -l ${(Z+c+)line}
+ print "*** Removed ***"
+ print -l ${(Z+C+)line}
+0:Comments with (z)
+>*** Normal ***
+>A
+>line
+>with
+>#
+>someone's comment
+>another line # (1 more
+>another one
+>*** Kept ***
+>A
+>line
+>with
+># someone's comment
+>;
+>another
+>line
+># (1 more
+>;
+>another
+>one
+>*** Removed ***
+>A
+>line
+>with
+>;
+>another
+>line
+>;
+>another
+>one
+
+ line='with comment # at the end'
+ print -l ${(Z+C+)line}
+0:Test we don't get an additional newline token
+>with
+>comment
+
+ line=$'echo one\necho two # with a comment\necho three'
+ print -l ${(Z+nc+)line}
+0:Treating zplit newlines as ordinary whitespace
+>echo
+>one
+>echo
+>two
+># with a comment
+>echo
+>three
+
+ print -rl - ${(z):-":;(( echo 42 "}
+0:${(z)} with incomplete math expressions
+>:
+>;
+>(( echo 42
+
+ # From parse error on it's not possible to split.
+ # Just check we get the complete string.
+ foo='echo $(|||) bar'
+ print -rl ${(z)foo}
+0:$($(z)} with parse error in command substitution.
+>echo
+>$(|||) bar
+
+ psvar=(dog)
+ setopt promptsubst
+ foo='It shouldn'\''t $(happen) to a %1v.'
+ bar='But `echo what can you do\?`'
+ print -r ${(%)foo}
+ print -r ${(%%)bar}
+0:${(%)...}
+>It shouldn't $(happen) to a dog.
+>But what can you do?
+
+ foo='unmatched "'
+ print ${(QX)foo}
+1:${(QX)...}
+?(eval):2: unmatched "
+# " deconfuse emacs
+
+ array=(characters in an array)
+ print ${(c)#array}
+0:${(c)#...}
+>22
+
+ print ${(w)#array}
+ str='colon::bolon::solon'
+ print ${(ws.:.)#str}
+ print ${(Ws.:.)#str}
+0:${(w)...}, ${(W)...}
+>4
+>3
+>5
+
+ typeset -A assoc
+ assoc=(key1 val1 key2 val2)
+ print ${(o)assoc}
+ print ${(ok)assoc}
+ print ${(ov)assoc}
+ print ${(okv)assoc}
+0:${(k)...}, ${(v)...}
+>val1 val2
+>key1 key2
+>val1 val2
+>key1 key2 val1 val2
+
+ word="obfuscatory"
+ print !${(l.16.)word}! +${(r.16.)word}+
+0:simple padding
+>! obfuscatory! +obfuscatory +
+
+ foo=(resulting words uproariously padded)
+ print ${(pl.10..\x22..X.)foo}
+0:${(pl...)...}
+>Xresulting """"Xwords roariously """Xpadded
+#" deconfuse emacs
+
+ print ${(l.5..X.r.5..Y.)foo}
+ print ${(l.6..X.r.4..Y.)foo}
+ print ${(l.7..X.r.3..Y.)foo}
+ print ${(l.6..X..A.r.6..Y..B.)foo}
+ print ${(l.6..X..AROOGA.r.6..Y..BARSOOM.)foo}
+0:simultaneous left and right padding
+>Xresulting XXXwordsYY proariousl XXpaddedYY
+>XXresultin XXXXwordsY uproarious XXXpaddedY
+>XXXresulti XXXXXwords Xuproariou XXXXpadded
+>XAresultingB XXXAwordsBYY uproariously XXApaddedBYY
+>GAresultingB OOGAwordsBAR uproariously OGApaddedBAR
+
+ foo=(why in goodness name am I doing this)
+ print ${(r.5..!..?.)foo}
+0:${(r...)...}
+>why?! in?!! goodn name? am?!! I?!!! doing this?
+
+ array=(I\'m simply putting a brave face on)
+ print ${(j:--:)array}
+0:${(j)...}
+>I'm--simply--putting--a--brave--face--on
+
+ print ${(F)array}
+0:${(F)...}
+>I'm
+>simply
+>putting
+>a
+>brave
+>face
+>on
+
+ string='zometimez zis getz zplit on a z'
+ print -l ${(s?z?)string}
+0:${(s...)...}
+>ometime
+>
+>is get
+>
+>plit on a
+
+ str=s
+ arr=(a)
+ typeset -A ass
+ ass=(a a)
+ integer i
+ float f
+ print ${(t)str} ${(t)arr} ${(t)ass} ${(t)i} ${(t)f}
+0:${(t)...}
+>scalar array association-local integer-local float-local
+
+ # it's not quite clear that these are actually right unless you know
+ # the algorithm: search along the string for the point at which the
+ # first (last) match occurs, for ## (%%), then take the shortest possible
+ # version of that for # (%). it's as good a definition as anything.
+ string='where is the white windmill, whispered walter wisely'
+ print ${(S)string#h*e}
+ print ${(S)string##h*e}
+ print ${(S)string%h*e}
+ print ${(S)string%%h*e}
+0:${(S)...#...} etc.
+>wre is the white windmill, whispered walter wisely
+>wly
+>where is the white windmill, wred walter wisely
+>where is the white windmill, wly
+
+ setopt extendedglob
+ print ${(SI:1:)string##w[^[:space:]]# }
+ print ${(SI:1+1:)string##w[^[:space:]]# }
+ print ${(SI:1+1+1:)string##w[^[:space:]]# }
+ print ${(SI:1+1+1+1:)string##w[^[:space:]]# }
+0:${(I:...:)...}
+>is the white windmill, whispered walter wisely
+>where is the windmill, whispered walter wisely
+>where is the white whispered walter wisely
+>where is the white windmill, walter wisely
+
+ print ${(MSI:1:)string##w[^[:space:]]# }
+0:${(M...)...}
+>where
+
+ print ${(R)string//w[a-z]# #}
+0:${(R)...}
+>is the ,
+
+ # This (1) doesn't work with // or /
+ # (2) perhaps ought to be 18, to be consistent with normal zsh
+ # substring indexing and with backreferences.
+ print ${(BES)string##white}
+0:${(BE...)...}
+>14 19
+
+ print ${(NS)string##white}
+0:${(N)...}
+>5
+
+ string='abcdefghijklmnopqrstuvwxyz'
+ print ${${string%[aeiou]*}/(#m)?(#e)/${(U)MATCH}}
+0:Rule 1: Nested substitutions
+>abcdefghijklmnopqrsT
+
+ array=(et Swann avec cette muflerie intermittente)
+ string="qui reparaissait chez lui"
+ print ${array[4,5]}
+ print ${array[4,5][1]}
+ print ${array[4,5][1][2,3]}
+ print ${string[4,5]}
+ print ${string[4,5][1]}
+0:Rule 2: Parameter subscripting
+>cette muflerie
+>cette
+>et
+> r
+>
+
+ foo=stringalongamax
+ print ${${(P)foo[1,6]}[1,3]}
+0:Rule 3: Parameter Name Replacement
+>qui
+
+ print "${array[5,6]}"
+ print "${(j.:.)array[1,2]}"
+0:Rule 4: Double-Quoted Joining
+>muflerie intermittente
+>et:Swann
+
+ print "${${array}[5,7]}"
+ print "${${(@)array}[1,2]}"
+0:Rule 5: Nested Subscripting
+>wan
+>et Swann
+
+ print "${${(@)array}[1,2]#?}"
+ print "${(@)${(@)array}[1,2]#?}"
+0:Rule 6: Modifiers
+>t Swann
+>t wann
+
+ array=(she sells z shells by the z shore)
+ (IFS='+'; print ${(s.s.)array})
+0:Rule 7: Forced Joining, and 8: Forced splitting
+>he+ ell +z+ hell +by+the+z+ hore
+
+ setopt shwordsplit
+ string='another poxy boring string'
+ print -l ${${string}/o/ }
+ unsetopt shwordsplit
+0:Rule 9: Shell Word Splitting
+>an
+>ther
+>p
+>xy
+>b
+>ring
+>string
+
+ setopt nonomatch
+ foo='b* e*'
+ print ${(e)~foo}
+ print ${(e)~=foo}
+ setopt nomatch
+0:Rule 10: Re-Evaluation
+>b* e*
+>boringfile evenmoreboringfile
+
+ # ${bar} -> $bar here would yield "bad substitution".
+ bar=confinement
+ print ${(el.20..X.)${bar}}
+0:Rule 11: Padding
+>XXXXXXXXXconfinement
+
+ foo=(bar baz)
+ bar=(ax1 bx1)
+ print "${(@)${foo}[1]}"
+ print "${${(@)foo}[1]}"
+ print -l ${(s/x/)bar}
+ print -l ${(j/x/s/x/)bar}
+ print -l ${(s/x/)bar%%1*}
+0:Examples in manual on parameter expansion
+>b
+>bar
+>a
+>1 b
+>1
+>a
+>1
+>b
+>1
+>a
+> b
+
+ set If "this test fails" "we have broken" the shell again
+ print -l ${1+"$@"}
+0:Regression test of ${1+"$@"} bug
+>If
+>this test fails
+>we have broken
+>the
+>shell
+>again
+
+ set If "this test fails" "we have broken" the shell again
+ print -l "${(A)foo::=$@}"
+ print -l ${(t)foo}
+ print -l $foo
+0:Regression test of "${(A)foo=$@}" bug
+>If this test fails we have broken the shell again
+>array
+>If
+>this test fails
+>we have broken
+>the
+>shell
+>again
+
+ local sure_that='sure that' varieties_of='varieties of' one=1 two=2
+ extra=(5 4 3)
+ unset foo
+ set Make $sure_that "this test keeps" on 'preserving all' "$varieties_of" quoted whitespace
+ print -l ${=1+"$@"}
+ print -l ${(A)=foo=Make $sure_that "this test keeps" on 'preserving all' "$varieties_of" quoted whitespace}
+ print ${(t)foo}
+ print -l ${=1+$one $two}
+ print -l ${1+$extra$two$one}
+0:Regression test of ${=1+"$@"} bug and some related expansions
+>Make
+>sure that
+>this test keeps
+>on
+>preserving all
+>varieties of
+>quoted
+>whitespace
+>Make
+>sure
+>that
+>this test keeps
+>on
+>preserving all
+>varieties of
+>quoted
+>whitespace
+>array
+>1
+>2
+>5
+>4
+>321
+
+ splitfn() {
+ emulate -L sh
+ local HOME="/differs from/bash" foo='1 2' bar='3 4'
+ print -l ${1:-~}
+ touch has\ space
+ print -l ${1:-*[ ]*}
+ print -l ${1:-*[\ ]*}
+ print -l ${1:-*}
+ print -l ${1:-"$foo" $bar}
+ print -l ${==1:-$foo $bar}
+ rm has\ space
+ }
+ splitfn
+0:More bourne-shell-compatible nested word-splitting with wildcards and ~
+>/differs from/bash
+>*[
+>]*
+>has space
+>boringfile
+>evenmoreboringfile
+>has space
+>1 2
+>3
+>4
+>1 2 3 4
+
+ splitfn() {
+ local IFS=.-
+ local foo=1-2.3-4
+ #
+ print "Called with argument '$1'"
+ print "No quotes"
+ print -l ${=1:-1-2.3-4} ${=1:-$foo}
+ print "With quotes on default argument only"
+ print -l ${=1:-"1-2.3-4"} ${=1:-"$foo"}
+ }
+ print 'Using "="'
+ splitfn
+ splitfn 5.6-7.8
+ #
+ splitfn() {
+ emulate -L zsh
+ setopt shwordsplit
+ local IFS=.-
+ local foo=1-2.3-4
+ #
+ print "Called with argument '$1'"
+ print "No quotes"
+ print -l ${1:-1-2.3-4} ${1:-$foo}
+ print "With quotes on default argument only"
+ print -l ${1:-"1-2.3-4"} ${1:-"$foo"}
+ }
+ print Using shwordsplit
+ splitfn
+ splitfn 5.6-7.8
+0:Test of nested word splitting with and without quotes
+>Using "="
+>Called with argument ''
+>No quotes
+>1
+>2
+>3
+>4
+>1
+>2
+>3
+>4
+>With quotes on default argument only
+>1-2.3-4
+>1-2.3-4
+>Called with argument '5.6-7.8'
+>No quotes
+>5
+>6
+>7
+>8
+>5
+>6
+>7
+>8
+>With quotes on default argument only
+>5
+>6
+>7
+>8
+>5
+>6
+>7
+>8
+>Using shwordsplit
+>Called with argument ''
+>No quotes
+>1
+>2
+>3
+>4
+>1
+>2
+>3
+>4
+>With quotes on default argument only
+>1-2.3-4
+>1-2.3-4
+>Called with argument '5.6-7.8'
+>No quotes
+>5
+>6
+>7
+>8
+>5
+>6
+>7
+>8
+>With quotes on default argument only
+>5
+>6
+>7
+>8
+>5
+>6
+>7
+>8
+
+# Tests a long-standing bug with joining on metafied characters in IFS
+ (array=(one two three)
+ IFS=$'\0'
+ foo="$array"
+ for (( i = 1; i <= ${#foo}; i++ )); do
+ char=${foo[i]}
+ print $(( #char ))
+ done)
+0:Joining with NULL character from IFS
+>111
+>110
+>101
+>0
+>116
+>119
+>111
+>0
+>116
+>104
+>114
+>101
+>101
+
+ unset SHLVL
+ (( SHLVL++ ))
+ print $SHLVL
+0:Unsetting and recreation of numerical special parameters
+>1
+
+ unset manpath
+ print $+MANPATH
+ manpath=(/here /there)
+ print $MANPATH
+ unset MANPATH
+ print $+manpath
+ MANPATH=/elsewhere:/somewhere
+ print $manpath
+0:Unsetting and recreation of tied special parameters
+>0
+>/here:/there
+>0
+>/elsewhere /somewhere
+
+ local STRING=a:b
+ typeset -T STRING string
+ print $STRING $string
+ unset STRING
+ set -A string x y z
+ print $STRING $string
+ STRING=a:b
+ typeset -T STRING string
+ print $STRING $string
+ unset STRING
+ set -A string x y z
+ print $STRING $string
+ STRING=a:b
+ typeset -T STRING string
+ print $STRING $string
+ unset string
+ STRING=x:y:z
+ print $STRING $string
+ STRING=a:b
+ typeset -T STRING string
+ print $STRING $string
+ unset string
+ STRING=x:y:z
+ print $STRING $string
+0:Unsetting and recreation of tied normal parameters
+>a:b a b
+>x y z
+>a:b a b
+>x y z
+>a:b a b
+>x:y:z
+>a:b a b
+>x:y:z
+
+ typeset -T tied1 tied2 +
+ typeset -T tied2 tied1 +
+1:Attempts to swap tied variables are safe but futile
+?(eval):typeset:2: already tied as non-scalar: tied2
+
+ string='look for a match in here'
+ if [[ ${string%%(#b)(match)*} = "look for a " ]]; then
+ print $match[1] $mbegin[1] $mend[1] $string[$mbegin[1],$mend[1]]
+ print $#match $#mbegin $#mend
+ else
+ print That didn\'t work.
+ fi
+0:Parameters associated with backreferences
+>match 12 16 match
+>1 1 1
+#' deconfuse emacs
+
+ string='and look for a MATCH in here'
+ if [[ ${(S)string%%(#m)M*H} = "and look for a in here" ]]; then
+ print $MATCH $MBEGIN $MEND $string[$MBEGIN,$MEND]
+ print $#MATCH
+ else
+ print Oh, dear. Back to the drawing board.
+ fi
+0:Parameters associated with (#m) flag
+>MATCH 16 20 MATCH
+>5
+
+ string='this is a string'
+ print ${string//(#m)s/$MATCH $MBEGIN $MEND}
+0:(#m) flag with pure string
+>this 4 4 is 7 7 a s 11 11tring
+
+ print ${${~:-*}//(#m)*/$MATCH=$MATCH}
+0:(#m) flag with tokenized input
+>*=*
+
+ print -l JAMES${(u)${=:-$(echo yes yes)}}JOYCE
+ print -l JAMES${(u)${=:-$(echo yes yes she said yes i will yes)}}JOYCE
+0:Bug with (u) flag reducing arrays to one element
+>JAMESyesJOYCE
+>JAMESyes
+>she
+>said
+>i
+>willJOYCE
+
+ print -l JAMES${(u)${=:-$(echo yes yes she said yes i will yes she said she will and yes she did yes)}}JOYCE
+0:New hash seive unique algorithm for arrays of more than 10 elements
+>JAMESyes
+>she
+>said
+>i
+>will
+>and
+>didJOYCE
+
+ foo=
+ print "${${foo}/?*/replacement}"
+0:Quoted zero-length strings are handled properly
+>
+
+ file=aleftkept
+ print ${file//(#b)(*)left/${match/a/andsome}}
+ print ${file//(#b)(*)left/${match//a/andsome}}
+0:Substitutions where $match is itself substituted in the replacement
+>andsomekept
+>andsomekept
+
+ file=/one/two/three/four
+ print ${file:fh}
+ print ${file:F.1.h}
+ print ${file:F+2+h}
+ print ${file:F(3)h}
+ print ${file:F<4>h}
+ print ${file:F{5}h}
+0:Modifiers with repetition
+>/
+>/one/two/three
+>/one/two
+>/one
+>/
+>/
+
+ baz=foo/bar
+ zab=oof+rab
+ print ${baz:s/\//+/}
+ print "${baz:s/\//+/}"
+ print ${zab:s/+/\//}
+ print "${zab:s/+/\//}"
+0:Quoting of separator in substitution modifier
+>foo+bar
+>foo+bar
+>oof/rab
+>oof/rab
+
+ bsbs='X\\\\Y'
+ print -r -- ${bsbs:s/\\/\\/}
+ print -r -- "${bsbs:s/\\/\\/}"
+ print -r -- ${bsbs:s/\\\\/\\\\/}
+ print -r -- "${bsbs:s/\\\\/\\\\/}"
+ print -r -- ${bsbs:gs/\\/\\/}
+ print -r -- "${bsbs:gs/\\/\\/}"
+ print -r -- ${bsbs:gs/\\\\/\\\\/}
+ print -r -- "${bsbs:gs/\\\\/\\\\/}"
+0:Handling of backslashed backslashes in substitution modifier
+>X\\\\Y
+>X\\\\Y
+>X\\\\Y
+>X\\\\Y
+>X\\\\Y
+>X\\\\Y
+>X\\\\Y
+>X\\\\Y
+
+ print -r ${${:-one/two}:s,/,X&Y,}
+ print -r ${${:-one/two}:s,/,X\&Y,}
+ print -r ${${:-one/two}:s,/,X\\&Y,}
+ print -r "${${:-one/two}:s,/,X&Y,}"
+ print -r "${${:-one/two}:s,/,X\&Y,}"
+ print -r "${${:-one/two}:s,/,X\\&Y,}"
+0:Quoting of ampersand in substitution modifier RHS
+>oneX/Ytwo
+>oneX&Ytwo
+>oneX\/Ytwo
+>oneX/Ytwo
+>oneX&Ytwo
+>oneX\/Ytwo
+
+ nully=($'a\0c' $'a\0b\0b' $'a\0b\0a' $'a\0b\0' $'a\0b' $'a\0' $'a')
+ for string in ${(o)nully}; do
+ for (( i = 1; i <= ${#string}; i++ )); do
+ foo=$string[i]
+ printf "%02x" $(( #foo ))
+ done
+ print
+ done
+0:Sorting arrays with embedded nulls
+>61
+>6100
+>610062
+>61006200
+>6100620061
+>6100620062
+>610063
+
+ array=(X)
+ patterns=("*X*" "spong" "a[b")
+ for pat in $patterns; do
+ print A${array[(r)$pat]}B C${array[(I)$pat]}D
+ done
+0:Bad patterns should never match array elements
+>AXB C1D
+>AB C0D
+>AB C0D
+
+ foo=(a6 a117 a17 b6 b117 b17)
+ print ${(n)foo}
+ print ${(On)foo}
+0:Numeric sorting
+>a6 a17 a117 b6 b17 b117
+>b117 b17 b6 a117 a17 a6
+
+ x=sprodj
+ x[-10]=scrumf
+ print $x
+0:Out of range negative scalar subscripts
+>scrumfsprodj
+
+ a=(some sunny day)
+ a[-10]=(we\'ll meet again)
+ print -l $a
+0:Out of range negative array subscripts
+>we'll
+>meet
+>again
+>some
+>sunny
+>day
+
+# ' emacs likes this close quote
+
+ a=(sping spang spong bumble)
+ print ${a[(i)spong]}
+ print ${a[(i)spung]}
+ print ${a[(ib.1.)spong]}
+ print ${a[(ib.4.)spong]}
+ print ${a[(ib.10.)spong]}
+0:In and out of range reverse matched indices without and with b: arrays
+>3
+>5
+>3
+>5
+>5
+
+ a="thrimblewuddlefrong"
+ print ${a[(i)w]}
+ print ${a[(i)x]}
+ print ${a[(ib.3.)w]}
+ print ${a[(ib.10.)w]}
+ print ${a[(ib.30.)w]}
+0:In and out of range reverse matched indices without and with b: strings
+>9
+>20
+>9
+>20
+>20
+
+ foo="line:with::missing::fields:in:it"
+ print -l ${(s.:.)foo}
+0:Removal of empty fields in unquoted splitting
+>line
+>with
+>missing
+>fields
+>in
+>it
+
+ foo="line:with::missing::fields:in:it"
+ print -l "${(s.:.)foo}"
+0:Hacky removal of empty fields in quoted splitting with no "@"
+>line
+>with
+>missing
+>fields
+>in
+>it
+
+ foo="line:with::missing::fields:in:it:"
+ print -l "${(@s.:.)foo}"
+0:Retention of empty fields in quoted splitting with "@"
+>line
+>with
+>
+>missing
+>
+>fields
+>in
+>it
+>
+
+ str=abcd
+ print -l ${(s..)str}
+ print -l "${(s..)str}"
+0:splitting of strings into characters
+>a
+>b
+>c
+>d
+>a
+>b
+>c
+>d
+
+ array=('%' '$' 'j' '*' '$foo')
+ print ${array[(i)*]} "${array[(i)*]}"
+ print ${array[(ie)*]} "${array[(ie)*]}"
+ key='$foo'
+ print ${array[(ie)$key]} "${array[(ie)$key]}"
+ key='*'
+ print ${array[(ie)$key]} "${array[(ie)$key]}"
+0:Matching array indices with and without quoting
+>1 1
+>4 4
+>5 5
+>4 4
+
+# Ordering of associative arrays is arbitrary, so we need to use
+# patterns that only match one element.
+ typeset -A assoc_r
+ assoc_r=(star '*' of '*this*' and '!that!' or '(the|other)')
+ print ${(kv)assoc_r[(re)*]}
+ print ${(kv)assoc_r[(re)*this*]}
+ print ${(kv)assoc_r[(re)!that!]}
+ print ${(kv)assoc_r[(re)(the|other)]}
+ print ${(kv)assoc_r[(r)*at*]}
+ print ${(kv)assoc_r[(r)*(ywis|bliss|kiss|miss|this)*]}
+ print ${(kv)assoc_r[(r)(this|that|\(the\|other\))]}
+0:Reverse subscripting associative arrays with literal matching
+>star *
+>of *this*
+>and !that!
+>or (the|other)
+>and !that!
+>of *this*
+>or (the|other)
+
+ print $ZSH_SUBSHELL
+ (print $ZSH_SUBSHELL)
+ ( (print $ZSH_SUBSHELL) )
+ ( (print $ZSH_SUBSHELL); print $ZSH_SUBSHELL )
+ print $(print $ZSH_SUBSHELL)
+ cat =(print $ZSH_SUBSHELL)
+0:ZSH_SUBSHELL
+>0
+>1
+>2
+>2
+>1
+>1
+>1
+
+ foo=("|" "?")
+ [[ "|" = ${(j.|.)foo} ]] && print yes || print no
+ [[ "|" = ${(j.|.)~foo} ]] && print yes || print no
+ [[ "|" = ${(~j.|.)foo} ]] && print yes || print no
+ [[ "|" = ${(~~j.|.)foo} ]] && print yes || print no
+ [[ "|" = ${(j.|.~)foo} ]] && print yes || print no
+ [[ "x" = ${(j.|.)foo} ]] && print yes || print no
+ [[ "x" = ${(j.|.)~foo} ]] && print yes || print no
+ [[ "x" = ${(~j.|.)foo} ]] && print yes || print no
+ [[ "x" = ${(~~j.|.)foo} ]] && print yes || print no
+ [[ "x" = ${(j.|.~)foo} ]] && print yes || print no
+0:GLOBSUBST only on parameter substitution arguments
+>no
+>yes
+>yes
+>no
+>no
+>no
+>yes
+>no
+>no
+>no
+
+ rcexbug() {
+ emulate -L zsh
+ setopt rcexpandparam
+ local -A hash
+ local -a full empty
+ full=(X x)
+ hash=(X x)
+ print ORDINARY ARRAYS
+ : The following behaves as documented in zshoptions
+ print FULL expand=$full
+ : Empty arrays remove the adjacent argument
+ print EMPTY expand=$empty
+ print ASSOCIATIVE ARRAY
+ print Subscript flags returning many values
+ print FOUND key=$hash[(I)X] val=$hash[(R)x]
+ : This should behave like $empty, and does
+ print LOST key=$hash[(I)y] val=$hash[(R)Y]
+ print Subscript flags returning single values
+ : Doc says "substitutes ... empty string"
+ : so must not behave like an empty array
+ print STRING key=$hash[(i)y] val=$hash[(r)Y]
+ }
+ rcexbug
+0:Lookup failures on elements of arrays with RC_EXPAND_PARAM
+>ORDINARY ARRAYS
+>FULL expand=X expand=x
+>EMPTY
+>ASSOCIATIVE ARRAY
+>Subscript flags returning many values
+>FOUND key=X val=x
+>LOST
+>Subscript flags returning single values
+>STRING key= val=
+
+ print $zsh_eval_context[1]
+ [[ $ZSH_EVAL_CONTEXT = ${(j.:.)zsh_eval_context} ]] || print Not equal!
+ (( icontext = ${#zsh_eval_context} + 1 ))
+ contextfn() { print $(print $zsh_eval_context[icontext,-1]); }
+ contextfn
+0:$ZSH_EVAL_CONTEXT and $zsh_eval_context
+>toplevel
+>shfunc cmdsubst
+
+ foo="123456789"
+ print ${foo:3}
+ print ${foo: 1 + 3}
+ print ${foo:$(( 2 + 3))}
+ print ${foo:$(echo 3 + 3)}
+ print ${foo:3:1}
+ print ${foo: 1 + 3:(4-2)/2}
+ print ${foo:$(( 2 + 3)):$(( 7 - 6 ))}
+ print ${foo:$(echo 3 + 3):`echo 4 - 3`}
+ print ${foo: -1}
+ print ${foo: -10}
+ print ${foo:5:-2}
+0:Bash-style offsets, scalar
+>456789
+>56789
+>6789
+>789
+>4
+>5
+>6
+>7
+>9
+>123456789
+>67
+
+ foo=(1 2 3 4 5 6 7 8 9)
+ print ${foo:3}
+ print ${foo: 1 + 3}
+ print ${foo:$(( 2 + 3))}
+ print ${foo:$(echo 3 + 3)}
+ print ${foo:3:1}
+ print ${foo: 1 + 3:(4-2)/2}
+ print ${foo:$(( 2 + 3)):$(( 7 - 6 ))}
+ print ${foo:$(echo 3 + 3):`echo 4 - 3`}
+ print ${foo: -1}
+ print ${foo: -10}
+ print ${foo:5:-2}
+0:Bash-style offsets, array
+>4 5 6 7 8 9
+>5 6 7 8 9
+>6 7 8 9
+>7 8 9
+>4
+>5
+>6
+>7
+>9
+>1 2 3 4 5 6 7 8 9
+>6 7
+
+ testfn() {
+ emulate -L sh
+ set -A foo 1 2 3
+ set -- 1 2 3
+ str=abc
+ echo ${foo[*]:0:1}
+ echo ${foo[*]:1:1}
+ echo ${foo[*]: -1:1}
+ :
+ echo ${*:0:1}
+ echo ${*:1:1}
+ echo ${*: -1:1}
+ :
+ echo ${str:0:1}
+ echo ${str:1:1}
+ echo ${str: -1:1}
+ }
+ testfn
+0:Bash-style offsets, Bourne-style indexing
+>1
+>2
+>3
+>testfn
+>1
+>3
+>a
+>b
+>c
+
+ printf "%n" '[0]'
+1:Regression test for identifier test
+?(eval):1: not an identifier: [0]
+
+ str=rts
+ print ${str:0:}
+1:Regression test for missing length after offset
+?(eval):2: unrecognized modifier
+
+ foo="123456789"
+ print ${foo:5:-6}
+1:Regression test for total length < 0 in string
+?(eval):2: substring expression: 3 < 5
+
+ foo=(1 2 3 4 5 6 7 8 9)
+ print ${foo:5:-6}
+1:Regression test for total length < 0 in array
+?(eval):2: substring expression: 3 < 5
+
+ foo=(${(0)"$(print -n)"})
+ print ${#foo}
+0:Nularg removed from split empty string
+>0
+
+ (set -- a b c
+ setopt shwordsplit
+ IFS=
+ print -rl "$*"
+ unset IFS
+ print -rl "$*")
+0:Regression test for shwordsplit with null or unset IFS and quoted array
+>abc
+>a b c
+
+ foo=
+ print ${foo:wq}
+ print ${:wq}
+0:Empty parameter should not cause modifiers to crash the shell
+>
+>
+
+# This used to cause uncontrolled behaviour, but at best
+# you got the wrong output so the check is worth it.
+ args() { print $#; }
+ args ${:*}
+ args ${:|}
+0:Intersection and disjunction with empty parameters
+>0
+>0
+
+ foo=(a b c)
+ bar=(1 2 3)
+ print ${foo:^bar}
+ print ${foo:^^bar}
+ foo=(a b c d)
+ bar=(1 2)
+ print ${foo:^bar}
+ print ${foo:^^bar}
+ foo=('a a' b)
+ bar=(1 '2 2')
+ print -l "${foo:^bar}"
+ print -l "${(@)foo:^bar}"
+0:Zipping arrays, correct output
+>a 1 b 2 c 3
+>a 1 b 2 c 3
+>a 1 b 2
+>a 1 b 2 c 1 d 2
+# maybe this should be changed to output "a a b 1"
+>a a b
+>1
+>a a
+>1
+>b
+>2 2
+
+ foo=(a b c)
+ bar=()
+ print ${foo:^bar}
+ print ${foo:^^bar}
+ print ${bar:^foo}
+ print ${bar:^^foo}
+ print ${bar:^bar}
+ print ${bar:^^bar}
+0:Zipping arrays, one or both inputs empty
+>
+>a b c
+>
+>a b c
+>
+>
+
+ foo=text
+ bar=()
+ print ${foo:^bar}
+ print ${bar:^^foo}
+ bar=other
+ print ${foo:^bar}
+ bar=(array elements)
+ print ${foo:^bar}
+ print ${foo:^^bar}
+ print ${bar:^foo}
+ print ${bar:^^foo}
+0:Zipping arrays, scalar input
+>
+>text
+>text other
+>text array
+>text array text elements
+>array text
+>array text elements text
+
+ foo=(a b c)
+ print ${foo:^^^bar}
+1:Zipping arrays, parsing
+?(eval):2: not an identifier: ^bar
+
+ (setopt nounset
+ print ${foo:^noexist})
+1:Zipping arrays, NO_UNSET part 1
+?(eval):2: noexist: parameter not set
+
+ (setopt nounset
+ print ${noexist:^foo})
+1:Zipping arrays, NO_UNSET part 2
+?(eval):2: noexist: parameter not set
+
+ expr="a@b,c@d:e@f,g@h:i@j,k@l"
+ for sep in : , @; do
+ print -l ${(ps.$sep.)expr}
+ done
+0:Use of variable to get separator when splitting parameter
+>a@b,c@d
+>e@f,g@h
+>i@j,k@l
+>a@b
+>c@d:e@f
+>g@h:i@j
+>k@l
+>a
+>b,c
+>d:e
+>f,g
+>h:i
+>j,k
+>l
+
+ SHLVL=1
+ $ZTST_testdir/../Src/zsh -fc 'echo $SHLVL'
+ $ZTST_testdir/../Src/zsh -fc '(echo $SHLVL)'
+0:SHLVL appears sensible when about to exit shell
+>2
+>2
+
+ # SHLVL is incremented twice and decremented once in between.
+ SHLVL=1
+ $ZTST_testdir/../Src/zsh -fc $ZTST_testdir/../Src/zsh' -fc "echo \$SHLVL"'
+ $ZTST_testdir/../Src/zsh -fc '('$ZTST_testdir/../Src/zsh' -fc "echo \$SHLVL")'
+ $ZTST_testdir/../Src/zsh -fc '( ('$ZTST_testdir/../Src/zsh' -fc "echo \$SHLVL"))'
+0:SHLVL decremented upon implicit exec optimisation
+>2
+>2
+>2
+
+ # SHLVL is incremented twice with no decrement in between.
+ SHLVL=1
+ $ZTST_testdir/../Src/zsh -fc '('$ZTST_testdir/../Src/zsh' -fc "echo \$SHLVL"); exit'
+ $ZTST_testdir/../Src/zsh -fc '(exec '$ZTST_testdir/../Src/zsh' -fc "echo \$SHLVL"); exit'
+ $ZTST_testdir/../Src/zsh -fc '( ('$ZTST_testdir/../Src/zsh' -fc "echo \$SHLVL"); exit)'
+0:SHLVL not decremented upon exec in subshells
+>3
+>3
+>3
+
+# The following tests the return behaviour of parsestr/parsestrnoerr
+ alias param-test-alias='print $'\''\x45xpanded in substitution'\'
+ param='$(param-test-alias)'
+ print ${(e)param}
+0:Alias expansion in command substitution in parameter evaluation
+>Expanded in substitution
+
+ a=1 b=2 c=3
+ : One;
+ function {
+ : Two
+ echo $_
+ print -l $argv
+ } $_ Three
+ print -l $_ Four;
+0:$_ with anonymous function
+>Two
+>One
+>Three
+>Three
+>Four
+
+ a=1 b=2 c=3
+ : One
+ function {
+ : Two
+ echo $_
+ print -l $argv
+ }
+ print -l "$_" Four
+0:$_ with anonymous function without arguments
+>Two
+>
+>
+>Four
+
+ funnychars='The qu*nk br!wan f@x j/mps o[]r \(e la~# ^"&;'
+ [[ $funnychars = ${~${(b)funnychars}} ]]
+0:${(b)...} quoting protects from GLOB_SUBST
+
+ set -- foo
+ echo $(( $#*3 ))
+ emulate sh -c 'nolenwithoutbrace() { echo $#-1; }'
+ nolenwithoutbrace
+0:Avoid confusion after overloaded characters in braceless substitution in sh
+>13
+>0-1
+
+ a="aaa bab cac"
+ b=d
+ echo $a:gs/a/${b}/
+ a=(aaa bab cac)
+ echo $a:gs/a/${b}/
+0:History modifier works the same for scalar and array substitution
+>ddd bdb cdc
+>ddd bdb cdc
+
+ a=1_2_3_4_5_6
+ print ${a#(*_)(#c2)}
+ print ${a#(*_)(#c5)}
+ print ${a#(*_)(#c7)}
+0:Complicated backtracking with match counts
+>3_4_5_6
+>6
+>1_2_3_4_5_6
+
+ (setopt shwordsplit
+ do_test() {
+ print $#: "$@"
+ }
+ foo=bar
+ foo2="bar bar"
+ do_test ${:- foo }
+ do_test ${:- foo bar }
+ do_test ${:- $foo }
+ do_test ${:- $foo2 }
+ do_test x${:- foo }y
+ do_test x${:- foo bar }y
+ do_test x${:- $foo }y
+ do_test x${:- $foo2 }y
+ do_test x${foo:+ $foo }y
+ )
+0:We Love SH_WORD_SPLIT Day celebrated with space at start of internal subst
+>1: foo
+>2: foo bar
+>1: bar
+>2: bar bar
+>3: x foo y
+>4: x foo bar y
+>3: x bar y
+>4: x bar bar y
+>3: x bar y
+
+ (unsetopt shwordsplit # default, for clarity
+ do_test() {
+ print $#: "$@"
+ }
+ foo=bar
+ foo2="bar bar"
+ do_test ${:- foo }
+ do_test ${:- foo bar }
+ do_test ${:- $foo }
+ do_test ${:- $foo2 }
+ do_test x${:- foo }y
+ do_test x${:- foo bar }y
+ do_test x${:- $foo }y
+ do_test x${:- $foo2 }y
+ do_test x${foo:+ $foo }y
+ )
+0:We Love NO_SH_WORD_SPLIT Even More Day celebrated as sanity check
+>1: foo
+>1: foo bar
+>1: bar
+>1: bar bar
+>1: x foo y
+>1: x foo bar y
+>1: x bar y
+>1: x bar bar y
+>1: x bar y
+
+ testfn() {
+ local scalar=obfuscation
+ local -a array=(alpha bravo charlie delta echo foxtrot)
+ local -A assoc=(one eins two zwei three drei four vier)
+ local name subscript
+ for name subscript in scalar 3 array 5 assoc three; do
+ print ${${(P)name}[$subscript]}
+ done
+ }
+ testfn
+0:${(P)...} with normal subscripting
+>f
+>echo
+>drei
+
+ testfn() {
+ local s1=foo s2=bar
+ local -a val=(s1)
+ print ${${(P)val}[1,3]}
+ val=(s1 s2)
+ print ${${(P)val}[1,3]}
+ }
+ testfn
+1:${(P)...} with array as name
+>foo
+?testfn:5: parameter name reference used with array
+
+ testfn() {
+ local -A assoc=(one buckle two show three knock four door)
+ local name='assoc[two]'
+ print ${${(P)name}[2,3]}
+ }
+ testfn
+0:${(P)...} with internal subscripting
+>ho
+
+ testfn() {
+ local one=two
+ local two=three
+ local three=four
+ local -a four=(all these worlds belong to foo)
+ print ${(P)${(P)${(P)one}}}
+ print ${${(P)${(P)${(P)one}}}[3]}
+ }
+ testfn
+0:nested parameter name references
+>all these worlds belong to foo
+>worlds
+
+ (
+ path=(/random /value)
+ testfn1() {
+ local path=
+ print $#path
+ }
+ testfn1
+ testfn2() {
+ local path=/somewhere
+ print $#path $path
+ }
+ testfn2
+ print $#path $path
+ )
+0:Local special variables with loose typing
+>0
+>1 /somewhere
+>2 /random /value
+
+ print -r -- ${(q+):-}
+ print -r -- ${(q+)IFS}
+ print -r -- ${(q+):-oneword}
+ print -r -- ${(q+):-two words}
+ print -r -- ${(q+):-three so-called \'words\'}
+ (setopt rcquotes; print -r -- ${(q+):-three so-called \'words\'})
+0:${(q+)...}
+>''
+>$' \t\n\C-@'
+>oneword
+>'two words'
+>'three so-called '\''words'\'
+>'three so-called ''words'''
+
+ array=(one two three)
+ array[1]=${nonexistent:-foo}
+ print $array
+0:"-" works after "[" in same expression (Dash problem)
+>foo two three
+
+ (
+ setopt shwordsplit
+ set -- whim:wham:whom
+ IFS=:
+ print -l $@
+ )
+0:Splitting of $@ on IFS: single element
+>whim
+>wham
+>whom
+
+ (
+ setopt shwordsplit
+ set -- one:two bucklemy:shoe
+ IFS=:
+ print -l $@
+ )
+0:Splitting of $@ on IFS: multiple elements
+# No forced joining in this case
+>one
+>two
+>bucklemy
+>shoe
+
+ (
+ set -- one:two bucklemy:shoe
+ print -l ${(s.:.)@}
+ )
+0:Splitting of $@ on (s): multiple elements
+# Forced joining in this case
+>one
+>two bucklemy
+>shoe
+
+ (
+ set -- one:two bucklemy:shoe
+ print -l ${(@s.:.)@}
+ )
+0:Splitting of $@ on (@s): multiple elements
+# Forced non-joining in this case
+>one
+>two
+>bucklemy
+>shoe
+
+ (
+ set -- one:two bucklemy:shoe
+ IFS=
+ setopt shwordsplit
+ print -l ${@} ${(s.:.)*} ${(s.:.j.-.)*}
+ )
+0:Joining of $@ does not happen when IFS is empty, but splitting $* does
+>one:two
+>bucklemy:shoe
+>one
+>twobucklemy
+>shoe
+>one
+>two-bucklemy
+>shoe
+
+ (
+ set -- "one two" "bucklemy shoe"
+ IFS=
+ setopt shwordsplit rcexpandparam
+ print -l "X${(@j.-.)*}"
+ )
+0:Use of @ does not prevent forced join with j
+>Xone two-bucklemy shoe
+
+ () { print -r -- "${(q)1}" "${(b)1}" "${(qq)1}" } '=foo'
+0:(q) and (b) quoting deal with the EQUALS option
+>\=foo =foo '=foo'
+
+ args() { print $#; }
+ a=(foo)
+ args "${a[3,-1]}"
+ args "${(@)a[3,-1]}"
+0:Out-of-range multiple array subscripts with quoting, with and without (@)
+>1
+>0
+
+ a='~-/'; echo $~a
+0:Regression: "-" became Dash in workers/37689, breaking ~- expansion
+*>*
+F:We do not care what $OLDPWD is, as long as it doesn't cause an error
diff --git a/dotfiles/system/.zsh/modules/Test/D05array.ztst b/dotfiles/system/.zsh/modules/Test/D05array.ztst
new file mode 100644
index 0000000..1fa607d
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/D05array.ztst
@@ -0,0 +1,112 @@
+# Tests for array indexing
+
+%prep
+
+ foo=(a b c d e f g)
+ arr=(foo bar baz)
+ mkdir array.tmp
+ touch array.tmp/{1..9}
+
+%test
+
+ echo .$foo[1].
+0:The first element
+>.a.
+
+ echo .$foo[1,4].
+0:Normal multi-item indexing
+>.a b c d.
+
+ echo .$foo[1,0].
+0:This should be empty
+>..
+
+ echo .$foo[4,1].
+0:Another empty slice
+>..
+
+ echo .$foo[1,-8].
+0:An empty slice with a negative end
+>..
+
+ echo .$foo[0].
+0:Treat 0 as empty
+>..
+
+ echo .$foo[0,0].
+0:Treat 0,0 as empty
+>..
+
+ echo .$foo[0,1].
+0:Another weird way to access the first element
+>.a.
+
+ echo .$foo[3].
+0:An inner element
+>.c.
+
+ echo .$foo[2,2].
+0:Another inner element
+>.b.
+
+ echo .$foo[2,-4].
+0:A slice with a negative end
+>.b c d.
+
+ echo .$foo[-4,5].
+0:A slice with a negative start
+>.d e.
+
+ echo .$foo[-6,-2].
+0:A slice with a negative start and end
+>.b c d e f.
+
+ echo .${${arr[2]}[1]}.
+ echo .${${arr[-2]}[1]}.
+ echo .${${arr[2,2]}[1]}.
+ echo .${${arr[-2,-2]}[1]}.
+ echo .${${arr[2,-2]}[1]}.
+ echo .${${arr[-2,2]}[1]}.
+0:Slices should return an array, elements a scalar
+>.b.
+>.b.
+>.bar.
+>.bar.
+>.bar.
+>.bar.
+
+ setopt ksh_arrays
+ echo .${foo[1,2]}.
+ unsetopt ksh_arrays
+0:Ksh array indexing
+>.b c.
+
+ setopt ksh_arrays
+ echo .${foo[0,1]}.
+ unsetopt ksh_arrays
+0:Ksh array indexing (ii)
+>.a b.
+
+ setopt ksh_arrays
+ echo .${foo[1,-1]}.
+ unsetopt ksh_arrays
+0:Ksh array indexing (iii)
+>.b c d e f g.
+
+ cd array.tmp
+ echo . ?([3,5]) .
+ cd ..
+0:Glob array indexing
+>. 3 4 5 .
+
+ cd array.tmp
+ echo . ?([2,-2]) .
+ cd ..
+0:Glob array indexing (ii)
+>. 2 3 4 5 6 7 8 .
+
+ cd array.tmp
+ echo . ?([-6,-4]) .
+ cd ..
+0:Glob array indexing (iii)
+>. 4 5 6 .
diff --git a/dotfiles/system/.zsh/modules/Test/D06subscript.ztst b/dotfiles/system/.zsh/modules/Test/D06subscript.ztst
new file mode 100644
index 0000000..1449236
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/D06subscript.ztst
@@ -0,0 +1,268 @@
+# Test parameter subscripting.
+
+%prep
+
+ s='Twinkle, twinkle, little *, [how] I [wonder] what? You are!'
+ a=('1' ']' '?' '\2' '\]' '\?' '\\3' '\\]' '\\?' '\\\4' '\\\]' '\\\?')
+ typeset -g -A A
+ A=($a)
+
+%test
+
+ x=','
+ print $s[(i)winkle] $s[(I)winkle]
+ print ${s[(i)You are]} $#s
+ print ${s[(r)$x,(R)$x]}
+0:Scalar pattern subscripts without wildcards
+>2 11
+>53 60
+>, twinkle, little *,
+
+ x='*'
+ print $s[(i)*] $s[(i)\*] $s[(i)$x*] $s[(i)${(q)x}*] $s[(I)$x\*]
+ print $s[(r)?,(R)\?] $s[(r)\?,(R)?]
+ print $s[(r)\*,(R)*]
+ print $s[(r)\],(R)\[]
+0:Scalar pattern subscripts with wildcards
+>1 26 1 26 26
+>Twinkle, twinkle, little *, [how] I [wonder] what? ? You are!
+>*, [how] I [wonder] what? You are!
+>] I [
+
+ print $s[(i)x] : $s[(I)x]
+ print $s[(r)x] : $s[(R)x]
+0:Scalar pattern subscripts that do not match
+>61 : 0
+>:
+
+ print -R $s[$s[(i)\[]] $s[(i)$s[(r)\*]] $s[(i)${(q)s[(r)\]]}]
+0:Scalar subscripting using a pattern subscript to get the index
+>[ 1 33
+
+ print -R $a[(r)?] $a[(R)?]
+ print $a[(n:2:i)?] $a[(n:2:I)?]
+ print $a[(i)\?] $a[(I)\?]
+ print $a[(i)*] $a[(i)\*]
+0:Array pattern subscripts
+>1 ?
+>2 2
+>3 3
+>1 13
+
+ # It'd be nice to do some of the following with (r), but we run into
+ # limitations of the ztst script parsing of backslashes in the output.
+ print -R $a[(i)\\\\?] $a[(i)\\\\\?]
+ print -R $a[(i)\\\\\\\\?] $a[(i)\\\\\\\\\?]
+ print -R ${a[(i)\\\\\\\\?]} ${a[(i)\\\\\\\\\?]}
+ print -R "$a[(i)\\\\\\\\?] $a[(i)\\\\\\\\\?]"
+ print -R $a[(i)\]] $a[(i)\\\\\]] $a[(i)\\\\\\\\\]] $a[(i)\\\\\\\\\\\\\]]
+ print -R $a[(i)${(q)a[5]}] $a[(i)${(q)a[8]}] $a[(i)${(q)a[11]}]
+ print -R $a[(i)${a[3]}] $a[(i)${a[6]}] $a[(i)${a[9]}] $a[(i)${a[12]}]
+0:Array pattern subscripts with multiple backslashes
+>4 6
+>7 9
+>7 9
+>7 9
+>2 5 8 11
+>5 8 11
+>1 3 4 6
+
+ print -R $A[1] $A[?] $A[\\\\3] $A[\\\]]
+ print -R $A[$a[11]]
+ print -R $A[${(q)a[5]}]
+0:Associative array lookup (direct subscripting)
+>] \2 \\] \?
+>\\\?
+>\\\?
+
+ # The (o) is necessary here for predictable output ordering
+ print -R $A[(I)\?] ${(o)A[(I)?]}
+ print -R $A[(i)\\\\\\\\3]
+ print -R $A[(I)\\\\\\\\\?] ${(o)A[(I)\\\\\\\\?]}
+0:Associative array lookup (pattern subscripting)
+>? 1 ?
+>\\3
+>\\? \\3 \\?
+
+ print -R $A[(R)\?] : ${(o)A[(R)?]}
+ print -R $A[(R)\\\\\?] ${(o)A[(R)\\\\?]} ${(o)A[(R)\\\\\?]}
+ print -R ${(o)A[(R)\\\\\\\\\]]}
+0:Associative array lookup (reverse subscripting)
+>: ]
+>\? \2 \? \?
+>\\]
+
+ eval 'A[*]=star'
+1:Illegal associative array assignment
+?(eval):1: A: attempt to set slice of associative array
+
+ x='*'
+ A[$x]=xstar
+ A[${(q)x}]=qxstar
+ print -R ${(k)A[(r)xstar]} $A[$x]
+ print -R ${(k)A[(r)qxstar]} $A[${(q)x}]
+ A[(e)*]=star
+ A[\*]=backstar
+ print -R ${(k)A[(r)star]} $A[(e)*]
+ print -R ${(k)A[(r)backstar]} $A[\*]
+0:Associative array assignment
+>* xstar
+>\* qxstar
+>* star
+>\* backstar
+
+ o='['
+ c=']'
+ A[\]]=cbrack
+ A[\[]=obrack
+ A[\\\[]=backobrack
+ A[\\\]]=backcbrack
+ print -R $A[$o] $A[$c] $A[\[] $A[\]] $A[\\\[] $A[\\\]]
+ print -R $A[(i)\[] $A[(i)\]] $A[(i)\\\\\[] $A[(i)\\\\\]]
+0:Associative array keys with open and close brackets
+>obrack cbrack obrack cbrack backobrack backcbrack
+>[ ] \[ \]
+
+ print -R $A[$o] $A[$s[(r)\[]]
+ print -R $A[(r)$c] $A[(r)$s[(r)\]]]
+ print -R $A[$A[(i)\\\\\]]]
+0:Associative array lookup using a pattern subscript to get the key
+>obrack obrack
+>] ]
+>backcbrack
+
+ print -R ${A[${A[(r)\\\\\\\\\]]}]::=zounds}
+ print -R ${A[${A[(r)\\\\\\\\\]]}]}
+ print -R $A[\\\\\]]
+0:Associative array substitution-assignment with reverse pattern subscript key
+>zounds
+>zounds
+>zounds
+
+ print -R ${(o)A[(K)\]]}
+ print -R ${(o)A[(K)\\\]]}
+0:Associative array keys interpreted as patterns
+>\2 backcbrack cbrack star
+>\\\4 \\\? star zounds
+
+# It doesn't matter which element we get, since we never guarantee
+# ordering of an associative array. So just test the number of matches.
+ array=(${(o)A[(k)\]]})
+ print ${#array}
+ array=(${(o)A[(k)\\\]]})
+ print ${#array}
+0:Associative array keys interpreted as patterns, single match
+>1
+>1
+
+ typeset -g "A[one\"two\"three\"quotes]"=QQQ
+ typeset -g 'A[one\"two\"three\"quotes]'=qqq
+ print -R "$A[one\"two\"three\"quotes]"
+ print -R $A[one\"two\"three\"quotes]
+ A[one"two"three"four"quotes]=QqQq
+ print -R $A[one"two"three"four"quotes]
+ print -R $A[$A[(i)one\"two\"three\"quotes]]
+ print -R "$A[$A[(i)one\"two\"three\"quotes]]"
+0:Associative array keys with double quotes
+>QQQ
+>qqq
+>QqQq
+>qqq
+>QQQ
+
+ print ${x::=$A[$A[(i)one\"two\"three\"quotes]]}
+ print $x
+ print ${x::="$A[$A[(i)one\"two\"three\"quotes]]"}
+ print $x
+0:More keys with double quotes, used in assignment-expansion
+>qqq
+>qqq
+>QQQ
+>QQQ
+
+ qqq=lower
+ QQQ=upper
+ print ${(P)A[one\"two\"three\"quotes]}
+ print "${(P)A[$A[(i)one\"two\"three\"quotes]]}"
+0:Keys with double quotes and the (P) expansion flag
+>lower
+>upper
+
+ typeset -ga empty
+ echo X${${empty##*}[-1]}X
+0:Negative index applied to substition result from empty array
+>XX
+
+ print $empty[(i)] $empty[(I)]
+0:(i) returns 1 for empty array, (I) returns 0.
+>1 0
+
+ array=(one two three four)
+ print X$array[0]X
+0:Element zero is empty if KSH_ZERO_SUBSCRIPT is off.
+>XX
+
+ array[0]=fumble
+1:Can't set element zero if KSH_ZERO_SUBSCRIPT is off.
+?(eval):1: array: assignment to invalid subscript range
+
+ print X$array[(R)notfound]X
+0:(R) returns empty if not found if KSH_ZERO_SUBSCRIPT is off.
+>XX
+
+ setopt KSH_ZERO_SUBSCRIPT
+ print X$array[0]X
+0:Element zero is element one if KSH_ZERO_SUBSCRIPT is on.
+>XoneX
+
+ array[0]=fimble
+ print $array
+0:Can set element zero if KSH_ZERO_SUBSCRIPT is on.
+>fimble two three four
+
+ print X$array[(R)notfound]X
+0:(R) yuckily returns the first element on failure withe KSH_ZERO_SUBSCRIPT
+>XfimbleX
+
+ unsetopt KSH_ZERO_SUBSCRIPT
+ array[(R)notfound,(r)notfound]=(help help here come the seventies retreads)
+ print $array
+0:[(R)notfound,(r)notfound] replaces the whole array
+>help help here come the seventies retreads
+
+ string="Why, if it isn't Officer Dibble"
+ print "[${string[0]}][${string[1]}][${string[0,3]}]"
+0:String subscripts with KSH_ZERO_SUBSCRIPT unset
+>[][W][Why]
+
+ setopt KSH_ZERO_SUBSCRIPT
+ print "[${string[0]}][${string[1]}][${string[0,3]}]"
+0:String subscripts with KSH_ZERO_SUBSCRIPT set
+>[W][W][Why]
+
+ unsetopt KSH_ZERO_SUBSCRIPT
+ string[0,3]="Goodness"
+ print $string
+0:Assignment to chunk of string ignores element 0
+>Goodness, if it isn't Officer Dibble
+
+ string[0]=!
+1:Can't set only element zero of string
+?(eval):1: string: assignment to invalid subscript range
+
+ typeset -A assoc=(leader topcat officer dibble sidekick choochoo)
+ alias myind='echo leader' myletter='echo 1' myletter2='echo 4'
+ print ${assoc[$(myind)]}
+ print $assoc[$(myind)]
+ print ${assoc[$(myind)][$(myletter)]}${assoc[$(myind)][$(myletter2)]}
+ assoc[$(myind)]='of the gang'
+ print ${assoc[$(myind)]}
+ print $assoc[$(myind)]
+ print $assoc[leader]
+0: Parsing subscript with non-trivial tokenisation
+>topcat
+>topcat
+>tc
+>of the gang
+>of the gang
+>of the gang
diff --git a/dotfiles/system/.zsh/modules/Test/D07multibyte.ztst b/dotfiles/system/.zsh/modules/Test/D07multibyte.ztst
new file mode 100644
index 0000000..e203153
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/D07multibyte.ztst
@@ -0,0 +1,587 @@
+%prep
+
+# Find a UTF-8 locale.
+ setopt multibyte
+# Don't let LC_* override our choice of locale.
+ unset -m LC_\*
+ mb_ok=
+ langs=(en_{US,GB}.{UTF-,utf}8 en.UTF-8
+ $(locale -a 2>/dev/null | egrep 'utf8|UTF-8'))
+ for LANG in $langs; do
+ if [[ é = ? ]]; then
+ mb_ok=1
+ break;
+ fi
+ done
+ if [[ -z $mb_ok ]]; then
+ ZTST_unimplemented="no UTF-8 locale or multibyte mode is not implemented"
+ else
+ print -u $ZTST_fd Testing multibyte with locale $LANG
+ mkdir multibyte.tmp && cd multibyte.tmp
+ fi
+
+%test
+
+ a=ténébreux
+ for i in {1..9}; do
+ print ${a[i]}
+ for j in {$i..9}; do
+ print $i $j ${a[i,j]} ${a[-j,-i]}
+ done
+ done
+0:Basic indexing with multibyte characters
+>t
+>1 1 t x
+>1 2 té ux
+>1 3 tén eux
+>1 4 téné reux
+>1 5 ténéb breux
+>1 6 ténébr ébreux
+>1 7 ténébre nébreux
+>1 8 ténébreu énébreux
+>1 9 ténébreux ténébreux
+>é
+>2 2 é u
+>2 3 én eu
+>2 4 éné reu
+>2 5 énéb breu
+>2 6 énébr ébreu
+>2 7 énébre nébreu
+>2 8 énébreu énébreu
+>2 9 énébreux ténébreu
+>n
+>3 3 n e
+>3 4 né re
+>3 5 néb bre
+>3 6 nébr ébre
+>3 7 nébre nébre
+>3 8 nébreu énébre
+>3 9 nébreux ténébre
+>é
+>4 4 é r
+>4 5 éb br
+>4 6 ébr ébr
+>4 7 ébre nébr
+>4 8 ébreu énébr
+>4 9 ébreux ténébr
+>b
+>5 5 b b
+>5 6 br éb
+>5 7 bre néb
+>5 8 breu énéb
+>5 9 breux ténéb
+>r
+>6 6 r é
+>6 7 re né
+>6 8 reu éné
+>6 9 reux téné
+>e
+>7 7 e n
+>7 8 eu én
+>7 9 eux tén
+>u
+>8 8 u é
+>8 9 ux té
+>x
+>9 9 x t
+
+ s=é
+ print A${s[-2]}A B${s[-1]}B C${s[0]}C D${s[1]}D E${s[2]}E
+0:Out of range subscripts with multibyte characters
+>AA BéB CC DéD EE
+
+ print ${a[(i)é]} ${a[(I)é]} ${a[${a[(i)é]},${a[(I)é]}]}
+0:Reverse indexing with multibyte characters
+>2 4 éné
+
+ print ${a[(r)én,(r)éb]}
+0:Subscript searching with multibyte characters
+>énéb
+
+ print ${a[(rb:1:)é,-1]}
+ print ${a[(rb:2:)é,-1]}
+ print ${a[(rb:3:)é,-1]}
+ print ${a[(rb:4:)é,-1]}
+ print ${a[(rb:5:)é,-1]}
+0:Subscript searching with initial offset
+>énébreux
+>énébreux
+>ébreux
+>ébreux
+>
+
+ print ${a[(rn:1:)é,-1]}
+ print ${a[(rn:2:)é,-1]}
+ print ${a[(rn:3:)é,-1]}
+0:Subscript searching with count
+>énébreux
+>ébreux
+>
+
+ print ${a[(R)én,(R)éb]}
+0:Backward subscript searching with multibyte characters
+>énéb
+
+# Starting offsets with (R) seem to be so strange as to be hardly
+# worth testing.
+
+ setopt extendedglob
+ [[ $a = (#b)t(én)(éb)reux ]] || print "Failed to match." >&2
+ for i in {1..${#match}}; do
+ print $match[i] $mbegin[i] $mend[i] ${a[$mbegin[i],$mend[i]]}
+ done
+0:Multibyte offsets in pattern tests
+>én 2 3 én
+>éb 4 5 éb
+
+ b=${(U)a}
+ print $b
+ print ${(L)b}
+ desdichado="Je suis le $a, le veuf, l'inconsolé"
+ print ${(C)desdichado}
+ lxiv="l'état c'est moi"
+ print ${(C)lxiv}
+0:Case modification of multibyte strings
+>TÉNÉBREUX
+>ténébreux
+>Je Suis Le Ténébreux, Le Veuf, L'Inconsolé
+>L'État C'Est Moi
+
+ array=(ølaf ødd øpened án encyclopædia)
+ barray=(${(U)array})
+ print $barray
+ print ${(L)barray}
+ print ${(C)array}
+ print ${(C)barray}
+0:Case modification of arrays with multibyte strings
+>ØLAF ØDD ØPENED ÁN ENCYCLOPÆDIA
+>ølaf ødd øpened án encyclopædia
+>Ølaf Ødd Øpened Án Encyclopædia
+>Ølaf Ødd Øpened Án Encyclopædia
+
+ print $(( ##¥ ))
+ pound=£
+ print $(( #pound ))
+ alpha=α
+ print $(( ##α )) $(( #alpha ))
+0:Conversion to Unicode in mathematical expressions
+>165
+>163
+>945 945
+
+ unsetopt posix_identifiers
+ expr='hähä=3 || exit 1; print $hähä'
+ eval $expr
+ setopt posix_identifiers
+ (eval $expr)
+1:POSIX_IDENTIFIERS option
+>3
+?(eval):1: command not found: hähä=3
+
+ foo="Ølaf«Ødd«øpénëd«ån«àpple"
+ print -l ${(s.«.)foo}
+ ioh="Ἐν ἀρχῇ ἦν ὁ λόγος, καὶ ὁ λόγος ἦν πρὸς τὸν θεόν, καὶ θεὸς ἦν ὁ λόγος."
+ print -l ${=ioh}
+ print ${(w)#ioh}
+0:Splitting with multibyte characters
+>Ølaf
+>Ødd
+>øpénëd
+>ån
+>àpple
+>Ἐν
+>ἀρχῇ
+>ἦν
+>ὁ
+>λόγος,
+>καὶ
+>ὁ
+>λόγος
+>ἦν
+>πρὸς
+>τὸν
+>θεόν,
+>καὶ
+>θεὸς
+>ἦν
+>ὁ
+>λόγος.
+>17
+
+ read -d £ one
+ read -d £ two
+ print $one
+ print $two
+0:read with multibyte delimiter
+<first£second£
+>first
+>second
+
+ (IFS=«
+ read -d » -A array
+ print -l $array)
+0:read -A with multibyte IFS
+<dominus«illuminatio«mea»ignored
+>dominus
+>illuminatio
+>mea
+
+ read -k2 -u0 twochars
+ print $twochars
+0:read multibyte characters
+<«»ignored
+>«»
+
+ read -q -u0 mb
+ print $?
+0:multibyte character makes read -q return false
+<«
+>1
+
+ # See if the system grokks first-century Greek...
+ ioh="Ἐν ἀρχῇ ἦν ὁ λόγος, καὶ ὁ λόγος ἦν πρὸς τὸν θεόν, καὶ θεὸς ἦν ὁ λόγος."
+ for (( i = 1; i <= ${#ioh}; i++ )); do
+ # FC3 doesn't recognise ῇ (U+1FC7: Greek small letter eta with
+ # perispomeni and ypogegrammeni, of course) as a lower case character.
+ if [[ $ioh[i] != [[:lower:]] && $i != 7 ]]; then
+ for tp in upper space punct invalid; do
+ if [[ $tp = invalid || $ioh[i] = [[:${tp}:]] ]]; then
+ print "$i: $tp"
+ break
+ fi
+ done
+ fi
+ done
+0:isw* functions on non-ASCII wide characters
+>1: upper
+>3: space
+>8: space
+>11: space
+>13: space
+>19: punct
+>20: space
+>24: space
+>26: space
+>32: space
+>35: space
+>40: space
+>44: space
+>49: punct
+>50: space
+>54: space
+>59: space
+>62: space
+>64: space
+>70: punct
+
+ ioh="Ἐν ἀρχῇ ἦν ὁ λόγος, καὶ ὁ λόγος ἦν πρὸς τὸν θεόν, καὶ θεὸς ἦν ὁ λόγος"
+ print ${ioh#[[:alpha:]]##}
+ print ${ioh##[[:alpha:]]##}
+ print ${ioh%[[:alpha:]]##}
+ print ${ioh%%[[:alpha:]]##}
+ print ${(S)ioh#λ*ς}
+ print ${(S)ioh##λ*ς}
+ print ${(S)ioh%θ*ς}
+ print ${(S)ioh%%θ*ς}
+0:Parameter #, ##, %, %% with multibyte characters
+>ν ἀρχῇ ἦν ὁ λόγος, καὶ ὁ λόγος ἦν πρὸς τὸν θεόν, καὶ θεὸς ἦν ὁ λόγος
+> ἀρχῇ ἦν ὁ λόγος, καὶ ὁ λόγος ἦν πρὸς τὸν θεόν, καὶ θεὸς ἦν ὁ λόγος
+>Ἐν ἀρχῇ ἦν ὁ λόγος, καὶ ὁ λόγος ἦν πρὸς τὸν θεόν, καὶ θεὸς ἦν ὁ λόγο
+>Ἐν ἀρχῇ ἦν ὁ λόγος, καὶ ὁ λόγος ἦν πρὸς τὸν θεόν, καὶ θεὸς ἦν ὁ
+>Ἐν ἀρχῇ ἦν ὁ , καὶ ὁ λόγος ἦν πρὸς τὸν θεόν, καὶ θεὸς ἦν ὁ λόγος
+>Ἐν ἀρχῇ ἦν ὁ
+>Ἐν ἀρχῇ ἦν ὁ λόγος, καὶ ὁ λόγος ἦν πρὸς τὸν θεόν, καὶ ἦν ὁ λόγος
+>Ἐν ἀρχῇ ἦν ὁ λόγος, καὶ ὁ λόγος ἦν πρὸς τὸν θεόν, καὶ
+
+ a="1ë34ë6"
+ print ${(BEN)a#*4}
+ print ${(BEN)a##*ë}
+ print ${(BEN)a%4*}
+ print ${(BEN)a%%ë*}
+ print ${(SBEN)a#ë3}
+ print ${(SBEN)a%4ë}
+0:Flags B, E, N and S in ${...#...} and ${...%...}
+>1 5 4
+>1 6 5
+>4 7 3
+>2 7 5
+>2 4 2
+>4 6 2
+
+ foo=(κατέβην χθὲς εἰς Πειραιᾶ)
+ print ${(l.3..¥.r.3..£.)foo}
+ print ${(l.4..¥.r.2..£.)foo}
+ print ${(l.5..¥.r.1..£.)foo}
+ print ${(l.4..¥..«.r.4..£..».)foo}
+ print ${(l.4..¥..Σωκράτης.r.4..£..Γλαύκωνος.)foo}
+0:simultaneous left and right padding
+>κατέβη ¥χθὲς£ ¥¥εἰς£ Πειραι
+>¥κατέβ ¥¥χθὲς ¥¥¥εἰς ¥Πειρα
+>¥¥κατέ ¥¥¥χθὲ ¥¥¥¥εἰ ¥¥Πειρ
+>«κατέβην ¥«χθὲς»£ ¥¥«εἰς»£ «Πειραιᾶ
+>ςκατέβην ηςχθὲςΓλ τηςεἰςΓλ ςΠειραιᾶ
+# er... yeah, that looks right...
+
+ foo=picobarn
+ print ${foo:s£bar£rod£:s¥rod¥stick¥}
+0:Delimiters in modifiers
+>picostickn
+
+# TODO: if we get paired multibyte bracket delimiters to work
+# (as Emacs does, the smug so-and-so), the following should change.
+ foo=bar
+ print ${(r£5££X£)foo}
+ print ${(l«10««Y««HI«)foo}
+0:Delimiters in parameter flags
+>barXX
+>YYYYYHIbar
+
+ printf "%4.3s\n" főobar
+0:Multibyte characters in printf widths
+> főo
+
+# 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.
+ print -oi HÛH HÔH HÎH HÊH HÂH
+ (LC_ALL=C; print -oi HAH HUH HEH HÉH HÈH)
+0:Multibyte characters in print sorting
+>HÂH HÊH HÎH HÔH HÛH
+>HAH HEH HUH HÈH HÉH
+
+# These are control characters in Unicode, so don't show up.
+# We just want to check they're not being treated as tokens.
+ for x in {128..150}; do
+ print ${(#)x}
+ done | while read line; do
+ print ${#line} $(( #line ))
+ done
+0:evaluated character number with multibyte characters
+>1 128
+>1 129
+>1 130
+>1 131
+>1 132
+>1 133
+>1 134
+>1 135
+>1 136
+>1 137
+>1 138
+>1 139
+>1 140
+>1 141
+>1 142
+>1 143
+>1 144
+>1 145
+>1 146
+>1 147
+>1 148
+>1 149
+>1 150
+
+ touch ngs1txt ngs2txt ngs10txt ngs20txt ngs100txt ngs200txt
+ setopt numericglobsort
+ print -l ngs*
+0:NUMERIC_GLOB_SORT option in UTF-8 locale
+>ngs1txt
+>ngs2txt
+>ngs10txt
+>ngs20txt
+>ngs100txt
+>ngs200txt
+
+# Not strictly multibyte, but gives us a well-defined locale for testing.
+ foo=$'X\xc0Y\x07Z\x7fT'
+ print -r ${(q)foo}
+0:Backslash-quoting of unprintable/invalid characters uses $'...'
+>X$'\300'Y$'\a'Z$'\177'T
+
+# This also isn't strictly multibyte and is here to reduce the
+# likelihood of a "cannot do character set conversion" error.
+ (print $'\u00e9') 2>&1 | read
+ if [[ $REPLY != é ]]; then
+ print "warning: your system can't do simple Unicode conversion." >&$ZTST_fd
+ print "Check you have a correctly installed iconv library." >&$ZTST_fd
+ # cheat
+ repeat 4 print OK
+ else
+ testfn() { (LC_ALL=C; print $'\u00e9') }
+ repeat 4 testfn 2>&1 | while read line; do
+ if [[ $line = *"character not in range"* ]]; then
+ print OK
+ elif [[ $line = "?" ]]; then
+ print OK
+ else
+ print Failed: no error message and no question mark
+ fi
+ done
+ fi
+ true
+0:error handling in Unicode quoting
+>OK
+>OK
+>OK
+>OK
+
+ tmp1='glob/\(\)Ą/*'
+ [[ glob/'()Ą'/foo == $~tmp1 ]] && print "Matched against $tmp1"
+ tmp1='glob/\(\)Ā/*'
+ [[ glob/'()Ā'/bar == $~tmp1 ]] && print "Matched against $tmp1"
+0:Backslashes and metafied characters in patterns
+>Matched against glob/()Ą/*
+>Matched against glob/()Ā/*
+
+ mkdir 梶浦由記 'Пётр Ильич Чайковский'
+ (cd 梶浦由記; print ${${(%):-%~}:t})
+ (cd 'Пётр Ильич Чайковский'; print ${${(%):-%~}:t})
+0:Metafied characters in prompt expansion
+>梶浦由記
+>Пётр Ильич Чайковский
+
+ (
+ setopt nonomatch
+ tmp1=Ą
+ tmpA=(Ą 'Пётр Ильич Чайковский' 梶浦由記)
+ print ${tmp1} ${(%)tmp1} ${(%%)tmp1}
+ print ${#tmp1} ${#${(%)tmp1}} ${#${(%%)tmp1}}
+ print ${tmpA}
+ print ${(%)tmpA}
+ print ${(%%)tmpA}
+ )
+0:More metafied characters in prompt expansion
+>Ą Ą Ą
+>1 1 1
+>Ą Пётр Ильич Чайковский 梶浦由記
+>Ą Пётр Ильич Чайковский 梶浦由記
+>Ą Пётр Ильич Чайковский 梶浦由記
+
+ setopt cbases
+ print $'\xc5' | read
+ print $(( [#16] #REPLY ))
+0:read passes through invalid multibyte characters
+>0xC5
+
+ word=abcま
+ word[-1]=
+ print $word
+ word=abcま
+ word[-2]=
+ print $word
+ word=abcま
+ word[4]=d
+ print $word
+ word=abcま
+ word[3]=not_c
+ print $word
+0:assignment with negative indices
+>abc
+>abま
+>abcd
+>abnot_cま
+
+ # The following doesn't necessarily need UTF-8, but this gives
+ # us the full effect --- if we parse this wrongly the \xe9
+ # in combination with the tokenized input afterwards looks like a
+ # valid UTF-8 character. But it isn't.
+ print $'$\xe9#``' >test_bad_param
+ (setopt nonomatch
+ . ./test_bad_param)
+127:Invalid parameter name with following tokenized input
+?./test_bad_param:1: command not found: $\M-i#
+
+ lines=$'one\tZSH\tthree\nfour\tfive\tsix'
+ print -X8 -r -- $lines
+0:Tab expansion with extra-wide characters
+>one ZSH three
+>four five six
+# This doesn't look aligned in my editor because actually the characters
+# aren't quite double width, but the arithmetic is correct.
+# It appears just to be an effect of the font.
+
+ () {
+ emulate -L zsh
+ setopt errreturn
+ local cdpath=(.)
+ mkdir ホ
+ cd ホ
+ cd ..
+ cd ./ホ
+ cd ..
+ }
+0:cd with special characters
+
+ test_array=(
+ '[[ \xcc = \xcc ]]'
+ '[[ \xcc != \xcd ]]'
+ '[[ \xcc != \ucc ]]'
+ '[[ \ucc = \ucc ]]'
+ '[[ \ucc = [\ucc] ]]'
+ '[[ \xcc != [\ucc] ]]'
+ # Not clear how useful the following is...
+ '[[ \xcc = [\xcc] ]]'
+ )
+ for test in $test_array; do
+ if ! eval ${(g::)test} ; then
+ print -rl "Test $test failed" >&2
+ fi
+ done
+0:Invalid characters in pattern matching
+
+ [[ $'\xe3' == [[:INCOMPLETE:]] ]] || print fail 1
+ [[ $'\xe3\x83' == [[:INCOMPLETE:]][[:INVALID:]] ]] || print fail 2
+ [[ $'\xe3\x83\x9b' != [[:INCOMPLETE:][:INVALID:]] ]] || print fail 3
+ [[ $'\xe3\x83\x9b' = ? ]] || print fail 4
+0:Testing incomplete and invalid multibyte character components
+
+ print -r -- ${(q+):-ホ}
+ foo='She said "ホ". I said "You can'\''t '\''ホ'\'' me!'
+ print -r -- ${(q+)foo}
+0:${(q+)...} with printable multibyte characters
+>ホ
+>'She said "ホ". I said "You can'\''t '\''ホ'\'' me!'
+
+# This will silently succeed if zsh/parameter isn't available
+ (zmodload zsh/parameter >/dev/null 2>&1
+ f() {
+ : $(:)
+ "↓"
+ }
+ : $functions)
+0:Multibyte handling of functions parameter
+
+# c1=U+0104 (Ą) and c2=U+0120 (Ġ) are chosen so that
+# u1 = utf8(c1) = c4 84 < u2 = utf8(c2) = c4 a0
+# metafy(u1) = c4 83 a4 > metafy(u2) = c4 83 80
+# in both UTF-8 and ASCII collations (the latter is used in macOS
+# and some versions of BSDs).
+ local -a names=( $'\u0104' $'\u0120' )
+ print -o $names
+ mkdir -p colltest
+ cd colltest
+ touch $names
+ print ?
+0:Sorting of metafied characters
+>Ą Ġ
+>Ą Ġ
+
+ printf '%q%q\n' 你你
+0:printf %q and quotestring and general metafy / token madness
+>你你
+
+# This test is kept last as it introduces an additional
+# dependency on the system regex library.
+ if zmodload zsh/regex 2>/dev/null; then
+ [[ $'\ua0' =~ '^.$' ]] && print OK
+ [[ $'\ua0' =~ $'^\ua0$' ]] && print OK
+ [[ $'\ua0'X =~ '^X$' ]] || print OK
+ else
+ ZTST_skip="regexp library not found."
+ fi
+0:Ensure no confusion on metafied input to regex module
+>OK
+>OK
+>OK
+F:A failure here may indicate the system regex library does not
+F:support character sets outside the portable 7-bit range.
diff --git a/dotfiles/system/.zsh/modules/Test/D08cmdsubst.ztst b/dotfiles/system/.zsh/modules/Test/D08cmdsubst.ztst
new file mode 100644
index 0000000..3625373
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/D08cmdsubst.ztst
@@ -0,0 +1,169 @@
+# Tests for command substitution.
+
+%prep
+ mkdir cmdsubst.tmp
+ touch cmdsubst.tmp/file{1,2}.txt
+
+%test
+ foo="two words"
+ print -l `echo $foo bar`
+0:Basic `...` substitution
+>two
+>words
+>bar
+
+ foo="two words"
+ print -l $(echo $foo bar)
+0:Basic $(...) substitution
+>two
+>words
+>bar
+
+ foo='intricate buffoonery'
+ print -l "`echo $foo and licentiousness`"
+0:Quoted `...` substitution
+>intricate buffoonery and licentiousness
+
+ foo="more words"
+ print -l "$(echo $foo here)"
+0:Quoted $(...) substitution
+>more words here
+
+# we used never to get this one right, but I think it is now...
+ print -r "`print -r \\\\\\\\`"
+0:Stripping of backslasshes in quoted `...`
+>\\
+
+ print -r "$(print -r \\\\\\\\)"
+0:Stripping of backslashes in quoted $(...)
+>\\\\
+
+ fnify() { print \"$*\"; }
+ print `fnify \`fnify understatement\``
+0:Nested `...`
+>""understatement""
+
+ print $(fnify $(fnify overboard))
+0:Nested $(...)
+>""overboard""
+
+ fructify() { print \'$*\'; }
+ print "`fructify \`fructify indolence\``"
+0:Nested quoted `...`
+>''indolence''
+
+ print "$(fructify $(fructify obtuseness))"
+0:Nested quoted $(...)
+>''obtuseness''
+
+ gesticulate() { print \!$*\!; }
+ print $((gesticulate wildly); gesticulate calmly)
+0:$(( ... ) ... ) is not arithmetic
+>!wildly! !calmly!
+
+ commencify() { print +$*+; }
+ print "$((commencify output); commencify input)"
+0:quoted $(( ... ) .. ) is not arithmetic
+>+output+
+>+input+
+
+ (
+ cd cmdsubst.tmp
+ print first: ${$(print \*)}
+ print second: ${~$(print \*)}
+ print third: ${$(print *)}
+ print fourth: "${~$(print \*)}"
+ print fifth: ${~"$(print \*)"}
+ )
+0:mixing $(...) with parameter substitution and globbing
+>first: *
+>second: file1.txt file2.txt
+>third: file1.txt file2.txt
+>fourth: *
+>fifth: file1.txt file2.txt
+
+ $(exit 0) $(exit 3) || print $?
+0:empty command uses exit value of last substitution
+>3
+
+ X=$(exit 2) $(exit 0) || print $?
+0:variable assignments processed after other substitutions
+>2
+
+ false
+ ``
+0:Empty command substitution resets status
+
+ false
+ echo `echo $?`
+0:Non-empty command substitution inherits status
+>1
+
+ echo $(( ##\" ))
+ echo $(echo \")
+ echo $((echo \"); echo OK)
+0:Handling of backslash double quote in parenthesised substitutions
+>34
+>"
+>" OK
+
+ echo $(case foo in
+ foo)
+ echo This test worked.
+ ;;
+ bar)
+ echo This test failed in a rather bizarre way.
+ ;;
+ *)
+ echo This test failed.
+ ;;
+ esac)
+0:Parsing of command substitution with unmatched parentheses: case, basic
+>This test worked.
+
+ echo "$(case bar in
+ foo)
+ echo This test spoobed.
+ ;;
+ bar)
+ echo This test plurbled.
+ ;;
+ *)
+ echo This test bzonked.
+ ;;
+ esac)"
+0:Parsing of command substitution with unmatched parentheses: case with quotes
+>This test plurbled.
+
+ echo before $(
+ echo start; echo unpretentious |
+ while read line; do
+ case $line in
+ u*)
+ print Word began with u
+ print and ended with a crunch
+ ;;
+ esac
+ done | sed -e 's/Word/Universe/'; echo end
+ ) after
+0:Parsing of command substitution with ummatched parentheses: with frills
+>before start Universe began with u and ended with a crunch end after
+
+ alias foo='echo $('
+ eval 'foo echo this just works, OK\?)'
+0:backtracking within command string parsing with alias still pending
+>this just works, OK?
+
+ (
+ set errexit
+ show_nargs() { print $#; }
+ print a $() b
+ print c "$()" d
+ )
+0:Empty $() is a valid empty substitution.
+>a b
+>c d
+
+ empty=$() && print "'$empty'"
+0:Empty $() is a valid assignment
+>''
diff --git a/dotfiles/system/.zsh/modules/Test/D09brace.ztst b/dotfiles/system/.zsh/modules/Test/D09brace.ztst
new file mode 100644
index 0000000..3e667a8
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/D09brace.ztst
@@ -0,0 +1,114 @@
+# Tests for brace expansion
+
+%prep
+
+ foo=(a b c)
+ arr=(foo bar baz)
+
+%test
+
+ print X{1,2,{3..6},7,8}Y
+0:Basic brace expansion
+>X1Y X2Y X3Y X4Y X5Y X6Y X7Y X8Y
+
+ print ${foo}{one,two,three}$arr
+0:Brace expansion with arrays, no RC_EXPAND_PARAM
+>a b conefoo ctwofoo cthreefoo bar baz
+
+ print ${^foo}{one,two,three}$arr
+0:Brace expansion with arrays, with RC_EXPAND_PARAM (1)
+>aonefoo atwofoo athreefoo bonefoo btwofoo bthreefoo conefoo ctwofoo cthreefoo bar baz
+
+ print ${foo}{one,two,three}$^arr
+0:Brace expansion with arrays, with RC_EXPAND_PARAM (2)
+>a b conefoo ctwofoo cthreefoo conebar ctwobar cthreebar conebaz ctwobaz cthreebaz
+
+ print ${^foo}{one,two,three}$^arr
+0:Brace expansion with arrays, with RC_EXPAND_PARAM (3)
+>aonefoo atwofoo athreefoo aonebar atwobar athreebar aonebaz atwobaz athreebaz bonefoo btwofoo bthreefoo bonebar btwobar bthreebar bonebaz btwobaz bthreebaz conefoo ctwofoo cthreefoo conebar ctwobar cthreebar conebaz ctwobaz cthreebaz
+
+ print X{01..4}Y
+0:Numeric range expansion, padding (1)
+>X01Y X02Y X03Y X04Y
+
+ print X{1..04}Y
+0:Numeric range expansion, padding (2)
+>X01Y X02Y X03Y X04Y
+
+ print X{7..12}Y
+0:Numeric range expansion, padding (or not) (3)
+>X7Y X8Y X9Y X10Y X11Y X12Y
+
+ print X{07..12}Y
+0:Numeric range expansion, padding (4)
+>X07Y X08Y X09Y X10Y X11Y X12Y
+
+ print X{7..012}Y
+0:Numeric range expansion, padding (5)
+>X007Y X008Y X009Y X010Y X011Y X012Y
+
+ print X{4..1}Y
+0:Numeric range expansion, decreasing
+>X4Y X3Y X2Y X1Y
+
+ print X{1..4}{1..4}Y
+0:Numeric range expansion, combined braces
+>X11Y X12Y X13Y X14Y X21Y X22Y X23Y X24Y X31Y X32Y X33Y X34Y X41Y X42Y X43Y X44Y
+
+ print X{-4..4}Y
+0:Numeric range expansion, negative numbers (1)
+>X-4Y X-3Y X-2Y X-1Y X0Y X1Y X2Y X3Y X4Y
+
+ print X{4..-4}Y
+0:Numeric range expansion, negative numbers (2)
+>X4Y X3Y X2Y X1Y X0Y X-1Y X-2Y X-3Y X-4Y
+
+ print X{004..-4..2}Y
+0:Numeric range expansion, stepping and padding (1)
+>X004Y X002Y X000Y X-02Y X-04Y
+
+ print X{4..-4..02}Y
+0:Numeric range expansion, stepping and padding (1)
+>X04Y X02Y X00Y X-2Y X-4Y
+
+ print X{1..32..3}Y
+0:Numeric range expansion, step alignment (1)
+>X1Y X4Y X7Y X10Y X13Y X16Y X19Y X22Y X25Y X28Y X31Y
+
+ print X{1..32..-3}Y
+0:Numeric range expansion, step alignment (2)
+>X31Y X28Y X25Y X22Y X19Y X16Y X13Y X10Y X7Y X4Y X1Y
+
+ print X{32..1..3}Y
+0:Numeric range expansion, step alignment (3)
+>X32Y X29Y X26Y X23Y X20Y X17Y X14Y X11Y X8Y X5Y X2Y
+
+ print X{32..1..-3}Y
+0:Numeric range expansion, step alignment (4)
+>X2Y X5Y X8Y X11Y X14Y X17Y X20Y X23Y X26Y X29Y X32Y
+
+ setopt brace_ccl
+ print X{za-q521}Y
+ unsetopt brace_ccl
+0:BRACE_CCL on
+>X1Y X2Y X5Y XaY XbY XcY XdY XeY XfY XgY XhY XiY XjY XkY XlY XmY XnY XoY XpY XqY XzY
+
+ print X{za-q521}Y
+0:BRACE_CCL off
+>X{za-q521}Y
+
+ print -r hey{a..j}there
+0:{char..char} ranges, simple case
+>heyathere heybthere heycthere heydthere heyethere heyfthere heygthere heyhthere heyithere heyjthere
+
+ print -r gosh{1,{Z..a},2}cripes
+0:{char..char} ranges, ASCII ordering
+>gosh1cripes goshZcripes gosh[cripes gosh\cripes gosh]cripes gosh^cripes gosh_cripes gosh`cripes goshacripes gosh2cripes
+
+ print -r crumbs{y..p}ooh
+0:{char..char} ranges, reverse
+>crumbsyooh crumbsxooh crumbswooh crumbsvooh crumbsuooh crumbstooh crumbssooh crumbsrooh crumbsqooh crumbspooh
+
+ print -r left{[..]}right
+0:{char..char} ranges with tokenized characters
+>left[right left\right left]right
diff --git a/dotfiles/system/.zsh/modules/Test/E01options.ztst b/dotfiles/system/.zsh/modules/Test/E01options.ztst
new file mode 100644
index 0000000..2bd4fdb
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/E01options.ztst
@@ -0,0 +1,1313 @@
+# Test various shell options.
+# Interactive options not tested here:
+# ALWAYS_LAST_PROMPT
+# ALWAYS_TO_END
+# APPEND_HISTORY (history not maintained)
+# AUTO_LIST
+# AUTO_MENU
+# AUTO_NAME_DIRS (named directory table not maintained)
+# AUTO_PARAM_KEYS
+# AUTO_PARAM_SLASH
+# AUTO_REMOVE_SLASH
+# AUTO_RESUME
+# BANG_HIST
+# BASH_AUTO_LIST
+# BEEP (!)
+# BG_NICE
+# CHECK_JOBS
+# COMPLETE_ALIASES
+# COMPLETE_IN_WORD
+# CORRECT
+# CORRECT_ALL
+# CSH_JUNKIE_HISTORY
+# DVORAK
+# EXTENDED_HISTORY
+# FLOW_CONTROL
+# GLOB_COMPLETE
+# HIST_ALLOW_CLOBBER
+# HIST_BEEP
+# HIST_EXPIRE_DUPS_FIRST
+# HIST_FIND_NO_DUPS
+# HIST_IGNORE_ALL_DUPS
+# HIST_IGNORE_DUPS (-h)
+# HIST_IGNORE_SPACE (-g)
+# HIST_NO_FUNCTIONS
+# HIST_NO_STORE
+# HIST_REDUCE_BLANKS
+# HIST_SAVE_NO_DUPS
+# HIST_VERIFY
+# HUP
+# IGNORE_EOF
+# INC_APPEND_HISTORY
+# INTERACTIVE
+# INTERACTIVE_COMMENTS
+# LIST_AMBIGUOUS
+# LIST_BEEP
+# LIST_PACKED
+# LIST_ROWS_FIRST
+# LIST_TYPES
+# LOGIN
+# LONG_LIST_JOBS
+# MAIL_WARNING
+# MENU_COMPLETE
+# MONITOR
+# NOTIFY
+# OVERSTRIKE
+# PRINT_EIGHT_BIT
+# PROMPT_CR
+# PUSHD_SILENT
+# REC_EXACT
+# RM_STAR_SILENT
+# RM_STAR_WAIT
+# SHARE_HISTORY
+# SINGLE_LINE_ZLE
+# SUN_KEYBOARD_HACK
+# ZLE
+# The following require SHINSTDIN and are not (yet) tested:
+# AUTO_CD
+# SHINSTDIN
+#
+# Other difficult things I haven't done:
+# GLOBAL_RCS (uses fixed files outside build area)
+# HASH_CMDS )
+# HASH_DIRS ) fairly seriously internal, hard to test at all
+# HASH_LIST_ALL )
+# PRINT_EXIT_STATUS haven't worked out what this does yet, although
+# Bart suggested a fix.
+# PRIVILEGED (similar to GLOBAL_RCS)
+# RCS ( " " " " )
+# SH_OPTION_LETTERS even I found this too dull to set up a test for
+# SINGLE_COMMAND kills shell
+# VERBOSE hard because done on input (c.f. SHINSTDIN).
+
+%prep
+ mkdir options.tmp && cd options.tmp
+
+ mkdir tmpcd homedir
+
+ touch tmpfile1 tmpfile2
+
+ mydir=$PWD
+ mydirt=`print -P %~`
+ mydirhome=`export HOME=$mydir/homedir; print -P %~`
+ catpath=$(which cat)
+ lspath==ls
+
+%test
+
+ alias echo='print foo'
+ unsetopt aliases
+ # use eval else aliases are all parsed at start
+ eval echo bar
+ setopt aliases
+ eval echo bar
+ unalias echo
+0:ALIASES option
+>bar
+>foo bar
+
+ setopt allexport
+ testpm1=exported
+ unsetopt allexport
+ testpm2=unexported
+ print ${(t)testpm1}
+ print ${(t)testpm2}
+0:ALL_EXPORT option
+>scalar-export
+>scalar
+
+ # Count the number of directories on the stack. Don't care what they are.
+ dircount() { dirs -v | tail -1 | awk '{ print $1 + 1}'; }
+ unsetopt autopushd
+ cd tmpcd
+ dircount
+ cd ..
+ setopt autopushd
+ cd tmpcd
+ dircount
+ unsetopt autopushd
+ popd >/dev/null
+0:AUTO_PUSHD option
+>1
+>2
+
+ unsetopt badpattern
+ print [a
+ setopt badpattern
+ print [b
+1:BAD_PATTERN option
+>[a
+?(eval):4: bad pattern: [b
+
+ unsetopt bareglobqual nomatch
+ print *(.)
+ setopt bareglobqual nomatch
+ print *(.)
+0:BARE_GLOB_QUAL option
+>*(.)
+>tmpfile1 tmpfile2
+
+ setopt braceccl
+ print {abcd}
+ unsetopt braceccl
+ print {abcd}
+0:BRACE_CCL option
+>a b c d
+>{abcd}
+
+# Don't use NUL as a field separator in the following.
+ setopt braceccl
+ print {$'\0'-$'\5'} | IFS=' ' read -A chars
+ for c in $chars; do print $(( #c )); done
+ unsetopt braceccl
+0:BRACE_CCL option starting from NUL
+>0
+>1
+>2
+>3
+>4
+>5
+
+ setopt bsdecho
+ echo "histon\nimpington"
+ echo -e "girton\ncottenham"
+ unsetopt bsdecho
+ echo "newnham\ncomberton"
+0:BSD_ECHO option
+>histon\nimpington
+>girton
+>cottenham
+>newnham
+>comberton
+
+ unsetopt c_bases
+ print $(( [#16]15 ))
+ print $(( [#8]9 ))
+ setopt c_bases
+ print $(( [#16]31 ))
+ print $(( [#8]17 ))
+ setopt octal_zeroes
+ print $(( [#8]19 ))
+ unsetopt c_bases octal_zeroes
+0:C_BASES option
+>16#F
+>8#11
+>0x1F
+>8#21
+>023
+
+ setopt cdablevars
+ # only absolute paths are eligible for ~-expansion
+ cdablevar1=tmpcd
+ (cd cdablevar1)
+ cdablevar2=$PWD/tmpcd
+ cd cdablevar2
+ cd ..
+ print back in ${PWD:t}
+ unsetopt cdablevars
+ cd cdablevar2
+1q:CDABLE_VARS option
+>back in options.tmp
+?(eval):cd:4: no such file or directory: cdablevar1
+?(eval):cd:10: no such file or directory: cdablevar2
+
+# CHASE_DOTS should go with CHASE_LINKS in B01cd.ztst
+# which saves me having to write it here.
+
+ setopt noclobber
+ rm -f foo1 bar1 rod1
+ echo waterbeach >foo1
+ (echo landbeach >foo1)
+ cat foo1
+ (echo lode >>bar1)
+ [[ -f bar1 ]] && print That shouldn\'t be there.
+ echo denny >rod1
+ echo wicken >>rod1
+ cat rod1
+ unsetopt noclobber
+ rm -f foo2 bar2 rod2
+ echo ely >foo2
+ echo march >foo2
+ cat foo2
+ echo wimpole >>bar2
+ cat bar2
+ echo royston >rod2
+ echo foxton >>rod2
+ cat rod2
+ rm -f foo* bar* rod*
+0:CLOBBER option
+>waterbeach
+>denny
+>wicken
+>march
+>wimpole
+>royston
+>foxton
+?(eval):4: file exists: foo1
+?(eval):6: no such file or directory: bar1
+
+ setopt cshjunkieloops
+ eval 'for f in swaffham bulbeck; print $f; end'
+ print next one should fail >&2
+ unsetopt cshjunkieloops
+ eval 'for f in chesterton arbury; print $f; end'
+1:CSH_JUNKIE_LOOPS option (for loop)
+>swaffham
+>bulbeck
+?next one should fail
+?(eval):1: parse error near `end'
+
+# ` emacs deconfusion
+
+ setopt cshjunkiequotes
+ print this should cause an error >&2
+ eval "print 'line one
+ line two'"
+ print this should not >&2
+ eval "print 'line three\\
+ line four'"
+ unsetopt cshjunkiequotes
+0:CSH_JUNKIE_QUOTES option
+>line three
+> line four
+?this should cause an error
+?(eval):1: unmatched '
+?this should not
+
+# ' emacs deconfusion
+
+ nullcmd() { print '$NULLCMD run'; }
+ readnullcmd() { print 'Running $READNULLCMD'; cat; }
+ NULLCMD=nullcmd
+ READNULLCMD=readnullcmd
+ setopt cshnullcmd
+ rm -f foo
+ print "This should fail" >&2
+ (>foo)
+ print "This should succeed" >&2
+ print "These are the contents of foo" >foo
+ cat foo
+ print "This should also fail" >&2
+ (<foo)
+ unsetopt cshnullcmd
+ rm -f foo
+ >foo
+ <foo
+ rm -f foo
+0:CSH_NULL_CMD option
+>These are the contents of foo
+>Running $READNULLCMD
+>$NULLCMD run
+?This should fail
+?(eval):8: redirection with no command
+?This should succeed
+?This should also fail
+?(eval):13: redirection with no command
+
+# nomatch should be overridden by cshnullglob
+ setopt nomatch cshnullglob
+ print tmp* nothing* blah
+ print -n 'hoping for no match: ' >&2
+ (print nothing* blah)
+ print >&2
+ unsetopt cshnullglob nomatch
+ print tmp* nothing* blah
+ print nothing* blah
+0:CSH_NULL_GLOB option
+>tmpcd tmpfile1 tmpfile2 blah
+>tmpcd tmpfile1 tmpfile2 nothing* blah
+>nothing* blah
+?hoping for no match: (eval):4: no match
+?
+
+# The trick is to avoid =cat being expanded in the output while $catpath is.
+ setopt NO_equals
+ print -n trick; print =cat
+ setopt equals
+ print -n trick; print =cat
+0q:EQUALS option
+>trick=cat
+>trick$catpath
+
+# explanation of expected TRAPZERR output: from false and from
+# testfn() with ERR_EXIT on (hmm, should we really get a second one from
+# the function exiting?), then from the false only with ERR_EXIT off.
+ TRAPZERR() { print ZERR trapped; }
+ testfn() { setopt localoptions $2; print $1 before; false; print $1 after; }
+ (testfn on errexit)
+ testfn off
+ unfunction TRAPZERR testfn
+0:ERR_EXIT option
+>on before
+>ZERR trapped
+>ZERR trapped
+>off before
+>ZERR trapped
+>off after
+
+ (print before; setopt noexec; print after)
+0:NO_EXEC option
+>before
+
+ (setopt noexec
+ typeset -A hash
+ hash['this is a string'])
+0:NO_EXEC option should not attempt to parse subscripts
+
+ (setopt noexec nomatch
+ echo *NonExistentFile*)
+0:NO_EXEC option should not do globbing
+
+ (setopt noexec
+ echo ${unset_var?Not an error})
+0:NO_EXEC should not test for unset variables
+
+ (setopt noexec
+ : ${${string%[aeiou]*}/(#m)?(#e)/${(U)MATCH}} Rule 1
+ : ${array[4,5][1][2,3]} Rule 2
+ : ${${(P)foo[1,6]}[1,3]} Rule 3
+ : "${${(@)array}[1,2]}" Rule 5
+ : "${(@)${(@)array}[1,2]#?}" Rule 6
+ : ${(el.20..X.)${bar}} Rule 11 success case)
+0:NO_EXEC handles parameter substitution examples
+
+ (setopt noexec
+ : ${(el.20..X.)$bar} Rule 11 failure case)
+1:NO_EXEC does recognize bad substitution syntax
+*?* bad substitution
+
+ setopt NO_eval_lineno
+ eval 'print $LINENO'
+ setopt eval_lineno
+ eval 'print $LINENO'
+0:EVAL_LINENO option
+>2
+>1
+
+ # The EXTENDED_GLOB test doesn't test globbing fully --- it just tests
+ # that certain patterns are treated literally with the option off
+ # and as patterns with the option on.
+ testfn() { print -n "$1 $2 $3 "; if [[ $1 = ${~2} ]];
+ then print yes; else print no; fi; }
+ tests=('a#' '?~b' '^aa')
+ strings=('a' 'aa' 'b' 'a#' '?~b' '^aa')
+ for opt in noextendedglob extendedglob; do
+ setopt $opt
+ for test in $tests; do
+ for string in $strings; do
+ testfn $string $test $opt
+ done
+ done
+ done
+0:EXTENDED_GLOB option
+>a a# noextendedglob no
+>aa a# noextendedglob no
+>b a# noextendedglob no
+>a# a# noextendedglob yes
+>?~b a# noextendedglob no
+>^aa a# noextendedglob no
+>a ?~b noextendedglob no
+>aa ?~b noextendedglob no
+>b ?~b noextendedglob no
+>a# ?~b noextendedglob no
+>?~b ?~b noextendedglob yes
+>^aa ?~b noextendedglob no
+>a ^aa noextendedglob no
+>aa ^aa noextendedglob no
+>b ^aa noextendedglob no
+>a# ^aa noextendedglob no
+>?~b ^aa noextendedglob no
+>^aa ^aa noextendedglob yes
+>a a# extendedglob yes
+>aa a# extendedglob yes
+>b a# extendedglob no
+>a# a# extendedglob no
+>?~b a# extendedglob no
+>^aa a# extendedglob no
+>a ?~b extendedglob yes
+>aa ?~b extendedglob no
+>b ?~b extendedglob no
+>a# ?~b extendedglob no
+>?~b ?~b extendedglob no
+>^aa ?~b extendedglob no
+>a ^aa extendedglob yes
+>aa ^aa extendedglob no
+>b ^aa extendedglob yes
+>a# ^aa extendedglob yes
+>?~b ^aa extendedglob yes
+>^aa ^aa extendedglob yes
+
+ foo() { print My name is $0; }
+ unsetopt functionargzero
+ foo
+ setopt functionargzero
+ foo
+ unfunction foo
+0:FUNCTION_ARGZERO option
+>My name is (anon)
+>My name is foo
+
+ setopt _NO_glob_
+ print tmp*
+ set -o glob
+ print tmp*
+0:GLOB option
+>tmp*
+>tmpcd tmpfile1 tmpfile2
+
+ showit() { local v;
+ for v in first second third; do
+ eval print \$$v \$\{\(t\)$v\}
+ done;
+ }
+ setit() { typeset -x first=inside1;
+ typeset +g -x second=inside2;
+ typeset -g -x third=inside3;
+ showit;
+ }
+ first=outside1 second=outside2 third=outside3
+ unsetopt globalexport
+ setit
+ showit
+ setopt globalexport
+ setit
+ showit
+ unfunction setit showit
+0:GLOBAL_EXPORT option
+>inside1 scalar-local-export
+>inside2 scalar-local-export
+>inside3 scalar-export
+>outside1 scalar
+>outside2 scalar
+>inside3 scalar-export
+>inside1 scalar-export
+>inside2 scalar-local-export
+>inside3 scalar-export
+>inside1 scalar-export
+>outside2 scalar
+>inside3 scalar-export
+
+# GLOB_ASSIGN is tested in A06assign.ztst.
+
+ mkdir onlysomefiles
+ touch onlysomefiles/.thisfile onlysomefiles/thatfile
+ setopt globdots
+ print onlysomefiles/*
+ unsetopt globdots
+ print onlysomefiles/*
+ rm -rf onlysomefiles
+0:GLOB_DOTS option
+>onlysomefiles/.thisfile onlysomefiles/thatfile
+>onlysomefiles/thatfile
+
+ # we've tested this enough times already...
+ # could add some stuff for other sorts of expansion
+ foo='tmp*'
+ setopt globsubst
+ print ${foo}
+ unsetopt globsubst
+ print ${foo}
+0:GLOB_SUBST option
+>tmpcd tmpfile1 tmpfile2
+>tmp*
+
+ setopt histsubstpattern
+ print *(:s/t??/TING/)
+ foo=(tmp*)
+ print ${foo:s/??p/THUMP/}
+ foo=(one.c two.c three.c)
+ print ${foo:s/#%(#b)t(*).c/T${match[1]}.X/}
+ print *(#q:s/#(#b)tmp(*e)/'scrunchy${match[1]}'/)
+ unsetopt histsubstpattern
+0:HIST_SUBST_PATTERN option
+>TINGcd TINGfile1 TINGfile2 homedir
+>THUMPcd THUMPfile1 THUMPfile2
+>one.c Two.X Three.X
+>homedir scrunchyfile1 scrunchyfile2 tmpcd
+
+ setopt ignorebraces
+ echo X{a,b}Y
+ unsetopt ignorebraces
+ echo X{a,b}Y
+0:IGNORE_BRACES option
+>X{a,b}Y
+>XaY XbY
+
+ setopt ksh_arrays
+ array=(one two three)
+ print $array $array[2]
+ print ${array[0]} ${array[1]} ${array[2]} ${array[3]}
+ unsetopt ksh_arrays
+ print $array $array[2]
+ print ${array[0]} ${array[1]} ${array[2]} ${array[3]}
+ unset array
+0:KSH_ARRAYS option
+>one one[2]
+>one two three
+>one two three two
+>one two three
+
+ fpath=(.)
+ echo >foo 'echo foo loaded; foo() { echo foo run; }'
+ echo >bar 'bar() { echo bar run; }'
+ setopt kshautoload
+ autoload foo bar
+ foo
+ bar
+ unfunction foo bar
+ unsetopt kshautoload
+ autoload foo bar
+ foo
+ bar
+0:KSH_AUTOLOAD option
+>foo loaded
+>foo run
+>bar run
+>foo loaded
+>bar run
+
+# ksh_glob is tested by the glob tests.
+
+ setopt kshoptionprint globassign
+ print set
+ setopt | grep kshoptionprint
+ setopt | grep globassign
+ unsetopt kshoptionprint
+ print unset
+ setopt | grep kshoptionprint
+ setopt | grep globassign
+ unsetopt globassign
+0:KSH_OPTION_PRINT option
+>set
+>kshoptionprint on
+>globassign on
+>unset
+>globassign
+
+ # This test is now somewhat artificial as
+ # KSH_TYPESET only applies to the builtin
+ # interface. Tests to the more standard
+ # reserved word interface appear elsewhere.
+ (
+ # reserved words are handled during parsing,
+ # hence eval...
+ disable -r typeset
+ eval '
+ setopt kshtypeset
+ ktvars=(ktv1 ktv2)
+ typeset ktfoo=`echo arg1 arg2` $ktvars
+ print $+ktv1 $+ktv2 $+ktv3
+ print $ktfoo
+ unsetopt kshtypeset
+ typeset noktfoo=`echo noktarg1 noktarg2`
+ print $noktfoo
+ print $+noktarg1 $+noktarg2
+ unset ktfoo ktv1 ktv2 noktfoo noktarg2
+ '
+ )
+0:KSH_TYPESET option
+>1 1 0
+>arg1 arg2
+>noktarg1
+>0 1
+
+ showopt() { setopt | egrep 'localoptions|ksharrays'; }
+ f1() { setopt localoptions ksharrays; showopt }
+ f2() { setopt ksharrays; showopt }
+ setopt kshoptionprint
+ showopt
+ f1
+ showopt
+ f2
+ showopt
+ unsetopt ksh_arrays
+0:LOCAL_OPTIONS option
+>ksharrays off
+>localoptions off
+>ksharrays on
+>localoptions on
+>ksharrays off
+>localoptions off
+>ksharrays on
+>localoptions off
+>ksharrays on
+>localoptions off
+
+# LOCAL_TRAPS was tested in C03traps (phew).
+
+ fn() {
+ local HOME=/any/old/name
+ print -l var=~ 'anything goes/here'=~ split=`echo maybe not`;
+ }
+ setopt magicequalsubst
+ fn
+ setopt kshtypeset
+ fn
+ unsetopt magicequalsubst kshtypeset
+ fn
+0:MAGIC_EQUAL_SUBST option
+>var=/any/old/name
+>anything goes/here=/any/old/name
+>split=maybe
+>not
+>var=/any/old/name
+>anything goes/here=/any/old/name
+>split=maybe not
+>var=~
+>anything goes/here=~
+>split=maybe
+>not
+
+ setopt MARK_DIRS
+ print tmp*
+ unsetopt MARK_DIRS
+ print tmp*
+0:MARK_DIRS option
+>tmpcd/ tmpfile1 tmpfile2
+>tmpcd tmpfile1 tmpfile2
+
+# maybe should be in A04redirect
+ print "This is in1" >in1
+ print "This is in2" >in2
+ unsetopt multios
+ print Test message >foo1 >foo2
+ print foo1: $(<foo1)
+ print foo2: $(<foo2)
+ cat <in1 <in2
+ setopt multios
+ print Test message >foo1 >foo2
+ sleep 1 # damn, race in multios
+ print foo1: $(<foo1)
+ print foo2: $(<foo2)
+ cat <in1 <in2
+ rm -f foo1 foo2 in1 in2
+0:MULTIOS option
+>foo1:
+>foo2: Test message
+>This is in2
+>foo1: Test message
+>foo2: Test message
+>This is in1
+>This is in2
+
+# This is trickier than it looks. There's a hack at the end of
+# execcmd() to catch the multio processes attached to the
+# subshell, which otherwise sort of get lost in the general turmoil.
+# Without that, the multios aren't synchronous with the subshell
+# or the main shell starting the "cat", so the output files appear
+# empty.
+ setopt multios
+ ( echo hello ) >multio_out1 >multio_out2 && cat multio_out*
+0:Multios attached to a subshell
+>hello
+>hello
+
+# This tests for another race in multios.
+ print -u $ZTST_fd 'This test hangs the shell when it fails...'
+ setopt multios
+ echo These are the contents of the file >multio_race.out
+ multio_race_fn() { cat; }
+ multio_race_fn <$(echo multio_race.out multio_race.out)
+0:Fix for race with input multios
+>These are the contents of the file
+>These are the contents of the file
+
+# tried this with other things, but not on its own, so much.
+ unsetopt nomatch
+ print with nonomatch: flooble*
+ setopt nomatch
+ print with nomatch flooble*
+1:NOMATCH option
+>with nonomatch: flooble*
+?(eval):4: no matches found: flooble*
+
+# NULL_GLOB should override NONOMATCH...
+ setopt nullglob nomatch
+ print frooble* tmp*
+ unsetopt nullglob nomatch
+ print frooble* tmp*
+0:NULL_GLOB option
+>tmpcd tmpfile1 tmpfile2
+>frooble* tmpcd tmpfile1 tmpfile2
+
+ touch ngs1.txt ngs2.txt ngs10.txt ngs20.txt ngs100.txt ngs200.txt
+ setopt numericglobsort
+ print -l ngs*
+ unsetopt numericglobsort
+ print -l ngs*
+0:NUMERIC_GLOB_SORT option
+>ngs1.txt
+>ngs2.txt
+>ngs10.txt
+>ngs20.txt
+>ngs100.txt
+>ngs200.txt
+>ngs1.txt
+>ngs10.txt
+>ngs100.txt
+>ngs2.txt
+>ngs20.txt
+>ngs200.txt
+
+ typeset -i 10 oznum
+ setopt octalzeroes
+ (( oznum = 012 + 013 ))
+ print $oznum
+ unsetopt octalzeroes
+ (( oznum = 012 + 013 ))
+ print $oznum
+ unset oznum
+0:OCTAL_ZEROES options
+>21
+>25
+
+ typeset -a oldpath
+ oldpath=($path)
+ mkdir pdt_topdir pathtestdir pdt_topdir/pathtestdir
+ print "#!/bin/sh\necho File in upper dir" >pathtestdir/findme
+ print "#!/bin/sh\necho File in lower dir" >pdt_topdir/pathtestdir/findme
+ chmod u+x pathtestdir/findme pdt_topdir/pathtestdir/findme
+ pathtestdir/findme
+ rm -f pathtestdir/findme
+ setopt pathdirs
+ path=($PWD $PWD/pdt_topdir)
+ pathtestdir/findme
+ print unsetting option...
+ unsetopt pathdirs
+ pathtestdir/findme
+ path=($oldpath)
+ unset oldpath
+ rm -rf pdt_topdir pathtestdir
+0:PATH_DIRS option
+>File in upper dir
+>File in lower dir
+>unsetting option...
+?(eval):14: no such file or directory: pathtestdir/findme
+
+ (setopt pathdirs; path+=( /usr/bin ); type ./env)
+1:whence honours PATH_DIRS option
+>./env not found
+
+ setopt posixbuiltins
+ PATH= command -v print
+ PATH= command -V print
+ PATH= command print foo
+ unsetopt posixbuiltins
+ print unsetting...
+ PATH= command -V print
+ PATH= command print foo
+127:POSIX_BUILTINS option
+>print
+>print is a shell builtin
+>foo
+>unsetting...
+>print is a shell builtin
+?(eval):8: command not found: print
+
+ # With non-special command: original value restored
+ # With special builtin: new value kept
+ # With special builtin preceeded by "command": original value restored.
+ (setopt posixbuiltins
+ FOO=val0
+ FOO=val1 true; echo $FOO
+ FOO=val2 times 1>/dev/null 2>&1; echo $FOO
+ FOO=val3 command times 1>/dev/null 2>&1; echo $FOO)
+0:POSIX_BUILTINS and restoring variables
+>val0
+>val2
+>val2
+
+# PRINTEXITVALUE only works if shell input is coming from standard input.
+# Goodness only knows why.
+ $ZTST_testdir/../Src/zsh -f <<<'
+ setopt printexitvalue
+ func() {
+ false
+ }
+ func
+ '
+1:PRINT_EXIT_VALUE option
+?zsh: exit 1
+
+ $ZTST_testdir/../Src/zsh -f <<<'
+ setopt printexitvalue
+ () { false; }
+ '
+1:PRINT_EXIT_VALUE option for anonymous function
+?zsh: exit 1
+
+ setopt promptbang
+ print -P !
+ setopt nopromptbang
+ print -P !
+0:PROMPT_BANG option
+>0
+>!
+
+ unsetopt promptpercent
+ print -P '%/'
+ setopt promptpercent
+ print -P '%/'
+0q:PROMPT_PERCENT option
+>%/
+>$mydir
+
+ setopt promptsubst
+ print -P '`echo waaah`'
+ unsetopt promptsubst
+ print -P '`echo waaah`'
+0:PROMPT_SUBST option
+>waaah
+>`echo waaah`
+
+ dirs
+ pushd $mydir/tmpcd
+ dirs
+ pushd $mydir/tmpcd
+ dirs
+ setopt pushdignoredups
+ pushd $mydir/tmpcd
+ dirs
+ unsetopt pushdignoredups
+ popd >/dev/null
+ popd >/dev/null
+0q:PUSHD_IGNOREDUPS option
+>$mydirt
+>$mydirt/tmpcd $mydirt
+>$mydirt/tmpcd $mydirt/tmpcd $mydirt
+>$mydirt/tmpcd $mydirt/tmpcd $mydirt
+
+ mkdir newcd
+ cd $mydir
+ pushd $mydir/tmpcd
+ pushd $mydir/newcd
+ dirs
+ pushd -0
+ dirs
+ setopt pushdminus pushdsilent
+ pushd -0
+ dirs
+ unsetopt pushdminus
+ popd >/dev/null
+ popd >/dev/null
+ cd $mydir
+0q:PUSHD_MINUS option
+>$mydirt/newcd $mydirt/tmpcd $mydirt
+>$mydirt $mydirt/newcd $mydirt/tmpcd
+>$mydirt $mydirt/newcd $mydirt/tmpcd
+
+# Do you have any idea how dull this is?
+
+ (export HOME=$mydir/homedir
+ pushd $mydir/tmpcd
+ pushd
+ dirs
+ setopt pushdtohome
+ pushd
+ dirs
+ unsetopt pushdtohome
+ popd
+ pushd
+ popd
+ dirs)
+0q:PUSHD_TO_HOME option
+>$mydirhome $mydirhome/tmpcd
+>~ $mydirhome $mydirhome/tmpcd
+>$mydirhome
+
+ array=(one two three four)
+ setopt rcexpandparam
+ print aa${array}bb
+ unsetopt rcexpandparam
+ print aa${array}bb
+0:RC_EXPAND_PARAM option
+>aaonebb aatwobb aathreebb aafourbb
+>aaone two three fourbb
+
+ setopt rcquotes
+ # careful, this is done when parsing a complete block
+ eval "print 'one''quoted''expression'"
+ unsetopt rcquotes
+ eval "print 'another''quoted''expression'"
+0:RC_QUOTES option
+>one'quoted'expression
+>anotherquotedexpression
+
+# too lazy to test jobs -Z and ARGV0.
+ (setopt restricted; cd /)
+ (setopt restricted; PATH=/bin:/usr/bin)
+ (setopt restricted; /bin/ls)
+ (setopt restricted; hash ls=/bin/ls)
+ (setopt restricted; print ha >outputfile)
+ (setopt restricted; exec ls)
+ (setopt restricted; unsetopt restricted)
+ :
+0:RESTRICTED option
+?(eval):cd:1: restricted
+?(eval):2: PATH: restricted
+?(eval):3: /bin/ls: restricted
+?(eval):hash:4: restricted: /bin/ls
+?(eval):5: writing redirection not allowed in restricted mode
+?(eval):exec:6: ls: restricted
+?(eval):unsetopt:7: can't change option: restricted
+
+# ' emacs deconfusion
+
+ fn() {
+ print =ls ={ls,}
+ local foo='=ls'
+ print ${~foo}
+ }
+ setopt shfileexpansion
+ fn
+ unsetopt shfileexpansion
+ fn
+0q:SH_FILE_EXPANSION option
+>$lspath =ls =
+>=ls
+>$lspath $lspath =
+>$lspath
+
+ testpat() {
+ if [[ $1 = ${~2} ]]; then print $1 $2 yes; else print $1 $2 no; fi
+ }
+ print option on
+ setopt shglob
+ repeat 2; do
+ for str in 'a(b|c)' ab; do
+ testpat $str 'a(b|c)'
+ done
+ for str in 'a<1-10>' a9; do
+ testpat $str 'a<1-10>'
+ done
+ [[ ! -o shglob ]] && break
+ print option off
+ unsetopt shglob
+ done
+0:SH_GLOB option
+>option on
+>a(b|c) a(b|c) yes
+>ab a(b|c) no
+>a<1-10> a<1-10> yes
+>a9 a<1-10> no
+>option off
+>a(b|c) a(b|c) no
+>ab a(b|c) yes
+>a<1-10> a<1-10> no
+>a9 a<1-10> yes
+
+ print this is bar >bar
+ fn() {
+ local NULLCMD=cat READNULLCMD=cat
+ { echo hello | >foo } 2>/dev/null
+ cat foo
+ <bar
+ }
+ setopt shnullcmd
+ print option set
+ fn
+ unsetopt shnullcmd
+ print option unset
+ fn
+ rm -f foo bar
+0:SH_NULLCMD option
+>option set
+>option unset
+>hello
+>this is bar
+
+ fn() {
+ eval 'for f in foo bar; print $f'
+ eval 'for f (word1 word2) print $f'
+ eval 'repeat 3 print nonsense'
+ }
+ unsetopt shortloops
+ print option unset
+ fn
+ setopt shortloops
+ print option set
+ fn
+0:SHORT_LOOPS option
+>option unset
+>option set
+>foo
+>bar
+>word1
+>word2
+>nonsense
+>nonsense
+>nonsense
+?(eval):1: parse error near `print'
+?(eval):1: parse error near `print'
+?(eval):1: parse error near `print'
+
+ fn() { print -l $*; }
+ setopt shwordsplit
+ print option set
+ repeat 2; do
+ foo='two words'
+ fn $foo
+ fn "${=foo}"
+ [[ ! -o shwordsplit ]] && break
+ unsetopt shwordsplit
+ print option unset
+ done
+0:SH_WORD_SPLIT option
+>option set
+>two
+>words
+>two
+>words
+>option unset
+>two words
+>two
+>words
+
+ fn() { unset foo; print value is $foo; }
+ setopt nounset
+ print option unset unset by setting nounset
+ eval fn
+ print option unset reset
+ setopt unset
+ fn
+0:UNSET option
+>option unset unset by setting nounset
+>option unset reset
+>value is
+?fn: foo: parameter not set
+
+ fn1() { unset foo; print value 1 is ${foo#bar}; }
+ fn2() { unset foo; print value 2 is ${foo%bar}; }
+ fn3() { unset foo; print value 3 is ${foo/bar}; }
+ setopt nounset
+ print option unset unset by setting nounset
+ eval fn1
+ eval fn2
+ eval fn3
+ print option unset reset
+ setopt unset
+ fn1
+ fn2
+ fn3
+0:UNSET option with operators
+>option unset unset by setting nounset
+>option unset reset
+>value 1 is
+>value 2 is
+>value 3 is
+?fn1: foo: parameter not set
+?fn2: foo: parameter not set
+?fn3: foo: parameter not set
+
+ fn() {
+ emulate -L zsh
+ setopt warncreateglobal
+ foo1=bar1
+ unset foo1
+ foo1=bar2
+ local foo2=bar3
+ unset foo2
+ foo2=bar4
+ typeset -g foo3
+ foo3=bar5
+ fn2() {
+ foo3=bar6
+ }
+ foo4=bar7 =true
+ (( foo5=8 ))
+ integer foo6=9
+ (( foo6=10 ))
+ }
+ # don't pollute the test environment with the variables...
+ (fn)
+0:WARN_CREATE_GLOBAL option
+?fn:3: scalar parameter foo1 created globally in function fn
+?fn:5: scalar parameter foo1 created globally in function fn
+?fn:15: numeric parameter foo5 created globally in function fn
+
+ fn() {
+ emulate -L zsh
+ setopt warncreateglobal
+ TZ=UTC date >&/dev/null
+ local um=$(TZ=UTC date 2>/dev/null)
+ }
+ fn
+0:WARN_CREATE_GLOBAL negative cases
+
+ (
+ foo1=global1 foo2=global2 foo3=global3 foo4=global4
+ integer foo5=5
+ # skip foo6, defined in fn_wnv
+ foo7=(one two)
+ fn_wnv() {
+ # warns
+ foo1=bar1
+ # doesn't warn
+ local foo2=bar3
+ unset foo2
+ # still doesn't warn
+ foo2=bar4
+ # doesn't warn
+ typeset -g foo3=bar5
+ # warns
+ foo3=bar6
+ fn2() {
+ # warns if global option, not attribute
+ foo3=bar6
+ }
+ fn2
+ # doesn't warn
+ foo4=bar7 =true
+ # warns
+ (( foo5=8 ))
+ integer foo6=9
+ # doesn't warn
+ (( foo6=10 ))
+ foo7[3]=three
+ foo7[4]=(four)
+ }
+ print option off >&2
+ fn_wnv
+ print option on >&2
+ setopt warnnestedvar
+ fn_wnv
+ unsetopt warnnestedvar
+ print function attribute on >&2
+ functions -W fn_wnv
+ fn_wnv
+ print all off again >&2
+ functions +W fn_wnv
+ fn_wnv
+ )
+0:WARN_NESTED_VAR option
+?option off
+?option on
+?fn_wnv:2: scalar parameter foo1 set in enclosing scope in function fn_wnv
+?fn_wnv:11: scalar parameter foo3 set in enclosing scope in function fn_wnv
+?fn2:2: scalar parameter foo3 set in enclosing scope in function fn2
+?fn_wnv:20: numeric parameter foo5 set in enclosing scope in function fn_wnv
+?function attribute on
+?fn_wnv:2: scalar parameter foo1 set in enclosing scope in function fn_wnv
+?fn_wnv:11: scalar parameter foo3 set in enclosing scope in function fn_wnv
+?fn_wnv:20: numeric parameter foo5 set in enclosing scope in function fn_wnv
+?all off again
+
+
+ (
+ setopt warnnestedvar
+ () {
+ typeset -A a
+ : ${a[hello world]::=foo}
+ print ${(t)a}
+ key="hello world"
+ print $a[$key]
+ }
+ )
+0:No false positive on parameter used with subscripted assignment
+>association-local
+>foo
+
+ (
+ setopt warnnestedvar
+ () {
+ local var=(one two)
+ () { var=three; }
+ print $var
+ }
+ )
+0:Warn when changing type of nested variable: array to scalar.
+?(anon): scalar parameter var set in enclosing scope in function (anon)
+>three
+
+ (
+ setopt warnnestedvar
+ () {
+ local var=three
+ () { var=(one two); }
+ print $var
+ }
+ )
+0:Warn when changing type of nested variable: scalar to array.
+?(anon): array parameter var set in enclosing scope in function (anon)
+>one two
+
+# This really just tests if XTRACE is egregiously broken.
+# To test it properly would need a full set of its own.
+ fn() { print message; }
+ PS4='+%N:%i> '
+ setopt xtrace
+ fn
+ unsetopt xtrace
+ fn
+0:XTRACE option
+>message
+>message
+?+(eval):4> fn
+?+fn:0> print message
+?+(eval):5> unsetopt xtrace
+
+ setopt ignoreclosebraces
+ eval "icb_test() { echo this is OK; }"
+ icb_test
+ icb_args() { print $#; }
+ eval "icb_args { this, is, ok, too }"
+0:IGNORE_CLOSE_BRACES option
+>this is OK
+>6
+
+ (setopt pipefail
+ true | true | true
+ print $?
+ true | false | true
+ print $?
+ exit 2 | false | true
+ print $?
+ false | exit 2 | true
+ print $?)
+0:PIPE_FAIL option
+>0
+>1
+>1
+>2
+
+ for (( i = 0; i < 10; i++ )); do
+ () {
+ print $i
+ break
+ }
+ done
+0:NO_LOCAL_LOOPS
+>0
+
+ () {
+ emulate -L zsh
+ setopt localloops
+ for (( i = 0; i < 10; i++ )); do
+ () {
+ setopt nolocalloops # ignored in parent
+ print $i
+ break
+ }
+ done
+ }
+0:LOCAL_LOOPS
+>0
+>1
+>2
+>3
+>4
+>5
+>6
+>7
+>8
+>9
+?(anon):4: `break' active at end of function scope
+?(anon):4: `break' active at end of function scope
+?(anon):4: `break' active at end of function scope
+?(anon):4: `break' active at end of function scope
+?(anon):4: `break' active at end of function scope
+?(anon):4: `break' active at end of function scope
+?(anon):4: `break' active at end of function scope
+?(anon):4: `break' active at end of function scope
+?(anon):4: `break' active at end of function scope
+?(anon):4: `break' active at end of function scope
diff --git a/dotfiles/system/.zsh/modules/Test/E02xtrace.ztst b/dotfiles/system/.zsh/modules/Test/E02xtrace.ztst
new file mode 100644
index 0000000..da6191c
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/E02xtrace.ztst
@@ -0,0 +1,148 @@
+# Test that xtrace output is correctly generated
+
+%prep
+ mkdir xtrace.tmp && cd xtrace.tmp
+
+ function xtf {
+ local regression_test_dummy_variable
+ print "$*"
+ }
+ function xtfx {
+ local regression_test_dummy_variable
+ print "Tracing: (){ builtin 2>file }" 2>>xtrace.err
+ { print "Tracing: (){ { builtin } 2>file }" } 2>>xtrace.err
+ }
+ echo 'print "$*"' > xt.in
+
+%test
+
+ PS4='+%N:%i> '
+ set -x
+ print 'Tracing: builtin'
+ print 'Tracing: builtin 2>file' 2>xtrace.err
+ cat <<<'Tracing: external'
+ cat <<<'Tracing: external 2>file' 2>>xtrace.err
+ ( print 'Tracing: ( builtin )' )
+ ( print 'Tracing: ( builtin ) 2>file' ) 2>>xtrace.err
+ ( cat <<<'Tracing: ( external )' )
+ ( cat <<<'Tracing: ( external ) 2>file' ) 2>>xtrace.err
+ { print 'Tracing: { builtin }' }
+ { print 'Tracing: { builtin } 2>file' } 2>>xtrace.err
+ { cat <<<'Tracing: { external }' }
+ { cat <<<'Tracing: { external } 2>file' } 2>>xtrace.err
+ repeat 1 do print 'Tracing: do builtin done'; done
+ repeat 1 do print 'Tracing: do builtin done 2>file'; done 2>>xtrace.err
+ repeat 1 do cat <<<'Tracing: do external done'; done
+ repeat 1 do cat <<<'Tracing: do external done 2>file'; done 2>>xtrace.err
+ xtf 'Tracing: function'
+ xtf 'Tracing: function 2>file' 2>>xtrace.err
+ xtfx
+ . ./xt.in 'Tracing: source'
+ . ./xt.in 'Tracing: source 2>file' 2>>xtrace.err
+ set +x
+ cat xtrace.err
+0:xtrace with and without redirection
+>Tracing: builtin
+>Tracing: builtin 2>file
+>Tracing: external
+>Tracing: external 2>file
+>Tracing: ( builtin )
+>Tracing: ( builtin ) 2>file
+>Tracing: ( external )
+>Tracing: ( external ) 2>file
+>Tracing: { builtin }
+>Tracing: { builtin } 2>file
+>Tracing: { external }
+>Tracing: { external } 2>file
+>Tracing: do builtin done
+>Tracing: do builtin done 2>file
+>Tracing: do external done
+>Tracing: do external done 2>file
+>Tracing: function
+>Tracing: function 2>file
+>Tracing: (){ builtin 2>file }
+>Tracing: (){ { builtin } 2>file }
+>Tracing: source
+>Tracing: source 2>file
+>+(eval):8> print 'Tracing: ( builtin ) 2>file'
+>+(eval):10> cat
+>+(eval):12> print 'Tracing: { builtin } 2>file'
+>+(eval):14> cat
+>+(eval):16> print 'Tracing: do builtin done 2>file'
+>+(eval):18> cat
+>+xtf:1> local regression_test_dummy_variable
+>+xtf:2> print 'Tracing: function 2>file'
+>+xtfx:3> print 'Tracing: (){ { builtin } 2>file }'
+?+(eval):3> print 'Tracing: builtin'
+?+(eval):4> print 'Tracing: builtin 2>file'
+?+(eval):5> cat
+?+(eval):6> cat
+?+(eval):7> print 'Tracing: ( builtin )'
+?+(eval):9> cat
+?+(eval):11> print 'Tracing: { builtin }'
+?+(eval):13> cat
+?+(eval):15> print 'Tracing: do builtin done'
+?+(eval):17> cat
+?+(eval):19> xtf 'Tracing: function'
+?+xtf:1> local regression_test_dummy_variable
+?+xtf:2> print 'Tracing: function'
+?+(eval):20> xtf 'Tracing: function 2>file'
+?+(eval):21> xtfx
+?+xtfx:1> local regression_test_dummy_variable
+?+xtfx:2> print 'Tracing: (){ builtin 2>file }'
+?+(eval):22> . ./xt.in 'Tracing: source'
+?+./xt.in:1> print 'Tracing: source'
+?+(eval):23> . ./xt.in 'Tracing: source 2>file'
+?+./xt.in:1> print 'Tracing: source 2>file'
+?+(eval):24> set +x
+
+ typeset -ft xtf
+ xtf 'Tracing: function'
+0:tracing function
+>Tracing: function
+?+xtf:1> local regression_test_dummy_variable
+?+xtf:2> print 'Tracing: function'
+
+ echo 'PS4="+%x:%I> "
+ fn() {
+ print This is fn.
+ }
+ :
+ fn
+ ' >fnfile
+ $ZTST_testdir/../Src/zsh -fx ./fnfile 2>errfile
+ grep '\./fnfile' errfile 1>&2
+0:Trace output with sourcefile and line number.
+>This is fn.
+?+./fnfile:1> PS4='+%x:%I> '
+?+./fnfile:5> :
+?+./fnfile:6> fn
+?+./fnfile:3> print This is fn.
+
+ set -x
+ [[ 'f o' == 'f x'* || 'b r' != 'z o' && 'squashy sound' < 'squishy sound' ]]
+ [[ 'f o' = 'f x'* || 'b r' != 'z o' && 'squashy sound' < 'squishy sound' ]]
+ [[ -e nonexistentfile || ( -z '' && -t 3 ) ]]
+ set +x
+0:Trace for conditions
+?+(eval):2> [[ 'f o' == f\ x* || 'b r' != z\ o && 'squashy sound' < 'squishy sound' ]]
+?+(eval):3> [[ 'f o' = f\ x* || 'b r' != z\ o && 'squashy sound' < 'squishy sound' ]]
+?+(eval):4> [[ -e nonexistentfile || -z '' && -t 3 ]]
+?+(eval):5> set +x
+
+ # Part 1: Recurses into nested anonymous functions
+ fn() {
+ () { () { true } }
+ }
+ functions -T fn
+ fn
+ # Part 2: Doesn't recurse into named functions
+ gn() { true }
+ fn() { gn }
+ functions -T fn
+ fn
+0:tracing recurses into anonymous functions
+?+fn:1> '(anon)'
+?+(anon):0> '(anon)'
+?+(anon):0> true
+?+fn:0> gn
diff --git a/dotfiles/system/.zsh/modules/Test/Makefile.in b/dotfiles/system/.zsh/modules/Test/Makefile.in
new file mode 100644
index 0000000..083df49
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/Makefile.in
@@ -0,0 +1,75 @@
+#
+# Makefile for Test subdirectory
+#
+# Copyright (c) 1999 Peter Stephensons
+# All rights reserved.
+#
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and to distribute modified versions of this software for any
+# purpose, provided that the above copyright notice and the following
+# two paragraphs appear in all copies of this software.
+#
+# In no event shall Peter Stephenson or the Zsh Development Group be liable
+# to any party for direct, indirect, special, incidental, or consequential
+# damages arising out of the use of this software and its documentation,
+# even if Peter Stephenson and the Zsh Development Group have been advised of
+# the possibility of such damage.
+#
+# Peter Stephenson and the Zsh Development Group specifically disclaim any
+# warranties, including, but not limited to, the implied warranties of
+# merchantability and fitness for a particular purpose. The software
+# provided hereunder is on an "as is" basis, and Peter Stephenson and the
+# Zsh Development Group have no obligation to provide maintenance,
+# support, updates, enhancements, or modifications.
+#
+
+subdir = Test
+dir_top = ..
+SUBDIRS =
+
+@VERSION_MK@
+
+# source/build directories
+VPATH = @srcdir@
+sdir = @srcdir@
+sdir_top = @top_srcdir@
+INSTALL = @INSTALL@
+
+@DEFS_MK@
+
+# ========== DEPENDENCIES FOR TESTING ==========
+
+check test:
+ if test -n "$(DLLD)"; then \
+ cd $(dir_top) && DESTDIR= \
+ $(MAKE) MODDIR=`pwd`/$(subdir)/Modules install.modules > /dev/null; \
+ fi
+ if ZTST_testlist="`for f in $(sdir)/$(TESTNUM)*.ztst; \
+ do echo $$f; done`" \
+ ZTST_srcdir="$(sdir)" \
+ ZTST_exe=$(dir_top)/Src/zsh@EXEEXT@ \
+ $(dir_top)/Src/zsh@EXEEXT@ +Z -f $(sdir)/runtests.zsh; then \
+ stat=0; \
+ else \
+ stat=1; \
+ fi; \
+ sleep 1; \
+ rm -rf Modules .zcompdump; \
+ exit $$stat
+
+# ========== DEPENDENCIES FOR CLEANUP ==========
+
+@CLEAN_MK@
+
+mostlyclean-here:
+ rm -rf Modules .zcompdump *.tmp
+
+distclean-here:
+ rm -f Makefile
+
+realclean-here:
+
+# ========== DEPENDENCIES FOR MAINTENANCE ==========
+
+@CONFIG_MK@
diff --git a/dotfiles/system/.zsh/modules/Test/README b/dotfiles/system/.zsh/modules/Test/README
new file mode 100644
index 0000000..d012277
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/README
@@ -0,0 +1,30 @@
+There are now different sections, expressed by the first letter in the
+scripts names:
+
+ A: basic command parsing and execution
+ B: builtins
+ C: shell commands with special syntax
+ D: substititution
+ E: options
+ V: modules
+ W: builtin interactive commands and constructs
+ X: line editing
+ Y: completion
+ Z: separate systems and user contributions
+
+You will need to run these by using `make test' in the Test subdirectory of
+the build area for your system (which may or may not be the same as the
+Test subdirectory of the source tree), or the directory above. You can get
+more information about the tests being performed with
+ ZTST_verbose=1 make check
+(`test' is equivalent to `check') or change 1 to 2 for even more detail.
+
+Individual or groups of tests can be performed with
+ make TESTNUM=C02 check
+or
+ make TESTNUM=C check
+to perform just the test beginning C02, or all tests beginning C,
+respectively.
+
+Instructions on how to write tests are given in B01cd.ztst, which acts as a
+model.
diff --git a/dotfiles/system/.zsh/modules/Test/V02zregexparse.ztst b/dotfiles/system/.zsh/modules/Test/V02zregexparse.ztst
new file mode 100644
index 0000000..b4cec42
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/V02zregexparse.ztst
@@ -0,0 +1,382 @@
+# Tests corresponding to the texinfo node `Conditional Expressions'
+
+%prep
+
+ if ! zmodload zsh/zutil 2>/dev/null; then
+ ZTST_unimplemented="can't load the zsh/zutil module for testing"
+ fi
+
+%test
+
+ zregexparse p1 p2 ''
+0:empty
+
+ zregexparse p1 p2 a /a/
+0:element
+
+ zregexparse p1 p2 aaaaaa /a/ \#
+0:closure
+
+ zregexparse p1 p2 ab /a/ /b/
+0:concatenation
+
+ zregexparse p1 p2 a /a/ \| /b/
+0:alternation 1
+
+ zregexparse p1 p2 b /a/ \| /b/
+0:alternation 2
+
+ zregexparse p1 p2 a \( /a/ \)
+0:grouping
+
+ zregexparse p1 p2 abbaaab \( /a/ \| /b/ \) \#
+0:alternation, grouping and closure
+
+ zregexparse p1 p2 abcdef /ab/ %cd% /cdef/
+0:lookahead 1
+
+ zregexparse p1 p2 abcdef /ab/ %ZZ% /cdef/
+1:lookahead 2
+
+ zregexparse p1 p2 abcd /ab/ %cd% '-print guard' ':print caction' /cd/
+0:pattern, lookahead, guard and completion action
+>guard
+
+ zregexparse p1 p2 abcd /ab/ %cd% '-print guard; false' ':print caction' /cd/
+1:guard failure
+>guard
+>caction
+
+ zregexparse p1 p2 abcdef /ab/ '{print AB}' /cd/ '{print CD}' /ef/ '{print EF}'
+0:action
+>AB
+>CD
+>EF
+
+ zregexparse p1 p2 aaa
+ print $? $p1 $p2
+0:aaa
+>2 0 0
+
+ zregexparse p1 p2 aaa /a/
+ print $? $p1 $p2
+0:aaa /a/
+>2 1 1
+
+ zregexparse p1 p2 aaa /a/ /a/
+ print $? $p1 $p2
+0:aaa 2*/a/
+>2 2 2
+
+ zregexparse p1 p2 aaa /a/ /a/ /a/
+ print $? $p1 $p2
+0:aaa 3*/a/
+>0 3 3
+
+ zregexparse p1 p2 aaa /a/ /a/ /a/ /a/
+ print $? $p1 $p2
+0:aaa 4*/a/
+>1 3 3
+
+ zregexparse p1 p2 aaa /a/ /a/ /a/ /a/ /a/
+ print $? $p1 $p2
+0:aaa 5*/a/
+>1 3 3
+
+ zregexparse p1 p2 aaa /aaa/
+ print $? $p1 $p2
+0:aaa /aaa/
+>0 3 3
+
+ zregexparse p1 p2 aaa /aaa/ /a/
+ print $? $p1 $p2
+0:aaa /aaa/ /a/
+>1 3 3
+
+ zregexparse p1 p2 aaa /a/ \#
+ print $? $p1 $p2
+0:aaa /aaa/ #
+>0 3 3
+
+ zregexparse p1 p2 aaa /a/ \# \#
+ print $? $p1 $p2
+0:aaa /aaa/ # #
+>0 3 3
+
+ zregexparse p1 p2 aaa \( /a/ \)
+ print $? $p1 $p2
+0:aaa ( /a/ )
+>2 1 1
+
+ zregexparse p1 p2 aaa \( /a/ \) \#
+ print $? $p1 $p2
+0:aaa ( /a/ ) #
+>0 3 3
+
+ zregexparse p1 p2 aaa /a/ /b/
+ print $? $p1 $p2
+0:aaa /a/ /b/
+>1 1 1
+
+ zregexparse p1 p2 a /a/ '{print A}'
+ print $? $p1 $p2
+0:a /a/ '{A}'
+>A
+>0 1 1
+
+ zregexparse p1 p2 a /b/ '{print A}'
+ print $? $p1 $p2
+0:a /b/ '{A}'
+>1 0 0
+
+ zregexparse p1 p2 a /b/ ':print A' '{print B}'
+ print $? $p1 $p2
+0:a /b/ ':A' '{B}'
+>A
+>1 0 0
+
+ zregexparse p1 p2 ab /a/ '{print A}'
+ print $? $p1 $p2
+0:ab /a/ '{A}'
+>2 1 1
+
+ zregexparse p1 p2 ab /a/ '{print A}' /b/ '{print B}'
+ print $? $p1 $p2
+0:ab /a/ '{A}' /b/ '{B}'
+>A
+>B
+>0 2 2
+
+ zregexparse p1 p2 ab /a/ ':print A' '{print B}' /b/ ':print C' '{print D}'
+ print $? $p1 $p2
+0:ab /a/ ':A' '{B}' /b/ ':C' '{D}'
+>B
+>D
+>0 2 2
+
+ zregexparse p1 p2 abc /a/ '{print A}' /b/ '{print B}' /c/ '{print C}'
+ print $? $p1 $p2
+0:abc /a/ '{A}' /b/ '{B}' /c/ '{C}'
+>A
+>B
+>C
+>0 3 3
+
+ zregexparse p1 p2 abz /a/ '{print A}' /b/ '{print B}' /c/ '{print C}'
+ print $? $p1 $p2
+0:abz /a/ '{A}' /b/ '{B}' /c/ '{C}'
+>A
+>1 2 2
+
+ zregexparse p1 p2 azz /a/ '{print A}' /b/ '{print B}' /c/ '{print C}'
+ print $? $p1 $p2
+0:azz /a/ '{A}' /b/ '{B}' /c/ '{C}'
+>1 1 1
+
+ zregexparse p1 p2 aba '{print A}' /a/ '{print B}' /b/ '{print C}' /c/ '{print D}'
+ print $? $p1 $p2
+0:aba '{A}' /a/ '{B}' /b/ '{C}' /c/ '{D}'
+>A
+>B
+>1 2 2
+
+ zregexparse p1 p2 a /a/ '{print "$match[1]"}'
+ print $? $p1 $p2
+0:a /a/ '{M1}'
+>a
+>0 1 1
+
+ zregexparse p1 p2 aaa /a/ '{print A}' //
+ print $? $p1 $p2
+0:aaa /a/ '{A}' //
+>A
+>2 1 1
+
+ zregexparse p1 p2 aaa /a/ '{print "$match[1]"}' // '{print A}'
+ print $? $p1 $p2
+0:aaa /a/ '{M1}' // '{A}'
+>a
+>2 1 1
+
+ zregexparse p1 p2 abcdef /a/ '{print $match[1]}' /b/ '{print $match[1]}' /c/ '{print $match[1]}' // '{print A}'
+ print $? $p1 $p2
+0:abcdef /a/ '{M1}' /b/ '{M1}' /c/ '{M1}' // '{A}'
+>a
+>b
+>c
+>2 3 3
+
+ zregexparse p1 p2 abcdef /a/ '{print A}' /b/ '{print B}' /c/ '{print C}' // '{print D}'
+ print $? $p1 $p2
+0:abcdef /a/ '{A}' /b/ '{B}' /c/ '{C}' // '{D}'
+>A
+>B
+>C
+>2 3 3
+
+ zregexparse p1 p2 a /a/ '{print A}' /b/ '{print B}'
+ print $? $p1 $p2
+0:a /a/ {A} /b/ {B}
+>1 1 1
+
+ zregexparse p1 p2 abcdef \
+ /a/ '-print Ga:$p1:$p2:$match[1]' '{print Aa:$p1:$p2:$match[1]}' \
+ /b/ '-print Gb:$p1:$p2:$match[1]' '{print Ab:$p1:$p2:$match[1]}' \
+ /c/ '-print Gc:$p1:$p2:$match[1]' '{print Ac:$p1:$p2:$match[1]}' \
+ //
+ print $? $p1 $p2
+0:abcdef /a/ -Ga {Aa} /b/ -Gb {Aa} /c/ -Gc {Ac} //
+>Ga:0:0:a
+>Gb:1:1:b
+>Aa:1:1:a
+>Gc:2:2:c
+>Ab:2:2:b
+>Ac:3:3:c
+>2 3 3
+
+ zregexparse p1 p2 abcdef \
+ /a/ '-print Ga:$p1:$p2:$match[1]' '{print Aa:$p1:$p2:$match[1]}' \
+ /b/ '-print Gb:$p1:$p2:$match[1]' '{print Ab:$p1:$p2:$match[1]}' \
+ /c/ '-print Gc:$p1:$p2:$match[1]' '{print Ac:$p1:$p2:$match[1]}' \
+ '/[]/' ':print F:$p1:$p2'
+ print $? $p1 $p2
+0:abcdef /a/ -Ga {Aa} /b/ -Gb {Ab} /c/ -Gc {Ac} /[]/ :F
+>Ga:0:0:a
+>Gb:1:1:b
+>Aa:1:1:a
+>Gc:2:2:c
+>Ab:2:2:b
+>F:3:3
+>1 3 3
+
+ zregexparse p1 p2 abcdef \
+ /a/ '-print Ga:$p1:$p2:$match[1]' '{print Aa:$p1:$p2:$match[1]}' \
+ /b/ '-print Gb:$p1:$p2:$match[1]' '{print Ab:$p1:$p2:$match[1]}' \
+ /c/ '-print Gc:$p1:$p2:$match[1]' '{print Ac:$p1:$p2:$match[1]}' \
+ \( '/[]/' ':print F1:$p1:$p2' \| /z/ ':print F2' \)
+ print $? $p1 $p2
+0:abcdef /a/ -Ga {Aa} /b/ -Gb {Ab} /c/ -Gc {Ac} ( /[]/ :F1 | /z/ :F2 )
+>Ga:0:0:a
+>Gb:1:1:b
+>Aa:1:1:a
+>Gc:2:2:c
+>Ab:2:2:b
+>F1:3:3
+>F2
+>1 3 3
+
+ zregexparse p1 p2 a '/[]/' ':print A'
+ print $? $p1 $p2
+0:a /[]/ :A
+>A
+>1 0 0
+
+ zregexparse p1 p2 $'\0' $'/\0/' '{print A}'
+ print $? $p1 $p2
+0:"\0" /\0/ {A}
+>A
+>0 1 1
+
+ zregexparse p1 p2 $'\0' $'/\0/' '{print A}' '/ /' '{print B}'
+ print $? $p1 $p2
+0:"\0" /\0/ {A} / / {B}
+>1 1 1
+
+ zregexparse p1 p2 abcdef \( '/?/' '{print $match[1]}' \) \#
+ print $? $p1 $p2
+0:abcdef ( /?/ {M1} ) #
+>a
+>b
+>c
+>d
+>e
+>f
+>0 6 6
+
+ zregexparse p1 p2 abcdef \( '/c?|?/' '{print $match[1]}' \) \#
+ print $? $p1 $p2
+0:abcdef ( /c?|?/ {M1} ) #
+>a
+>b
+>cd
+>e
+>f
+>0 6 6
+
+ zregexparse p1 p2 abcacdef \( /a/ '{print $match[1]}' \| /b/ '{print $match[1]}' \| /c/ '{print $match[1]}' \) \#
+ print $? $p1 $p2
+0:abcacdef ( /a/ {M1} | /b/ {M1} | /c/ {M1} ) #
+>a
+>b
+>c
+>a
+>1 5 5
+
+ zregexparse p1 p2 abcdef \( /a/ ':print A' \| /b/ ':print B' \| /c/ ':print C' \) \#
+ print $? $p1 $p2
+0:abcdef ( /a/ :A | /b/ :B | /c/ :C ) #
+>A
+>B
+>C
+>1 3 3
+
+ zregexparse p1 p2 abcdef \( /a/ ':print A' '{print $match[1]}' \| /b/ ':print B' '{print $match[1]}' \| /c/ ':print C' '{print $match[1]}' \) \#
+ print $? $p1 $p2
+0:abcdef ( /a/ :A {M1} | /b/ :B {M1} | /c/ :C {M1} ) #
+>a
+>b
+>A
+>B
+>C
+>1 3 3
+
+ zregexparse p1 p2 $'com\0xx' /$'[^\0]#\0'/ \( /$'[^\0]#\0'/ :'print A' /$'[^\0]#\0'/ :'print B' \) \#
+ print $? $p1 $p2
+0:"com\0xx" /W/ ( /W/ :A /W/ :B ) #
+>A
+>1 4 4
+
+ zregexparse p1 p2 $'com\0xx\0yy' /$'[^\0]#\0'/ \( /$'[^\0]#\0'/ :'print A' /$'[^\0]#\0'/ :'print B' \) \#
+ print $? $p1 $p2
+0:"com\0xx\0yy" /W/ ( /W/ :A /W/ :B ) #
+>B
+>1 7 7
+
+ zregexparse p1 p2 $'com\0xx\0yy\0zz' /$'[^\0]#\0'/ \( /$'[^\0]#\0'/ :'print A' /$'[^\0]#\0'/ :'print B' \) \#
+ print $? $p1 $p2
+0:"com\0xx\0yy\0zz" /W/ ( /W/ :A /W/ :B ) #
+>A
+>1 10 10
+
+ zregexparse p1 p2 abcdez /abc/ ':print A:$p1:$p2' /def/ ':print B:$p1:$p2'
+ print $? $p1 $p2
+0:abcdez /abc/ :A /def/ :B
+>B:3:3
+>1 3 3
+
+ zregexparse p1 p2 abcdez /abc/+ ':print A:$p1:$p2' /def/ ':print B:$p1:$p2'
+ print $? $p1 $p2
+0:abcdez /abc/+ :A /def/ :B
+>A:0:3
+>B:0:3
+>1 0 3
+
+ zregexparse p1 p2 abcdez /abc/+ ':print A:$p1:$p2' // /def/ ':print B:$p1:$p2'
+ print $? $p1 $p2
+0:abcdez /abc/+ :A // /def/ :B
+>A:0:3
+>B:0:3
+>1 0 3
+
+ zregexparse p1 p2 abcdez /abc/+ ':print A:$p1:$p2' //- /def/ ':print B:$p1:$p2'
+ print $? $p1 $p2
+0:abcdez /abc/+ :A //- /def/ :B
+>B:3:3
+>1 3 3
+
+ zregexparse p1 p2 $'ZZZZ\0abcdef' $'/ZZZZ\0/' /abc/+ ':print A:$p1:$p2' /dee/ ':print B:$p1:$p2'
+ print $? $p1 $p2
+0:"ZZZZ\0abcdef" /ZZZZ\0/ /abc/+ :A /dee/ :B
+>A:5:8
+>B:5:8
+>1 5 8
diff --git a/dotfiles/system/.zsh/modules/Test/V03mathfunc.ztst b/dotfiles/system/.zsh/modules/Test/V03mathfunc.ztst
new file mode 100644
index 0000000..1edb7a2
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/V03mathfunc.ztst
@@ -0,0 +1,141 @@
+# Tests for the module zsh/mathfunc
+
+%prep
+ if ! zmodload zsh/mathfunc 2>/dev/null; then
+ ZTST_unimplemented="The module zsh/mathfunc is not available."
+ fi
+
+%test
+ # -g makes pi available in later tests
+ float -gF 5 pi
+ (( pi = 4 * atan(1.0) ))
+ print $pi
+0:Basic operation with atan
+>3.14159
+
+ float -F 5 result
+ (( result = atan(3,2) ))
+ print $result
+0:atan with two arguments
+>0.98279
+
+ print $(( atan(1,2,3) ))
+1:atan can't take three arguments
+?(eval):1: wrong number of arguments: atan(1,2,3)
+
+ float r1=$(( rand48() ))
+ float r2=$(( rand48() ))
+ float r3=$(( rand48() ))
+ # Yes, this is a floating point equality test like they tell
+ # you not to do. As the pseudrandom sequence is deterministic,
+ # this is the right thing to do in this case.
+ if (( r1 == r2 )); then
+ print "Seed not updated correctly the first time"
+ else
+ print "First two random numbers differ, OK"
+ fi
+ if (( r2 == r3 )); then
+ print "Seed not updated correctly the second time"
+ else
+ print "Second two random numbers differ, OK"
+ fi
+0:rand48 with default initialisation
+F:This test fails if your math library doesn't have erand48().
+>First two random numbers differ, OK
+>Second two random numbers differ, OK
+
+ seed=f45677a6cbe4
+ float r1=$(( rand48(seed) ))
+ float r2=$(( rand48(seed) ))
+ seed2=$seed
+ float r3=$(( rand48(seed) ))
+ float r4=$(( rand48(seed2) ))
+ # Yes, this is a floating point equality test like they tell
+ # you not to do. As the pseudrandom sequence is deterministic,
+ # this is the right thing to do in this case.
+ if (( r1 == r2 )); then
+ print "Seed not updated correctly the first time"
+ else
+ print "First two random numbers differ, OK"
+ fi
+ if (( r2 == r3 )); then
+ print "Seed not updated correctly the second time"
+ else
+ print "Second two random numbers differ, OK"
+ fi
+ if (( r3 == r4 )); then
+ print "Identical seeds generate identical numbers, OK"
+ else
+ print "Indeterminate result from identical seeds"
+ fi
+0:rand48 with pre-generated seed
+F:This test fails if your math library doesn't have erand48().
+>First two random numbers differ, OK
+>Second two random numbers differ, OK
+>Identical seeds generate identical numbers, OK
+
+ float -F 5 pitest
+ (( pitest = 4.0 * atan(1) ))
+ # This is a string test of the output to 5 digits.
+ if [[ $pi = $pitest ]]; then
+ print "OK, atan on an integer seemed to work"
+ else
+ print "BAD: got $pitest instead of $pi"
+ fi
+0:Conversion of arguments from integer
+>OK, atan on an integer seemed to work
+
+ float -F 5 result
+ typeset str
+ for str in 0 0.0 1 1.5 -1 -1.5; do
+ (( result = abs($str) ))
+ print $result
+ done
+0:Use of abs on various numbers
+>0.00000
+>0.00000
+>1.00000
+>1.50000
+>1.00000
+>1.50000
+
+ print $(( sqrt(-1) ))
+1:Non-negative argument checking for square roots.
+?(eval):1: math: argument to sqrt out of range
+
+# Simple test that the pseudorandom number generators are producing
+# something that could conceivably be pseudorandom numbers in a
+# linear range. Not a detailed quantitative verification.
+ integer N=10000 isource ok=1
+ float -F f sum sumsq max max2 av sd
+ typeset -a randoms
+ randoms=('f = RANDOM' 'f = rand48()')
+ for isource in 1 2; do
+ (( sum = sumsq = max = 0 ))
+ repeat $N; do
+ let $randoms[$isource]
+ (( f > max )) && (( max = f ))
+ (( sum += f, sumsq += f * f ))
+ done
+ (( av = sum / N ))
+ (( sd = sqrt((sumsq - N * av * av) / (N-1)) ))
+ (( max2 = 0.5 * max ))
+ if (( av > max2 * 1.1 )) || (( av < max2 * 0.9 )); then
+ print "WARNING: average of random numbers is suspicious.
+ Was testing: $randoms[$isource]"
+ (( ok = 0 ))
+ fi
+ if (( sd < max / 4 )); then
+ print "WARNING: distribution of random numbers is suspicious.
+ Was testing: $randoms[$isource]"
+ (( ok = 0 ))
+ fi
+ done
+ (( ok ))
+0:Test random number generator distributions are not grossly broken
+
+ float -F 5 g l
+ (( g = gamma(2), l = lgamma(2) ))
+ print $g, $l
+0:Test Gamma function gamma and lgamma
+>1.00000, 0.00000
diff --git a/dotfiles/system/.zsh/modules/Test/V04features.ztst b/dotfiles/system/.zsh/modules/Test/V04features.ztst
new file mode 100644
index 0000000..6939053
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/V04features.ztst
@@ -0,0 +1,172 @@
+%prep
+
+# Do some tests on handling of features.
+# This also does some slightly more sophisticated loading and
+# unloading tests than we did in V01zmodload.ztst.
+#
+# We use zsh/datetime because it has a list of features that is short
+# but contains two types.
+
+ # Subshell for prep test so we can load individual features later
+ if ! (zmodload zsh/datetime 2>/dev/null); then
+ ZTST_unimplemented="can't load the zsh/datetime module for testing"
+ fi
+
+%test
+ zmodload -F zsh/datetime
+ zmodload -lF zsh/datetime
+0:Loading modules with no features
+>-b:strftime
+>-p:EPOCHSECONDS
+>-p:EPOCHREALTIME
+>-p:epochtime
+
+ zmodload -F zsh/datetime b:strftime
+ zmodload -lF zsh/datetime
+0:Enabling features
+>+b:strftime
+>-p:EPOCHSECONDS
+>-p:EPOCHREALTIME
+>-p:epochtime
+
+ zmodload -F zsh/datetime +p:EPOCHSECONDS -b:strftime
+ zmodload -lF zsh/datetime
+0:Disabling features
+>-b:strftime
+>+p:EPOCHSECONDS
+>-p:EPOCHREALTIME
+>-p:epochtime
+
+ zmodload -Fe zsh/datetime p:EPOCHSECONDS b:strftime
+0:Testing existing features
+
+ zmodload -Fe zsh/datetime +p:EPOCHSECONDS
+0:Testing features are in given state (on feature is on)
+
+ zmodload -Fe zsh/datetime -p:EPOCHSECONDS
+1:Testing features are in given state (on feature is not off
+
+ zmodload -Fe zsh/datetime +p:strftime
+1:Testing features are in given state (off feature is not on)
+
+ zmodload -Fe zsh/datetime -b:strftime
+0:Testing features are in given state (off feature is off
+
+ zmodload -Fe zsh/datetime p:EPOCHSECONDS b:strftime b:mktimebetter
+1:Testing non-existent features
+
+ zmodload -FlP dtf zsh/datetime
+ for feature in b:strftime p:EPOCHSECONDS; do
+ if [[ ${${dtf[(R)?$feature]}[1]} = + ]]; then
+ print $feature is enabled
+ else
+ print $feature is disabled
+ fi
+ done
+0:Testing features via array parameter
+>b:strftime is disabled
+>p:EPOCHSECONDS is enabled
+
+ fn() {
+ local EPOCHSECONDS=scruts
+ print $EPOCHSECONDS
+ print ${(t)EPOCHSECONDS}
+ }
+ fn
+ if [[ $EPOCHSECONDS = <-> ]]; then
+ print EPOCHSECONDS is a number
+ else
+ print EPOCHSECONDS is some random piece of junk
+ fi
+ print ${(t)EPOCHSECONDS}
+0:Module special parameter is hidden by a local parameter
+>scruts
+>scalar-local
+>EPOCHSECONDS is a number
+>integer-readonly-hide-hideval-special
+
+ typeset +h EPOCHSECONDS
+ fn() {
+ local EPOCHSECONDS=scruts
+ print Didn\'t get here >&2
+ }
+ fn
+1:Unhidden readonly special can't be assigned to when made local
+?fn:1: read-only variable: EPOCHSECONDS
+
+ zmodload -u zsh/datetime
+0:Module unloaded
+
+ zmodload -e zsh/datetime
+1:Module doesn't exist when unloaded
+
+ zmodload -Fe zsh/datetime p:EPOCHSECONDS
+1:Module doesn't have features when unloaded
+
+ fn() {
+ local EPOCHSECONDS=scrimf
+ zmodload zsh/datetime
+ }
+ fn
+2:Failed to add parameter if local parameter present
+?fn:2: Can't add module parameter `EPOCHSECONDS': local parameter exists
+?fn:zsh/datetime:2: error when adding parameter `EPOCHSECONDS'
+
+ zmodload -lF zsh/datetime
+0:Feature state with loading after error enabling
+>+b:strftime
+>-p:EPOCHSECONDS
+>+p:EPOCHREALTIME
+>+p:epochtime
+
+ zmodload -F zsh/datetime p:EPOCHSECONDS
+ zmodload -Fe zsh/datetime +p:EPOCHSECONDS
+0:Successfully added feature parameter that previously failed
+
+ fn() {
+ local EPOCHSECONDS=scrooble
+ zmodload -u zsh/datetime
+ print $EPOCHSECONDS
+ }
+ fn
+ print ${+EPOCHSECONDS}
+0:Successfully unloaded a module despite a parameter being hidden
+>scrooble
+>0
+
+ EPOCHSECONDS=(any old parameter)
+ print -l $EPOCHSECONDS
+0:Using parameter as normal after unloading is OK
+>any
+>old
+>parameter
+
+ print strftime is ${builtins[strftime]:-undefined}
+ zmodload -F zsh/datetime b:strftime
+ print strftime is ${builtins[strftime]:-undefined}
+ zmodload -F zsh/datetime -b:strftime
+ print strftime is ${builtins[strftime]:-undefined}
+0:Enabling and disabling of builtins as features
+>strftime is undefined
+>strftime is defined
+>strftime is undefined
+
+ zmodload -u zsh/datetime
+ zmodload zsh/datetime
+2:Loading won't override global parameter
+?(eval):2: Can't add module parameter `EPOCHSECONDS': parameter already exists
+?(eval):zsh/datetime:2: error when adding parameter `EPOCHSECONDS'
+
+ unset EPOCHSECONDS
+ zmodload -F zsh/datetime p:EPOCHSECONDS
+ zmodload -Fe zsh/datetime +p:EPOCHSECONDS
+0:unsetting a global parameter allows feature parameter to be enabled
+
+ zmodload -F zsh/datetime -b:strftime -p:EPOCHSECONDS
+ zmodload zsh/datetime
+ zmodload -lF zsh/datetime
+0:zmodload with no -F enables all features
+>+b:strftime
+>+p:EPOCHSECONDS
+>+p:EPOCHREALTIME
+>+p:epochtime
diff --git a/dotfiles/system/.zsh/modules/Test/V05styles.ztst b/dotfiles/system/.zsh/modules/Test/V05styles.ztst
new file mode 100644
index 0000000..ca95b63
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/V05styles.ztst
@@ -0,0 +1,143 @@
+%prep
+
+# Test the use of styles, if the zsh/zutil module is available.
+
+ if ! zmodload zsh/zutil 2>/dev/null; then
+ ZTST_unimplemented="can't load the zsh/zutil module for testing"
+ fi
+
+%test
+ zstyle :random:stuff any-old-style with any old value
+ zstyle :randomly:chosen some-other-style I can go on and on
+ zstyle -d
+ zstyle
+0:zstyle -d restores a pristine state
+
+# patterns should be ordered by weight, so add in reverse order to check
+ zstyle ':ztst:context*' scalar-style other-scalar-value
+ zstyle ':ztst:context:*' scalar-style second-scalar-value
+ zstyle ':ztst:context:sub1' scalar-style scalar-value
+ zstyle ':ztst:context:sub1' array-style array value elements 'with spaces'
+ zstyle ':ztst:context*' boolean-style false
+ zstyle ':ztst:context:sub1' boolean-style true
+0:defining styles
+
+# styles are now sorted, but patterns are in order of definition
+ zstyle
+0:listing styles in default format
+>array-style
+> :ztst:context:sub1 array value elements 'with spaces'
+>boolean-style
+> :ztst:context:sub1 true
+> :ztst:context* false
+>scalar-style
+> :ztst:context:sub1 scalar-value
+> :ztst:context:* second-scalar-value
+> :ztst:context* other-scalar-value
+
+ zstyle -L
+0:listing styles in zstyle format
+>zstyle :ztst:context:sub1 array-style array value elements 'with spaces'
+>zstyle :ztst:context:sub1 boolean-style true
+>zstyle ':ztst:context*' boolean-style false
+>zstyle :ztst:context:sub1 scalar-style scalar-value
+>zstyle ':ztst:context:*' scalar-style second-scalar-value
+>zstyle ':ztst:context*' scalar-style other-scalar-value
+
+ zstyle -b :ztst:context:sub1 boolean-style bool; print $bool
+ zstyle -t :ztst:context:sub1 boolean-style
+0:boolean test -b/-t + true
+>yes
+
+ zstyle -b :ztst:context:sub2 boolean-style bool; print $bool
+ zstyle -t :ztst:context:sub2 boolean-style
+1:boolean test -b/-t + false
+>no
+
+ zstyle -b :ztst:context:sub1 boolean-unset-style bool; print $bool
+ zstyle -t :ztst:context:sub1 boolean-unset-style
+2:boolean test -b/-t + unset
+>no
+
+ zstyle -T :ztst:context:sub1 boolean-style
+0:boolean test -T + true
+
+ zstyle -T :ztst:context:sub2 boolean-style
+1:boolean test -T + false
+
+ zstyle -T :ztst:context:sub1 boolean-unset-style
+0:boolean test -T + unset
+
+ zstyle -s :ztst:context:sub1 scalar-style scalar && print $scalar
+ zstyle -s :ztst:context:sub2 scalar-style scalar && print $scalar
+ zstyle -s :ztst:contextual-psychedelia scalar-style scalar && print $scalar
+ zstyle -s :ztst:contemplative scalar-style scalar || print no match
+0:pattern matching rules
+>scalar-value
+>second-scalar-value
+>other-scalar-value
+>no match
+
+ zstyle -s :ztst:context:sub1 array-style scalar + && print $scalar
+0:scalar with separator
+>array+value+elements+with spaces
+
+ zstyle -e :ztst:\* eval-style 'reply=($something)'
+ something=(one two three)
+ zstyle -a :ztst:eval eval-style array && print -l $array
+0:zstyle -e evaluations
+>one
+>two
+>three
+
+# pattern ordering on output is not specified, so although in the
+# current implementation it's deterministic we shouldn't
+# assume it's always the same. Thus we sort the array.
+# (It might be a nice touch to order patterns by weight, which is
+# the way they are stored for each separate style.)
+ zstyle -g array && print -l ${(o)array}
+0:retrieving patterns
+>:ztst:*
+>:ztst:context*
+>:ztst:context:*
+>:ztst:context:sub1
+
+ zstyle -m :ztst:context:sub1 array-style 'w* *s'
+0:positive pattern match
+
+ zstyle -m :ztst:context:sub1 array-style 'v'
+1:negative pattern match
+
+ zstyle -g array ':ztst:context*' && print -l $array
+0:retrieving styles by pattern
+>boolean-style
+>scalar-style
+
+ zstyle -g array ':ztst:context:sub1' array-style && print -l $array
+0:retrieving values by pattern and name
+>array
+>value
+>elements
+>with spaces
+
+ zstyle -d :ztst:context:sub1
+ zstyle
+0:deleting styles by pattern only
+>boolean-style
+> :ztst:context* false
+>eval-style
+>(eval) :ztst:* 'reply=($something)'
+>scalar-style
+> :ztst:context:* second-scalar-value
+> :ztst:context* other-scalar-value
+
+ zstyle -d :ztst:context\* scalar-style
+ zstyle
+0:deleting styles by pattern and style name
+>boolean-style
+> :ztst:context* false
+>eval-style
+>(eval) :ztst:* 'reply=($something)'
+>scalar-style
+> :ztst:context:* second-scalar-value
+
diff --git a/dotfiles/system/.zsh/modules/Test/V07pcre.ztst b/dotfiles/system/.zsh/modules/Test/V07pcre.ztst
new file mode 100644
index 0000000..ad17707
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/V07pcre.ztst
@@ -0,0 +1,139 @@
+%prep
+
+ if ! zmodload -F zsh/pcre C:pcre-match 2>/dev/null
+ then
+ ZTST_unimplemented="the zsh/pcre module is not available"
+ return 0
+ fi
+# Load the rest of the builtins
+ zmodload zsh/pcre
+ setopt rematch_pcre
+# Find a UTF-8 locale.
+ setopt multibyte
+# Don't let LC_* override our choice of locale.
+ unset -m LC_\*
+ mb_ok=
+ langs=(en_{US,GB}.{UTF-,utf}8 en.UTF-8
+ $(locale -a 2>/dev/null | egrep 'utf8|UTF-8'))
+ for LANG in $langs; do
+ if [[ é = ? ]]; then
+ mb_ok=1
+ break;
+ fi
+ done
+ if [[ -z $mb_ok ]]; then
+ ZTST_unimplemented="no UTF-8 locale or multibyte mode is not implemented"
+ else
+ print -u $ZTST_fd Testing PCRE multibyte with locale $LANG
+ mkdir multibyte.tmp && cd multibyte.tmp
+ fi
+
+%test
+
+ [[ 'foo→bar' =~ .([^[:ascii:]]). ]]
+ print $MATCH
+ print $match[1]
+0:Basic non-ASCII regexp matching
+>o→b
+>→
+
+ unset match mend
+ s=$'\u00a0'
+ [[ $s =~ '^.$' ]] && print OK
+ [[ A${s}B =~ .(.). && $match[1] == $s ]] && print OK
+ [[ A${s}${s}B =~ A([^[:ascii:]]*)B && $mend[1] == 3 ]] && print OK
+ unset s
+0:Raw IMETA characters in input string
+>OK
+>OK
+>OK
+
+ [[ foo =~ f.+ ]] ; print $?
+ [[ foo =~ x.+ ]] ; print $?
+ [[ ! foo =~ f.+ ]] ; print $?
+ [[ ! foo =~ x.+ ]] ; print $?
+ [[ foo =~ f.+ && bar =~ b.+ ]] ; print $?
+ [[ foo =~ x.+ && bar =~ b.+ ]] ; print $?
+ [[ foo =~ f.+ && bar =~ x.+ ]] ; print $?
+ [[ ! foo =~ f.+ && bar =~ b.+ ]] ; print $?
+ [[ foo =~ f.+ && ! bar =~ b.+ ]] ; print $?
+ [[ ! ( foo =~ f.+ && bar =~ b.+ ) ]] ; print $?
+ [[ ! foo =~ x.+ && bar =~ b.+ ]] ; print $?
+ [[ foo =~ x.+ && ! bar =~ b.+ ]] ; print $?
+ [[ ! ( foo =~ x.+ && bar =~ b.+ ) ]] ; print $?
+0:Regex result inversion detection
+>0
+>1
+>1
+>0
+>0
+>1
+>1
+>1
+>1
+>1
+>0
+>1
+>0
+
+# Note that PCRE_ANCHORED only means anchored at the start
+# Also note that we don't unset MATCH/match on failed match (and it's an
+# open issue as to whether or not we should)
+ pcre_compile '.(→.)'
+ pcre_match foo→bar
+ print $? $MATCH $match ; unset MATCH match
+ pcre_match foo.bar
+ print $? $MATCH $match ; unset MATCH match
+ pcre_match foo†bar
+ print $? $MATCH $match ; unset MATCH match
+ pcre_match foo→†ar
+ print $? $MATCH $match ; unset MATCH match
+ pcre_study
+ pcre_match foo→bar
+ print $? $MATCH $match ; unset MATCH match
+ pcre_compile -a '.(→.)'
+ pcre_match foo→bar
+ print $? $MATCH $match ; unset MATCH match
+ pcre_match o→bar
+ print $? $MATCH $match ; unset MATCH match
+ pcre_match o→b
+ print $? $MATCH $match ; unset MATCH match
+ pcre_compile 'x.(→.)'
+ pcre_match xo→t
+ print $? $MATCH $match ; unset MATCH match
+ pcre_match Xo→t
+ print $? $MATCH $match ; unset MATCH match
+ pcre_compile -i 'x.(→.)'
+ pcre_match xo→t
+ print $? $MATCH $match ; unset MATCH match
+ pcre_match Xo→t
+ print $? $MATCH $match ; unset MATCH match
+0:pcre_compile interface testing: basic, anchored & case-insensitive
+>0 o→b →b
+>1
+>1
+>0 o→† →†
+>0 o→b →b
+>1
+>0 o→b →b
+>0 o→b →b
+>0 xo→t →t
+>1
+>0 xo→t →t
+>0 Xo→t →t
+
+ string="The following zip codes: 78884 90210 99513"
+ pcre_compile -m "\d{5}"
+ pcre_match -b -- $string && print "$MATCH; ZPCRE_OP: $ZPCRE_OP"
+ pcre_match -b -n $ZPCRE_OP[(w)2] -- $string || print failed
+ print "$MATCH; ZPCRE_OP: $ZPCRE_OP"
+0:pcre_match -b and pcre_match -n
+>78884; ZPCRE_OP: 25 30
+>90210; ZPCRE_OP: 31 36
+
+# Subshell because crash on failure
+ ( setopt re_match_pcre
+ [[ test.txt =~ '^(.*_)?(test)' ]]
+ echo $match[2] )
+0:regression for segmentation fault, workers/38307
+>test
diff --git a/dotfiles/system/.zsh/modules/Test/V08zpty.ztst b/dotfiles/system/.zsh/modules/Test/V08zpty.ztst
new file mode 100644
index 0000000..b0cbfa0
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/V08zpty.ztst
@@ -0,0 +1,29 @@
+# zpty is required by tests of interactive modes of the shell itself.
+# This tests some extra things.
+
+%prep
+
+ 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
+
+ zpty cat cat
+ zpty -w cat a line of text
+ var=
+ zpty -r cat var && print -r -- ${var%%$'\r\n'}
+ zpty -d cat
+0:zpty with a process that does not set up the terminal: internal write
+>a line of text
+
+ zpty cat cat
+ print a line of text | zpty -w cat
+ var=
+ zpty -r cat var && print -r -- ${var%%$'\r\n'}
+ zpty -d cat
+0:zpty with a process that does not set up the terminal: write via stdin
+>a line of text
diff --git a/dotfiles/system/.zsh/modules/Test/V09datetime.ztst b/dotfiles/system/.zsh/modules/Test/V09datetime.ztst
new file mode 100644
index 0000000..7905155
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/V09datetime.ztst
@@ -0,0 +1,74 @@
+%prep
+
+ if zmodload zsh/datetime 2>/dev/null; then
+ setopt multibyte
+ unset LC_ALL
+ LC_TIME=C
+ TZ=UTC+0
+ # It's not clear this skip_extensions is correct, but the
+ # format in question is causing problems on Solaris.
+ # We'll revist this after the release.
+ [[ "$(strftime %^_10B 0)" = " JANUARY" ]] || skip_extensions=1
+ [[ "$(LC_TIME=ja_JP.UTF-8 strftime %OS 1)" = 一 ]] || skip_japanese=1
+ else
+ ZTST_unimplemented="can't load the zsh/datetime module for testing"
+ fi
+
+%test
+
+ strftime %y 0
+ strftime %Y 1000000000
+ strftime %x 1200000000
+ strftime %X 1200000001
+0:basic format specifiers
+>70
+>2001
+>01/10/08
+>21:20:01
+
+ strftime %-m_%f_%K_%L 1181100000
+ strftime %6. 0
+0:zsh extensions
+>6_6_3_3
+>000000
+
+ if [[ $skip_extensions = 1 ]]; then
+ ZTST_skip="strftime extensions not supported"
+ elif [[ $skip_japanese = 1 ]]; then
+ ZTST_skip="Japanese UTF-8 locale not supported"
+ else
+ (
+ LC_TIME=ja_JP.UTF-8
+ strftime %Ey 1000000000
+ strftime %Oy 1000000000
+ strftime %Ex 1000000000
+ strftime %OS 1000000000
+ strftime %03Ey 650000000
+ )
+ fi
+0:alternate format extensions
+>13
+>一
+>平成13年09月09日
+>四十
+>002
+
+ if [[ $skip_extensions = 1 ]]; then
+ ZTST_skip="strftime extensions not supported"
+ else
+ (
+ strftime '%#A' 0
+ strftime '%^_10B' 0
+ strftime %03Ey 650000000
+ strftime %-Oe 0
+ )
+ fi
+0:various extensions
+>THURSDAY
+> JANUARY
+>090
+>1
+
+ print -r -- ${(V)"$(strftime $'%Y\0%m\0%d' 100000000)"}
+0:Embedded nulls
+>1973^@03^@03
diff --git a/dotfiles/system/.zsh/modules/Test/V10private.ztst b/dotfiles/system/.zsh/modules/Test/V10private.ztst
new file mode 100644
index 0000000..78ecd48
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/V10private.ztst
@@ -0,0 +1,304 @@
+# Tests for the zsh/param/private module
+
+%prep
+
+ if ! zmodload zsh/param/private 2>/dev/null; then
+ ZTST_unimplemented="can't load the zsh/param/private module for testing"
+ else
+ # Do not use .tmp here, ztst.zsh will remove it too soon (see %cleanup)
+ mkdir private.TMP
+ sed -e 's,# test_zsh_param_private,zmodload zsh/param/private,' < $ZTST_srcdir/B02typeset.ztst > private.TMP/B02
+ fi
+
+%test
+
+ (zmodload -u zsh/param/private && zmodload zsh/param/private)
+0:unload and reload the module without crashing
+
+ typeset scalar_test=toplevel
+ () {
+ print $scalar_test
+ private scalar_test
+ print $+scalar_test
+ unset scalar_test
+ print $+scalar_test
+ }
+ print $scalar_test
+0:basic scope hiding
+>toplevel
+>1
+>0
+>toplevel
+
+ typeset scalar_test=toplevel
+ print $scalar_test
+ () {
+ private scalar_test=function
+ print $scalar_test
+ }
+ print $scalar_test
+0:enter and exit a scope
+>toplevel
+>function
+>toplevel
+
+ print $+unset_test
+ () {
+ private unset_test
+ print $+unset_test
+ unset_test=setme
+ print $unset_test
+ }
+ print $+unset_test
+0:variable defined only in scope
+>0
+>1
+>setme
+>0
+
+ # Depends on zsh-5.0.9 typeset keyword
+ typeset -a array_test=(top level)
+ () {
+ local -Pa array_test=(in function)
+ () {
+ private array_test
+ print $+array_test
+ }
+ print $array_test
+ }
+ print $array_test
+0:nested scope with different type, correctly restored
+>1
+>in function
+>top level
+
+ typeset -a array_test=(top level)
+ () {
+ private array_test
+ array_test=(in function)
+ }
+1:type of private may not be changed by assignment
+?(anon):2: array_test: attempt to assign array value to non-array
+
+ typeset -A hash_test=(top level)
+ () {
+ setopt localoptions noglob
+ private hash_test[top]
+ }
+1:associative array fields may not be private
+?(anon):private:2: hash_test[top]: can't create local array elements
+
+ () {
+ private path
+ }
+1:tied params may not be private, part 1
+?(anon):private:1: can't change scope of existing param: path
+
+ () {
+ private PATH
+ }
+1:tied params may not be private, part 2
+?(anon):private:1: can't change scope of existing param: PATH
+
+ () {
+ private -h path
+ print X$path
+ }
+0:privates may hide tied paramters
+>X
+
+ # Deliberate type mismatch here
+ typeset -a hash_test=(top level)
+ typeset -p hash_test
+ inner () {
+ private -p hash_test
+ print ${(t)hash_test} ${(kv)hash_test}
+ }
+ outer () {
+ local -PA hash_test=(in function)
+ typeset -p 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 )
+>typeset -g -a hash_test=( top level )
+>array-local top level
+>top level
+F:note "typeset" rather than "private" in output from outer
+
+ () {
+ private -a array_test
+ local array_test=scalar
+ }
+1:private cannot be re-declared as local
+?(anon):local:2: array_test: inconsistent type for assignment
+
+ () {
+ local hash_test=scalar
+ private -A hash_test
+ }
+1:local cannot be re-declared as private
+?(anon):private:2: can't change scope of existing param: hash_test
+
+ inner () {
+ print $+scalar_test
+ $ZTST_testdir/../Src/zsh -fc 'print X $scalar_test'
+ }
+ () {
+ private -x scalar_test=whaat
+ $ZTST_testdir/../Src/zsh -fc 'print X $scalar_test'
+ inner
+ print Y $scalar_test
+ }
+0:exported private behaves like a local, part 1
+>X whaat
+>0
+>X whaat
+>Y whaat
+
+ inner () {
+ typeset -p array_test
+ $ZTST_testdir/../Src/zsh -fc 'print X $array_test'
+ }
+ () {
+ local -Pax array_test=(whaat)
+ print Y $array_test
+ $ZTST_testdir/../Src/zsh -fc 'print X $array_test'
+ inner
+ }
+0:exported private behaves like a local, part 2 (arrays do not export)
+?inner:typeset:1: no such variable: array_test
+>Y whaat
+>X
+>X
+
+ inner () {
+ print $+scalar_test
+ $ZTST_testdir/../Src/zsh -fc 'print X $scalar_test'
+ }
+ () {
+ private scalar_test=whaat
+ export scalar_test
+ $ZTST_testdir/../Src/zsh -fc 'print X $scalar_test'
+ inner
+ () {
+ print $+scalar_test
+ $ZTST_testdir/../Src/zsh -fc 'print X $scalar_test'
+ }
+ print Y $scalar_test
+ }
+0:exported private behaves like a local, part 3 (export does not change scope)
+>X whaat
+>0
+>X whaat
+>0
+>X whaat
+>Y whaat
+
+ typeset -A hash_test=(top level)
+ () {
+ local -PA hash_test=(in function)
+ () {
+ print X ${(kv)hash_test}
+ }
+ print Y ${(kv)hash_test}
+ }
+ print ${(kv)hash_test}
+0:privates are not visible in anonymous functions, part 1
+>X top level
+>Y in function
+>top level
+
+ typeset -A hash_test=(top level)
+ () {
+ local -PA hash_test=(in function)
+ () {
+ print X ${(kv)hash_test}
+ hash_test[in]=deeper
+ }
+ print Y ${(kv)hash_test}
+ }
+ print ${(okv)hash_test}
+0:privates are not visible in anonymous functions, part 2
+>X top level
+>Y in function
+>deeper in level top
+
+ typeset -A hash_test=(top level)
+ () {
+ local -Pa array_test=(in function)
+ local -PA hash_test=($array_test)
+ () {
+ print X ${(kv)hash_test}
+ hash_test=(even deeper)
+ {
+ array_test+=(${(kv)hash_test})
+ } always {
+ print ${array_test-array_test not set} ${(t)array_test}
+ }
+ }
+ print Y ${(kv)hash_test} Z $array_test
+ }
+ print ${(kv)hash_test} ${(t)array_test}
+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
+F:future revision will create a global with this assignment
+
+ typeset -a array_test
+ typeset -A hash_test=(top level)
+ () {
+ local -Pa array_test=(in function)
+ local -PA hash_test=($array_test)
+ () {
+ print X ${(kv)hash_test}
+ hash_test=(even deeper)
+ array_test+=(${(kv)hash_test})
+ }
+ print Y ${(kv)hash_test} Z $array_test
+ }
+ print ${(kv)hash_test} $array_test
+0:privates are not visible in anonymous functions, part 4
+>X top level
+>Y in function Z in function
+>even deeper even deeper
+
+ typeset -A hash_test=(top level)
+ () {
+ local -PA hash_test=(in function)
+ () {
+ print X ${(kv)hash_test}
+ unset hash_test
+ }
+ print Y ${(kv)hash_test}
+ }
+ print ${(t)hash_test} ${(kv)hash_test}
+0:privates are not visible in anonymous functions, part 5
+>X top level
+>Y in function
+>
+
+ # Subshell because otherwise this silently dumps core when broken
+ ( () { private SECONDS } )
+1:special parameters cannot be made private
+?(anon):private: can't change scope of existing param: SECONDS
+
+ () { private -h SECONDS }
+0:private parameter may hide a special parameter
+
+ if (( UID )); then
+ ZTST_verbose=0 $ZTST_exe +Z -f $ZTST_srcdir/ztst.zsh private.TMP/B02
+ else
+ ZTST_skip="cannot re-run typeset tests when tests run as superuser"
+ fi
+0:typeset still works with zsh/param/private module loaded
+*>*
+*>*
+
+%clean
+
+ rm -r private.TMP
diff --git a/dotfiles/system/.zsh/modules/Test/W01history.ztst b/dotfiles/system/.zsh/modules/Test/W01history.ztst
new file mode 100644
index 0000000..6ef9b11
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/W01history.ztst
@@ -0,0 +1,60 @@
+# Tests for BANG_HIST replacements
+
+%prep
+
+ if [[ -t 0 ]]; then print -u $ZTST_fd History tests write to /dev/tty; fi
+
+%test
+
+ $ZTST_testdir/../Src/zsh -fis <<<'
+ print one two three four five six seven eight nine ten
+ print !:$ !:10 !:9 !:1 !:0
+ print one two three four five six seven eight nine ten
+ print !:0-$ !:1-2
+ ' 2>/dev/null
+0:History word references
+>one two three four five six seven eight nine ten
+>ten ten nine one print
+>one two three four five six seven eight nine ten
+>print one two three four five six seven eight nine ten one two
+
+ $ZTST_testdir/../Src/zsh -fis <<<'
+ print line one of an arbitrary series
+ print issue two for some mystery sequence
+ print !-1:5-$
+ print !1:2
+ print !2:2
+ print !-3:1-$
+ ' 2>/dev/null
+0:History line numbering
+>line one of an arbitrary series
+>issue two for some mystery sequence
+>mystery sequence
+>one
+>two
+>mystery sequence
+
+ $ZTST_testdir/../Src/zsh -fis <<<'
+ print All metaphor, Malachi, stilts and all
+ print !1:2:s/,/\\\\?/ !1:2:s/m/shm/:s/,/\!/
+ print !1:2:&
+ print -l !1:2-3:gs/a/o/
+ ' 2>/dev/null
+0:History substitution
+>All metaphor, Malachi, stilts and all
+>metaphor? shmetaphor!
+>metaphor!
+>metophor,
+>Molochi,
+
+ $ZTST_testdir/../Src/zsh -fis <<<'
+ echo foo bar
+ echo $(!!) again
+ echo more $( !! )' 2>/dev/null
+0:Regression test for history references in command substitution
+>foo bar
+>foo bar again
+>more foo bar again
+*?*
+F:Check that a history bug introduced by workers/34160 is working again.
+# Discarded line of error output consumes prompts printed by "zsh -i".
diff --git a/dotfiles/system/.zsh/modules/Test/comptest b/dotfiles/system/.zsh/modules/Test/comptest
new file mode 100644
index 0000000..166d0b4
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/comptest
@@ -0,0 +1,177 @@
+comptestinit () {
+ setopt extendedglob
+ [[ -d $ZTST_testdir/Modules/zsh ]] && module_path=( $ZTST_testdir/Modules )
+ fpath=( $ZTST_srcdir/../Functions/*~*/CVS(/)
+ $ZTST_srcdir/../Completion
+ $ZTST_srcdir/../Completion/*/*~*/CVS(/) )
+
+ zmodload zsh/zpty || return $?
+
+ comptest_zsh=${ZSH:-zsh}
+ comptest_keymap=e
+
+ while getopts vz: opt; do
+ case $opt in
+ z) comptest_zsh="$OPTARG";;
+ v) comptest_keymap="v";;
+ esac
+ done
+ (( OPTIND > 1 )) && shift $(( OPTIND - 1 ))
+
+ export PS1="<PROMPT>"
+ zpty zsh "$comptest_zsh -f +Z"
+
+ zpty -r zsh log1 "*<PROMPT>*" || {
+ print "first prompt hasn't appeared."
+ return 1
+ }
+
+ comptesteval \
+"export LC_ALL=${ZSH_TEST_LANG:-C}" \
+"emulate -R zsh" \
+"export ZDOTDIR=$ZTST_testdir" \
+"module_path=( $module_path )" \
+"fpath=( $fpath )" \
+"bindkey -$comptest_keymap" \
+'LISTMAX=10000000
+stty 38400 columns 80 rows 24 tabs -icanon -iexten
+TERM=vt100
+KEYTIMEOUT=1
+setopt zle
+autoload -U compinit
+compinit -u
+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>
+"
+zstyle ":completion:*:descriptions" format "<DESCRIPTION>%d</DESCRIPTION>
+"
+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
+ print -lr - "<LBUFFER>$LBUFFER</LBUFFER>" "<RBUFFER>$RBUFFER</RBUFFER>"
+ zle clear-screen
+ zle -R
+}
+list-choices-with-report () {
+ print -lr "<WIDGET><list-choices>"
+ zle list-choices
+ zle clear-screen
+ zle -R
+}
+comp-finish () {
+ print "<WIDGET><finish>"
+ zle kill-whole-line
+ zle clear-screen
+ zle -R
+}
+zle-finish () {
+ local buffer="$BUFFER" cursor="$CURSOR" mark="$MARK"
+ (( region_active)) || unset mark
+ BUFFER=""
+ zle -I
+ zle clear-screen
+ zle redisplay
+ print -lr "<WIDGET><finish>" "BUFFER: $buffer" "CURSOR: $cursor"
+ (( $+mark )) && print -lr "MARK: $mark"
+ zle accept-line
+}
+zle -N expand-or-complete-with-report
+zle -N list-choices-with-report
+zle -N comp-finish
+zle -N zle-finish
+bindkey "^I" expand-or-complete-with-report
+bindkey "^D" list-choices-with-report
+bindkey "^Z" comp-finish
+bindkey "^X" zle-finish
+bindkey -a "^X" zle-finish
+'
+}
+
+zpty_flush() {
+ local junk
+ if zpty -r -t zsh junk \*; then
+ (( ZTST_verbose > 2 )) && print -n -u $ZTST_fd "$*: ${(V)junk}"
+ while zpty -r -t zsh junk \* ; do
+ (( ZTST_verbose > 2 )) && print -n -u $ZTST_fd "${(V)junk}"
+ done
+ (( ZTST_verbose > 2 )) && print -u $ZTST_fd ''
+ fi
+}
+
+zpty_run() {
+ zpty -w zsh "$*"
+ zpty -r -m zsh log "*<PROMPT>*" || {
+ print "prompt hasn't appeared."
+ return 1
+ }
+}
+
+comptesteval () {
+ local tmp=/tmp/comptest.$$
+
+ 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
+}
+
+comptest () {
+ input="$*"
+ zpty -n -w zsh "$input"$'\C-Z'
+ zpty -r -m zsh log "*<WIDGET><finish>*<PROMPT>*" || {
+ print "failed to invoke finish widget."
+ return 1
+ }
+
+ logs=(${(s:<WIDGET>:)log})
+ shift logs
+
+ for log in "$logs[@]"; do
+ if [[ "$log" = (#b)*$'<LBUFFER>'(*)$'</LBUFFER>\r\n<RBUFFER>'(*)$'</RBUFFER>'* ]]; then
+ print -lr "line: {$match[1]}{$match[2]}"
+ fi
+ while (( ${(N)log#*(#b)(<LC><(??)><RC>(*)<EC>|<DESCRIPTION>(*)</DESCRIPTION>|<MESSAGE>(*)</MESSAGE>|<COMPADD>(*)</COMPADD>|<INSERT_POSITIONS>(*)</INSERT_POSITIONS>)} )); do
+ log="${log[$mend[1]+1,-1]}"
+ if (( 0 <= $mbegin[2] )); then
+ if [[ $match[2] != TC && $match[3] != \ # ]]; then
+ print -lr "$match[2]:{${match[3]%${(%):-%E}}}"
+ fi
+ elif (( 0 <= $mbegin[4] )); then
+ print -lr "DESCRIPTION:{$match[4]}"
+ elif (( 0 <= $mbegin[5] )); then
+ print -lr "MESSAGE:{$match[5]}"
+ elif (( 0 <= $mbegin[6] )); then
+ print -lr "COMPADD:{${${match[6]}//[$'\r\n']/}}"
+ elif (( 0 <= $mbegin[7] )); then
+ print -lr "INSERT_POSITIONS:{${${match[7]}//[$'\r\n']/}}"
+ fi
+ done
+ done
+}
+
+zletest () {
+ local first=0
+ for input; do
+ # zpty_flush Before zletest
+ # sleep for $KEYTIMEOUT
+ (( first++ )) && { sleep 2 & } | read -t 0.011 -u 0 -k 1
+ zpty -n -w zsh "$input"
+ done
+ zpty -n -w zsh $'\C-X'
+ zpty -r -m zsh log "*<WIDGET><finish>*<PROMPT>*" || {
+ print "failed to invoke finish widget."
+ return 1
+ }
+ # zpty_flush After zletest
+ print -lr "${(@)${(@ps:\r\n:)log##*<WIDGET><finish>}[2,-2]}"
+}
diff --git a/dotfiles/system/.zsh/modules/Test/runtests.zsh b/dotfiles/system/.zsh/modules/Test/runtests.zsh
new file mode 100644
index 0000000..562234d
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/runtests.zsh
@@ -0,0 +1,27 @@
+#!/bin/zsh -f
+
+emulate zsh
+
+# Run all specified tests, keeping count of which succeeded.
+# The reason for this extra layer above the test script is to
+# protect from catastrophic failure of an individual test.
+# We could probably do that with subshells instead.
+
+integer success failure skipped retval
+for file in "${(f)ZTST_testlist}"; do
+ $ZTST_exe +Z -f $ZTST_srcdir/ztst.zsh $file
+ retval=$?
+ if (( $retval == 2 )); then
+ (( skipped++ ))
+ elif (( $retval )); then
+ (( failure++ ))
+ else
+ (( success++ ))
+ fi
+done
+print "**************************************
+$success successful test script${${success:#1}:+s}, \
+$failure failure${${failure:#1}:+s}, \
+$skipped skipped
+**************************************"
+return $(( failure ? 1 : 0 ))
diff --git a/dotfiles/system/.zsh/modules/Test/ztst.zsh b/dotfiles/system/.zsh/modules/Test/ztst.zsh
new file mode 100755
index 0000000..f172ae1
--- /dev/null
+++ b/dotfiles/system/.zsh/modules/Test/ztst.zsh
@@ -0,0 +1,547 @@
+#!/bin/zsh -f
+# The line above is just for convenience. Normally tests will be run using
+# a specified version of zsh. With dynamic loading, any required libraries
+# must already have been installed in that case.
+#
+# Takes one argument: the name of the test file. Currently only one such
+# file will be processed each time ztst.zsh is run. This is slower, but
+# much safer in terms of preserving the correct status.
+# To avoid namespace pollution, all functions and parameters used
+# only by the script begin with ZTST_.
+#
+# Options (without arguments) may precede the test file argument; these
+# are interpreted as shell options to set. -x is probably the most useful.
+
+# Produce verbose messages if non-zero.
+# If 1, produce reports of tests executed; if 2, also report on progress.
+# 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.
+# Unfortunately, due to the crud which may be in /etc/zshenv this might
+# still not be good enough. Maybe we should trick it somehow.
+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_COLLATE ]] && LC_COLLATE=C
+[[ -n $LC_NUMERIC ]] && LC_NUMERIC=C
+[[ -n $LC_MESSAGES ]] && LC_MESSAGES=C
+[[ -n $LANG ]] && LANG=C
+
+# Don't propagate variables that are set by default in the shell.
+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.
+zmodload zsh/parameter
+
+# Note that both the following are regular arrays, since we only use them
+# in whole array assignments to/from $options.
+# Options set in test code (i.e. by default all standard options)
+ZTST_testopts=(${(kv)options})
+
+setopt extendedglob nonomatch
+while [[ $1 = [-+]* ]]; do
+ set $1
+ shift
+done
+# Options set in main script
+ZTST_mainopts=(${(kv)options})
+
+# We run in the current directory, so remember it.
+ZTST_testdir=$PWD
+ZTST_testname=$1
+
+integer ZTST_testfailed
+
+# This is POSIX nonsense. Because of the vague feeling someone, somewhere
+# may one day need to examine the arguments of "tail" using a standard
+# option parser, every Unix user in the world is expected to switch
+# to using "tail -n NUM" instead of "tail -NUM". Older versions of
+# tail don't support this.
+tail() {
+ emulate -L zsh
+
+ if [[ -z $TAIL_SUPPORTS_MINUS_N ]]; then
+ local test
+ test=$(echo "foo\nbar" | command tail -n 1 2>/dev/null)
+ if [[ $test = bar ]]; then
+ TAIL_SUPPORTS_MINUS_N=1
+ else
+ TAIL_SUPPORTS_MINUS_N=0
+ fi
+ fi
+
+ integer argi=${argv[(i)-<->]}
+
+ if [[ $argi -le $# && $TAIL_SUPPORTS_MINUS_N = 1 ]]; then
+ argv[$argi]=(-n ${argv[$argi][2,-1]})
+ fi
+
+ command tail "$argv[@]"
+}
+
+# The source directory is not necessarily the current directory,
+# but if $0 doesn't contain a `/' assume it is.
+if [[ $0 = */* ]]; then
+ ZTST_srcdir=${0%/*}
+else
+ ZTST_srcdir=$PWD
+fi
+[[ $ZTST_srcdir = /* ]] || ZTST_srcdir="$ZTST_testdir/$ZTST_srcdir"
+
+# Set the function autoload paths to correspond to this build of zsh.
+fpath=( $ZTST_srcdir/../Functions/*~*/CVS(/)
+ $ZTST_srcdir/../Completion
+ $ZTST_srcdir/../Completion/*/*~*/CVS(/) )
+
+: ${TMPPREFIX:=/tmp/zsh}
+ZTST_tmp=${TMPPREFIX}.ztst.$$
+if ! rm -f $ZTST_tmp || ! mkdir -p $ZTST_tmp || ! chmod go-w $ZTST_tmp; then
+ print "Can't create $ZTST_tmp for exclusive use." >&2
+ exit 1
+fi
+# Temporary files for redirection inside tests.
+ZTST_in=${ZTST_tmp}/ztst.in
+# hold the expected output
+ZTST_out=${ZTST_tmp}/ztst.out
+ZTST_err=${ZTST_tmp}/ztst.err
+# hold the actual output from the test
+ZTST_tout=${ZTST_tmp}/ztst.tout
+ZTST_terr=${ZTST_tmp}/ztst.terr
+
+ZTST_cleanup() {
+ cd $ZTST_testdir
+ rm -rf $ZTST_testdir/dummy.tmp $ZTST_testdir/*.tmp(N) ${ZTST_tmp}
+}
+
+# This cleanup always gets performed, even if we abort. Later,
+# we should try and arrange that any test-specific cleanup
+# always gets called as well.
+##trap 'print cleaning up...
+##ZTST_cleanup' INT QUIT TERM
+# Make sure it's clean now.
+rm -rf dummy.tmp *.tmp
+
+# Report failure. Note that all output regarding the tests goes to stdout.
+# That saves an unpleasant mixture of stdout and stderr to sort out.
+ZTST_testfailed() {
+ print -r "Test $ZTST_testname failed: $1"
+ if [[ -n $ZTST_message ]]; then
+ print -r "Was testing: $ZTST_message"
+ fi
+ print -r "$ZTST_testname: test failed."
+ 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() {
+ local lev=$1
+ shift
+ if [[ -n $ZTST_verbose && $ZTST_verbose -ge $lev ]]; then
+ print -r -u $ZTST_fd -- $*
+ fi
+}
+ZTST_hashmark() {
+ if [[ ZTST_verbose -le 0 && -t $ZTST_fd ]]; then
+ print -n -u$ZTST_fd -- ${(pl:SECONDS::\#::\#\r:)}
+ fi
+ (( SECONDS > COLUMNS+1 && (SECONDS -= COLUMNS) ))
+}
+
+if [[ ! -r $ZTST_testname ]]; then
+ ZTST_testfailed "can't read test file."
+ exit 1
+fi
+
+exec {ZTST_fd}>&1
+exec {ZTST_input}<$ZTST_testname
+
+# The current line read from the test file.
+ZTST_curline=''
+# The current section being run
+ZTST_cursect=''
+
+# Get a new input line. Don't mangle spaces; set IFS locally to empty.
+# We shall skip comments at this level.
+ZTST_getline() {
+ local IFS=
+ while true; do
+ read -u $ZTST_input -r ZTST_curline || return 1
+ [[ $ZTST_curline == \#* ]] || return 0
+ done
+}
+
+# Get the name of the section. It may already have been read into
+# $curline, or we may have to skip some initial comments to find it.
+# If argument present, it's OK to skip the reset of the current section,
+# so no error if we find garbage.
+ZTST_getsect() {
+ local match mbegin mend
+
+ while [[ $ZTST_curline != '%'(#b)([[:alnum:]]##)* ]]; do
+ ZTST_getline || return 1
+ [[ $ZTST_curline = [[:blank:]]# ]] && continue
+ if [[ $# -eq 0 && $ZTST_curline != '%'[[:alnum:]]##* ]]; then
+ ZTST_testfailed "bad line found before or after section:
+$ZTST_curline"
+ exit 1
+ fi
+ done
+ # have the next line ready waiting
+ ZTST_getline
+ ZTST_cursect=${match[1]}
+ ZTST_verbose 2 "ZTST_getsect: read section name: $ZTST_cursect"
+ return 0
+}
+
+# Read in an indented code chunk for execution
+ZTST_getchunk() {
+ # Code chunks are always separated by blank lines or the
+ # end of a section, so if we already have a piece of code,
+ # we keep it. Currently that shouldn't actually happen.
+ ZTST_code=''
+ # First find the chunk.
+ while [[ $ZTST_curline = [[:blank:]]# ]]; do
+ ZTST_getline || break
+ done
+ while [[ $ZTST_curline = [[:blank:]]##[^[:blank:]]* ]]; do
+ ZTST_code="${ZTST_code:+${ZTST_code}
+}${ZTST_curline}"
+ ZTST_getline || break
+ done
+ ZTST_verbose 2 "ZTST_getchunk: read code chunk:
+$ZTST_code"
+ [[ -n $ZTST_code ]]
+}
+
+# Read in a piece for redirection.
+ZTST_getredir() {
+ local char=${ZTST_curline[1]} fn
+ ZTST_redir=${ZTST_curline[2,-1]}
+ while ZTST_getline; do
+ [[ $ZTST_curline[1] = $char ]] || break
+ ZTST_redir="${ZTST_redir}
+${ZTST_curline[2,-1]}"
+ done
+ ZTST_verbose 2 "ZTST_getredir: read redir for '$char':
+$ZTST_redir"
+
+ case $char in
+ ('<') fn=$ZTST_in
+ ;;
+ ('>') fn=$ZTST_out
+ ;;
+ ('?') fn=$ZTST_err
+ ;;
+ (*) ZTST_testfailed "bad redir operator: $char"
+ return 1
+ ;;
+ esac
+ if [[ $ZTST_flags = *q* && $char = '<' ]]; then
+ # delay substituting output until variables are set
+ print -r -- "${(e)ZTST_redir}" >>$fn
+ else
+ print -r -- "$ZTST_redir" >>$fn
+ fi
+
+ return 0
+}
+
+# Execute an indented chunk. Redirections will already have
+# been set up, but we need to handle the options.
+ZTST_execchunk() {
+ setopt localloops # don't let continue & break propagate out
+ options=($ZTST_testopts)
+ () {
+ unsetopt localloops
+ eval "$ZTST_code"
+ }
+ ZTST_status=$?
+ # careful... ksh_arrays may be in effect.
+ ZTST_testopts=(${(kv)options[*]})
+ options=(${ZTST_mainopts[*]})
+ ZTST_verbose 2 "ZTST_execchunk: status $ZTST_status"
+ return $ZTST_status
+}
+
+# Functions for preparation and cleaning.
+# When cleaning up (non-zero string argument), we ignore status.
+ZTST_prepclean() {
+ # Execute indented code chunks.
+ while ZTST_getchunk; do
+ ZTST_execchunk >/dev/null || [[ -n $1 ]] || {
+ [[ -n "$ZTST_unimplemented" ]] ||
+ ZTST_testfailed "non-zero status from preparation code:
+$ZTST_code" && return 0
+ }
+ done
+}
+
+# diff wrapper
+ZTST_diff() {
+ emulate -L zsh
+ setopt extendedglob
+
+ local diff_out
+ integer diff_pat diff_ret
+
+ case $1 in
+ (p)
+ diff_pat=1
+ ;;
+
+ (d)
+ ;;
+
+ (*)
+ print "Bad ZTST_diff code: d for diff, p for pattern match"
+ ;;
+ esac
+ shift
+
+ if (( diff_pat )); then
+ local -a diff_lines1 diff_lines2
+ integer failed i
+
+ diff_lines1=("${(f)$(<$argv[-2])}")
+ diff_lines2=("${(f)$(<$argv[-1])}")
+ if (( ${#diff_lines1} != ${#diff_lines2} )); then
+ failed=1
+ else
+ for (( i = 1; i <= ${#diff_lines1}; i++ )); do
+ if [[ ${diff_lines2[i]} != ${~diff_lines1[i]} ]]; then
+ failed=1
+ break
+ fi
+ done
+ fi
+ if (( failed )); then
+ print -rl "Pattern match failed:" \<${^diff_lines1} \>${^diff_lines2}
+ diff_ret=1
+ fi
+ else
+ diff_out=$(diff "$@")
+ diff_ret="$?"
+ if [[ "$diff_ret" != "0" ]]; then
+ print -r -- "$diff_out"
+ fi
+ fi
+
+ return "$diff_ret"
+}
+
+ZTST_test() {
+ local last match mbegin mend found substlines
+ local diff_out diff_err
+ local ZTST_skip
+
+ while true; do
+ rm -f $ZTST_in $ZTST_out $ZTST_err
+ touch $ZTST_in $ZTST_out $ZTST_err
+ ZTST_message=''
+ ZTST_failmsg=''
+ found=0
+ diff_out=d
+ diff_err=d
+
+ ZTST_verbose 2 "ZTST_test: looking for new test"
+
+ while true; do
+ ZTST_verbose 2 "ZTST_test: examining line:
+$ZTST_curline"
+ case $ZTST_curline in
+ (%*) if [[ $found = 0 ]]; then
+ break 2
+ else
+ last=1
+ break
+ fi
+ ;;
+ ([[:space:]]#)
+ if [[ $found = 0 ]]; then
+ ZTST_getline || break 2
+ continue
+ else
+ break
+ fi
+ ;;
+ ([[:space:]]##[^[:space:]]*) ZTST_getchunk
+ if [[ $ZTST_curline == (#b)([-0-9]##)([[:alpha:]]#)(:*)# ]]; then
+ ZTST_xstatus=$match[1]
+ ZTST_flags=$match[2]
+ ZTST_message=${match[3]:+${match[3][2,-1]}}
+ else
+ ZTST_testfailed "expecting test status at:
+$ZTST_curline"
+ return 1
+ fi
+ ZTST_getline
+ found=1
+ ;;
+ ('<'*) ZTST_getredir || return 1
+ found=1
+ ;;
+ ('*>'*)
+ ZTST_curline=${ZTST_curline[2,-1]}
+ diff_out=p
+ ;&
+ ('>'*)
+ ZTST_getredir || return 1
+ found=1
+ ;;
+ ('*?'*)
+ ZTST_curline=${ZTST_curline[2,-1]}
+ diff_err=p
+ ;&
+ ('?'*)
+ ZTST_getredir || return 1
+ found=1
+ ;;
+ ('F:'*) ZTST_failmsg="${ZTST_failmsg:+${ZTST_failmsg}
+} ${ZTST_curline[3,-1]}"
+ ZTST_getline
+ found=1
+ ;;
+ (*) ZTST_testfailed "bad line in test block:
+$ZTST_curline"
+ return 1
+ ;;
+ esac
+ done
+
+ # If we found some code to execute...
+ if [[ -n $ZTST_code ]]; then
+ ZTST_hashmark
+ ZTST_verbose 1 "Running test: $ZTST_message"
+ ZTST_verbose 2 "ZTST_test: expecting status: $ZTST_xstatus"
+ ZTST_verbose 2 "Input: $ZTST_in, output: $ZTST_out, error: $ZTST_terr"
+
+ ZTST_execchunk <$ZTST_in >$ZTST_tout 2>$ZTST_terr
+
+ if [[ -n $ZTST_skip ]]; then
+ ZTST_verbose 0 "Test case skipped: $ZTST_skip"
+ ZTST_skip=
+ if [[ -n $last ]]; then
+ break
+ else
+ continue
+ fi
+ fi
+
+ # First check we got the right status, if specified.
+ if [[ $ZTST_xstatus != - && $ZTST_xstatus != $ZTST_status ]]; then
+ ZTST_testfailed "bad status $ZTST_status, expected $ZTST_xstatus from:
+$ZTST_code${$(<$ZTST_terr):+
+Error output:
+$(<$ZTST_terr)}"
+ return 1
+ fi
+
+ ZTST_verbose 2 "ZTST_test: test produced standard output:
+$(<$ZTST_tout)
+ZTST_test: and standard error:
+$(<$ZTST_terr)"
+
+ # Now check output and error.
+ if [[ $ZTST_flags = *q* && -s $ZTST_out ]]; then
+ substlines="$(<$ZTST_out)"
+ rm -rf $ZTST_out
+ print -r -- "${(e)substlines}" >$ZTST_out
+ fi
+ if [[ $ZTST_flags != *d* ]] && ! ZTST_diff $diff_out -u $ZTST_out $ZTST_tout; then
+ ZTST_testfailed "output differs from expected as shown above for:
+$ZTST_code${$(<$ZTST_terr):+
+Error output:
+$(<$ZTST_terr)}"
+ return 1
+ fi
+ if [[ $ZTST_flags = *q* && -s $ZTST_err ]]; then
+ substlines="$(<$ZTST_err)"
+ rm -rf $ZTST_err
+ print -r -- "${(e)substlines}" >$ZTST_err
+ fi
+ if [[ $ZTST_flags != *D* ]] && ! ZTST_diff $diff_err -u $ZTST_err $ZTST_terr; then
+ ZTST_testfailed "error output differs from expected as shown above for:
+$ZTST_code"
+ return 1
+ fi
+ fi
+ ZTST_verbose 1 "Test successful."
+ [[ -n $last ]] && break
+ done
+
+ ZTST_verbose 2 "ZTST_test: all tests successful"
+
+ # reset message to keep ZTST_testfailed output correct
+ ZTST_message=''
+}
+
+
+# Remember which sections we've done.
+typeset -A ZTST_sects
+ZTST_sects=(prep 0 test 0 clean 0)
+
+print "$ZTST_testname: starting."
+
+# Now go through all the different sections until the end.
+# prep section may set ZTST_unimplemented, in this case the actual
+# tests will be skipped
+ZTST_skipok=
+ZTST_unimplemented=
+while [[ -z "$ZTST_unimplemented" ]] && ZTST_getsect $ZTST_skipok; do
+ case $ZTST_cursect in
+ (prep) if (( ${ZTST_sects[prep]} + ${ZTST_sects[test]} + \
+ ${ZTST_sects[clean]} )); then
+ ZTST_testfailed "\`prep' section must come first"
+ exit 1
+ fi
+ ZTST_prepclean
+ ZTST_sects[prep]=1
+ ;;
+ (test)
+ if (( ${ZTST_sects[test]} + ${ZTST_sects[clean]} )); then
+ ZTST_testfailed "bad placement of \`test' section"
+ exit 1
+ fi
+ # careful here: we can't execute ZTST_test before || or &&
+ # because that affects the behaviour of traps in the tests.
+ ZTST_test
+ (( $? )) && ZTST_skipok=1
+ ZTST_sects[test]=1
+ ;;
+ (clean)
+ if (( ${ZTST_sects[test]} == 0 || ${ZTST_sects[clean]} )); then
+ ZTST_testfailed "bad use of \`clean' section"
+ else
+ ZTST_prepclean 1
+ ZTST_sects[clean]=1
+ fi
+ ZTST_skipok=
+ ;;
+ *) ZTST_testfailed "bad section name: $ZTST_cursect"
+ ;;
+ esac
+done
+
+if [[ -n "$ZTST_unimplemented" ]]; then
+ print "$ZTST_testname: skipped ($ZTST_unimplemented)"
+ ZTST_testfailed=2
+elif (( ! $ZTST_testfailed )); then
+ print "$ZTST_testname: all tests successful."
+fi
+ZTST_cleanup
+exit $(( ZTST_testfailed ))