| [25] | 1 | # Commands covered:  apply | 
|---|
 | 2 | # | 
|---|
 | 3 | # This file contains a collection of tests for one or more of the Tcl | 
|---|
 | 4 | # built-in commands.  Sourcing this file into Tcl runs the tests and | 
|---|
 | 5 | # generates output for errors.  No output means no errors were found. | 
|---|
 | 6 | # | 
|---|
 | 7 | # Copyright (c) 1991-1993 The Regents of the University of California. | 
|---|
 | 8 | # Copyright (c) 1994-1996 Sun Microsystems, Inc. | 
|---|
 | 9 | # Copyright (c) 1998-1999 by Scriptics Corporation. | 
|---|
 | 10 | # Copyright (c) 2005-2006 Miguel Sofer | 
|---|
 | 11 | # | 
|---|
 | 12 | # See the file "license.terms" for information on usage and redistribution | 
|---|
 | 13 | # of this file, and for a DISCLAIMER OF ALL WARRANTIES. | 
|---|
 | 14 | # | 
|---|
 | 15 | # RCS: @(#) $Id: apply.test,v 1.12 2007/12/13 15:26:04 dgp Exp $ | 
|---|
 | 16 |  | 
|---|
 | 17 | if {[lsearch [namespace children] ::tcltest] == -1} { | 
|---|
 | 18 |     package require tcltest 2.2 | 
|---|
 | 19 |     namespace import -force ::tcltest::* | 
|---|
 | 20 | } | 
|---|
 | 21 |  | 
|---|
 | 22 | if {[info commands ::apply] eq {}} { | 
|---|
 | 23 |     return | 
|---|
 | 24 | } | 
|---|
 | 25 |  | 
|---|
 | 26 | testConstraint memory [llength [info commands memory]] | 
|---|
 | 27 |  | 
|---|
 | 28 | # Tests for wrong number of arguments | 
|---|
 | 29 |  | 
