summaryrefslogtreecommitdiffstats
path: root/tests/ioCmd.test
diff options
context:
space:
mode:
Diffstat (limited to 'tests/ioCmd.test')
-rw-r--r--tests/ioCmd.test3174
1 files changed, 3067 insertions, 107 deletions
diff --git a/tests/ioCmd.test b/tests/ioCmd.test
index 2d17d76..768a748 100644
--- a/tests/ioCmd.test
+++ b/tests/ioCmd.test
@@ -14,11 +14,16 @@
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
if {[lsearch [namespace children] ::tcltest] == -1} {
- package require tcltest
+ package require tcltest 2
namespace import -force ::tcltest::*
}
-testConstraint fcopy [llength [info commands fcopy]]
+# Custom constraints used in this file
+testConstraint fcopy [llength [info commands fcopy]]
+testConstraint testchannel [llength [info commands testchannel]]
+testConstraint testthread [llength [info commands testthread]]
+
+#----------------------------------------------------------------------
test iocmd-1.1 {puts command} {
list [catch {puts} msg] $msg
@@ -28,7 +33,7 @@ test iocmd-1.2 {puts command} {
} {1 {wrong # args: should be "puts ?-nonewline? ?channelId? string"}}
test iocmd-1.3 {puts command} {
list [catch {puts froboz -nonewline kablooie} msg] $msg
-} {1 {bad argument "kablooie": should be "nonewline"}}
+} {1 {wrong # args: should be "puts ?-nonewline? ?channelId? string"}}
test iocmd-1.4 {puts command} {
list [catch {puts froboz hello} msg] $msg
} {1 {can not find channel named "froboz"}}
@@ -60,7 +65,6 @@ test iocmd-1.8 {puts command} {
file size $path(test1)
} 9
-
test iocmd-2.1 {flush command} {
list [catch {flush} msg] $msg
} {1 {wrong # args: should be "flush channelId"}}
@@ -111,8 +115,8 @@ test iocmd-4.4 {read command} {
list [catch {read -nonewline} msg] $msg
} {1 {wrong # args: should be "read channelId ?numChars?" or "read ?-nonewline? channelId"}}
test iocmd-4.5 {read command} {
- list [catch {read -nonew file4} msg] $msg $errorCode
-} {1 {can not find channel named "-nonew"} NONE}
+ list [catch {read -nonew file4} msg] $msg $::errorCode
+} {1 {can not find channel named "-nonew"} {TCL LOOKUP CHANNEL -nonew}}
test iocmd-4.6 {read command} {
list [catch {read stdout} msg] $msg
} {1 {channel "stdout" wasn't opened for reading}}
@@ -126,32 +130,30 @@ test iocmd-4.8 {read command with incorrect combination of arguments} {
puts $f "and this one"
close $f
set f [open $path(test1)]
- set x [list [catch {read -nonewline $f 20 z} msg] $msg $errorCode]
+ set x [list [catch {read -nonewline $f 20 z} msg] $msg $::errorCode]
close $f
set x
} {1 {wrong # args: should be "read channelId ?numChars?" or "read ?-nonewline? channelId"} NONE}
test iocmd-4.9 {read command} {
- list [catch {read stdin foo} msg] $msg $errorCode
-} {1 {bad argument "foo": should be "nonewline"} NONE}
+ list [catch {read stdin foo} msg] $msg $::errorCode
+} {1 {expected integer but got "foo"} {TCL VALUE NUMBER}}
test iocmd-4.10 {read command} {
- list [catch {read file107} msg] $msg $errorCode
-} {1 {can not find channel named "file107"} NONE}
-
+ list [catch {read file107} msg] $msg $::errorCode
+} {1 {can not find channel named "file107"} {TCL LOOKUP CHANNEL file107}}
set path(test3) [makeFile {} test3]
-
test iocmd-4.11 {read command} {
set f [open $path(test3) w]
- set x [list [catch {read $f} msg] $msg $errorCode]
+ set x [list [catch {read $f} msg] $msg $::errorCode]
close $f
string compare [string tolower $x] \
[list 1 [format "channel \"%s\" wasn't opened for reading" $f] none]
} 0
test iocmd-4.12 {read command} {
set f [open $path(test1)]
- set x [list [catch {read $f 12z} msg] $msg $errorCode]
+ set x [list [catch {read $f 12z} msg] $msg $::errorCode]
close $f
set x
-} {1 {expected integer but got "12z"} NONE}
+} {1 {expected integer but got "12z"} {TCL VALUE NUMBER}}
test iocmd-5.1 {seek command} {
list [catch {seek} msg] $msg
@@ -239,108 +241,109 @@ test iocmd-8.9 {fconfigure command} {
test iocmd-8.10 {fconfigure command} {
list [catch {fconfigure a b} msg] $msg
} {1 {can not find channel named "a"}}
-
set path(fconfigure.dummy) [makeFile {} fconfigure.dummy]
-
test iocmd-8.11 {fconfigure command} {
set chan [open $path(fconfigure.dummy) r]
set res [list [catch {fconfigure $chan -froboz blarfo} msg] $msg]
close $chan
set res
} {1 {bad option "-froboz": should be one of -blocking, -buffering, -buffersize, -encoding, -eofchar, or -translation}}
-
test iocmd-8.12 {fconfigure command} {
set chan [open $path(fconfigure.dummy) r]
set res [list [catch {fconfigure $chan -b blarfo} msg] $msg]
close $chan
set res
} {1 {bad option "-b": should be one of -blocking, -buffering, -buffersize, -encoding, -eofchar, or -translation}}
-
test iocmd-8.13 {fconfigure command} {
set chan [open $path(fconfigure.dummy) r]
set res [list [catch {fconfigure $chan -buffer blarfo} msg] $msg]
close $chan
set res
} {1 {bad option "-buffer": should be one of -blocking, -buffering, -buffersize, -encoding, -eofchar, or -translation}}
-
removeFile fconfigure.dummy
-
test iocmd-8.14 {fconfigure command} {
fconfigure stdin -buffers
} 4096
-
-proc iocmdSSETUP {} {
- uplevel {
- set srv [socket -server iocmdSRV 0]
- set port [lindex [fconfigure $srv -sockname] 2]
- proc iocmdSRV {sock ip port} {close $sock}
- set cli [socket 127.0.0.1 $port]
+test iocmd-8.15.1 {fconfigure command / tcp channel} -constraints {socket unixOrPc} -setup {
+ set srv [socket -server iocmdSRV -myaddr 127.0.0.1 0]
+ set port [lindex [fconfigure $srv -sockname] 2]
+ proc iocmdSRV {sock ip port} {close $sock}
+ set cli [socket 127.0.0.1 $port]
+} -body {
+ fconfigure $cli -blah
+} -cleanup {
+ close $cli
+ close $srv
+ unset cli srv port
+ rename iocmdSRV {}
+} -returnCodes error -result {bad option "-blah": should be one of -blocking, -buffering, -buffersize, -encoding, -eofchar, -translation, -peername, or -sockname}
+test iocmd-8.16 {fconfigure command / tcp channel} -constraints socket -setup {
+ set srv [socket -server iocmdSRV -myaddr 127.0.0.1 0]
+ set port [lindex [fconfigure $srv -sockname] 2]
+ proc iocmdSRV {sock ip port} {close $sock}
+ set cli [socket 127.0.0.1 $port]
+} -body {
+ expr {[lindex [fconfigure $cli -peername] 2] == $port}
+} -cleanup {
+ close $cli
+ close $srv
+ unset cli srv port
+ rename iocmdSRV {}
+} -result 1
+test iocmd-8.17 {fconfigure command / tcp channel} -constraints nonPortable -setup {
+ set srv [socket -server iocmdSRV -myaddr 127.0.0.1 0]
+ set port [lindex [fconfigure $srv -sockname] 2]
+ proc iocmdSRV {sock ip port} {close $sock}
+ set cli [socket 127.0.0.1 $port]
+} -body {
+ # It is possible that you don't get the connection reset by peer
+ # error but rather a valid answer. Depends on the tcp implementation
+ update
+ puts $cli "blah"
+ flush $cli; # that flush could/should fail too
+ update
+ regsub -all {can([^:])+: } [catch {fconfigure $cli -peername} msg] {}
+} -cleanup {
+ close $cli
+ close $srv
+ unset cli srv port
+ rename iocmdSRV {}
+} -result 1
+test iocmd-8.18 {fconfigure command / unix tty channel} -constraints {nonPortable unix} -setup {
+ set tty ""
+} -body {
+ # might fail if /dev/ttya is unavailable
+ set tty [open /dev/ttya]
+ fconfigure $tty -blah blih
+} -cleanup {
+ if {$tty ne ""} {
+ close $tty
}
-}
-proc iocmdSSHTDWN {} {
- uplevel {
- close $cli
- close $srv
- unset cli srv port
- rename iocmdSRV {}
+} -returnCodes error -result {bad option "-blah": should be one of -blocking, -buffering, -buffersize, -encoding, -eofchar, -translation, or -mode}
+test iocmd-8.19 {fconfigure command / win tty channel} -constraints {nonPortable win} -setup {
+ set tty ""
+} -body {
+ # might fail early if com1 is unavailable
+ set tty [open com1]
+ fconfigure $tty -blah blih
+} -cleanup {
+ if {$tty ne ""} {
+ close $tty
}
-}
-
-test iocmd-8.15.0 {fconfigure command / tcp channel} {socket macOnly} {
- iocmdSSETUP
- set r [list [catch {fconfigure $cli -blah} msg] $msg]
- iocmdSSHTDWN
- set r
-} {1 {bad option "-blah": should be one of -blocking, -buffering, -buffersize, -encoding, -eofchar, -translation, -error, -peername, or -sockname}}
-test iocmd-8.15.1 {fconfigure command / tcp channel} {socket unixOrPc} {
- iocmdSSETUP
- set r [list [catch {fconfigure $cli -blah} msg] $msg]
- iocmdSSHTDWN
- set r
-} {1 {bad option "-blah": should be one of -blocking, -buffering, -buffersize, -encoding, -eofchar, -translation, -peername, or -sockname}}
-test iocmd-8.16 {fconfigure command / tcp channel} {socket} {
- iocmdSSETUP
- set r [expr [lindex [fconfigure $cli -peername] 2]==$port]
- iocmdSSHTDWN
- set r
-} 1
-test iocmd-8.17 {fconfigure command / tcp channel} {nonPortable} {
- # It is possible that you don't get the connection reset by peer
- # error but rather a valid answer. depends of the tcp implementation
- iocmdSSETUP
- update;
- puts $cli "blah"; flush $cli; # that flush could/should fail too
- update;
- set r [catch {fconfigure $cli -peername} msg]
- iocmdSSHTDWN
- regsub -all {can([^:])+: } $r {} r;
- set r
-} 1
-test iocmd-8.18 {fconfigure command / unix tty channel} {nonPortable unixOnly} {
- # might fail if /dev/ttya is unavailable
- set tty [open /dev/ttya]
- set r [list [catch {fconfigure $tty -blah blih} msg] $msg];
- close $tty;
- set r;
-} {1 {bad option "-blah": should be one of -blocking, -buffering, -buffersize, -encoding, -eofchar, -translation, or -mode}}
-test iocmd-8.19 {fconfigure command / win tty channel} {nonPortable pcOnly} {
- # might fail if com1 is unavailable
- set tty [open com1]
- set r [list [catch {fconfigure $tty -blah blih} msg] $msg];
- close $tty;
- set r;
-} {1 {bad option "-blah": should be one of -blocking, -buffering, -buffersize, -encoding, -eofchar, -translation, -mode, or -pollinterval}}
+} -returnCodes error -result {bad option "-blah": should be one of -blocking, -buffering, -buffersize, -encoding, -eofchar, -translation, -mode, -handshake, -pollinterval, -sysbuffer, -timeout, -ttycontrol, or -xchar}
+# TODO: Test parsing of serial channel options (nonportable, since requires an
+# open channel to work with).
test iocmd-9.1 {eof command} {
- list [catch {eof} msg] $msg $errorCode
+ list [catch {eof} msg] $msg $::errorCode
} {1 {wrong # args: should be "eof channelId"} NONE}
test iocmd-9.2 {eof command} {
- list [catch {eof a b} msg] $msg $errorCode
+ list [catch {eof a b} msg] $msg $::errorCode
} {1 {wrong # args: should be "eof channelId"} NONE}
test iocmd-9.3 {eof command} {
catch {close file100}
- list [catch {eof file100} msg] $msg $errorCode
-} {1 {can not find channel named "file100"} NONE}
+ list [catch {eof file100} msg] $msg $::errorCode
+} {1 {can not find channel named "file100"} {TCL LOOKUP CHANNEL file100}}
# The tests for Tcl_ExecObjCmd are in exec.test
@@ -367,14 +370,17 @@ file delete $path(test5)
test iocmd-11.1 {I/O to command pipelines} {unixOrPc unixExecs} {
set f [open $path(test4) w]
close $f
- list [catch {open "| cat < $path(test4) > $path(test5)" w} msg] $msg $errorCode
+ list [catch {open "| cat < \"$path(test4)\" > \"$path(test5)\"" w} msg] $msg $::errorCode
} {1 {can't write input to command: standard input was redirected} NONE}
test iocmd-11.2 {I/O to command pipelines} {unixOrPc unixExecs} {
- list [catch {open "| echo > $path(test5)" r} msg] $msg $errorCode
+ list [catch {open "| echo > \"$path(test5)\"" r} msg] $msg $::errorCode
} {1 {can't read output from command: standard output was redirected} NONE}
test iocmd-11.3 {I/O to command pipelines} {unixOrPc unixExecs} {
- list [catch {open "| echo > $path(test5)" r+} msg] $msg $errorCode
+ list [catch {open "| echo > \"$path(test5)\"" r+} msg] $msg $::errorCode
} {1 {can't read output from command: standard output was redirected} NONE}
+test iocmd-11.4 {I/O to command pipelines} unixOrPc {
+ list [catch {open "| no_such_command_exists" rb} msg] $msg $::errorCode
+} {1 {couldn't execute "no_such_command_exists": no such file or directory} {POSIX ENOENT {no such file or directory}}}
test iocmd-12.1 {POSIX open access modes: RDONLY} {
file delete $path(test1)
@@ -399,7 +405,7 @@ test iocmd-12.3 {POSIX open access modes: WRONLY} -match regexp -body {
#
# Test 13.4 relies on assigning the same channel name twice.
#
-test iocmd-12.4 {POSIX open access modes: WRONLY} {unixOnly} {
+test iocmd-12.4 {POSIX open access modes: WRONLY} {unix} {
file delete $path(test3)
set f [open $path(test3) w]
fconfigure $f -eofchar {}
@@ -423,7 +429,7 @@ test iocmd-12.5 {POSIX open access modes: RDWR} -match regexp -body {
open $path(test3) RDWR
} -returnCodes error -result {(?i)couldn't open ".*test3": no such file or directory}
test iocmd-12.6 {POSIX open access modes: errors} {
- concat [catch {open $path(test3) "FOO \{BAR BAZ"} msg] $msg\n$errorInfo
+ concat [catch {open $path(test3) "FOO \{BAR BAZ"} msg] $msg\n$::errorInfo
} "1 unmatched open brace in list
unmatched open brace in list
while processing open access modes \"FOO {BAR BAZ\"
@@ -431,11 +437,36 @@ unmatched open brace in list
\"open \$path(test3) \"FOO \\{BAR BAZ\"\""
test iocmd-12.7 {POSIX open access modes: errors} {
list [catch {open $path(test3) {FOO BAR BAZ}} msg] $msg
-} {1 {invalid access mode "FOO": must be RDONLY, WRONLY, RDWR, APPEND, CREAT EXCL, NOCTTY, NONBLOCK, or TRUNC}}
+} {1 {invalid access mode "FOO": must be RDONLY, WRONLY, RDWR, APPEND, BINARY, CREAT, EXCL, NOCTTY, NONBLOCK, or TRUNC}}
test iocmd-12.8 {POSIX open access modes: errors} {
list [catch {open $path(test3) {TRUNC CREAT}} msg] $msg
} {1 {access mode must include either RDONLY, WRONLY, or RDWR}}
close [open $path(test3) w]
+test iocmd-12.9 {POSIX open access modes: BINARY} {
+ list [catch {open $path(test1) BINARY} msg] $msg
+} {1 {access mode must include either RDONLY, WRONLY, or RDWR}}
+test iocmd-12.10 {POSIX open access modes: BINARY} {
+ set f [open $path(test1) {WRONLY BINARY TRUNC}]
+ puts $f a
+ puts $f b
+ puts -nonewline $f c ;# contents are now 5 bytes: a\nb\nc
+ close $f
+ set f [open $path(test1) r]
+ fconfigure $f -translation binary
+ set result [string length [read $f]]
+ close $f
+ set result
+} 5
+test iocmd-12.11 {POSIX open access modes: BINARY} {
+ set f [open $path(test1) {WRONLY BINARY TRUNC}]
+ puts $f \u0248 ;# gets truncated to \u0048
+ close $f
+ set f [open $path(test1) r]
+ fconfigure $f -translation binary
+ set result [read -nonewline $f]
+ close $f
+ set result
+} \u0048
test iocmd-13.1 {errors in open command} {
list [catch {open} msg] $msg
@@ -453,13 +484,20 @@ test iocmd-13.5 {errors in open command} {
list [catch {open $path(test1) r+1} msg] $msg
} {1 {illegal access mode "r+1"}}
test iocmd-13.6 {errors in open command} {
- set msg [list [catch {open _non_existent_} msg] $msg $errorCode]
+ set msg [list [catch {open _non_existent_} msg] $msg $::errorCode]
regsub [file join {} _non_existent_] $msg "_non_existent_" msg
- string tolower $msg
+ string tolower $msg
} {1 {couldn't open "_non_existent_": no such file or directory} {posix enoent {no such file or directory}}}
-
-
-test iocmd-13.7.1 {open for append, a mode} -setup {
+test iocmd-13.7 {errors in open command} {
+ list [catch {open $path(test1) b} msg] $msg
+} {1 {illegal access mode "b"}}
+test iocmd-13.8 {errors in open command} {
+ list [catch {open $path(test1) rbb} msg] $msg
+} {1 {illegal access mode "rbb"}}
+test iocmd-13.9 {errors in open command} {
+ list [catch {open $path(test1) r++} msg] $msg
+} {1 {illegal access mode "r++"}}
+test iocmd-13.10.1 {open for append, a mode} -setup {
set log [makeFile {} out]
set chans {}
} -body {
@@ -474,8 +512,7 @@ test iocmd-13.7.1 {open for append, a mode} -setup {
# Ensure that channels are gone, even if body failed to do so
foreach ch $chans {catch {close $ch}}
} -result {0 1 2 3 4 5 6 7 8 9}
-
-test iocmd-13.7.2 {open for append, O_APPEND} -setup {
+test iocmd-13.10.2 {open for append, O_APPEND} -setup {
set log [makeFile {} out]
set chans {}
} -body {
@@ -491,12 +528,9 @@ test iocmd-13.7.2 {open for append, O_APPEND} -setup {
foreach ch $chans {catch {close $ch}}
} -result {0 1 2 3 4 5 6 7 8 9}
-
-
-
test iocmd-14.1 {file id parsing errors} {
- list [catch {eof gorp} msg] $msg $errorCode
-} {1 {can not find channel named "gorp"} NONE}
+ list [catch {eof gorp} msg] $msg $::errorCode
+} {1 {can not find channel named "gorp"} {TCL LOOKUP CHANNEL gorp}}
test iocmd-14.2 {file id parsing errors} {
list [catch {eof filex} msg] $msg
} {1 {can not find channel named "filex"}}
@@ -547,10 +581,8 @@ test iocmd-15.5 {Tcl_FcopyObjCmd} {fcopy} {
} {1 {wrong # args: should be "fcopy input output ?-size size? ?-command callback?"}}
set path(test2) [makeFile {} test2]
-
set f [open $path(test1) w]
close $f
-
set rfile [open $path(test1) r]
set wfile [open $path(test2) w]
@@ -576,10 +608,2938 @@ test iocmd-15.12 {Tcl_FcopyObjCmd} {fcopy} {
list [catch {fcopy $rfile $wfile -command bar -size foo} msg] $msg
} {1 {expected integer but got "foo"}}
-
close $rfile
close $wfile
+# ### ### ### ######### ######### #########
+## Testing the reflected channel.
+
+test iocmd-20.0 {chan, wrong#args} {
+ catch {chan} msg
+ set msg
+} {wrong # args: should be "chan subcommand ?argument ...?"}
+test iocmd-20.1 {chan, unknown method} {
+ catch {chan foo} msg
+ set msg
+} {unknown or ambiguous subcommand "foo": must be blocked, close, configure, copy, create, eof, event, flush, gets, names, pending, postevent, puts, read, seek, tell, or truncate}
+
+# --- --- --- --------- --------- ---------
+# chan create, and method "initalize"
+
+test iocmd-21.0 {chan create, wrong#args, not enough} {
+ catch {chan create} msg
+ set msg
+} {wrong # args: should be "chan create mode cmdprefix"}
+test iocmd-21.1 {chan create, wrong#args, too many} {
+ catch {chan create a b c} msg
+ set msg
+} {wrong # args: should be "chan create mode cmdprefix"}
+test iocmd-21.2 {chan create, invalid r/w mode, empty} {
+ proc foo {} {}
+ catch {chan create {} foo} msg
+ rename foo {}
+ set msg
+} {bad mode list: is empty}
+test iocmd-21.3 {chan create, invalid r/w mode, bad string} {
+ proc foo {} {}
+ catch {chan create {c} foo} msg
+ rename foo {}
+ set msg
+} {bad mode "c": must be read or write}
+test iocmd-21.4 {chan create, bad handler, not a list} {
+ catch {chan create {r w} "foo \{"} msg
+ set msg
+} {unmatched open brace in list}
+test iocmd-21.5 {chan create, bad handler, not a command} {
+ catch {chan create {r w} foo} msg
+ set msg
+} {invalid command name "foo"}
+test iocmd-21.6 {chan create, initialize failed, bad signature} {
+ proc foo {} {}
+ catch {chan create {r w} foo} msg
+ rename foo {}
+ set msg
+} {wrong # args: should be "foo"}
+test iocmd-21.7 {chan create, initialize failed, bad signature} {
+ proc foo {} {}
+ catch {chan create {r w} ::foo} msg
+ rename foo {}
+ set msg
+} {wrong # args: should be "::foo"}
+test iocmd-21.8 {chan create, initialize failed, bad result, not a list} -body {
+ proc foo {args} {return "\{"}
+ catch {chan create {r w} foo} msg
+ rename foo {}
+ set ::errorInfo
+} -match glob -result {chan handler "foo initialize" returned non-list: *}
+test iocmd-21.9 {chan create, initialize failed, bad result, not a list} -body {
+ proc foo {args} {return \{\{\}}
+ catch {chan create {r w} foo} msg
+ rename foo {}
+ set msg
+} -match glob -result {chan handler "foo initialize" returned non-list: *}
+test iocmd-21.10 {chan create, initialize failed, bad result, empty list} -body {
+ proc foo {args} {}
+ catch {chan create {r w} foo} msg
+ rename foo {}
+ set msg
+} -match glob -result {*all required methods*}
+test iocmd-21.11 {chan create, initialize failed, bad result, bogus method name} -body {
+ proc foo {args} {return 1}
+ catch {chan create {r w} foo} msg
+ rename foo {}
+ set msg
+} -match glob -result {*bad method "1": must be *}
+test iocmd-21.12 {chan create, initialize failed, bad result, bogus method name} -body {
+ proc foo {args} {return {a b c}}
+ catch {chan create {r w} foo} msg
+ rename foo {}
+ set msg
+} -match glob -result {*bad method "c": must be *}
+test iocmd-21.13 {chan create, initialize failed, bad result, required methods missing} -body {
+ proc foo {args} {return {initialize finalize}}
+ catch {chan create {r w} foo} msg
+ rename foo {}
+ set msg
+} -match glob -result {*all required methods*}
+test iocmd-21.14 {chan create, initialize failed, bad result, mode/handler mismatch} -body {
+ proc foo {args} {return {initialize finalize watch read}}
+ catch {chan create {r w} foo} msg
+ rename foo {}
+ set msg
+} -match glob -result {*lacks a "write" method}
+test iocmd-21.15 {chan create, initialize failed, bad result, mode/handler mismatch} -body {
+ proc foo {args} {return {initialize finalize watch write}}
+ catch {chan create {r w} foo} msg
+ rename foo {}
+ set msg
+} -match glob -result {*lacks a "read" method}
+test iocmd-21.16 {chan create, initialize failed, bad result, cget(all) mismatch} -body {
+ proc foo {args} {return {initialize finalize watch cget write read}}
+ catch {chan create {r w} foo} msg
+ rename foo {}
+ set msg
+} -match glob -result {*supports "cget" but not "cgetall"}
+test iocmd-21.17 {chan create, initialize failed, bad result, cget(all) mismatch} -body {
+ proc foo {args} {return {initialize finalize watch cgetall read write}}
+ catch {chan create {r w} foo} msg
+ rename foo {}
+ set msg
+} -match glob -result {*supports "cgetall" but not "cget"}
+test iocmd-21.18 {chan create, initialize ok, creates channel} -match glob -body {
+ proc foo {args} {
+ global res
+ lappend res $args
+ if {[lindex $args 0] ne "initialize"} {return}
+ return {initialize finalize watch read write}
+ }
+ set res {}
+ lappend res [file channel rc*]
+ lappend res [chan create {r w} foo]
+ lappend res [close [lindex $res end]]
+ lappend res [file channel rc*]
+ rename foo {}
+ set res
+} -result {{} {initialize rc* {read write}} rc* {finalize rc*} {} {}}
+test iocmd-21.19 {chan create, init failure -> no channel, no finalize} -match glob -body {
+ proc foo {args} {
+ global res
+ lappend res $args
+ return {}
+ }
+ set res {}
+ lappend res [file channel rc*]
+ lappend res [catch {chan create {r w} foo} msg]
+ lappend res $msg
+ lappend res [file channel rc*]
+ rename foo {}
+ set res
+} -result {{} {initialize rc* {read write}} 1 {*all required methods*} {}}
+
+# --- --- --- --------- --------- ---------
+# Helper commands to record the arguments to handler methods.
+
+# Stored in a script so that the threads and interpreters needing this
+# code do not need their own copy but can access this variable.
+
+set helperscript {
+
+proc note {item} {global res; lappend res $item; return}
+proc track {} {upvar args item; note $item; return}
+proc notes {items} {foreach i $items {note $i}}
+# This forces the return options to be in the order that the test expects!
+proc noteOpts opts {global res; lappend res [dict merge {
+ -code !?! -level !?! -errorcode !?! -errorline !?! -errorinfo !?!
+} $opts]; return}
+
+# Helper command, canned result for 'initialize' method.
+# Gets the optional methods as arguments. Use return features
+# to post the result higher up.
+
+proc init {args} {
+ lappend args initialize finalize watch read write
+ return -code return $args
+}
+proc oninit {args} {
+ upvar args hargs
+ if {[lindex $hargs 0] ne "initialize"} {return}
+ lappend args initialize finalize watch read write
+ return -code return $args
+}
+proc onfinal {} {
+ upvar args hargs
+ if {[lindex $hargs 0] ne "finalize"} {return}
+ return -code return ""
+}
+}
+
+# Set everything up in the main thread.
+eval $helperscript
+
+# --- --- --- --------- --------- ---------
+# method finalize
+
+test iocmd-22.1 {chan finalize, handler destruction has no effect on channel} -match glob -body {
+ set res {}
+ proc foo {args} {track; oninit; return}
+ note [set c [chan create {r w} foo]]
+ rename foo {}
+ note [file channels rc*]
+ note [catch {close $c} msg]; note $msg
+ note [file channels rc*]
+ set res
+} -result {{initialize rc* {read write}} rc* rc* 1 {invalid command name "foo"} {}}
+test iocmd-22.2 {chan finalize, for close} -match glob -body {
+ set res {}
+ proc foo {args} {track; oninit; return {}}
+ note [set c [chan create {r w} foo]]
+ close $c
+ # Close deleted the channel.
+ note [file channels rc*]
+ # Channel destruction does not kill handler command!
+ note [info command foo]
+ rename foo {}
+ set res
+} -result {{initialize rc* {read write}} rc* {finalize rc*} {} foo}
+test iocmd-22.3 {chan finalize, for close, error, close error} -match glob -body {
+ set res {}
+ proc foo {args} {track; oninit; return -code error 5}
+ note [set c [chan create {r w} foo]]
+ note [catch {close $c} msg]; note $msg
+ # Channel is gone despite error.
+ note [file channels rc*]
+ rename foo {}
+ set res
+} -result {{initialize rc* {read write}} rc* {finalize rc*} 1 5 {}}
+test iocmd-22.4 {chan finalize, for close, error, close error} -match glob -body {
+ set res {}
+ proc foo {args} {track; oninit; error FOO}
+ note [set c [chan create {r w} foo]]
+ note [catch {close $c} msg]; note $msg; note $::errorInfo
+ rename foo {}
+ set res
+} -result {{initialize rc* {read write}} rc* {finalize rc*} 1 FOO {FOO
+*"close $c"}}
+test iocmd-22.5 {chan finalize, for close, arbitrary result, ignored} -match glob -body {
+ set res {}
+ proc foo {args} {track; oninit; return SOMETHING}
+ note [set c [chan create {r w} foo]]
+ note [catch {close $c} msg]; note $msg
+ rename foo {}
+ set res
+} -result {{initialize rc* {read write}} rc* {finalize rc*} 0 {}}
+test iocmd-22.6 {chan finalize, for close, break, close error} -match glob -body {
+ set res {}
+ proc foo {args} {track; oninit; return -code 3}
+ note [set c [chan create {r w} foo]]
+ note [catch {close $c} msg]; note $msg
+ rename foo {}
+ set res
+} -result {{initialize rc* {read write}} rc* {finalize rc*} 1 *bad code*}
+test iocmd-22.7 {chan finalize, for close, continue, close error} -match glob -body {
+ set res {}
+ proc foo {args} {track; oninit; return -code 4}
+ note [set c [chan create {r w} foo]]
+ note [catch {close $c} msg]; note $msg
+ rename foo {}
+ set res
+} -result {{initialize rc* {read write}} rc* {finalize rc*} 1 *bad code*}
+test iocmd-22.8 {chan finalize, for close, custom code, close error} -match glob -body {
+ set res {}
+ proc foo {args} {track; oninit; return -code 777 BANG}
+ note [set c [chan create {r w} foo]]
+ note [catch {close $c} msg]; note $msg
+ rename foo {}
+ set res
+} -result {{initialize rc* {read write}} rc* {finalize rc*} 1 *bad code*}
+test iocmd-22.9 {chan finalize, for close, ignore level, close error} -match glob -setup {
+ set res {}
+} -body {
+ proc foo {args} {track; oninit; return -level 5 -code 777 BANG}
+ note [set c [chan create {r w} foo]]
+ note [catch {close $c} msg opt]; note $msg; noteOpts $opt
+ return $res
+} -cleanup {
+ rename foo {}
+} -result {{initialize rc* {read write}} rc* {finalize rc*} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "finalize"*}}
+
+# --- === *** ###########################
+# method read
+
+test iocmd-23.1 {chan read, regular data return} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit; onfinal; track
+ return snarf
+ }
+ set c [chan create {r w} foo]
+ note [read $c 10]
+ close $c
+ rename foo {}
+ set res
+} -result {{read rc* 4096} {read rc* 4096} snarfsnarf}
+test iocmd-23.2 {chan read, bad data return, to much} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit; onfinal; track
+ return [string repeat snarf 1000]
+ }
+ set c [chan create {r w} foo]
+ note [catch {read $c 2} msg]; note $msg
+ close $c
+ rename foo {}
+ set res
+} -result {{read rc* 4096} 1 {read delivered more than requested}}
+test iocmd-23.3 {chan read, for non-readable channel} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit; onfinal; track; note MUST_NOT_HAPPEN
+ }
+ set c [chan create {w} foo]
+ note [catch {read $c 2} msg]; note $msg
+ close $c
+ rename foo {}
+ set res
+} -result {1 {channel "rc*" wasn't opened for reading}}
+test iocmd-23.4 {chan read, error return} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit; onfinal; track
+ return -code error BOOM!
+ }
+ set c [chan create {r w} foo]
+ note [catch {read $c 2} msg]; note $msg
+ close $c
+ rename foo {}
+ set res
+} -result {{read rc* 4096} 1 BOOM!}
+test iocmd-23.5 {chan read, break return is error} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit; onfinal; track
+ return -code break BOOM!
+ }
+ set c [chan create {r w} foo]
+ note [catch {read $c 2} msg]; note $msg
+ close $c
+ rename foo {}
+ set res
+} -result {{read rc* 4096} 1 *bad code*}
+test iocmd-23.6 {chan read, continue return is error} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit; onfinal; track
+ return -code continue BOOM!
+ }
+ set c [chan create {r w} foo]
+ note [catch {read $c 2} msg]; note $msg
+ close $c
+ rename foo {}
+ set res
+} -result {{read rc* 4096} 1 *bad code*}
+test iocmd-23.7 {chan read, custom return is error} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit; onfinal; track
+ return -code 777 BOOM!
+ }
+ set c [chan create {r w} foo]
+ note [catch {read $c 2} msg]; note $msg
+ close $c
+ rename foo {}
+ set res
+} -result {{read rc* 4096} 1 *bad code*}
+test iocmd-23.8 {chan read, level is squashed} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit; onfinal; track
+ return -level 55 -code 777 BOOM!
+ }
+ set c [chan create {r w} foo]
+ note [catch {read $c 2} msg opt]; note $msg; noteOpts $opt
+ close $c
+ rename foo {}
+ set res
+} -result {{read rc* 4096} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "read"*}}
+test iocmd-23.9 {chan read, no data means eof} -match glob -setup {
+ set res {}
+ proc foo {args} {
+ oninit; onfinal; track
+ return ""
+ }
+ set c [chan create {r w} foo]
+} -body {
+ note [read $c 2]
+ note [eof $c]
+ set res
+} -cleanup {
+ close $c
+ rename foo {}
+ unset res
+} -result {{read rc* 4096} {} 1}
+test iocmd-23.10 {chan read, EAGAIN means no data, yet no eof either} -match glob -setup {
+ set res {}
+ proc foo {args} {
+ oninit; onfinal; track
+ error EAGAIN
+ }
+ set c [chan create {r w} foo]
+} -body {
+ note [read $c 2]
+ note [eof $c]
+ set res
+} -cleanup {
+ close $c
+ rename foo {}
+ unset res
+} -result {{read rc* 4096} {} 0}
+
+# --- === *** ###########################
+# method write
+
+test iocmd-24.1 {chan write, regular write} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit; onfinal; track
+ set written [string length [lindex $args 2]]
+ note $written
+ return $written
+ }
+ set c [chan create {r w} foo]
+ puts -nonewline $c snarf; flush $c
+ close $c
+ rename foo {}
+ set res
+} -result {{write rc* snarf} 5}
+test iocmd-24.2 {chan write, partial write is ok} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit; onfinal; track
+ set written [string length [lindex $args 2]]
+ if {$written > 10} {set written [expr {$written / 2}]}
+ note $written
+ return $written
+ }
+ set c [chan create {r w} foo]
+ puts -nonewline $c snarfsnarfsnarf; flush $c
+ close $c
+ rename foo {}
+ set res
+} -result {{write rc* snarfsnarfsnarf} 7 {write rc* arfsnarf} 8}
+test iocmd-24.3 {chan write, failed write} -match glob -body {
+ set res {}
+ proc foo {args} {oninit; onfinal; track; note -1; return -1}
+ set c [chan create {r w} foo]
+ puts -nonewline $c snarfsnarfsnarf; flush $c
+ close $c
+ rename foo {}
+ set res
+} -result {{write rc* snarfsnarfsnarf} -1}
+test iocmd-24.4 {chan write, non-writable channel} -match glob -body {
+ set res {}
+ proc foo {args} {oninit; onfinal; track; note MUST_NOT_HAPPEN; return}
+ set c [chan create {r} foo]
+ note [catch {puts -nonewline $c snarfsnarfsnarf; flush $c} msg]; note $msg
+ close $c
+ rename foo {}
+ set res
+} -result {1 {channel "rc*" wasn't opened for writing}}
+test iocmd-24.5 {chan write, bad result, more written than data} -match glob -body {
+ set res {}
+ proc foo {args} {oninit; onfinal; track; return 10000}
+ set c [chan create {r w} foo]
+ note [catch {puts -nonewline $c snarf; flush $c} msg]; note $msg
+ close $c
+ rename foo {}
+ set res
+} -result {{write rc* snarf} 1 {write wrote more than requested}}
+test iocmd-24.6 {chan write, bad result, zero-length write} -match glob -body {
+ set res {}
+ proc foo {args} {oninit; onfinal; track; return 0}
+ set c [chan create {r w} foo]
+ note [catch {puts -nonewline $c snarf; flush $c} msg]; note $msg
+ close $c
+ rename foo {}
+ set res
+} -result {{write rc* snarf} 1 {write wrote nothing}}
+test iocmd-24.7 {chan write, failed write, error return} -match glob -body {
+ set res {}
+ proc foo {args} {oninit; onfinal; track; return -code error BOOM!}
+ set c [chan create {r w} foo]
+ note [catch {puts -nonewline $c snarfsnarfsnarf; flush $c} msg]
+ note $msg
+ close $c
+ rename foo {}
+ set res
+} -result {{write rc* snarfsnarfsnarf} 1 BOOM!}
+test iocmd-24.8 {chan write, failed write, error return} -match glob -body {
+ set res {}
+ proc foo {args} {oninit; onfinal; track; error BOOM!}
+ set c [chan create {r w} foo]
+ notes [catch {puts -nonewline $c snarfsnarfsnarf; flush $c} msg]
+ note $msg
+ close $c
+ rename foo {}
+ set res
+} -result {{write rc* snarfsnarfsnarf} 1 BOOM!}
+test iocmd-24.9 {chan write, failed write, break return is error} -match glob -body {
+ set res {}
+ proc foo {args} {oninit; onfinal; track; return -code break BOOM!}
+ set c [chan create {r w} foo]
+ note [catch {puts -nonewline $c snarfsnarfsnarf; flush $c} msg]
+ note $msg
+ close $c
+ rename foo {}
+ set res
+} -result {{write rc* snarfsnarfsnarf} 1 *bad code*}
+test iocmd-24.10 {chan write, failed write, continue return is error} -match glob -body {
+ set res {}
+ proc foo {args} {oninit; onfinal; track; return -code continue BOOM!}
+ set c [chan create {r w} foo]
+ note [catch {puts -nonewline $c snarfsnarfsnarf; flush $c} msg]
+ note $msg
+ close $c
+ rename foo {}
+ set res
+} -result {{write rc* snarfsnarfsnarf} 1 *bad code*}
+test iocmd-24.11 {chan write, failed write, custom return is error} -match glob -body {
+ set res {}
+ proc foo {args} {oninit; onfinal; track; return -code 777 BOOM!}
+ set c [chan create {r w} foo]
+ note [catch {puts -nonewline $c snarfsnarfsnarf; flush $c} msg]
+ note $msg
+ close $c
+ rename foo {}
+ set res
+} -result {{write rc* snarfsnarfsnarf} 1 *bad code*}
+test iocmd-24.12 {chan write, failed write, non-numeric return is error} -match glob -body {
+ set res {}
+ proc foo {args} {oninit; onfinal; track; return BANG}
+ set c [chan create {r w} foo]
+ note [catch {puts -nonewline $c snarfsnarfsnarf; flush $c} msg]
+ note $msg
+ close $c
+ rename foo {}
+ set res
+} -result {{write rc* snarfsnarfsnarf} 1 {expected integer but got "BANG"}}
+test iocmd-24.13 {chan write, failed write, level is ignored} -match glob -body {
+ set res {}
+ proc foo {args} {oninit; onfinal; track; return -level 55 -code 777 BOOM!}
+ set c [chan create {r w} foo]
+ note [catch {puts -nonewline $c snarfsnarfsnarf; flush $c} msg opt]
+ note $msg
+ noteOpts $opt
+ close $c
+ rename foo {}
+ set res
+} -result {{write rc* snarfsnarfsnarf} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "write"*}}
+test iocmd-24.14 {chan write, no EAGAIN means that writing is allowed at this time, bug 2936225} -match glob -setup {
+ set res {}
+ proc foo {args} {
+ oninit; onfinal; track
+ return 3
+ }
+ set c [chan create {r w} foo]
+} -body {
+ note [puts -nonewline $c ABC ; flush $c]
+ set res
+} -cleanup {
+ close $c
+ rename foo {}
+ unset res
+} -result {{write rc* ABC} {}}
+test iocmd-24.15 {chan write, EAGAIN means that writing is not allowed at this time, bug 2936225} -match glob -setup {
+ set res {}
+ proc foo {args} {
+ oninit; onfinal; track
+ # Note: The EAGAIN signals that the channel cannot accept
+ # write requests right now, this in turn causes the IO core to
+ # request the generation of writable events (see expected
+ # result below, and compare to case 24.14 above).
+ error EAGAIN
+ }
+ set c [chan create {r w} foo]
+} -body {
+ note [puts -nonewline $c ABC ; flush $c]
+ set res
+} -cleanup {
+ close $c
+ rename foo {}
+ unset res
+} -result {{write rc* ABC} {watch rc* write} {}}
+
+# --- === *** ###########################
+# method cgetall
+
+test iocmd-25.1 {chan configure, cgetall, standard options} -match glob -body {
+ set res {}
+ proc foo {args} {oninit; onfinal; track; note MUST_NOT_HAPPEN; return}
+ set c [chan create {r w} foo]
+ note [fconfigure $c]
+ close $c
+ rename foo {}
+ set res
+} -result {{-blocking 1 -buffering full -buffersize 4096 -encoding * -eofchar {{} {}} -translation {auto *}}}
+test iocmd-25.2 {chan configure, cgetall, no options} -match glob -body {
+ set res {}
+ proc foo {args} {oninit cget cgetall; onfinal; track; return ""}
+ set c [chan create {r w} foo]
+ note [fconfigure $c]
+ close $c
+ rename foo {}
+ set res
+} -result {{cgetall rc*} {-blocking 1 -buffering full -buffersize 4096 -encoding * -eofchar {{} {}} -translation {auto *}}}
+test iocmd-25.3 {chan configure, cgetall, regular result} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit cget cgetall; onfinal; track
+ return "-bar foo -snarf x"
+ }
+ set c [chan create {r w} foo]
+ note [fconfigure $c]
+ close $c
+ rename foo {}
+ set res
+} -result {{cgetall rc*} {-blocking 1 -buffering full -buffersize 4096 -encoding * -eofchar {{} {}} -translation {auto *} -bar foo -snarf x}}
+test iocmd-25.4 {chan configure, cgetall, bad result, list of uneven length} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit cget cgetall; onfinal; track
+ return "-bar"
+ }
+ set c [chan create {r w} foo]
+ note [catch {fconfigure $c} msg]; note $msg
+ close $c
+ rename foo {}
+ set res
+} -result {{cgetall rc*} 1 {Expected list with even number of elements, got 1 element instead}}
+test iocmd-25.5 {chan configure, cgetall, bad result, not a list} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit cget cgetall; onfinal; track
+ return "\{"
+ }
+ set c [chan create {r w} foo]
+ note [catch {fconfigure $c} msg]; note $msg
+ close $c
+ rename foo {}
+ set res
+} -result {{cgetall rc*} 1 {unmatched open brace in list}}
+test iocmd-25.6 {chan configure, cgetall, error return} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit cget cgetall; onfinal; track
+ return -code error BOOM!
+ }
+ set c [chan create {r w} foo]
+ note [catch {fconfigure $c} msg]; note $msg
+ close $c
+ rename foo {}
+ set res
+} -result {{cgetall rc*} 1 BOOM!}
+test iocmd-25.7 {chan configure, cgetall, break return is error} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit cget cgetall; onfinal; track
+ return -code break BOOM!
+ }
+ set c [chan create {r w} foo]
+ note [catch {fconfigure $c} msg]; note $msg
+ close $c
+ rename foo {}
+ set res
+} -result {{cgetall rc*} 1 *bad code*}
+test iocmd-25.8 {chan configure, cgetall, continue return is error} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit cget cgetall; onfinal; track
+ return -code continue BOOM!
+ }
+ set c [chan create {r w} foo]
+ note [catch {fconfigure $c} msg]; note $msg
+ close $c
+ rename foo {}
+ set res
+} -result {{cgetall rc*} 1 *bad code*}
+test iocmd-25.9 {chan configure, cgetall, custom return is error} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit cget cgetall; onfinal; track
+ return -code 777 BOOM!
+ }
+ set c [chan create {r w} foo]
+ note [catch {fconfigure $c} msg]; note $msg
+ close $c
+ rename foo {}
+ set res
+} -result {{cgetall rc*} 1 *bad code*}
+test iocmd-25.10 {chan configure, cgetall, level is ignored} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit cget cgetall; onfinal; track
+ return -level 55 -code 777 BANG
+ }
+ set c [chan create {r w} foo]
+ note [catch {fconfigure $c} msg opt]; note $msg; noteOpts $opt
+ close $c
+ rename foo {}
+ set res
+} -result {{cgetall rc*} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "cgetall"*}}
+
+# --- === *** ###########################
+# method configure
+
+test iocmd-26.1 {chan configure, set standard option} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit configure; onfinal; track; note MUST_NOT_HAPPEN; return
+ }
+ set c [chan create {r w} foo]
+ note [fconfigure $c -translation lf]
+ close $c
+ rename foo {}
+ set res
+} -result {{}}
+test iocmd-26.2 {chan configure, set option, error return} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit configure; onfinal; track
+ return -code error BOOM!
+ }
+ set c [chan create {r w} foo]
+ note [catch {fconfigure $c -rc-foo bar} msg]; note $msg
+ close $c
+ rename foo {}
+ set res
+} -result {{configure rc* -rc-foo bar} 1 BOOM!}
+test iocmd-26.3 {chan configure, set option, ok return} -match glob -body {
+ set res {}
+ proc foo {args} {oninit configure; onfinal; track; return}
+ set c [chan create {r w} foo]
+ note [fconfigure $c -rc-foo bar]
+ close $c
+ rename foo {}
+ set res
+} -result {{configure rc* -rc-foo bar} {}}
+test iocmd-26.4 {chan configure, set option, break return is error} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit configure; onfinal; track
+ return -code break BOOM!
+ }
+ set c [chan create {r w} foo]
+ note [catch {fconfigure $c -rc-foo bar} msg]; note $msg
+ close $c
+ rename foo {}
+ set res
+} -result {{configure rc* -rc-foo bar} 1 *bad code*}
+test iocmd-26.5 {chan configure, set option, continue return is error} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit configure; onfinal; track
+ return -code continue BOOM!
+ }
+ set c [chan create {r w} foo]
+ note [catch {fconfigure $c -rc-foo bar} msg]; note $msg
+ close $c
+ rename foo {}
+ set res
+} -result {{configure rc* -rc-foo bar} 1 *bad code*}
+test iocmd-26.6 {chan configure, set option, custom return is error} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit configure; onfinal; track
+ return -code 444 BOOM!
+ }
+ set c [chan create {r w} foo]
+ note [catch {fconfigure $c -rc-foo bar} msg]; note $msg
+ close $c
+ rename foo {}
+ set res
+} -result {{configure rc* -rc-foo bar} 1 *bad code*}
+test iocmd-26.7 {chan configure, set option, level is ignored} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit configure; onfinal; track
+ return -level 55 -code 444 BANG
+ }
+ set c [chan create {r w} foo]
+ note [catch {fconfigure $c -rc-foo bar} msg opt]; note $msg; noteOpts $opt
+ close $c
+ rename foo {}
+ set res
+} -result {{configure rc* -rc-foo bar} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "configure"*}}
+
+# --- === *** ###########################
+# method cget
+
+test iocmd-27.1 {chan configure, get option, ok return} -match glob -body {
+ set res {}
+ proc foo {args} {oninit cget cgetall; onfinal; track; return foo}
+ set c [chan create {r w} foo]
+ note [fconfigure $c -rc-foo]
+ close $c
+ rename foo {}
+ set res
+} -result {{cget rc* -rc-foo} foo}
+test iocmd-27.2 {chan configure, get option, error return} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit cget cgetall; onfinal; track
+ return -code error BOOM!
+ }
+ set c [chan create {r w} foo]
+ note [catch {fconfigure $c -rc-foo} msg]; note $msg
+ close $c
+ rename foo {}
+ set res
+} -result {{cget rc* -rc-foo} 1 BOOM!}
+test iocmd-27.3 {chan configure, get option, break return is error} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit cget cgetall; onfinal; track
+ return -code error BOOM!
+ }
+ set c [chan create {r w} foo]
+ note [catch {fconfigure $c -rc-foo} msg]; note $msg
+ close $c
+ rename foo {}
+ set res
+} -result {{cget rc* -rc-foo} 1 BOOM!}
+test iocmd-27.4 {chan configure, get option, continue return is error} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit cget cgetall; onfinal; track
+ return -code continue BOOM!
+ }
+ set c [chan create {r w} foo]
+ note [catch {fconfigure $c -rc-foo} msg]; note $msg
+ close $c
+ rename foo {}
+ set res
+} -result {{cget rc* -rc-foo} 1 *bad code*}
+test iocmd-27.5 {chan configure, get option, custom return is error} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit cget cgetall; onfinal; track
+ return -code 333 BOOM!
+ }
+ set c [chan create {r w} foo]
+ note [catch {fconfigure $c -rc-foo} msg]; note $msg
+ close $c
+ rename foo {}
+ set res
+} -result {{cget rc* -rc-foo} 1 *bad code*}
+test iocmd-27.6 {chan configure, get option, level is ignored} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit cget cgetall; onfinal; track
+ return -level 77 -code 333 BANG
+ }
+ set c [chan create {r w} foo]
+ note [catch {fconfigure $c -rc-foo} msg opt]; note $msg; noteOpts $opt
+ close $c
+ rename foo {}
+ set res
+} -result {{cget rc* -rc-foo} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "cget"*}}
+
+# --- === *** ###########################
+# method seek
+
+test iocmd-28.1 {chan tell, not supported by handler} -match glob -body {
+ set res {}
+ proc foo {args} {oninit; onfinal; track; note MUST_NOT_HAPPEN; return}
+ set c [chan create {r w} foo]
+ note [tell $c]
+ close $c
+ rename foo {}
+ set res
+} -result {-1}
+test iocmd-28.2 {chan tell, error return} -match glob -body {
+ set res {}
+ proc foo {args} {oninit seek; onfinal; track; return -code error BOOM!}
+ set c [chan create {r w} foo]
+ note [catch {tell $c} msg]; note $msg
+ close $c
+ rename foo {}
+ set res
+} -result {{seek rc* 0 current} 1 BOOM!}
+test iocmd-28.3 {chan tell, break return is error} -match glob -body {
+ set res {}
+ proc foo {args} {oninit seek; onfinal; track; return -code break BOOM!}
+ set c [chan create {r w} foo]
+ note [catch {tell $c} msg]; note $msg
+ close $c
+ rename foo {}
+ set res
+} -result {{seek rc* 0 current} 1 *bad code*}
+test iocmd-28.4 {chan tell, continue return is error} -match glob -body {
+ set res {}
+ proc foo {args} {oninit seek; onfinal; track; return -code continue BOOM!}
+ set c [chan create {r w} foo]
+ note [catch {tell $c} msg]; note $msg
+ close $c
+ rename foo {}
+ set res
+} -result {{seek rc* 0 current} 1 *bad code*}
+test iocmd-28.5 {chan tell, custom return is error} -match glob -body {
+ set res {}
+ proc foo {args} {oninit seek; onfinal; track; return -code 222 BOOM!}
+ set c [chan create {r w} foo]
+ note [catch {tell $c} msg]; note $msg
+ close $c
+ rename foo {}
+ set res
+} -result {{seek rc* 0 current} 1 *bad code*}
+test iocmd-28.6 {chan tell, level is ignored} -match glob -body {
+ set res {}
+ proc foo {args} {oninit seek; onfinal; track; return -level 11 -code 222 BANG}
+ set c [chan create {r w} foo]
+ note [catch {tell $c} msg opt]; note $msg; noteOpts $opt
+ close $c
+ rename foo {}
+ set res
+} -result {{seek rc* 0 current} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "seek"*}}
+test iocmd-28.7 {chan tell, regular return} -match glob -body {
+ set res {}
+ proc foo {args} {oninit seek; onfinal; track; return 88}
+ set c [chan create {r w} foo]
+ note [tell $c]
+ close $c
+ rename foo {}
+ set res
+} -result {{seek rc* 0 current} 88}
+test iocmd-28.8 {chan tell, negative return} -match glob -body {
+ set res {}
+ proc foo {args} {oninit seek; onfinal; track; return -1}
+ set c [chan create {r w} foo]
+ note [catch {tell $c} msg]; note $msg
+ close $c
+ rename foo {}
+ set res
+} -result {{seek rc* 0 current} 1 {Tried to seek before origin}}
+test iocmd-28.9 {chan tell, string return} -match glob -body {
+ set res {}
+ proc foo {args} {oninit seek; onfinal; track; return BOGUS}
+ set c [chan create {r w} foo]
+ note [catch {tell $c} msg]; note $msg
+ close $c
+ rename foo {}
+ set res
+} -result {{seek rc* 0 current} 1 {expected integer but got "BOGUS"}}
+test iocmd-28.10 {chan seek, not supported by handler} -match glob -body {
+ set res {}
+ proc foo {args} {oninit; onfinal; track; note MUST_NOT_HAPPEN; return}
+ set c [chan create {r w} foo]
+ note [catch {seek $c 0 start} msg]; note $msg
+ close $c
+ rename foo {}
+ set res
+} -result {1 {error during seek on "rc*": invalid argument}}
+test iocmd-28.11 {chan seek, error return} -match glob -body {
+ set res {}
+ proc foo {args} {oninit seek; onfinal; track; return -code error BOOM!}
+ set c [chan create {r w} foo]
+ note [catch {seek $c 0 start} msg]; note $msg
+ close $c
+ rename foo {}
+ set res
+} -result {{seek rc* 0 start} 1 BOOM!}
+test iocmd-28.12 {chan seek, break return is error} -match glob -body {
+ set res {}
+ proc foo {args} {oninit seek; onfinal; track; return -code break BOOM!}
+ set c [chan create {r w} foo]
+ note [catch {seek $c 0 start} msg]; note $msg
+ close $c
+ rename foo {}
+ set res
+} -result {{seek rc* 0 start} 1 *bad code*}
+test iocmd-28.13 {chan seek, continue return is error} -match glob -body {
+ set res {}
+ proc foo {args} {oninit seek; onfinal; track; return -code continue BOOM!}
+ set c [chan create {r w} foo]
+ note [catch {seek $c 0 start} msg]; note $msg
+ close $c
+ rename foo {}
+ set res
+} -result {{seek rc* 0 start} 1 *bad code*}
+test iocmd-28.14 {chan seek, custom return is error} -match glob -body {
+ set res {}
+ proc foo {args} {oninit seek; onfinal; track; return -code 99 BOOM!}
+ set c [chan create {r w} foo]
+ note [catch {seek $c 0 start} msg]; note $msg
+ close $c
+ rename foo {}
+ set res
+} -result {{seek rc* 0 start} 1 *bad code*}
+test iocmd-28.15 {chan seek, level is ignored} -match glob -body {
+ set res {}
+ proc foo {args} {oninit seek; onfinal; track; return -level 33 -code 99 BANG}
+ set c [chan create {r w} foo]
+ note [catch {seek $c 0 start} msg opt]; note $msg; noteOpts $opt
+ close $c
+ rename foo {}
+ set res
+} -result {{seek rc* 0 start} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "seek"*}}
+test iocmd-28.16 {chan seek, bogus return, negative location} -match glob -body {
+ set res {}
+ proc foo {args} {oninit seek; onfinal; track; return -45}
+ set c [chan create {r w} foo]
+ note [catch {seek $c 0 start} msg]; note $msg
+ close $c
+ rename foo {}
+ set res
+} -result {{seek rc* 0 start} 1 {Tried to seek before origin}}
+test iocmd-28.17 {chan seek, bogus return, string return} -match glob -body {
+ set res {}
+ proc foo {args} {oninit seek; onfinal; track; return BOGUS}
+ set c [chan create {r w} foo]
+ note [catch {seek $c 0 start} msg]; note $msg
+ close $c
+ rename foo {}
+ set res
+} -result {{seek rc* 0 start} 1 {expected integer but got "BOGUS"}}
+test iocmd-28.18 {chan seek, ok result} -match glob -body {
+ set res {}
+ proc foo {args} {oninit seek; onfinal; track; return 23}
+ set c [chan create {r w} foo]
+ note [seek $c 0 current]
+ close $c
+ rename foo {}
+ set res
+} -result {{seek rc* 0 current} {}}
+foreach {testname code} {
+ iocmd-28.19.0 start
+ iocmd-28.19.1 current
+ iocmd-28.19.2 end
+} {
+ test $testname "chan seek, base conversion, $code" -match glob -body {
+ set res {}
+ proc foo {args} {oninit seek; onfinal; track; return 0}
+ set c [chan create {r w} foo]
+ note [seek $c 0 $code]
+ close $c
+ rename foo {}
+ set res
+ } -result [list [list seek rc* 0 $code] {}]
+}
+
+# --- === *** ###########################
+# method blocking
+
+test iocmd-29.1 {chan blocking, no handler support} -match glob -body {
+ set res {}
+ proc foo {args} {oninit; onfinal; track; note MUST_NOT_HAPPEN; return}
+ set c [chan create {r w} foo]
+ note [fconfigure $c -blocking]
+ close $c
+ rename foo {}
+ set res
+} -result {1}
+test iocmd-29.2 {chan blocking, no handler support} -match glob -body {
+ set res {}
+ proc foo {args} {oninit; onfinal; track; note MUST_NOT_HAPPEN; return}
+ set c [chan create {r w} foo]
+ note [fconfigure $c -blocking 0]
+ note [fconfigure $c -blocking]
+ close $c
+ rename foo {}
+ set res
+} -result {{} 0}
+test iocmd-29.3 {chan blocking, retrieval, handler support} -match glob -body {
+ set res {}
+ proc foo {args} {oninit blocking; onfinal; track; note MUST_NOT_HAPPEN; return}
+ set c [chan create {r w} foo]
+ note [fconfigure $c -blocking]
+ close $c
+ rename foo {}
+ set res
+} -result {1}
+test iocmd-29.4 {chan blocking, resetting, handler support} -match glob -body {
+ set res {}
+ proc foo {args} {oninit blocking; onfinal; track; return}
+ set c [chan create {r w} foo]
+ note [fconfigure $c -blocking 0]
+ note [fconfigure $c -blocking]
+ close $c
+ rename foo {}
+ set res
+} -result {{blocking rc* 0} {} 0}
+test iocmd-29.5 {chan blocking, setting, handler support} -match glob -body {
+ set res {}
+ proc foo {args} {oninit blocking; onfinal; track; return}
+ set c [chan create {r w} foo]
+ note [fconfigure $c -blocking 1]
+ note [fconfigure $c -blocking]
+ close $c
+ rename foo {}
+ set res
+} -result {{blocking rc* 1} {} 1}
+test iocmd-29.6 {chan blocking, error return} -match glob -body {
+ set res {}
+ proc foo {args} {oninit blocking; onfinal; track; error BOOM!}
+ set c [chan create {r w} foo]
+ note [catch {fconfigure $c -blocking 0} msg]; note $msg
+ # Catch the close. It changes blocking mode internally, and runs into the error result.
+ catch {close $c}
+ rename foo {}
+ set res
+} -result {{blocking rc* 0} 1 BOOM!}
+test iocmd-29.7 {chan blocking, break return is error} -match glob -body {
+ set res {}
+ proc foo {args} {oninit blocking; onfinal; track; return -code break BOOM!}
+ set c [chan create {r w} foo]
+ note [catch {fconfigure $c -blocking 0} msg]; note $msg
+ catch {close $c}
+ rename foo {}
+ set res
+} -result {{blocking rc* 0} 1 *bad code*}
+test iocmd-29.8 {chan blocking, continue return is error} -match glob -body {
+ set res {}
+ proc foo {args} {oninit blocking; onfinal; track; return -code continue BOOM!}
+ set c [chan create {r w} foo]
+ note [catch {fconfigure $c -blocking 0} msg]; note $msg
+ catch {close $c}
+ rename foo {}
+ set res
+} -result {{blocking rc* 0} 1 *bad code*}
+test iocmd-29.9 {chan blocking, custom return is error} -match glob -body {
+ set res {}
+ proc foo {args} {oninit blocking; onfinal; track; return -code 44 BOOM!}
+ set c [chan create {r w} foo]
+ note [catch {fconfigure $c -blocking 0} msg]; note $msg
+ catch {close $c}
+ rename foo {}
+ set res
+} -result {{blocking rc* 0} 1 *bad code*}
+test iocmd-29.10 {chan blocking, level is ignored} -match glob -setup {
+ set res {}
+} -body {
+ proc foo {args} {oninit blocking; onfinal; track; return -level 99 -code 44 BANG}
+ set c [chan create {r w} foo]
+ note [catch {fconfigure $c -blocking 0} msg opt]; note $msg; noteOpts $opt
+ catch {close $c}
+ return $res
+} -cleanup {
+ rename foo {}
+} -result {{blocking rc* 0} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "blocking"*}}
+test iocmd-29.11 {chan blocking, regular return ok, value ignored} -match glob -body {
+ set res {}
+ proc foo {args} {oninit blocking; onfinal; track; return BOGUS}
+ set c [chan create {r w} foo]
+ note [catch {fconfigure $c -blocking 0} msg]; note $msg
+ catch {close $c}
+ rename foo {}
+ set res
+} -result {{blocking rc* 0} 0 {}}
+
+# --- === *** ###########################
+# method watch
+
+test iocmd-30.1 {chan watch, read interest, some return} -match glob -body {
+ set res {}
+ proc foo {args} {oninit; onfinal; track; return IGNORED}
+ set c [chan create {r w} foo]
+ note [fileevent $c readable {set tick $tick}]
+ close $c ;# 2nd watch, interest zero.
+ rename foo {}
+ set res
+} -result {{watch rc* read} {} {watch rc* {}}}
+test iocmd-30.2 {chan watch, write interest, error return} -match glob -body {
+ set res {}
+ proc foo {args} {oninit; onfinal; track; return -code error BOOM!_IGNORED}
+ set c [chan create {r w} foo]
+ note [fileevent $c writable {set tick $tick}]
+ note [fileevent $c writable {}]
+ close $c
+ rename foo {}
+ set res
+} -result {{watch rc* write} {} {watch rc* {}} {}}
+test iocmd-30.3 {chan watch, accumulated interests} -match glob -body {
+ set res {}
+ proc foo {args} {oninit; onfinal; track; return}
+ set c [chan create {r w} foo]
+ note [fileevent $c writable {set tick $tick}]
+ note [fileevent $c readable {set tick $tick}]
+ note [fileevent $c writable {}]
+ note [fileevent $c readable {}]
+ close $c
+ rename foo {}
+ set res
+} -result {{watch rc* write} {} {watch rc* {read write}} {} {watch rc* read} {} {watch rc* {}} {}}
+test iocmd-30.4 {chan watch, unchanged interest not forwarded} -match glob -body {
+ set res {}
+ proc foo {args} {oninit; onfinal; track; return}
+ set c [chan create {r w} foo]
+ note [fileevent $c writable {set tick $tick}]
+ note [fileevent $c readable {set tick $tick}] ;# Script is changing,
+ note [fileevent $c readable {set tock $tock}] ;# interest does not.
+ close $c ;# 3rd and 4th watch, removing the event handlers.
+ rename foo {}
+ set res
+} -result {{watch rc* write} {} {watch rc* {read write}} {} {} {watch rc* write} {watch rc* {}}}
+
+# --- === *** ###########################
+# chan postevent
+
+test iocmd-31.1 {chan postevent, restricted to reflected channels} -match glob -body {
+ set c [open [makeFile {} goo] r]
+ catch {chan postevent $c {r w}} msg
+ close $c
+ removeFile goo
+ set msg
+} -result {can not find reflected channel named "file*"}
+test iocmd-31.2 {chan postevent, unwanted events} -match glob -body {
+ set res {}
+ proc foo {args} {oninit; onfinal; track; return}
+ set c [chan create {r w} foo]
+ catch {chan postevent $c {r w}} msg; note $msg
+ close $c
+ rename foo {}
+ set res
+} -result {{tried to post events channel "rc*" is not interested in}}
+test iocmd-31.3 {chan postevent, bad input, empty list} -match glob -body {
+ set res {}
+ proc foo {args} {oninit; onfinal; track; return}
+ set c [chan create {r w} foo]
+ catch {chan postevent $c {}} msg; note $msg
+ close $c
+ rename foo {}
+ set res
+} -result {{bad event list: is empty}}
+test iocmd-31.4 {chan postevent, bad input, illlegal keyword} -match glob -body {
+ set res {}
+ proc foo {args} {oninit; onfinal; track; return}
+ set c [chan create {r w} foo]
+ catch {chan postevent $c goo} msg; note $msg
+ close $c
+ rename foo {}
+ set res
+} -result {{bad event "goo": must be read or write}}
+test iocmd-31.5 {chan postevent, bad input, not a list} -match glob -body {
+ set res {}
+ proc foo {args} {oninit; onfinal; track; return}
+ set c [chan create {r w} foo]
+ catch {chan postevent $c "\{"} msg; note $msg
+ close $c
+ rename foo {}
+ set res
+} -result {{unmatched open brace in list}}
+test iocmd-31.6 {chan postevent, posted events do happen} -match glob -body {
+ set res {}
+ proc foo {args} {oninit; onfinal; track; return}
+ set c [chan create {r w} foo]
+ note [fileevent $c readable {note TOCK}]
+ set stop [after 10000 {note TIMEOUT}]
+ after 1000 {note [chan postevent $c r]}
+ vwait ::res
+ catch {after cancel $stop}
+ close $c
+ rename foo {}
+ set res
+} -result {{watch rc* read} {} TOCK {} {watch rc* {}}}
+test iocmd-31.7 {chan postevent, posted events do happen} -match glob -body {
+ set res {}
+ proc foo {args} {oninit; onfinal; track; return}
+ set c [chan create {r w} foo]
+ note [fileevent $c writable {note TOCK}]
+ set stop [after 10000 {note TIMEOUT}]
+ after 1000 {note [chan postevent $c w]}
+ vwait ::res
+ catch {after cancel $stop}
+ close $c
+ rename foo {}
+ set res
+} -result {{watch rc* write} {} TOCK {} {watch rc* {}}}
+test iocmd-31.8 {chan postevent after close throws error} -match glob -setup {
+ proc foo {args} {oninit; onfinal; track; return}
+ proc dummy args { return }
+ set c [chan create {r w} foo]
+ fileevent $c readable dummy
+} -body {
+ close $c
+ chan postevent $c read
+} -cleanup {
+ rename foo {}
+ rename dummy {}
+} -returnCodes error -result {can not find reflected channel named "rc*"}
+
+# --- === *** ###########################
+# 'Pull the rug' tests. Create channel in a interpreter A, move to
+# other interpreter B, destroy the origin interpreter (A) before or
+# during access from B. Must not crash, must return proper errors.
+
+test iocmd-32.0 {origin interpreter of moved channel gone} -match glob -body {
+
+ set ida [interp create];#puts <<$ida>>
+ set idb [interp create];#puts <<$idb>>
+
+ # Magic to get the test* commands in the slaves
+ load {} Tcltest $ida
+ load {} Tcltest $idb
+
+ # Set up channel in interpreter
+ interp eval $ida $helperscript
+ set chan [interp eval $ida {
+ proc foo {args} {oninit seek; onfinal; track; return}
+ set chan [chan create {r w} foo]
+ fconfigure $chan -buffering none
+ set chan
+ }]
+
+ # Move channel to 2nd interpreter.
+ interp eval $ida [list testchannel cut $chan]
+ interp eval $idb [list testchannel splice $chan]
+
+ # Kill origin interpreter, then access channel from 2nd interpreter.
+ interp delete $ida
+
+ set res {}
+ lappend res [catch {interp eval $idb [list puts $chan shoo]} msg] $msg
+ lappend res [catch {interp eval $idb [list tell $chan]} msg] $msg
+ lappend res [catch {interp eval $idb [list seek $chan 1]} msg] $msg
+ lappend res [catch {interp eval $idb [list gets $chan]} msg] $msg
+ lappend res [catch {interp eval $idb [list close $chan]} msg] $msg
+ set res
+
+} -constraints {testchannel} \
+ -result {1 {Owner lost} 1 {Owner lost} 1 {Owner lost} 1 {Owner lost} 1 {Owner lost}}
+
+test iocmd-32.1 {origin interpreter of moved channel destroyed during access} -match glob -body {
+
+ set ida [interp create];#puts <<$ida>>
+ set idb [interp create];#puts <<$idb>>
+
+ # Magic to get the test* commands in the slaves
+ load {} Tcltest $ida
+ load {} Tcltest $idb
+
+ # Set up channel in thread
+ set chan [interp eval $ida $helperscript]
+ set chan [interp eval $ida {
+ proc foo {args} {
+ oninit; onfinal; track;
+ # destroy interpreter during channel access
+ # Actually not possible for an interp to destroy itself.
+ interp delete {}
+ return}
+ set chan [chan create {r w} foo]
+ fconfigure $chan -buffering none
+ set chan
+ }]
+
+ # Move channel to 2nd thread.
+ interp eval $ida [list testchannel cut $chan]
+ interp eval $idb [list testchannel splice $chan]
+
+ # Run access from interpreter B, this will give us a synchronous
+ # response.
+
+ interp eval $idb [list set chan $chan]
+ interp eval $idb [list set mid $tcltest::mainThread]
+ set res [interp eval $idb {
+ # wait a bit, give the main thread the time to start its event
+ # loop to wait for the response from B
+ after 2000
+ catch { puts $chan shoo } res
+ set res
+ }]
+ set res
+} -constraints {testchannel impossible} \
+ -result {Owner lost}
+
+test iocmd-32.2 {delete interp of reflected chan} {
+ # Bug 3034840
+ # Run this test in an interp with memory debugging to panic
+ # on the double free
+ interp create slave
+ slave eval {
+ proc no-op args {}
+ proc driver {sub args} {return {initialize finalize watch read}}
+ chan event [chan create read driver] readable no-op
+ }
+ interp delete slave
+} {}
+
+# ### ### ### ######### ######### #########
+## Same tests as above, but exercising the code forwarding and
+## receiving driver operations to the originator thread.
+
+# -*- tcl -*-
+# ### ### ### ######### ######### #########
+## Testing the reflected channel (Thread forwarding).
+#
+## The id numbers refer to the original test without thread
+## forwarding, and gaps due to tests not applicable to forwarding are
+## left to keep this asociation.
+
+# Duplicate of code in "thread.test". Find a better way of doing this
+# without duplication. Maybe placement into a proc which transforms to
+# nop after the first call, and placement of its defintion in a
+# central location.
+
+if {[testConstraint testthread]} {
+ testthread errorproc ThreadError
+
+ proc ThreadError {id info} {
+ global threadError
+ set threadError $info
+ }
+ proc ThreadNullError {id info} {
+ # ignore
+ }
+}
+
+# ### ### ### ######### ######### #########
+## Helper command. Runs a script in a separate thread and returns the
+## result. A channel is transfered into the thread as well, and list of
+## configuation variables
+
+proc inthread {chan script args} {
+ # Test thread.
+
+ set tid [testthread create]
+
+ # Init thread configuration.
+ # - Listed variables
+ # - Id of main thread
+ # - A number of helper commands
+
+ foreach v $args {
+ upvar 1 $v x
+ testthread send $tid [list set $v $x]
+ }
+ testthread send $tid [list set mid $tcltest::mainThread]
+ testthread send $tid {
+ proc note {item} {global notes; lappend notes $item}
+ proc notes {} {global notes; return $notes}
+ proc noteOpts opts {global notes; lappend notes [dict merge {
+ -code !?! -level !?! -errorcode !?! -errorline !?! -errorinfo !?!
+ } $opts]}
+ }
+ testthread send $tid [list proc s {} [list uplevel 1 $script]]; # (*)
+
+ # Transfer channel (cut/splice aka detach/attach)
+
+ testchannel cut $chan
+ testthread send $tid [list testchannel splice $chan]
+
+ # Run test script, also run local event loop!
+ # The local event loop waits for the result to come back.
+ # It is also necessary for the execution of forwarded channel
+ # operations.
+
+ set ::tres ""
+ testthread send -async $tid {
+ after 500
+ catch {s} res; # This runs the script, 's' was defined at (*)
+ testthread send -async $mid [list set ::tres $res]
+ }
+ vwait ::tres
+ # Remove test thread, and return the captured result.
+
+ tcltest::threadReap
+ return $::tres
+}
+
+# ### ### ### ######### ######### #########
+
+# ### ### ### ######### ######### #########
+
+test iocmd.tf-22.2 {chan finalize, for close} -match glob -body {
+ set res {}
+ proc foo {args} {track; oninit; return {}}
+ note [set c [chan create {r w} foo]]
+ note [inthread $c {
+ close $c
+ # Close the deleted the channel.
+ file channels rc*
+ } c]
+ # Channel destruction does not kill handler command!
+ note [info command foo]
+ rename foo {}
+ set res
+} -constraints {testchannel testthread} -result {{initialize rc* {read write}} rc* {finalize rc*} {} foo}
+test iocmd.tf-22.3 {chan finalize, for close, error, close error} -match glob -body {
+ set res {}
+ proc foo {args} {track; oninit; return -code error 5}
+ note [set c [chan create {r w} foo]]
+ notes [inthread $c {
+ note [catch {close $c} msg]; note $msg
+ # Channel is gone despite error.
+ note [file channels rc*]
+ notes
+ } c]
+ rename foo {}
+ set res
+} -constraints {testchannel testthread} -result {{initialize rc* {read write}} rc* {finalize rc*} 1 5 {}}
+test iocmd.tf-22.4 {chan finalize, for close, error, close errror} -match glob -body {
+ set res {}
+ proc foo {args} {track; oninit; error FOO}
+ note [set c [chan create {r w} foo]]
+ notes [inthread $c {
+ note [catch {close $c} msg]; note $msg
+ notes
+ } c]
+ rename foo {}
+ set res
+} -constraints {testchannel testthread} -result {{initialize rc* {read write}} rc* {finalize rc*} 1 FOO}
+test iocmd.tf-22.5 {chan finalize, for close, arbitrary result} -match glob -body {
+ set res {}
+ proc foo {args} {track; oninit; return SOMETHING}
+ note [set c [chan create {r w} foo]]
+ notes [inthread $c {
+ note [catch {close $c} msg]; note $msg
+ notes
+ } c]
+ rename foo {}
+ set res
+} -constraints {testchannel testthread} -result {{initialize rc* {read write}} rc* {finalize rc*} 0 {}}
+test iocmd.tf-22.6 {chan finalize, for close, break, close error} -match glob -body {
+ set res {}
+ proc foo {args} {track; oninit; return -code 3}
+ note [set c [chan create {r w} foo]]
+ notes [inthread $c {
+ note [catch {close $c} msg]; note $msg
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{initialize rc* {read write}} rc* {finalize rc*} 1 *bad code*} \
+ -constraints {testchannel testthread}
+test iocmd.tf-22.7 {chan finalize, for close, continue, close error} -match glob -body {
+ set res {}
+ proc foo {args} {track; oninit; return -code 4}
+ note [set c [chan create {r w} foo]]
+ notes [inthread $c {
+ note [catch {close $c} msg]; note $msg
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{initialize rc* {read write}} rc* {finalize rc*} 1 *bad code*} \
+ -constraints {testchannel testthread}
+test iocmd.tf-22.8 {chan finalize, for close, custom code, close error} -match glob -body {
+ set res {}
+ proc foo {args} {track; oninit; return -code 777 BANG}
+ note [set c [chan create {r w} foo]]
+ notes [inthread $c {
+ note [catch {close $c} msg]; note $msg
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{initialize rc* {read write}} rc* {finalize rc*} 1 *bad code*} \
+ -constraints {testchannel testthread}
+test iocmd.tf-22.9 {chan finalize, for close, ignore level, close error} -match glob -body {
+ set res {}
+ proc foo {args} {track; oninit; return -level 5 -code 777 BANG}
+ note [set c [chan create {r w} foo]]
+ notes [inthread $c {
+ note [catch {close $c} msg opt]; note $msg; noteOpts $opt
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{initialize rc* {read write}} rc* {finalize rc*} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "finalize"*}} \
+ -constraints {testchannel testthread}
+
+# --- === *** ###########################
+# method read
+
+test iocmd.tf-23.1 {chan read, regular data return} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit; onfinal; track
+ return snarf
+ }
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [read $c 10]
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -constraints {testchannel testthread} -result {{read rc* 4096} {read rc* 4096} snarfsnarf}
+test iocmd.tf-23.2 {chan read, bad data return, to much} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit; onfinal; track
+ return [string repeat snarf 1000]
+ }
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {[read $c 2]} msg]; note $msg
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -constraints {testchannel testthread} -result {{read rc* 4096} 1 {read delivered more than requested}}
+test iocmd.tf-23.3 {chan read, for non-readable channel} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit; onfinal; track; note MUST_NOT_HAPPEN
+ }
+ set c [chan create {w} foo]
+ notes [inthread $c {
+ note [catch {[read $c 2]} msg]; note $msg
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -constraints {testchannel testthread} -result {1 {channel "rc*" wasn't opened for reading}}
+test iocmd.tf-23.4 {chan read, error return} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit; onfinal; track
+ return -code error BOOM!
+ }
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {read $c 2} msg]; note $msg
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{read rc* 4096} 1 BOOM!} \
+ -constraints {testchannel testthread}
+test iocmd.tf-23.5 {chan read, break return is error} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit; onfinal; track
+ return -code break BOOM!
+ }
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {read $c 2} msg]; note $msg
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{read rc* 4096} 1 *bad code*} \
+ -constraints {testchannel testthread}
+test iocmd.tf-23.6 {chan read, continue return is error} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit; onfinal; track
+ return -code continue BOOM!
+ }
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {read $c 2} msg]; note $msg
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{read rc* 4096} 1 *bad code*} \
+ -constraints {testchannel testthread}
+test iocmd.tf-23.7 {chan read, custom return is error} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit; onfinal; track
+ return -code 777 BOOM!
+ }
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {read $c 2} msg]; note $msg
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{read rc* 4096} 1 *bad code*} \
+ -constraints {testchannel testthread}
+test iocmd.tf-23.8 {chan read, level is squashed} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit; onfinal; track
+ return -level 55 -code 777 BOOM!
+ }
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {read $c 2} msg opt]; note $msg; noteOpts $opt
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{read rc* 4096} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "read"*}} \
+ -constraints {testchannel testthread}
+test iocmd.tf-23.9 {chan read, no data means eof} -match glob -setup {
+ set res {}
+ proc foo {args} {
+ oninit; onfinal; track
+ return ""
+ }
+ set c [chan create {r w} foo]
+} -body {
+ notes [inthread $c {
+ note [read $c 2]
+ note [eof $c]
+ close $c
+ notes
+ } c]
+ set res
+} -cleanup {
+ rename foo {}
+ unset res
+} -result {{read rc* 4096} {} 1} \
+ -constraints {testchannel testthread}
+test iocmd.tf-23.10 {chan read, EAGAIN means no data, yet no eof either} -match glob -setup {
+ set res {}
+ proc foo {args} {
+ oninit; onfinal; track
+ error EAGAIN
+ }
+ set c [chan create {r w} foo]
+} -body {
+ notes [inthread $c {
+ note [read $c 2]
+ note [eof $c]
+ close $c
+ notes
+ } c]
+ set res
+} -cleanup {
+ rename foo {}
+ unset res
+} -result {{read rc* 4096} {} 0} \
+ -constraints {testchannel testthread}
+
+# --- === *** ###########################
+# method write
+
+test iocmd.tf-24.1 {chan write, regular write} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit; onfinal; track
+ set written [string length [lindex $args 2]]
+ note $written
+ return $written
+ }
+ set c [chan create {r w} foo]
+ inthread $c {
+ puts -nonewline $c snarf; flush $c
+ close $c
+ } c
+ rename foo {}
+ set res
+} -constraints {testchannel testthread} -result {{write rc* snarf} 5}
+test iocmd.tf-24.2 {chan write, ack partial writes} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit; onfinal; track
+ set written [string length [lindex $args 2]]
+ if {$written > 10} {set written [expr {$written / 2}]}
+ note $written
+ return $written
+ }
+ set c [chan create {r w} foo]
+ inthread $c {
+ puts -nonewline $c snarfsnarfsnarf; flush $c
+ close $c
+ } c
+ rename foo {}
+ set res
+} -constraints {testchannel testthread} -result {{write rc* snarfsnarfsnarf} 7 {write rc* arfsnarf} 8}
+test iocmd.tf-24.3 {chan write, failed write} -match glob -body {
+ set res {}
+ proc foo {args} {oninit; onfinal; track; note -1; return -1}
+ set c [chan create {r w} foo]
+ inthread $c {
+ puts -nonewline $c snarfsnarfsnarf; flush $c
+ close $c
+ } c
+ rename foo {}
+ set res
+} -constraints {testchannel testthread} -result {{write rc* snarfsnarfsnarf} -1}
+test iocmd.tf-24.4 {chan write, non-writable channel} -match glob -body {
+ set res {}
+ proc foo {args} {oninit; onfinal; track; note MUST_NOT_HAPPEN; return}
+ set c [chan create {r} foo]
+ notes [inthread $c {
+ note [catch {puts -nonewline $c snarfsnarfsnarf; flush $c} msg]
+ note $msg
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -constraints {testchannel testthread} -result {1 {channel "rc*" wasn't opened for writing}}
+test iocmd.tf-24.5 {chan write, bad result, more written than data} -match glob -body {
+ set res {}
+ proc foo {args} {oninit; onfinal; track; return 10000}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {puts -nonewline $c snarf; flush $c} msg]
+ note $msg
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -constraints {testchannel testthread} -result {{write rc* snarf} 1 {write wrote more than requested}}
+test iocmd.tf-24.6 {chan write, zero writes} -match glob -body {
+ set res {}
+ proc foo {args} {oninit; onfinal; track; return 0}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {puts -nonewline $c snarf; flush $c} msg]
+ note $msg
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -constraints {testchannel testthread} -result {{write rc* snarf} 1 {write wrote more than requested}}
+test iocmd.tf-24.7 {chan write, failed write, error return} -match glob -body {
+ set res {}
+ proc foo {args} {oninit; onfinal; track; return -code error BOOM!}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {puts -nonewline $c snarfsnarfsnarf; flush $c} msg]
+ note $msg
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{write rc* snarfsnarfsnarf} 1 BOOM!} \
+ -constraints {testchannel testthread}
+test iocmd.tf-24.8 {chan write, failed write, error return} -match glob -body {
+ set res {}
+ proc foo {args} {oninit; onfinal; track; error BOOM!}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {puts -nonewline $c snarfsnarfsnarf; flush $c} msg]
+ note $msg
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{write rc* snarfsnarfsnarf} 1 BOOM!} \
+ -constraints {testchannel testthread}
+test iocmd.tf-24.9 {chan write, failed write, break return is error} -match glob -body {
+ set res {}
+ proc foo {args} {oninit; onfinal; track; return -code break BOOM!}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {puts -nonewline $c snarfsnarfsnarf; flush $c} msg]
+ note $msg
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{write rc* snarfsnarfsnarf} 1 *bad code*} \
+ -constraints {testchannel testthread}
+test iocmd.tf-24.10 {chan write, failed write, continue return is error} -match glob -body {
+ set res {}
+ proc foo {args} {oninit; onfinal; track; return -code continue BOOM!}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {puts -nonewline $c snarfsnarfsnarf; flush $c} msg]
+ note $msg
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{write rc* snarfsnarfsnarf} 1 *bad code*} \
+ -constraints {testchannel testthread}
+test iocmd.tf-24.11 {chan write, failed write, custom return is error} -match glob -body {
+ set res {}
+ proc foo {args} {oninit; onfinal; track; return -code 777 BOOM!}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {puts -nonewline $c snarfsnarfsnarf; flush $c} msg]
+ note $msg
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{write rc* snarfsnarfsnarf} 1 *bad code*} \
+ -constraints {testchannel testthread}
+test iocmd.tf-24.12 {chan write, failed write, non-numeric return is error} -match glob -body {
+ set res {}
+ proc foo {args} {oninit; onfinal; track; return BANG}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {puts -nonewline $c snarfsnarfsnarf; flush $c} msg]
+ note $msg
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{write rc* snarfsnarfsnarf} 1 {expected integer but got "BANG"}} \
+ -constraints {testchannel testthread}
+test iocmd.tf-24.13 {chan write, failed write, level is ignored} -match glob -body {
+ set res {}
+ proc foo {args} {oninit; onfinal; track; return -level 55 -code 777 BOOM!}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {puts -nonewline $c snarfsnarfsnarf; flush $c} msg opt]
+ note $msg
+ noteOpts $opt
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{write rc* snarfsnarfsnarf} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "write"*}} \
+ -constraints {testchannel testthread}
+test iocmd.tf-24.14 {chan write, no EAGAIN means that writing is allowed at this time, bug 2936225} -match glob -setup {
+ set res {}
+ proc foo {args} {
+ oninit; onfinal; track
+ return 3
+ }
+ set c [chan create {r w} foo]
+} -body {
+ notes [inthread $c {
+ note [puts -nonewline $c ABC ; flush $c]
+ close $c
+ notes
+ } c]
+ set res
+} -cleanup {
+ rename foo {}
+ unset res
+} -result {{write rc* ABC} {}} \
+ -constraints {testchannel testthread}
+test iocmd.tf-24.15 {chan write, EAGAIN means that writing is not allowed at this time, bug 2936225} -match glob -setup {
+ set res {}
+ proc foo {args} {
+ oninit; onfinal; track
+ # Note: The EAGAIN signals that the channel cannot accept
+ # write requests right now, this in turn causes the IO core to
+ # request the generation of writable events (see expected
+ # result below, and compare to case 24.14 above).
+ error EAGAIN
+ }
+ set c [chan create {r w} foo]
+} -body {
+ notes [inthread $c {
+ note [puts -nonewline $c ABC ; flush $c]
+ close $c
+ notes
+ } c]
+ set res
+} -cleanup {
+ rename foo {}
+ unset res
+} -result {{write rc* ABC} {watch rc* write} {}} \
+ -constraints {testchannel testthread}
+
+# --- === *** ###########################
+# method cgetall
+
+test iocmd.tf-25.1 {chan configure, cgetall, standard options} -match glob -body {
+ set res {}
+ proc foo {args} {oninit; onfinal; track; note MUST_NOT_HAPPEN; return}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [fconfigure $c]
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -constraints {testchannel testthread} \
+ -result {{-blocking 1 -buffering full -buffersize 4096 -encoding * -eofchar {{} {}} -translation {auto *}}}
+test iocmd.tf-25.2 {chan configure, cgetall, no options} -match glob -body {
+ set res {}
+ proc foo {args} {oninit cget cgetall; onfinal; track; return ""}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [fconfigure $c]
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -constraints {testchannel testthread} \
+ -result {{cgetall rc*} {-blocking 1 -buffering full -buffersize 4096 -encoding * -eofchar {{} {}} -translation {auto *}}}
+test iocmd.tf-25.3 {chan configure, cgetall, regular result} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit cget cgetall; onfinal; track
+ return "-bar foo -snarf x"
+ }
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [fconfigure $c]
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -constraints {testchannel testthread} \
+ -result {{cgetall rc*} {-blocking 1 -buffering full -buffersize 4096 -encoding * -eofchar {{} {}} -translation {auto *} -bar foo -snarf x}}
+test iocmd.tf-25.4 {chan configure, cgetall, bad result, list of uneven length} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit cget cgetall; onfinal; track
+ return "-bar"
+ }
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {fconfigure $c} msg]
+ note $msg
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -constraints {testchannel testthread} -result {{cgetall rc*} 1 {Expected list with even number of elements, got 1 element instead}}
+test iocmd.tf-25.5 {chan configure, cgetall, bad result, not a list} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit cget cgetall; onfinal; track
+ return "\{"
+ }
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {fconfigure $c} msg]
+ note $msg
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -constraints {testchannel testthread} -result {{cgetall rc*} 1 {unmatched open brace in list}}
+test iocmd.tf-25.6 {chan configure, cgetall, error return} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit cget cgetall; onfinal; track
+ return -code error BOOM!
+ }
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {fconfigure $c} msg]
+ note $msg
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -constraints {testchannel testthread} -result {{cgetall rc*} 1 BOOM!}
+test iocmd.tf-25.7 {chan configure, cgetall, break return is error} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit cget cgetall; onfinal; track
+ return -code break BOOM!
+ }
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {fconfigure $c} msg]
+ note $msg
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{cgetall rc*} 1 *bad code*} \
+ -constraints {testchannel testthread}
+test iocmd.tf-25.8 {chan configure, cgetall, continue return is error} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit cget cgetall; onfinal; track
+ return -code continue BOOM!
+ }
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {fconfigure $c} msg]
+ note $msg
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{cgetall rc*} 1 *bad code*} \
+ -constraints {testchannel testthread}
+test iocmd.tf-25.9 {chan configure, cgetall, custom return is error} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit cget cgetall; onfinal; track
+ return -code 777 BOOM!
+ }
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {fconfigure $c} msg]
+ note $msg
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{cgetall rc*} 1 *bad code*} \
+ -constraints {testchannel testthread}
+test iocmd.tf-25.10 {chan configure, cgetall, level is ignored} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit cget cgetall; onfinal; track
+ return -level 55 -code 777 BANG
+ }
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {fconfigure $c} msg opt]
+ note $msg
+ noteOpts $opt
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{cgetall rc*} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "cgetall"*}} \
+ -constraints {testchannel testthread}
+
+# --- === *** ###########################
+# method configure
+
+test iocmd.tf-26.1 {chan configure, set standard option} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit configure; onfinal; track; note MUST_NOT_HAPPEN; return
+ }
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [fconfigure $c -translation lf]
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -constraints {testchannel testthread} -result {{}}
+test iocmd.tf-26.2 {chan configure, set option, error return} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit configure; onfinal; track
+ return -code error BOOM!
+ }
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {fconfigure $c -rc-foo bar} msg]
+ note $msg
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -constraints {testchannel testthread} -result {{configure rc* -rc-foo bar} 1 BOOM!}
+test iocmd.tf-26.3 {chan configure, set option, ok return} -match glob -body {
+ set res {}
+ proc foo {args} {oninit configure; onfinal; track; return}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [fconfigure $c -rc-foo bar]
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -constraints {testchannel testthread} -result {{configure rc* -rc-foo bar} {}}
+test iocmd.tf-26.4 {chan configure, set option, break return is error} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit configure; onfinal; track
+ return -code break BOOM!
+ }
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {fconfigure $c -rc-foo bar} msg]
+ note $msg
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{configure rc* -rc-foo bar} 1 *bad code*} \
+ -constraints {testchannel testthread}
+test iocmd.tf-26.5 {chan configure, set option, continue return is error} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit configure; onfinal; track
+ return -code continue BOOM!
+ }
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {fconfigure $c -rc-foo bar} msg]
+ note $msg
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{configure rc* -rc-foo bar} 1 *bad code*} \
+ -constraints {testchannel testthread}
+test iocmd.tf-26.6 {chan configure, set option, custom return is error} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit configure; onfinal; track
+ return -code 444 BOOM!
+ }
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {fconfigure $c -rc-foo bar} msg]
+ note $msg
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{configure rc* -rc-foo bar} 1 *bad code*} \
+ -constraints {testchannel testthread}
+test iocmd.tf-26.7 {chan configure, set option, level is ignored} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit configure; onfinal; track
+ return -level 55 -code 444 BANG
+ }
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {fconfigure $c -rc-foo bar} msg opt]
+ note $msg
+ noteOpts $opt
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{configure rc* -rc-foo bar} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "configure"*}} \
+ -constraints {testchannel testthread}
+
+# --- === *** ###########################
+# method cget
+
+test iocmd.tf-27.1 {chan configure, get option, ok return} -match glob -body {
+ set res {}
+ proc foo {args} {oninit cget cgetall; onfinal; track; return foo}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [fconfigure $c -rc-foo]
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -constraints {testchannel testthread} -result {{cget rc* -rc-foo} foo}
+test iocmd.tf-27.2 {chan configure, get option, error return} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit cget cgetall; onfinal; track
+ return -code error BOOM!
+ }
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {fconfigure $c -rc-foo} msg]
+ note $msg
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -constraints {testchannel testthread} -result {{cget rc* -rc-foo} 1 BOOM!}
+test iocmd.tf-27.3 {chan configure, get option, break return is error} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit cget cgetall; onfinal; track
+ return -code error BOOM!
+ }
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {fconfigure $c -rc-foo} msg]
+ note $msg
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{cget rc* -rc-foo} 1 BOOM!} \
+ -constraints {testchannel testthread}
+test iocmd.tf-27.4 {chan configure, get option, continue return is error} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit cget cgetall; onfinal; track
+ return -code continue BOOM!
+ }
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {fconfigure $c -rc-foo} msg]
+ note $msg
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{cget rc* -rc-foo} 1 *bad code*} \
+ -constraints {testchannel testthread}
+test iocmd.tf-27.5 {chan configure, get option, custom return is error} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit cget cgetall; onfinal; track
+ return -code 333 BOOM!
+ }
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {fconfigure $c -rc-foo} msg]
+ note $msg
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{cget rc* -rc-foo} 1 *bad code*} \
+ -constraints {testchannel testthread}
+test iocmd.tf-27.6 {chan configure, get option, level is ignored} -match glob -body {
+ set res {}
+ proc foo {args} {
+ oninit cget cgetall; onfinal; track
+ return -level 77 -code 333 BANG
+ }
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {fconfigure $c -rc-foo} msg opt]
+ note $msg
+ noteOpts $opt
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{cget rc* -rc-foo} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "cget"*}} \
+ -constraints {testchannel testthread}
+
+# --- === *** ###########################
+# method seek
+
+test iocmd.tf-28.1 {chan tell, not supported by handler} -match glob -body {
+ set res {}
+ proc foo {args} {oninit; onfinal; track; note MUST_NOT_HAPPEN; return}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [tell $c]
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {-1} \
+ -constraints {testchannel testthread}
+test iocmd.tf-28.2 {chan tell, error return} -match glob -body {
+ set res {}
+ proc foo {args} {oninit seek; onfinal; track; return -code error BOOM!}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {tell $c} msg]
+ note $msg
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{seek rc* 0 current} 1 BOOM!} \
+ -constraints {testchannel testthread}
+test iocmd.tf-28.3 {chan tell, break return is error} -match glob -body {
+ set res {}
+ proc foo {args} {oninit seek; onfinal; track; return -code break BOOM!}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {tell $c} msg]
+ note $msg
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{seek rc* 0 current} 1 *bad code*} \
+ -constraints {testchannel testthread}
+test iocmd.tf-28.4 {chan tell, continue return is error} -match glob -body {
+ set res {}
+ proc foo {args} {oninit seek; onfinal; track; return -code continue BOOM!}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {tell $c} msg]
+ note $msg
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{seek rc* 0 current} 1 *bad code*} \
+ -constraints {testchannel testthread}
+test iocmd.tf-28.5 {chan tell, custom return is error} -match glob -body {
+ set res {}
+ proc foo {args} {oninit seek; onfinal; track; return -code 222 BOOM!}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {tell $c} msg]
+ note $msg
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{seek rc* 0 current} 1 *bad code*} \
+ -constraints {testchannel testthread}
+test iocmd.tf-28.6 {chan tell, level is ignored} -match glob -body {
+ set res {}
+ proc foo {args} {oninit seek; onfinal; track; return -level 11 -code 222 BANG}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {tell $c} msg opt]
+ note $msg
+ noteOpts $opt
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{seek rc* 0 current} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "seek"*}} \
+ -constraints {testchannel testthread}
+test iocmd.tf-28.7 {chan tell, regular return} -match glob -body {
+ set res {}
+ proc foo {args} {oninit seek; onfinal; track; return 88}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [tell $c]
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{seek rc* 0 current} 88} \
+ -constraints {testchannel testthread}
+test iocmd.tf-28.8 {chan tell, negative return} -match glob -body {
+ set res {}
+ proc foo {args} {oninit seek; onfinal; track; return -1}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {tell $c} msg]
+ note $msg
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{seek rc* 0 current} 1 {Tried to seek before origin}} \
+ -constraints {testchannel testthread}
+test iocmd.tf-28.9 {chan tell, string return} -match glob -body {
+ set res {}
+ proc foo {args} {oninit seek; onfinal; track; return BOGUS}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {tell $c} msg]
+ note $msg
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{seek rc* 0 current} 1 {expected integer but got "BOGUS"}} \
+ -constraints {testchannel testthread}
+test iocmd.tf-28.10 {chan seek, not supported by handler} -match glob -body {
+ set res {}
+ proc foo {args} {oninit; onfinal; track; note MUST_NOT_HAPPEN; return}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {seek $c 0 start} msg]
+ note $msg
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {1 {error during seek on "rc*": invalid argument}} \
+ -constraints {testchannel testthread}
+test iocmd.tf-28.11 {chan seek, error return} -match glob -body {
+ set res {}
+ proc foo {args} {oninit seek; onfinal; track; return -code error BOOM!}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {seek $c 0 start} msg]
+ note $msg
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{seek rc* 0 start} 1 BOOM!} \
+ -constraints {testchannel testthread}
+test iocmd.tf-28.12 {chan seek, break return is error} -match glob -body {
+ set res {}
+ proc foo {args} {oninit seek; onfinal; track; return -code break BOOM!}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {seek $c 0 start} msg]
+ note $msg
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{seek rc* 0 start} 1 *bad code*} \
+ -constraints {testchannel testthread}
+test iocmd.tf-28.13 {chan seek, continue return is error} -match glob -body {
+ set res {}
+ proc foo {args} {oninit seek; onfinal; track; return -code continue BOOM!}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {seek $c 0 start} msg]
+ note $msg
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{seek rc* 0 start} 1 *bad code*} \
+ -constraints {testchannel testthread}
+test iocmd.tf-28.14 {chan seek, custom return is error} -match glob -body {
+ set res {}
+ proc foo {args} {oninit seek; onfinal; track; return -code 99 BOOM!}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {seek $c 0 start} msg]
+ note $msg
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{seek rc* 0 start} 1 *bad code*} \
+ -constraints {testchannel testthread}
+test iocmd.tf-28.15 {chan seek, level is ignored} -match glob -body {
+ set res {}
+ proc foo {args} {oninit seek; onfinal; track; return -level 33 -code 99 BANG}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {seek $c 0 start} msg opt]
+ note $msg
+ noteOpts $opt
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{seek rc* 0 start} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "seek"*}} \
+ -constraints {testchannel testthread}
+test iocmd.tf-28.16 {chan seek, bogus return, negative location} -match glob -body {
+ set res {}
+ proc foo {args} {oninit seek; onfinal; track; return -45}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {seek $c 0 start} msg]
+ note $msg
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{seek rc* 0 start} 1 {Tried to seek before origin}} \
+ -constraints {testchannel testthread}
+test iocmd.tf-28.17 {chan seek, bogus return, string return} -match glob -body {
+ set res {}
+ proc foo {args} {oninit seek; onfinal; track; return BOGUS}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {seek $c 0 start} msg]
+ note $msg
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{seek rc* 0 start} 1 {expected integer but got "BOGUS"}} \
+ -constraints {testchannel testthread}
+test iocmd.tf-28.18 {chan seek, ok result} -match glob -body {
+ set res {}
+ proc foo {args} {oninit seek; onfinal; track; return 23}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [seek $c 0 current]
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{seek rc* 0 current} {}} \
+ -constraints {testchannel testthread}
+foreach {testname code} {
+ iocmd.tf-28.19.0 start
+ iocmd.tf-28.19.1 current
+ iocmd.tf-28.19.2 end
+} {
+ test $testname "chan seek, base conversion, $code" -match glob -body {
+ set res {}
+ proc foo {args} {oninit seek; onfinal; track; return 0}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [seek $c 0 $code]
+ close $c
+ notes
+ } c code]
+ rename foo {}
+ set res
+ } -result [list [list seek rc* 0 $code] {}] \
+ -constraints {testchannel testthread}
+}
+
+# --- === *** ###########################
+# method blocking
+
+test iocmd.tf-29.1 {chan blocking, no handler support} -match glob -body {
+ set res {}
+ proc foo {args} {oninit; onfinal; track; note MUST_NOT_HAPPEN; return}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [fconfigure $c -blocking]
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {1} \
+ -constraints {testchannel testthread}
+test iocmd.tf-29.2 {chan blocking, no handler support} -match glob -body {
+ set res {}
+ proc foo {args} {oninit; onfinal; track; note MUST_NOT_HAPPEN; return}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [fconfigure $c -blocking 0]
+ note [fconfigure $c -blocking]
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{} 0} \
+ -constraints {testchannel testthread}
+test iocmd.tf-29.3 {chan blocking, retrieval, handler support} -match glob -body {
+ set res {}
+ proc foo {args} {oninit blocking; onfinal; track; note MUST_NOT_HAPPEN; return}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [fconfigure $c -blocking]
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {1} \
+ -constraints {testchannel testthread}
+test iocmd.tf-29.4 {chan blocking, resetting, handler support} -match glob -body {
+ set res {}
+ proc foo {args} {oninit blocking; onfinal; track; return}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [fconfigure $c -blocking 0]
+ note [fconfigure $c -blocking]
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{blocking rc* 0} {} 0} \
+ -constraints {testchannel testthread}
+test iocmd.tf-29.5 {chan blocking, setting, handler support} -match glob -body {
+ set res {}
+ proc foo {args} {oninit blocking; onfinal; track; return}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [fconfigure $c -blocking 1]
+ note [fconfigure $c -blocking]
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{blocking rc* 1} {} 1} \
+ -constraints {testchannel testthread}
+test iocmd.tf-29.6 {chan blocking, error return} -match glob -body {
+ set res {}
+ proc foo {args} {oninit blocking; onfinal; track; error BOOM!}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {fconfigure $c -blocking 0} msg]
+ note $msg
+ # Catch the close. It changes blocking mode internally, and runs into the error result.
+ catch {close $c}
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{blocking rc* 0} 1 BOOM!} \
+ -constraints {testchannel testthread}
+test iocmd.tf-29.7 {chan blocking, break return is error} -match glob -body {
+ set res {}
+ proc foo {args} {oninit blocking; onfinal; track; return -code break BOOM!}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {fconfigure $c -blocking 0} msg]
+ note $msg
+ catch {close $c}
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{blocking rc* 0} 1 *bad code*} \
+ -constraints {testchannel testthread}
+test iocmd.tf-29.8 {chan blocking, continue return is error} -match glob -body {
+ set res {}
+ proc foo {args} {oninit blocking; onfinal; track; return -code continue BOOM!}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {fconfigure $c -blocking 0} msg]
+ note $msg
+ catch {close $c}
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{blocking rc* 0} 1 *bad code*} \
+ -constraints {testchannel testthread}
+test iocmd.tf-29.9 {chan blocking, custom return is error} -match glob -body {
+ set res {}
+ proc foo {args} {oninit blocking; onfinal; track; return -code 44 BOOM!}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {fconfigure $c -blocking 0} msg]
+ note $msg
+ catch {close $c}
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{blocking rc* 0} 1 *bad code*} \
+ -constraints {testchannel testthread}
+test iocmd.tf-29.10 {chan blocking, level is ignored} -match glob -body {
+ set res {}
+ proc foo {args} {oninit blocking; onfinal; track; return -level 99 -code 44 BANG}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {fconfigure $c -blocking 0} msg opt]
+ note $msg
+ noteOpts $opt
+ catch {close $c}
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{blocking rc* 0} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "blocking"*}} \
+ -constraints {testchannel testthread}
+test iocmd.tf-29.11 {chan blocking, regular return ok, value ignored} -match glob -body {
+ set res {}
+ proc foo {args} {oninit blocking; onfinal; track; return BOGUS}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [catch {fconfigure $c -blocking 0} msg]
+ note $msg
+ catch {close $c}
+ notes
+ } c]
+ rename foo {}
+ set res
+} -result {{blocking rc* 0} 0 {}} \
+ -constraints {testchannel testthread}
+
+# --- === *** ###########################
+# method watch
+
+test iocmd.tf-30.1 {chan watch, read interest, some return} -match glob -body {
+ set res {}
+ proc foo {args} {oninit; onfinal; track; return IGNORED}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [fileevent $c readable {set tick $tick}]
+ close $c ;# 2nd watch, interest zero.
+ notes
+ } c]
+ rename foo {}
+ set res
+} -constraints {testchannel testthread} -result {{watch rc* read} {watch rc* {}} {}}
+test iocmd.tf-30.2 {chan watch, write interest, error return} -match glob -body {
+ set res {}
+ proc foo {args} {oninit; onfinal; track; return -code error BOOM!_IGNORED}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [fileevent $c writable {set tick $tick}]
+ note [fileevent $c writable {}]
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -constraints {testchannel testthread} -result {{watch rc* write} {watch rc* {}} {} {}}
+test iocmd.tf-30.3 {chan watch, accumulated interests} -match glob -body {
+ set res {}
+ proc foo {args} {oninit; onfinal; track; return}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [fileevent $c writable {set tick $tick}]
+ note [fileevent $c readable {set tick $tick}]
+ note [fileevent $c writable {}]
+ note [fileevent $c readable {}]
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -constraints {testchannel testthread} \
+ -result {{watch rc* write} {watch rc* {read write}} {watch rc* read} {watch rc* {}} {} {} {} {}}
+test iocmd.tf-30.4 {chan watch, unchanged interest not forwarded} -match glob -body {
+ set res {}
+ proc foo {args} {oninit; onfinal; track; return}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ note [fileevent $c writable {set tick $tick}]
+ note [fileevent $c readable {set tick $tick}] ;# Script is changing,
+ note [fileevent $c readable {set tock $tock}] ;# interest does not.
+ close $c ;# 3rd and 4th watch, removing the event handlers.
+ notes
+ } c]
+ rename foo {}
+ set res
+} -constraints {testchannel testthread} \
+ -result {{watch rc* write} {watch rc* {read write}} {watch rc* write} {watch rc* {}} {} {} {}}
+
+# --- === *** ###########################
+# postevent
+# Not possible from a thread not containing the command handler.
+# Check that this is rejected.
+
+test iocmd.tf-31.8 {chan postevent, bad input} -match glob -body {
+ set res {}
+ proc foo {args} {oninit; onfinal; track; return}
+ set c [chan create {r w} foo]
+ notes [inthread $c {
+ catch {chan postevent $c r} msg
+ note $msg
+ close $c
+ notes
+ } c]
+ rename foo {}
+ set res
+} -constraints {testchannel testthread} \
+ -result {{can not find reflected channel named "rc*"}}
+
+# --- === *** ###########################
+# 'Pull the rug' tests. Create channel in a thread A, move to other
+# thread B, destroy the origin thread (A) before or during access from
+# B. Must not crash, must return proper errors.
+
+test iocmd.tf-32.0 {origin thread of moved channel gone} -match glob -body {
+
+ #puts <<$tcltest::mainThread>>main
+ set tida [testthread create];#puts <<$tida>>
+ set tidb [testthread create];#puts <<$tidb>>
+
+ # Set up channel in thread
+ testthread send $tida $helperscript
+ set chan [testthread send $tida {
+ proc foo {args} {oninit seek; onfinal; track; return}
+ set chan [chan create {r w} foo]
+ fconfigure $chan -buffering none
+ set chan
+ }]
+
+ # Move channel to 2nd thread.
+ testthread send $tida [list testchannel cut $chan]
+ testthread send $tidb [list testchannel splice $chan]
+
+ # Kill origin thread, then access channel from 2nd thread.
+ testthread send -async $tida {testthread exit}
+ after 100
+
+ set res {}
+ lappend res [catch {testthread send $tidb [list puts $chan shoo]} msg] $msg
+
+ lappend res [catch {testthread send $tidb [list tell $chan]} msg] $msg
+ lappend res [catch {testthread send $tidb [list seek $chan 1]} msg] $msg
+ lappend res [catch {testthread send $tidb [list gets $chan]} msg] $msg
+ lappend res [catch {testthread send $tidb [list close $chan]} msg] $msg
+ tcltest::threadReap
+ set res
+
+} -constraints {testchannel testthread} \
+ -result {1 {Owner lost} 1 {Owner lost} 1 {Owner lost} 1 {Owner lost} 1 {Owner lost}}
+
+test iocmd.tf-32.1 {origin thread of moved channel destroyed during access} -match glob -body {
+
+ #puts <<$tcltest::mainThread>>main
+ set tida [testthread create];#puts <<$tida>>
+ set tidb [testthread create];#puts <<$tidb>>
+
+ # Set up channel in thread
+ set chan [testthread send $tida $helperscript]
+ set chan [testthread send $tida {
+ proc foo {args} {
+ oninit; onfinal; track;
+ # destroy thread during channel access
+ testthread exit
+ return}
+ set chan [chan create {r w} foo]
+ fconfigure $chan -buffering none
+ set chan
+ }]
+
+ # Move channel to 2nd thread.
+ testthread send $tida [list testchannel cut $chan]
+ testthread send $tidb [list testchannel splice $chan]
+
+ # Run access from thread B, wait for response from A (A is not
+ # using event loop at this point, so the event pile up in the
+ # queue.
+
+ testthread send $tidb [list set chan $chan]
+ testthread send $tidb [list set mid $tcltest::mainThread]
+ testthread send -async $tidb {
+ # wait a bit, give the main thread the time to start its event
+ # loop to wait for the response from B
+ after 2000
+ catch { puts $chan shoo } res
+ testthread send -async $mid [list set ::res $res]
+ }
+ vwait ::res
+
+ tcltest::threadReap
+ set res
+} -constraints {testchannel testthread} \
+ -result {Owner lost}
+
+# ### ### ### ######### ######### #########
+
+# ### ### ### ######### ######### #########
+
+rename track {}
# cleanup
foreach file [list test1 test2 test3 test4] {
removeFile $file