aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteve Bennett <steveb@workware.net.au>2022-06-11 23:42:52 +1000
committerSteve Bennett <steveb@workware.net.au>2025-07-16 09:34:08 +1000
commitefe7b772f231a236ec5f27973c6f2205a23cc4e1 (patch)
treeaa2c2a6936cee31e30078f5eb655ad96f8b81c46
parent76de7e190c7d9033ed0a1227d668c1d8f51ac60f (diff)
downloadjimtcl-efe7b772f231a236ec5f27973c6f2205a23cc4e1.zip
jimtcl-efe7b772f231a236ec5f27973c6f2205a23cc4e1.tar.gz
jimtcl-efe7b772f231a236ec5f27973c6f2205a23cc4e1.tar.bz2
tests: add tests for TIP424 exec syntax
Signed-off-by: Steve Bennett <steveb@workware.net.au>
-rw-r--r--tests/exec-tip424.test424
1 files changed, 424 insertions, 0 deletions
diff --git a/tests/exec-tip424.test b/tests/exec-tip424.test
new file mode 100644
index 0000000..043c895
--- /dev/null
+++ b/tests/exec-tip424.test
@@ -0,0 +1,424 @@
+# The same tests as exec.test, but changed to TIP424 exec syntax
+
+source [file dirname [info script]]/testing.tcl
+
+needs cmd exec
+needs cmd flush
+# Need [pipe] to implement [open |command]
+constraint cmd pipe
+
+constraint expr unix {$tcl_platform(platform) eq {unix}}
+
+# Sleep which supports fractions of a second
+if {[info commands sleep] eq {}} {
+ proc sleep {n} {
+ exec {*}$::sleepx $n
+ }
+}
+
+set f [open sleepx w]
+puts $f {
+ sleep "$@"
+}
+close $f
+#catch {exec chmod +x sleepx}
+set sleepx [list sh sleepx]
+
+# Basic operations.
+
+test exec-1.1 {basic exec operation} {
+ exec | {echo a b c}
+} "a b c"
+test exec-1.2 {pipelining} {
+ exec | {echo a b c d} | cat | cat
+} "a b c d"
+test exec-1.3 {pipelining} {
+ set a [exec | {echo a b c d} | cat | wc]
+ list [scan $a "%d %d %d" b c d] $b $c
+} {3 1 4}
+set arg {12345678901234567890123456789012345678901234567890}
+set arg "$arg$arg$arg$arg$arg$arg"
+test exec-1.4 {long command lines} {
+ exec | [list echo $arg]
+} $arg
+set arg {}
+
+# I/O redirection: input from Tcl command.
+
+test exec-2.1 {redirecting input from immediate source} {
+ exec | cat << "Sample text"
+} {Sample text}
+test exec-2.2 {redirecting input from immediate source} {
+ exec | cat << "Sample text" | cat
+} {Sample text}
+test exec-2.4 {redirecting input from immediate source} {
+ exec | cat | cat << "Sample text"
+} {Sample text}
+test exec-2.5 {redirecting input from immediate source} {
+ exec | cat "<<Joined to arrows"
+} {Joined to arrows}
+test exec-2.6 {redirecting input from immediate source, with UTF} {
+ # If this fails, it may give back:
+ # "\uC3\uA9\uC3\uA0\uC3\uBC\uC3\uB1"
+ # If it does, this means that the UTF -> external conversion did not
+ # occur before writing out the temp file.
+ exec | cat << "\uE9\uE0\uFC\uF1"
+} "\uE9\uE0\uFC\uF1"
+test exec-2.7 {redirecting input from immediate source with nulls} {
+ exec | cat << "Sample\0text"
+} "Sample\0text"
+
+# I/O redirection: output to file.
+
+file delete gorp.file
+test exec-3.1 {redirecting output to file} {
+ exec | {echo "Some simple words"} > gorp.file
+ exec | {cat gorp.file}
+} "Some simple words"
+test exec-3.2 {redirecting output to file} {
+ exec | {echo "More simple words"} | cat >gorp.file | cat
+ exec | {cat gorp.file}
+} "More simple words"
+test exec-3.3 {redirecting output to file} {
+ exec | {echo "Different simple words"} > gorp.file | cat | cat
+ exec | {cat gorp.file}
+} "Different simple words"
+test exec-3.4 {redirecting output to file} {
+ exec | {echo "Some simple words"} >gorp.file
+ exec | {cat gorp.file}
+} "Some simple words"
+test exec-3.5 {redirecting output to file} {
+ exec | {echo "First line"} >gorp.file
+ exec | {echo "Second line"} >> gorp.file
+ exec | {cat gorp.file}
+} "First line\nSecond line"
+test exec-3.7 {redirecting output to file} {
+ set f [open gorp.file w]
+ puts $f "Line 1"
+ flush $f
+ exec | {echo "More text"} >@ $f
+ exec | {echo "Even more"} >@$f
+ puts $f "Line 3"
+ close $f
+ exec | {cat gorp.file}
+} "Line 1\nMore text\nEven more\nLine 3"
+
+# I/O redirection: output and stderr to file.
+
+file delete gorp.file
+test exec-4.1 {redirecting output and stderr to file} {
+ exec | {echo "test output"} >& gorp.file
+ exec | {cat gorp.file}
+} "test output"
+test exec-4.2 {redirecting output and stderr to file} {
+ list [exec | {sh -c "echo foo bar 1>&2"} >&gorp.file] \
+ [exec | {cat gorp.file}]
+} {{} {foo bar}}
+test exec-4.3 {redirecting output and stderr to file} {
+ exec | {echo "first line"} > gorp.file
+ list [exec | {sh -c "echo foo bar 1>&2"} >>&gorp.file] \
+ [exec | {cat gorp.file}]
+} "{} {first line\nfoo bar}"
+test exec-4.4 {redirecting output and stderr to file} {
+ set f [open gorp.file w]
+ puts $f "Line 1"
+ flush $f
+ exec | {echo "More text"} >&@ $f
+ exec | {echo "Even more"} >&@$f
+ puts $f "Line 3"
+ close $f
+ exec | {cat gorp.file}
+} "Line 1\nMore text\nEven more\nLine 3"
+test exec-4.5 {redirecting output and stderr to file} {
+ set f [open gorp.file w]
+ puts $f "Line 1"
+ flush $f
+ exec | {sh -c "echo foo bar 1>&2"} >&@ $f
+ exec | {sh -c "echo xyzzy 1>&2"} >&@$f
+ puts $f "Line 3"
+ close $f
+ exec | {cat gorp.file}
+} "Line 1\nfoo bar\nxyzzy\nLine 3"
+
+# I/O redirection: input from file.
+
+exec | {echo "Just a few thoughts"} > gorp.file
+
+test exec-5.1 {redirecting input from file} {
+ exec | cat < gorp.file
+} {Just a few thoughts}
+test exec-5.2 {redirecting input from file} {
+ exec | cat | cat < gorp.file
+} {Just a few thoughts}
+test exec-5.3 {redirecting input from file} {
+ exec | cat < gorp.file | cat
+} {Just a few thoughts}
+test exec-5.5 {redirecting input from file} {
+ exec | cat <gorp.file
+} {Just a few thoughts}
+test exec-5.6 {redirecting input from file} {
+ set f [open gorp.file r]
+ set result [exec | cat <@ $f]
+ close $f
+ set result
+} {Just a few thoughts}
+test exec-5.7 {redirecting input from file} {
+ set f [open gorp.file r]
+ set result [exec | cat <@$f]
+ close $f
+ set result
+} {Just a few thoughts}
+
+# I/O redirection: standard error through a pipeline.
+
+test exec-6.1 {redirecting stderr through a pipeline} {
+ exec | {sh -c "echo foo bar"} |& cat
+} "foo bar"
+test exec-6.2 {redirecting stderr through a pipeline} {
+ exec | {sh -c "echo foo bar 1>&2"} |& cat
+} "foo bar"
+test exec-6.3 {redirecting stderr through a pipeline} {
+ exec | {sh -c "echo foo bar 1>&2"} \
+ |& cat |& cat
+} "foo bar"
+
+# I/O redirection: combinations.
+
+file delete gorp.file2
+test exec-7.1 {multiple I/O redirections} {
+ exec | cat << "command input" > gorp.file2 < gorp.file
+ exec | {cat gorp.file2}
+} {Just a few thoughts}
+test exec-7.2 {multiple I/O redirections} {
+ exec cat < gorp.file << "command input"
+} {command input}
+
+# Long input to command and output from command.
+
+set a [string repeat a 1000000]
+test exec-8.1 {long input and output} {
+ string length [exec | cat << $a]
+} 1000000
+
+# More than 20 arguments to exec.
+
+test exec-8.1 {long input and output} {
+ exec | {echo 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23}
+} {1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23}
+
+# Commands that return errors.
+
+test exec-9.1 {commands returning errors} {
+ catch {exec | gorp456}
+} {1}
+test exec-9.2 {commands returning errors} {
+ catch {exec | {echo foo} | foo123} msg
+} {1}
+test exec-9.3 {commands returning errors} {
+ list [catch {exec | [list {*}$sleepx 0.1] | false | [list {*}$sleepx 0.1]} msg]
+} {1}
+test exec-9.4 {commands returning errors} jim {
+ list [catch {exec | false | {echo "foo bar"}} msg] $msg
+} {1 {foo bar}}
+test exec-9.5 {commands returning errors} {
+ list [catch {exec | gorp456 | {echo a b c}} msg]
+} {1}
+test exec-9.6 {commands returning errors} jim {
+ list [catch {exec | {sh -c "echo error msg 1>&2"}} msg] $msg
+} {0 {error msg}}
+test exec-9.7 {commands returning errors} jim {
+ # Note: Use sleep here to ensure the order
+ list [catch {exec | {sh -c "echo error msg 1 1>&2"} \
+ | {sh -c "sleep 0.1; echo error msg 2 1>&2"}} msg] $msg
+} {0 {error msg 1
+error msg 2}}
+
+# Errors in executing the Tcl command, as opposed to errors in the
+# processes that are invoked.
+
+test exec-10.1 {errors in exec invocation} {
+ list [catch {exec |} msg]
+} {1}
+test exec-10.3 {errors in exec invocation} {
+ list [catch {exec | cat |} msg] $msg
+} {1 {cmdlist required after |}}
+test exec-10.4 {errors in exec invocation} {
+ list [catch {exec | cat | | cat} msg] $msg
+} {1 {invalid redirection cat}}
+test exec-10.5 {errors in exec invocation} {
+ list [catch {exec | cat | |& cat} msg] $msg
+} {1 {invalid redirection cat}}
+test exec-10.6 {errors in exec invocation} {
+ list [catch {exec | cat |&} msg] $msg
+} {1 {cmdlist required after |&}}
+test exec-10.7 {errors in exec invocation} {
+ list [catch {exec | cat <} msg] $msg
+} {1 {can't specify "<" as last word in command}}
+test exec-10.8 {errors in exec invocation} {
+ list [catch {exec | cat >} msg] $msg
+} {1 {can't specify ">" as last word in command}}
+test exec-10.9 {errors in exec invocation} {
+ list [catch {exec | cat <<} msg] $msg
+} {1 {can't specify "<<" as last word in command}}
+test exec-10.10 {errors in exec invocation} {
+ list [catch {exec | cat >>} msg] $msg
+} {1 {can't specify ">>" as last word in command}}
+test exec-10.11 {errors in exec invocation} {
+ list [catch {exec | cat >&} msg] $msg
+} {1 {can't specify ">&" as last word in command}}
+test exec-10.12 {errors in exec invocation} {
+ list [catch {exec | cat >>&} msg] $msg
+} {1 {can't specify ">>&" as last word in command}}
+test exec-10.13 {errors in exec invocation} {
+ list [catch {exec | cat >@} msg] $msg
+} {1 {can't specify ">@" as last word in command}}
+test exec-10.14 {errors in exec invocation} {
+ list [catch {exec | cat <@} msg] $msg
+} {1 {can't specify "<@" as last word in command}}
+test exec-10.15 {errors in exec invocation} {
+ list [catch {exec | cat < a/b/c} msg] [string tolower $msg]
+} {1 {couldn't read file "a/b/c": no such file or directory}}
+test exec-10.16 {errors in exec invocation} {
+ list [catch {exec | cat << foo > a/b/c} msg] [string tolower $msg]
+} {1 {couldn't write file "a/b/c": no such file or directory}}
+test exec-10.17 {errors in exec invocation} {
+ list [catch {exec | cat << foo > a/b/c} msg] [string tolower $msg]
+} {1 {couldn't write file "a/b/c": no such file or directory}}
+set f [open gorp.file w]
+test exec-10.18 {errors in exec invocation} {
+ list [catch {exec | cat <<test <@ $f} msg]
+} 1
+close $f
+set f [open gorp.file r]
+test exec-10.19 {errors in exec invocation} {
+ list [catch {exec | cat <<test >@ $f} msg]
+} 1
+close $f
+
+# Commands in background.
+
+test exec-11.1 {commands in background} {
+ set x [lindex [time {exec | [list {*}$sleepx 0.2] &}] 0]
+ expr $x<1000000
+} 1
+test exec-11.2 {commands in background} {
+ list [catch {exec | {echo a &b}} msg] $msg
+} {0 {a &b}}
+test exec-11.3 {commands in background} {
+ llength [exec | [list {*}$sleepx 0.1] &]
+} 1
+test exec-11.4 {commands in background} {
+ llength [exec | [list {*}$sleepx 0.1] | [list {*}$sleepx 0.1] | [list {*}$sleepx 0.1] &]
+} 3
+
+# Make sure that background commands are properly reaped when
+# they eventually die.
+
+exec | [list {*}$sleepx 0.3]
+
+test exec-12.1 {reaping background processes} -constraints unix -body {
+ for {set i 0} {$i < 20} {incr i} {
+ exec | {echo foo} > exec.tmp1 &
+ }
+ exec | [list {*}$sleepx 0.1]
+ catch {exec | ps | {fgrep "echo foo"} | {fgrep -v grep} | wc} msg
+ lindex $msg 0
+} -cleanup {
+ file delete exec.tmp1
+} -result 0
+
+# Redirecting standard error separately from standard output
+
+test exec-15.1 {standard error redirection} {
+ exec | {echo "First line"} > gorp.file
+ list [exec | {sh -c "echo foo bar 1>&2"} 2> gorp.file] \
+ [exec | {cat gorp.file}]
+} {{} {foo bar}}
+test exec-15.2 {standard error redirection} {
+ list [exec | {sh -c "echo foo bar 1>&2"} \
+ | {echo biz baz} >gorp.file 2> gorp.file2] \
+ [exec | {cat gorp.file}] \
+ [exec | {cat gorp.file2}]
+} {{} {biz baz} {foo bar}}
+test exec-15.3 {standard error redirection} {
+ list [exec | {sh -c "echo foo bar 1>&2"} \
+ | {echo biz baz} 2>gorp.file > gorp.file2] \
+ [exec | {cat gorp.file}] \
+ [exec | {cat gorp.file2}]
+} {{} {foo bar} {biz baz}}
+test exec-15.4 {standard error redirection} {
+ set f [open gorp.file w]
+ puts $f "Line 1"
+ flush $f
+ exec | {sh -c "echo foo bar 1>&2"} 2>@ $f
+ puts $f "Line 3"
+ close $f
+ exec | {cat gorp.file}
+} {Line 1
+foo bar
+Line 3}
+test exec-15.5 {standard error redirection} {
+ exec | {echo "First line"} > gorp.file
+ exec | {sh -c "echo foo bar 1>&2"} 2>> gorp.file
+ exec | {cat gorp.file}
+} {First line
+foo bar}
+test exec-15.6 {standard error redirection} {
+ exec | {sh -c "echo foo bar 1>&2"} > gorp.file2 2> gorp.file \
+ >& gorp.file 2> gorp.file2 | {echo biz baz}
+ list [exec | {cat gorp.file}] [exec | {cat gorp.file2}]
+} {{biz baz} {foo bar}}
+test exec-15.7 {combine standard output/standard error} -body {
+ exec | {sh -c "echo foo bar 1>&2"} > gorp.file 2>@1
+ exec | {cat gorp.file}
+} -cleanup {
+ file delete gorp.file gorp.file2
+} -result {foo bar}
+
+test exec-16.1 {flush output before exec} -body {
+ set f [open gorp.file w]
+ puts $f "First line"
+ exec | {echo "Second line"} >@ $f
+ puts $f "Third line"
+ close $f
+ exec | {cat gorp.file}
+} -cleanup {
+ file delete gorp.file
+} -result {First line
+Second line
+Third line}
+
+test exec-17.1 {redirecting from command pipeline} -setup {
+ makeFile "abc\nghi\njkl" gorp.file
+} -constraints pipe -body {
+ set f [open "|| {cat gorp.file} | {wc -l}" r]
+ set result [lindex [exec | cat <@$f] 0]
+ close $f
+ set result
+} -cleanup {
+ file delete gorp.file
+} -result {3}
+
+test exec-17.2 {redirecting to command pipeline} -setup {
+ makeFile "abc\nghi\njkl" gorp.file
+} -constraints pipe -body {
+ set f [open "|| {wc -l} >gorp2.file" w]
+ exec | {cat gorp.file} >@$f
+ flush $f
+ close $f
+ lindex [exec | {cat gorp2.file}] 0
+} -cleanup {
+ file delete gorp.file gorp2.file
+} -result {3}
+
+test exec-17.3 {redirecting stderr to stdout} -body {
+ exec | {sh -c "echo foo bar 1>&2"} 2>@1
+} -result {foo bar}
+
+file delete sleepx
+
+# Now we probably have a lot of unreaped zombies at this point
+# so reap them to avoid confusing further tests
+wait
+
+testreport