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