blob: 93847444fe2307e44bb1c89fe0388d97cd395cd0 [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
Guido van Rossumd8faa362007-04-27 19:54:29 +00004from 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__)
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
117 names = [''.join([random.choice(string.ascii_letters) for j in range(10)]) for i in range(n)]
118 Big = namedtuple('Big', names)
119 b = Big(*range(n))
120 self.assertEqual(b, tuple(range(n)))
Christian Heimesfaf2f632008-01-06 16:59:19 +0000121 self.assertEqual(Big._make(range(n)), tuple(range(n)))
Christian Heimes99170a52007-12-19 02:07:34 +0000122 for pos, name in enumerate(names):
123 self.assertEqual(getattr(b, name), pos)
124 repr(b) # make sure repr() doesn't blow-up
125 d = b._asdict()
126 d_expected = dict(zip(names, range(n)))
127 self.assertEqual(d, d_expected)
128 b2 = b._replace(**dict([(names[1], 999),(names[-5], 42)]))
129 b2_expected = list(range(n))
130 b2_expected[1] = 999
131 b2_expected[-5] = 42
132 self.assertEqual(b2, tuple(b2_expected))
133 self.assertEqual(b._fields, tuple(names))
Guido van Rossumd8faa362007-04-27 19:54:29 +0000134
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000135class TestOneTrickPonyABCs(unittest.TestCase):
136
137 def test_Hashable(self):
138 # Check some non-hashables
Guido van Rossum254348e2007-11-21 19:29:53 +0000139 non_samples = [bytearray(), list(), set(), dict()]
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000140 for x in non_samples:
141 self.failIf(isinstance(x, Hashable), repr(x))
142 self.failIf(issubclass(type(x), Hashable), repr(type(x)))
143 # Check some hashables
144 samples = [None,
145 int(), float(), complex(),
Guido van Rossum07d4e782007-07-03 16:59:47 +0000146 str(),
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000147 tuple(), frozenset(),
Guido van Rossum98297ee2007-11-06 21:34:58 +0000148 int, list, object, type, bytes()
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000149 ]
150 for x in samples:
151 self.failUnless(isinstance(x, Hashable), repr(x))
152 self.failUnless(issubclass(type(x), Hashable), repr(type(x)))
153 self.assertRaises(TypeError, Hashable)
154 # Check direct subclassing
155 class H(Hashable):
156 def __hash__(self):
157 return super().__hash__()
158 self.assertEqual(hash(H()), 0)
159 self.failIf(issubclass(int, H))
160
161 def test_Iterable(self):
162 # Check some non-iterables
163 non_samples = [None, 42, 3.14, 1j]
164 for x in non_samples:
165 self.failIf(isinstance(x, Iterable), repr(x))
166 self.failIf(issubclass(type(x), Iterable), repr(type(x)))
167 # Check some iterables
Guido van Rossum07d4e782007-07-03 16:59:47 +0000168 samples = [bytes(), str(),
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000169 tuple(), list(), set(), frozenset(), dict(),
170 dict().keys(), dict().items(), dict().values(),
171 (lambda: (yield))(),
172 (x for x in []),
173 ]
174 for x in samples:
175 self.failUnless(isinstance(x, Iterable), repr(x))
176 self.failUnless(issubclass(type(x), Iterable), repr(type(x)))
177 # Check direct subclassing
178 class I(Iterable):
179 def __iter__(self):
180 return super().__iter__()
181 self.assertEqual(list(I()), [])
182 self.failIf(issubclass(str, I))
183
184 def test_Iterator(self):
Guido van Rossum07d4e782007-07-03 16:59:47 +0000185 non_samples = [None, 42, 3.14, 1j, b"", "", (), [], {}, set()]
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000186 for x in non_samples:
187 self.failIf(isinstance(x, Iterator), repr(x))
188 self.failIf(issubclass(type(x), Iterator), repr(type(x)))
Guido van Rossum07d4e782007-07-03 16:59:47 +0000189 samples = [iter(bytes()), iter(str()),
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000190 iter(tuple()), iter(list()), iter(dict()),
191 iter(set()), iter(frozenset()),
192 iter(dict().keys()), iter(dict().items()),
193 iter(dict().values()),
194 (lambda: (yield))(),
195 (x for x in []),
196 ]
197 for x in samples:
198 self.failUnless(isinstance(x, Iterator), repr(x))
199 self.failUnless(issubclass(type(x), Iterator), repr(type(x)))
200
201 def test_Sized(self):
202 non_samples = [None, 42, 3.14, 1j,
203 (lambda: (yield))(),
204 (x for x in []),
205 ]
206 for x in non_samples:
207 self.failIf(isinstance(x, Sized), repr(x))
208 self.failIf(issubclass(type(x), Sized), repr(type(x)))
Guido van Rossum07d4e782007-07-03 16:59:47 +0000209 samples = [bytes(), str(),
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000210 tuple(), list(), set(), frozenset(), dict(),
211 dict().keys(), dict().items(), dict().values(),
212 ]
213 for x in samples:
214 self.failUnless(isinstance(x, Sized), repr(x))
215 self.failUnless(issubclass(type(x), Sized), repr(type(x)))
216
217 def test_Container(self):
218 non_samples = [None, 42, 3.14, 1j,
219 (lambda: (yield))(),
220 (x for x in []),
221 ]
222 for x in non_samples:
223 self.failIf(isinstance(x, Container), repr(x))
224 self.failIf(issubclass(type(x), Container), repr(type(x)))
Guido van Rossum07d4e782007-07-03 16:59:47 +0000225 samples = [bytes(), str(),
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000226 tuple(), list(), set(), frozenset(), dict(),
227 dict().keys(), dict().items(),
228 ]
229 for x in samples:
230 self.failUnless(isinstance(x, Container), repr(x))
231 self.failUnless(issubclass(type(x), Container), repr(type(x)))
232
233 def test_Callable(self):
234 non_samples = [None, 42, 3.14, 1j,
235 "", b"", (), [], {}, set(),
236 (lambda: (yield))(),
237 (x for x in []),
238 ]
239 for x in non_samples:
240 self.failIf(isinstance(x, Callable), repr(x))
241 self.failIf(issubclass(type(x), Callable), repr(type(x)))
242 samples = [lambda: None,
243 type, int, object,
244 len,
245 list.append, [].append,
246 ]
247 for x in samples:
248 self.failUnless(isinstance(x, Callable), repr(x))
249 self.failUnless(issubclass(type(x), Callable), repr(type(x)))
250
251 def test_direct_subclassing(self):
252 for B in Hashable, Iterable, Iterator, Sized, Container, Callable:
253 class C(B):
254 pass
255 self.failUnless(issubclass(C, B))
256 self.failIf(issubclass(int, C))
257
258 def test_registration(self):
259 for B in Hashable, Iterable, Iterator, Sized, Container, Callable:
260 class C:
261 __hash__ = None # Make sure it isn't hashable by default
262 self.failIf(issubclass(C, B), B.__name__)
263 B.register(C)
264 self.failUnless(issubclass(C, B))
265
266
267class TestCollectionABCs(unittest.TestCase):
268
269 # XXX For now, we only test some virtual inheritance properties.
270 # We should also test the proper behavior of the collection ABCs
271 # as real base classes or mix-in classes.
272
273 def test_Set(self):
274 for sample in [set, frozenset]:
275 self.failUnless(isinstance(sample(), Set))
276 self.failUnless(issubclass(sample, Set))
277
278 def test_MutableSet(self):
279 self.failUnless(isinstance(set(), MutableSet))
280 self.failUnless(issubclass(set, MutableSet))
281 self.failIf(isinstance(frozenset(), MutableSet))
282 self.failIf(issubclass(frozenset, MutableSet))
283
284 def test_Mapping(self):
285 for sample in [dict]:
286 self.failUnless(isinstance(sample(), Mapping))
287 self.failUnless(issubclass(sample, Mapping))
288
289 def test_MutableMapping(self):
290 for sample in [dict]:
291 self.failUnless(isinstance(sample(), MutableMapping))
292 self.failUnless(issubclass(sample, MutableMapping))
293
294 def test_Sequence(self):
295 for sample in [tuple, list, bytes, str]:
296 self.failUnless(isinstance(sample(), Sequence))
297 self.failUnless(issubclass(sample, Sequence))
Guido van Rossum3172c5d2007-10-16 18:12:55 +0000298 self.failUnless(issubclass(str, Sequence))
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000299
Guido van Rossumd05eb002007-11-21 22:26:24 +0000300 def test_ByteString(self):
301 for sample in [bytes, bytearray]:
302 self.failUnless(isinstance(sample(), ByteString))
303 self.failUnless(issubclass(sample, ByteString))
304 for sample in [str, list, tuple]:
305 self.failIf(isinstance(sample(), ByteString))
306 self.failIf(issubclass(sample, ByteString))
307 self.failIf(isinstance(memoryview(b""), ByteString))
308 self.failIf(issubclass(memoryview, ByteString))
309
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000310 def test_MutableSequence(self):
Guido van Rossumd05eb002007-11-21 22:26:24 +0000311 for sample in [tuple, str, bytes]:
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000312 self.failIf(isinstance(sample(), MutableSequence))
313 self.failIf(issubclass(sample, MutableSequence))
Guido van Rossumd05eb002007-11-21 22:26:24 +0000314 for sample in [list, bytearray]:
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000315 self.failUnless(isinstance(sample(), MutableSequence))
316 self.failUnless(issubclass(sample, MutableSequence))
Guido van Rossum3172c5d2007-10-16 18:12:55 +0000317 self.failIf(issubclass(str, MutableSequence))
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000318
Christian Heimes25bb7832008-01-11 16:17:00 +0000319import doctest, collections
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000320
Guido van Rossumd8faa362007-04-27 19:54:29 +0000321def test_main(verbose=None):
Benjamin Petersonad9d48d2008-04-02 21:49:44 +0000322 NamedTupleDocs = doctest.DocTestSuite(module=collections)
Christian Heimes25bb7832008-01-11 16:17:00 +0000323 test_classes = [TestNamedTuple, NamedTupleDocs, TestOneTrickPonyABCs, TestCollectionABCs]
Guido van Rossumd8faa362007-04-27 19:54:29 +0000324 test_support.run_unittest(*test_classes)
Benjamin Petersonad9d48d2008-04-02 21:49:44 +0000325 test_support.run_doctest(collections, verbose)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000326
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000327
Guido van Rossumd8faa362007-04-27 19:54:29 +0000328if __name__ == "__main__":
329 test_main(verbose=True)