blob: 5a4029d356579e1004b425d38cc80630f0995bd3 [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
Christian Heimes0449f632007-12-15 01:27:15 +000031 self.assertRaises(ValueError, namedtuple, 'abc', '_efg ghi') # field with leading underscore
Guido van Rossum8ce8a782007-11-01 19:42:39 +000032 self.assertRaises(ValueError, namedtuple, 'abc', 'efg efg ghi') # duplicate field
33
34 namedtuple('Point0', 'x1 y2') # Verify that numbers are allowed in names
Christian Heimes0449f632007-12-15 01:27:15 +000035 namedtuple('_', 'a b c') # Test leading underscores in a typename
Guido van Rossumd8faa362007-04-27 19:54:29 +000036
37 def test_instance(self):
Guido van Rossum8ce8a782007-11-01 19:42:39 +000038 Point = namedtuple('Point', 'x y')
Guido van Rossumd8faa362007-04-27 19:54:29 +000039 p = Point(11, 22)
40 self.assertEqual(p, Point(x=11, y=22))
41 self.assertEqual(p, Point(11, y=22))
42 self.assertEqual(p, Point(y=22, x=11))
43 self.assertEqual(p, Point(*(11, 22)))
44 self.assertEqual(p, Point(**dict(x=11, y=22)))
45 self.assertRaises(TypeError, Point, 1) # too few args
46 self.assertRaises(TypeError, Point, 1, 2, 3) # too many args
47 self.assertRaises(TypeError, eval, 'Point(XXX=1, y=2)', locals()) # wrong keyword argument
48 self.assertRaises(TypeError, eval, 'Point(x=1)', locals()) # missing keyword argument
49 self.assertEqual(repr(p), 'Point(x=11, y=22)')
50 self.assert_('__dict__' not in dir(p)) # verify instance has no dict
51 self.assert_('__weakref__' not in dir(p))
Christian Heimes0449f632007-12-15 01:27:15 +000052 self.assertEqual(p._fields, ('x', 'y')) # test _fields attribute
53 self.assertEqual(p._replace(x=1), (1, 22)) # test _replace method
54 self.assertEqual(p._asdict(), dict(x=11, y=22)) # test _asdict method
Thomas Wouters1b7f8912007-09-19 03:06:30 +000055
Christian Heimes0449f632007-12-15 01:27:15 +000056 # Verify that _fields is read-only
Guido van Rossum3d392eb2007-11-16 00:35:22 +000057 try:
Christian Heimes0449f632007-12-15 01:27:15 +000058 p._fields = ('F1' ,'F2')
Guido van Rossum3d392eb2007-11-16 00:35:22 +000059 except AttributeError:
60 pass
61 else:
Christian Heimes0449f632007-12-15 01:27:15 +000062 self.fail('The _fields attribute needs to be read-only')
Guido van Rossum3d392eb2007-11-16 00:35:22 +000063
Thomas Wouters1b7f8912007-09-19 03:06:30 +000064 # verify that field string can have commas
Guido van Rossum8ce8a782007-11-01 19:42:39 +000065 Point = namedtuple('Point', 'x, y')
66 p = Point(x=11, y=22)
67 self.assertEqual(repr(p), 'Point(x=11, y=22)')
68
69 # verify that fieldspec can be a non-string sequence
70 Point = namedtuple('Point', ('x', 'y'))
Thomas Wouters1b7f8912007-09-19 03:06:30 +000071 p = Point(x=11, y=22)
72 self.assertEqual(repr(p), 'Point(x=11, y=22)')
Guido van Rossumd8faa362007-04-27 19:54:29 +000073
74 def test_tupleness(self):
Guido van Rossum8ce8a782007-11-01 19:42:39 +000075 Point = namedtuple('Point', 'x y')
Guido van Rossumd8faa362007-04-27 19:54:29 +000076 p = Point(11, 22)
77
78 self.assert_(isinstance(p, tuple))
79 self.assertEqual(p, (11, 22)) # matches a real tuple
80 self.assertEqual(tuple(p), (11, 22)) # coercable to a real tuple
81 self.assertEqual(list(p), [11, 22]) # coercable to a list
82 self.assertEqual(max(p), 22) # iterable
83 self.assertEqual(max(*p), 22) # star-able
84 x, y = p
85 self.assertEqual(p, (x, y)) # unpacks like a tuple
86 self.assertEqual((p[0], p[1]), (11, 22)) # indexable like a tuple
87 self.assertRaises(IndexError, p.__getitem__, 3)
88
89 self.assertEqual(p.x, x)
90 self.assertEqual(p.y, y)
91 self.assertRaises(AttributeError, eval, 'p.z', locals())
92
Thomas Wouters1b7f8912007-09-19 03:06:30 +000093 def test_odd_sizes(self):
Guido van Rossum8ce8a782007-11-01 19:42:39 +000094 Zero = namedtuple('Zero', '')
Thomas Wouters1b7f8912007-09-19 03:06:30 +000095 self.assertEqual(Zero(), ())
Guido van Rossum8ce8a782007-11-01 19:42:39 +000096 Dot = namedtuple('Dot', 'd')
Thomas Wouters1b7f8912007-09-19 03:06:30 +000097 self.assertEqual(Dot(1), (1,))
98
Guido van Rossumd8faa362007-04-27 19:54:29 +000099
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000100class TestOneTrickPonyABCs(unittest.TestCase):
101
102 def test_Hashable(self):
103 # Check some non-hashables
Guido van Rossum254348e2007-11-21 19:29:53 +0000104 non_samples = [bytearray(), list(), set(), dict()]
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000105 for x in non_samples:
106 self.failIf(isinstance(x, Hashable), repr(x))
107 self.failIf(issubclass(type(x), Hashable), repr(type(x)))
108 # Check some hashables
109 samples = [None,
110 int(), float(), complex(),
Guido van Rossum07d4e782007-07-03 16:59:47 +0000111 str(),
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000112 tuple(), frozenset(),
Guido van Rossum98297ee2007-11-06 21:34:58 +0000113 int, list, object, type, bytes()
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000114 ]
115 for x in samples:
116 self.failUnless(isinstance(x, Hashable), repr(x))
117 self.failUnless(issubclass(type(x), Hashable), repr(type(x)))
118 self.assertRaises(TypeError, Hashable)
119 # Check direct subclassing
120 class H(Hashable):
121 def __hash__(self):
122 return super().__hash__()
123 self.assertEqual(hash(H()), 0)
124 self.failIf(issubclass(int, H))
125
126 def test_Iterable(self):
127 # Check some non-iterables
128 non_samples = [None, 42, 3.14, 1j]
129 for x in non_samples:
130 self.failIf(isinstance(x, Iterable), repr(x))
131 self.failIf(issubclass(type(x), Iterable), repr(type(x)))
132 # Check some iterables
Guido van Rossum07d4e782007-07-03 16:59:47 +0000133 samples = [bytes(), str(),
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000134 tuple(), list(), set(), frozenset(), dict(),
135 dict().keys(), dict().items(), dict().values(),
136 (lambda: (yield))(),
137 (x for x in []),
138 ]
139 for x in samples:
140 self.failUnless(isinstance(x, Iterable), repr(x))
141 self.failUnless(issubclass(type(x), Iterable), repr(type(x)))
142 # Check direct subclassing
143 class I(Iterable):
144 def __iter__(self):
145 return super().__iter__()
146 self.assertEqual(list(I()), [])
147 self.failIf(issubclass(str, I))
148
149 def test_Iterator(self):
Guido van Rossum07d4e782007-07-03 16:59:47 +0000150 non_samples = [None, 42, 3.14, 1j, b"", "", (), [], {}, set()]
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000151 for x in non_samples:
152 self.failIf(isinstance(x, Iterator), repr(x))
153 self.failIf(issubclass(type(x), Iterator), repr(type(x)))
Guido van Rossum07d4e782007-07-03 16:59:47 +0000154 samples = [iter(bytes()), iter(str()),
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000155 iter(tuple()), iter(list()), iter(dict()),
156 iter(set()), iter(frozenset()),
157 iter(dict().keys()), iter(dict().items()),
158 iter(dict().values()),
159 (lambda: (yield))(),
160 (x for x in []),
161 ]
162 for x in samples:
163 self.failUnless(isinstance(x, Iterator), repr(x))
164 self.failUnless(issubclass(type(x), Iterator), repr(type(x)))
165
166 def test_Sized(self):
167 non_samples = [None, 42, 3.14, 1j,
168 (lambda: (yield))(),
169 (x for x in []),
170 ]
171 for x in non_samples:
172 self.failIf(isinstance(x, Sized), repr(x))
173 self.failIf(issubclass(type(x), Sized), repr(type(x)))
Guido van Rossum07d4e782007-07-03 16:59:47 +0000174 samples = [bytes(), str(),
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000175 tuple(), list(), set(), frozenset(), dict(),
176 dict().keys(), dict().items(), dict().values(),
177 ]
178 for x in samples:
179 self.failUnless(isinstance(x, Sized), repr(x))
180 self.failUnless(issubclass(type(x), Sized), repr(type(x)))
181
182 def test_Container(self):
183 non_samples = [None, 42, 3.14, 1j,
184 (lambda: (yield))(),
185 (x for x in []),
186 ]
187 for x in non_samples:
188 self.failIf(isinstance(x, Container), repr(x))
189 self.failIf(issubclass(type(x), Container), repr(type(x)))
Guido van Rossum07d4e782007-07-03 16:59:47 +0000190 samples = [bytes(), str(),
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000191 tuple(), list(), set(), frozenset(), dict(),
192 dict().keys(), dict().items(),
193 ]
194 for x in samples:
195 self.failUnless(isinstance(x, Container), repr(x))
196 self.failUnless(issubclass(type(x), Container), repr(type(x)))
197
198 def test_Callable(self):
199 non_samples = [None, 42, 3.14, 1j,
200 "", b"", (), [], {}, set(),
201 (lambda: (yield))(),
202 (x for x in []),
203 ]
204 for x in non_samples:
205 self.failIf(isinstance(x, Callable), repr(x))
206 self.failIf(issubclass(type(x), Callable), repr(type(x)))
207 samples = [lambda: None,
208 type, int, object,
209 len,
210 list.append, [].append,
211 ]
212 for x in samples:
213 self.failUnless(isinstance(x, Callable), repr(x))
214 self.failUnless(issubclass(type(x), Callable), repr(type(x)))
215
216 def test_direct_subclassing(self):
217 for B in Hashable, Iterable, Iterator, Sized, Container, Callable:
218 class C(B):
219 pass
220 self.failUnless(issubclass(C, B))
221 self.failIf(issubclass(int, C))
222
223 def test_registration(self):
224 for B in Hashable, Iterable, Iterator, Sized, Container, Callable:
225 class C:
226 __hash__ = None # Make sure it isn't hashable by default
227 self.failIf(issubclass(C, B), B.__name__)
228 B.register(C)
229 self.failUnless(issubclass(C, B))
230
231
232class TestCollectionABCs(unittest.TestCase):
233
234 # XXX For now, we only test some virtual inheritance properties.
235 # We should also test the proper behavior of the collection ABCs
236 # as real base classes or mix-in classes.
237
238 def test_Set(self):
239 for sample in [set, frozenset]:
240 self.failUnless(isinstance(sample(), Set))
241 self.failUnless(issubclass(sample, Set))
242
243 def test_MutableSet(self):
244 self.failUnless(isinstance(set(), MutableSet))
245 self.failUnless(issubclass(set, MutableSet))
246 self.failIf(isinstance(frozenset(), MutableSet))
247 self.failIf(issubclass(frozenset, MutableSet))
248
249 def test_Mapping(self):
250 for sample in [dict]:
251 self.failUnless(isinstance(sample(), Mapping))
252 self.failUnless(issubclass(sample, Mapping))
253
254 def test_MutableMapping(self):
255 for sample in [dict]:
256 self.failUnless(isinstance(sample(), MutableMapping))
257 self.failUnless(issubclass(sample, MutableMapping))
258
259 def test_Sequence(self):
260 for sample in [tuple, list, bytes, str]:
261 self.failUnless(isinstance(sample(), Sequence))
262 self.failUnless(issubclass(sample, Sequence))
Guido van Rossum3172c5d2007-10-16 18:12:55 +0000263 self.failUnless(issubclass(str, Sequence))
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000264
Guido van Rossumd05eb002007-11-21 22:26:24 +0000265 def test_ByteString(self):
266 for sample in [bytes, bytearray]:
267 self.failUnless(isinstance(sample(), ByteString))
268 self.failUnless(issubclass(sample, ByteString))
269 for sample in [str, list, tuple]:
270 self.failIf(isinstance(sample(), ByteString))
271 self.failIf(issubclass(sample, ByteString))
272 self.failIf(isinstance(memoryview(b""), ByteString))
273 self.failIf(issubclass(memoryview, ByteString))
274
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000275 def test_MutableSequence(self):
Guido van Rossumd05eb002007-11-21 22:26:24 +0000276 for sample in [tuple, str, bytes]:
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000277 self.failIf(isinstance(sample(), MutableSequence))
278 self.failIf(issubclass(sample, MutableSequence))
Guido van Rossumd05eb002007-11-21 22:26:24 +0000279 for sample in [list, bytearray]:
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000280 self.failUnless(isinstance(sample(), MutableSequence))
281 self.failUnless(issubclass(sample, MutableSequence))
Guido van Rossum3172c5d2007-10-16 18:12:55 +0000282 self.failIf(issubclass(str, MutableSequence))
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000283
284
Guido van Rossumd8faa362007-04-27 19:54:29 +0000285def test_main(verbose=None):
Guido van Rossumd59da4b2007-05-22 18:11:13 +0000286 import collections as CollectionsModule
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000287 test_classes = [TestNamedTuple, TestOneTrickPonyABCs, TestCollectionABCs]
Guido van Rossumd8faa362007-04-27 19:54:29 +0000288 test_support.run_unittest(*test_classes)
Guido van Rossumd59da4b2007-05-22 18:11:13 +0000289 test_support.run_doctest(CollectionsModule, verbose)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000290
Guido van Rossumcd16bf62007-06-13 18:07:49 +0000291
Guido van Rossumd8faa362007-04-27 19:54:29 +0000292if __name__ == "__main__":
293 test_main(verbose=True)