|---|
 | 30 | test apply-1.1 {too few arguments} { | 
|---|
 | 31 |     set res [catch apply msg] | 
|---|
 | 32 |     list $res $msg | 
|---|
 | 33 | } {1 {wrong # args: should be "apply lambdaExpr ?arg1 arg2 ...?"}} | 
|---|
 | 34 |  | 
|---|
 | 35 | # Tests for malformed lambda | 
|---|
 | 36 |  | 
|---|
 | 37 | test apply-2.0 {malformed lambda} { | 
|---|
 | 38 |     set lambda a | 
|---|
 | 39 |     set res [catch {apply $lambda} msg] | 
|---|
 | 40 |     list $res $msg | 
|---|
 | 41 | } {1 {can't interpret "a" as a lambda expression}} | 
|---|
 | 42 | test apply-2.1 {malformed lambda} { | 
|---|
 | 43 |     set lambda [list a b c d] | 
|---|
 | 44 |     set res [catch {apply $lambda} msg] | 
|---|
 | 45 |     list $res $msg | 
|---|
 | 46 | } {1 {can't interpret "a b c d" as a lambda expression}} | 
|---|
 | 47 | test apply-2.2 {malformed lambda} { | 
|---|
 | 48 |     set lambda [list {{}} boo] | 
|---|
 | 49 |     set res [catch {apply $lambda} msg] | 
|---|
 | 50 |     list $res $msg $::errorInfo | 
|---|
 | 51 | } {1 {argument with no name} {argument with no name | 
|---|
 | 52 |     (parsing lambda expression "{{}} boo") | 
|---|
 | 53 |     invoked from within | 
|---|
 | 54 | "apply $lambda"}} | 
|---|
 | 55 | test apply-2.3 {malformed lambda} { | 
|---|
 | 56 |     set lambda [list {{a b c}} boo] | 
|---|
 | 57 |     set res [catch {apply $lambda} msg] | 
|---|
 | 58 |     list $res $msg $::errorInfo | 
|---|
 | 59 | } {1 {too many fields in argument specifier "a b c"} {too many fields in argument specifier "a b c" | 
|---|
 | 60 |     (parsing lambda expression "{{a b c}} boo") | 
|---|
 | 61 |     invoked from within | 
|---|
 | 62 | "apply $lambda"}} | 
|---|
 | 63 | test apply-2.4 {malformed lambda} { | 
|---|
 | 64 |     set lambda [list a(1) boo] | 
|---|
 | 65 |     set res [catch {apply $lambda} msg] | 
|---|
 | 66 |     list $res $msg $::errorInfo | 
|---|
 | 67 | } {1 {formal parameter "a(1)" is an array element} {formal parameter "a(1)" is an array element | 
|---|
 | 68 |     (parsing lambda expression "a(1) boo") | 
|---|
 | 69 |     invoked from within | 
|---|
 | 70 | "apply $lambda"}} | 
|---|
 | 71 | test apply-2.5 {malformed lambda} { | 
|---|
 | 72 |     set lambda [list a::b boo] | 
|---|
 | 73 |     set res [catch {apply $lambda} msg] | 
|---|
 | 74 |     list $res $msg $::errorInfo | 
|---|
 | 75 | } {1 {formal parameter "a::b" is not a simple name} {formal parameter "a::b" is not a simple name | 
|---|
 | 76 |     (parsing lambda expression "a::b boo") | 
|---|
 | 77 |     invoked from within | 
|---|
 | 78 | "apply $lambda"}} | 
|---|
 | 79 |  | 
|---|
 | 80 | # Tests for runtime errors in the lambda expression | 
|---|
 | 81 |  | 
|---|
 | 82 | test apply-3.1 {non-existing namespace} -body { | 
|---|
 | 83 |     apply [list x {set x 1} ::NONEXIST::FOR::SURE] x | 
|---|
 | 84 | } -returnCodes error -result {namespace "::NONEXIST::FOR::SURE" not found} | 
|---|
 | 85 | test apply-3.2 {non-existing namespace} -body { | 
|---|
 | 86 |     namespace eval ::NONEXIST::FOR::SURE {} | 
|---|
 | 87 |     set lambda [list x {set x 1} ::NONEXIST::FOR::SURE] | 
|---|
 | 88 |     apply $lambda x | 
|---|
 | 89 |     namespace delete ::NONEXIST | 
|---|
 | 90 |     apply $lambda x | 
|---|
 | 91 | } -returnCodes error -result {namespace "::NONEXIST::FOR::SURE" not found} | 
|---|
 | 92 | test apply-3.3 {non-existing namespace} -body { | 
|---|
 | 93 |     apply [list x {set x 1} NONEXIST::FOR::SURE] x | 
|---|
 | 94 | } -returnCodes error -result {namespace "::NONEXIST::FOR::SURE" not found} | 
|---|
 | 95 | test apply-3.4 {non-existing namespace} -body { | 
|---|
 | 96 |     namespace eval ::NONEXIST::FOR::SURE {} | 
|---|
 | 97 |     set lambda [list x {set x 1} NONEXIST::FOR::SURE] | 
|---|
 | 98 |     apply $lambda x | 
|---|
 | 99 |     namespace delete ::NONEXIST | 
|---|
 | 100 |     apply $lambda x | 
|---|
 | 101 | } -returnCodes error -result {namespace "::NONEXIST::FOR::SURE" not found} | 
|---|
 | 102 |  | 
|---|
 | 103 | test apply-4.1 {error in arguments to lambda expression} { | 
|---|
 | 104 |     set lambda [list x {set x 1}] | 
|---|
 | 105 |     set res [catch {apply $lambda} msg] | 
|---|
 | 106 |     list $res $msg | 
|---|
 | 107 | } {1 {wrong # args: should be "apply {x {set x 1}} x"}} | 
|---|
 | 108 | test apply-4.2 {error in arguments to lambda expression} { | 
|---|
 | 109 |     set lambda [list x {set x 1}] | 
|---|
 | 110 |     set res [catch {apply $lambda a b} msg] | 
|---|
 | 111 |     list $res $msg | 
|---|
 | 112 | } {1 {wrong # args: should be "apply {x {set x 1}} x"}} | 
|---|
 | 113 | test apply-4.3 {error in arguments to lambda expression} { | 
|---|
 | 114 |     set lambda [list x {set x 1}] | 
|---|
 | 115 |     interp alias {} foo {} ::apply $lambda | 
|---|
 | 116 |     set res [catch {foo a b} msg] | 
|---|
 | 117 |     list $res $msg [rename foo {}] | 
|---|
 | 118 | } {1 {wrong # args: should be "foo x"} {}} | 
|---|
 | 119 | test apply-4.4 {error in arguments to lambda expression} { | 
|---|
 | 120 |     set lambda [list x {set x 1}] | 
|---|
 | 121 |     interp alias {} foo {} ::apply $lambda a | 
|---|
 | 122 |     set res [catch {foo b} msg] | 
|---|
 | 123 |     list $res $msg [rename foo {}] | 
|---|
 | 124 | } {1 {wrong # args: should be "foo"} {}} | 
|---|
 | 125 | test apply-4.5 {error in arguments to lambda expression} { | 
|---|
 | 126 |     set lambda [list x {set x 1}] | 
|---|
 | 127 |     namespace eval a { | 
|---|
 | 128 |         namespace ensemble create -command ::bar -map {id {::a::const foo}} | 
|---|
 | 129 |         proc const val { return $val } | 
|---|
 | 130 |         proc alias {object slot = command args} { | 
|---|
 | 131 |             set map [namespace ensemble configure $object -map] | 
|---|
 | 132 |             dict set map $slot [linsert $args 0 $command] | 
|---|
 | 133 |             namespace ensemble configure $object -map $map | 
|---|
 | 134 |         } | 
|---|
 | 135 |         proc method {object name params body} { | 
|---|
 | 136 |             set params [linsert $params 0 self] | 
|---|
 | 137 |             alias $object $name = ::apply [list $params $body] $object | 
|---|
 | 138 |         } | 
|---|
 | 139 |         method ::bar boo x {return "[expr {$x*$x}] - $self"} | 
|---|
 | 140 |     } | 
|---|
 | 141 |     set res [catch {bar boo} msg] | 
|---|
 | 142 |     list $res $msg [namespace delete ::a] | 
|---|
 | 143 | } {1 {wrong # args: should be "bar boo x"} {}} | 
|---|
 | 144 |  | 
|---|
 | 145 | test apply-5.1 {runtime error in lambda expression} { | 
|---|
 | 146 |     set lambda [list {} {error foo}] | 
|---|
 | 147 |     set res [catch {apply $lambda}] | 
|---|
 | 148 |     list $res $::errorInfo | 
|---|
 | 149 | } {1 {foo | 
|---|
 | 150 |     while executing | 
|---|
 | 151 | "error foo" | 
|---|
 | 152 |     (lambda term "{} {error foo}" line 1) | 
|---|
 | 153 |     invoked from within | 
|---|
 | 154 | "apply $lambda"}} | 
|---|
 | 155 |  | 
|---|
 | 156 | # Tests for correct execution; as the implementation is the same as that for | 
|---|
 | 157 | # procs, the general functionality is mostly tested elsewhere | 
|---|
 | 158 |  | 
|---|
 | 159 | test apply-6.1 {info level} { | 
|---|
 | 160 |     set lev [info level] | 
|---|
 | 161 |     set lambda [list {} {info level}] | 
|---|
 | 162 |     expr {[apply $lambda] - $lev} | 
|---|
 | 163 | } 1 | 
|---|
 | 164 | test apply-6.2 {info level} { | 
|---|
 | 165 |     set lambda [list {} {info level 0}] | 
|---|
 | 166 |     apply $lambda | 
|---|
 | 167 | } {apply {{} {info level 0}}} | 
|---|
 | 168 | test apply-6.3 {info level} { | 
|---|
 | 169 |     set lambda [list args {info level 0}] | 
|---|
 | 170 |     apply $lambda x y | 
|---|
 | 171 | } {apply {args {info level 0}} x y} | 
|---|
 | 172 |  | 
|---|
 | 173 | # Tests for correct namespace scope | 
|---|
 | 174 |  | 
|---|
 | 175 | namespace eval ::testApply { | 
|---|
 | 176 |     proc testApply args {return testApply} | 
|---|
 | 177 | } | 
|---|
 | 178 |  | 
|---|
 | 179 | test apply-7.1 {namespace access} { | 
|---|
 | 180 |     set ::testApply::x 0 | 
|---|
 | 181 |     set body {set x 1; set x} | 
|---|
 | 182 |     list [apply [list args $body ::testApply]] $::testApply::x | 
|---|
 | 183 | } {1 0} | 
|---|
 | 184 | test apply-7.2 {namespace access} { | 
|---|
 | 185 |     set ::testApply::x 0 | 
|---|
 | 186 |     set body {variable x; set x} | 
|---|
 | 187 |     list [apply [list args $body ::testApply]] $::testApply::x | 
|---|
 | 188 | } {0 0} | 
|---|
 | 189 | test apply-7.3 {namespace access} { | 
|---|
 | 190 |     set ::testApply::x 0 | 
|---|
 | 191 |     set body {variable x; set x 1} | 
|---|
 | 192 |     list [apply [list args $body ::testApply]] $::testApply::x | 
|---|
 | 193 | } {1 1} | 
|---|
 | 194 | test apply-7.4 {namespace access} { | 
|---|
 | 195 |     set ::testApply::x 0 | 
|---|
 | 196 |     set body {testApply} | 
|---|
 | 197 |     apply [list args $body ::testApply] | 
|---|
 | 198 | } testApply | 
|---|
 | 199 | test apply-7.5 {namespace access} { | 
|---|
 | 200 |     set ::testApply::x 0 | 
|---|
 | 201 |     set body {set x 1; set x} | 
|---|
 | 202 |     list [apply [list args $body testApply]] $::testApply::x | 
|---|
 | 203 | } {1 0} | 
|---|
 | 204 | test apply-7.6 {namespace access} { | 
|---|
 | 205 |     set ::testApply::x 0 | 
|---|
 | 206 |     set body {variable x; set x} | 
|---|
 | 207 |     list [apply [list args $body testApply]] $::testApply::x | 
|---|
 | 208 | } {0 0} | 
|---|
 | 209 | test apply-7.7 {namespace access} { | 
|---|
 | 210 |     set ::testApply::x 0 | 
|---|
 | 211 |     set body {variable x; set x 1} | 
|---|
 | 212 |     list [apply [list args $body testApply]] $::testApply::x | 
|---|
 | 213 | } {1 1} | 
|---|
 | 214 | test apply-7.8 {namespace access} { | 
|---|
 | 215 |     set ::testApply::x 0 | 
|---|
 | 216 |     set body {testApply} | 
|---|
 | 217 |     apply [list args $body testApply] | 
|---|
 | 218 | } testApply | 
|---|
 | 219 |  | 
|---|
 | 220 | # Tests for correct argument treatment | 
|---|
 | 221 |  | 
|---|
 | 222 | set applyBody { | 
|---|
 | 223 |     set res {} | 
|---|
 | 224 |     foreach v [info locals] { | 
|---|
 | 225 |         if {$v eq "res"} continue | 
|---|
 | 226 |         lappend res [list $v [set $v]] | 
|---|
 | 227 |     } | 
|---|
 | 228 |     set res | 
|---|
 | 229 | } | 
|---|
 | 230 |  | 
|---|
 | 231 | test apply-8.1 {args treatment} { | 
|---|
 | 232 |     apply [list args $applyBody] 1 2 3 | 
|---|
 | 233 | } {{args {1 2 3}}} | 
|---|
 | 234 | test apply-8.2 {args treatment} { | 
|---|
 | 235 |     apply [list {x args} $applyBody] 1 2 | 
|---|
 | 236 | } {{x 1} {args 2}} | 
|---|
 | 237 | test apply-8.3 {args treatment} { | 
|---|
 | 238 |     apply [list {x args} $applyBody] 1 2 3 | 
|---|
 | 239 | } {{x 1} {args {2 3}}} | 
|---|
 | 240 | test apply-8.4 {default values} { | 
|---|
 | 241 |     apply [list {{x 1} {y 2}} $applyBody]  | 
|---|
 | 242 | } {{x 1} {y 2}} | 
|---|
 | 243 | test apply-8.5 {default values} { | 
|---|
 | 244 |     apply [list {{x 1} {y 2}} $applyBody] 3 4 | 
|---|
 | 245 | } {{x 3} {y 4}} | 
|---|
 | 246 | test apply-8.6 {default values} { | 
|---|
 | 247 |     apply [list {{x 1} {y 2}} $applyBody] 3 | 
|---|
 | 248 | } {{x 3} {y 2}} | 
|---|
 | 249 | test apply-8.7 {default values} { | 
|---|
 | 250 |     apply [list {x {y 2}} $applyBody] 1 | 
|---|
 | 251 | } {{x 1} {y 2}} | 
|---|
 | 252 | test apply-8.8 {default values} { | 
|---|
 | 253 |     apply [list {x {y 2}} $applyBody] 1 3 | 
|---|
 | 254 | } {{x 1} {y 3}} | 
|---|
 | 255 | test apply-8.9 {default values} { | 
|---|
 | 256 |     apply [list {x {y 2} args} $applyBody] 1 | 
|---|
 | 257 | } {{x 1} {y 2} {args {}}} | 
|---|
 | 258 | test apply-8.10 {default values} { | 
|---|
 | 259 |     apply [list {x {y 2} args} $applyBody] 1 3 | 
|---|
 | 260 | } {{x 1} {y 3} {args {}}} | 
|---|
 | 261 |  | 
|---|
 | 262 | # Tests for leaks | 
|---|
 | 263 |  | 
|---|
 | 264 | test apply-9.1 {leaking internal rep} -setup { | 
|---|
 | 265 |     proc getbytes {} { | 
|---|
 | 266 |         set lines [split [memory info] "\n"] | 
|---|
 | 267 |         lindex $lines 3 3 | 
|---|
 | 268 |     } | 
|---|
 | 269 |     set lam [list {} {set a 1}] | 
|---|
 | 270 | } -constraints memory -body { | 
|---|
 | 271 |     set end [getbytes] | 
|---|
 | 272 |     for {set i 0} {$i < 5} {incr i} { | 
|---|
 | 273 |         ::apply [lrange $lam 0 end] | 
|---|
 | 274 |         set tmp $end | 
|---|
 | 275 |         set end [getbytes] | 
|---|
 | 276 |     } | 
|---|
 | 277 |     set leakedBytes [expr {$end - $tmp}] | 
|---|
 | 278 | } -cleanup { | 
|---|
 | 279 |     rename getbytes {} | 
|---|
 | 280 |     unset lam | 
|---|
 | 281 | } -result 0 | 
|---|
 | 282 | test apply-9.2 {leaking internal rep} -setup { | 
|---|
 | 283 |     proc getbytes {} { | 
|---|
 | 284 |         set lines [split [memory info] "\n"] | 
|---|
 | 285 |         lindex $lines 3 3 | 
|---|
 | 286 |     } | 
|---|
 | 287 | } -constraints memory -body { | 
|---|
 | 288 |     set end [getbytes] | 
|---|
 | 289 |     for {set i 0} {$i < 5} {incr i} { | 
|---|
 | 290 |         ::apply [list {} {set a 1}] | 
|---|
 | 291 |         set tmp $end | 
|---|
 | 292 |         set end [getbytes] | 
|---|
 | 293 |     } | 
|---|
 | 294 |     set leakedBytes [expr {$end - $tmp}] | 
|---|
 | 295 | } -cleanup { | 
|---|
 | 296 |     rename getbytes {} | 
|---|
 | 297 | } -result 0 | 
|---|
 | 298 | test apply-9.3 {leaking internal rep} -setup { | 
|---|
 | 299 |     proc getbytes {} { | 
|---|
 | 300 |         set lines [split [memory info] "\n"] | 
|---|
 | 301 |         lindex $lines 3 3 | 
|---|
 | 302 |     } | 
|---|
 | 303 | } -constraints memory -body { | 
|---|
 | 304 |     set end [getbytes] | 
|---|
 | 305 |     for {set i 0} {$i < 5} {incr i} { | 
|---|
 | 306 |         set x [list {} {set a 1} ::NS::THAT::DOES::NOT::EXIST] | 
|---|
 | 307 |         catch {::apply $x} | 
|---|
 | 308 |         set x {} | 
|---|
 | 309 |         set tmp $end | 
|---|
 | 310 |         set end [getbytes] | 
|---|
 | 311 |     } | 
|---|
 | 312 |     set leakedBytes [expr {$end - $tmp}] | 
|---|
 | 313 | } -cleanup { | 
|---|
 | 314 |     rename getbytes {} | 
|---|
 | 315 | } -result 0 | 
|---|
 | 316 |  | 
|---|
 | 317 | # Tests for the avoidance of recompilation | 
|---|
 | 318 |  | 
|---|
 | 319 | # cleanup | 
|---|
 | 320 |  | 
|---|
 | 321 | namespace delete testApply | 
|---|
 | 322 |  | 
|---|
 | 323 | ::tcltest::cleanupTests | 
|---|
 | 324 | return | 
|---|