Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
[PATCH] Tests for nofork substitutions
- X-seq: zsh-workers 51988
- From: Bart Schaefer <schaefer@xxxxxxxxxxxxxxxx>
- To: Zsh hackers list <zsh-workers@xxxxxxx>
- Subject: [PATCH] Tests for nofork substitutions
- Date: Mon, 24 Jul 2023 23:25:52 -0700
- Archived-at: <https://zsh.org/workers/51988>
- List-id: <zsh-workers.zsh.org>
Suggestions for additional tests?
Some remarks on these tests:
1) In the example
${| print -v REPLY one word here; setopt shwordsplit }
Although the current context is used so the setopt persists after the
command is executed, the substitution code has already decided what
options apply to the result, so the words in this example are not
split. It would be pretty complicated to invert that.
2) It occurred to me that ${|var| ...} is just another way to write
${${| ...}:-$var} (if REPLY remains unset). So the former could be
dropped with no loss of functionality, if consensus deems it to be
fluff.
3) Note that ${|...} always substitutes at least an empty string, so
${${|...}-alt} is never "alt".
4) In the example
print ${|return 1} $?
The value printed for $? is 1 but the status of the whole expression
is 0, that is, it is the status of the "print" command.
5) If a test sets the errreturn option, the whole test harness breaks
silently. I encountered some other instances of that too, e.g., only
about half of the tests were run but the harness still reported "all
tests successful".
6) While writing the above I thought of another test I could add. Later.
diff --git b/Test/D10nofork.ztst a/Test/D10nofork.ztst
new file mode 100644
index 000000000..6e14f343e
--- /dev/null
+++ a/Test/D10nofork.ztst
@@ -0,0 +1,326 @@
+# Tests for "nofork" command substitution.
+
+%prep
+ mkdir nofork.tmp
+ touch nofork.tmp/file{1,2}.txt
+
+ purr() { print -r -- "$@" }
+ purl() { print -rl -- "$@" }
+
+%test
+
+ REPLY=OUTER
+ purr ${| REPLY=INNER } $REPLY
+0:Basic substitution and REPLY scoping
+>INNER OUTER
+
+ purr ${| REPLY=first}:${| REPLY=second}:$REPLY
+0:re-scoping of REPLY in one statement
+>first:second:OUTER
+
+ purr BEGIN${| printf -v REPLY '%s\n' one two three ; }END
+0:Adjacent words
+>BEGINone
+>two
+>three
+>END
+
+ purr "BEGIN${| printf -v REPLY '%s\n' one two three }END"
+0:Adjacent words and quoting, part 1
+>BEGINone
+>two
+>three
+>END
+
+ purr BEGIN"${| printf -v REPLY '%s\n' one two three }"END
+0:Adjacent words and quoting, part 2
+>BEGINone
+>two
+>three
+>END
+
+ purr BEGIN"${|
+ printf -v REPLY '%s\n'\
+ one two three
+ }"END
+0:Embedded newlines
+>BEGINone
+>two
+>three
+>END
+
+ purr BEGIN"${|
+ printf -v REPLY $'%s\n' one two three
+ }"END
+0:Embedded newlines and $'...'
+>BEGINone
+>two
+>three
+>END
+
+ purl ${| print -v REPLY one word here; setopt shwordsplit }
+ purl ${| print -v REPLY three words here }
+ purl "and ${| print -v REPLY one word here }"
+ unsetopt shwordsplit
+0:test word splitting on result
+F:setting option inside is too late for that substitution
+>one word here
+>three
+>words
+>here
+>and one word here
+
+ (
+ cd nofork.tmp
+ setopt globsubst
+ print ${| REPLY=f* }
+ print ${| REPLY=f? }*
+ unsetopt globsubst
+ print ${| REPLY=f* }
+ print ${| REPLY=f? }*
+ )
+1:globsubst on result
+>file1.txt file2.txt
+>file1.txt file2.txt
+>f*
+?(eval):8: no matches found: f?*
+
+ purr ${| REPLY=$'trailing newlines remain\n\n' }
+0:newline removal should not occur
+>trailing newlines remain
+>
+>
+
+ () {
+ purr ${| REPLY=$* ; shift 2 }
+ purr $*
+ } these are arguments
+0:access to context $argv
+>these are arguments
+>arguments
+
+ purr ${:-${| REPLY=${REPLY:-buried}}}
+ purr ${:-"${| REPLY=${REPLY:-more buried}}"}
+0:nofork inside parameter scope
+>buried
+>more buried
+
+ : ${(e):-'${| REPLY=oops'}
+1:unclosed braces are sometimes a bad substitution
+F:This seems silly, but see A01grammar ${(e):-'${'} test
+?(eval):1: bad substitution
+
+ purr ${| REPLY=oops
+1:other times lack of closing brace is merely unexpected
+F:Why not use this error in the previous case as well?
+?(eval):1: closing brace expected
+
+# Next tests check that the PS2 stack is properly managed on error
+
+ purr ${| REPLY=${REPLY:-buried}}}
+1:unbalanced braces, part 0
+?(eval):1: parse error near `}'
+
+ purr ${:-${| REPLY=${REPLY:-buried}}
+1:unbalanced braces, part 1
+?(eval):1: closing brace expected
+
+ purr ${:-"${| REPLY=${REPLY:-more buried}"}
+1:unbalanced braces, part 2
+?(eval):1: unmatched "
+
+ purr ${:-"${| REPLY=${REPLY:-more buried"}}}
+1:unbalanced braces, part 3
+?(eval):1: unmatched "
+
+ purr ${:-"${| REPLY=${REPLY:-more buried}}}"
+1:unbalanced braces, part 4
+?(eval):1: closing brace expected
+
+# Same tests with leading space (future-proofing)
+
+ purr ${ purr ${REPLY:-buried}}}
+1:unbalanced braces, part 0+
+?(eval):1: parse error near `}'
+
+ purr ${:-${ purr ${REPLY:-buried}}
+1:unbalanced braces, part 1+
+?(eval):1: closing brace expected
+
+ purr ${:-"${ purr ${REPLY:-more buried}"}
+1:unbalanced braces, part 2+
+?(eval):1: unmatched "
+
+ purr ${:-"${ purr ${REPLY:-more buried"}}}
+1:unbalanced braces, part 3+
+?(eval):1: unmatched "
+
+ purr ${:-"${ purr ${REPLY:-more buried}}}"
+1:unbalanced braces, part 4+
+?(eval):1: closing brace expected
+
+ purr ${ purr STDOUT }
+0f:capture stdout
+>STDOUT
+
+# end PS2 stack tests
+
+ purr $(print outside ${| REPLY=inside })
+ purr BEGIN$(print outside ${| REPLY=inside })END
+ purr "BEGIN$(print outside ${| REPLY=inside })END"
+ purr outside ${| REPLY=$(print inside)}
+ purr "outside ${| REPLY=$(print inside)}"
+0:mixing with forking cmdsubst
+>outside inside
+>BEGINoutside insideEND
+>BEGINoutside insideEND
+>outside inside
+>outside inside
+
+ purr `purr outside ${| REPLY=inside }`
+ purr "outside `purr ${| REPLY=inside }`"
+ purr outside ${| REPLY=`purr inside`}
+ purr "outside ${| REPLY=`purr inside`}"
+ purr outside "`purr ${| REPLY="${:-inside}"}`"
+ purr "outside ${| REPLY=`purr ${:-inside}`}"
+0:mixing with backticks
+>outside inside
+>outside inside
+>outside inside
+>outside inside
+>outside inside
+>outside inside
+
+ purr ${| REPLY=$(( 9 + 17 )) }
+ purr $(( 9 + ${| REPLY=17 } ))
+0:mixing with arithemetic
+>26
+>26
+
+ unset reply
+ purl ${|reply| reply=(1 2 ${| REPLY=3 } 4) }
+ typeset -p reply
+0:array behavior with global assignment
+>1
+>2
+>3
+>4
+>typeset -g -a reply=( 1 2 3 4 )
+
+ unset outer
+ purr "${|
+ outer=OUTER
+ REPLY=INNER
+ return 7
+ OUTER=NOTREACHED
+ } $outer $?"
+0:return statement inside, part 1
+F:status of "print" should hide return
+>INNER OUTER 7
+
+ unset outer
+ purr "${|
+ outer=OUTER
+ REPLY=INNER
+ return 7
+ OUTER=NOTREACHED
+ } $outer $?"
+ print REACHED $OUTER
+0:return statement inside, part 2
+>INNER OUTER 7
+>REACHED
+
+ unset outer
+ purr "${|
+ # Localoptions needed to avoid breaking test harness?
+ # The setopt command affects surrounding context
+ setopt localoptions errreturn
+ outer=OUTER
+ REPLY=INNER
+ false
+ OUTER=NOTREACHED
+ } $outer $?"
+ print REACHED $OUTER ${options[errreturn]}
+0:errreturn works inside and remains outside
+>INNER OUTER 1
+>REACHED on
+
+ (
+ unset outer
+ purr "${|
+ outer=OUTER
+ REPLY=INNER
+ exit 7
+ OUTER=NOTREACHED
+ } $outer $OUTER $?"
+ print NOT REACHED
+ )
+7:exit statement inside
+
+ (
+ unset outer
+ purr "${|
+ setopt errexit
+ outer=OUTER
+ REPLY=INNER
+ false
+ OUTER=NOTREACHED
+ } $outer $?"
+ print NOT REACHED
+ )
+1:errexit inside
+
+ outer=GLOBAL
+ purr "${|
+ local outer=LOCAL
+ REPLY=INNER
+ } $outer $?"
+0:local declaration inside
+>INNER GLOBAL 0
+
+ unset zz
+ outer=GLOBAL
+ purr "${|zz|
+ local outer=LOCAL
+ zz=NONLOCAL
+ } $outer $?"
+ print $zz
+0:local declaration, global assignment, part 1
+>NONLOCAL GLOBAL 0
+>NONLOCAL
+
+ unset zz
+ outer=GLOBAL
+ purr "${${|
+ local outer=LOCAL
+ zz=NONLOCAL
+ }:-$zz} $outer $?"
+0:local declaration, global assignment, part 2 (evaluation order)
+>NONLOCAL GLOBAL 0
+
+ : ${| fn1() { () { print -v REPLY $'Defined Function' } } }
+ print "IN${| fn2() { () { print "${:-Second }${|fn1}" } } }OUT"
+ fn2
+0:function definition, brace nesting, quote nesting
+>INOUT
+>Second Defined Function
+
+ <<-EOF
+ ${| REPLY=$'in a here document\n' }
+ EOF
+0:here-document behavior
+F:Fiddly here to get EOF past the test syntax
+>in a here document
+>
+
+ <<<${| REPLY="in a here string" }
+0:here-string behavior
+>in a here string
+
+ print -u $ZTST_fd ${ZTST_testname}: TEST COMPLETE
+0:make sure we got to the end
+F:some tests might silently break the test harness
+
+%clean
+
+ unfunction purr purl
Messages sorted by:
Reverse Date,
Date,
Thread,
Author