]> git.saurik.com Git - redis.git/blob - tests/unit/type/list.tcl
4c131fc3774eb2953102dbbc5e6b89fe42288488
[redis.git] / tests / unit / type / list.tcl
1 start_server {
2 tags {"list"}
3 overrides {
4 "list-max-ziplist-value" 16
5 "list-max-ziplist-entries" 256
6 }
7 } {
8 # We need a value larger than list-max-ziplist-value to make sure
9 # the list has the right encoding when it is swapped in again.
10 array set largevalue {}
11 set largevalue(ziplist) "hello"
12 set largevalue(linkedlist) [string repeat "hello" 4]
13
14 test {LPUSH, RPUSH, LLENGTH, LINDEX - ziplist} {
15 # first lpush then rpush
16 assert_equal 1 [r lpush myziplist1 a]
17 assert_equal 2 [r rpush myziplist1 b]
18 assert_equal 3 [r rpush myziplist1 c]
19 assert_equal 3 [r llen myziplist1]
20 assert_equal a [r lindex myziplist1 0]
21 assert_equal b [r lindex myziplist1 1]
22 assert_equal c [r lindex myziplist1 2]
23 assert_encoding ziplist myziplist1
24
25 # first rpush then lpush
26 assert_equal 1 [r rpush myziplist2 a]
27 assert_equal 2 [r lpush myziplist2 b]
28 assert_equal 3 [r lpush myziplist2 c]
29 assert_equal 3 [r llen myziplist2]
30 assert_equal c [r lindex myziplist2 0]
31 assert_equal b [r lindex myziplist2 1]
32 assert_equal a [r lindex myziplist2 2]
33 assert_encoding ziplist myziplist2
34 }
35
36 test {LPUSH, RPUSH, LLENGTH, LINDEX - regular list} {
37 # first lpush then rpush
38 assert_equal 1 [r lpush mylist1 $largevalue(linkedlist)]
39 assert_encoding linkedlist mylist1
40 assert_equal 2 [r rpush mylist1 b]
41 assert_equal 3 [r rpush mylist1 c]
42 assert_equal 3 [r llen mylist1]
43 assert_equal $largevalue(linkedlist) [r lindex mylist1 0]
44 assert_equal b [r lindex mylist1 1]
45 assert_equal c [r lindex mylist1 2]
46
47 # first rpush then lpush
48 assert_equal 1 [r rpush mylist2 $largevalue(linkedlist)]
49 assert_encoding linkedlist mylist2
50 assert_equal 2 [r lpush mylist2 b]
51 assert_equal 3 [r lpush mylist2 c]
52 assert_equal 3 [r llen mylist2]
53 assert_equal c [r lindex mylist2 0]
54 assert_equal b [r lindex mylist2 1]
55 assert_equal $largevalue(linkedlist) [r lindex mylist2 2]
56 }
57
58 test {DEL a list - ziplist} {
59 assert_equal 1 [r del myziplist2]
60 assert_equal 0 [r exists myziplist2]
61 assert_equal 0 [r llen myziplist2]
62 }
63
64 test {DEL a list - regular list} {
65 assert_equal 1 [r del mylist2]
66 assert_equal 0 [r exists mylist2]
67 assert_equal 0 [r llen mylist2]
68 }
69
70 proc create_ziplist {key entries} {
71 r del $key
72 foreach entry $entries { r rpush $key $entry }
73 assert_encoding ziplist $key
74 }
75
76 proc create_linkedlist {key entries} {
77 r del $key
78 foreach entry $entries { r rpush $key $entry }
79 assert_encoding linkedlist $key
80 }
81
82 foreach {type large} [array get largevalue] {
83 test "BLPOP, BRPOP: single existing list - $type" {
84 set rd [redis_deferring_client]
85 create_$type blist "a b $large c d"
86
87 $rd blpop blist 1
88 assert_equal {blist a} [$rd read]
89 $rd brpop blist 1
90 assert_equal {blist d} [$rd read]
91
92 $rd blpop blist 1
93 assert_equal {blist b} [$rd read]
94 $rd brpop blist 1
95 assert_equal {blist c} [$rd read]
96 }
97
98 test "BLPOP, BRPOP: multiple existing lists - $type" {
99 set rd [redis_deferring_client]
100 create_$type blist1 "a $large c"
101 create_$type blist2 "d $large f"
102
103 $rd blpop blist1 blist2 1
104 assert_equal {blist1 a} [$rd read]
105 $rd brpop blist1 blist2 1
106 assert_equal {blist1 c} [$rd read]
107 assert_equal 1 [r llen blist1]
108 assert_equal 3 [r llen blist2]
109
110 $rd blpop blist2 blist1 1
111 assert_equal {blist2 d} [$rd read]
112 $rd brpop blist2 blist1 1
113 assert_equal {blist2 f} [$rd read]
114 assert_equal 1 [r llen blist1]
115 assert_equal 1 [r llen blist2]
116 }
117
118 test "BLPOP, BRPOP: second list has an entry - $type" {
119 set rd [redis_deferring_client]
120 r del blist1
121 create_$type blist2 "d $large f"
122
123 $rd blpop blist1 blist2 1
124 assert_equal {blist2 d} [$rd read]
125 $rd brpop blist1 blist2 1
126 assert_equal {blist2 f} [$rd read]
127 assert_equal 0 [r llen blist1]
128 assert_equal 1 [r llen blist2]
129 }
130 }
131
132 foreach {pop} {BLPOP BRPOP} {
133 test "$pop: with single empty list argument" {
134 set rd [redis_deferring_client]
135 r del blist1
136 $rd $pop blist1 1
137 r rpush blist1 foo
138 assert_equal {blist1 foo} [$rd read]
139 assert_equal 0 [r exists blist1]
140 }
141
142 test "$pop: with negative timeout" {
143 set rd [redis_deferring_client]
144 $rd $pop blist1 -1
145 assert_error "ERR*is negative*" {$rd read}
146 }
147
148 test "$pop: with non-integer timeout" {
149 set rd [redis_deferring_client]
150 $rd $pop blist1 1.1
151 assert_error "ERR*not an integer*" {$rd read}
152 }
153
154 test "$pop: with zero timeout should block indefinitely" {
155 # To test this, use a timeout of 0 and wait a second.
156 # The blocking pop should still be waiting for a push.
157 set rd [redis_deferring_client]
158 $rd $pop blist1 0
159 after 1000
160 r rpush blist1 foo
161 assert_equal {blist1 foo} [$rd read]
162 }
163
164 test "$pop: second argument is not a list" {
165 set rd [redis_deferring_client]
166 r del blist1 blist2
167 r set blist2 nolist
168 $rd $pop blist1 blist2 1
169 assert_error "ERR*wrong kind*" {$rd read}
170 }
171
172 test "$pop: timeout" {
173 set rd [redis_deferring_client]
174 r del blist1 blist2
175 $rd $pop blist1 blist2 1
176 assert_equal {} [$rd read]
177 }
178
179 test "$pop: arguments are empty" {
180 set rd [redis_deferring_client]
181 r del blist1 blist2
182
183 $rd $pop blist1 blist2 1
184 r rpush blist1 foo
185 assert_equal {blist1 foo} [$rd read]
186 assert_equal 0 [r exists blist1]
187 assert_equal 0 [r exists blist2]
188
189 $rd $pop blist1 blist2 1
190 r rpush blist2 foo
191 assert_equal {blist2 foo} [$rd read]
192 assert_equal 0 [r exists blist1]
193 assert_equal 0 [r exists blist2]
194 }
195 }
196
197 test {BLPOP inside a transaction} {
198 r del xlist
199 r lpush xlist foo
200 r lpush xlist bar
201 r multi
202 r blpop xlist 0
203 r blpop xlist 0
204 r blpop xlist 0
205 r exec
206 } {{xlist bar} {xlist foo} {}}
207
208 test {LPUSHX, RPUSHX - generic} {
209 r del xlist
210 assert_equal 0 [r lpushx xlist a]
211 assert_equal 0 [r llen xlist]
212 assert_equal 0 [r rpushx xlist a]
213 assert_equal 0 [r llen xlist]
214 }
215
216 foreach {type large} [array get largevalue] {
217 test "LPUSHX, RPUSHX - $type" {
218 create_$type xlist "$large c"
219 assert_equal 3 [r rpushx xlist d]
220 assert_equal 4 [r lpushx xlist a]
221 assert_equal "a $large c d" [r lrange xlist 0 -1]
222 }
223
224 test "LINSERT - $type" {
225 create_$type xlist "a $large c d"
226 assert_equal 5 [r linsert xlist before c zz]
227 assert_equal "a $large zz c d" [r lrange xlist 0 10]
228 assert_equal 6 [r linsert xlist after c yy]
229 assert_equal "a $large zz c yy d" [r lrange xlist 0 10]
230 assert_equal 7 [r linsert xlist after d dd]
231 assert_equal -1 [r linsert xlist after bad ddd]
232 assert_equal "a $large zz c yy d dd" [r lrange xlist 0 10]
233 assert_equal 8 [r linsert xlist before a aa]
234 assert_equal -1 [r linsert xlist before bad aaa]
235 assert_equal "aa a $large zz c yy d dd" [r lrange xlist 0 10]
236
237 # check inserting integer encoded value
238 assert_equal 9 [r linsert xlist before aa 42]
239 assert_equal 42 [r lrange xlist 0 0]
240 }
241 }
242
243 test {LPUSHX, RPUSHX convert from ziplist to list} {
244 set large $largevalue(linkedlist)
245
246 # convert when a large value is pushed
247 create_ziplist xlist a
248 assert_equal 2 [r rpushx xlist $large]
249 assert_encoding linkedlist xlist
250 create_ziplist xlist a
251 assert_equal 2 [r lpushx xlist $large]
252 assert_encoding linkedlist xlist
253
254 # convert when the length threshold is exceeded
255 create_ziplist xlist [lrepeat 256 a]
256 assert_equal 257 [r rpushx xlist b]
257 assert_encoding linkedlist xlist
258 create_ziplist xlist [lrepeat 256 a]
259 assert_equal 257 [r lpushx xlist b]
260 assert_encoding linkedlist xlist
261 }
262
263 test {LINSERT convert from ziplist to list} {
264 set large $largevalue(linkedlist)
265
266 # convert when a large value is inserted
267 create_ziplist xlist a
268 assert_equal 2 [r linsert xlist before a $large]
269 assert_encoding linkedlist xlist
270 create_ziplist xlist a
271 assert_equal 2 [r linsert xlist after a $large]
272 assert_encoding linkedlist xlist
273
274 # convert when the length threshold is exceeded
275 create_ziplist xlist [lrepeat 256 a]
276 assert_equal 257 [r linsert xlist before a a]
277 assert_encoding linkedlist xlist
278 create_ziplist xlist [lrepeat 256 a]
279 assert_equal 257 [r linsert xlist after a a]
280 assert_encoding linkedlist xlist
281
282 # don't convert when the value could not be inserted
283 create_ziplist xlist [lrepeat 256 a]
284 assert_equal -1 [r linsert xlist before foo a]
285 assert_encoding ziplist xlist
286 create_ziplist xlist [lrepeat 256 a]
287 assert_equal -1 [r linsert xlist after foo a]
288 assert_encoding ziplist xlist
289 }
290
291 foreach {type num} {ziplist 250 linkedlist 500} {
292 proc check_numbered_list_consistency {key} {
293 set len [r llen $key]
294 for {set i 0} {$i < $len} {incr i} {
295 assert_equal $i [r lindex $key $i]
296 assert_equal [expr $len-1-$i] [r lindex $key [expr (-$i)-1]]
297 }
298 }
299
300 proc check_random_access_consistency {key} {
301 set len [r llen $key]
302 for {set i 0} {$i < $len} {incr i} {
303 set rint [expr int(rand()*$len)]
304 assert_equal $rint [r lindex $key $rint]
305 assert_equal [expr $len-1-$rint] [r lindex $key [expr (-$rint)-1]]
306 }
307 }
308
309 test "LINDEX consistency test - $type" {
310 r del mylist
311 for {set i 0} {$i < $num} {incr i} {
312 r rpush mylist $i
313 }
314 assert_encoding $type mylist
315 check_numbered_list_consistency mylist
316 }
317
318 test "LINDEX random access - $type" {
319 assert_encoding $type mylist
320 check_random_access_consistency mylist
321 }
322
323 test "Check if list is still ok after a DEBUG RELOAD - $type" {
324 r debug reload
325 assert_encoding $type mylist
326 check_numbered_list_consistency mylist
327 check_random_access_consistency mylist
328 }
329 }
330
331 test {LLEN against non-list value error} {
332 r del mylist
333 r set mylist foobar
334 assert_error ERR* {r llen mylist}
335 }
336
337 test {LLEN against non existing key} {
338 assert_equal 0 [r llen not-a-key]
339 }
340
341 test {LINDEX against non-list value error} {
342 assert_error ERR* {r lindex mylist 0}
343 }
344
345 test {LINDEX against non existing key} {
346 assert_equal "" [r lindex not-a-key 10]
347 }
348
349 test {LPUSH against non-list value error} {
350 assert_error ERR* {r lpush mylist 0}
351 }
352
353 test {RPUSH against non-list value error} {
354 assert_error ERR* {r rpush mylist 0}
355 }
356
357 foreach {type large} [array get largevalue] {
358 test "RPOPLPUSH base case - $type" {
359 r del mylist1 mylist2
360 create_$type mylist1 "a $large c d"
361 assert_equal d [r rpoplpush mylist1 mylist2]
362 assert_equal c [r rpoplpush mylist1 mylist2]
363 assert_equal "a $large" [r lrange mylist1 0 -1]
364 assert_equal "c d" [r lrange mylist2 0 -1]
365 assert_encoding ziplist mylist2
366 }
367
368 test "RPOPLPUSH with the same list as src and dst - $type" {
369 create_$type mylist "a $large c"
370 assert_equal "a $large c" [r lrange mylist 0 -1]
371 assert_equal c [r rpoplpush mylist mylist]
372 assert_equal "c a $large" [r lrange mylist 0 -1]
373 }
374
375 foreach {othertype otherlarge} [array get largevalue] {
376 test "RPOPLPUSH with $type source and existing target $othertype" {
377 create_$type srclist "a b c $large"
378 create_$othertype dstlist "$otherlarge"
379 assert_equal $large [r rpoplpush srclist dstlist]
380 assert_equal c [r rpoplpush srclist dstlist]
381 assert_equal "a b" [r lrange srclist 0 -1]
382 assert_equal "c $large $otherlarge" [r lrange dstlist 0 -1]
383
384 # When we rpoplpush'ed a large value, dstlist should be
385 # converted to the same encoding as srclist.
386 if {$type eq "linkedlist"} {
387 assert_encoding linkedlist dstlist
388 }
389 }
390 }
391 }
392
393 test {RPOPLPUSH against non existing key} {
394 r del srclist dstlist
395 assert_equal {} [r rpoplpush srclist dstlist]
396 assert_equal 0 [r exists srclist]
397 assert_equal 0 [r exists dstlist]
398 }
399
400 test {RPOPLPUSH against non list src key} {
401 r del srclist dstlist
402 r set srclist x
403 assert_error ERR* {r rpoplpush srclist dstlist}
404 assert_type string srclist
405 assert_equal 0 [r exists newlist]
406 }
407
408 test {RPOPLPUSH against non list dst key} {
409 create_ziplist srclist {a b c d}
410 r set dstlist x
411 assert_error ERR* {r rpoplpush srclist dstlist}
412 assert_type string dstlist
413 assert_equal {a b c d} [r lrange srclist 0 -1]
414 }
415
416 test {RPOPLPUSH against non existing src key} {
417 r del srclist dstlist
418 assert_equal {} [r rpoplpush srclist dstlist]
419 } {}
420
421 foreach {type large} [array get largevalue] {
422 test "Basic LPOP/RPOP - $type" {
423 create_$type mylist "$large 1 2"
424 assert_equal $large [r lpop mylist]
425 assert_equal 2 [r rpop mylist]
426 assert_equal 1 [r lpop mylist]
427 assert_equal 0 [r llen mylist]
428
429 # pop on empty list
430 assert_equal {} [r lpop mylist]
431 assert_equal {} [r rpop mylist]
432 }
433 }
434
435 test {LPOP/RPOP against non list value} {
436 r set notalist foo
437 assert_error ERR*kind* {r lpop notalist}
438 assert_error ERR*kind* {r rpop notalist}
439 }
440
441 foreach {type num} {ziplist 250 linkedlist 500} {
442 test "Mass RPOP/LPOP - $type" {
443 r del mylist
444 set sum1 0
445 for {set i 0} {$i < $num} {incr i} {
446 r lpush mylist $i
447 incr sum1 $i
448 }
449 assert_encoding $type mylist
450 set sum2 0
451 for {set i 0} {$i < [expr $num/2]} {incr i} {
452 incr sum2 [r lpop mylist]
453 incr sum2 [r rpop mylist]
454 }
455 assert_equal $sum1 $sum2
456 }
457 }
458
459 foreach {type large} [array get largevalue] {
460 test "LRANGE basics - $type" {
461 create_$type mylist "$large 1 2 3 4 5 6 7 8 9"
462 assert_equal {1 2 3 4 5 6 7 8} [r lrange mylist 1 -2]
463 assert_equal {7 8 9} [r lrange mylist -3 -1]
464 assert_equal {4} [r lrange mylist 4 4]
465 }
466
467 test "LRANGE inverted indexes - $type" {
468 create_$type mylist "$large 1 2 3 4 5 6 7 8 9"
469 assert_equal {} [r lrange mylist 6 2]
470 }
471
472 test "LRANGE out of range indexes including the full list - $type" {
473 create_$type mylist "$large 1 2 3"
474 assert_equal "$large 1 2 3" [r lrange mylist -1000 1000]
475 }
476
477 test "LRANGE out of range negative end index - $type" {
478 create_$type mylist "$large 1 2 3"
479 assert_equal $large [r lrange mylist 0 -4]
480 assert_equal {} [r lrange mylist 0 -5]
481 }
482 }
483
484 test {LRANGE against non existing key} {
485 assert_equal {} [r lrange nosuchkey 0 1]
486 }
487
488 foreach {type large} [array get largevalue] {
489 proc trim_list {type min max} {
490 upvar 1 large large
491 r del mylist
492 create_$type mylist "1 2 3 4 $large"
493 r ltrim mylist $min $max
494 r lrange mylist 0 -1
495 }
496
497 test "LTRIM basics - $type" {
498 assert_equal "1" [trim_list $type 0 0]
499 assert_equal "1 2" [trim_list $type 0 1]
500 assert_equal "1 2 3" [trim_list $type 0 2]
501 assert_equal "2 3" [trim_list $type 1 2]
502 assert_equal "2 3 4 $large" [trim_list $type 1 -1]
503 assert_equal "2 3 4" [trim_list $type 1 -2]
504 assert_equal "4 $large" [trim_list $type -2 -1]
505 assert_equal "$large" [trim_list $type -1 -1]
506 assert_equal "1 2 3 4 $large" [trim_list $type -5 -1]
507 assert_equal "1 2 3 4 $large" [trim_list $type -10 10]
508 assert_equal "1 2 3 4 $large" [trim_list $type 0 5]
509 assert_equal "1 2 3 4 $large" [trim_list $type 0 10]
510 }
511
512 test "LTRIM out of range negative end index - $type" {
513 assert_equal {1} [trim_list $type 0 -5]
514 assert_equal {} [trim_list $type 0 -6]
515 }
516
517 tags {"slow"} {
518 test "LTRIM stress testing - $type" {
519 set mylist {}
520 set startlen 32
521 r del mylist
522
523 # Start with the large value to ensure the
524 # right encoding is used.
525 r rpush mylist $large
526 lappend mylist $large
527
528 for {set i 0} {$i < $startlen} {incr i} {
529 set str [randomInt 9223372036854775807]
530 r rpush mylist $str
531 lappend mylist $str
532 }
533
534 for {set i 0} {$i < 1000} {incr i} {
535 set min [expr {int(rand()*$startlen)}]
536 set max [expr {$min+int(rand()*$startlen)}]
537 set mylist [lrange $mylist $min $max]
538 r ltrim mylist $min $max
539 assert_equal $mylist [r lrange mylist 0 -1]
540
541 for {set j [r llen mylist]} {$j < $startlen} {incr j} {
542 set str [randomInt 9223372036854775807]
543 r rpush mylist $str
544 lappend mylist $str
545 }
546 }
547 }
548 }
549 }
550
551 foreach {type large} [array get largevalue] {
552 test "LSET - $type" {
553 create_$type mylist "99 98 $large 96 95"
554 r lset mylist 1 foo
555 r lset mylist -1 bar
556 assert_equal "99 foo $large 96 bar" [r lrange mylist 0 -1]
557 }
558
559 test "LSET out of range index - $type" {
560 assert_error ERR*range* {r lset mylist 10 foo}
561 }
562 }
563
564 test {LSET against non existing key} {
565 assert_error ERR*key* {r lset nosuchkey 10 foo}
566 }
567
568 test {LSET against non list value} {
569 r set nolist foobar
570 assert_error ERR*value* {r lset nolist 0 foo}
571 }
572
573 foreach {type e} [array get largevalue] {
574 test "LREM remove all the occurrences - $type" {
575 create_$type mylist "$e foo bar foobar foobared zap bar test foo"
576 assert_equal 2 [r lrem mylist 0 bar]
577 assert_equal "$e foo foobar foobared zap test foo" [r lrange mylist 0 -1]
578 }
579
580 test "LREM remove the first occurrence - $type" {
581 assert_equal 1 [r lrem mylist 1 foo]
582 assert_equal "$e foobar foobared zap test foo" [r lrange mylist 0 -1]
583 }
584
585 test "LREM remove non existing element - $type" {
586 assert_equal 0 [r lrem mylist 1 nosuchelement]
587 assert_equal "$e foobar foobared zap test foo" [r lrange mylist 0 -1]
588 }
589
590 test "LREM starting from tail with negative count - $type" {
591 create_$type mylist "$e foo bar foobar foobared zap bar test foo foo"
592 assert_equal 1 [r lrem mylist -1 bar]
593 assert_equal "$e foo bar foobar foobared zap test foo foo" [r lrange mylist 0 -1]
594 }
595
596 test "LREM starting from tail with negative count (2) - $type" {
597 assert_equal 2 [r lrem mylist -2 foo]
598 assert_equal "$e foo bar foobar foobared zap test" [r lrange mylist 0 -1]
599 }
600
601 test "LREM deleting objects that may be int encoded - $type" {
602 create_$type myotherlist "$e 1 2 3"
603 assert_equal 1 [r lrem myotherlist 1 2]
604 assert_equal 3 [r llen myotherlist]
605 }
606
607 }
608 }
609
610 start_server {
611 tags {list ziplist}
612 overrides {
613 "list-max-ziplist-value" 200000
614 "list-max-ziplist-entries" 256
615 }
616 } {
617 test {Explicit regression for a list bug} {
618 set mylist {49376042582 {BkG2o\pIC]4YYJa9cJ4GWZalG[4tin;1D2whSkCOW`mX;SFXGyS8sedcff3fQI^tgPCC@^Nu1J6o]meM@Lko]t_jRyo<xSJ1oObDYd`ppZuW6P@fS278YaOx=s6lvdFlMbP0[SbkI^Kr\HBXtuFaA^mDx:yzS4a[skiiPWhT<nNfAf=aQVfclcuwDrfe;iVuKdNvB9kbfq>tK?tH[\EvWqS]b`o2OCtjg:?nUTwdjpcUm]y:pg5q24q7LlCOwQE^}}
619 r del l
620 r rpush l [lindex $mylist 0]
621 r rpush l [lindex $mylist 1]
622 assert_equal [r lindex l 0] [lindex $mylist 0]
623 assert_equal [r lindex l 1] [lindex $mylist 1]
624 }
625
626 tags {slow} {
627 test {ziplist implementation: value encoding and backlink} {
628 for {set j 0} {$j < 100} {incr j} {
629 r del l
630 set l {}
631 for {set i 0} {$i < 200} {incr i} {
632 randpath {
633 set data [string repeat x [randomInt 100000]]
634 } {
635 set data [randomInt 65536]
636 } {
637 set data [randomInt 4294967296]
638 } {
639 set data [randomInt 18446744073709551616]
640 }
641 lappend l $data
642 r rpush l $data
643 }
644 assert_equal [llength $l] [r llen l]
645 # Traverse backward
646 for {set i 199} {$i >= 0} {incr i -1} {
647 if {[lindex $l $i] ne [r lindex l $i]} {
648 assert_equal [lindex $l $i] [r lindex l $i]
649 }
650 }
651 }
652 }
653
654 test {ziplist implementation: encoding stress testing} {
655 for {set j 0} {$j < 200} {incr j} {
656 r del l
657 set l {}
658 set len [randomInt 400]
659 for {set i 0} {$i < $len} {incr i} {
660 set rv [randomValue]
661 randpath {
662 lappend l $rv
663 r rpush l $rv
664 } {
665 set l [concat [list $rv] $l]
666 r lpush l $rv
667 }
668 }
669 assert_equal [llength $l] [r llen l]
670 for {set i 0} {$i < 200} {incr i} {
671 if {[lindex $l $i] ne [r lindex l $i]} {
672 assert_equal [lindex $l $i] [r lindex l $i]
673 }
674 }
675 }
676 }
677 }
678 }