summaryrefslogtreecommitdiffstats
path: root/tests/io.test
diff options
context:
space:
mode:
Diffstat (limited to 'tests/io.test')
-rw-r--r--tests/io.test639
1 files changed, 559 insertions, 80 deletions
diff --git a/tests/io.test b/tests/io.test
index a25f3c3..edc0b11 100644
--- a/tests/io.test
+++ b/tests/io.test
@@ -12,16 +12,27 @@
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
-#
-# RCS: @(#) $Id: io.test,v 1.71 2006/03/21 11:12:29 dkf Exp $
if {[catch {package require tcltest 2}]} {
puts stderr "Skipping tests in [info script]. tcltest 2 required."
return
}
+
+::tcltest::loadTestedCommands
+catch [list package require -exact Tcltest [info patchlevel]]
+
namespace eval ::tcl::test::io {
namespace import ::tcltest::*
+ variable umaskValue
+ variable path
+ variable f
+ variable i
+ variable n
+ variable v
+ variable msg
+ variable expected
+
testConstraint testchannel [llength [info commands testchannel]]
testConstraint exec [llength [info commands exec]]
testConstraint openpipe 1
@@ -30,7 +41,7 @@ testConstraint fcopy [llength [info commands fcopy]]
testConstraint testfevent [llength [info commands testfevent]]
testConstraint testchannelevent [llength [info commands testchannelevent]]
testConstraint testmainthread [llength [info commands testmainthread]]
-testConstraint testthread [llength [info commands testthread]]
+testConstraint thread [expr {0 == [catch {package require Thread 2.7-}]}]
# You need a *very* special environment to do some tests. In
# particular, many file systems do not support large-files...
@@ -39,7 +50,7 @@ testConstraint largefileSupport 0
# some tests can only be run is umask is 2
# if "umask" cannot be run, the tests will be skipped.
set umaskValue 0
-testConstraint umask [expr {![catch {set umaskValue [exec /bin/sh -c umask]}]}]
+testConstraint umask [expr {![catch {set umaskValue [scan [exec /bin/sh -c umask] %o]}]}]
testConstraint makeFileInHome [expr {![file exists ~/_test_] && [file writable ~]}]
@@ -117,6 +128,66 @@ test io-1.8 {Tcl_WriteChars: WriteChars} {
contents $path(test2)
} " \x1b\$B\$O\x1b(B"
+test io-1.9 {Tcl_WriteChars: WriteChars} {
+ # When closing a channel with an encoding that appends
+ # escape bytes, check for the case where the escape
+ # bytes overflow the current IO buffer. The bytes
+ # should be moved into a new buffer.
+
+ set data "1234567890 [format %c 12399]"
+
+ set sizes [list]
+
+ # With default buffer size
+ set f [open $path(test2) w]
+ fconfigure $f -encoding iso2022-jp
+ puts -nonewline $f $data
+ close $f
+ lappend sizes [file size $path(test2)]
+
+ # With buffer size equal to the length
+ # of the data, the escape bytes would
+ # go into the next buffer.
+
+ set f [open $path(test2) w]
+ fconfigure $f -encoding iso2022-jp -buffersize 16
+ puts -nonewline $f $data
+ close $f
+ lappend sizes [file size $path(test2)]
+
+ # With buffer size that is large enough
+ # to hold 1 byte of escaped data, but
+ # not all 3. This should not write
+ # the escape bytes to the first buffer
+ # and then again to the second buffer.
+
+ set f [open $path(test2) w]
+ fconfigure $f -encoding iso2022-jp -buffersize 17
+ puts -nonewline $f $data
+ close $f
+ lappend sizes [file size $path(test2)]
+
+ # With buffer size that can hold 2 out of
+ # 3 bytes of escaped data.
+
+ set f [open $path(test2) w]
+ fconfigure $f -encoding iso2022-jp -buffersize 18
+ puts -nonewline $f $data
+ close $f
+ lappend sizes [file size $path(test2)]
+
+ # With buffer size that can hold all the
+ # data and escape bytes.
+
+ set f [open $path(test2) w]
+ fconfigure $f -encoding iso2022-jp -buffersize 19
+ puts -nonewline $f $data
+ close $f
+ lappend sizes [file size $path(test2)]
+
+ set sizes
+} {19 19 19 19 19}
+
test io-2.1 {WriteBytes} {
# loop until all bytes are written
@@ -1601,8 +1672,8 @@ test io-14.3 {Tcl_SetStdChannel & Tcl_GetStdChannel} {exec openpipe} {
out
} {err
}}
-# This test relies on the fact that the smallest available fd is used first.
-test io-14.4 {Tcl_SetStdChannel & Tcl_GetStdChannel} {exec unix} {
+# This test relies on the fact that stdout is used before stderr
+test io-14.4 {Tcl_SetStdChannel & Tcl_GetStdChannel} {exec} {
set f [open $path(test1) w]
puts -nonewline $f { close stdin
close stdout
@@ -1627,8 +1698,8 @@ test io-14.4 {Tcl_SetStdChannel & Tcl_GetStdChannel} {exec unix} {
close $f2
set result
} {{ close stdin
-file1
-} {file2
+stdout
+} {stderr
}}
catch {interp delete z}
test io-14.5 {Tcl_GetChannel: stdio name translation} {
@@ -2019,6 +2090,8 @@ set path(pipe) [makeFile {} pipe]
set path(output) [makeFile {} output]
test io-27.6 {FlushChannel, async flushing, async close} \
{stdio asyncPipeClose openpipe} {
+ # This test may fail on old Unix systems (seen on IRIX64 6.5) with
+ # obsolete gettimeofday() calls. See Tcl Bugs 3530533, 1942197.
file delete $path(pipe)
file delete $path(output)
set f [open $path(pipe) w]
@@ -2138,7 +2211,7 @@ test io-28.4 {Tcl_Close} {testchannel} {
close $f
lappend l [lsort [testchannel open]]
set x [list $consoleFileNames \
- [lsort [list {expand}$consoleFileNames $f]] \
+ [lsort [list {*}$consoleFileNames $f]] \
$consoleFileNames]
string compare $l $x
} 0
@@ -2153,7 +2226,7 @@ test io-28.5 {Tcl_Close vs standard handles} {stdio unix testchannel openpipe} {
set f [open "|[list [interpreter] $path(script)]" r]
set l [gets $f]
close $f
- set l
+ lsort $l
} {file1 file2}
test io-29.1 {Tcl_WriteChars, channel not writable} {
@@ -2539,11 +2612,11 @@ test io-29.27 {Tcl_Flush on closed pipeline} {stdio openpipe} {
# you disable the debugger's signal interception.
#
if {[catch {flush $f} msg]} {
- set x [list 1 $msg $errorCode]
+ set x [list 1 $msg $::errorCode]
catch {close $f}
} else {
if {[catch {close $f} msg]} {
- set x [list 1 $msg $errorCode]
+ set x [list 1 $msg $::errorCode]
} else {
set x {this was supposed to fail and did not}
}
@@ -2578,6 +2651,8 @@ test io-29.30 {Tcl_WriteChars, crlf mode} {
file size $path(test1)
} 25
test io-29.31 {Tcl_WriteChars, background flush} {stdio openpipe} {
+ # This test may fail on old Unix systems (seen on IRIX64 6.5) with
+ # obsolete gettimeofday() calls. See Tcl Bugs 3530533, 1942197.
file delete $path(pipe)
file delete $path(output)
set f [open $path(pipe) w]
@@ -2619,6 +2694,8 @@ test io-29.31 {Tcl_WriteChars, background flush} {stdio openpipe} {
} ok
test io-29.32 {Tcl_WriteChars, background flush to slow reader} \
{stdio asyncPipeClose openpipe} {
+ # This test may fail on old Unix systems (seen on IRIX64 6.5) with
+ # obsolete gettimeofday() calls. See Tcl Bugs 3530533, 1942197.
file delete $path(pipe)
file delete $path(output)
set f [open $path(pipe) w]
@@ -2669,6 +2746,26 @@ test io-29.33 {Tcl_Flush, implicit flush on exit} {exec} {
close $f
set r
} "hello\nbye\nstrange\n"
+set path(script2) [makeFile {} script2]
+test io-29.33b {TIP#398, no implicit flush of nonblocking on exit} {exec} {
+ set f [open $path(script) w]
+ puts $f {
+ fconfigure stdout -blocking 0
+ puts -nonewline stdout [string repeat A 655360]
+ flush stdout
+ }
+ close $f
+ set f [open $path(script2) w]
+ puts $f {after 2000}
+ close $f
+ set t1 [clock milliseconds]
+ set ff [open "|[list [interpreter] $path(script2)]" w]
+ catch {unset ::env(TCL_FLUSH_NONBLOCKING_ON_EXIT)}
+ exec [interpreter] $path(script) >@ $ff
+ set t2 [clock milliseconds]
+ close $ff
+ expr {($t2-$t1)/2000 ? $t2-$t1 : 0}
+} 0
test io-29.34 {Tcl_Close, async flush on close, using sockets} {socket tempNotMac fileevent} {
variable c 0
variable x running
@@ -2688,7 +2785,7 @@ test io-29.34 {Tcl_Close, async flush on close, using sockets} {socket tempNotMa
variable c
variable x
set l [gets $s]
-
+
if {[eof $s]} {
close $s
set x done
@@ -2696,8 +2793,8 @@ test io-29.34 {Tcl_Close, async flush on close, using sockets} {socket tempNotMa
incr c
}
}
- set ss [socket -server [namespace code accept] 0]
- set cs [socket [info hostname] [lindex [fconfigure $ss -sockname] 2]]
+ set ss [socket -server [namespace code accept] -myaddr 127.0.0.1 0]
+ set cs [socket 127.0.0.1 [lindex [fconfigure $ss -sockname] 2]]
vwait [namespace which -variable x]
fconfigure $cs -blocking off
writelots $cs $l
@@ -2707,19 +2804,19 @@ test io-29.34 {Tcl_Close, async flush on close, using sockets} {socket tempNotMa
set c
} 2000
test io-29.35 {Tcl_Close vs fileevent vs multiple interpreters} {socket tempNotMac fileevent} {
- # On Mac, this test screws up sockets such that subsequent tests using port 2828
+ # On Mac, this test screws up sockets such that subsequent tests using port 2828
# either cause errors or panic().
-
+
catch {interp delete x}
catch {interp delete y}
interp create x
interp create y
- set s [socket -server [namespace code accept] 0]
+ set s [socket -server [namespace code accept] -myaddr 127.0.0.1 0]
proc accept {s a p} {
puts $s hello
close $s
}
- set c [socket [info hostname] [lindex [fconfigure $s -sockname] 2]]
+ set c [socket 127.0.0.1 [lindex [fconfigure $s -sockname] 2]]
interp share {} $c x
interp share {} $c y
close $c
@@ -3789,7 +3886,7 @@ test io-32.3 {Tcl_Read, negative byte count} {
set l [list [catch {read $f -1} msg] $msg]
close $f
set l
-} {1 {bad argument "-1": should be "nonewline"}}
+} {1 {expected non-negative integer but got "-1"}}
test io-32.4 {Tcl_Read, positive byte count} {
set f [open $path(longfile) r]
set x [read $f 1024]
@@ -4283,7 +4380,7 @@ test io-34.15 {Tcl_Tell combined with seeking} {
close $f1
list $c1 $c2
} {10 20}
-test io-34.16 {Tcl_tell on pipe: always -1} {stdio openpipe} {
+test io-34.16 {Tcl_Tell on pipe: always -1} {stdio openpipe} {
set f1 [open "|[list [interpreter]]" r+]
set c [tell $f1]
close $f1
@@ -4628,6 +4725,77 @@ test io-35.17 {Tcl_Eof, eof char in middle, crlf write, crlf read} {
close $f
list $c $l $e
} {21 8 1}
+test io-35.18 {Tcl_Eof, eof char, cr write, crlf read} -body {
+ file delete $path(test1)
+ set f [open $path(test1) w]
+ fconfigure $f -translation cr
+ puts $f abc\ndef
+ close $f
+ set s [file size $path(test1)]
+ set f [open $path(test1) r]
+ fconfigure $f -translation crlf
+ set l [string length [set in [read $f]]]
+ set e [eof $f]
+ close $f
+ list $s $l $e [scan [string index $in end] %c]
+} -result {8 8 1 13}
+test io-35.18a {Tcl_Eof, eof char, cr write, crlf read} -body {
+ file delete $path(test1)
+ set f [open $path(test1) w]
+ fconfigure $f -translation cr -eofchar \x1a
+ puts $f abc\ndef
+ close $f
+ set s [file size $path(test1)]
+ set f [open $path(test1) r]
+ fconfigure $f -translation crlf -eofchar \x1a
+ set l [string length [set in [read $f]]]
+ set e [eof $f]
+ close $f
+ list $s $l $e [scan [string index $in end] %c]
+} -result {9 8 1 13}
+test io-35.18b {Tcl_Eof, eof char, cr write, crlf read} -constraints knownBug -body {
+ file delete $path(test1)
+ set f [open $path(test1) w]
+ fconfigure $f -translation cr -eofchar \x1a
+ puts $f {}
+ close $f
+ set s [file size $path(test1)]
+ set f [open $path(test1) r]
+ fconfigure $f -translation crlf -eofchar \x1a
+ set l [string length [set in [read $f]]]
+ set e [eof $f]
+ close $f
+ list $s $l $e [scan [string index $in end] %c]
+} -result {2 1 1 13}
+test io-35.18c {Tcl_Eof, eof char, cr write, crlf read} -body {
+ file delete $path(test1)
+ set f [open $path(test1) w]
+ fconfigure $f -translation cr
+ puts $f {}
+ close $f
+ set s [file size $path(test1)]
+ set f [open $path(test1) r]
+ fconfigure $f -translation crlf
+ set l [string length [set in [read $f]]]
+ set e [eof $f]
+ close $f
+ list $s $l $e [scan [string index $in end] %c]
+} -result {1 1 1 13}
+test io-35.19 {Tcl_Eof, eof char in middle, cr write, crlf read} -body {
+ file delete $path(test1)
+ set f [open $path(test1) w]
+ fconfigure $f -translation cr -eofchar {}
+ set i [format abc\ndef\n%cqrs\nuvw 26]
+ puts $f $i
+ close $f
+ set c [file size $path(test1)]
+ set f [open $path(test1) r]
+ fconfigure $f -translation crlf -eofchar \x1a
+ set l [string length [set in [read $f]]]
+ set e [eof $f]
+ close $f
+ list $c $l $e [scan [string index $in end] %c]
+} -result {17 8 1 13}
# Test Tcl_InputBlocked
@@ -4789,7 +4957,7 @@ test io-38.2 {Tcl_SetChannelBufferSize, Tcl_GetChannelBufferSize} {
lappend l [fconfigure $f -buffersize]
close $f
set l
-} {4096 10000 1 1 1 100000 100000}
+} {4096 10000 1 1 1 100000 1048576}
test io-38.3 {Tcl_SetChannelBufferSize, changing buffersize between reads} {
# This test crashes the interp if Bug #427196 is not fixed
@@ -4950,22 +5118,22 @@ test io-39.10 {Tcl_SetChannelOption, blocking mode} {stdio openpipe} {
close $f1
set x
} {0 {} 1 {} 1 {} 1 1 hi 0 0 {} 1}
-test io-39.11 {Tcl_SetChannelOption, Tcl_GetChannelOption, buffer size} {
+test io-39.11 {Tcl_SetChannelOption, Tcl_GetChannelOption, buffer size clipped to lower bound} {
file delete $path(test1)
set f [open $path(test1) w]
fconfigure $f -buffersize -10
set x [fconfigure $f -buffersize]
close $f
set x
-} 4096
-test io-39.12 {Tcl_SetChannelOption, Tcl_GetChannelOption buffer size} {
+} 1
+test io-39.12 {Tcl_SetChannelOption, Tcl_GetChannelOption buffer size clipped to upper bound} {
file delete $path(test1)
set f [open $path(test1) w]
fconfigure $f -buffersize 10000000
set x [fconfigure $f -buffersize]
close $f
set x
-} 4096
+} 1048576
test io-39.13 {Tcl_SetChannelOption, Tcl_GetChannelOption, buffer size} {
file delete $path(test1)
set f [open $path(test1) w]
@@ -5030,7 +5198,7 @@ test io-39.17 {Tcl_SetChannelOption: -encoding, clearing CHANNEL_NEED_MORE_DATA}
test io-39.18 {Tcl_SetChannelOption, setting read mode independently} \
{socket} {
proc accept {s a p} {close $s}
- set s1 [socket -server [namespace code accept] 0]
+ set s1 [socket -server [namespace code accept] -myaddr 127.0.0.1 0]
set port [lindex [fconfigure $s1 -sockname] 2]
set s2 [socket 127.0.0.1 $port]
update
@@ -5043,7 +5211,7 @@ test io-39.18 {Tcl_SetChannelOption, setting read mode independently} \
test io-39.19 {Tcl_SetChannelOption, setting read mode independently} \
{socket} {
proc accept {s a p} {close $s}
- set s1 [socket -server [namespace code accept] 0]
+ set s1 [socket -server [namespace code accept] -myaddr 127.0.0.1 0]
set port [lindex [fconfigure $s1 -sockname] 2]
set s2 [socket 127.0.0.1 $port]
update
@@ -5056,7 +5224,7 @@ test io-39.19 {Tcl_SetChannelOption, setting read mode independently} \
test io-39.20 {Tcl_SetChannelOption, setting read mode independently} \
{socket} {
proc accept {s a p} {close $s}
- set s1 [socket -server [namespace code accept] 0]
+ set s1 [socket -server [namespace code accept] -myaddr 127.0.0.1 0]
set port [lindex [fconfigure $s1 -sockname] 2]
set s2 [socket 127.0.0.1 $port]
update
@@ -5069,7 +5237,7 @@ test io-39.20 {Tcl_SetChannelOption, setting read mode independently} \
test io-39.21 {Tcl_SetChannelOption, setting read mode independently} \
{socket} {
proc accept {s a p} {close $s}
- set s1 [socket -server [namespace code accept] 0]
+ set s1 [socket -server [namespace code accept] -myaddr 127.0.0.1 0]
set port [lindex [fconfigure $s1 -sockname] 2]
set s2 [socket 127.0.0.1 $port]
update
@@ -5106,7 +5274,7 @@ test io-39.22a {Tcl_SetChannelOption, invariance} {
test io-39.23 {Tcl_GetChannelOption, server socket is not readable or
writeable, it should still have valid -eofchar and -translation options } {
set l [list]
- set sock [socket -server [namespace code accept] 0]
+ set sock [socket -server [namespace code accept] -myaddr 127.0.0.1 0]
lappend l [fconfigure $sock -eofchar] [fconfigure $sock -translation]
close $sock
set l
@@ -5114,7 +5282,7 @@ test io-39.23 {Tcl_GetChannelOption, server socket is not readable or
test io-39.24 {Tcl_SetChannelOption, server socket is not readable or
writable so we can't change -eofchar or -translation } {
set l [list]
- set sock [socket -server [namespace code accept] 0]
+ set sock [socket -server [namespace code accept] -myaddr 127.0.0.1 0]
fconfigure $sock -eofchar D -translation lf
lappend l [fconfigure $sock -eofchar] [fconfigure $sock -translation]
close $sock
@@ -5138,24 +5306,24 @@ test io-40.1 {POSIX open access modes: RDWR} {
} {zzy abzzy}
test io-40.2 {POSIX open access modes: CREAT} {unix} {
file delete $path(test3)
- set f [open $path(test3) {WRONLY CREAT} 0600]
+ set f [open $path(test3) {WRONLY CREAT} 0o600]
file stat $path(test3) stats
- set x [format "0%o" [expr $stats(mode)&0777]]
+ set x [format "0o%o" [expr $stats(mode)&0o777]]
puts $f "line 1"
close $f
set f [open $path(test3) r]
lappend x [gets $f]
close $f
set x
-} {0600 {line 1}}
+} {0o600 {line 1}}
test io-40.3 {POSIX open access modes: CREAT} {unix umask} {
# This test only works if your umask is 2, like ouster's.
file delete $path(test3)
set f [open $path(test3) {WRONLY CREAT}]
close $f
file stat $path(test3) stats
- format "0%o" [expr $stats(mode)&0777]
-} [format %04o [expr {0666 & ~ $umaskValue}]]
+ format "0%o" [expr $stats(mode)&0o777]
+} [format %04o [expr {0o666 & ~ $umaskValue}]]
test io-40.4 {POSIX open access modes: CREAT} {
file delete $path(test3)
set f [open $path(test3) w]
@@ -5278,15 +5446,15 @@ test io-40.15 {POSIX open access modes: RDWR} {
test io-40.16 {tilde substitution in open} -constraints makeFileInHome -setup {
makeFile {Some text} _test_ ~
} -body {
- file exists [file join $env(HOME) _test_]
+ file exists [file join $::env(HOME) _test_]
} -cleanup {
removeFile _test_ ~
} -result 1
test io-40.17 {tilde substitution in open} {
- set home $env(HOME)
- unset env(HOME)
+ set home $::env(HOME)
+ unset ::env(HOME)
set x [list [catch {open ~/foo} msg] $msg]
- set env(HOME) $home
+ set ::env(HOME) $home
set x
} {1 {couldn't find HOME environment variable to expand path}}
@@ -6391,27 +6559,29 @@ test io-51.1 {Test old socket deletion on Macintosh} {socket} {
close $s
set wait done
}
- set ss [socket -server [namespace code accept] 0]
+ set ss [socket -server [namespace code accept] -myaddr 127.0.0.1 0]
+ set port [lindex [fconfigure $ss -sockname] 2]
+
variable wait ""
- set cs [socket [info hostname] [lindex [fconfigure $ss -sockname] 2]]
+ set cs [socket 127.0.0.1 $port]
vwait [namespace which -variable wait]
lappend result [gets $cs]
close $cs
set wait ""
- set cs [socket [info hostname] [lindex [fconfigure $ss -sockname] 2]]
+ set cs [socket 127.0.0.1 $port]
vwait [namespace which -variable wait]
lappend result [gets $cs]
close $cs
set wait ""
- set cs [socket [info hostname] [lindex [fconfigure $ss -sockname] 2]]
+ set cs [socket 127.0.0.1 $port]
vwait [namespace which -variable wait]
lappend result [gets $cs]
close $cs
set wait ""
- set cs [socket [info hostname] [lindex [fconfigure $ss -sockname] 2]]
+ set cs [socket 127.0.0.1 $port]
vwait [namespace which -variable wait]
lappend result [gets $cs]
close $cs
@@ -6470,13 +6640,47 @@ test io-52.4 {TclCopyChannel} {fcopy} {
close $f2
lappend result [file size $path(test1)]
} {0 0 40}
-test io-52.5 {TclCopyChannel} {fcopy} {
+test io-52.5 {TclCopyChannel, all} {fcopy} {
+ file delete $path(test1)
+ set f1 [open $thisScript]
+ set f2 [open $path(test1) w]
+ fconfigure $f1 -translation lf -blocking 0
+ fconfigure $f2 -translation lf -blocking 0
+ fcopy $f1 $f2 -size -1 ;# -1 means 'copy all', same as if no -size specified.
+ set result [list [fconfigure $f1 -blocking] [fconfigure $f2 -blocking]]
+ close $f1
+ close $f2
+ set s1 [file size $thisScript]
+ set s2 [file size $path(test1)]
+ if {"$s1" == "$s2"} {
+ lappend result ok
+ }
+ set result
+} {0 0 ok}
+test io-52.5a {TclCopyChannel, all, other negative value} {fcopy} {
file delete $path(test1)
set f1 [open $thisScript]
set f2 [open $path(test1) w]
fconfigure $f1 -translation lf -blocking 0
fconfigure $f2 -translation lf -blocking 0
- fcopy $f1 $f2 -size -1
+ fcopy $f1 $f2 -size -2 ;# < 0 behaves like -1, copy all
+ set result [list [fconfigure $f1 -blocking] [fconfigure $f2 -blocking]]
+ close $f1
+ close $f2
+ set s1 [file size $thisScript]
+ set s2 [file size $path(test1)]
+ if {"$s1" == "$s2"} {
+ lappend result ok
+ }
+ set result
+} {0 0 ok}
+test io-52.5b {TclCopyChannel, all, wrap to negative value} {fcopy} {
+ file delete $path(test1)
+ set f1 [open $thisScript]
+ set f2 [open $path(test1) w]
+ fconfigure $f1 -translation lf -blocking 0
+ fconfigure $f2 -translation lf -blocking 0
+ fcopy $f1 $f2 -size 3221176172 ;# Wrapped to < 0, behaves like -1, copy all
set result [list [fconfigure $f1 -blocking] [fconfigure $f2 -blocking]]
close $f1
close $f2
@@ -6735,7 +6939,7 @@ proc FcopyTestDone {bytes {error {}}} {
}
test io-53.5 {CopyData: error during fcopy} {socket fcopy} {
variable fcopyTestDone
- set listen [socket -server [namespace code FcopyTestAccept] 0]
+ set listen [socket -server [namespace code FcopyTestAccept] -myaddr 127.0.0.1 0]
set in [open $thisScript] ;# 126 K
set out [socket 127.0.0.1 [lindex [fconfigure $listen -sockname] 2]]
catch {unset fcopyTestDone}
@@ -6816,6 +7020,280 @@ test io-53.7 {CopyData: Flooding fcopy from pipe} {stdio openpipe fcopy} {
# -1=error 0=script error N=number of bytes
expr ($fcopyTestDone == 0) ? $fcopyTestCount : -1
} {3450}
+test io-53.8 {CopyData: async callback and error handling, Bug 1932639} -setup {
+ # copy progress callback. errors out intentionally
+ proc ::cmd args {
+ lappend ::RES "CMD $args"
+ error !STOP
+ }
+ # capture callback error here
+ proc ::bgerror args {
+ lappend ::RES "bgerror/OK $args"
+ set ::forever has-been-reached
+ return
+ }
+ # Files we use for our channels
+ set foo [makeFile ashgdfashdgfasdhgfasdhgf foo]
+ set bar [makeFile {} bar]
+ # Channels to copy between
+ set f [open $foo r] ; fconfigure $f -translation binary
+ set g [open $bar w] ; fconfigure $g -translation binary -buffering none
+} -constraints {stdio openpipe fcopy} -body {
+ # Record input size, so that result is always defined
+ lappend ::RES [file size $bar]
+ # Run the copy. Should not invoke -command now.
+ fcopy $f $g -size 2 -command ::cmd
+ # Check that -command was not called synchronously
+ set sbs [file size $bar]
+ lappend ::RES [expr {($sbs > 0) ? "sync/FAIL" : "sync/OK"}] $sbs
+ # Now let the async part happen. Should capture the error in cmd
+ # via bgerror. If not break the event loop via timer.
+ set token [after 1000 {
+ lappend ::RES {bgerror/FAIL timeout}
+ set ::forever has-been-reached
+ }]
+ vwait ::forever
+ catch {after cancel $token}
+ # Report
+ set ::RES
+} -cleanup {
+ close $f
+ close $g
+ catch {unset ::RES}
+ catch {unset ::forever}
+ rename ::cmd {}
+ rename ::bgerror {}
+ removeFile foo
+ removeFile bar
+} -result {0 sync/OK 0 {CMD 2} {bgerror/OK !STOP}}
+test io-53.8a {CopyData: async callback and error handling, Bug 1932639, at eof} -setup {
+ # copy progress callback. errors out intentionally
+ proc ::cmd args {
+ lappend ::RES "CMD $args"
+ set ::forever has-been-reached
+ return
+ }
+ # Files we use for our channels
+ set foo [makeFile ashgdfashdgfasdhgfasdhgf foo]
+ set bar [makeFile {} bar]
+ # Channels to copy between
+ set f [open $foo r] ; fconfigure $f -translation binary
+ set g [open $bar w] ; fconfigure $g -translation binary -buffering none
+} -constraints {stdio openpipe fcopy} -body {
+ # Initialize and force eof on the input.
+ seek $f 0 end ; read $f 1
+ set ::RES [eof $f]
+ # Run the copy. Should not invoke -command now.
+ fcopy $f $g -size 2 -command ::cmd
+ # Check that -command was not called synchronously
+ lappend ::RES [expr {([llength $::RES] > 1) ? "sync/FAIL" : "sync/OK"}]
+ # Now let the async part happen. Should capture the eof in cmd
+ # If not break the event loop via timer.
+ set token [after 1000 {
+ lappend ::RES {cmd/FAIL timeout}
+ set ::forever has-been-reached
+ }]
+ vwait ::forever
+ catch {after cancel $token}
+ # Report
+ set ::RES
+} -cleanup {
+ close $f
+ close $g
+ catch {unset ::RES}
+ catch {unset ::forever}
+ rename ::cmd {}
+ removeFile foo
+ removeFile bar
+} -result {1 sync/OK {CMD 0}}
+test io-53.8b {CopyData: async callback and -size 0} -setup {
+ # copy progress callback. errors out intentionally
+ proc ::cmd args {
+ lappend ::RES "CMD $args"
+ set ::forever has-been-reached
+ return
+ }
+ # Files we use for our channels
+ set foo [makeFile ashgdfashdgfasdhgfasdhgf foo]
+ set bar [makeFile {} bar]
+ # Channels to copy between
+ set f [open $foo r] ; fconfigure $f -translation binary
+ set g [open $bar w] ; fconfigure $g -translation binary -buffering none
+} -constraints {stdio openpipe fcopy} -body {
+ set ::RES {}
+ # Run the copy. Should not invoke -command now.
+ fcopy $f $g -size 0 -command ::cmd
+ # Check that -command was not called synchronously
+ lappend ::RES [expr {([llength $::RES] > 1) ? "sync/FAIL" : "sync/OK"}]
+ # Now let the async part happen. Should capture the eof in cmd
+ # If not break the event loop via timer.
+ set token [after 1000 {
+ lappend ::RES {cmd/FAIL timeout}
+ set ::forever has-been-reached
+ }]
+ vwait ::forever
+ catch {after cancel $token}
+ # Report
+ set ::RES
+} -cleanup {
+ close $f
+ close $g
+ catch {unset ::RES}
+ catch {unset ::forever}
+ rename ::cmd {}
+ removeFile foo
+ removeFile bar
+} -result {sync/OK {CMD 0}}
+test io-53.9 {CopyData: -size and event interaction, Bug 780533} -setup {
+ set out [makeFile {} out]
+ set err [makeFile {} err]
+ set pipe [open "|[list [info nameofexecutable] 2> $err]" r+]
+ fconfigure $pipe -translation binary -buffering line
+ puts $pipe {
+ fconfigure stdout -translation binary -buffering line
+ puts stderr Waiting...
+ after 1000
+ foreach x {a b c} {
+ puts stderr Looping...
+ puts $x
+ after 500
+ }
+ proc bye args {
+ if {[gets stdin line]<0} {
+ puts stderr "CHILD: EOF detected, exiting"
+ exit
+ } else {
+ puts stderr "CHILD: ignoring line: $line"
+ }
+ }
+ puts stderr Now-sleeping-forever
+ fileevent stdin readable bye
+ vwait forever
+ }
+ proc ::done args {
+ set ::forever OK
+ return
+ }
+ set ::forever {}
+ set out [open $out w]
+} -constraints {stdio openpipe fcopy} -body {
+ fcopy $pipe $out -size 6 -command ::done
+ set token [after 5000 {
+ set ::forever {fcopy hangs}
+ }]
+ vwait ::forever
+ catch {after cancel $token}
+ set ::forever
+} -cleanup {
+ close $pipe
+ rename ::done {}
+ after 1000; # Give Windows time to kill the process
+ catch {close $out}
+ catch {removeFile out}
+ catch {removeFile err}
+ catch {unset ::forever}
+} -result OK
+test io-53.10 {Bug 1350564, multi-directional fcopy} -setup {
+ set err [makeFile {} err]
+ set pipe [open "|[list [info nameofexecutable] 2> $err]" r+]
+ fconfigure $pipe -translation binary -buffering line
+ puts $pipe {
+ fconfigure stderr -buffering line
+ # Kill server when pipe closed by invoker.
+ proc bye args {
+ if {![eof stdin]} { gets stdin ; return }
+ puts stderr BYE
+ exit
+ }
+ # Server code. Bi-directional copy between 2 sockets.
+ proc geof {sok} {
+ puts stderr DONE/$sok
+ close $sok
+ }
+ proc new {sok args} {
+ puts stderr NEW/$sok
+ global l srv
+ fconfigure $sok -translation binary -buffering none
+ lappend l $sok
+ if {[llength $l]==2} {
+ close $srv
+ foreach {a b} $l break
+ fcopy $a $b -command [list geof $a]
+ fcopy $b $a -command [list geof $b]
+ puts stderr 2COPY
+ }
+ puts stderr ...
+ }
+ puts stderr SRV
+ set l {}
+ set srv [socket -server new 9999]
+ puts stderr WAITING
+ fileevent stdin readable bye
+ puts OK
+ vwait forever
+ }
+ # wait for OK from server.
+ gets $pipe
+ # Now the two clients.
+ proc ::done {sock} {
+ if {[eof $sock]} { close $sock ; return }
+ lappend ::forever [gets $sock]
+ return
+ }
+ set a [socket 127.0.0.1 9999]
+ set b [socket 127.0.0.1 9999]
+ fconfigure $a -translation binary -buffering none
+ fconfigure $b -translation binary -buffering none
+ fileevent $a readable [list ::done $a]
+ fileevent $b readable [list ::done $b]
+} -constraints {stdio openpipe fcopy} -body {
+ # Now pass data through the server in both directions.
+ set ::forever {}
+ puts $a AB
+ vwait ::forever
+ puts $b BA
+ vwait ::forever
+ set ::forever
+} -cleanup {
+ catch {close $a}
+ catch {close $b}
+ close $pipe
+ rename ::done {}
+ after 1000 ;# Give Windows time to kill the process
+ removeFile err
+ catch {unset ::forever}
+} -result {AB BA}
+test io-53.11 {Bug 2895565} -setup {
+ set in [makeFile {} in]
+ set f [open $in w]
+ fconfigure $f -encoding utf-8 -translation binary
+ puts -nonewline $f [string repeat "Ho hum\n" 11]
+ close $f
+ set inChan [open $in r]
+ fconfigure $inChan -translation binary
+ set out [makeFile {} out]
+ set outChan [open $out w]
+ fconfigure $outChan -encoding cp1252 -translation crlf
+ proc CopyDone {bytes args} {
+ variable done
+ if {[llength $args]} {
+ set done "Error: '[lindex $args 0]' after $bytes bytes copied"
+ } else {
+ set done "$bytes bytes copied"
+ }
+ }
+} -body {
+ variable done
+ after 2000 [list set [namespace which -variable done] timeout]
+ fcopy $inChan $outChan -size 40 -command [namespace which CopyDone]
+ vwait [namespace which -variable done]
+ set done
+} -cleanup {
+ close $outChan
+ close $inChan
+ removeFile out
+ removeFile in
+} -result {40 bytes copied}
test io-54.1 {Recursive channel events} {socket fileevent} {
# This test checks to see if file events are delivered during recursive
@@ -6838,14 +7316,14 @@ test io-54.1 {Recursive channel events} {socket fileevent} {
}
incr x
}
- set ss [socket -server [namespace code accept] 0]
+ set ss [socket -server [namespace code accept] -myaddr 127.0.0.1 0]
# We need to delay on some systems until the creation of the
# server socket completes.
set done 0
for {set i 0} {$i < 10} {incr i} {
- if {![catch {set cs [socket [info hostname] [lindex [fconfigure $ss -sockname] 2]]}]} {
+ if {![catch {set cs [socket 127.0.0.1 [lindex [fconfigure $ss -sockname] 2]]}]} {
set done 1
break
}
@@ -6874,7 +7352,7 @@ test io-54.1 {Recursive channel events} {socket fileevent} {
test io-54.2 {Testing for busy-wait in recursive channel events} {socket fileevent} {
set accept {}
set after {}
- variable s [socket -server [namespace code accept] 0]
+ variable s [socket -server [namespace code accept] -myaddr 127.0.0.1 0]
proc accept {s a p} {
variable counter
variable accept
@@ -6984,7 +7462,7 @@ test io-57.1 {buffered data and file events, gets} {fileevent} {
variable s2
set s2 $sock
}
- set server [socket -server [namespace code accept] 0]
+ set server [socket -server [namespace code accept] -myaddr 127.0.0.1 0]
set s [socket 127.0.0.1 [lindex [fconfigure $server -sockname] 2]]
variable s2
vwait [namespace which -variable s2]
@@ -7007,7 +7485,7 @@ test io-57.2 {buffered data and file events, read} {fileevent} {
variable s2
set s2 $sock
}
- set server [socket -server [namespace code accept] 0]
+ set server [socket -server [namespace code accept] -myaddr 127.0.0.1 0]
set s [socket 127.0.0.1 [lindex [fconfigure $server -sockname] 2]]
variable s2
vwait [namespace which -variable s2]
@@ -7058,7 +7536,7 @@ test io-59.1 {Thread reference of channels} {testmainthread testchannel} {
# More complicated tests (like that the reference changes as a
# channel is moved from thread to thread) can be done only in the
# extension which fully implements the moving of channels between
- # threads, i.e. 'Threads'. Or we have to extend [testthread] as well.
+ # threads, i.e. 'Threads'.
set f [open $path(longfile) r]
set result [testchannel mthread $f]
@@ -7150,25 +7628,7 @@ test io-70.0 {Cutting & Splicing channels} {testchannel} {
} {0 1 0}
-# 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
- }
-}
-
-test io-70.1 {Transfer channel} {testchannel testthread} {
+test io-70.1 {Transfer channel} {testchannel thread} {
set f [makeFile {... dummy ...} cutsplice]
set c [open $f r]
@@ -7177,16 +7637,17 @@ test io-70.1 {Transfer channel} {testchannel testthread} {
testchannel cut $c
lappend res [catch {seek $c 0 start}]
- set tid [testthread create]
- testthread send $tid [list set c $c]
- lappend res [testthread send $tid {
+ set tid [thread::create -preserved]
+ thread::send $tid [list set c $c]
+ thread::send $tid {load {} Tcltest}
+ lappend res [thread::send $tid {
testchannel splice $c
set res [catch {seek $c 0 start}]
close $c
set res
}]
- tcltest::threadReap
+ thread::release $tid
removeFile cutsplice
set res
@@ -7380,11 +7841,29 @@ foreach {n msg expected} {
} [lrange $expected 0 end]
}
+test io-73.1 {channel Tcl_Obj SetChannelFromAny} {} {
+ # Test for Bug 1847044 - don't spoil type unless we have a valid channel
+ catch {close [lreplace [list a] 0 end]}
+} {1}
+
+test io-73.2 {channel Tcl_Obj SetChannelFromAny, bug 2407783} -setup {
+ # Invalidate intrep of 'channel' Tcl_Obj when transiting between interpreters.
+ set f [open [info script] r]
+} -body {
+ interp create foo
+ seek $f 0
+ set code [catch {interp eval foo [list seek $f 0]} msg]
+ # The string map converts the changing channel handle to a fixed string
+ list $code [string map [list $f @@] $msg]
+} -cleanup {
+ close $f
+} -result {1 {can not find channel named "@@"}}
+
# ### ### ### ######### ######### #########
# cleanup
-foreach file [list fooBar longfile script output test1 pipe my_script foo \
- bar test2 test3 cat stdout kyrillic.txt utf8-fcopy.txt utf8-rp.txt] {
+foreach file [list fooBar longfile script script2 output test1 pipe my_script \
+ test2 test3 cat stdout kyrillic.txt utf8-fcopy.txt utf8-rp.txt] {
removeFile $file
}
cleanupTests