1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
|
# 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
|