Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | import unittest |
2 | from test import test_support | |
3 | ||
4 | import sys, UserDict, cStringIO | |
5 | ||
6 | ||
7 | class DictTest(unittest.TestCase): | |
8 | def test_constructor(self): | |
9 | # calling built-in types without argument must return empty | |
10 | self.assertEqual(dict(), {}) | |
11 | self.assert_(dict() is not {}) | |
12 | ||
13 | def test_bool(self): | |
14 | self.assert_(not {}) | |
15 | self.assert_({1: 2}) | |
16 | self.assert_(bool({}) is False) | |
17 | self.assert_(bool({1: 2}) is True) | |
18 | ||
19 | def test_keys(self): | |
20 | d = {} | |
21 | self.assertEqual(d.keys(), []) | |
22 | d = {'a': 1, 'b': 2} | |
23 | k = d.keys() | |
24 | self.assert_(d.has_key('a')) | |
25 | self.assert_(d.has_key('b')) | |
26 | ||
27 | self.assertRaises(TypeError, d.keys, None) | |
28 | ||
29 | def test_values(self): | |
30 | d = {} | |
31 | self.assertEqual(d.values(), []) | |
32 | d = {1:2} | |
33 | self.assertEqual(d.values(), [2]) | |
34 | ||
35 | self.assertRaises(TypeError, d.values, None) | |
36 | ||
37 | def test_items(self): | |
38 | d = {} | |
39 | self.assertEqual(d.items(), []) | |
40 | ||
41 | d = {1:2} | |
42 | self.assertEqual(d.items(), [(1, 2)]) | |
43 | ||
44 | self.assertRaises(TypeError, d.items, None) | |
45 | ||
46 | def test_has_key(self): | |
47 | d = {} | |
48 | self.assert_(not d.has_key('a')) | |
49 | d = {'a': 1, 'b': 2} | |
50 | k = d.keys() | |
51 | k.sort() | |
52 | self.assertEqual(k, ['a', 'b']) | |
53 | ||
54 | self.assertRaises(TypeError, d.has_key) | |
55 | ||
56 | def test_contains(self): | |
57 | d = {} | |
58 | self.assert_(not ('a' in d)) | |
59 | self.assert_('a' not in d) | |
60 | d = {'a': 1, 'b': 2} | |
61 | self.assert_('a' in d) | |
62 | self.assert_('b' in d) | |
63 | self.assert_('c' not in d) | |
64 | ||
65 | self.assertRaises(TypeError, d.__contains__) | |
66 | ||
67 | def test_len(self): | |
68 | d = {} | |
69 | self.assertEqual(len(d), 0) | |
70 | d = {'a': 1, 'b': 2} | |
71 | self.assertEqual(len(d), 2) | |
72 | ||
73 | def test_getitem(self): | |
74 | d = {'a': 1, 'b': 2} | |
75 | self.assertEqual(d['a'], 1) | |
76 | self.assertEqual(d['b'], 2) | |
77 | d['c'] = 3 | |
78 | d['a'] = 4 | |
79 | self.assertEqual(d['c'], 3) | |
80 | self.assertEqual(d['a'], 4) | |
81 | del d['b'] | |
82 | self.assertEqual(d, {'a': 4, 'c': 3}) | |
83 | ||
84 | self.assertRaises(TypeError, d.__getitem__) | |
85 | ||
86 | class BadEq(object): | |
87 | def __eq__(self, other): | |
88 | raise Exc() | |
89 | ||
90 | d = {} | |
91 | d[BadEq()] = 42 | |
92 | self.assertRaises(KeyError, d.__getitem__, 23) | |
93 | ||
94 | class Exc(Exception): pass | |
95 | ||
96 | class BadHash(object): | |
97 | fail = False | |
98 | def __hash__(self): | |
99 | if self.fail: | |
100 | raise Exc() | |
101 | else: | |
102 | return 42 | |
103 | ||
104 | x = BadHash() | |
105 | d[x] = 42 | |
106 | x.fail = True | |
107 | self.assertRaises(Exc, d.__getitem__, x) | |
108 | ||
109 | def test_clear(self): | |
110 | d = {1:1, 2:2, 3:3} | |
111 | d.clear() | |
112 | self.assertEqual(d, {}) | |
113 | ||
114 | self.assertRaises(TypeError, d.clear, None) | |
115 | ||
116 | def test_update(self): | |
117 | d = {} | |
118 | d.update({1:100}) | |
119 | d.update({2:20}) | |
120 | d.update({1:1, 2:2, 3:3}) | |
121 | self.assertEqual(d, {1:1, 2:2, 3:3}) | |
122 | ||
123 | d.update() | |
124 | self.assertEqual(d, {1:1, 2:2, 3:3}) | |
125 | ||
126 | self.assertRaises((TypeError, AttributeError), d.update, None) | |
127 | ||
128 | class SimpleUserDict: | |
129 | def __init__(self): | |
130 | self.d = {1:1, 2:2, 3:3} | |
131 | def keys(self): | |
132 | return self.d.keys() | |
133 | def __getitem__(self, i): | |
134 | return self.d[i] | |
135 | d.clear() | |
136 | d.update(SimpleUserDict()) | |
137 | self.assertEqual(d, {1:1, 2:2, 3:3}) | |
138 | ||
139 | class Exc(Exception): pass | |
140 | ||
141 | d.clear() | |
142 | class FailingUserDict: | |
143 | def keys(self): | |
144 | raise Exc | |
145 | self.assertRaises(Exc, d.update, FailingUserDict()) | |
146 | ||
147 | class FailingUserDict: | |
148 | def keys(self): | |
149 | class BogonIter: | |
150 | def __init__(self): | |
151 | self.i = 1 | |
152 | def __iter__(self): | |
153 | return self | |
154 | def next(self): | |
155 | if self.i: | |
156 | self.i = 0 | |
157 | return 'a' | |
158 | raise Exc | |
159 | return BogonIter() | |
160 | def __getitem__(self, key): | |
161 | return key | |
162 | self.assertRaises(Exc, d.update, FailingUserDict()) | |
163 | ||
164 | class FailingUserDict: | |
165 | def keys(self): | |
166 | class BogonIter: | |
167 | def __init__(self): | |
168 | self.i = ord('a') | |
169 | def __iter__(self): | |
170 | return self | |
171 | def next(self): | |
172 | if self.i <= ord('z'): | |
173 | rtn = chr(self.i) | |
174 | self.i += 1 | |
175 | return rtn | |
176 | raise StopIteration | |
177 | return BogonIter() | |
178 | def __getitem__(self, key): | |
179 | raise Exc | |
180 | self.assertRaises(Exc, d.update, FailingUserDict()) | |
181 | ||
182 | class badseq(object): | |
183 | def __iter__(self): | |
184 | return self | |
185 | def next(self): | |
186 | raise Exc() | |
187 | ||
188 | self.assertRaises(Exc, {}.update, badseq()) | |
189 | ||
190 | self.assertRaises(ValueError, {}.update, [(1, 2, 3)]) | |
191 | ||
192 | def test_fromkeys(self): | |
193 | self.assertEqual(dict.fromkeys('abc'), {'a':None, 'b':None, 'c':None}) | |
194 | d = {} | |
195 | self.assert_(not(d.fromkeys('abc') is d)) | |
196 | self.assertEqual(d.fromkeys('abc'), {'a':None, 'b':None, 'c':None}) | |
197 | self.assertEqual(d.fromkeys((4,5),0), {4:0, 5:0}) | |
198 | self.assertEqual(d.fromkeys([]), {}) | |
199 | def g(): | |
200 | yield 1 | |
201 | self.assertEqual(d.fromkeys(g()), {1:None}) | |
202 | self.assertRaises(TypeError, {}.fromkeys, 3) | |
203 | class dictlike(dict): pass | |
204 | self.assertEqual(dictlike.fromkeys('a'), {'a':None}) | |
205 | self.assertEqual(dictlike().fromkeys('a'), {'a':None}) | |
206 | self.assert_(type(dictlike.fromkeys('a')) is dictlike) | |
207 | self.assert_(type(dictlike().fromkeys('a')) is dictlike) | |
208 | class mydict(dict): | |
209 | def __new__(cls): | |
210 | return UserDict.UserDict() | |
211 | ud = mydict.fromkeys('ab') | |
212 | self.assertEqual(ud, {'a':None, 'b':None}) | |
213 | self.assert_(isinstance(ud, UserDict.UserDict)) | |
214 | self.assertRaises(TypeError, dict.fromkeys) | |
215 | ||
216 | class Exc(Exception): pass | |
217 | ||
218 | class baddict1(dict): | |
219 | def __init__(self): | |
220 | raise Exc() | |
221 | ||
222 | self.assertRaises(Exc, baddict1.fromkeys, [1]) | |
223 | ||
224 | class BadSeq(object): | |
225 | def __iter__(self): | |
226 | return self | |
227 | def next(self): | |
228 | raise Exc() | |
229 | ||
230 | self.assertRaises(Exc, dict.fromkeys, BadSeq()) | |
231 | ||
232 | class baddict2(dict): | |
233 | def __setitem__(self, key, value): | |
234 | raise Exc() | |
235 | ||
236 | self.assertRaises(Exc, baddict2.fromkeys, [1]) | |
237 | ||
238 | def test_copy(self): | |
239 | d = {1:1, 2:2, 3:3} | |
240 | self.assertEqual(d.copy(), {1:1, 2:2, 3:3}) | |
241 | self.assertEqual({}.copy(), {}) | |
242 | self.assertRaises(TypeError, d.copy, None) | |
243 | ||
244 | def test_get(self): | |
245 | d = {} | |
246 | self.assert_(d.get('c') is None) | |
247 | self.assertEqual(d.get('c', 3), 3) | |
248 | d = {'a' : 1, 'b' : 2} | |
249 | self.assert_(d.get('c') is None) | |
250 | self.assertEqual(d.get('c', 3), 3) | |
251 | self.assertEqual(d.get('a'), 1) | |
252 | self.assertEqual(d.get('a', 3), 1) | |
253 | self.assertRaises(TypeError, d.get) | |
254 | self.assertRaises(TypeError, d.get, None, None, None) | |
255 | ||
256 | def test_setdefault(self): | |
257 | # dict.setdefault() | |
258 | d = {} | |
259 | self.assert_(d.setdefault('key0') is None) | |
260 | d.setdefault('key0', []) | |
261 | self.assert_(d.setdefault('key0') is None) | |
262 | d.setdefault('key', []).append(3) | |
263 | self.assertEqual(d['key'][0], 3) | |
264 | d.setdefault('key', []).append(4) | |
265 | self.assertEqual(len(d['key']), 2) | |
266 | self.assertRaises(TypeError, d.setdefault) | |
267 | ||
268 | class Exc(Exception): pass | |
269 | ||
270 | class BadHash(object): | |
271 | fail = False | |
272 | def __hash__(self): | |
273 | if self.fail: | |
274 | raise Exc() | |
275 | else: | |
276 | return 42 | |
277 | ||
278 | x = BadHash() | |
279 | d[x] = 42 | |
280 | x.fail = True | |
281 | self.assertRaises(Exc, d.setdefault, x, []) | |
282 | ||
283 | def test_popitem(self): | |
284 | # dict.popitem() | |
285 | for copymode in -1, +1: | |
286 | # -1: b has same structure as a | |
287 | # +1: b is a.copy() | |
288 | for log2size in range(12): | |
289 | size = 2**log2size | |
290 | a = {} | |
291 | b = {} | |
292 | for i in range(size): | |
293 | a[repr(i)] = i | |
294 | if copymode < 0: | |
295 | b[repr(i)] = i | |
296 | if copymode > 0: | |
297 | b = a.copy() | |
298 | for i in range(size): | |
299 | ka, va = ta = a.popitem() | |
300 | self.assertEqual(va, int(ka)) | |
301 | kb, vb = tb = b.popitem() | |
302 | self.assertEqual(vb, int(kb)) | |
303 | self.assert_(not(copymode < 0 and ta != tb)) | |
304 | self.assert_(not a) | |
305 | self.assert_(not b) | |
306 | ||
307 | d = {} | |
308 | self.assertRaises(KeyError, d.popitem) | |
309 | ||
310 | def test_pop(self): | |
311 | # Tests for pop with specified key | |
312 | d = {} | |
313 | k, v = 'abc', 'def' | |
314 | d[k] = v | |
315 | self.assertRaises(KeyError, d.pop, 'ghi') | |
316 | ||
317 | self.assertEqual(d.pop(k), v) | |
318 | self.assertEqual(len(d), 0) | |
319 | ||
320 | self.assertRaises(KeyError, d.pop, k) | |
321 | ||
322 | # verify longs/ints get same value when key > 32 bits (for 64-bit archs) | |
323 | # see SF bug #689659 | |
324 | x = 4503599627370496L | |
325 | y = 4503599627370496 | |
326 | h = {x: 'anything', y: 'something else'} | |
327 | self.assertEqual(h[x], h[y]) | |
328 | ||
329 | self.assertEqual(d.pop(k, v), v) | |
330 | d[k] = v | |
331 | self.assertEqual(d.pop(k, 1), v) | |
332 | ||
333 | self.assertRaises(TypeError, d.pop) | |
334 | ||
335 | class Exc(Exception): pass | |
336 | ||
337 | class BadHash(object): | |
338 | fail = False | |
339 | def __hash__(self): | |
340 | if self.fail: | |
341 | raise Exc() | |
342 | else: | |
343 | return 42 | |
344 | ||
345 | x = BadHash() | |
346 | d[x] = 42 | |
347 | x.fail = True | |
348 | self.assertRaises(Exc, d.pop, x) | |
349 | ||
350 | def test_mutatingiteration(self): | |
351 | d = {} | |
352 | d[1] = 1 | |
353 | try: | |
354 | for i in d: | |
355 | d[i+1] = 1 | |
356 | except RuntimeError: | |
357 | pass | |
358 | else: | |
359 | self.fail("changing dict size during iteration doesn't raise Error") | |
360 | ||
361 | def test_repr(self): | |
362 | d = {} | |
363 | self.assertEqual(repr(d), '{}') | |
364 | d[1] = 2 | |
365 | self.assertEqual(repr(d), '{1: 2}') | |
366 | d = {} | |
367 | d[1] = d | |
368 | self.assertEqual(repr(d), '{1: {...}}') | |
369 | ||
370 | class Exc(Exception): pass | |
371 | ||
372 | class BadRepr(object): | |
373 | def __repr__(self): | |
374 | raise Exc() | |
375 | ||
376 | d = {1: BadRepr()} | |
377 | self.assertRaises(Exc, repr, d) | |
378 | ||
379 | def test_le(self): | |
380 | self.assert_(not ({} < {})) | |
381 | self.assert_(not ({1: 2} < {1L: 2L})) | |
382 | ||
383 | class Exc(Exception): pass | |
384 | ||
385 | class BadCmp(object): | |
386 | def __eq__(self, other): | |
387 | raise Exc() | |
388 | ||
389 | d1 = {BadCmp(): 1} | |
390 | d2 = {1: 1} | |
391 | try: | |
392 | d1 < d2 | |
393 | except Exc: | |
394 | pass | |
395 | else: | |
396 | self.fail("< didn't raise Exc") | |
397 | ||
398 | import mapping_tests | |
399 | ||
400 | class GeneralMappingTests(mapping_tests.BasicTestMappingProtocol): | |
401 | type2test = dict | |
402 | ||
403 | class Dict(dict): | |
404 | pass | |
405 | ||
406 | class SubclassMappingTests(mapping_tests.BasicTestMappingProtocol): | |
407 | type2test = Dict | |
408 | ||
409 | def test_main(): | |
410 | test_support.run_unittest( | |
411 | DictTest, | |
412 | GeneralMappingTests, | |
413 | SubclassMappingTests, | |
414 | ) | |
415 | ||
416 | if __name__ == "__main__": | |
417 | test_main() |