dict: Fix [dict values] with duplicate values
[jimtcl.git] / tests / dict2.test
blob54d4d0dc4c60932c220abe0cf90498f265ce851c
1 # This test file covers the dictionary object type and the dict command used
2 # to work with values of that type.
4 # This file contains a collection of tests for one or more of the Tcl built-in
5 # commands. Sourcing this file into Tcl runs the tests and generates output
6 # for errors.  No output means no errors were found.
8 # Copyright (c) 2003-2009 Donal K. Fellows
9 # See the file "license.terms" for information on usage and redistribution of
10 # this file, and for a DISCLAIMER OF ALL WARRANTIES.
12 source [file dirname [info script]]/testing.tcl
14 # jim dicts don't preserve order, so always sort
15 # before checking results
16 proc dict-sort {dict} {
17     set result {}
18     foreach k [lsort [dict keys $dict]] {
19         lappend result $k [dict get $dict $k]
20     }
21     return $result
24 test dict-1.1 {dict command basic syntax} -returnCodes error -body {
25     dict
26 }  -match glob -result {wrong # args: should be "dict subcommand ?arg* ...?"}
27 test dict-1.2 {dict command basic syntax} -returnCodes error -body {
28     dict ?
29 } -match glob -result *
31 test dict-2.1 {dict create command} {
32     dict create
33 } {}
34 test dict-2.2 {dict create command} {
35     dict create a b
36 } {a b}
37 test dict-2.3 {dict create command} -body {
38     set result {}
39     set dict [dict create a b c d]
40     # Can't compare directly as ordering of values is undefined
41     foreach key {a c} {
42         set idx [lsearch -exact $dict $key]
43         if {$idx & 1} {
44             error "found $key at odd index $idx in $dict"
45         }
46         lappend result [lindex $dict [expr {$idx+1}]]
47     }
48     return $result
49 } -cleanup {
50     unset result dict key idx
51 } -result {b d}
52 test dict-2.4 {dict create command} -returnCodes error -body {
53     dict create a
54 } -result {wrong # args: should be "dict create ?key value ...?"}
55 test dict-2.5 {dict create command} -returnCodes error -body {
56     dict create a b c
57 } -result {wrong # args: should be "dict create ?key value ...?"}
58 test dict-2.6 {dict create command - initialse refcount field!} -body {
59     # Bug 715751 will show up in memory debuggers like purify
60     for {set i 0} {$i<10} {incr i} {
61         set dictv [dict create a 0]
62         if {[catch {
63             set share [dict values $dictv]
64         }]} {
65             set share [array get dictv]
66         }
67         list [dict incr dictv a]
68     }
69 } -cleanup {
70     unset i dictv share
71 } -result {}
72 test dict-2.7 {dict create command - #-quoting in string rep} {
73     dict create # #comment
74 } {{#} #comment}
75 test dict-2.8 {dict create command - #-quoting in string rep} -body {
76     dict create #a x #b x
77 } -match glob -result {{#?} x #? x}
79 test dict-3.1 {dict get command} {dict get {a b} a} b
80 test dict-3.2 {dict get command} {dict get {a b c d} a} b
81 test dict-3.3 {dict get command} {dict get {a b c d} c} d
82 test dict-3.4 {dict get command} -returnCodes error -body {
83     dict get {a b c d} b
84 } -result {key "b" not known in dictionary}
85 test dict-3.5 {dict get command} {dict get {a {p q r s} b {u v x y}} a p} q
86 test dict-3.6 {dict get command} {dict get {a {p q r s} b {u v x y}} a r} s
87 test dict-3.7 {dict get command} {dict get {a {p q r s} b {u v x y}} b u} v
88 test dict-3.8 {dict get command} {dict get {a {p q r s} b {u v x y}} b x} y
89 test dict-3.9 {dict get command} -returnCodes error -body {
90     dict get {a {p q r s} b {u v x y}} a z
91 } -result {key "z" not known in dictionary}
92 test dict-3.10 {dict get command} -returnCodes error -body {
93     dict get {a {p q r s} b {u v x y}} c z
94 } -result {key "c" not known in dictionary}
95 test dict-3.11 {dict get command} {dict get [dict create a b c d] a} b
96 test dict-3.12 {dict get command} -returnCodes error -body {
97     dict get
98 } -result {wrong # args: should be "dict get dictionary ?key ...?"}
99 test dict-3.13 {dict get command} -body {
100     set dict [dict get {a b c d}]
101     if {$dict eq "a b c d"} {
102         return OK
103     } elseif {$dict eq "c d a b"} {
104         return reordered
105     } else {
106         return $dict
107     }
108 } -cleanup {
109     unset dict
110 } -result OK
111 test dict-3.14 {dict get command} -returnCodes error -body {
112     dict get {a b c d} a c
113 } -result {missing value to go with key}
114 test dict-3.15 {compiled dict get error cleanliness - Bug 2431847} -body {
115     proc x {} {
116         dict set a(z) b c
117         dict get $a(z) d
118     }
119     x
120 } -returnCodes error -result {key "d" not known in dictionary}
121 test dict-3.16 {dict/list shimmering - Bug 3004007} {set l [list p 1 p 2 q 3];dict get $l q;set l} {p 1 p 2 q 3}
122 test dict-3.17 {dict/list shimmering - Bug 3004007} {set l [list p 1 p 2 q 3];dict get $l q;llength $l} 6
123 test dict-3.18 {array set non-dict get command} -constraints jim -returnCodes error -body {
124     set a one
125     array set a {a b c d}
126 } -result {missing value to go with key}
128 test dict-4.1 {dict replace command} {
129     dict-sort [dict replace {a b c d}]
130 } {a b c d}
131 test dict-4.2 {dict replace command} {
132     dict-sort [dict replace {a b c d} e f]
133 } {a b c d e f}
134 test dict-4.3 {dict replace command} {
135     dict-sort [dict replace {a b c d} c f]
136 } {a b c f}
137 test dict-4.4 {dict replace command} {
138     dict-sort [dict replace {a b c d} c x a y]
139 } {a y c x}
140 test dict-4.5 {dict replace command} -returnCodes error -body {
141     dict replace
142 } -result {wrong # args: should be "dict replace dictionary ?key value ...?"}
143 test dict-4.6 {dict replace command} -returnCodes error -body {
144     dict replace {a a} a
145 } -result {wrong # args: should be "dict replace dictionary ?key value ...?"}
146 test dict-4.7 {dict replace command} -returnCodes error -body {
147     dict replace {a a a} a b
148 } -result {missing value to go with key}
149 test dict-4.8 {dict replace command} -returnCodes error -body {
150     dict replace [list a a a] a b
151 } -result {missing value to go with key}
152 test dict-4.9 {dict replace command} {dict replace [list a a] a b} {a b}
153 test dict-4.10 {dict replace command} {dict replace [list a a] a b a c} {a c}
155 test dict-5.1 {dict remove command} {dict remove {a b c d} a} {c d}
156 test dict-5.2 {dict remove command} {dict remove {a b c d} c} {a b}
157 test dict-5.3 {dict remove command} {dict remove {a b c d} a c} {}
158 test dict-5.4 {dict remove command} {dict remove {a b c d} c a} {}
159 test dict-5.5 {dict remove command} {
160     dict remove {a b c d}
161 } {a b c d}
162 test dict-5.6 {dict remove command} {dict remove {a b} c} {a b}
163 test dict-5.7 {dict remove command} -returnCodes error -body {
164     dict remove
165 } -result {wrong # args: should be "dict remove dictionary ?key ...?"}
167 test dict-6.1 {dict keys command} {dict keys {a b}} a
168 test dict-6.2 {dict keys command} {dict keys {c d}} c
169 test dict-6.3 {dict keys command} {lsort [dict keys {a b c d}]} {a c}
170 test dict-6.4 {dict keys command} {dict keys {a b c d} a} a
171 test dict-6.5 {dict keys command} {dict keys {a b c d} c} c
172 test dict-6.6 {dict keys command} {dict keys {a b c d} e} {}
173 test dict-6.7 {dict keys command} {lsort [dict keys {a b c d ca da} c*]} {c ca}
174 test dict-6.8 {dict keys command} -returnCodes error -body {
175     dict keys
176 } -result {wrong # args: should be "dict keys dictionary ?pattern?"}
177 test dict-6.9 {dict keys command} -returnCodes error -body {
178     dict keys {} a b
179 } -result {wrong # args: should be "dict keys dictionary ?pattern?"}
180 test dict-6.10 {dict keys command} -returnCodes error -body {
181     dict keys a
182 } -result {missing value to go with key}
184 test dict-7.1 {dict values command} {dict values {a b}} b
185 test dict-7.2 {dict values command} {dict values {c d}} d
186 test dict-7.3 {dict values command} {lsort [dict values {a b c d}]} {b d}
187 test dict-7.4 {dict values command} {dict values {a b c d} b} b
188 test dict-7.5 {dict values command} {dict values {a b c d} d} d
189 test dict-7.6 {dict values command} {dict values {a b c d} e} {}
190 test dict-7.7 {dict values command} {lsort [dict values {a b c d ca da} d*]} {d da}
191 test dict-7.8 {dict values command} -returnCodes error -body {
192     dict values
193 } -result {wrong # args: should be "dict values dictionary ?pattern?"}
194 test dict-7.9 {dict values command} -returnCodes error -body {
195     dict values {} a b
196 } -result {wrong # args: should be "dict values dictionary ?pattern?"}
197 test dict-7.10 {dict values command} -returnCodes error -body {
198     dict values a
199 } -result {missing value to go with key}
200 test dict-7.11 {dict values with duplicate values} {dict values {a b c b} b} {b b}
202 test dict-8.1 {dict size command} {dict size {}} 0
203 test dict-8.2 {dict size command} {dict size {a b}} 1
204 test dict-8.3 {dict size command} {dict size {a b c d}} 2
205 test dict-8.4 {dict size command} -returnCodes error -body {
206     dict size
207 } -result {wrong # args: should be "dict size dictionary"}
208 test dict-8.5 {dict size command} -returnCodes error -body {
209     dict size a b
210 } -result {wrong # args: should be "dict size dictionary"}
211 test dict-8.6 {dict size command} -returnCodes error -body {
212     dict size a
213 } -result {missing value to go with key}
215 test dict-9.1 {dict exists command} {dict exists {a b} a} 1
216 test dict-9.2 {dict exists command} {dict exists {a b} b} 0
217 test dict-9.3 {dict exists command} {dict exists {a {b c}} a b} 1
218 test dict-9.4 {dict exists command} {dict exists {a {b c}} a c} 0
219 test dict-9.5 {dict exists command} {dict exists {a {b c}} b c} 0
220 test dict-9.6 {dict exists command} -returnCodes error -body {
221     dict exists {a {b c d}} a c
222 } -result {missing value to go with key}
223 test dict-9.7 {dict exists command} -returnCodes error -body {
224     dict exists
225 } -result {wrong # args: should be "dict exists dictionary key ?key ...?"}
226 test dict-9.8 {dict exists command} -returnCodes error -body {
227     dict exists {}
228 } -result {wrong # args: should be "dict exists dictionary key ?key ...?"}
230 #test dict-10.1 {dict info command} -body {
231 #    # Actual string returned by this command is undefined; it is
232 #    # intended for human consumption and not for use by scripts.
233 #    dict info {}
234 #} -match glob -result *
235 #test dict-10.2 {dict info command} -returnCodes error -body {
236 #    dict info
237 #} -result {wrong # args: should be "dict info dictionary"}
238 #test dict-10.3 {dict info command} -returnCodes error -body {
239 #    dict info {} x
240 #} -result {wrong # args: should be "dict info dictionary"}
241 #test dict-10.4 {dict info command} -returnCodes error -body {
242 #    dict info x
243 #} -result {missing value to go with key}
245 test dict-11.1 {dict incr command: unshared value} -body {
246     set dictv [dict create \
247             a [string index "=0=" 1] \
248             b [expr {1+2}] \
249             c [expr {0x80000000+1}]]
250     dict incr dictv a
251         dict-sort $dictv
252 } -cleanup {
253     unset dictv
254 } -result {a 1 b 3 c 2147483649}
255 test dict-11.2 {dict incr command: unshared value} -body {
256     set dictv [dict create \
257             a [string index "=0=" 1] \
258             b [expr {1+2}] \
259             c [expr {0x80000000+1}]]
260     dict incr dictv b
261         dict-sort $dictv
262 } -cleanup {
263     unset dictv
264 } -result {a 0 b 4 c 2147483649}
265 test dict-11.3 {dict incr command: unshared value} -body {
266     set dictv [dict create \
267             a [string index "=0=" 1] \
268             b [expr {1+2}] \
269             c [expr {0x80000000+1}]]
270     dict incr dictv c
271         dict-sort $dictv
272 } -cleanup {
273     unset dictv
274 } -result {a 0 b 3 c 2147483650}
275 test dict-11.4 {dict incr command: shared value} -body {
276     set dictv [dict create a 0 b [expr {1+2}] c [expr {0x80000000+1}]]
277     set sharing [dict values $dictv]
278     dict incr dictv a
279         dict-sort $dictv
280 } -cleanup {
281     unset dictv sharing
282 } -result {a 1 b 3 c 2147483649}
283 test dict-11.5 {dict incr command: shared value} -body {
284     set dictv [dict create a 0 b [expr {1+2}] c [expr {0x80000000+1}]]
285     set sharing [dict values $dictv]
286     dict incr dictv b
287         dict-sort $dictv
288 } -cleanup {
289     unset dictv sharing
290 } -result {a 0 b 4 c 2147483649}
291 test dict-11.6 {dict incr command: shared value} -body {
292     set dictv [dict create a 0 b [expr {1+2}] c [expr {0x80000000+1}]]
293     set sharing [dict values $dictv]
294     dict incr dictv c
295         dict-sort $dictv
296 } -cleanup {
297     unset dictv sharing
298 } -result {a 0 b 3 c 2147483650}
299 test dict-11.7 {dict incr command: unknown values} -body {
300     set dictv [dict create a 0 b [expr {1+2}] c [expr {0x80000000+1}]]
301     dict incr dictv d
302         dict-sort $dictv
303 } -cleanup {
304     unset dictv
305 } -result {a 0 b 3 c 2147483649 d 1}
306 test dict-11.8 {dict incr command} -body {
307     set dictv {a 1}
308     dict incr dictv a 2
309         dict-sort $dictv
310 } -cleanup {
311     unset dictv
312 } -result {a 3}
313 test dict-11.9 {dict incr command} -returnCodes error -body {
314     set dictv {a dummy}
315     dict incr dictv a
316         dict-sort $dictv
317 } -cleanup {
318     unset dictv
319 } -result {expected integer but got "dummy"}
320 test dict-11.10 {dict incr command} -returnCodes error -body {
321     set dictv {a 1}
322     dict incr dictv a dummy
323         dict-sort $dictv
324 } -cleanup {
325     unset dictv
326 } -result {expected integer but got "dummy"}
327 test dict-11.11 {dict incr command} -setup {
328     unset -nocomplain dictv
329 } -body {
330     dict incr dictv a
331         dict-sort $dictv
332 } -cleanup {
333     unset dictv
334 } -result {a 1}
335 test dict-11.12 {dict incr command} -returnCodes error -body {
336     set dictv a
337     dict incr dictv a
338         dict-sort $dictv
339 } -cleanup {
340     unset dictv
341 } -result {missing value to go with key}
342 test dict-11.13 {dict incr command} -returnCodes error -body {
343     set dictv a
344     dict incr dictv a a a
345         dict-sort $dictv
346 } -cleanup {
347     unset dictv
348 } -result {wrong # args: should be "dict incr varName key ?increment?"}
349 test dict-11.14 {dict incr command} -returnCodes error -body {
350     set dictv a
351     dict incr dictv
352         dict-sort $dictv
353 } -cleanup {
354     unset dictv
355 } -result {wrong # args: should be "dict incr varName key ?increment?"}
356 test dict-11.15 {dict incr command: write failure} -setup {
357     unset -nocomplain dictVar
358 } -body {
359     set dictVar 1
360     dict incr dictVar a
361         dict-sort $dictv
362 } -returnCodes error -cleanup {
363     unset dictVar
364 } -result {missing value to go with key}
365 test dict-11.16 {dict incr command: compilation} {
366     apply {{} {
367         set v {a 0 b 0 c 0}
368         dict incr v a
369         dict incr v b 1
370         dict incr v c 2
371         dict incr v d 3
372         list [dict get $v a] [dict get $v b] [dict get $v c] [dict get $v d]
373     }}
374 } {1 1 2 3}
375 test dict-11.17 {dict incr command: compilation} {
376     apply {{} {
377         set dictv {a 1}
378         dict incr dictv a 2
379         dict-sort $dictv
380     }}
381 } {a 3}
383 test dict-12.1 {dict lappend command} -body {
384     set dictv {a a}
385     dict lappend dictv a
386 } -cleanup {
387     unset dictv
388 } -result {a a}
389 test dict-12.2 {dict lappend command} -body {
390     set dictv {a a}
391     set sharing [dict values $dictv]
392     dict lappend dictv a b
393         dict-sort $dictv
394 } -cleanup {
395     unset dictv sharing
396 } -result {a {a b}}
397 test dict-12.3 {dict lappend command} -body {
398     set dictv {a a}
399     dict lappend dictv a b c
400         dict-sort $dictv
401 } -cleanup {
402     unset dictv
403 } -result {a {a b c}}
404 test dict-12.2.1 {dict lappend command} -body {
405     set dictv [dict create a [string index =a= 1]]
406     dict lappend dictv a b
407         dict-sort $dictv
408 } -cleanup {
409     unset dictv
410 } -result {a {a b}}
411 test dict-12.4 {dict lappend command} -body {
412     set dictv {}
413     dict lappend dictv a x y z
414         dict-sort $dictv
415 } -cleanup {
416     unset dictv
417 } -result {a {x y z}}
418 test dict-12.5 {dict lappend command} -body {
419     unset -nocomplain dictv
420     dict lappend dictv a b
421         dict-sort $dictv
422 } -cleanup {
423     unset dictv
424 } -result {a b}
425 test dict-12.6 {dict lappend command} -returnCodes error -body {
426     set dictv a
427     dict lappend dictv a a
428         dict-sort $dictv
429 } -cleanup {
430     unset dictv
431 } -result {missing value to go with key}
432 test dict-12.7 {dict lappend command} -returnCodes error -body {
433     dict lappend
434 } -result {wrong # args: should be "dict lappend varName key ?value ...?"}
435 test dict-12.8 {dict lappend command} -returnCodes error -body {
436     dict lappend dictv
437 } -result {wrong # args: should be "dict lappend varName key ?value ...?"}
438 test dict-12.9 {dict lappend command} -returnCodes error -constraints tcl -body {
439     set dictv [dict create a "\{"]
440     dict lappend dictv a a
441 } -cleanup {
442     unset dictv
443 } -result {unmatched open brace in list}
444 test dict-12.10 {dict lappend command: write failure} -setup {
445     unset -nocomplain dictVar
446 } -body {
447     set dictVar 1
448     dict lappend dictVar a x
449 } -returnCodes error -cleanup {
450     unset dictVar
451 } -result {missing value to go with key}
452 test dict-12.11 {compiled dict append: invalidate string rep - Bug 3079830} {
453     dict-sort [apply {{} {set d {a 1 b 2 c 3}; dict lappend d b 22}}]
454 } {a 1 b {2 22} c 3}
456 test dict-13.1 {dict append command} -body {
457     set dictv {a a}
458     dict append dictv a
459 } -cleanup {
460     unset dictv
461 } -result {a a}
462 test dict-13.2 {dict append command} -body {
463     set dictv {a a}
464     set sharing [dict values $dictv]
465     dict append dictv a b
466 } -cleanup {
467     unset dictv sharing
468 } -result {a ab}
469 test dict-13.3 {dict append command} -body {
470     set dictv {a a}
471     dict append dictv a b c
472 } -cleanup {
473     unset dictv
474 } -result {a abc}
475 test dict-13.2.1 {dict append command} -body {
476     set dictv [dict create a [string index =a= 1]]
477     dict append dictv a b
478 } -cleanup {
479     unset dictv
480 } -result {a ab}
481 test dict-13.4 {dict append command} -body {
482     set dictv {}
483     dict append dictv a x y z
484 } -cleanup {
485     unset dictv
486 } -result {a xyz}
487 test dict-13.5 {dict append command} -body {
488     unset -nocomplain dictv
489     dict append dictv a b
490 } -cleanup {
491     unset dictv
492 } -result {a b}
493 test dict-13.6 {dict append command} -returnCodes error -body {
494     set dictv a
495     dict append dictv a a
496 } -cleanup {
497     unset dictv
498 } -result {missing value to go with key}
499 test dict-13.7 {dict append command} -returnCodes error -body {
500     dict append
501 } -result {wrong # args: should be "dict append varName key ?value ...?"}
502 test dict-13.8 {dict append command} -returnCodes error -body {
503     dict append dictv
504 } -result {wrong # args: should be "dict append varName key ?value ...?"}
505 test dict-13.9 {dict append command: write failure} -setup {
506     unset -nocomplain dictVar
507 } -body {
508     set dictVar 1
509     dict append dictVar a x
510 } -returnCodes error -cleanup {
511     unset dictVar
512 } -result {missing value to go with key}
513 test dict-13.10 {compiled dict append: crash case} {
514     apply {{} {dict append dictVar a o k}}
515 } {a ok}
516 test dict-13.11 {compiled dict append: invalidate string rep - Bug 3079830} {
517     dict-sort [apply {{} {set d {a 1 b 2 c 3}; dict append d b 22}}]
518 } {a 1 b 222 c 3}
520 test dict-14.1 {dict for command: syntax} -returnCodes error -body {
521     dict for
522 } -match glob -result {wrong # args: should be *}
523 test dict-14.2 {dict for command: syntax} -returnCodes error -body {
524     dict for x
525 } -match glob -result {wrong # args: should be *}
526 test dict-14.3 {dict for command: syntax} -returnCodes error -body {
527     dict for x x
528 } -match glob -result {wrong # args: should be *}
529 test dict-14.4 {dict for command: syntax} -returnCodes error -body {
530     dict for x x x x
531 } -match glob -result {wrong # args: should be *}
532 test dict-14.5 {dict for command: syntax} -returnCodes error -body {
533     dict for x x x
534 } -result {must have exactly two variable names}
535 test dict-14.6 {dict for command: syntax} -returnCodes error -body {
536     dict for {x x x} x x
537 } -result {must have exactly two variable names}
538 test dict-14.7 {dict for command: syntax} -returnCodes error -constraints tcl -body {
539     dict for "\{x" x x
540 } -result {unmatched open brace in list}
541 test dict-14.8 {dict for command} -constraints tcl -body {
542     # This test confirms that [dict keys], [dict values] and [dict for]
543     # all traverse a dictionary in the same order.
544         # Note that Jim Tcl does *not* preserver order
545     set dictv {a A b B c C}
546     set keys {}
547     set values {}
548     dict for {k v} $dictv {
549         lappend keys $k
550         lappend values $v
551     }
552     set result [expr {
553         $keys eq [dict keys $dictv] && $values eq [dict values $dictv]
554     }]
555     expr {$result ? "YES" : [list "NO" $dictv $keys $values]}
556 } -cleanup {
557     unset result keys values k v dictv
558 } -result YES
559 test dict-14.9 {dict for command} {
560     dict for {k v} {} {
561         error "unexpected execution of 'dict for' body"
562     }
563 } {}
564 test dict-14.10 {dict for command: script results} -body {
565     set times 0
566     dict for {k v} {a a b b} {
567         incr times
568         continue
569         error "shouldn't get here"
570     }
571     return $times
572 } -cleanup {
573     unset times k v
574 } -result 2
575 test dict-14.11 {dict for command: script results} -body {
576     set times 0
577     dict for {k v} {a a b b} {
578         incr times
579         break
580         error "shouldn't get here"
581     }
582     return $times
583 } -cleanup {
584     unset times k v
585 } -result 1
586 test dict-14.12 {dict for command: script results} -body {
587     set times 0
588     list [catch {
589         dict for {k v} {a a b b} {
590             incr times
591             error test
592         }
593     } msg] $msg $times
594 } -cleanup {
595     unset times k v msg
596 } -result {1 test 1}
597 test dict-14.13 {dict for command: script results} {
598     apply {{} {
599         dict for {k v} {a b} {
600             return ok,$k,$v
601             error "skipped return completely"
602         }
603         error "return didn't go far enough"
604     }}
605 } ok,a,b
606 test dict-14.14 {dict for command: handle representation loss} -body {
607     set dictVar {a b c d e f g h}
608     set keys {}
609     set values {}
610     dict for {k v} $dictVar {
611         if {[llength $dictVar]} {
612             lappend keys $k
613             lappend values $v
614         }
615     }
616     list [lsort $keys] [lsort $values]
617 } -cleanup {
618     unset dictVar keys values k v
619 } -result {{a c e g} {b d f h}}
620 test dict-14.15 {dict for command: keys are unique and iterated over once only} -setup {
621     unset -nocomplain accum
622     array set accum {}
623 } -body {
624     set dictVar {a1 a a2 b b1 c b2 d foo bar bar foo}
625     dict for {k v} $dictVar {
626         append accum($k) $v,
627     }
628     set result [lsort [array names accum]]
629     lappend result :
630     foreach k $result {
631         catch {lappend result $accum($k)}
632     }
633     return $result
634 } -cleanup {
635     unset dictVar k v result accum
636 } -result {a1 a2 b1 b2 bar foo : a, b, c, d, foo, bar,}
637 test dict-14.16 {dict for command in compilation context} {
638     apply {{} {
639         set res {x x x x x x}
640         dict for {k v} {a 0 b 1 c 2 d 3 e 4 f 5} {
641             lset res $v $k
642             continue
643         }
644         return $res
645     }}
646 } {a b c d e f}
647 test dict-14.17 {dict for command in compilation context} {
648     # Bug 1379349
649     apply {{} {
650         set d [dict create a 1]         ;# Dict must be unshared!
651         dict for {k v} $d {
652             dict set d $k 0             ;# Any modification will do
653         }
654         return $d
655     }}
656 } {a 0}
657 test dict-14.18 {dict for command in compilation context} {
658     # Bug 1382528
659     apply {{} {
660         dict for {k v} {} {}            ;# Note empty dict
661         catch { error foo }             ;# Note compiled [catch]
662     }}
663 } 1
664 test dict-14.19 {dict for and invalid dicts: bug 1531184} -body {
665     di[list]ct for {k v} x {}
666 } -returnCodes 1 -result {missing value to go with key}
667 test dict-14.20 {dict for stack space compilation: bug 1903325} {
668     apply {{x y args} {
669         dict for {a b} $x {}
670         concat "c=$y,$args"
671     }} {} 1 2 3
672 } {c=1,2 3}
673 # There's probably a lot more tests to add here. Really ought to use a
674 # coverage tool for this job...
676 test dict-15.1 {dict set command} -body {
677     set dictVar {}
678     dict set dictVar a x
679 } -cleanup {
680     unset dictVar
681 } -result {a x}
682 test dict-15.2 {dict set command} -body {
683     set dictvar {a {}}
684     dict set dictvar a b x
685 } -cleanup {
686     unset dictvar
687 } -result {a {b x}}
688 test dict-15.3 {dict set command} -body {
689     set dictvar {a {b {}}}
690     dict set dictvar a b c x
691 } -cleanup {
692     unset dictvar
693 } -result {a {b {c x}}}
694 test dict-15.4 {dict set command} -body {
695     set dictVar {a y}
696     dict set dictVar a x
697 } -cleanup {
698     unset dictVar
699 } -result {a x}
700 test dict-15.5 {dict set command} -body {
701     set dictVar {a {b y}}
702     dict set dictVar a b x
703 } -cleanup {
704     unset dictVar
705 } -result {a {b x}}
706 test dict-15.6 {dict set command} -body {
707     set dictVar {a {b {c y}}}
708     dict set dictVar a b c x
709 } -cleanup {
710     unset dictVar
711 } -result {a {b {c x}}}
712 test dict-15.7 {dict set command: path creation} -body {
713     set dictVar {}
714     dict set dictVar a b x
715 } -cleanup {
716     unset dictVar
717 } -result {a {b x}}
718 test dict-15.8 {dict set command: creates variables} -setup {
719     unset -nocomplain dictVar
720 } -body {
721     dict set dictVar a x
722     return $dictVar
723 } -cleanup {
724     unset dictVar
725 } -result {a x}
726 test dict-15.9 {dict set command: write failure} -setup {
727     unset -nocomplain dictVar
728 } -body {
729     set dictVar 1
730     dict set dictVar a x
731 } -returnCodes error -cleanup {
732     unset dictVar
733 } -result {missing value to go with key}
734 test dict-15.10 {dict set command: syntax} -returnCodes error -body {
735     dict set
736 } -result {wrong # args: should be "dict set varName key ?key ...? value"}
737 test dict-15.11 {dict set command: syntax} -returnCodes error -body {
738     dict set a
739 } -result {wrong # args: should be "dict set varName key ?key ...? value"}
740 test dict-15.12 {dict set command: syntax} -returnCodes error -body {
741     dict set a a
742 } -result {wrong # args: should be "dict set varName key ?key ...? value"}
743 test dict-15.13 {dict set command} -returnCodes error -body {
744     set dictVar a
745     dict set dictVar b c
746 } -cleanup {
747     unset dictVar
748 } -result {missing value to go with key}
750 test dict-16.1 {dict unset command} -body {
751     set dictVar {a b c d}
752     dict unset dictVar a
753 } -cleanup {
754     unset dictVar
755 } -result {c d}
756 test dict-16.2 {dict unset command} -body {
757     set dictVar {a b c d}
758     dict unset dictVar c
759 } -cleanup {
760     unset dictVar
761 } -result {a b}
762 test dict-16.3 {dict unset command} -body {
763     set dictVar {a b}
764     dict unset dictVar c
765 } -cleanup {
766     unset dictVar
767 } -result {a b}
768 test dict-16.4 {dict unset command} -body {
769     set dictVar {a {b c d e}}
770     dict unset dictVar a b
771 } -cleanup {
772     unset dictVar
773 } -result {a {d e}}
774 test dict-16.5 {dict unset command} -returnCodes error -body {
775     set dictVar a
776     dict unset dictVar a
777 } -cleanup {
778     unset dictVar
779 } -result {missing value to go with key}
780 test dict-16.6 {dict unset command} -returnCodes error -body {
781     set dictVar {a b}
782     dict unset dictVar c d
783 } -cleanup {
784     unset dictVar
785 } -result {key "c" not known in dictionary}
786 test dict-16.7 {dict unset command} -setup {
787     unset -nocomplain dictVar
788 } -body {
789     list [info exists dictVar] [dict unset dictVar a] [info exists dictVar]
790 } -cleanup {
791     unset dictVar
792 } -result {0 {} 1}
793 test dict-16.8 {dict unset command} -returnCodes error -body {
794     dict unset dictVar
795 } -result {wrong # args: should be "dict unset varName key ?key ...?"}
796 test dict-16.9 {dict unset command: write failure} -setup {
797     unset -nocomplain dictVar
798 } -body {
799     set dictVar 1
800     dict unset dictVar a
801 } -returnCodes error -cleanup {
802     unset dictVar
803 } -result {missing value to go with key}
805 #test dict-17.1 {dict filter command: key} -body {
806 #    set dictVar {a1 a a2 b b1 c b2 d foo bar bar foo}
807 #    dict filter $dictVar key a2
808 #} -cleanup {
809 #    unset dictVar
810 #} -result {a2 b}
811 #test dict-17.2 {dict filter command: key} -body {
812 #    set dictVar {a1 a a2 b b1 c b2 d foo bar bar foo}
813 #    dict size [dict filter $dictVar key *]
814 #} -cleanup {
815 #    unset dictVar
816 #} -result 6
817 #test dict-17.3 {dict filter command: key} -body {
818 #    set dictVar {a1 a a2 b b1 c b2 d foo bar bar foo}
819 #    dict filter $dictVar key ???
820 #} -cleanup {
821 #    unset dictVar
822 #} -result {foo bar bar foo}
823 #test dict-17.4 {dict filter command: key - no patterns} {
824 #    dict filter {a b c d} key
825 #} {}
826 #test dict-17.4.1 {dict filter command: key - many patterns} {
827 #    dict filter {a1 a a2 b b1 c b2 d foo bar bar foo} key a? b?
828 #} {a1 a a2 b b1 c b2 d}
829 #test dict-17.5 {dict filter command: key - bad dict} -returnCodes error -body {
830 #    dict filter {a b c} key
831 #} -result {missing value to go with key}
832 #test dict-17.6 {dict filter command: value} -body {
833 #    set dictVar {a1 a a2 b b1 c b2 d foo bar bar foo}
834 #    dict filter $dictVar value c
835 #} -cleanup {
836 #    unset dictVar
837 #} -result {b1 c}
838 #test dict-17.7 {dict filter command: value} -body {
839 #    set dictVar {a1 a a2 b b1 c b2 d foo bar bar foo}
840 #    dict size [dict filter $dictVar value *]
841 #} -cleanup {
842 #    unset dictVar
843 #} -result 6
844 #test dict-17.8 {dict filter command: value} -body {
845 #    set dictVar {a1 a a2 b b1 c b2 d foo bar bar foo}
846 #    dict filter $dictVar value ???
847 #} -cleanup {
848 #    unset dictVar
849 #} -result {foo bar bar foo}
850 #test dict-17.9 {dict filter command: value - no patterns} {
851 #    dict filter {a b c d} value
852 #} {}
853 #test dict-17.9.1 {dict filter command: value - many patterns} {
854 #    dict filter {a a1 b a2 c b1 foo bar bar foo d b2} value a? b?
855 #} {a a1 b a2 c b1 d b2}
856 #test dict-17.10 {dict filter command: value - bad dict} -body {
857 #    dict filter {a b c} value a
858 #} -returnCodes error -result {missing value to go with key}
859 #test dict-17.11 {dict filter command: script} -body {
860 #    set dictVar {a1 a a2 b b1 c b2 d foo bar bar foo}
861 #    set n 0
862 #    list [dict filter $dictVar script {k v} {
863 #       incr n
864 #       expr {[string length $k] == [string length $v]}
865 #    }] $n
866 #} -cleanup {
867 #    unset dictVar n k v
868 #} -result {{foo bar bar foo} 6}
869 #test dict-17.12 {dict filter command: script} -returnCodes error -body {
870 #    dict filter {a b} script {k v} {
871 #       concat $k $v
872 #    }
873 #} -cleanup {
874 #    unset k v
875 #} -result {expected boolean value but got "a b"}
876 #test dict-17.13 {dict filter command: script} -body {
877 #    list [catch {dict filter {a b} script {k v} {error x}} msg] $msg \
878 #           $::errorInfo
879 #} -cleanup {
880 #    unset k v msg
881 #} -result {1 x {x
882 #    while executing
883 #"error x"
884 #    ("dict filter" script line 1)
885 #    invoked from within
886 #"dict filter {a b} script {k v} {error x}"}}
887 #test dict-17.14 {dict filter command: script} -setup {
888 #    set n 0
889 #} -body {
890 #    list [dict filter {a b c d} script {k v} {
891 #       incr n
892 #       break
893 #       error boom!
894 #    }] $n
895 #} -cleanup {
896 #    unset n k v
897 #} -result {{} 1}
898 #test dict-17.15 {dict filter command: script} -setup {
899 #    set n 0
900 #} -body {
901 #    list [dict filter {a b c d} script {k v} {
902 #       incr n
903 #       continue
904 #       error boom!
905 #    }] $n
906 #} -cleanup {
907 #    unset n k v
908 #} -result {{} 2}
909 #test dict-17.16 {dict filter command: script} {
910 #    apply {{} {
911 #       dict filter {a b} script {k v} {
912 #           return ok,$k,$v
913 #           error "skipped return completely"
914 #       }
915 #       error "return didn't go far enough"
916 #    }}
917 #} ok,a,b
918 #test dict-17.17 {dict filter command: script} -body {
919 #    dict filter {a b} script {k k} {continue}
920 #    return $k
921 #} -cleanup {
922 #    unset k
923 #} -result b
924 #test dict-17.18 {dict filter command: script} -returnCodes error -body {
925 #    dict filter {a b} script {k k}
926 #} -result {wrong # args: should be "dict filter dictionary script {keyVar valueVar} filterScript"}
927 #test dict-17.19 {dict filter command: script} -returnCodes error -body {
928 #    dict filter {a b} script k {continue}
929 #} -result {must have exactly two variable names}
930 #test dict-17.20 {dict filter command: script} -returnCodes error -body {
931 #    dict filter {a b} script "\{k v" {continue}
932 #} -result {unmatched open brace in list}
933 #test dict-17.21 {dict filter command} -returnCodes error -body {
934 #    dict filter {a b}
935 #} -result {wrong # args: should be "dict filter dictionary filterType ?arg ...?"}
936 #test dict-17.22 {dict filter command} -returnCodes error -body {
937 #    dict filter {a b} JUNK
938 #} -result {bad filterType "JUNK": must be key, script, or value}
939 #test dict-17.23 {dict filter command} -returnCodes error -body {
940 #    dict filter a key *
941 #} -result {missing value to go with key}
943 test dict-18.1 {dict-list relationship} -body {
944     # Test that any internal conversion between list and dict does not change
945     # the object
946     set l [list 1 2 3 4 5 6 7 8 9 0 q w e r t y]
947     dict values $l
948     return $l
949 } -cleanup {
950     unset l
951 } -result {1 2 3 4 5 6 7 8 9 0 q w e r t y}
952 test dict-18.2 {dict-list relationship} -body {
953     # Test that the dictionary is a valid list
954     set d [dict create "abc def" 0 "a\{b" 1 "c\}d" 2]
955     for {set t 0} {$t < 5} {incr t} {
956         llength $d
957         dict lappend d "abc def" "\}\{"
958         dict append  d "a\{b" "\}"
959         dict incr    d "c\}d" 1
960     }
961     llength $d
962 } -cleanup {
963     unset d t
964 } -result 6
965 test dict-18.3 {dict-list relationship} -body {
966     set ld [list a b c d c e f g]
967     list [string length $ld] [dict size $ld] [llength $ld]
968 } -cleanup {
969     unset ld
970 } -result {15 3 8}
971 test dict-18.4 {dict-list relationship} -body {
972     set ld [list a b c d c e f g]
973     list [llength $ld] [dict size $ld] [llength $ld]
974 } -cleanup {
975     unset ld
976 } -result {8 3 8}
978 test dict-20.1 {dict merge command} {
979     dict merge
980 } {}
981 test dict-20.2 {dict merge command} {
982     dict-sort [dict merge {a b c d e f}]
983 } {a b c d e f}
984 test dict-20.3 {dict merge command} -body {
985     dict-sort [dict merge {a b c d e}]
986 } -result {missing value to go with key} -returnCodes error
987 test dict-20.4 {dict merge command} {
988     dict-sort [dict merge {a b c d} {e f g h}]
989 } {a b c d e f g h}
990 test dict-20.5 {dict merge command} -body {
991     dict-sort [dict merge {a b c d e} {e f g h}]
992 } -result {missing value to go with key} -returnCodes error
993 test dict-20.6 {dict merge command} -body {
994     dict-sort [dict merge {a b c d} {e f g h i}]
995 } -result {missing value to go with key} -returnCodes error
996 test dict-20.7 {dict merge command} {
997     dict-sort [dict merge {a b c d e f} {e x g h}]
998 } {a b c d e x g h}
999 test dict-20.8 {dict merge command} {
1000     dict-sort [dict merge {a b c d} {a x c y}]
1001 } {a x c y}
1002 test dict-20.9 {dict merge command} {
1003     dict-sort [dict merge {a b c d} {c y a x}]
1004 } {a x c y}
1005 test dict-20.10 {dict merge command} {
1006     dict-sort [dict merge {a b c d e f} {a x 1 2 3 4} {a - 1 -}]
1007 } {1 - 3 4 a - c d e f}
1009 test dict-21.1 {dict update command} -returnCodes 1 -body {
1010     dict update
1011 } -match glob -result {wrong # args: should be "dict update varName * script"}
1012 test dict-21.2 {dict update command} -returnCodes 1 -body {
1013     dict update v
1014 } -match glob -result {wrong # args: should be "dict update varName * script"}
1015 test dict-21.3 {dict update command} -returnCodes 1 -body {
1016     dict update v k
1017 } -match glob -result {wrong # args: should be "dict update varName * script"}
1018 test dict-21.4 {dict update command} -returnCodes 1 -body {
1019     dict update v k v
1020 } -match glob -result {wrong # args: should be "dict update varName * script"}
1021 test dict-21.5 {dict update command} -body {
1022     set a {b c}
1023     set result {}
1024     set bb {}
1025     dict update a b bb {
1026         lappend result $a $bb
1027     }
1028     lappend result $a
1029 } -cleanup {
1030     unset a result bb
1031 } -result {{b c} c {b c}}
1032 test dict-21.6 {dict update command} -body {
1033     set a {b c}
1034     set result {}
1035     set bb {}
1036     dict update a b bb {
1037         lappend result $a $bb [set bb d]
1038     }
1039     lappend result $a
1040 } -cleanup {
1041     unset a result bb
1042 } -result {{b c} c d {b d}}
1043 test dict-21.7 {dict update command} -body {
1044     set a {b c}
1045     set result {}
1046     set bb {}
1047     dict update a b bb {
1048         lappend result $a $bb [unset bb]
1049     }
1050     lappend result $a
1051 } -cleanup {
1052     unset a result
1053 } -result {{b c} c {} {}}
1054 test dict-21.8 {dict update command} -body {
1055     set a {b c d e}
1056     dict update a b v1 d v2 {
1057         lassign "$v1 $v2" v2 v1
1058     }
1059     dict-sort $a
1060 } -cleanup {
1061     unset a v1 v2
1062 } -result {b e d c}
1063 test dict-21.9 {dict update command} -body {
1064     set a {b c d e}
1065     dict update a b v1 d v2 {unset a}
1066     info exist a
1067 } -cleanup {
1068     unset v1 v2
1069 } -result 0
1070 test dict-21.10 {dict update command} -body {
1071     set a {b {c d}}
1072     dict update a b v1 {
1073         dict update v1 c v2 {
1074             set v2 foo
1075         }
1076     }
1077     dict-sort $a
1078 } -cleanup {
1079     unset a v1 v2
1080 } -result {b {c foo}}
1081 test dict-21.11 {dict update command} -body {
1082     set a {b c d e}
1083     dict update a b v1 d v2 {
1084         dict set a f g
1085     }
1086     dict-sort $a
1087 } -cleanup {
1088     unset a v1 v2
1089 } -result {b c d e f g}
1090 test dict-21.12 {dict update command} -body {
1091     set a {b c d e}
1092     dict update a b v1 d v2 f v3 {
1093         set v3 g
1094     }
1095     dict-sort $a
1096 } -cleanup {
1097     unset a v1 v2 v3
1098 } -result {b c d e f g}
1099 test dict-21.13 {dict update command: compilation} {
1100     apply {d {
1101         while 1 {
1102             dict update d a alpha b beta {
1103                 set beta $alpha
1104                 unset alpha
1105                 break
1106             }
1107         }
1108         dict-sort $d
1109     }} {a 1 c 2}
1110 } {b 1 c 2}
1111 test dict-21.14 {dict update command: compilation} tcl {
1112     apply {x {
1113         set indices {2 3}
1114         trace add variable aa write "string length \$indices ;#"
1115         dict update x k aa l bb {}
1116     }} {k 1 l 2}
1117 } {}
1118 test dict-21.15 {dict update command: compilation} tcl {
1119     apply {x {
1120         set indices {2 3}
1121         trace add variable aa read "string length \$indices ;#"
1122         dict update x k aa l bb {}
1123     }} {k 1 l 2}
1124 } {}
1125 test dict-21.16 {dict update command: no recursive structures [Bug 1786481]} -body {
1126     set foo {a {b {c {d {e 1}}}}}
1127     dict update foo a t {
1128         dict update t b t {
1129             dict update t c t {
1130                 dict update t d t {
1131                     dict incr t e
1132                 }
1133             }
1134         }
1135     }
1136     string range [append foo OK] end-1 end
1137 } -cleanup {
1138     unset foo t
1139 } -result OK
1140 test dict-21.17 {dict update command: no recursive structures [Bug 1786481]} {
1141     apply {{} {
1142         set foo {a {b {c {d {e 1}}}}}
1143         dict update foo a t {
1144             dict update t b t {
1145                 dict update t c t {
1146                     dict update t d t {
1147                         dict incr t e
1148                     }
1149                 }
1150             }
1151         }
1152         string range [append foo OK] end-1 end
1153     }}
1154 } OK
1156 test dict-22.1 {dict with command} -body {
1157     dict with
1158 } -returnCodes 1 -result {wrong # args: should be "dict with dictVar ?key ...? script"}
1159 test dict-22.2 {dict with command} -body {
1160     dict with v
1161 } -returnCodes 1 -result {wrong # args: should be "dict with dictVar ?key ...? script"}
1162 test dict-22.3 {dict with command} -body {
1163     unset -nocomplain v
1164     dict with v {error "in body"}
1165 } -returnCodes 1 -result {can't read "v": no such variable}
1166 test dict-22.4 {dict with command} -body {
1167     set a {b c d e}
1168     unset -nocomplain b d
1169     set result [list [info exist b] [info exist d]]
1170     dict with a {
1171         lappend result [info exist b] [info exist d] $b $d
1172     }
1173     return $result
1174 } -cleanup {
1175     unset a b d result
1176 } -result {0 0 1 1 c e}
1177 test dict-22.5 {dict with command} -body {
1178     set a {b c d e}
1179     dict with a {
1180         lassign "$b $d" d b
1181     }
1182     dict-sort $a
1183 } -cleanup {
1184     unset a b d
1185 } -result {b e d c}
1186 test dict-22.6 {dict with command} -body {
1187     set a {b c d e}
1188     dict with a {
1189         unset b
1190         # This *won't* go into the dict...
1191         set f g
1192     }
1193     return $a
1194 } -cleanup {
1195     unset a d f
1196 } -result {d e}
1197 test dict-22.7 {dict with command} -body {
1198     set a {b c d e}
1199     dict with a {
1200         dict unset a b
1201     }
1202     return [dict-sort $a]
1203 } -cleanup {
1204     unset a
1205 } -result {b c d e}
1206 test dict-22.8 {dict with command} -body {
1207     set a [dict create b c]
1208     dict with a {
1209         set b $a
1210     }
1211     return $a
1212 } -cleanup {
1213     unset a b
1214 } -result {b {b c}}
1215 test dict-22.9 {dict with command} -body {
1216     set a {b {c d}}
1217     dict with a b {
1218         set c $c$c
1219     }
1220     return $a
1221 } -cleanup {
1222     unset a c
1223 } -result {b {c dd}}
1224 test dict-22.10 {dict with command: result handling tricky case} -body {
1225     set a {b {c d}}
1226     foreach i {0 1} {
1227         if {$i} break
1228         dict with a b {
1229             set a {}
1230             # We're checking to see if we lose this break
1231             break
1232         }
1233     }
1234     list $i $a
1235 } -cleanup {
1236     unset a i c
1237 } -result {0 {}}
1238 test dict-22.11 {dict with command: no recursive structures [Bug 1786481]} -body {
1239     set foo {t {t {t {inner 1}}}}
1240     dict with foo {
1241         dict with t {
1242             dict with t {
1243                 dict with t {
1244                     incr inner
1245                 }
1246             }
1247         }
1248     }
1249     string range [append foo OK] end-1 end
1250 } -cleanup {
1251     unset foo t inner
1252 } -result OK
1254 testreport