238 lines
4.6 KiB
Tcl
238 lines
4.6 KiB
Tcl
# vim:se syntax=tcl:
|
|
|
|
source [file dirname [info script]]/testing.tcl
|
|
|
|
needs cmd defer
|
|
needs cmd interp
|
|
|
|
test defer-1.1 {defer in proc} {
|
|
set x -
|
|
proc a {} {
|
|
set x +
|
|
# This does nothing since it increments a local variable
|
|
defer {append x L}
|
|
# This increments the global variable
|
|
defer {append ::x G}
|
|
# Will return "-", not "-L" since return happens before defer triggers
|
|
return $x
|
|
}
|
|
list [a] $x
|
|
} {+ -G}
|
|
|
|
test defer-1.2 {set $defer directly} {
|
|
set x -
|
|
proc a {} {
|
|
lappend jim::defer {append ::x a}
|
|
lappend jim::defer {append ::x b}
|
|
return $jim::defer
|
|
}
|
|
list [a] $x
|
|
} {{{append ::x a} {append ::x b}} -ba}
|
|
|
|
|
|
test defer-1.3 {unset $defer} {
|
|
set x -
|
|
proc a {} {
|
|
defer {append ::x a}
|
|
# unset, to remove all defer actions
|
|
unset jim::defer
|
|
}
|
|
a
|
|
set x
|
|
} {-}
|
|
|
|
test defer-1.4 {error in defer - error} {
|
|
set x -
|
|
proc a {} {
|
|
# First defer script will not happen because of error in next defer script
|
|
defer {append ::x a}
|
|
# Error ignored because of error from proc
|
|
defer {blah}
|
|
# Last defer script will happen
|
|
defer {append ::x b}
|
|
# This error will take precedence over the error from defer
|
|
error "from a"
|
|
}
|
|
set rc [catch {a} msg]
|
|
list [info ret $rc] $msg $x
|
|
} {error {from a} -b}
|
|
|
|
test defer-1.5 {error in defer - return} {
|
|
set x -
|
|
proc a {} {
|
|
# First defer script will not happen
|
|
defer {append ::x a}
|
|
defer {blah}
|
|
# Last defer script will happen
|
|
defer {append ::x b}
|
|
return 3
|
|
}
|
|
set rc [catch {a} msg]
|
|
list [info ret $rc] $msg $x
|
|
} {error {invalid command name "blah"} -b}
|
|
|
|
test defer-1.6 {error in defer - ok} {
|
|
set x -
|
|
proc a {} {
|
|
# First defer script will not happen
|
|
defer {append ::x a}
|
|
# Error ignored because of error from proc
|
|
defer {blah}
|
|
# Last defer script will happen
|
|
defer {append ::x b}
|
|
}
|
|
set rc [catch {a} msg]
|
|
list [info ret $rc] $msg $x
|
|
} {error {invalid command name "blah"} -b}
|
|
|
|
test defer-1.7 {error in defer - break} {
|
|
set x -
|
|
proc a {} {
|
|
# First defer script will not happen
|
|
defer {append ::x a}
|
|
# This non-zero return code will take precedence over the proc return
|
|
defer {return -code 30 ret30}
|
|
# Last defer script will happen
|
|
defer {append ::x b}
|
|
|
|
return -code 20 ret20
|
|
}
|
|
set rc [catch {a} msg]
|
|
list [info ret $rc] $msg $x
|
|
} {30 ret30 -b}
|
|
|
|
test defer-1.8 {error in defer - tailcall} {
|
|
set x -
|
|
proc a {} {
|
|
# This will prevent tailcall from happening
|
|
defer {blah}
|
|
|
|
# Tailcall will not happen because of error in defer
|
|
tailcall append ::x a
|
|
}
|
|
set rc [catch {a} msg]
|
|
list [info ret $rc] $msg $x
|
|
} {error {invalid command name "blah"} -}
|
|
|
|
test defer-1.9 {Add to defer in defer body} {
|
|
set x -
|
|
proc a {} {
|
|
defer {
|
|
# Add to defer in defer
|
|
defer {
|
|
# This will do nothing
|
|
error here
|
|
}
|
|
}
|
|
defer {append ::x a}
|
|
}
|
|
a
|
|
set x
|
|
} {-a}
|
|
|
|
test defer-1.10 {Unset defer in defer body} {
|
|
set x -
|
|
proc a {} {
|
|
defer {
|
|
# This will do nothing
|
|
unset -nocomplain jim::defer
|
|
}
|
|
defer {append ::x a}
|
|
}
|
|
a
|
|
set x
|
|
} {-a}
|
|
|
|
test defer-1.11 {defer through tailcall} {
|
|
set x {}
|
|
proc a {} {
|
|
defer {append ::x a}
|
|
b
|
|
}
|
|
proc b {} {
|
|
defer {append ::x b}
|
|
# c will be invoked as through called from a but this
|
|
# won't make any difference for defer
|
|
tailcall c
|
|
}
|
|
proc c {} {
|
|
defer {append ::x c}
|
|
}
|
|
a
|
|
set x
|
|
} {bca}
|
|
|
|
test defer-1.12 {defer in recursive call} {
|
|
set x {}
|
|
proc a {n} {
|
|
# defer happens just before the return, so after the recursive call to a
|
|
defer {lappend ::x $n}
|
|
if {$n > 0} {
|
|
a $($n - 1)
|
|
}
|
|
}
|
|
a 3
|
|
set x
|
|
} {0 1 2 3}
|
|
|
|
test defer-1.13 {defer in recursive tailcall} {
|
|
set x {}
|
|
proc a {n} {
|
|
# defer happens just before the return, so before the tailcall to a
|
|
defer {lappend ::x $n}
|
|
if {$n > 0} {
|
|
tailcall a $($n - 1)
|
|
}
|
|
}
|
|
a 3
|
|
set x
|
|
} {3 2 1 0}
|
|
|
|
test defer-1.14 {defer capture variables} {
|
|
set x {}
|
|
proc a {} {
|
|
set y 1
|
|
# A normal defer will evaluate at the end of the proc, so $y may change
|
|
defer {lappend ::x $y}
|
|
incr y
|
|
|
|
# What if we want to capture the value of y here? list will work
|
|
defer [list lappend ::x $y]
|
|
incr y
|
|
|
|
# But with multiple statements, list doesn't work, so use a lambda
|
|
# to capture the value instead
|
|
defer [lambda {} {y} {
|
|
# multi-line script
|
|
lappend ::x $y
|
|
}]
|
|
incr y
|
|
|
|
return $y
|
|
}
|
|
list [a] $x
|
|
} {4 {3 2 4}}
|
|
|
|
test defer-2.1 {defer from interp} -body {
|
|
set i [interp]
|
|
# defer needs to have some effect to detect on exit,
|
|
# so write to a file
|
|
file delete defer.tmp
|
|
$i eval {
|
|
defer {
|
|
[open defer.tmp w] puts "leaving child"
|
|
}
|
|
}
|
|
set a [file exists defer.tmp]
|
|
$i delete
|
|
# Now the file should exist
|
|
set f [open defer.tmp]
|
|
$f gets b
|
|
$f close
|
|
list $a $b
|
|
} -result {0 {leaving child}} -cleanup {
|
|
file delete defer.tmp
|
|
}
|
|
|
|
testreport
|