88import threading
99
1010from ..collections import (box , ThreadLocalBox , Some , Shim , unbox ,
11- frozendict , view , roview , ShadowedSequence , mogrify )
11+ frozendict , view , roview , ShadowedSequence , mogrify ,
12+ in_slice , index_in_slice )
1213from ..fold import foldr
14+ from ..llist import cons , ll
1315
1416def runtests ():
17+ with testset ("internal utilities" ):
18+ test [in_slice (5 , slice (10 ))]
19+ test [in_slice (5 , 5 )] # convenience: int instead of a slice
20+ test [in_slice (5 , slice (1 , 10 , 2 ))]
21+ test [not in_slice (5 , slice (0 , 10 , 2 ))]
22+
23+ test [index_in_slice (5 , slice (10 )) == 5 ]
24+ test [index_in_slice (5 , slice (1 , 10 , 2 )) == 2 ]
25+
26+ # with sequence length parameter, and with negative indices
27+ test [in_slice (8 , slice (0 , None , 1 ), 10 )]
28+ test [in_slice (- 2 , slice (0 , None , 1 ), 10 )]
29+ test [in_slice (9 , 9 , 10 )] # convenience
30+ test [in_slice (- 1 , - 1 , 10 )]
31+ test [in_slice (7 , slice (None , None , - 1 ), 10 )]
32+ test [in_slice (- 3 , slice (None , None , - 1 ), 10 )]
33+ test [in_slice (7 , slice (9 , None , - 1 ), 10 )]
34+ test [in_slice (- 3 , slice (9 , None , - 1 ), 10 )]
35+
36+ test [in_slice (5 , slice (0 , None , 1 ), 10 )]
37+ test_raises [IndexError , in_slice (5 , slice (0 , None , 1 ), 3 )] # out of range when length = 3
38+
39+ test [index_in_slice (- 1 , slice (10 ), 10 ) == 9 ]
40+ test [index_in_slice (- 1 , slice (None , None , - 1 ), 10 ) == 0 ]
41+ test [index_in_slice (7 , slice (None , None , - 2 ), 10 ) == 1 ]
42+ test [index_in_slice (- 3 , slice (None , None , - 2 ), 10 ) == 1 ]
43+
44+ test_raises [TypeError , in_slice ("not an index" , slice (10 ))]
45+ test_raises [TypeError , in_slice (5 , "not a slice or int" )]
46+ test_raises [TypeError , in_slice (1 , slice (10 ), "not a length" )]
47+ test_raises [ValueError , in_slice (1 , slice (10 ), - 3 )] # negative length
48+
49+ test_raises [ValueError , in_slice (- 1 , slice (10 ))] # need length to interpret negative indices
50+
51+ test_raises [ValueError , in_slice (1 , slice (0 , None , 0 ))] # zero step
52+ test_raises [ValueError , in_slice (1 , slice (0 , None , 1 ))] # missing length for default stop with positive step
53+ test_raises [ValueError , in_slice (1 , slice (None , None , - 1 ))] # missing length for default start with negative step
54+
1555 # box: mutable single-item container à la Racket
1656 with testset ("box" ):
1757 b = box (17 )
@@ -76,6 +116,15 @@ def test_threadlocalbox_worker():
76116 t .join ()
77117 test [unbox (tlb ) == 42 ] # In the main thread, this box still has the original value.
78118
119+ test [42 in tlb ]
120+ test [[x for x in tlb ] == [42 ]]
121+ test [tlb == 42 ]
122+ test [len (tlb ) == 1 ]
123+
124+ tlb2 = ThreadLocalBox (42 )
125+ test [tlb2 is not tlb ]
126+ test [tlb2 == tlb ]
127+
79128 # The default object can be changed.
80129 tlb = ThreadLocalBox (42 )
81130 # We haven't sent any object to the box, so we see the default object.
@@ -116,6 +165,9 @@ def test_threadlocalbox_worker():
116165 test_raises [TypeError , s << 23 ] # immutable
117166 test_raises [AttributeError , s .set (23 )]
118167
168+ test [[x for x in s ] == [42 ]]
169+ test [len (s ) == 1 ]
170+
119171 # Shim (a.k.a. attribute proxy): redirect attribute accesses.
120172 #
121173 # The shim holds a box. Attribute accesses on the shim are redirected
@@ -181,6 +233,8 @@ class Zee:
181233 test [s .z == "hi from Zee" ]
182234 test_chaining ()
183235
236+ test_raises [TypeError , Shim ("la la la" )] # not a box, shouldn't be able to Shim it
237+
184238 # frozendict: immutable dictionary (like frozenset, but for dictionaries)
185239 with testset ("frozendict" ):
186240 d3 = frozendict ({'a' : 1 , 'b' : 2 })
@@ -320,6 +374,18 @@ class Zee:
320374 test [v == [1 , 2 , 3 , 4 , 5 ]]
321375 test [lst == [42 , 0 , 1 , 2 , 3 , 4 , 5 ]]
322376
377+ tup = (1 , 2 , 3 , 4 , 5 )
378+ test_raises [TypeError , view (tup )] # tuple is read-only, view is read/write
379+
380+ lst = list (range (5 ))
381+ v = view (lst )[2 :]
382+ with test_raises (TypeError ):
383+ v [2 , 3 ] = 42 # multidimensional indexing not supported
384+ with test_raises (IndexError ):
385+ v [9001 ] = 42
386+ with test_raises (IndexError ):
387+ v [- 9001 ] = 42
388+
323389 # read-only live view for sequences
324390 # useful to give read access to a sequence that is an internal detail
325391 with testset ("roview" ):
@@ -335,6 +401,24 @@ class Zee:
335401 v [2 ] = 3
336402 test_raises [AttributeError , v .reverse ()] # read-only view does not support in-place reverse
337403
404+ tup = tuple (range (5 ))
405+ v1 = roview (tup )[2 :]
406+ test [v1 == v1 ]
407+ v2 = roview (tup )[2 :]
408+ test [v2 is not v1 ]
409+ test [v2 == v1 ]
410+ v3 = roview (tup )[3 :]
411+ test [v3 != v1 ]
412+ v4 = roview (tup )[0 :2 ]
413+ v5 = roview (tup )[1 :3 ]
414+ test [v5 != v4 ]
415+
416+ tup = tuple (range (5 ))
417+ v1 = roview (tup )[2 :]
418+ test_raises [TypeError , v1 [2 , 3 ]] # multidimensional indexing not supported
419+ test_raises [IndexError , v1 [9001 ]]
420+ test_raises [IndexError , v1 [- 9001 ]]
421+
338422 # sequence shadowing (like ChainMap, but only two levels, and for sequences, not mappings)
339423 with testset ("ShadowedSequence" ):
340424 tpl = (1 , 2 , 3 , 4 , 5 )
@@ -343,6 +427,10 @@ class Zee:
343427 test [tpl == (1 , 2 , 3 , 4 , 5 )]
344428 test [s [2 :] == (42 , 4 , 5 )]
345429
430+ test_raises [TypeError , s [2 , 3 ]] # multidimensional indexing not supported
431+ test_raises [IndexError , s [9001 ]]
432+ test_raises [IndexError , s [- 9001 ]]
433+
346434 s2 = ShadowedSequence (tpl , slice (2 , 4 ), (23 , 42 ))
347435 test [s2 == (1 , 2 , 23 , 42 , 5 )]
348436 test [tpl == (1 , 2 , 3 , 4 , 5 )]
@@ -357,6 +445,16 @@ class Zee:
357445 test [s2 == (1 , 2 , 23 , 42 , 5 )]
358446 test [tpl == (1 , 2 , 3 , 4 , 5 )]
359447
448+ with test_raises (TypeError ):
449+ ShadowedSequence (s4 , "la la la" , "new value" ) # not a valid index specification
450+
451+ # no-op ShadowedSequence is allowed
452+ s5 = ShadowedSequence (tpl )
453+ test [s5 [3 ] == 4 ]
454+
455+ s6 = ShadowedSequence (tpl , slice (2 , 4 ), (23 ,)) # replacement too short...
456+ test_raises [IndexError , s6 [3 ]] # ...which is detected here
457+
360458 # mogrify: in-place map for various data structures (see docstring for details)
361459 with testset ("mogrify" ):
362460 double = lambda x : 2 * x
@@ -387,11 +485,16 @@ class Zee:
387485 test [mogrify (double , d .values ()) == {4 , 8 , 12 }]
388486 test [d == {1 : 2 , 3 : 4 , 5 : 6 }]
389487
488+ test [mogrify (double , cons (1 , 2 )) == cons (2 , 4 )]
489+ test [mogrify (double , ll (1 , 2 , 3 )) == ll (2 , 4 , 6 )]
490+
390491 b = box (17 )
391492 b2 = mogrify (double , b )
392493 test [b2 == 34 ]
393494 test [b2 is b ]
394495
496+ test [mogrify (double , Some (21 )) == Some (42 )]
497+
395498 tup = (1 , 2 , 3 )
396499 tup2 = mogrify (double , tup )
397500 test [tup2 == (2 , 4 , 6 )]
0 commit comments