blob: 4ed0e241655d67e3ded7e90b060abbe07a27afdf [file] [log] [blame]
Guido van Rossumcd16bf62007-06-13 18:07:49 +00001"""Unit tests for collections.py."""
2
Christian Heimes25bb7832008-01-11 16:17:00 +00003import unittest, doctest
Benjamin Petersonee8712c2008-05-20 21:35:26 +00004from test import 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__)
Christian Heimesfaf2f632008-01-06 16:59:19 +000023 self.assertEqual(Point._fields, ('x', 'y'))
Guido van Rossum8ce8a782007-11-01 19:42:39 +000024
25 self.assertRaises(ValueError, namedtuple, 'abc%', 'efg ghi') # type has non-alpha char
26 self.assertRaises(ValueError, namedtuple, 'class', 'efg ghi') # type has keyword
27 self.assertRaises(ValueError, namedtuple, '9abc', 'efg ghi') # type starts with digit
28
29 self.assertRaises(ValueError, namedtuple, 'abc', 'efg g%hi') # field with non-alpha char
30 self.assertRaises(ValueError, namedtuple, 'abc', 'abc class') # field has keyword
31 self.assertRaises(ValueError, namedtuple, 'abc', '8efg 9ghi') # field starts with digit
Christian Heimes0449f632007-12-15 01:27:15 +000032 self.assertRaises(ValueError, namedtuple, 'abc', '_efg ghi') # field with leading underscore
Guido van Rossum8ce8a782007-11-01 19:42:39 +000033 self.assertRaises(ValueError, namedtuple, 'abc', 'efg efg ghi') # duplicate field
34
35 namedtuple('Point0', 'x1 y2') # Verify that numbers are allowed in names
Christian Heimes0449f632007-12-15 01:27:15 +000036 namedtuple('_', 'a b c') # Test leading underscores in a typename
Guido van Rossumd8faa362007-04-27 19:54:29 +000037
Christian Heimesfaf2f632008-01-06 16:59:19 +000038 self.assertRaises(TypeError, Point._make, [11]) # catch too few args
39 self.assertRaises(TypeError, Point._make, [11, 22, 33]) # catch too many args
40
Guido van Rossumd8faa362007-04-27 19:54:29 +000041 def test_instance(self):
Guido van Rossum8ce8a782007-11-01 19:42:39 +000042 Point = namedtuple('Point', 'x y')
Guido van Rossumd8faa362007-04-27 19:54:29 +000043 p = Point(11, 22)
44 self.assertEqual(p, Point(x=11, y=22))
45 self.assertEqual(p, Point(11, y=22))
46 self.assertEqual(p, Point(y=22, x=11))
47 self.assertEqual(p, Point(*(11, 22)))
48 self.assertEqual(p, Point(**dict(x=11, y=22)))
49 self.assertRaises(TypeError, Point, 1) # too few args
50 self.assertRaises(TypeError, Point, 1, 2, 3) # too many args
51 self.assertRaises(TypeError, eval, 'Point(XXX=1, y=2)', locals()) # wrong keyword argument
52 self.assertRaises(TypeError, eval, 'Point(x=1)', locals()) # missing keyword argument
53 self.assertEqual(repr(p), 'Point(x=11, y=22)')
54 self.assert_('__dict__' not in dir(p)) # verify instance has no dict
55 self.assert_('__weakref__' not in dir(p))
Christian Heimesfaf2f632008-01-06 16:59:19 +000056 self.assertEqual(p, Point._make([11, 22])) # test _make classmethod
Christian Heimes0449f632007-12-15 01:27:15 +000057 self.assertEqual(p._fields, ('x', 'y')) # test _fields attribute
58 self.assertEqual(p._replace(x=1), (1, 22)) # test _replace method
59 self.assertEqual(p._asdict(), dict(x=11, y=22)) # test _asdict method
Thomas Wouters1b7f8912007-09-19 03:06:30 +000060
Guido van Rossum3d392eb2007-11-16 00:35:22 +000061 try:
Christian Heimesfaf2f632008-01-06 16:59:19 +000062 p._replace(x=1, error=2)
63 except ValueError:
Guido van Rossum3d392eb2007-11-16 00:35:22 +000064 pass
65 else:
Christian Heimesfaf2f632008-01-06 16:59:19 +000066 self._fail('Did not detect an incorrect fieldname')
Guido van Rossum3d392eb2007-11-16 00:35:22 +000067
Thomas Wouters1b7f8912007-09-19 03:06:30 +000068 # verify that field string can have commas
Guido van Rossum8ce8a782007-11-01 19:42:39 +000069 Point = namedtuple('Point', 'x, y')
70 p = Point(x=11, y=22)
71 self.assertEqual(repr(p), 'Point(x=11, y=22)')
72
73 # verify that fieldspec can be a non-string sequence
74 Point = namedtuple('Point', ('x', 'y'))
Thomas Wouters1b7f8912007-09-19 03:06:30 +000075 p = Point(x=11, y=22)
76 self.assertEqual(repr(p), 'Point(x=11, y=22)')
Guido van Rossumd8faa362007-04-27 19:54:29 +000077
78 def test_tupleness(self):
Guido van Rossum8ce8a782007-11-01 19:42:39 +000079 Point = namedtuple('Point', 'x y')
Guido van Rossumd8faa362007-04-27 19:54:29 +000080 p = Point(11, 22)
81
82 self.assert_(isinstance(p, tuple))
83 self.assertEqual(p, (11, 22)) # matches a real tuple
84 self.assertEqual(tuple(p), (11, 22)) # coercable to a real tuple
85 self.assertEqual(list(p), [11, 22]) # coercable to a list
86 self.assertEqual(max(p), 22) # iterable
87 self.assertEqual(max(*p), 22) # star-able
88 x, y = p
89 self.assertEqual(p, (x, y)) # unpacks like a tuple
90 self.assertEqual((p[0], p[1]), (11, 22)) # indexable like a tuple
91 self.assertRaises(IndexError, p.__getitem__, 3)
92
93 self.assertEqual(p.x, x)
94 self.assertEqual(p.y, y)
95 self.assertRaises(AttributeError, eval, 'p.z', locals())
96
Thomas Wouters1b7f8912007-09-19 03:06:30 +000097 def test_odd_sizes(self):
Guido van Rossum8ce8a782007-11-01 19:42:39 +000098 Zero = namedtuple('Zero', '')
Thomas Wouters1b7f8912007-09-19 03:06:30 +000099 self.assertEqual(Zero(), ())
Christian Heimesfaf2f632008-01-06 16:59:19 +0000100 self.assertEqual(Zero._make([]), ())
Christian Heimes99170a52007-12-19 02:07:34 +0000101 self.assertEqual(repr(Zero()), 'Zero()')
102 self.assertEqual(Zero()._asdict(), {})
103 self.assertEqual(Zero()._fields, ())
104
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000105 Dot = namedtuple('Dot', 'd')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000106 self.assertEqual(Dot(1), (1,))
Christian Heimesfaf2f632008-01-06 16:59:19 +0000107 self.assertEqual(Dot._make([1]), (1,))
Christian Heimes99170a52007-12-19 02:07:34 +0000108 self.assertEqual(Dot(1).d, 1)
109 self.assertEqual(repr(Dot(1)), 'Dot(d=1)')
110 self.assertEqual(Dot(1)._asdict(), {'d':1})
111 self.assertEqual(Dot(1)._replace(d=999), (999,))
112 self.assertEqual(Dot(1)._fields, ('d',))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000113
Christian Heimes99170a52007-12-19 02:07:34 +0000114 # n = 10000
115 n = 254 # SyntaxError: more than 255 arguments:
116 import string, random
Georg Brandlb533e262008-05-25 18:19:30 +0000117 names = list(set(''.join([random.choice(string.ascii_letters)
118 for j in range(10)]) for i in range(n)))
119 n = len(names)
Christian Heimes99170a52007-12-19 02:07:34 +0000120 Big = namedtuple('Big', names)
121 b = Big(*range(n))
122 self.assertEqual(b, tuple(range(n)))
Christian Heimesfaf2f632008-01-06 16:59:19 +0000123 self.assertEqual(Big._make(range(n)), tuple(range(n)))
Christian Heimes99170a52007-12-19 02:07:34 +0000124 for pos, name in enumerate(names):
125 self.assertEqual(getattr(b, name), pos)
126 repr(b) # make sure repr() doesn't blow-up
127 d = b._asdict()
128 d_expected = dict(zip(names, range(n)))
129 self.assertEqual(d, d_expected)
130 b2 = b._replace(**dict([(names[1], 999),(names[-5], 42)]))
131 b2_expected = list(range(n))
132 b2_expected[1] = 999
133 b2_expected[-5] = 42
134 self.assertEqual(b2, tuple(b2_expected))
135 self.assertEqual(b._fields, tuple(names))
Guido van Rossumd8faa362007-04-27 19:54:29 +0000136
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000137class TestOneTrickPonyABCs(unittest.TestCase):
138
139 def test_Hashable(self):
140 # Check some non-hashables
Guido van Rossum254348e2007-11-21 19:29:53 +0000141 non_samples = [bytearray(), list(), set(), dict()]
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000142 for x in non_samples:
143 self.failIf(isinstance(x, Hashable), repr(x))
144 self.failIf(issubclass(type(x), Hashable), repr(type(x)))
145 # Check some hashables
146 samples = [None,
147 int(), float(), complex(),
Guido van Rossum07d4e782007-07-03 16:59:47 +0000148 str(),
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000149 tuple(), frozenset(),
Guido van Rossum98297ee2007-11-06 21:34:58 +0000150 int, list, object, type, bytes()
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000151 ]
152 for x in samples:
153 self.failUnless(isinstance(x, Hashable), repr(x))
154 self.failUnless(issubclass(type(x), Hashable), repr(type(x)))
155 self.assertRaises(TypeError, Hashable)
156 # Check direct subclassing
157 class H(Hashable):
158 def __hash__(self):
159 return super().__hash__()
160 self.assertEqual(hash(H()), 0)
161 self.failIf(issubclass(int, H))
162
163 def test_Iterable(self):
164 # Check some non-iterables
165 non_samples = [None, 42, 3.14, 1j]
166 for x in non_samples:
167 self.failIf(isinstance(x, Iterable), repr(x))
168 self.failIf(issubclass(type(x), Iterable), repr(type(x)))
169 # Check some iterables
Guido van Rossum07d4e782007-07-03 16:59:47 +0000170 samples = [bytes(), str(),
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000171 tuple(), list(), set(), frozenset(), dict(),
172 dict().keys(), dict().items(), dict().values(),
173 (lambda: (yield))(),
174 (x for x in []),
175 ]
176 for x in samples:
177 self.failUnless(isinstance(x, Iterable), repr(x))
178 self.failUnless(issubclass(type(x), Iterable), repr(type(x)))
179 # Check direct subclassing
180 class I(Iterable):
181 def __iter__(self):
182 return super().__iter__()
183 self.assertEqual(list(I()), [])
184 self.failIf(issubclass(str, I))
185
186 def test_Iterator(self):
Guido van Rossum07d4e782007-07-03 16:59:47 +0000187 non_samples = [None, 42, 3.14, 1j, b"", "", (), [], {}, set()]
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000188 for x in non_samples:
189 self.failIf(isinstance(x, Iterator), repr(x))
190 self.failIf(issubclass(type(x), Iterator), repr(type(x)))
Guido van Rossum07d4e782007-07-03 16:59:47 +0000191 samples = [iter(bytes()), iter(str()),
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000192 iter(tuple()), iter(list()), iter(dict()),
193 iter(set()), iter(frozenset()),
194 iter(dict().keys()), iter(dict().items()),
195 iter(dict().values()),
196 (lambda: (yield))(),
197 (x for x in []),
198 ]
199 for x in samples:
200 self.failUnless(isinstance(x, Iterator), repr(x))
201 self.failUnless(issubclass(type(x), Iterator), repr(type(x)))
202
203 def test_Sized(self):
204 non_samples = [None, 42, 3.14, 1j,
205 (lambda: (yield))(),
206 (x for x in []),
207 ]
208 for x in non_samples:
209 self.failIf(isinstance(x, Sized), repr(x))
210 self.failIf(issubclass(type(x), Sized), repr(type(x)))
Guido van Rossum07d4e782007-07-03 16:59:47 +0000211 samples = [bytes(), str(),
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000212 tuple(), list(), set(), frozenset(), dict(),
213 dict().keys(), dict().items(), dict().values(),
214 ]
215 for x in samples:
216 self.failUnless(isinstance(x, Sized), repr(x))
217 self.failUnless(issubclass(type(x), Sized), repr(type(x)))
218
219 def test_Container(self):
220 non_samples = [None, 42, 3.14, 1j,
221 (lambda: (yield))(),
222 (x for x in []),
223 ]
224 for x in non_samples:
225 self.failIf(isinstance(x, Container), repr(x))
226 self.failIf(issubclass(type(x), Container), repr(type(x)))
Guido van Rossum07d4e782007-07-03 16:59:47 +0000227 samples = [bytes(), str(),
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000228 tuple(), list(), set(), frozenset(), dict(),
229 dict().keys(), dict().items(),
230 ]
231 for x in samples:
232 self.failUnless(isinstance(x, Container), repr(x))
233 self.failUnless(issubclass(type(x), Container), repr(type(x)))
234
235 def test_Callable(self):
236 non_samples = [None, 42, 3.14, 1j,
237 "", b"", (), [], {}, set(),
238 (lambda: (yield))(),
239 (x for x in []),
240 ]
241 for x in non_samples:
242 self.failIf(isinstance(x, Callable), repr(x))
243 self.failIf(issubclass(type(x), Callable), repr(type(x)))
244 samples = [lambda: None,
245 type, int, object,
246 len,
247 list.append, [].append,
248 ]
249 for x in samples:
250 self.failUnless(isinstance(x, Callable), repr(x))
251 self.failUnless(issubclass(type(x), Callable), repr(type(x)))
252
253 def test_direct_subclassing(self):
254 for B in Hashable, Iterable, Iterator, Sized, Container, Callable:
255 class C(B):
256 pass
257 self.failUnless(issubclass(C, B))
258 self.failIf(issubclass(int, C))
259
260 def test_registration(self):
261 for B in Hashable, Iterable, Iterator, Sized, Container, Callable:
262 class C:
263 __hash__ = None # Make sure it isn't hashable by default
264 self.failIf(issubclass(C, B), B.__name__)
265 B.register(C)
266 self.failUnless(issubclass(C, B))
267
268
269class TestCollectionABCs(unittest.TestCase):
270
271 # XXX For now, we only test some virtual inheritance properties.
272 # We should also test the proper behavior of the collection ABCs
273 # as real base classes or mix-in classes.
274
275 def test_Set(self):
276 for sample in [set, frozenset]:
277 self.failUnless(isinstance(sample(), Set))
278 self.failUnless(issubclass(sample, Set))
279
280 def test_MutableSet(self):
281 self.failUnless(isinstance(set(), MutableSet))
282 self.failUnless(issubclass(set, MutableSet))
283 self.failIf(isinstance(frozenset(), MutableSet))
284 self.failIf(issubclass(frozenset, MutableSet))
285
286 def test_Mapping(self):
287 for sample in [dict]:
288 self.failUnless(isinstance(sample(), Mapping))
289 self.failUnless(issubclass(sample, Mapping))
290
291 def test_MutableMapping(self):
292 for sample in [dict]:
293 self.failUnless(isinstance(sample(), MutableMapping))
294 self.failUnless(issubclass(sample, MutableMapping))
295
296 def test_Sequence(self):
297 for sample in [tuple, list, bytes, str]:
298 self.failUnless(isinstance(sample(), Sequence))
299 self.failUnless(issubclass(sample, Sequence))
Guido van Rossum3172c5d2007-10-16 18:12:55 +0000300 self.failUnless(issubclass(str, Sequence))
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000301
Guido van Rossumd05eb002007-11-21 22:26:24 +0000302 def test_ByteString(self):
303 for sample in [bytes, bytearray]:
304 self.failUnless(isinstance(sample(), ByteString))
305 self.failUnless(issubclass(sample, ByteString))
306 for sample in [str, list, tuple]:
307 self.failIf(isinstance(sample(), ByteString))
308 self.failIf(issubclass(sample, ByteString))
309 self.failIf(isinstance(memoryview(b""), ByteString))
310 self.failIf(issubclass(memoryview, ByteString))
311
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000312 def test_MutableSequence(self):
Guido van Rossumd05eb002007-11-21 22:26:24 +0000313 for sample in [tuple, str, bytes]:
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000314 self.failIf(isinstance(sample(), MutableSequence))
315 self.failIf(issubclass(sample, MutableSequence))
Guido van Rossumd05eb002007-11-21 22:26:24 +0000316 for sample in [list, bytearray]:
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000317 self.failUnless(isinstance(sample(), MutableSequence))
318 self.failUnless(issubclass(sample, MutableSequence))
Guido van Rossum3172c5d2007-10-16 18:12:55 +0000319 self.failIf(issubclass(str, MutableSequence))
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000320
Christian Heimes25bb7832008-01-11 16:17:00 +0000321import doctest, collections
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000322
Guido van Rossumd8faa362007-04-27 19:54:29 +0000323def test_main(verbose=None):
Benjamin Petersonad9d48d2008-04-02 21:49:44 +0000324 NamedTupleDocs = doctest.DocTestSuite(module=collections)
Christian Heimes25bb7832008-01-11 16:17:00 +0000325 test_classes = [TestNamedTuple, NamedTupleDocs, TestOneTrickPonyABCs, TestCollectionABCs]
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000326 support.run_unittest(*test_classes)
327 support.run_doctest(collections, verbose)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000328
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000329
Guido van Rossumd8faa362007-04-27 19:54:29 +0000330if __name__ == "__main__":
331 test_main(verbose=True)