/Lib/test/test_dict.py

http://unladen-swallow.googlecode.com/ · Python · 592 lines · 470 code · 91 blank · 31 comment · 51 complexity · def008ac0970e10e2bcd602c94ac42dc MD5 · raw file

  1. import unittest
  2. from test import test_support
  3. import UserDict, random, string
  4. import gc, weakref
  5. class DictTest(unittest.TestCase):
  6. def test_constructor(self):
  7. # calling built-in types without argument must return empty
  8. self.assertEqual(dict(), {})
  9. self.assert_(dict() is not {})
  10. def test_literal_constructor(self):
  11. # check literal constructor for different sized dicts (to exercise the BUILD_MAP oparg
  12. for n in (0, 1, 6, 256, 400):
  13. items = [(''.join([random.choice(string.letters)
  14. for j in range(8)]),
  15. i)
  16. for i in range(n)]
  17. random.shuffle(items)
  18. dictliteral = '{' + ', '.join('%r: %d' % item for item in items) + '}'
  19. self.assertEqual(eval(dictliteral), dict(items))
  20. def test_bool(self):
  21. self.assert_(not {})
  22. self.assert_({1: 2})
  23. self.assert_(bool({}) is False)
  24. self.assert_(bool({1: 2}) is True)
  25. def test_keys(self):
  26. d = {}
  27. self.assertEqual(d.keys(), [])
  28. d = {'a': 1, 'b': 2}
  29. k = d.keys()
  30. self.assert_(d.has_key('a'))
  31. self.assert_(d.has_key('b'))
  32. self.assertRaises(TypeError, d.keys, None)
  33. def test_values(self):
  34. d = {}
  35. self.assertEqual(d.values(), [])
  36. d = {1:2}
  37. self.assertEqual(d.values(), [2])
  38. self.assertRaises(TypeError, d.values, None)
  39. def test_items(self):
  40. d = {}
  41. self.assertEqual(d.items(), [])
  42. d = {1:2}
  43. self.assertEqual(d.items(), [(1, 2)])
  44. self.assertRaises(TypeError, d.items, None)
  45. def test_has_key(self):
  46. d = {}
  47. self.assert_(not d.has_key('a'))
  48. d = {'a': 1, 'b': 2}
  49. k = d.keys()
  50. k.sort()
  51. self.assertEqual(k, ['a', 'b'])
  52. self.assertRaises(TypeError, d.has_key)
  53. def test_contains(self):
  54. d = {}
  55. self.assert_(not ('a' in d))
  56. self.assert_('a' not in d)
  57. d = {'a': 1, 'b': 2}
  58. self.assert_('a' in d)
  59. self.assert_('b' in d)
  60. self.assert_('c' not in d)
  61. self.assertRaises(TypeError, d.__contains__)
  62. def test_len(self):
  63. d = {}
  64. self.assertEqual(len(d), 0)
  65. d = {'a': 1, 'b': 2}
  66. self.assertEqual(len(d), 2)
  67. def test_getitem(self):
  68. d = {'a': 1, 'b': 2}
  69. self.assertEqual(d['a'], 1)
  70. self.assertEqual(d['b'], 2)
  71. d['c'] = 3
  72. d['a'] = 4
  73. self.assertEqual(d['c'], 3)
  74. self.assertEqual(d['a'], 4)
  75. del d['b']
  76. self.assertEqual(d, {'a': 4, 'c': 3})
  77. self.assertRaises(TypeError, d.__getitem__)
  78. class BadEq(object):
  79. def __eq__(self, other):
  80. raise Exc()
  81. def __hash__(self):
  82. return 24
  83. d = {}
  84. d[BadEq()] = 42
  85. self.assertRaises(KeyError, d.__getitem__, 23)
  86. class Exc(Exception): pass
  87. class BadHash(object):
  88. fail = False
  89. def __hash__(self):
  90. if self.fail:
  91. raise Exc()
  92. else:
  93. return 42
  94. x = BadHash()
  95. d[x] = 42
  96. x.fail = True
  97. self.assertRaises(Exc, d.__getitem__, x)
  98. def test_clear(self):
  99. d = {1:1, 2:2, 3:3}
  100. d.clear()
  101. self.assertEqual(d, {})
  102. self.assertRaises(TypeError, d.clear, None)
  103. def test_update(self):
  104. d = {}
  105. d.update({1:100})
  106. d.update({2:20})
  107. d.update({1:1, 2:2, 3:3})
  108. self.assertEqual(d, {1:1, 2:2, 3:3})
  109. d.update()
  110. self.assertEqual(d, {1:1, 2:2, 3:3})
  111. self.assertRaises((TypeError, AttributeError), d.update, None)
  112. class SimpleUserDict:
  113. def __init__(self):
  114. self.d = {1:1, 2:2, 3:3}
  115. def keys(self):
  116. return self.d.keys()
  117. def __getitem__(self, i):
  118. return self.d[i]
  119. d.clear()
  120. d.update(SimpleUserDict())
  121. self.assertEqual(d, {1:1, 2:2, 3:3})
  122. class Exc(Exception): pass
  123. d.clear()
  124. class FailingUserDict:
  125. def keys(self):
  126. raise Exc
  127. self.assertRaises(Exc, d.update, FailingUserDict())
  128. class FailingUserDict:
  129. def keys(self):
  130. class BogonIter:
  131. def __init__(self):
  132. self.i = 1
  133. def __iter__(self):
  134. return self
  135. def next(self):
  136. if self.i:
  137. self.i = 0
  138. return 'a'
  139. raise Exc
  140. return BogonIter()
  141. def __getitem__(self, key):
  142. return key
  143. self.assertRaises(Exc, d.update, FailingUserDict())
  144. class FailingUserDict:
  145. def keys(self):
  146. class BogonIter:
  147. def __init__(self):
  148. self.i = ord('a')
  149. def __iter__(self):
  150. return self
  151. def next(self):
  152. if self.i <= ord('z'):
  153. rtn = chr(self.i)
  154. self.i += 1
  155. return rtn
  156. raise StopIteration
  157. return BogonIter()
  158. def __getitem__(self, key):
  159. raise Exc
  160. self.assertRaises(Exc, d.update, FailingUserDict())
  161. class badseq(object):
  162. def __iter__(self):
  163. return self
  164. def next(self):
  165. raise Exc()
  166. self.assertRaises(Exc, {}.update, badseq())
  167. self.assertRaises(ValueError, {}.update, [(1, 2, 3)])
  168. def test_fromkeys(self):
  169. self.assertEqual(dict.fromkeys('abc'), {'a':None, 'b':None, 'c':None})
  170. d = {}
  171. self.assert_(not(d.fromkeys('abc') is d))
  172. self.assertEqual(d.fromkeys('abc'), {'a':None, 'b':None, 'c':None})
  173. self.assertEqual(d.fromkeys((4,5),0), {4:0, 5:0})
  174. self.assertEqual(d.fromkeys([]), {})
  175. def g():
  176. yield 1
  177. self.assertEqual(d.fromkeys(g()), {1:None})
  178. self.assertRaises(TypeError, {}.fromkeys, 3)
  179. class dictlike(dict): pass
  180. self.assertEqual(dictlike.fromkeys('a'), {'a':None})
  181. self.assertEqual(dictlike().fromkeys('a'), {'a':None})
  182. self.assert_(type(dictlike.fromkeys('a')) is dictlike)
  183. self.assert_(type(dictlike().fromkeys('a')) is dictlike)
  184. class mydict(dict):
  185. def __new__(cls):
  186. return UserDict.UserDict()
  187. ud = mydict.fromkeys('ab')
  188. self.assertEqual(ud, {'a':None, 'b':None})
  189. self.assert_(isinstance(ud, UserDict.UserDict))
  190. self.assertRaises(TypeError, dict.fromkeys)
  191. class Exc(Exception): pass
  192. class baddict1(dict):
  193. def __init__(self):
  194. raise Exc()
  195. self.assertRaises(Exc, baddict1.fromkeys, [1])
  196. class BadSeq(object):
  197. def __iter__(self):
  198. return self
  199. def next(self):
  200. raise Exc()
  201. self.assertRaises(Exc, dict.fromkeys, BadSeq())
  202. class baddict2(dict):
  203. def __setitem__(self, key, value):
  204. raise Exc()
  205. self.assertRaises(Exc, baddict2.fromkeys, [1])
  206. # test fast path for dictionary inputs
  207. d = dict(zip(range(6), range(6)))
  208. self.assertEqual(dict.fromkeys(d, 0), dict(zip(range(6), [0]*6)))
  209. def test_copy(self):
  210. d = {1:1, 2:2, 3:3}
  211. self.assertEqual(d.copy(), {1:1, 2:2, 3:3})
  212. self.assertEqual({}.copy(), {})
  213. self.assertRaises(TypeError, d.copy, None)
  214. def test_get(self):
  215. d = {}
  216. self.assert_(d.get('c') is None)
  217. self.assertEqual(d.get('c', 3), 3)
  218. d = {'a' : 1, 'b' : 2}
  219. self.assert_(d.get('c') is None)
  220. self.assertEqual(d.get('c', 3), 3)
  221. self.assertEqual(d.get('a'), 1)
  222. self.assertEqual(d.get('a', 3), 1)
  223. self.assertRaises(TypeError, d.get)
  224. self.assertRaises(TypeError, d.get, None, None, None)
  225. def test_setdefault(self):
  226. # dict.setdefault()
  227. d = {}
  228. self.assert_(d.setdefault('key0') is None)
  229. d.setdefault('key0', [])
  230. self.assert_(d.setdefault('key0') is None)
  231. d.setdefault('key', []).append(3)
  232. self.assertEqual(d['key'][0], 3)
  233. d.setdefault('key', []).append(4)
  234. self.assertEqual(len(d['key']), 2)
  235. self.assertRaises(TypeError, d.setdefault)
  236. class Exc(Exception): pass
  237. class BadHash(object):
  238. fail = False
  239. def __hash__(self):
  240. if self.fail:
  241. raise Exc()
  242. else:
  243. return 42
  244. x = BadHash()
  245. d[x] = 42
  246. x.fail = True
  247. self.assertRaises(Exc, d.setdefault, x, [])
  248. def test_popitem(self):
  249. # dict.popitem()
  250. for copymode in -1, +1:
  251. # -1: b has same structure as a
  252. # +1: b is a.copy()
  253. for log2size in range(12):
  254. size = 2**log2size
  255. a = {}
  256. b = {}
  257. for i in range(size):
  258. a[repr(i)] = i
  259. if copymode < 0:
  260. b[repr(i)] = i
  261. if copymode > 0:
  262. b = a.copy()
  263. for i in range(size):
  264. ka, va = ta = a.popitem()
  265. self.assertEqual(va, int(ka))
  266. kb, vb = tb = b.popitem()
  267. self.assertEqual(vb, int(kb))
  268. self.assert_(not(copymode < 0 and ta != tb))
  269. self.assert_(not a)
  270. self.assert_(not b)
  271. d = {}
  272. self.assertRaises(KeyError, d.popitem)
  273. def test_pop(self):
  274. # Tests for pop with specified key
  275. d = {}
  276. k, v = 'abc', 'def'
  277. d[k] = v
  278. self.assertRaises(KeyError, d.pop, 'ghi')
  279. self.assertEqual(d.pop(k), v)
  280. self.assertEqual(len(d), 0)
  281. self.assertRaises(KeyError, d.pop, k)
  282. # verify longs/ints get same value when key > 32 bits (for 64-bit archs)
  283. # see SF bug #689659
  284. x = 4503599627370496L
  285. y = 4503599627370496
  286. h = {x: 'anything', y: 'something else'}
  287. self.assertEqual(h[x], h[y])
  288. self.assertEqual(d.pop(k, v), v)
  289. d[k] = v
  290. self.assertEqual(d.pop(k, 1), v)
  291. self.assertRaises(TypeError, d.pop)
  292. class Exc(Exception): pass
  293. class BadHash(object):
  294. fail = False
  295. def __hash__(self):
  296. if self.fail:
  297. raise Exc()
  298. else:
  299. return 42
  300. x = BadHash()
  301. d[x] = 42
  302. x.fail = True
  303. self.assertRaises(Exc, d.pop, x)
  304. def test_mutatingiteration(self):
  305. d = {}
  306. d[1] = 1
  307. try:
  308. for i in d:
  309. d[i+1] = 1
  310. except RuntimeError:
  311. pass
  312. else:
  313. self.fail("changing dict size during iteration doesn't raise Error")
  314. def test_repr(self):
  315. d = {}
  316. self.assertEqual(repr(d), '{}')
  317. d[1] = 2
  318. self.assertEqual(repr(d), '{1: 2}')
  319. d = {}
  320. d[1] = d
  321. self.assertEqual(repr(d), '{1: {...}}')
  322. class Exc(Exception): pass
  323. class BadRepr(object):
  324. def __repr__(self):
  325. raise Exc()
  326. d = {1: BadRepr()}
  327. self.assertRaises(Exc, repr, d)
  328. def test_le(self):
  329. self.assert_(not ({} < {}))
  330. self.assert_(not ({1: 2} < {1L: 2L}))
  331. class Exc(Exception): pass
  332. class BadCmp(object):
  333. def __eq__(self, other):
  334. raise Exc()
  335. def __hash__(self):
  336. return 42
  337. d1 = {BadCmp(): 1}
  338. d2 = {1: 1}
  339. try:
  340. d1 < d2
  341. except Exc:
  342. pass
  343. else:
  344. self.fail("< didn't raise Exc")
  345. def test_missing(self):
  346. # Make sure dict doesn't have a __missing__ method
  347. self.assertEqual(hasattr(dict, "__missing__"), False)
  348. self.assertEqual(hasattr({}, "__missing__"), False)
  349. # Test several cases:
  350. # (D) subclass defines __missing__ method returning a value
  351. # (E) subclass defines __missing__ method raising RuntimeError
  352. # (F) subclass sets __missing__ instance variable (no effect)
  353. # (G) subclass doesn't define __missing__ at a all
  354. class D(dict):
  355. def __missing__(self, key):
  356. return 42
  357. d = D({1: 2, 3: 4})
  358. self.assertEqual(d[1], 2)
  359. self.assertEqual(d[3], 4)
  360. self.assert_(2 not in d)
  361. self.assert_(2 not in d.keys())
  362. self.assertEqual(d[2], 42)
  363. class E(dict):
  364. def __missing__(self, key):
  365. raise RuntimeError(key)
  366. e = E()
  367. try:
  368. e[42]
  369. except RuntimeError, err:
  370. self.assertEqual(err.args, (42,))
  371. else:
  372. self.fail("e[42] didn't raise RuntimeError")
  373. class F(dict):
  374. def __init__(self):
  375. # An instance variable __missing__ should have no effect
  376. self.__missing__ = lambda key: None
  377. f = F()
  378. try:
  379. f[42]
  380. except KeyError, err:
  381. self.assertEqual(err.args, (42,))
  382. else:
  383. self.fail("f[42] didn't raise KeyError")
  384. class G(dict):
  385. pass
  386. g = G()
  387. try:
  388. g[42]
  389. except KeyError, err:
  390. self.assertEqual(err.args, (42,))
  391. else:
  392. self.fail("g[42] didn't raise KeyError")
  393. def test_tuple_keyerror(self):
  394. # SF #1576657
  395. d = {}
  396. try:
  397. d[(1,)]
  398. except KeyError, e:
  399. self.assertEqual(e.args, ((1,),))
  400. else:
  401. self.fail("missing KeyError")
  402. def test_bad_key(self):
  403. # Dictionary lookups should fail if __cmp__() raises an exception.
  404. class CustomException(Exception):
  405. pass
  406. class BadDictKey:
  407. def __hash__(self):
  408. return hash(self.__class__)
  409. def __cmp__(self, other):
  410. if isinstance(other, self.__class__):
  411. raise CustomException
  412. return other
  413. d = {}
  414. x1 = BadDictKey()
  415. x2 = BadDictKey()
  416. d[x1] = 1
  417. for stmt in ['d[x2] = 2',
  418. 'z = d[x2]',
  419. 'x2 in d',
  420. 'd.has_key(x2)',
  421. 'd.get(x2)',
  422. 'd.setdefault(x2, 42)',
  423. 'd.pop(x2)',
  424. 'd.update({x2: 2})']:
  425. try:
  426. exec stmt in locals()
  427. except CustomException:
  428. pass
  429. else:
  430. self.fail("Statement didn't raise exception")
  431. def test_resize1(self):
  432. # Dict resizing bug, found by Jack Jansen in 2.2 CVS development.
  433. # This version got an assert failure in debug build, infinite loop in
  434. # release build. Unfortunately, provoking this kind of stuff requires
  435. # a mix of inserts and deletes hitting exactly the right hash codes in
  436. # exactly the right order, and I can't think of a randomized approach
  437. # that would be *likely* to hit a failing case in reasonable time.
  438. d = {}
  439. for i in range(5):
  440. d[i] = i
  441. for i in range(5):
  442. del d[i]
  443. for i in range(5, 9): # i==8 was the problem
  444. d[i] = i
  445. def test_resize2(self):
  446. # Another dict resizing bug (SF bug #1456209).
  447. # This caused Segmentation faults or Illegal instructions.
  448. class X(object):
  449. def __hash__(self):
  450. return 5
  451. def __eq__(self, other):
  452. if resizing:
  453. d.clear()
  454. return False
  455. d = {}
  456. resizing = False
  457. d[X()] = 1
  458. d[X()] = 2
  459. d[X()] = 3
  460. d[X()] = 4
  461. d[X()] = 5
  462. # now trigger a resize
  463. resizing = True
  464. d[9] = 6
  465. def test_empty_presized_dict_in_freelist(self):
  466. # Bug #3537: if an empty but presized dict with a size larger
  467. # than 7 was in the freelist, it triggered an assertion failure
  468. try:
  469. d = {'a': 1/0, 'b': None, 'c': None, 'd': None, 'e': None,
  470. 'f': None, 'g': None, 'h': None}
  471. except ZeroDivisionError:
  472. pass
  473. d = {}
  474. def test_container_iterator(self):
  475. # Bug #3680: tp_traverse was not implemented for dictiter objects
  476. class C(object):
  477. pass
  478. iterators = (dict.iteritems, dict.itervalues, dict.iterkeys)
  479. for i in iterators:
  480. obj = C()
  481. ref = weakref.ref(obj)
  482. container = {obj: 1}
  483. obj.x = i(container)
  484. del obj, container
  485. gc.collect()
  486. self.assert_(ref() is None, "Cycle was not collected")
  487. from test import mapping_tests
  488. class GeneralMappingTests(mapping_tests.BasicTestMappingProtocol):
  489. type2test = dict
  490. class Dict(dict):
  491. pass
  492. class SubclassMappingTests(mapping_tests.BasicTestMappingProtocol):
  493. type2test = Dict
  494. def test_main():
  495. test_support.run_unittest(
  496. DictTest,
  497. GeneralMappingTests,
  498. SubclassMappingTests,
  499. )
  500. if __name__ == "__main__":
  501. test_main()