blob: 62da9c5c3fe118d42e4df488e62bbfef6f76553b [file] [log] [blame]
Guido van Rossumcd16bf62007-06-13 18:07:49 +00001"""Unit tests for collections.py."""
2
Guido van Rossumd8faa362007-04-27 19:54:29 +00003import unittest
4from test import test_support
Guido van Rossum8ce8a782007-11-01 19:42:39 +00005from collections import namedtuple
Guido van Rossumcd16bf62007-06-13 18:07:49 +00006from collections import Hashable, Iterable, Iterator
7from collections import Sized, Container, Callable
8from collections import Set, MutableSet
9from collections import Mapping, MutableMapping
10from collections import Sequence, MutableSequence
Guido van Rossumd05eb002007-11-21 22:26:24 +000011from collections import ByteString
Guido van Rossumcd16bf62007-06-13 18:07:49 +000012
Guido van Rossumd8faa362007-04-27 19:54:29 +000013
14class TestNamedTuple(unittest.TestCase):
15
16 def test_factory(self):
Guido van Rossum8ce8a782007-11-01 19:42:39 +000017 Point = namedtuple('Point', 'x y')
Guido van Rossumd8faa362007-04-27 19:54:29 +000018 self.assertEqual(Point.__name__, 'Point')
19 self.assertEqual(Point.__doc__, 'Point(x, y)')
20 self.assertEqual(Point.__slots__, ())
21 self.assertEqual(Point.__module__, __name__)
22 self.assertEqual(Point.__getitem__, tuple.__getitem__)
Guido van Rossum8ce8a782007-11-01 19:42:39 +000023
24 self.assertRaises(ValueError, namedtuple, 'abc%', 'efg ghi') # type has non-alpha char
25 self.assertRaises(ValueError, namedtuple, 'class', 'efg ghi') # type has keyword
26 self.assertRaises(ValueError, namedtuple, '9abc', 'efg ghi') # type starts with digit
27
28 self.assertRaises(ValueError, namedtuple, 'abc', 'efg g%hi') # field with non-alpha char
29 self.assertRaises(ValueError, namedtuple, 'abc', 'abc class') # field has keyword
30 self.assertRaises(ValueError, namedtuple, 'abc', '8efg 9ghi') # field starts with digit
31 self.assertRaises(ValueError, namedtuple, 'abc', '__efg__ ghi') # field with double underscores
32 self.assertRaises(ValueError, namedtuple, 'abc', 'efg efg ghi') # duplicate field
33
34 namedtuple('Point0', 'x1 y2') # Verify that numbers are allowed in names
Guido van Rossumd8faa362007-04-27 19:54:29 +000035
36 def test_instance(self):
Guido van Rossum8ce8a782007-11-01 19:42:39 +000037 Point = namedtuple('Point', 'x y')
Guido van Rossumd8faa362007-04-27 19:54:29 +000038 p = Point(11, 22)
39 self.assertEqual(p, Point(x=11, y=22))
40 self.assertEqual(p, Point(11, y=22))
41 self.assertEqual(p, Point(y=22, x=11))
42 self.assertEqual(p, Point(*(11, 22)))
43 self.assertEqual(p, Point(**dict(x=11, y=22)))
44 self.assertRaises(TypeError, Point, 1) # too few args
45 self.assertRaises(TypeError, Point, 1, 2, 3) # too many args
46 self.assertRaises(TypeError, eval, 'Point(XXX=1, y=2)', locals()) # wrong keyword argument
47 self.assertRaises(TypeError, eval, 'Point(x=1)', locals()) # missing keyword argument
48 self.assertEqual(repr(p), 'Point(x=11, y=22)')
49 self.assert_('__dict__' not in dir(p)) # verify instance has no dict
50 self.assert_('__weakref__' not in dir(p))
Thomas Wouters1b7f8912007-09-19 03:06:30 +000051 self.assertEqual(p.__fields__, ('x', 'y')) # test __fields__ attribute
Guido van Rossum3d392eb2007-11-16 00:35:22 +000052 self.assertEqual(p.__replace__(x=1), (1, 22)) # test __replace__ method
Guido van Rossum8ce8a782007-11-01 19:42:39 +000053 self.assertEqual(p.__asdict__(), dict(x=11, y=22)) # test __dict__ method
Thomas Wouters1b7f8912007-09-19 03:06:30 +000054
Guido van Rossum3d392eb2007-11-16 00:35:22 +000055 # Verify that __fields__ is read-only
56 try:
57 p.__fields__ = ('F1' ,'F2')
58 except AttributeError:
59 pass
60 else:
61 self.fail('The __fields__ attribute needs to be read-only')
62
Thomas Wouters1b7f8912007-09-19 03:06:30 +000063 # verify that field string can have commas
Guido van Rossum8ce8a782007-11-01 19:42:39 +000064 Point = namedtuple('Point', 'x, y')
65 p = Point(x=11, y=22)
66 self.assertEqual(repr(p), 'Point(x=11, y=22)')
67
68 # verify that fieldspec can be a non-string sequence
69 Point = namedtuple('Point', ('x', 'y'))
Thomas Wouters1b7f8912007-09-19 03:06:30 +000070 p = Point(x=11, y=22)
71 self.assertEqual(repr(p), 'Point(x=11, y=22)')
Guido van Rossumd8faa362007-04-27 19:54:29 +000072
73 def test_tupleness(self):
Guido van Rossum8ce8a782007-11-01 19:42:39 +000074 Point = namedtuple('Point', 'x y')
Guido van Rossumd8faa362007-04-27 19:54:29 +000075 p = Point(11, 22)
76
77 self.assert_(isinstance(p, tuple))
78 self.assertEqual(p, (11, 22)) # matches a real tuple
79 self.assertEqual(tuple(p), (11, 22)) # coercable to a real tuple
80 self.assertEqual(list(p), [11, 22]) # coercable to a list
81 self.assertEqual(max(p), 22) # iterable
82 self.assertEqual(max(*p), 22) # star-able
83 x, y = p
84 self.assertEqual(p, (x, y)) # unpacks like a tuple
85 self.assertEqual((p[0], p[1]), (11, 22)) # indexable like a tuple
86 self.assertRaises(IndexError, p.__getitem__, 3)
87
88 self.assertEqual(p.x, x)
89 self.assertEqual(p.y, y)
90 self.assertRaises(AttributeError, eval, 'p.z', locals())
91
Thomas Wouters1b7f8912007-09-19 03:06:30 +000092 def test_odd_sizes(self):
Guido van Rossum8ce8a782007-11-01 19:42:39 +000093 Zero = namedtuple('Zero', '')
Thomas Wouters1b7f8912007-09-19 03:06:30 +000094 self.assertEqual(Zero(), ())
Guido van Rossum8ce8a782007-11-01 19:42:39 +000095 Dot = namedtuple('Dot', 'd')
Thomas Wouters1b7f8912007-09-19 03:06:30 +000096 self.assertEqual(Dot(1), (1,))
97
Guido van Rossumd8faa362007-04-27 19:54:29 +000098
Guido van Rossumcd16bf62007-06-13 18:07:49 +000099class TestOneTrickPonyABCs(unittest.TestCase):
100
101 def test_Hashable(self):
102 # Check some non-hashables
Guido van Rossum254348e2007-11-21 19:29:53 +0000103 non_samples = [bytearray(), list(), set(), dict()]
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000104 for x in non_samples:
105 self.failIf(isinstance(x, Hashable), repr(x))
106 self.failIf(issubclass(type(x), Hashable), repr(type(x)))
107 # Check some hashables
108 samples = [None,
109 int(), float(), complex(),
Guido van Rossum07d4e782007-07-03 16:59:47 +0000110 str(),
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000111 tuple(), frozenset(),
Guido van Rossum98297ee2007-11-06 21:34:58 +0000112 int, list, object, type, bytes()
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000113 ]
114 for x in samples:
115 self.failUnless(isinstance(x, Hashable), repr(x))
116 self.failUnless(issubclass(type(x), Hashable), repr(type(x)))
117 self.assertRaises(TypeError, Hashable)
118 # Check direct subclassing
119 class H(Hashable):
120 def __hash__(self):
121 return super().__hash__()
122 self.assertEqual(hash(H()), 0)
123 self.failIf(issubclass(int, H))
124
125 def test_Iterable(self):
126 # Check some non-iterables
127 non_samples = [None, 42, 3.14, 1j]
128 for x in non_samples:
129 self.failIf(isinstance(x, Iterable), repr(x))
130 self.failIf(issubclass(type(x), Iterable), repr(type(x)))
131 # Check some iterables
Guido van Rossum07d4e782007-07-03 16:59:47 +0000132 samples = [bytes(), str(),
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000133 tuple(), list(), set(), frozenset(), dict(),
134 dict().keys(), dict().items(), dict().values(),
135 (lambda: (yield))(),
136 (x for x in []),
137 ]
138 for x in samples:
139 self.failUnless(isinstance(x, Iterable), repr(x))
140 self.failUnless(issubclass(type(x), Iterable), repr(type(x)))
141 # Check direct subclassing
142 class I(Iterable):
143 def __iter__(self):
144 return super().__iter__()
145 self.assertEqual(list(I()), [])
146 self.failIf(issubclass(str, I))
147
148 def test_Iterator(self):
Guido van Rossum07d4e782007-07-03 16:59:47 +0000149 non_samples = [None, 42, 3.14, 1j, b"", "", (), [], {}, set()]
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000150 for x in non_samples:
151 self.failIf(isinstance(x, Iterator), repr(x))
152 self.failIf(issubclass(type(x), Iterator), repr(type(x)))
Guido van Rossum07d4e782007-07-03 16:59:47 +0000153 samples = [iter(bytes()), iter(str()),
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000154 iter(tuple()), iter(list()), iter(dict()),
155 iter(set()), iter(frozenset()),
156 iter(dict().keys()), iter(dict().items()),
157 iter(dict().values()),
158 (lambda: (yield))(),
159 (x for x in []),
160 ]
161 for x in samples:
162 self.failUnless(isinstance(x, Iterator), repr(x))
163 self.failUnless(issubclass(type(x), Iterator), repr(type(x)))
164
165 def test_Sized(self):
166 non_samples = [None, 42, 3.14, 1j,
167 (lambda: (yield))(),
168 (x for x in []),
169 ]
170 for x in non_samples:
171 self.failIf(isinstance(x, Sized), repr(x))
172 self.failIf(issubclass(type(x), Sized), repr(type(x)))
Guido van Rossum07d4e782007-07-03 16:59:47 +0000173 samples = [bytes(), str(),
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000174 tuple(), list(), set(), frozenset(), dict(),
175 dict().keys(), dict().items(), dict().values(),
176 ]
177 for x in samples:
178 self.failUnless(isinstance(x, Sized), repr(x))
179 self.failUnless(issubclass(type(x), Sized), repr(type(x)))
180
181 def test_Container(self):
182 non_samples = [None, 42, 3.14, 1j,
183 (lambda: (yield))(),
184 (x for x in []),
185 ]
186 for x in non_samples:
187 self.failIf(isinstance(x, Container), repr(x))
188 self.failIf(issubclass(type(x), Container), repr(type(x)))
Guido van Rossum07d4e782007-07-03 16:59:47 +0000189 samples = [bytes(), str(),
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000190 tuple(), list(), set(), frozenset(), dict(),
191 dict().keys(), dict().items(),
192 ]
193 for x in samples:
194 self.failUnless(isinstance(x, Container), repr(x))
195 self.failUnless(issubclass(type(x), Container), repr(type(x)))
196
197 def test_Callable(self):
198 non_samples = [None, 42, 3.14, 1j,
199 "", b"", (), [], {}, set(),
200 (lambda: (yield))(),
201 (x for x in []),
202 ]
203 for x in non_samples:
204 self.failIf(isinstance(x, Callable), repr(x))
205 self.failIf(issubclass(type(x), Callable), repr(type(x)))
206 samples = [lambda: None,
207 type, int, object,
208 len,
209 list.append, [].append,
210 ]
211 for x in samples:
212 self.failUnless(isinstance(x, Callable), repr(x))
213 self.failUnless(issubclass(type(x), Callable), repr(type(x)))
214
215 def test_direct_subclassing(self):
216 for B in Hashable, Iterable, Iterator, Sized, Container, Callable:
217 class C(B):
218 pass
219 self.failUnless(issubclass(C, B))
220 self.failIf(issubclass(int, C))
221
222 def test_registration(self):
223 for B in Hashable, Iterable, Iterator, Sized, Container, Callable:
224 class C:
225 __hash__ = None # Make sure it isn't hashable by default
226 self.failIf(issubclass(C, B), B.__name__)
227 B.register(C)
228 self.failUnless(issubclass(C, B))
229
230
231class TestCollectionABCs(unittest.TestCase):
232
233 # XXX For now, we only test some virtual inheritance properties.
234 # We should also test the proper behavior of the collection ABCs
235 # as real base classes or mix-in classes.
236
237 def test_Set(self):
238 for sample in [set, frozenset]:
239 self.failUnless(isinstance(sample(), Set))
240 self.failUnless(issubclass(sample, Set))
241
242 def test_MutableSet(self):
243 self.failUnless(isinstance(set(), MutableSet))
244 self.failUnless(issubclass(set, MutableSet))
245 self.failIf(isinstance(frozenset(), MutableSet))
246 self.failIf(issubclass(frozenset, MutableSet))
247
248 def test_Mapping(self):
249 for sample in [dict]:
250 self.failUnless(isinstance(sample(), Mapping))
251 self.failUnless(issubclass(sample, Mapping))
252
253 def test_MutableMapping(self):
254 for sample in [dict]:
255 self.failUnless(isinstance(sample(), MutableMapping))
256 self.failUnless(issubclass(sample, MutableMapping))
257
258 def test_Sequence(self):
259 for sample in [tuple, list, bytes, str]:
260 self.failUnless(isinstance(sample(), Sequence))
261 self.failUnless(issubclass(sample, Sequence))
Guido van Rossum3172c5d2007-10-16 18:12:55 +0000262 self.failUnless(issubclass(str, Sequence))
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000263
Guido van Rossumd05eb002007-11-21 22:26:24 +0000264 def test_ByteString(self):
265 for sample in [bytes, bytearray]:
266 self.failUnless(isinstance(sample(), ByteString))
267 self.failUnless(issubclass(sample, ByteString))
268 for sample in [str, list, tuple]:
269 self.failIf(isinstance(sample(), ByteString))
270 self.failIf(issubclass(sample, ByteString))
271 self.failIf(isinstance(memoryview(b""), ByteString))
272 self.failIf(issubclass(memoryview, ByteString))
273
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000274 def test_MutableSequence(self):
Guido van Rossumd05eb002007-11-21 22:26:24 +0000275 for sample in [tuple, str, bytes]:
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000276 self.failIf(isinstance(sample(), MutableSequence))
277 self.failIf(issubclass(sample, MutableSequence))
Guido van Rossumd05eb002007-11-21 22:26:24 +0000278 for sample in [list, bytearray]:
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000279 self.failUnless(isinstance(sample(), MutableSequence))
280 self.failUnless(issubclass(sample, MutableSequence))
Guido van Rossum3172c5d2007-10-16 18:12:55 +0000281 self.failIf(issubclass(str, MutableSequence))
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000282
283
Guido van Rossumd8faa362007-04-27 19:54:29 +0000284def test_main(verbose=None):
Guido van Rossumd59da4b2007-05-22 18:11:13 +0000285 import collections as CollectionsModule
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000286 test_classes = [TestNamedTuple, TestOneTrickPonyABCs, TestCollectionABCs]
Guido van Rossumd8faa362007-04-27 19:54:29 +0000287 test_support.run_unittest(*test_classes)
Guido van Rossumd59da4b2007-05-22 18:11:13 +0000288 test_support.run_doctest(CollectionsModule, verbose)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000289
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000290
Guido van Rossumd8faa362007-04-27 19:54:29 +0000291if __name__ == "__main__":
292 test_main(verbose=True)