Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/tcl8.5.2/tests/trace.test @ 68

Last change on this file since 68 was 25, checked in by landauf, 16 years ago

added tcl to libs

File size: 79.7 KB
Line 
1# Commands covered:  trace
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 Sun Microsystems, Inc.
9# Copyright (c) 1998-1999 by Scriptics Corporation.
10#
11# See the file "license.terms" for information on usage and redistribution
12# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13#
14# RCS: @(#) $Id: trace.test,v 1.61 2007/12/13 15:26:07 dgp Exp $
15
16if {[lsearch [namespace children] ::tcltest] == -1} {
17    package require tcltest
18    namespace import -force ::tcltest::*
19}
20
21testConstraint testcmdtrace [llength [info commands testcmdtrace]]
22testConstraint testevalobjv [llength [info commands testevalobjv]]
23
24# Used for constraining memory leak tests
25testConstraint memory [llength [info commands memory]]
26
27proc getbytes {} {
28    set lines [split [memory info] "\n"]
29    lindex [lindex $lines 3] 3
30}
31
32proc traceScalar {name1 name2 op} {
33    global info
34    set info [list $name1 $name2 $op [catch {uplevel set $name1} msg] $msg]
35}
36proc traceScalarAppend {name1 name2 op} {
37    global info
38    lappend info $name1 $name2 $op [catch {uplevel set $name1} msg] $msg
39}
40proc traceArray {name1 name2 op} {
41    global info
42    set info [list $name1 $name2 $op [catch {uplevel set [set name1]($name2)} msg] $msg]
43}
44proc traceArray2 {name1 name2 op} {
45    global info
46    set info [list $name1 $name2 $op]
47}
48proc traceProc {name1 name2 op} {
49    global info
50    set info [concat $info [list $name1 $name2 $op]]
51}
52proc traceTag {tag args} {
53    global info
54    set info [concat $info $tag]
55}
56proc traceError {args} {
57    error "trace returned error"
58}
59proc traceCheck {cmd args} {
60    global info
61    set info [list [catch $cmd msg] $msg]
62}
63proc traceCrtElement {value name1 name2 op} {
64    uplevel set ${name1}($name2) $value
65}
66proc traceCommand {oldName newName op} {
67    global info
68    set info [list $oldName $newName $op]
69}
70
71test trace-0.0 {memory corruption in trace (Tcl Bug 484339)} {
72    # You may need Purify or Electric Fence to reliably
73    # see this one fail.
74    catch {unset z}
75    trace add variable z array {set z(foo) 1 ;#}
76    set res "names: [array names z]"
77    catch {unset ::z}
78    trace variable ::z w {unset ::z; error "memory corruption";#}
79    list [catch {set ::z 1} msg] $msg
80} {1 {can't set "::z": memory corruption}}
81
82# Read-tracing on variables
83
84test trace-1.1 {trace variable reads} {
85    catch {unset x}
86    set info {}
87    trace add variable x read traceScalar
88    list [catch {set x} msg] $msg $info
89} {1 {can't read "x": no such variable} {x {} read 1 {can't read "x": no such variable}}}
90test trace-1.2 {trace variable reads} {
91    catch {unset x}
92    set x 123
93    set info {}
94    trace add variable x read traceScalar
95    list [catch {set x} msg] $msg $info
96} {0 123 {x {} read 0 123}}
97test trace-1.3 {trace variable reads} {
98    catch {unset x}
99    set info {}
100    trace add variable x read traceScalar
101    set x 123
102    set info
103} {}
104test trace-1.4 {trace array element reads} {
105    catch {unset x}
106    set info {}
107    trace add variable x(2) read traceArray
108    list [catch {set x(2)} msg] $msg $info
109} {1 {can't read "x(2)": no such element in array} {x 2 read 1 {can't read "x(2)": no such element in array}}}
110test trace-1.5 {trace array element reads} {
111    catch {unset x}
112    set x(2) zzz
113    set info {}
114    trace add variable x(2) read traceArray
115    list [catch {set x(2)} msg] $msg $info
116} {0 zzz {x 2 read 0 zzz}}
117test trace-1.6 {trace array element reads} {
118    catch {unset x}
119    set info {}
120    trace add variable x read traceArray2
121    proc p {} {
122        global x
123        set x(2) willi
124        return $x(2)
125    }
126    list [catch {p} msg] $msg $info
127} {0 willi {x 2 read}}
128test trace-1.7 {trace array element reads, create element undefined if nonexistant} {
129    catch {unset x}
130    set info {}
131    trace add variable x read q
132    proc q {name1 name2 op} {
133        global info
134        set info [list $name1 $name2 $op]
135        global $name1
136        set ${name1}($name2) wolf
137    }
138    proc p {} {
139        global x
140        set x(X) willi
141        return $x(Y)
142    }
143    list [catch {p} msg] $msg $info
144} {0 wolf {x Y read}}
145test trace-1.8 {trace reads on whole arrays} {
146    catch {unset x}
147    set info {}
148    trace add variable x read traceArray
149    list [catch {set x(2)} msg] $msg $info
150} {1 {can't read "x(2)": no such variable} {}}
151test trace-1.9 {trace reads on whole arrays} {
152    catch {unset x}
153    set x(2) zzz
154    set info {}
155    trace add variable x read traceArray
156    list [catch {set x(2)} msg] $msg $info
157} {0 zzz {x 2 read 0 zzz}}
158test trace-1.10 {trace variable reads} {
159    catch {unset x}
160    set x 444
161    set info {}
162    trace add variable x read traceScalar
163    unset x
164    set info
165} {}
166test trace-1.11 {read traces that modify the array structure} {
167    catch {unset x}
168    set x(bar) 0
169    trace variable x r {set x(foo) 1 ;#}
170    trace variable x r {unset -nocomplain x(bar) ;#}
171    array get x
172} {}
173test trace-1.12 {read traces that modify the array structure} {
174    catch {unset x}
175    set x(bar) 0
176    trace variable x r {unset -nocomplain x(bar) ;#}
177    trace variable x r {set x(foo) 1 ;#}
178    array get x
179} {}
180test trace-1.13 {read traces that modify the array structure} {
181    catch {unset x}
182    set x(bar) 0
183    trace variable x r {set x(foo) 1 ;#}
184    trace variable x r {unset -nocomplain x;#}
185    list [catch {array get x} res] $res
186} {1 {can't read "x(bar)": no such variable}}
187test trace-1.14 {read traces that modify the array structure} {
188    catch {unset x}
189    set x(bar) 0
190    trace variable x r {unset -nocomplain x;#}
191    trace variable x r {set x(foo) 1 ;#}
192    list [catch {array get x} res] $res
193} {1 {can't read "x(bar)": no such variable}}
194
195# Basic write-tracing on variables
196
197test trace-2.1 {trace variable writes} {
198    catch {unset x}
199    set info {}
200    trace add variable x write traceScalar
201    set x 123
202    set info
203} {x {} write 0 123}
204test trace-2.2 {trace writes to array elements} {
205    catch {unset x}
206    set info {}
207    trace add variable x(33) write traceArray
208    set x(33) 444
209    set info
210} {x 33 write 0 444}
211test trace-2.3 {trace writes on whole arrays} {
212    catch {unset x}
213    set info {}
214    trace add variable x write traceArray
215    set x(abc) qq
216    set info
217} {x abc write 0 qq}
218test trace-2.4 {trace variable writes} {
219    catch {unset x}
220    set x 1234
221    set info {}
222    trace add variable x write traceScalar
223    set x
224    set info
225} {}
226test trace-2.5 {trace variable writes} {
227    catch {unset x}
228    set x 1234
229    set info {}
230    trace add variable x write traceScalar
231    unset x
232    set info
233} {}
234test trace-2.6 {trace variable writes on compiled local} {
235    #
236    # Check correct function of whole array traces on compiled local
237    # arrays [Bug 1770591]. The corresponding function for read traces is
238    # already indirectly tested in trace-1.7
239    #
240    catch {unset x}
241    set info {}
242    proc p {} {
243        trace add variable x write traceArray
244        set x(X) willy
245    }
246    p
247    set info
248} {x X write 0 willy}
249test trace-2.7 {trace variable writes on errorInfo} -body {
250   #
251   # Check correct behaviour of write traces on errorInfo.
252   # [Bug 1773040]
253   trace add variable ::errorInfo write traceScalar
254   catch {set dne}
255   lrange [set info] 0 2
256} -cleanup {
257   # always remove trace on errorInfo otherwise further tests will fail
258   unset ::errorInfo
259} -result {::errorInfo {} write}
260
261
262
263# append no longer triggers read traces when fetching the old values of
264# variables before doing the append operation. However, lappend _does_
265# still trigger these read traces. Also lappend triggers only one write
266# trace: after appending all arguments to the list.
267
268test trace-3.1 {trace variable read-modify-writes} {
269    catch {unset x}
270    set info {}
271    trace add variable x read traceScalarAppend
272    append x 123
273    append x 456
274    lappend x 789
275    set info
276} {x {} read 0 123456}
277test trace-3.2 {trace variable read-modify-writes} {
278    catch {unset x}
279    set info {}
280    trace add variable x {read write} traceScalarAppend
281    append x 123
282    lappend x 456
283    set info
284} {x {} write 0 123 x {} read 0 123 x {} write 0 {123 456}}
285
286# Basic unset-tracing on variables
287
288test trace-4.1 {trace variable unsets} {
289    catch {unset x}
290    set info {}
291    trace add variable x unset traceScalar
292    catch {unset x}
293    set info
294} {x {} unset 1 {can't read "x": no such variable}}
295test trace-4.2 {variable mustn't exist during unset trace} {
296    catch {unset x}
297    set x 1234
298    set info {}
299    trace add variable x unset traceScalar
300    unset x
301    set info
302} {x {} unset 1 {can't read "x": no such variable}}
303test trace-4.3 {unset traces mustn't be called during reads and writes} {
304    catch {unset x}
305    set info {}
306    trace add variable x unset traceScalar
307    set x 44
308    set x
309    set info
310} {}
311test trace-4.4 {trace unsets on array elements} {
312    catch {unset x}
313    set x(0) 18
314    set info {}
315    trace add variable x(1) unset traceArray
316    catch {unset x(1)}
317    set info
318} {x 1 unset 1 {can't read "x(1)": no such element in array}}
319test trace-4.5 {trace unsets on array elements} {
320    catch {unset x}
321    set x(1) 18
322    set info {}
323    trace add variable x(1) unset traceArray
324    unset x(1)
325    set info
326} {x 1 unset 1 {can't read "x(1)": no such element in array}}
327test trace-4.6 {trace unsets on array elements} {
328    catch {unset x}
329    set x(1) 18
330    set info {}
331    trace add variable x(1) unset traceArray
332    unset x
333    set info
334} {x 1 unset 1 {can't read "x(1)": no such variable}}
335test trace-4.7 {trace unsets on whole arrays} {
336    catch {unset x}
337    set x(1) 18
338    set info {}
339    trace add variable x unset traceProc
340    catch {unset x(0)}
341    set info
342} {}
343test trace-4.8 {trace unsets on whole arrays} {
344    catch {unset x}
345    set x(1) 18
346    set x(2) 144
347    set x(3) 14
348    set info {}
349    trace add variable x unset traceProc
350    unset x(1)
351    set info
352} {x 1 unset}
353test trace-4.9 {trace unsets on whole arrays} {
354    catch {unset x}
355    set x(1) 18
356    set x(2) 144
357    set x(3) 14
358    set info {}
359    trace add variable x unset traceProc
360    unset x
361    set info
362} {x {} unset}
363
364# Array tracing on variables
365test trace-5.1 {array traces fire on accesses via [array]} {
366    catch {unset x}
367    set x(b) 2
368    trace add variable x array traceArray2
369    set ::info {}
370    array set x {a 1}
371    set ::info
372} {x {} array}
373test trace-5.2 {array traces do not fire on normal accesses} {
374    catch {unset x}
375    set x(b) 2
376    trace add variable x array traceArray2
377    set ::info {}
378    set x(a) 1
379    set x(b) $x(a)
380    set ::info
381} {}
382test trace-5.3 {array traces do not outlive variable} {
383    catch {unset x}
384    trace add variable x array traceArray2
385    set ::info {}
386    set x(a) 1
387    unset x
388    array set x {a 1}
389    set ::info
390} {}
391test trace-5.4 {array traces properly listed in trace information} {
392    catch {unset x}
393    trace add variable x array traceArray2
394    set result [trace info variable x]
395    set result
396} [list [list array traceArray2]]
397test trace-5.5 {array traces properly listed in trace information} {
398    catch {unset x}
399    trace variable x a traceArray2
400    set result [trace vinfo x]
401    set result
402} [list [list a traceArray2]]
403test trace-5.6 {array traces don't fire on scalar variables} {
404    catch {unset x}
405    set x foo
406    trace add variable x array traceArray2
407    set ::info {}
408    catch {array set x {a 1}}
409    set ::info
410} {}
411test trace-5.7 {array traces fire for undefined variables} {
412    catch {unset x}
413    trace add variable x array traceArray2
414    set ::info {}
415    array set x {a 1}
416    set ::info
417} {x {} array}
418test trace-5.8 {array traces fire for undefined variables} {
419    catch {unset x}
420    trace add variable x array {set x(foo) 1 ;#}
421    set res "names: [array names x]"
422} {names: foo}
423   
424# Trace multiple trace types at once.
425
426test trace-6.1 {multiple ops traced at once} {
427    catch {unset x}
428    set info {}
429    trace add variable x {read write unset} traceProc
430    catch {set x}
431    set x 22
432    set x
433    set x 33
434    unset x
435    set info
436} {x {} read x {} write x {} read x {} write x {} unset}
437test trace-6.2 {multiple ops traced on array element} {
438    catch {unset x}
439    set info {}
440    trace add variable x(0) {read write unset} traceProc
441    catch {set x(0)}
442    set x(0) 22
443    set x(0)
444    set x(0) 33
445    unset x(0)
446    unset x
447    set info
448} {x 0 read x 0 write x 0 read x 0 write x 0 unset}
449test trace-6.3 {multiple ops traced on whole array} {
450    catch {unset x}
451    set info {}
452    trace add variable x {read write unset} traceProc
453    catch {set x(0)}
454    set x(0) 22
455    set x(0)
456    set x(0) 33
457    unset x(0)
458    unset x
459    set info
460} {x 0 write x 0 read x 0 write x 0 unset x {} unset}
461
462# Check order of invocation of traces
463
464test trace-7.1 {order of invocation of traces} {
465    catch {unset x}
466    set info {}
467    trace add variable x read "traceTag 1"
468    trace add variable x read "traceTag 2"
469    trace add variable x read "traceTag 3"
470    catch {set x}
471    set x 22
472    set x
473    set info
474} {3 2 1 3 2 1}
475test trace-7.2 {order of invocation of traces} {
476    catch {unset x}
477    set x(0) 44
478    set info {}
479    trace add variable x(0) read "traceTag 1"
480    trace add variable x(0) read "traceTag 2"
481    trace add variable x(0) read "traceTag 3"
482    set x(0)
483    set info
484} {3 2 1}
485test trace-7.3 {order of invocation of traces} {
486    catch {unset x}
487    set x(0) 44
488    set info {}
489    trace add variable x(0) read "traceTag 1"
490    trace add variable x read "traceTag A1"
491    trace add variable x(0) read "traceTag 2"
492    trace add variable x read "traceTag A2"
493    trace add variable x(0) read "traceTag 3"
494    trace add variable x read "traceTag A3"
495    set x(0)
496    set info
497} {A3 A2 A1 3 2 1}
498
499# Check effects of errors in trace procedures
500
501test trace-8.1 {error returns from traces} {
502    catch {unset x}
503    set x 123
504    set info {}
505    trace add variable x read "traceTag 1"
506    trace add variable x read traceError
507    list [catch {set x} msg] $msg $info
508} {1 {can't read "x": trace returned error} {}}
509test trace-8.2 {error returns from traces} {
510    catch {unset x}
511    set x 123
512    set info {}
513    trace add variable x write "traceTag 1"
514    trace add variable x write traceError
515    list [catch {set x 44} msg] $msg $info
516} {1 {can't set "x": trace returned error} {}}
517test trace-8.3 {error returns from traces} {
518    catch {unset x}
519    set x 123
520    set info {}
521    trace add variable x write traceError
522    list [catch {append x 44} msg] $msg $info
523} {1 {can't set "x": trace returned error} {}}
524test trace-8.4 {error returns from traces} {
525    catch {unset x}
526    set x 123
527    set info {}
528    trace add variable x unset "traceTag 1"
529    trace add variable x unset traceError
530    list [catch {unset x} msg] $msg $info
531} {0 {} 1}
532test trace-8.5 {error returns from traces} {
533    catch {unset x}
534    set x(0) 123
535    set info {}
536    trace add variable x(0) read "traceTag 1"
537    trace add variable x read "traceTag 2"
538    trace add variable x read traceError
539    trace add variable x read "traceTag 3"
540    list [catch {set x(0)} msg] $msg $info
541} {1 {can't read "x(0)": trace returned error} 3}
542test trace-8.6 {error returns from traces} {
543    catch {unset x}
544    set x 123
545    trace add variable x unset traceError
546    list [catch {unset x} msg] $msg
547} {0 {}}
548test trace-8.7 {error returns from traces} {
549    # This test just makes sure that the memory for the error message
550    # gets deallocated correctly when the trace is invoked again or
551    # when the trace is deleted.
552    catch {unset x}
553    set x 123
554    trace add variable x read traceError
555    catch {set x}
556    catch {set x}
557    trace remove variable x read traceError
558} {}
559test trace-8.8 {error returns from traces} {
560    # Yet more elaborate memory corruption testing that checks nothing
561    # bad happens when the trace deletes itself and installs something
562    # new.  Alas, there is no neat way to guarantee that this test will
563    # fail if there is a problem, but that's life and with the new code
564    # it should *never* fail.
565    #
566    # Adapted from Bug #219393 reported by Don Porter.
567    catch {rename ::foo {}}
568    proc foo {old args} {
569        trace remove variable ::x write [list foo $old]
570        trace add    variable ::x write [list foo $::x]
571        error "foo"
572    }
573    catch {unset ::x ::y}
574    set x junk
575    trace add variable ::x write [list foo $x]
576    for {set y 0} {$y<100} {incr y} {
577        catch {set x junk}
578    }
579    unset x
580} {}
581
582# Check to see that variables are expunged before trace
583# procedures are invoked, so trace procedure can even manipulate
584# a new copy of the variables.
585
586test trace-9.1 {be sure variable is unset before trace is called} {
587    catch {unset x}
588    set x 33
589    set info {}
590    trace add variable x unset {traceCheck {uplevel set x}}
591    unset x
592    set info
593} {1 {can't read "x": no such variable}}
594test trace-9.2 {be sure variable is unset before trace is called} {
595    catch {unset x}
596    set x 33
597    set info {}
598    trace add variable x unset {traceCheck {uplevel set x 22}}
599    unset x
600    concat $info [list [catch {set x} msg] $msg]
601} {0 22 0 22}
602test trace-9.3 {be sure traces are cleared before unset trace called} {
603    catch {unset x}
604    set x 33
605    set info {}
606    trace add variable x unset {traceCheck {uplevel trace info variable x}}
607    unset x
608    set info
609} {0 {}}
610test trace-9.4 {set new trace during unset trace} {
611    catch {unset x}
612    set x 33
613    set info {}
614    trace add variable x unset {traceCheck {global x; trace add variable x unset traceProc}}
615    unset x
616    concat $info [trace info variable x]
617} {0 {} {unset traceProc}}
618
619test trace-10.1 {make sure array elements are unset before traces are called} {
620    catch {unset x}
621    set x(0) 33
622    set info {}
623    trace add variable x(0) unset {traceCheck {uplevel set x(0)}}
624    unset x(0)
625    set info
626} {1 {can't read "x(0)": no such element in array}}
627test trace-10.2 {make sure array elements are unset before traces are called} {
628    catch {unset x}
629    set x(0) 33
630    set info {}
631    trace add variable x(0) unset {traceCheck {uplevel set x(0) zzz}}
632    unset x(0)
633    concat $info [list [catch {set x(0)} msg] $msg]
634} {0 zzz 0 zzz}
635test trace-10.3 {array elements are unset before traces are called} {
636    catch {unset x}
637    set x(0) 33
638    set info {}
639    trace add variable x(0) unset {traceCheck {global x; trace info variable x(0)}}
640    unset x(0)
641    set info
642} {0 {}}
643test trace-10.4 {set new array element trace during unset trace} {
644    catch {unset x}
645    set x(0) 33
646    set info {}
647    trace add variable x(0) unset {traceCheck {uplevel {trace add variable x(0) read {}}}}
648    catch {unset x(0)}
649    concat $info [trace info variable x(0)]
650} {0 {} {read {}}}
651
652test trace-11.1 {make sure arrays are unset before traces are called} {
653    catch {unset x}
654    set x(0) 33
655    set info {}
656    trace add variable x unset {traceCheck {uplevel set x(0)}}
657    unset x
658    set info
659} {1 {can't read "x(0)": no such variable}}
660test trace-11.2 {make sure arrays are unset before traces are called} {
661    catch {unset x}
662    set x(y) 33
663    set info {}
664    trace add variable x unset {traceCheck {uplevel set x(y) 22}}
665    unset x
666    concat $info [list [catch {set x(y)} msg] $msg]
667} {0 22 0 22}
668test trace-11.3 {make sure arrays are unset before traces are called} {
669    catch {unset x}
670    set x(y) 33
671    set info {}
672    trace add variable x unset {traceCheck {uplevel array exists x}}
673    unset x
674    set info
675} {0 0}
676test trace-11.4 {make sure arrays are unset before traces are called} {
677    catch {unset x}
678    set x(y) 33
679    set info {}
680    set cmd {traceCheck {uplevel {trace info variable x}}}
681    trace add variable x unset $cmd
682    unset x
683    set info
684} {0 {}}
685test trace-11.5 {set new array trace during unset trace} {
686    catch {unset x}
687    set x(y) 33
688    set info {}
689    trace add variable x unset {traceCheck {global x; trace add variable x read {}}}
690    unset x
691    concat $info [trace info variable x]
692} {0 {} {read {}}}
693test trace-11.6 {create scalar during array unset trace} {
694    catch {unset x}
695    set x(y) 33
696    set info {}
697    trace add variable x unset {traceCheck {global x; set x 44}}
698    unset x
699    concat $info [list [catch {set x} msg] $msg]
700} {0 44 0 44}
701
702# Check special conditions (e.g. errors) in Tcl_TraceVar2.
703
704test trace-12.1 {creating array when setting variable traces} {
705    catch {unset x}
706    set info {}
707    trace add variable x(0) write traceProc
708    list [catch {set x 22} msg] $msg
709} {1 {can't set "x": variable is array}}
710test trace-12.2 {creating array when setting variable traces} {
711    catch {unset x}
712    set info {}
713    trace add variable x(0) write traceProc
714    list [catch {set x(0)} msg] $msg
715} {1 {can't read "x(0)": no such element in array}}
716test trace-12.3 {creating array when setting variable traces} {
717    catch {unset x}
718    set info {}
719    trace add variable x(0) write traceProc
720    set x(0) 22
721    set info
722} {x 0 write}
723test trace-12.4 {creating variable when setting variable traces} {
724    catch {unset x}
725    set info {}
726    trace add variable x write traceProc
727    list [catch {set x} msg] $msg
728} {1 {can't read "x": no such variable}}
729test trace-12.5 {creating variable when setting variable traces} {
730    catch {unset x}
731    set info {}
732    trace add variable x write traceProc
733    set x 22
734    set info
735} {x {} write}
736test trace-12.6 {creating variable when setting variable traces} {
737    catch {unset x}
738    set info {}
739    trace add variable x write traceProc
740    set x(0) 22
741    set info
742} {x 0 write}
743test trace-12.7 {create array element during read trace} {
744    catch {unset x}
745    set x(2) zzz
746    trace add variable x read {traceCrtElement xyzzy}
747    list [catch {set x(3)} msg] $msg
748} {0 xyzzy}
749test trace-12.8 {errors when setting variable traces} {
750    catch {unset x}
751    set x 44
752    list [catch {trace add variable x(0) write traceProc} msg] $msg
753} {1 {can't trace "x(0)": variable isn't array}}
754
755# Check trace deletion
756
757test trace-13.1 {delete one trace from another} {
758    proc delTraces {args} {
759        global x
760        trace remove variable x read {traceTag 2}
761        trace remove variable x read {traceTag 3}
762        trace remove variable x read {traceTag 4}
763    }
764    catch {unset x}
765    set x 44
766    set info {}
767    trace add variable x read {traceTag 1}
768    trace add variable x read {traceTag 2}
769    trace add variable x read {traceTag 3}
770    trace add variable x read {traceTag 4}
771    trace add variable x read delTraces
772    trace add variable x read {traceTag 5}
773    set x
774    set info
775} {5 1}
776
777test trace-13.2 {leak when unsetting traced variable} \
778    -constraints memory -body {
779        set end [getbytes]
780        proc f args {}
781        for {set i 0} {$i < 5} {incr i} {
782            trace add variable bepa write f
783            set bepa a
784            unset bepa
785            set tmp $end
786            set end [getbytes]
787        }
788        expr {$end - $tmp}
789    } -cleanup {
790        unset -nocomplain end i tmp
791    } -result 0
792test trace-13.3 {leak when removing traces} \
793    -constraints memory -body {
794        set end [getbytes]
795        proc f args {}
796        for {set i 0} {$i < 5} {incr i} {
797            trace add variable bepa write f
798            set bepa a
799            trace remove variable bepa write f
800            set tmp $end
801            set end [getbytes]
802        }
803        expr {$end - $tmp}
804    } -cleanup {
805        unset -nocomplain end i tmp
806    } -result 0
807test trace-13.4 {leaks in error returns from traces} \
808    -constraints memory -body {
809        set end [getbytes]
810        for {set i 0} {$i < 5} {incr i} {
811            set apa {a 1 b 2}
812            set bepa [lrange $apa 0 end]
813            trace add variable bepa write {error hej}
814            catch {set bepa a}
815            unset bepa
816            set tmp $end
817            set end [getbytes]
818        }
819        expr {$end - $tmp}
820    } -cleanup {
821        unset -nocomplain end i tmp
822    } -result 0
823
824# Check operation and syntax of "trace" command.
825
826# Syntax for adding/removing variable and command traces is basically the
827# same:
828#       trace add variable name opList command
829#       trace remove variable name opList command
830#
831# The following loops just get all the common "wrong # args" tests done.
832
833set i 0
834set start "wrong # args:"
835foreach type {variable command} {
836    foreach op {add remove} {
837        test trace-14.0.[incr i] "trace command, wrong # args errors" {
838            list [catch {trace $op $type} msg] $msg
839        } [list 1 "$start should be \"trace $op $type name opList command\""]
840        test trace-14.0.[incr i] "trace command wrong # args errors" {
841            list [catch {trace $op $type foo} msg] $msg
842        } [list 1 "$start should be \"trace $op $type name opList command\""]
843        test trace-14.0.[incr i] "trace command, wrong # args errors" {
844            list [catch {trace $op $type foo bar} msg] $msg
845        } [list 1 "$start should be \"trace $op $type name opList command\""]
846        test trace-14.0.[incr i] "trace command, wrong # args errors" {
847            list [catch {trace $op $type foo bar baz boo} msg] $msg
848        } [list 1 "$start should be \"trace $op $type name opList command\""]
849    }
850    test trace-14.0.[incr i] "trace command, wrong # args errors" {
851        list [catch {trace info $type foo bar} msg] $msg
852    } [list 1 "$start should be \"trace info $type name\""]
853    test trace-14.0.[incr i] "trace command, wrong # args errors" {
854        list [catch {trace info $type} msg] $msg
855    } [list 1 "$start should be \"trace info $type name\""]
856}
857
858test trace-14.1 "trace command, wrong # args errors" {
859    list [catch {trace} msg] $msg
860} [list 1 "wrong # args: should be \"trace option ?arg arg ...?\""]
861test trace-14.2 "trace command, wrong # args errors" {
862    list [catch {trace add} msg] $msg
863} [list 1 "wrong # args: should be \"trace add type ?arg arg ...?\""]
864test trace-14.3 "trace command, wrong # args errors" {
865    list [catch {trace remove} msg] $msg
866} [list 1 "wrong # args: should be \"trace remove type ?arg arg ...?\""]
867test trace-14.4 "trace command, wrong # args errors" {
868    list [catch {trace info} msg] $msg
869} [list 1 "wrong # args: should be \"trace info type name\""]
870
871test trace-14.5 {trace command, invalid option} {
872    list [catch {trace gorp} msg] $msg
873} [list 1 "bad option \"gorp\": must be add, info, remove, variable, vdelete, or vinfo"]
874
875# Again, [trace ... command] and [trace ... variable] share syntax and
876# error message styles for their opList options; these loops test those
877# error messages.
878
879set i 0
880set errs [list "array, read, unset, or write" "delete or rename" "enter, leave, enterstep, or leavestep"]
881set abbvs [list {a r u w} {d r} {}]
882proc x {} {}
883foreach type {variable command execution} err $errs abbvlist $abbvs {
884    foreach op {add remove} {
885        test trace-14.6.[incr i] "trace $op $type errors" {
886            list [catch {trace $op $type x {y z w} a} msg] $msg
887        } [list 1 "bad operation \"y\": must be $err"]
888        foreach abbv $abbvlist {
889            test trace-14.6.[incr i] "trace $op $type rejects abbreviations" {
890                list [catch {trace $op $type x $abbv a} msg] $msg
891            } [list 1 "bad operation \"$abbv\": must be $err"]
892        }
893        test trace-14.6.[incr i] "trace $op $type rejects null opList" {
894            list [catch {trace $op $type x {} a} msg] $msg
895        } [list 1 "bad operation list \"\": must be one or more of $err"]
896    }
897}
898rename x {}
899
900test trace-14.7 {trace command, "trace variable" errors} {
901    list [catch {trace variable} msg] $msg
902} [list 1 "wrong # args: should be \"trace variable name ops command\""]
903test trace-14.8 {trace command, "trace variable" errors} {
904    list [catch {trace variable x} msg] $msg
905} [list 1 "wrong # args: should be \"trace variable name ops command\""]
906test trace-14.9 {trace command, "trace variable" errors} {
907    list [catch {trace variable x y} msg] $msg
908} [list 1 "wrong # args: should be \"trace variable name ops command\""]
909test trace-14.10 {trace command, "trace variable" errors} {
910    list [catch {trace variable x y z w} msg] $msg
911} [list 1 "wrong # args: should be \"trace variable name ops command\""]
912test trace-14.11 {trace command, "trace variable" errors} {
913    list [catch {trace variable x y z} msg] $msg
914} [list 1 "bad operations \"y\": should be one or more of rwua"]
915
916
917test trace-14.12 {trace command ("remove variable" option)} {
918    catch {unset x}
919    set info {}
920    trace add variable x write traceProc
921    trace remove variable x write traceProc
922} {}
923test trace-14.13 {trace command ("remove variable" option)} {
924    catch {unset x}
925    set info {}
926    trace add variable x write traceProc
927    trace remove variable x write traceProc
928    set x 12345
929    set info
930} {}
931test trace-14.14 {trace command ("remove variable" option)} {
932    catch {unset x}
933    set info {}
934    trace add variable x write {traceTag 1}
935    trace add variable x write traceProc
936    trace add variable x write {traceTag 2}
937    set x yy
938    trace remove variable x write traceProc
939    set x 12345
940    trace remove variable x write {traceTag 1}
941    set x foo
942    trace remove variable x write {traceTag 2}
943    set x gorp
944    set info
945} {2 x {} write 1 2 1 2}
946test trace-14.15 {trace command ("remove variable" option)} {
947    catch {unset x}
948    set info {}
949    trace add variable x write {traceTag 1}
950    trace remove variable x write non_existent
951    set x 12345
952    set info
953} {1}
954test trace-14.16 {trace command ("info variable" option)} {
955    catch {unset x}
956    trace add variable x write {traceTag 1}
957    trace add variable x write traceProc
958    trace add variable x write {traceTag 2}
959    trace info variable x
960} {{write {traceTag 2}} {write traceProc} {write {traceTag 1}}}
961test trace-14.17 {trace command ("info variable" option)} {
962    catch {unset x}
963    trace info variable x
964} {}
965test trace-14.18 {trace command ("info variable" option)} {
966    catch {unset x}
967    trace info variable x(0)
968} {}
969test trace-14.19 {trace command ("info variable" option)} {
970    catch {unset x}
971    set x 44
972    trace info variable x(0)
973} {}
974test trace-14.20 {trace command ("info variable" option)} {
975    catch {unset x}
976    set x 44
977    trace add variable x write {traceTag 1}
978    proc check {} {global x; trace info variable x}
979    check
980} {{write {traceTag 1}}}
981
982# Check fancy trace commands (long ones, weird arguments, etc.)
983
984test trace-15.1 {long trace command} {
985    catch {unset x}
986    set info {}
987    trace add variable x write {traceTag {This is a very very long argument.  It's \
988        designed to test out the facilities of TraceVarProc for dealing \
989        with such long arguments by malloc-ing space.  One possibility \
990        is that space doesn't get freed properly.  If this happens, then \
991        invoking this test over and over again will eventually leak memory.}}
992    set x 44
993    set info
994} {This is a very very long argument.  It's \
995        designed to test out the facilities of TraceVarProc for dealing \
996        with such long arguments by malloc-ing space.  One possibility \
997        is that space doesn't get freed properly.  If this happens, then \
998        invoking this test over and over again will eventually leak memory.}
999test trace-15.2 {long trace command result to ignore} {
1000    proc longResult {args} {return "quite a bit of text, designed to
1001        generate a core leak if this command file is invoked over and over again
1002        and memory isn't being recycled correctly"}
1003    catch {unset x}
1004    trace add variable x write longResult
1005    set x 44
1006    set x 5
1007    set x abcde
1008} abcde
1009test trace-15.3 {special list-handling in trace commands} {
1010    catch {unset "x y z"}
1011    set "x y z(a\n\{)" 44
1012    set info {}
1013    trace add variable "x y z(a\n\{)" write traceProc
1014    set "x y z(a\n\{)" 33
1015    set info
1016} "{x y z} a\\n\\\{ write"
1017
1018# Check for proper handling of unsets during traces.
1019
1020proc traceUnset {unsetName args} {
1021    global info
1022    upvar $unsetName x
1023    lappend info [catch {unset x} msg] $msg [catch {set x} msg] $msg
1024}
1025proc traceReset {unsetName resetName args} {
1026    global info
1027    upvar $unsetName x $resetName y
1028    lappend info [catch {unset x} msg] $msg [catch {set y xyzzy} msg] $msg
1029}
1030proc traceReset2 {unsetName resetName args} {
1031    global info
1032    lappend info [catch {uplevel unset $unsetName} msg] $msg \
1033            [catch {uplevel set $resetName xyzzy} msg] $msg
1034}
1035proc traceAppend {string name1 name2 op} {
1036    global info
1037    lappend info $string
1038}
1039
1040test trace-16.1 {unsets during read traces} {
1041    catch {unset y}
1042    set y 1234
1043    set info {}
1044    trace add variable y read {traceUnset y}
1045    trace add variable y unset {traceAppend unset}
1046    lappend info [catch {set y} msg] $msg
1047} {unset 0 {} 1 {can't read "x": no such variable} 1 {can't read "y": no such variable}}
1048test trace-16.2 {unsets during read traces} {
1049    catch {unset y}
1050    set y(0) 1234
1051    set info {}
1052    trace add variable y(0) read {traceUnset y(0)}
1053    lappend info [catch {set y(0)} msg] $msg
1054} {0 {} 1 {can't read "x": no such variable} 1 {can't read "y(0)": no such element in array}}
1055test trace-16.3 {unsets during read traces} {
1056    catch {unset y}
1057    set y(0) 1234
1058    set info {}
1059    trace add variable y(0) read {traceUnset y}
1060    lappend info [catch {set y(0)} msg] $msg
1061} {0 {} 1 {can't read "x": no such variable} 1 {can't read "y(0)": no such variable}}
1062test trace-16.4 {unsets during read traces} {
1063    catch {unset y}
1064    set y 1234
1065    set info {}
1066    trace add variable y read {traceReset y y}
1067    lappend info [catch {set y} msg] $msg
1068} {0 {} 0 xyzzy 0 xyzzy}
1069test trace-16.5 {unsets during read traces} {
1070    catch {unset y}
1071    set y(0) 1234
1072    set info {}
1073    trace add variable y(0) read {traceReset y(0) y(0)}
1074    lappend info [catch {set y(0)} msg] $msg
1075} {0 {} 0 xyzzy 0 xyzzy}
1076test trace-16.6 {unsets during read traces} {
1077    catch {unset y}
1078    set y(0) 1234
1079    set info {}
1080    trace add variable y(0) read {traceReset y y(0)}
1081    lappend info [catch {set y(0)} msg] $msg [catch {set y(0)} msg] $msg
1082} {0 {} 1 {can't set "y": upvar refers to element in deleted array} 1 {can't read "y(0)": no such variable} 1 {can't read "y(0)": no such variable}}
1083test trace-16.7 {unsets during read traces} {
1084    catch {unset y}
1085    set y(0) 1234
1086    set info {}
1087    trace add variable y(0) read {traceReset2 y y(0)}
1088    lappend info [catch {set y(0)} msg] $msg [catch {set y(0)} msg] $msg
1089} {0 {} 0 xyzzy 1 {can't read "y(0)": no such element in array} 0 xyzzy}
1090test trace-16.8 {unsets during write traces} {
1091    catch {unset y}
1092    set y 1234
1093    set info {}
1094    trace add variable y write {traceUnset y}
1095    trace add variable y unset {traceAppend unset}
1096    lappend info [catch {set y xxx} msg] $msg
1097} {unset 0 {} 1 {can't read "x": no such variable} 0 {}}
1098test trace-16.9 {unsets during write traces} {
1099    catch {unset y}
1100    set y(0) 1234
1101    set info {}
1102    trace add variable y(0) write {traceUnset y(0)}
1103    lappend info [catch {set y(0) xxx} msg] $msg
1104} {0 {} 1 {can't read "x": no such variable} 0 {}}
1105test trace-16.10 {unsets during write traces} {
1106    catch {unset y}
1107    set y(0) 1234
1108    set info {}
1109    trace add variable y(0) write {traceUnset y}
1110    lappend info [catch {set y(0) xxx} msg] $msg
1111} {0 {} 1 {can't read "x": no such variable} 0 {}}
1112test trace-16.11 {unsets during write traces} {
1113    catch {unset y}
1114    set y 1234
1115    set info {}
1116    trace add variable y write {traceReset y y}
1117    lappend info [catch {set y xxx} msg] $msg
1118} {0 {} 0 xyzzy 0 xyzzy}
1119test trace-16.12 {unsets during write traces} {
1120    catch {unset y}
1121    set y(0) 1234
1122    set info {}
1123    trace add variable y(0) write {traceReset y(0) y(0)}
1124    lappend info [catch {set y(0) xxx} msg] $msg
1125} {0 {} 0 xyzzy 0 xyzzy}
1126test trace-16.13 {unsets during write traces} {
1127    catch {unset y}
1128    set y(0) 1234
1129    set info {}
1130    trace add variable y(0) write {traceReset y y(0)}
1131    lappend info [catch {set y(0) xxx} msg] $msg [catch {set y(0)} msg] $msg
1132} {0 {} 1 {can't set "y": upvar refers to element in deleted array} 0 {} 1 {can't read "y(0)": no such variable}}
1133test trace-16.14 {unsets during write traces} {
1134    catch {unset y}
1135    set y(0) 1234
1136    set info {}
1137    trace add variable y(0) write {traceReset2 y y(0)}
1138    lappend info [catch {set y(0) xxx} msg] $msg [catch {set y(0)} msg] $msg
1139} {0 {} 0 xyzzy 0 {} 0 xyzzy}
1140test trace-16.15 {unsets during unset traces} {
1141    catch {unset y}
1142    set y 1234
1143    set info {}
1144    trace add variable y unset {traceUnset y}
1145    lappend info [catch {unset y} msg] $msg [catch {set y} msg] $msg
1146} {1 {can't unset "x": no such variable} 1 {can't read "x": no such variable} 0 {} 1 {can't read "y": no such variable}}
1147test trace-16.16 {unsets during unset traces} {
1148    catch {unset y}
1149    set y(0) 1234
1150    set info {}
1151    trace add variable y(0) unset {traceUnset y(0)}
1152    lappend info [catch {unset y(0)} msg] $msg [catch {set y(0)} msg] $msg
1153} {1 {can't unset "x": no such variable} 1 {can't read "x": no such variable} 0 {} 1 {can't read "y(0)": no such element in array}}
1154test trace-16.17 {unsets during unset traces} {
1155    catch {unset y}
1156    set y(0) 1234
1157    set info {}
1158    trace add variable y(0) unset {traceUnset y}
1159    lappend info [catch {unset y(0)} msg] $msg [catch {set y(0)} msg] $msg
1160} {0 {} 1 {can't read "x": no such variable} 0 {} 1 {can't read "y(0)": no such variable}}
1161test trace-16.18 {unsets during unset traces} {
1162    catch {unset y}
1163    set y 1234
1164    set info {}
1165    trace add variable y unset {traceReset2 y y}
1166    lappend info [catch {unset y} msg] $msg [catch {set y} msg] $msg
1167} {1 {can't unset "y": no such variable} 0 xyzzy 0 {} 0 xyzzy}
1168test trace-16.19 {unsets during unset traces} {
1169    catch {unset y}
1170    set y(0) 1234
1171    set info {}
1172    trace add variable y(0) unset {traceReset2 y(0) y(0)}
1173    lappend info [catch {unset y(0)} msg] $msg [catch {set y(0)} msg] $msg
1174} {1 {can't unset "y(0)": no such element in array} 0 xyzzy 0 {} 0 xyzzy}
1175test trace-16.20 {unsets during unset traces} {
1176    catch {unset y}
1177    set y(0) 1234
1178    set info {}
1179    trace add variable y(0) unset {traceReset2 y y(0)}
1180    lappend info [catch {unset y(0)} msg] $msg [catch {set y(0)} msg] $msg
1181} {0 {} 0 xyzzy 0 {} 0 xyzzy}
1182test trace-16.21 {unsets cancelling traces} {
1183    catch {unset y}
1184    set y 1234
1185    set info {}
1186    trace add variable y read {traceAppend first}
1187    trace add variable y read {traceUnset y}
1188    trace add variable y read {traceAppend third}
1189    trace add variable y unset {traceAppend unset}
1190    lappend info [catch {set y} msg] $msg
1191} {third unset 0 {} 1 {can't read "x": no such variable} 1 {can't read "y": no such variable}}
1192test trace-16.22 {unsets cancelling traces} {
1193    catch {unset y}
1194    set y(0) 1234
1195    set info {}
1196    trace add variable y(0) read {traceAppend first}
1197    trace add variable y(0) read {traceUnset y}
1198    trace add variable y(0) read {traceAppend third}
1199    trace add variable y(0) unset {traceAppend unset}
1200    lappend info [catch {set y(0)} msg] $msg
1201} {third unset 0 {} 1 {can't read "x": no such variable} 1 {can't read "y(0)": no such variable}}
1202
1203# Check various non-interference between traces and other things.
1204
1205test trace-17.1 {trace doesn't prevent unset errors} {
1206    catch {unset x}
1207    set info {}
1208    trace add variable x unset {traceProc}
1209    list [catch {unset x} msg] $msg $info
1210} {1 {can't unset "x": no such variable} {x {} unset}}
1211test trace-17.2 {traced variables must survive procedure exits} {
1212    catch {unset x}
1213    proc p1 {} {global x; trace add variable x write traceProc}
1214    p1
1215    trace info variable x
1216} {{write traceProc}}
1217test trace-17.3 {traced variables must survive procedure exits} {
1218    catch {unset x}
1219    set info {}
1220    proc p1 {} {global x; trace add variable x write traceProc}
1221    p1
1222    set x 44
1223    set info
1224} {x {} write}
1225
1226# Be sure that procedure frames are released before unset traces
1227# are invoked.
1228
1229test trace-18.1 {unset traces on procedure returns} {
1230    proc p1 {x y} {set a 44; p2 14}
1231    proc p2 {z} {trace add variable z unset {traceCheck {lsort [uplevel {info vars}]}}}
1232    set info {}
1233    p1 foo bar
1234    set info
1235} {0 {a x y}}
1236test trace-18.2 {namespace delete / trace vdelete combo} {
1237    namespace eval ::foo {
1238        variable x 123
1239    }
1240    proc p1 args {
1241        trace vdelete ::foo::x u p1
1242    }
1243    trace variable ::foo::x u p1
1244    namespace delete ::foo
1245    info exists ::foo::x
1246} 0
1247test trace-18.3 {namespace delete / trace vdelete combo, Bug \#1337229} {
1248    namespace eval ::ns {}
1249    trace add variable ::ns::var unset {unset ::ns::var ;#}
1250    namespace delete ::ns
1251} {}
1252test trace-18.4 {namespace delete / trace vdelete combo, Bug \#1338280} {
1253    namespace eval ::ref {}
1254    set ::ref::var1 AAA
1255    trace add variable ::ref::var1 unset doTrace
1256    set ::ref::var2 BBB
1257    trace add variable ::ref::var2 {unset} doTrace
1258    proc doTrace {vtraced vidx op} {
1259        global info
1260        append info [catch {set ::$vtraced}][llength [info vars ::ref::*]]
1261    }
1262    set info {}
1263    namespace delete ::ref
1264    rename doTrace {}
1265    set info
1266} 1110
1267
1268# Delete arrays when done, so they can be re-used as scalars
1269# elsewhere.
1270
1271catch {unset x}
1272catch {unset y}
1273
1274test trace-19.0.1 {trace add command (command existence)} {
1275    # Just in case!
1276    catch {rename nosuchname ""}
1277    list [catch {trace add command nosuchname rename traceCommand} msg] $msg
1278} {1 {unknown command "nosuchname"}}
1279test trace-19.0.2 {trace add command (command existence in ns)} {
1280    list [catch {trace add command nosuchns::nosuchname rename traceCommand} msg] $msg
1281} {1 {unknown command "nosuchns::nosuchname"}}
1282
1283
1284test trace-19.1 {trace add command (rename option)} {
1285    proc foo {} {}
1286    catch {rename bar {}}
1287    trace add command foo rename traceCommand
1288    rename foo bar
1289    set info
1290} {::foo ::bar rename}
1291test trace-19.2 {traces stick with renamed commands} {
1292    proc foo {} {}
1293    catch {rename bar {}}
1294    trace add command foo rename traceCommand
1295    rename foo bar
1296    rename bar foo
1297    set info
1298} {::bar ::foo rename}
1299test trace-19.2.1 {trace add command rename trace exists} {
1300    proc foo {} {}
1301    trace add command foo rename traceCommand
1302    trace info command foo
1303} {{rename traceCommand}}
1304test trace-19.3 {command rename traces don't fire on command deletion} {
1305    proc foo {} {}
1306    set info {}
1307    trace add command foo rename traceCommand
1308    rename foo {}
1309    set info
1310} {}
1311test trace-19.4 {trace add command rename doesn't trace recreated commands} {
1312    proc foo {} {}
1313    catch {rename bar {}}
1314    trace add command foo rename traceCommand
1315    proc foo {} {}
1316    rename foo bar
1317    set info
1318} {}
1319test trace-19.5 {trace add command deleted removes traces} {
1320    proc foo {} {}
1321    trace add command foo rename traceCommand
1322    proc foo {} {}
1323    trace info command foo
1324} {}
1325
1326namespace eval tc {}
1327proc tc::tcfoo {} {}
1328test trace-19.6 {trace add command rename in namespace} {
1329    trace add command tc::tcfoo rename traceCommand
1330    rename tc::tcfoo tc::tcbar
1331    set info
1332} {::tc::tcfoo ::tc::tcbar rename}
1333test trace-19.7 {trace add command rename in namespace back again} {
1334    rename tc::tcbar tc::tcfoo
1335    set info
1336} {::tc::tcbar ::tc::tcfoo rename}
1337test trace-19.8 {trace add command rename in namespace to out of namespace} {
1338    rename tc::tcfoo tcbar
1339    set info
1340} {::tc::tcfoo ::tcbar rename}
1341test trace-19.9 {trace add command rename back into namespace} {
1342    rename tcbar tc::tcfoo
1343    set info
1344} {::tcbar ::tc::tcfoo rename}
1345test trace-19.10 {trace add command failed rename doesn't trigger trace} {
1346    set info {}
1347    proc foo {} {}
1348    proc bar {} {}
1349    trace add command foo {rename delete} traceCommand
1350    catch {rename foo bar}
1351    set info
1352} {}
1353catch {rename foo {}}
1354catch {rename bar {}}
1355test trace-19.11 {trace add command qualifies when renamed in namespace} {
1356    set info {}
1357    namespace eval tc {rename tcfoo tcbar}
1358    set info
1359} {::tc::tcfoo ::tc::tcbar rename}
1360
1361# Make sure it exists again
1362proc foo {} {}
1363
1364test trace-20.1 {trace add command (delete option)} {
1365    trace add command foo delete traceCommand
1366    rename foo ""
1367    set info
1368} {::foo {} delete}
1369test trace-20.2 {trace add command delete doesn't trace recreated commands} {
1370    set info {}
1371    proc foo {} {}
1372    rename foo ""
1373    set info
1374} {}
1375test trace-20.2.1 {trace add command delete trace info} {
1376    proc foo {} {}
1377    trace add command foo delete traceCommand
1378    trace info command foo
1379} {{delete traceCommand}}
1380test trace-20.3 {trace add command implicit delete} {
1381    proc foo {} {}
1382    trace add command foo delete traceCommand
1383    proc foo {} {}
1384    set info
1385} {::foo {} delete}
1386test trace-20.3.1 {trace add command delete trace info} {
1387    proc foo {} {}
1388    trace info command foo
1389} {}
1390test trace-20.4 {trace add command rename followed by delete} {
1391    set infotemp {}
1392    proc foo {} {}
1393    trace add command foo {rename delete} traceCommand
1394    rename foo bar
1395    lappend infotemp $info
1396    rename bar {}
1397    lappend infotemp $info
1398    set info $infotemp
1399    unset infotemp
1400    set info
1401} {{::foo ::bar rename} {::bar {} delete}}
1402catch {rename foo {}}
1403catch {rename bar {}}
1404
1405test trace-20.5 {trace add command rename and delete} {
1406    set infotemp {}
1407    set info {}
1408    proc foo {} {}
1409    trace add command foo {rename delete} traceCommand
1410    rename foo bar
1411    lappend infotemp $info
1412    rename bar {}
1413    lappend infotemp $info
1414    set info $infotemp
1415    unset infotemp
1416    set info
1417} {{::foo ::bar rename} {::bar {} delete}}
1418
1419test trace-20.6 {trace add command rename and delete in subinterp} {
1420    set tc [interp create]
1421    foreach p {traceCommand} {
1422        $tc eval [list proc $p [info args $p] [info body $p]]
1423    }
1424    $tc eval [list set infotemp {}]
1425    $tc eval [list set info {}]
1426    $tc eval [list proc foo {} {}]
1427    $tc eval [list trace add command foo {rename delete} traceCommand]
1428    $tc eval [list rename foo bar]
1429    $tc eval {lappend infotemp $info}
1430    $tc eval [list rename bar {}]
1431    $tc eval {lappend infotemp $info}
1432    $tc eval {set info $infotemp}
1433    $tc eval [list unset infotemp]
1434    set info [$tc eval [list set info]]
1435    interp delete $tc
1436    set info
1437} {{::foo ::bar rename} {::bar {} delete}}
1438
1439# I'd like it if this test could give 'foo {} d' as a result,
1440# but interp deletion means there is no interp to evaluate
1441# the trace in.
1442test trace-20.7 {trace add command delete in subinterp while being deleted} {
1443    set info {}
1444    set tc [interp create]
1445    interp alias $tc traceCommand {} traceCommand
1446    $tc eval [list proc foo {} {}]
1447    $tc eval [list trace add command foo {rename delete} traceCommand]
1448    interp delete $tc
1449    set info
1450} {}
1451
1452proc traceDelete {cmd old new op} {
1453    trace remove command $cmd {*}[lindex [trace info command $cmd] 0]
1454    global info
1455    set info [list $old $new $op]
1456}
1457proc traceCmdrename {cmd old new op} {
1458    rename $old someothername
1459}
1460proc traceCmddelete {cmd old new op} {
1461    rename $old ""
1462}
1463test trace-20.8 {trace delete while trace is active} {
1464    set info {}
1465    proc foo {} {}
1466    catch {rename bar {}}
1467    trace add command foo {rename delete} [list traceDelete foo]
1468    rename foo bar
1469    list [set info] [trace info command bar]
1470} {{::foo ::bar rename} {}}
1471
1472test trace-20.9 {rename trace deletes command} {
1473    set info {}
1474    proc foo {} {}
1475    catch {rename bar {}}
1476    catch {rename someothername {}}
1477    trace add command foo rename [list traceCmddelete foo]
1478    rename foo bar
1479    list [info commands foo] [info commands bar] [info commands someothername]
1480} {{} {} {}}
1481
1482test trace-20.10 {rename trace renames command} {
1483    set info {}
1484    proc foo {} {}
1485    catch {rename bar {}}
1486    catch {rename someothername {}}
1487    trace add command foo rename [list traceCmdrename foo]
1488    rename foo bar
1489    set info [list [info commands foo] [info commands bar] [info commands someothername]]
1490    rename someothername {}
1491    set info
1492} {{} {} someothername}
1493
1494test trace-20.11 {delete trace deletes command} {
1495    set info {}
1496    proc foo {} {}
1497    catch {rename bar {}}
1498    catch {rename someothername {}}
1499    trace add command foo delete [list traceCmddelete foo]
1500    rename foo {}
1501    list [info commands foo] [info commands bar] [info commands someothername]
1502} {{} {} {}}
1503
1504test trace-20.12 {delete trace renames command} {
1505    set info {}
1506    proc foo {} {}
1507    catch {rename bar {}}
1508    catch {rename someothername {}}
1509    trace add command foo delete [list traceCmdrename foo]
1510    rename foo bar
1511    rename bar {}
1512    # None of these should exist.
1513    list [info commands foo] [info commands bar] [info commands someothername]
1514} {{} {} {}}
1515
1516test trace-20.13 {rename trace discards result [Bug 1355342]} {
1517    proc foo {} {}
1518    trace add command foo rename {set w Aha!;#}
1519    list [rename foo bar] [rename bar {}]
1520} {{} {}}
1521test trace-20.14 {rename trace discards error result [Bug 1355342]} {
1522    proc foo {} {}
1523    trace add command foo rename {error}
1524    list [rename foo bar] [rename bar {}]
1525} {{} {}}
1526test trace-20.15 {delete trace discards result [Bug 1355342]} {
1527    proc foo {} {}
1528    trace add command foo delete {set w Aha!;#}
1529    rename foo {}
1530} {}
1531test trace-20.16 {delete trace discards error result [Bug 1355342]} {
1532    proc foo {} {}
1533    trace add command foo delete {error}
1534    rename foo {}
1535} {}
1536
1537
1538proc foo {b} { set a $b }
1539
1540
1541# Delete arrays when done, so they can be re-used as scalars
1542# elsewhere.
1543
1544catch {unset x}
1545catch {unset y}
1546
1547# Delete procedures when done, so we don't clash with other tests
1548# (e.g. foobar will clash with 'unknown' tests).
1549catch {rename foobar {}}
1550catch {rename foo {}}
1551catch {rename bar {}}
1552
1553proc foo {a} {
1554    set b $a
1555}
1556
1557proc traceExecute {args} {
1558    global info
1559    lappend info $args
1560}
1561
1562test trace-21.1 {trace execution: enter} {
1563    set info {}
1564    trace add execution foo enter [list traceExecute foo]
1565    foo 1
1566    trace remove execution foo enter [list traceExecute foo]
1567    set info
1568} {{foo {foo 1} enter}}
1569
1570test trace-21.2 {trace exeuction: leave} {
1571    set info {}
1572    trace add execution foo leave [list traceExecute foo]
1573    foo 2
1574    trace remove execution foo leave [list traceExecute foo]
1575    set info
1576} {{foo {foo 2} 0 2 leave}}
1577
1578test trace-21.3 {trace exeuction: enter, leave} {
1579    set info {}
1580    trace add execution foo {enter leave} [list traceExecute foo]
1581    foo 3
1582    trace remove execution foo {enter leave} [list traceExecute foo]
1583    set info
1584} {{foo {foo 3} enter} {foo {foo 3} 0 3 leave}}
1585
1586test trace-21.4 {trace execution: enter, leave, enterstep} {
1587    set info {}
1588    trace add execution foo {enter leave enterstep} [list traceExecute foo]
1589    foo 3
1590    trace remove execution foo {enter leave enterstep} [list traceExecute foo]
1591    set info
1592} {{foo {foo 3} enter} {foo {set b 3} enterstep} {foo {foo 3} 0 3 leave}}
1593
1594test trace-21.5 {trace execution: enter, leave, enterstep, leavestep} {
1595    set info {}
1596    trace add execution foo {enter leave enterstep leavestep} [list traceExecute foo]
1597    foo 3
1598    trace remove execution foo {enter leave enterstep leavestep} [list traceExecute foo]
1599    set info
1600} {{foo {foo 3} enter} {foo {set b 3} enterstep} {foo {set b 3} 0 3 leavestep} {foo {foo 3} 0 3 leave}}
1601
1602test trace-21.6 {trace execution: enterstep, leavestep} {
1603    set info {}
1604    trace add execution foo {enterstep leavestep} [list traceExecute foo]
1605    foo 3
1606    trace remove execution foo {enterstep leavestep} [list traceExecute foo]
1607    set info
1608} {{foo {set b 3} enterstep} {foo {set b 3} 0 3 leavestep}}
1609
1610test trace-21.7 {trace execution: enterstep} {
1611    set info {}
1612    trace add execution foo {enterstep} [list traceExecute foo]
1613    foo 3
1614    trace remove execution foo {enterstep} [list traceExecute foo]
1615    set info
1616} {{foo {set b 3} enterstep}}
1617
1618test trace-21.8 {trace execution: leavestep} {
1619    set info {}
1620    trace add execution foo {leavestep} [list traceExecute foo]
1621    foo 3
1622    trace remove execution foo {leavestep} [list traceExecute foo]
1623    set info
1624} {{foo {set b 3} 0 3 leavestep}}
1625
1626test trace-21.9 {trace execution: TCL_EVAL_GLOBAL} testevalobjv {
1627    trace add execution foo enter soom
1628    proc ::soom args {lappend ::info SUCCESS [info level]}
1629    set ::info {}
1630    namespace eval test_ns_1 {
1631        proc soom args {lappend ::info FAIL [info level]}
1632        # [testevalobjv 1 ...] ought to produce the same
1633       # results as [uplevel #0 ...].
1634        testevalobjv 1 foo x
1635       uplevel #0 foo x
1636    }
1637    namespace delete test_ns_1
1638    trace remove execution foo enter soom
1639    set ::info
1640} {SUCCESS 1 SUCCESS 1}
1641
1642test trace-21.10 {trace execution: TCL_EVAL_GLOBAL} testevalobjv {
1643    trace add execution foo leave soom
1644    proc ::soom args {lappend ::info SUCCESS [info level]}
1645    set ::info {}
1646    namespace eval test_ns_1 {
1647        proc soom args {lappend ::info FAIL [info level]}
1648        # [testevalobjv 1 ...] ought to produce the same
1649       # results as [uplevel #0 ...].
1650        testevalobjv 1 foo x
1651       uplevel #0 foo x
1652    }
1653    namespace delete test_ns_1
1654    trace remove execution foo leave soom
1655    set ::info
1656} {SUCCESS 1 SUCCESS 1}
1657
1658test trace-21.11 {trace execution and alias} -setup {
1659    set res {}
1660    proc ::x {} {return ::}
1661    namespace eval a {}
1662    proc ::a::x {} {return ::a}
1663    interp alias {} y {} x
1664} -body {
1665    lappend res [namespace eval ::a y]
1666    trace add execution ::x enter {
1667      rename ::x {}
1668        proc ::x {} {return ::}
1669    #}
1670    lappend res [namespace eval ::a y]
1671} -cleanup {
1672    namespace delete a
1673    rename ::x {}
1674} -result {:: ::}
1675
1676proc factorial {n} {
1677    if {$n != 1} { return [expr {$n * [factorial [expr {$n -1 }]]}] }
1678    return 1
1679}
1680
1681test trace-22.1 {recursive(1) trace execution: enter} {
1682    set info {}
1683    trace add execution factorial {enter} [list traceExecute factorial]
1684    factorial 1
1685    trace remove execution factorial {enter} [list traceExecute factorial]
1686    set info
1687} {{factorial {factorial 1} enter}}
1688
1689test trace-22.2 {recursive(2) trace execution: enter} {
1690    set info {}
1691    trace add execution factorial {enter} [list traceExecute factorial]
1692    factorial 2
1693    trace remove execution factorial {enter} [list traceExecute factorial]
1694    set info
1695} {{factorial {factorial 2} enter} {factorial {factorial 1} enter}}
1696
1697test trace-22.3 {recursive(3) trace execution: enter} {
1698    set info {}
1699    trace add execution factorial {enter} [list traceExecute factorial]
1700    factorial 3
1701    trace remove execution factorial {enter} [list traceExecute factorial]
1702    set info
1703} {{factorial {factorial 3} enter} {factorial {factorial 2} enter} {factorial {factorial 1} enter}}
1704
1705test trace-23.1 {recursive(1) trace execution: enter, leave, enterstep, leavestep} {
1706    set info {}
1707    trace add execution factorial {enter leave enterstep leavestep} [list traceExecute]
1708    factorial 1
1709    trace remove execution factorial {enter leave enterstep leavestep} [list traceExecute]
1710    join $info "\n"
1711} {{factorial 1} enter
1712{if {$n != 1} { return [expr {$n * [factorial [expr {$n -1 }]]}] }} enterstep
1713{if {$n != 1} { return [expr {$n * [factorial [expr {$n -1 }]]}] }} 0 {} leavestep
1714{return 1} enterstep
1715{return 1} 2 1 leavestep
1716{factorial 1} 0 1 leave}
1717
1718test trace-23.2 {recursive(2) trace execution: enter, leave, enterstep, leavestep} {
1719    set info {}
1720    trace add execution factorial {enter leave enterstep leavestep} [list traceExecute]
1721    factorial 2
1722    trace remove execution factorial {enter leave enterstep leavestep} [list traceExecute]
1723    join $info "\n"
1724} {{factorial 2} enter
1725{if {$n != 1} { return [expr {$n * [factorial [expr {$n -1 }]]}] }} enterstep
1726{expr {$n * [factorial [expr {$n -1 }]]}} enterstep
1727{expr {$n -1 }} enterstep
1728{expr {$n -1 }} 0 1 leavestep
1729{factorial 1} enterstep
1730{factorial 1} enter
1731{if {$n != 1} { return [expr {$n * [factorial [expr {$n -1 }]]}] }} enterstep
1732{if {$n != 1} { return [expr {$n * [factorial [expr {$n -1 }]]}] }} 0 {} leavestep
1733{return 1} enterstep
1734{return 1} 2 1 leavestep
1735{factorial 1} 0 1 leave
1736{factorial 1} 0 1 leavestep
1737{expr {$n * [factorial [expr {$n -1 }]]}} 0 2 leavestep
1738{return 2} enterstep
1739{return 2} 2 2 leavestep
1740{if {$n != 1} { return [expr {$n * [factorial [expr {$n -1 }]]}] }} 2 2 leavestep
1741{factorial 2} 0 2 leave}
1742
1743test trace-23.3 {recursive(3) trace execution: enter, leave, enterstep, leavestep} {
1744    set info {}
1745    trace add execution factorial {enter leave enterstep leavestep} [list traceExecute]
1746    factorial 3
1747    trace remove execution factorial {enter leave enterstep leavestep} [list traceExecute]
1748    join $info "\n"
1749} {{factorial 3} enter
1750{if {$n != 1} { return [expr {$n * [factorial [expr {$n -1 }]]}] }} enterstep
1751{expr {$n * [factorial [expr {$n -1 }]]}} enterstep
1752{expr {$n -1 }} enterstep
1753{expr {$n -1 }} 0 2 leavestep
1754{factorial 2} enterstep
1755{factorial 2} enter
1756{if {$n != 1} { return [expr {$n * [factorial [expr {$n -1 }]]}] }} enterstep
1757{expr {$n * [factorial [expr {$n -1 }]]}} enterstep
1758{expr {$n -1 }} enterstep
1759{expr {$n -1 }} 0 1 leavestep
1760{factorial 1} enterstep
1761{factorial 1} enter
1762{if {$n != 1} { return [expr {$n * [factorial [expr {$n -1 }]]}] }} enterstep
1763{if {$n != 1} { return [expr {$n * [factorial [expr {$n -1 }]]}] }} 0 {} leavestep
1764{return 1} enterstep
1765{return 1} 2 1 leavestep
1766{factorial 1} 0 1 leave
1767{factorial 1} 0 1 leavestep
1768{expr {$n * [factorial [expr {$n -1 }]]}} 0 2 leavestep
1769{return 2} enterstep
1770{return 2} 2 2 leavestep
1771{if {$n != 1} { return [expr {$n * [factorial [expr {$n -1 }]]}] }} 2 2 leavestep
1772{factorial 2} 0 2 leave
1773{factorial 2} 0 2 leavestep
1774{expr {$n * [factorial [expr {$n -1 }]]}} 0 6 leavestep
1775{return 6} enterstep
1776{return 6} 2 6 leavestep
1777{if {$n != 1} { return [expr {$n * [factorial [expr {$n -1 }]]}] }} 2 6 leavestep
1778{factorial 3} 0 6 leave}
1779
1780proc traceDelete {cmd args} {
1781    trace remove execution $cmd {*}[lindex [trace info execution $cmd] 0]
1782    global info
1783    set info $args
1784}
1785
1786test trace-24.1 {delete trace during enter trace} {
1787    set info {}
1788    trace add execution foo enter [list traceDelete foo]
1789    foo 1
1790    list $info [catch {trace info execution foo} res] $res
1791} {{{foo 1} enter} 0 {}}
1792
1793test trace-24.2 {delete trace during leave trace} {
1794    set info {}
1795    trace add execution foo leave [list traceDelete foo]
1796    foo 1
1797    list $info [catch {trace info execution foo} res] $res
1798} {{{foo 1} 0 1 leave} 0 {}}
1799
1800test trace-24.3 {delete trace during enter-leave trace} {
1801    set info {}
1802    trace add execution foo {enter leave} [list traceDelete foo]
1803    foo 1
1804    list $info [catch {trace info execution foo} res] $res
1805} {{{foo 1} enter} 0 {}}
1806
1807test trace-24.4 {delete trace during all exec traces} {
1808    set info {}
1809    trace add execution foo {enter leave enterstep leavestep} [list traceDelete foo]
1810    foo 1
1811    list $info [catch {trace info execution foo} res] $res
1812} {{{foo 1} enter} 0 {}}
1813
1814test trace-24.5 {delete trace during all exec traces except enter} {
1815    set info {}
1816    trace add execution foo {leave enterstep leavestep} [list traceDelete foo]
1817    foo 1
1818    list $info [catch {trace info execution foo} res] $res
1819} {{{set b 1} enterstep} 0 {}}
1820
1821proc traceDelete {cmd args} {
1822    rename $cmd {}
1823    global info
1824    set info $args
1825}
1826
1827proc foo {a} {
1828    set b $a
1829}
1830
1831test trace-25.1 {delete command during enter trace} {
1832    set info {}
1833    trace add execution foo enter [list traceDelete foo]
1834    catch {foo 1} err
1835    list $err $info [catch {trace info execution foo} res] $res
1836} {{invalid command name "foo"} {{foo 1} enter} 1 {unknown command "foo"}}
1837
1838proc foo {a} {
1839    set b $a
1840}
1841
1842test trace-25.2 {delete command during leave trace} {
1843    set info {}
1844    trace add execution foo leave [list traceDelete foo]
1845    foo 1
1846    list $info [catch {trace info execution foo} res] $res
1847} {{{foo 1} 0 1 leave} 1 {unknown command "foo"}}
1848
1849proc foo {a} {
1850    set b $a
1851}
1852
1853test trace-25.3 {delete command during enter then leave trace} {
1854    set info {}
1855    trace add execution foo enter [list traceDelete foo]
1856    trace add execution foo leave [list traceDelete foo]
1857    catch {foo 1} err
1858    list $err $info [catch {trace info execution foo} res] $res
1859} {{invalid command name "foo"} {{foo 1} enter} 1 {unknown command "foo"}}
1860
1861proc foo {a} {
1862    set b $a
1863}
1864proc traceExecute2 {args} {
1865    global info
1866    lappend info $args
1867}
1868
1869# This shows the peculiar consequences of having two traces
1870# at the same time: as well as tracing the procedure you want
1871test trace-25.4 {order dependencies of two enter traces} {
1872    set info {}
1873    trace add execution foo enter [list traceExecute traceExecute]
1874    trace add execution foo enter [list traceExecute2 traceExecute2]
1875    catch {foo 1} err
1876    trace remove execution foo enter [list traceExecute traceExecute]
1877    trace remove execution foo enter [list traceExecute2 traceExecute2]
1878    join [list $err [join $info \n] [trace info execution foo]] "\n"
1879} {1
1880traceExecute2 {foo 1} enter
1881traceExecute {foo 1} enter
1882}
1883
1884test trace-25.5 {order dependencies of two step traces} {
1885    set info {}
1886    trace add execution foo enterstep [list traceExecute traceExecute]
1887    trace add execution foo enterstep [list traceExecute2 traceExecute2]
1888    catch {foo 1} err
1889    trace remove execution foo enterstep [list traceExecute traceExecute]
1890    trace remove execution foo enterstep [list traceExecute2 traceExecute2]
1891    join [list $err [join $info \n] [trace info execution foo]] "\n"
1892} {1
1893traceExecute2 {set b 1} enterstep
1894traceExecute {set b 1} enterstep
1895}
1896
1897# We don't want the result string (5th argument), or the results
1898# will get unmanageable.
1899proc tracePostExecute {args} {
1900    global info
1901    lappend info [concat [lrange $args 0 2] [lindex $args 4]]
1902}
1903proc tracePostExecute2 {args} {
1904    global info
1905    lappend info [concat [lrange $args 0 2] [lindex $args 4]]
1906}
1907
1908test trace-25.6 {order dependencies of two leave traces} {
1909    set info {}
1910    trace add execution foo leave [list tracePostExecute tracePostExecute]
1911    trace add execution foo leave [list tracePostExecute2 tracePostExecute2]
1912    catch {foo 1} err
1913    trace remove execution foo leave [list tracePostExecute tracePostExecute]
1914    trace remove execution foo leave [list tracePostExecute2 tracePostExecute2]
1915    join [list $err [join $info \n] [trace info execution foo]] "\n"
1916} {1
1917tracePostExecute {foo 1} 0 leave
1918tracePostExecute2 {foo 1} 0 leave
1919}
1920
1921test trace-25.7 {order dependencies of two leavestep traces} {
1922    set info {}
1923    trace add execution foo leavestep [list tracePostExecute tracePostExecute]
1924    trace add execution foo leavestep [list tracePostExecute2 tracePostExecute2]
1925    catch {foo 1} err
1926    trace remove execution foo leavestep [list tracePostExecute tracePostExecute]
1927    trace remove execution foo leavestep [list tracePostExecute2 tracePostExecute2]
1928    join [list $err [join $info \n] [trace info execution foo]] "\n"
1929} {1
1930tracePostExecute {set b 1} 0 leavestep
1931tracePostExecute2 {set b 1} 0 leavestep
1932}
1933
1934proc foo {a} {
1935    set b $a
1936}
1937
1938proc traceDelete {cmd args} {
1939    rename $cmd {}
1940    global info
1941    set info $args
1942}
1943
1944test trace-25.8 {delete command during enter leave and enter/leave-step traces} {
1945    set info {}
1946    trace add execution foo enter [list traceDelete foo]
1947    trace add execution foo leave [list traceDelete foo]
1948    trace add execution foo enterstep [list traceDelete foo]
1949    trace add execution foo leavestep [list traceDelete foo]
1950    catch {foo 1} err
1951    list $err $info [catch {trace info execution foo} res] $res
1952} {{invalid command name "foo"} {{foo 1} enter} 1 {unknown command "foo"}}
1953
1954proc foo {a} {
1955    set b $a
1956}
1957
1958test trace-25.9 {delete command during enter leave and leavestep traces} {
1959    set info {}
1960    trace add execution foo enter [list traceDelete foo]
1961    trace add execution foo leave [list traceDelete foo]
1962    trace add execution foo leavestep [list traceDelete foo]
1963    catch {foo 1} err
1964    list $err $info [catch {trace info execution foo} res] $res
1965} {{invalid command name "foo"} {{foo 1} enter} 1 {unknown command "foo"}}
1966
1967proc foo {a} {
1968    set b $a
1969}
1970
1971test trace-25.10 {delete command during leave and leavestep traces} {
1972    set info {}
1973    trace add execution foo leave [list traceDelete foo]
1974    trace add execution foo leavestep [list traceDelete foo]
1975    catch {foo 1} err
1976    list $err $info [catch {trace info execution foo} res] $res
1977} {1 {{set b 1} 0 1 leavestep} 1 {unknown command "foo"}}
1978
1979proc foo {a} {
1980    set b $a
1981}
1982
1983test trace-25.11 {delete command during enter and enterstep traces} {
1984    set info {}
1985    trace add execution foo enter [list traceDelete foo]
1986    trace add execution foo enterstep [list traceDelete foo]
1987    catch {foo 1} err
1988    list $err $info [catch {trace info execution foo} res] $res
1989} {{invalid command name "foo"} {{foo 1} enter} 1 {unknown command "foo"}}
1990
1991test trace-26.1 {trace targetCmd when invoked through an alias} {
1992    proc foo {args} {
1993        set b $args
1994    }
1995    set info {}
1996    trace add execution foo enter [list traceExecute foo]
1997    interp alias {} bar {} foo 1
1998    bar 2
1999    trace remove execution foo enter [list traceExecute foo]
2000    set info
2001} {{foo {foo 1 2} enter}}
2002test trace-26.2 {trace targetCmd when invoked through an alias} {
2003    proc foo {args} {
2004        set b $args
2005    }
2006    set info {}
2007    trace add execution foo enter [list traceExecute foo]
2008    interp create child
2009    interp alias child bar {} foo 1
2010    child eval bar 2
2011    interp delete child
2012    trace remove execution foo enter [list traceExecute foo]
2013    set info
2014} {{foo {foo 1 2} enter}}
2015
2016test trace-27.1 {memory leak in rename trace (604609)} {
2017    catch {rename bar {}}
2018    proc foo {} {error foo}
2019    trace add command foo rename {rename foo "" ;#}
2020    rename foo bar
2021    info commands foo
2022} {}
2023
2024test trace-27.2 {command trace remove nonsense} {
2025    list [catch {trace remove command thisdoesntexist \
2026      {delete rename} bar} res] $res
2027} {1 {unknown command "thisdoesntexist"}}
2028
2029test trace-27.3 {command trace info nonsense} {
2030    list [catch {trace info command thisdoesntexist} res] $res
2031} {1 {unknown command "thisdoesntexist"}}
2032
2033
2034test trace-28.1 {enterstep and leavestep traces with update idletasks (615043)} {
2035    catch {rename foo {}}
2036    proc foo {} {
2037        set a 1
2038        update idletasks
2039        set b 1
2040    }
2041
2042    set info {}
2043    trace add execution foo {enter enterstep leavestep leave} \
2044        [list traceExecute foo]
2045    update
2046    after idle {set a "idle"}
2047    foo
2048
2049    trace remove execution foo {enter enterstep leavestep leave} \
2050        [list traceExecute foo]
2051    rename foo {}
2052    catch {unset a}
2053    join $info "\n"
2054} {foo foo enter
2055foo {set a 1} enterstep
2056foo {set a 1} 0 1 leavestep
2057foo {update idletasks} enterstep
2058foo {set a idle} enterstep
2059foo {set a idle} 0 idle leavestep
2060foo {update idletasks} 0 {} leavestep
2061foo {set b 1} enterstep
2062foo {set b 1} 0 1 leavestep
2063foo foo 0 1 leave}
2064
2065test trace-28.2 {exec traces with 'error'} {
2066    set info {}
2067    set res {}
2068   
2069    proc foo {} {
2070        if {[catch {bar}]} {
2071            return "error"
2072        } else {
2073            return "ok"
2074        }
2075    }
2076
2077    proc bar {} { error "msg" }
2078
2079    lappend res [foo]
2080
2081    trace add execution foo {enter enterstep leave leavestep} \
2082      [list traceExecute foo]
2083
2084    # With the trace active
2085
2086    lappend res [foo]
2087
2088    trace remove execution foo {enter enterstep leave leavestep} \
2089      [list traceExecute foo]
2090   
2091    list $res [join $info \n]
2092} {{error error} {foo foo enter
2093foo {if {[catch {bar}]} {
2094            return "error"
2095        } else {
2096            return "ok"
2097        }} enterstep
2098foo {catch bar} enterstep
2099foo bar enterstep
2100foo {error msg} enterstep
2101foo {error msg} 1 msg leavestep
2102foo bar 1 msg leavestep
2103foo {catch bar} 0 1 leavestep
2104foo {return error} enterstep
2105foo {return error} 2 error leavestep
2106foo {if {[catch {bar}]} {
2107            return "error"
2108        } else {
2109            return "ok"
2110        }} 2 error leavestep
2111foo foo 0 error leave}}
2112
2113test trace-28.3 {exec traces with 'return -code error'} {
2114    set info {}
2115    set res {}
2116   
2117    proc foo {} {
2118        if {[catch {bar}]} {
2119            return "error"
2120        } else {
2121            return "ok"
2122        }
2123    }
2124
2125    proc bar {} { return -code error "msg" }
2126
2127    lappend res [foo]
2128
2129    trace add execution foo {enter enterstep leave leavestep} \
2130      [list traceExecute foo]
2131
2132    # With the trace active
2133
2134    lappend res [foo]
2135
2136    trace remove execution foo {enter enterstep leave leavestep} \
2137      [list traceExecute foo]
2138   
2139    list $res [join $info \n]
2140} {{error error} {foo foo enter
2141foo {if {[catch {bar}]} {
2142            return "error"
2143        } else {
2144            return "ok"
2145        }} enterstep
2146foo {catch bar} enterstep
2147foo bar enterstep
2148foo {return -code error msg} enterstep
2149foo {return -code error msg} 2 msg leavestep
2150foo bar 1 msg leavestep
2151foo {catch bar} 0 1 leavestep
2152foo {return error} enterstep
2153foo {return error} 2 error leavestep
2154foo {if {[catch {bar}]} {
2155            return "error"
2156        } else {
2157            return "ok"
2158        }} 2 error leavestep
2159foo foo 0 error leave}}
2160
2161test trace-28.4 {exec traces in slave with 'return -code error'} {
2162    interp create slave
2163    interp alias slave traceExecute {} traceExecute
2164    set info {}
2165    set res [interp eval slave {
2166        set info {}
2167        set res {}
2168       
2169        proc foo {} {
2170            if {[catch {bar}]} {
2171                return "error"
2172            } else {
2173                return "ok"
2174            }
2175        }
2176       
2177        proc bar {} { return -code error "msg" }
2178       
2179        lappend res [foo]
2180       
2181        trace add execution foo {enter enterstep leave leavestep} \
2182          [list traceExecute foo]
2183       
2184        # With the trace active
2185       
2186        lappend res [foo]
2187       
2188        trace remove execution foo {enter enterstep leave leavestep} \
2189          [list traceExecute foo]
2190       
2191        list $res
2192    }]
2193    interp delete slave
2194    lappend res [join $info \n]
2195} {{error error} {foo foo enter
2196foo {if {[catch {bar}]} {
2197                return "error"
2198            } else {
2199                return "ok"
2200            }} enterstep
2201foo {catch bar} enterstep
2202foo bar enterstep
2203foo {return -code error msg} enterstep
2204foo {return -code error msg} 2 msg leavestep
2205foo bar 1 msg leavestep
2206foo {catch bar} 0 1 leavestep
2207foo {return error} enterstep
2208foo {return error} 2 error leavestep
2209foo {if {[catch {bar}]} {
2210                return "error"
2211            } else {
2212                return "ok"
2213            }} 2 error leavestep
2214foo foo 0 error leave}}
2215
2216test trace-28.5 {exec traces} {
2217    set info {}
2218    proc foo {args} { set a 1 }
2219    trace add execution foo {enter enterstep leave leavestep} \
2220      [list traceExecute foo]
2221    after idle [list foo test-28.4]
2222    update
2223    # Complicated way of removing traces
2224    set ti [lindex [eval [list trace info execution ::foo]] 0]
2225    if {[llength $ti]} {
2226        eval [concat [list trace remove execution foo] $ti]
2227    }
2228    join $info \n
2229} {foo {foo test-28.4} enter
2230foo {set a 1} enterstep
2231foo {set a 1} 0 1 leavestep
2232foo {foo test-28.4} 0 1 leave}
2233
2234test trace-28.6 {exec traces firing order} {
2235    set info {}
2236    proc enterStep {cmd op} {lappend ::info "enter $cmd/$op"}
2237    proc leaveStep {cmd code result op} {lappend ::info "leave $cmd/$code/$result/$op"}
2238
2239    proc foo x {
2240        set b x=$x
2241        incr x
2242    }
2243    trace add execution foo enterstep enterStep
2244    trace add execution foo leavestep leaveStep
2245    foo 42
2246    rename foo {}
2247    join $info \n
2248} {enter set b x=42/enterstep
2249leave set b x=42/0/x=42/leavestep
2250enter incr x/enterstep
2251leave incr x/0/43/leavestep}
2252
2253test trace-28.7 {exec trace information} {
2254    set info {}
2255    proc foo x { incr x }
2256    proc bar {args} {}
2257    trace add execution foo {enter leave enterstep leavestep} bar
2258    set info [trace info execution foo]
2259    trace remove execution foo {enter leave enterstep leavestep} bar
2260} {}
2261
2262test trace-28.8 {exec trace remove nonsense} {
2263    list [catch {trace remove execution thisdoesntexist \
2264      {enter leave enterstep leavestep} bar} res] $res
2265} {1 {unknown command "thisdoesntexist"}}
2266
2267test trace-28.9 {exec trace info nonsense} {
2268    list [catch {trace info execution thisdoesntexist} res] $res
2269} {1 {unknown command "thisdoesntexist"}}
2270
2271test trace-28.10 {exec trace info nonsense} {
2272    list [catch {trace remove execution} res] $res
2273} {1 {wrong # args: should be "trace remove execution name opList command"}}
2274
2275test trace-29.1 {Tcl_CreateTrace, correct command and argc/argv arguments of trace proc} {testcmdtrace} {
2276    testcmdtrace tracetest {set stuff [expr 14 + 16]}
2277} {{expr 14 + 16} {expr 14 + 16} {set stuff [expr 14 + 16]} {set stuff 30}}
2278test trace-29.2 {Tcl_CreateTrace, correct command and argc/argv arguments of trace proc} {testcmdtrace} {
2279    testcmdtrace tracetest {set stuff [info tclversion]}
2280} [concat {{info tclversion} {info tclversion} ::tcl::info::tclversion {::tcl::info::tclversion} {set stuff [info tclversion]}} [list "set stuff [info tclversion]"]]
2281test trace-29.3 {Tcl_CreateTrace, correct command and argc/argv arguments of trace proc} {testcmdtrace} {
2282    testcmdtrace deletetest {set stuff [info tclversion]}
2283} [info tclversion]
2284test trace-29.4 {Tcl_CreateTrace, check that tracing doesn't cause memory faults} {testcmdtrace} {
2285    # Note that the proc call is the same as the variable name, and that
2286    # the call can be direct or indirect by way of another procedure
2287    proc tracer {args} {}
2288    proc tracedLoop {level} {
2289        incr level
2290        tracer
2291        foreach tracer [expr {$level==1 ? {1 2} : {}}] {tracedLoop $level}
2292    }
2293    testcmdtrace tracetest {tracedLoop 0}
2294} {{tracedLoop 0} {tracedLoop 0} {incr level} {incr level} tracer {tracer} {expr {$level==1 ? {1 2} : {}}} {expr {$level==1 ? {1 2} : {}}} {foreach tracer [expr {$level==1 ? {1 2} : {}}] {tracedLoop $level}} {foreach tracer {1 2} {tracedLoop $level}} {tracedLoop $level} {tracedLoop 1} {incr level} {incr level} tracer {tracer} {expr {$level==1 ? {1 2} : {}}} {expr {$level==1 ? {1 2} : {}}} {foreach tracer [expr {$level==1 ? {1 2} : {}}] {tracedLoop $level}} {foreach tracer {} {tracedLoop $level}} {tracedLoop $level} {tracedLoop 1} {incr level} {incr level} tracer {tracer} {expr {$level==1 ? {1 2} : {}}} {expr {$level==1 ? {1 2} : {}}} {foreach tracer [expr {$level==1 ? {1 2} : {}}] {tracedLoop $level}} {foreach tracer {} {tracedLoop $level}}}
2295catch {rename tracer {}}
2296catch {rename tracedLoop {}}
2297
2298test trace-29.5 {Tcl_CreateObjTrace, status return TCL_ERROR} {testcmdtrace} {
2299    proc Error { args } { error "Shouldn't get here" }
2300    set x 1;
2301    list [catch {testcmdtrace resulttest {Error $x}} result] [set result]
2302} {1 {Error $x}}
2303
2304test trace-29.6 {Tcl_CreateObjTrace, status return TCL_RETURN} {testcmdtrace} {
2305    proc Return { args } { error "Shouldn't get here" }
2306    set x 1;
2307    list [catch {testcmdtrace resulttest {Return $x}} result] [set result]
2308} {2 {}}
2309
2310test trace-29.7 {Tcl_CreateObjTrace, status return TCL_BREAK} {testcmdtrace} {
2311    proc Break { args } { error "Shouldn't get here" }
2312    set x 1;
2313    list [catch {testcmdtrace resulttest {Break $x}} result] [set result]
2314} {3 {}}
2315
2316test trace-29.8 {Tcl_CreateObjTrace, status return TCL_CONTINUE} {testcmdtrace} {
2317    proc Continue { args } { error "Shouldn't get here" }
2318    set x 1;
2319    list [catch {testcmdtrace resulttest {Continue $x}} result] [set result]
2320} {4 {}}
2321
2322test trace-29.9 {Tcl_CreateObjTrace, status return unknown} {testcmdtrace} {
2323    proc OtherStatus { args } { error "Shouldn't get here" }
2324    set x 1;
2325    list [catch {testcmdtrace resulttest {OtherStatus $x}} result] [set result]
2326} {6 {}}
2327
2328test trace-29.10 {Tcl_CreateTrace, correct level interpretation} {testcmdtrace} {
2329    proc foo {} {uplevel 1 bar}
2330    proc bar {} {uplevel 1 grok}
2331    proc grok {} {uplevel 1 spock}
2332    proc spock {} {uplevel 1 fascinating}
2333    proc fascinating {} {}
2334    testcmdtrace leveltest {foo}
2335} {foo {foo} {uplevel 1 bar} {uplevel 1 bar} bar {bar} {uplevel 1 grok} {uplevel 1 grok}}
2336
2337test trace-29.11 {Tcl_CreateTrace, multiple traces} {testcmdtrace} {
2338    testcmdtrace doubletest {format xx}
2339} {{format xx} {format xx}}
2340
2341test trace-30.1 {Tcl_DeleteTrace} {emptyTest} {
2342    # the above tests have tested Tcl_DeleteTrace
2343} {}
2344
2345test trace-31.1 {command and execution traces shared struct} {
2346    # Tcl Bug 807243
2347    proc foo {} {}
2348    trace add command foo delete foo
2349    trace add execution foo enter foo
2350    set result [trace info command foo]
2351    trace remove command foo delete foo
2352    trace remove execution foo enter foo
2353    rename foo {}
2354    set result
2355} [list [list delete foo]]
2356test trace-31.2 {command and execution traces shared struct} {
2357    # Tcl Bug 807243
2358    proc foo {} {}
2359    trace add command foo delete foo
2360    trace add execution foo enter foo
2361    set result [trace info execution foo]
2362    trace remove command foo delete foo
2363    trace remove execution foo enter foo
2364    rename foo {}
2365    set result
2366} [list [list enter foo]]
2367
2368test trace-32.1 {
2369    TraceCommandInfo refcount decr in TraceCommandProc w/o loss of reference
2370} {
2371    # Tcl Bug 811483
2372    proc foo {} {}
2373    trace add command foo delete foo
2374    trace add execution foo enter foo
2375    set result [trace info command foo]
2376    rename foo {}
2377    set result
2378} [list [list delete foo]]
2379
2380test trace-33.1 {variable match with remove variable} {
2381    unset -nocomplain x
2382    trace variable x w foo
2383    trace remove variable x write foo
2384    llength [trace info variable x]
2385} 0
2386
2387test trace-34.1 {Bug 1201035} {
2388    set ::x [list]
2389    proc foo {} {lappend ::x foo}
2390    proc bar args {
2391        lappend ::x $args
2392        trace remove execution foo leavestep bar
2393        trace remove execution foo enterstep bar
2394        trace add execution foo leavestep bar
2395        trace add execution foo enterstep bar
2396        lappend ::x done
2397    }
2398    trace add execution foo leavestep bar
2399    trace add execution foo enterstep bar
2400    foo
2401    set ::x
2402} {{{lappend ::x foo} enterstep} done foo}
2403
2404test trace-34.2 {Bug 1224585} {
2405    proc foo {} {}
2406    proc bar args {trace remove execution foo leave soom}
2407    trace add execution foo leave bar
2408    trace add execution foo leave soom
2409    foo
2410} {}
2411
2412test trace-34.3 {Bug 1224585} {
2413    proc foo {} {set x {}}
2414    proc bar args {trace remove execution foo enterstep soom}
2415    trace add execution foo enterstep soom
2416    trace add execution foo enterstep bar
2417    foo
2418} {}
2419
2420# We test here for the half-documented and currently valid interplay between
2421# delete traces and namespace deletion.
2422test trace-34.4 {Bug 1047286} {
2423    variable x notrace
2424    proc callback {old - -} {
2425        variable x "$old exists: [namespace which -command $old]"
2426    }
2427    namespace eval ::foo {proc bar {} {}}
2428    trace add command ::foo::bar delete [namespace code callback]
2429    namespace delete ::foo
2430    set x
2431} {::foo::bar exists: ::foo::bar}
2432
2433test trace-34.5 {Bug 1047286} {
2434    variable x notrace
2435    proc callback {old - -} {
2436        variable x "$old exists: [namespace which -command $old]"
2437    }
2438    namespace eval ::foo {proc bar {} {}}
2439    trace add command ::foo::bar delete [namespace code callback]
2440    namespace eval ::foo namespace delete ::foo
2441    set x
2442} {::foo::bar exists: }
2443
2444test trace-34.6 {Bug 1458266} -setup {
2445    proc dummy {} {}
2446    proc stepTraceHandler {cmdString args} {
2447        variable log
2448        append log "[expr {[info level] - 1}]: [lindex [split $cmdString] 0]\n"
2449        dummy
2450        isTracedInside_2
2451    }
2452    proc cmdTraceHandler {cmdString args} {
2453        # silent
2454    }
2455    proc isTracedInside_1 {} {
2456        isTracedInside_2
2457    }
2458    proc isTracedInside_2 {} {
2459        set x 2
2460    }
2461} -body {
2462    variable log {}
2463    trace add execution isTracedInside_1 enterstep stepTraceHandler
2464    trace add execution isTracedInside_2 enterstep stepTraceHandler
2465    isTracedInside_1
2466    variable first $log
2467    set log {}
2468    trace add execution dummy enter cmdTraceHandler
2469    isTracedInside_1
2470    variable second $log
2471    expr {($first eq $second) ? "ok" : "\n$first\nand\n\n$second\ndiffer"}
2472} -cleanup {
2473    unset -nocomplain log first second
2474    rename dummy {}
2475    rename stepTraceHandler {}
2476    rename cmdTraceHandler {}
2477    rename isTracedInside_1 {}
2478    rename isTracedInside_2 {}
2479} -result ok
2480
2481test trace-35.1 {527164: Keep -errorinfo of traces} -setup {
2482    unset -nocomplain x y
2483} -body {
2484    trace add variable x write {error foo;#}
2485    trace add variable y write {set x 2;#}
2486    list [catch {set y 1} msg opts] $msg [dict get $opts -errorinfo]
2487} -cleanup {
2488    unset -nocomplain x y
2489} -result {1 {can't set "y": can't set "x": foo} {foo
2490    while executing
2491"error foo"
2492    (write trace on "x")
2493    invoked from within
2494"set x 2"
2495    (write trace on "y")
2496    invoked from within
2497"set y 1"}}
2498
2499
2500#
2501# Test for the correct(?) dynamics of execution traces. This test insures that
2502# the dynamics of the original implementation remain valid; note that
2503# these aspects are neither documented nor do they appear in TIP 62
2504
2505proc traceproc {tracevar args} {
2506    append ::$tracevar *
2507}
2508proc untraced {type} {
2509    trace add execution untraced $type {traceproc tracevar}
2510    append ::tracevar -
2511}
2512proc runbase {results base} {
2513    set tt {enter leave enterstep leavestep}
2514    foreach n {1 2 3 4} t $tt r $results {
2515        eval [subst $base]
2516    }
2517}
2518set base {
2519    test trace-36.$n {dynamic trace creation: $t} -setup {
2520        set ::tracevar {}
2521    } -cleanup {
2522        unset ::tracevar
2523        trace remove execution untraced $t {traceproc tracevar}
2524    } -body {
2525        untraced $t
2526        set ::tracevar
2527    } -result {$r}
2528}
2529runbase {- - - -} $base
2530
2531set base {
2532    test trace-37.$n {dynamic trace addition: $t} -setup {
2533        set ::tracevar {}
2534        set ::tracevar2 {}
2535        trace add execution untraced enter {traceproc tracevar2}
2536    } -cleanup {
2537        trace remove execution untraced $t {traceproc tracevar}
2538        trace remove execution untraced enter {traceproc tracevar2}
2539        unset ::tracevar ::tracevar2
2540    } -body {
2541        untraced $t
2542        list \$::tracevar \$::tracevar2
2543    } -result {$r}
2544}
2545runbase {{- *} {-* *} {- *} {- *}} $base
2546
2547set base {
2548    test trace-38.$n {dynamic trace addition: $t} -setup {
2549        set ::tracevar {}
2550        set ::tracevar2 {}
2551        trace add execution untraced leave {traceproc tracevar2}
2552    } -cleanup {
2553        trace remove execution untraced $t {traceproc tracevar}
2554        trace remove execution untraced leave {traceproc tracevar2}
2555        unset ::tracevar ::tracevar2
2556    } -body {
2557        untraced $t
2558        list \$::tracevar \$::tracevar2
2559    } -result {$r}
2560}
2561runbase {{- *} {-* *} {- *} {- *}} $base
2562
2563
2564
2565# Delete procedures when done, so we don't clash with other tests
2566# (e.g. foobar will clash with 'unknown' tests).
2567catch {rename foobar {}}
2568catch {rename foo {}}
2569catch {rename bar {}}
2570catch {rename untraced {}}
2571catch {rename traceproc {}}
2572catch {rename runbase {}}
2573
2574# Unset the variable when done
2575catch {unset info}
2576catch {unset base}
2577
2578# cleanup
2579::tcltest::cleanupTests
2580return
Note: See TracBrowser for help on using the repository browser.