blob: d6cfe9b2067f7db29dd2d4f80d29d46731c2e244 [file] [log] [blame]
Raymond Hettingerc37e5e02007-03-01 06:16:43 +00001import unittest
2from test import test_support
Raymond Hettinger01a09572007-10-23 20:37:41 +00003from collections import namedtuple
Guido van Rossum64c06e32007-11-22 00:55:51 +00004from collections import Hashable, Iterable, Iterator
5from collections import Sized, Container, Callable
6from collections import Set, MutableSet
7from collections import Mapping, MutableMapping
8from collections import Sequence, MutableSequence
9
Raymond Hettingerc37e5e02007-03-01 06:16:43 +000010
11class TestNamedTuple(unittest.TestCase):
12
13 def test_factory(self):
Raymond Hettinger01a09572007-10-23 20:37:41 +000014 Point = namedtuple('Point', 'x y')
Raymond Hettingerc37e5e02007-03-01 06:16:43 +000015 self.assertEqual(Point.__name__, 'Point')
16 self.assertEqual(Point.__doc__, 'Point(x, y)')
17 self.assertEqual(Point.__slots__, ())
18 self.assertEqual(Point.__module__, __name__)
19 self.assertEqual(Point.__getitem__, tuple.__getitem__)
Raymond Hettingerabfd8df2007-10-16 21:28:32 +000020
Raymond Hettinger01a09572007-10-23 20:37:41 +000021 self.assertRaises(ValueError, namedtuple, 'abc%', 'efg ghi') # type has non-alpha char
22 self.assertRaises(ValueError, namedtuple, 'class', 'efg ghi') # type has keyword
23 self.assertRaises(ValueError, namedtuple, '9abc', 'efg ghi') # type starts with digit
Raymond Hettingerabfd8df2007-10-16 21:28:32 +000024
Raymond Hettinger01a09572007-10-23 20:37:41 +000025 self.assertRaises(ValueError, namedtuple, 'abc', 'efg g%hi') # field with non-alpha char
26 self.assertRaises(ValueError, namedtuple, 'abc', 'abc class') # field has keyword
27 self.assertRaises(ValueError, namedtuple, 'abc', '8efg 9ghi') # field starts with digit
Raymond Hettinger42da8742007-12-14 02:49:47 +000028 self.assertRaises(ValueError, namedtuple, 'abc', '_efg ghi') # field with leading underscore
Raymond Hettinger01a09572007-10-23 20:37:41 +000029 self.assertRaises(ValueError, namedtuple, 'abc', 'efg efg ghi') # duplicate field
Raymond Hettingerabfd8df2007-10-16 21:28:32 +000030
Raymond Hettinger01a09572007-10-23 20:37:41 +000031 namedtuple('Point0', 'x1 y2') # Verify that numbers are allowed in names
Raymond Hettinger42da8742007-12-14 02:49:47 +000032 namedtuple('_', 'a b c') # Test leading underscores in a typename
Raymond Hettingerc37e5e02007-03-01 06:16:43 +000033
34 def test_instance(self):
Raymond Hettinger01a09572007-10-23 20:37:41 +000035 Point = namedtuple('Point', 'x y')
Raymond Hettingerc37e5e02007-03-01 06:16:43 +000036 p = Point(11, 22)
37 self.assertEqual(p, Point(x=11, y=22))
38 self.assertEqual(p, Point(11, y=22))
39 self.assertEqual(p, Point(y=22, x=11))
40 self.assertEqual(p, Point(*(11, 22)))
41 self.assertEqual(p, Point(**dict(x=11, y=22)))
42 self.assertRaises(TypeError, Point, 1) # too few args
43 self.assertRaises(TypeError, Point, 1, 2, 3) # too many args
44 self.assertRaises(TypeError, eval, 'Point(XXX=1, y=2)', locals()) # wrong keyword argument
45 self.assertRaises(TypeError, eval, 'Point(x=1)', locals()) # missing keyword argument
46 self.assertEqual(repr(p), 'Point(x=11, y=22)')
47 self.assert_('__dict__' not in dir(p)) # verify instance has no dict
48 self.assert_('__weakref__' not in dir(p))
Raymond Hettinger42da8742007-12-14 02:49:47 +000049 self.assertEqual(p._fields, ('x', 'y')) # test _fields attribute
50 self.assertEqual(p._replace(x=1), (1, 22)) # test _replace method
51 self.assertEqual(p._asdict(), dict(x=11, y=22)) # test _asdict method
Raymond Hettingerd36a60e2007-09-17 00:55:00 +000052
Raymond Hettinger42da8742007-12-14 02:49:47 +000053 # Verify that _fields is read-only
Raymond Hettingerb5e5d072007-11-14 23:02:30 +000054 try:
Raymond Hettinger42da8742007-12-14 02:49:47 +000055 p._fields = ('F1' ,'F2')
Raymond Hettingerb5e5d072007-11-14 23:02:30 +000056 except AttributeError:
57 pass
58 else:
Raymond Hettinger42da8742007-12-14 02:49:47 +000059 self.fail('The _fields attribute needs to be read-only')
Raymond Hettingerb5e5d072007-11-14 23:02:30 +000060
Raymond Hettingerd36a60e2007-09-17 00:55:00 +000061 # verify that field string can have commas
Raymond Hettinger01a09572007-10-23 20:37:41 +000062 Point = namedtuple('Point', 'x, y')
Raymond Hettingerd36a60e2007-09-17 00:55:00 +000063 p = Point(x=11, y=22)
64 self.assertEqual(repr(p), 'Point(x=11, y=22)')
Raymond Hettingerc37e5e02007-03-01 06:16:43 +000065
Raymond Hettinger2115bbc2007-10-08 09:14:28 +000066 # verify that fieldspec can be a non-string sequence
Raymond Hettinger01a09572007-10-23 20:37:41 +000067 Point = namedtuple('Point', ('x', 'y'))
Raymond Hettinger2115bbc2007-10-08 09:14:28 +000068 p = Point(x=11, y=22)
69 self.assertEqual(repr(p), 'Point(x=11, y=22)')
70
Raymond Hettingerc37e5e02007-03-01 06:16:43 +000071 def test_tupleness(self):
Raymond Hettinger01a09572007-10-23 20:37:41 +000072 Point = namedtuple('Point', 'x y')
Raymond Hettingerc37e5e02007-03-01 06:16:43 +000073 p = Point(11, 22)
74
75 self.assert_(isinstance(p, tuple))
76 self.assertEqual(p, (11, 22)) # matches a real tuple
77 self.assertEqual(tuple(p), (11, 22)) # coercable to a real tuple
78 self.assertEqual(list(p), [11, 22]) # coercable to a list
79 self.assertEqual(max(p), 22) # iterable
80 self.assertEqual(max(*p), 22) # star-able
81 x, y = p
82 self.assertEqual(p, (x, y)) # unpacks like a tuple
83 self.assertEqual((p[0], p[1]), (11, 22)) # indexable like a tuple
84 self.assertRaises(IndexError, p.__getitem__, 3)
85
86 self.assertEqual(p.x, x)
87 self.assertEqual(p.y, y)
88 self.assertRaises(AttributeError, eval, 'p.z', locals())
89
Raymond Hettinger2b03d452007-09-18 03:33:19 +000090 def test_odd_sizes(self):
Raymond Hettinger01a09572007-10-23 20:37:41 +000091 Zero = namedtuple('Zero', '')
Raymond Hettinger2b03d452007-09-18 03:33:19 +000092 self.assertEqual(Zero(), ())
Raymond Hettinger01a09572007-10-23 20:37:41 +000093 Dot = namedtuple('Dot', 'd')
Raymond Hettinger2b03d452007-09-18 03:33:19 +000094 self.assertEqual(Dot(1), (1,))
95
Guido van Rossum64c06e32007-11-22 00:55:51 +000096
97class TestOneTrickPonyABCs(unittest.TestCase):
98
99 def test_Hashable(self):
100 # Check some non-hashables
101 non_samples = [list(), set(), dict()]
102 for x in non_samples:
103 self.failIf(isinstance(x, Hashable), repr(x))
104 self.failIf(issubclass(type(x), Hashable), repr(type(x)))
105 # Check some hashables
106 samples = [None,
107 int(), float(), complex(),
108 str(),
109 tuple(), frozenset(),
110 int, list, object, type,
111 ]
112 for x in samples:
113 self.failUnless(isinstance(x, Hashable), repr(x))
114 self.failUnless(issubclass(type(x), Hashable), repr(type(x)))
115 self.assertRaises(TypeError, Hashable)
116 # Check direct subclassing
117 class H(Hashable):
118 def __hash__(self):
119 return super(H, self).__hash__()
120 self.assertEqual(hash(H()), 0)
121 self.failIf(issubclass(int, H))
122
123 def test_Iterable(self):
124 # Check some non-iterables
125 non_samples = [None, 42, 3.14, 1j]
126 for x in non_samples:
127 self.failIf(isinstance(x, Iterable), repr(x))
128 self.failIf(issubclass(type(x), Iterable), repr(type(x)))
129 # Check some iterables
130 samples = [str(),
131 tuple(), list(), set(), frozenset(), dict(),
132 dict().keys(), dict().items(), dict().values(),
133 (lambda: (yield))(),
134 (x for x in []),
135 ]
136 for x in samples:
137 self.failUnless(isinstance(x, Iterable), repr(x))
138 self.failUnless(issubclass(type(x), Iterable), repr(type(x)))
139 # Check direct subclassing
140 class I(Iterable):
141 def __iter__(self):
142 return super(I, self).__iter__()
143 self.assertEqual(list(I()), [])
144 self.failIf(issubclass(str, I))
145
146 def test_Iterator(self):
147 non_samples = [None, 42, 3.14, 1j, "".encode('ascii'), "", (), [],
148 {}, set()]
149 for x in non_samples:
150 self.failIf(isinstance(x, Iterator), repr(x))
151 self.failIf(issubclass(type(x), Iterator), repr(type(x)))
152 samples = [iter(str()),
153 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)))
172 samples = [str(),
173 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)))
188 samples = [str(),
189 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 "", "".encode('ascii'), (), [], {}, 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 __metaclass__ = type
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, str]:
260 self.failUnless(isinstance(sample(), Sequence))
261 self.failUnless(issubclass(sample, Sequence))
262 self.failUnless(issubclass(basestring, Sequence))
263
264 def test_MutableSequence(self):
265 for sample in [tuple, str]:
266 self.failIf(isinstance(sample(), MutableSequence))
267 self.failIf(issubclass(sample, MutableSequence))
268 for sample in [list]:
269 self.failUnless(isinstance(sample(), MutableSequence))
270 self.failUnless(issubclass(sample, MutableSequence))
271 self.failIf(issubclass(basestring, MutableSequence))
272
273
Raymond Hettingerc37e5e02007-03-01 06:16:43 +0000274def test_main(verbose=None):
Raymond Hettinger5a41daf2007-05-19 01:11:16 +0000275 import collections as CollectionsModule
Guido van Rossum64c06e32007-11-22 00:55:51 +0000276 test_classes = [TestNamedTuple, TestOneTrickPonyABCs, TestCollectionABCs]
Raymond Hettingerc37e5e02007-03-01 06:16:43 +0000277 test_support.run_unittest(*test_classes)
Raymond Hettinger5a41daf2007-05-19 01:11:16 +0000278 test_support.run_doctest(CollectionsModule, verbose)
Raymond Hettingerc37e5e02007-03-01 06:16:43 +0000279
280if __name__ == "__main__":
281 test_main(verbose=True)