1# tests common to dict and UserDict 2import unittest 3import UserDict 4import test_support 5 6 7class BasicTestMappingProtocol(unittest.TestCase): 8 # This base class can be used to check that an object conforms to the 9 # mapping protocol 10 11 # Functions that can be useful to override to adapt to dictionary 12 # semantics 13 type2test = None # which class is being tested (overwrite in subclasses) 14 15 def _reference(self): 16 """Return a dictionary of values which are invariant by storage 17 in the object under test.""" 18 return {1:2, "key1":"value1", "key2":(1,2,3)} 19 def _empty_mapping(self): 20 """Return an empty mapping object""" 21 return self.type2test() 22 def _full_mapping(self, data): 23 """Return a mapping object with the value contained in data 24 dictionary""" 25 x = self._empty_mapping() 26 for key, value in data.items(): 27 x[key] = value 28 return x 29 30 def __init__(self, *args, **kw): 31 unittest.TestCase.__init__(self, *args, **kw) 32 self.reference = self._reference().copy() 33 34 # A (key, value) pair not in the mapping 35 key, value = self.reference.popitem() 36 self.other = {key:value} 37 38 # A (key, value) pair in the mapping 39 key, value = self.reference.popitem() 40 self.inmapping = {key:value} 41 self.reference[key] = value 42 43 def test_read(self): 44 # Test for read only operations on mapping 45 p = self._empty_mapping() 46 p1 = dict(p) #workaround for singleton objects 47 d = self._full_mapping(self.reference) 48 if d is p: 49 p = p1 50 #Indexing 51 for key, value in self.reference.items(): 52 self.assertEqual(d[key], value) 53 knownkey = self.other.keys()[0] 54 self.assertRaises(KeyError, lambda:d[knownkey]) 55 #len 56 self.assertEqual(len(p), 0) 57 self.assertEqual(len(d), len(self.reference)) 58 #in 59 for k in self.reference: 60 self.assertIn(k, d) 61 for k in self.other: 62 self.assertNotIn(k, d) 63 #has_key 64 with test_support.check_py3k_warnings(quiet=True): 65 for k in self.reference: 66 self.assertTrue(d.has_key(k)) 67 for k in self.other: 68 self.assertFalse(d.has_key(k)) 69 #cmp 70 self.assertEqual(cmp(p,p), 0) 71 self.assertEqual(cmp(d,d), 0) 72 self.assertEqual(cmp(p,d), -1) 73 self.assertEqual(cmp(d,p), 1) 74 #__non__zero__ 75 if p: self.fail("Empty mapping must compare to False") 76 if not d: self.fail("Full mapping must compare to True") 77 # keys(), items(), iterkeys() ... 78 def check_iterandlist(iter, lst, ref): 79 self.assertTrue(hasattr(iter, 'next')) 80 self.assertTrue(hasattr(iter, '__iter__')) 81 x = list(iter) 82 self.assertTrue(set(x)==set(lst)==set(ref)) 83 check_iterandlist(d.iterkeys(), d.keys(), self.reference.keys()) 84 check_iterandlist(iter(d), d.keys(), self.reference.keys()) 85 check_iterandlist(d.itervalues(), d.values(), self.reference.values()) 86 check_iterandlist(d.iteritems(), d.items(), self.reference.items()) 87 #get 88 key, value = d.iteritems().next() 89 knownkey, knownvalue = self.other.iteritems().next() 90 self.assertEqual(d.get(key, knownvalue), value) 91 self.assertEqual(d.get(knownkey, knownvalue), knownvalue) 92 self.assertNotIn(knownkey, d) 93 94 def test_write(self): 95 # Test for write operations on mapping 96 p = self._empty_mapping() 97 #Indexing 98 for key, value in self.reference.items(): 99 p[key] = value 100 self.assertEqual(p[key], value) 101 for key in self.reference.keys(): 102 del p[key] 103 self.assertRaises(KeyError, lambda:p[key]) 104 p = self._empty_mapping() 105 #update 106 p.update(self.reference) 107 self.assertEqual(dict(p), self.reference) 108 items = p.items() 109 p = self._empty_mapping() 110 p.update(items) 111 self.assertEqual(dict(p), self.reference) 112 d = self._full_mapping(self.reference) 113 #setdefault 114 key, value = d.iteritems().next() 115 knownkey, knownvalue = self.other.iteritems().next() 116 self.assertEqual(d.setdefault(key, knownvalue), value) 117 self.assertEqual(d[key], value) 118 self.assertEqual(d.setdefault(knownkey, knownvalue), knownvalue) 119 self.assertEqual(d[knownkey], knownvalue) 120 #pop 121 self.assertEqual(d.pop(knownkey), knownvalue) 122 self.assertNotIn(knownkey, d) 123 self.assertRaises(KeyError, d.pop, knownkey) 124 default = 909 125 d[knownkey] = knownvalue 126 self.assertEqual(d.pop(knownkey, default), knownvalue) 127 self.assertNotIn(knownkey, d) 128 self.assertEqual(d.pop(knownkey, default), default) 129 #popitem 130 key, value = d.popitem() 131 self.assertNotIn(key, d) 132 self.assertEqual(value, self.reference[key]) 133 p=self._empty_mapping() 134 self.assertRaises(KeyError, p.popitem) 135 136 def test_constructor(self): 137 self.assertEqual(self._empty_mapping(), self._empty_mapping()) 138 139 def test_bool(self): 140 self.assertTrue(not self._empty_mapping()) 141 self.assertTrue(self.reference) 142 self.assertTrue(bool(self._empty_mapping()) is False) 143 self.assertTrue(bool(self.reference) is True) 144 145 def test_keys(self): 146 d = self._empty_mapping() 147 self.assertEqual(d.keys(), []) 148 d = self.reference 149 self.assertIn(self.inmapping.keys()[0], d.keys()) 150 self.assertNotIn(self.other.keys()[0], d.keys()) 151 self.assertRaises(TypeError, d.keys, None) 152 153 def test_values(self): 154 d = self._empty_mapping() 155 self.assertEqual(d.values(), []) 156 157 self.assertRaises(TypeError, d.values, None) 158 159 def test_items(self): 160 d = self._empty_mapping() 161 self.assertEqual(d.items(), []) 162 163 self.assertRaises(TypeError, d.items, None) 164 165 def test_len(self): 166 d = self._empty_mapping() 167 self.assertEqual(len(d), 0) 168 169 def test_getitem(self): 170 d = self.reference 171 self.assertEqual(d[self.inmapping.keys()[0]], self.inmapping.values()[0]) 172 173 self.assertRaises(TypeError, d.__getitem__) 174 175 def test_update(self): 176 # mapping argument 177 d = self._empty_mapping() 178 d.update(self.other) 179 self.assertEqual(d.items(), self.other.items()) 180 181 # No argument 182 d = self._empty_mapping() 183 d.update() 184 self.assertEqual(d, self._empty_mapping()) 185 186 # item sequence 187 d = self._empty_mapping() 188 d.update(self.other.items()) 189 self.assertEqual(d.items(), self.other.items()) 190 191 # Iterator 192 d = self._empty_mapping() 193 d.update(self.other.iteritems()) 194 self.assertEqual(d.items(), self.other.items()) 195 196 # FIXME: Doesn't work with UserDict 197 # self.assertRaises((TypeError, AttributeError), d.update, None) 198 self.assertRaises((TypeError, AttributeError), d.update, 42) 199 200 outerself = self 201 class SimpleUserDict: 202 def __init__(self): 203 self.d = outerself.reference 204 def keys(self): 205 return self.d.keys() 206 def __getitem__(self, i): 207 return self.d[i] 208 d.clear() 209 d.update(SimpleUserDict()) 210 i1 = d.items() 211 i2 = self.reference.items() 212 213 def safe_sort_key(kv): 214 k, v = kv 215 return id(type(k)), id(type(v)), k, v 216 i1.sort(key=safe_sort_key) 217 i2.sort(key=safe_sort_key) 218 self.assertEqual(i1, i2) 219 220 class Exc(Exception): pass 221 222 d = self._empty_mapping() 223 class FailingUserDict: 224 def keys(self): 225 raise Exc 226 self.assertRaises(Exc, d.update, FailingUserDict()) 227 228 d.clear() 229 230 class FailingUserDict: 231 def keys(self): 232 class BogonIter: 233 def __init__(self): 234 self.i = 1 235 def __iter__(self): 236 return self 237 def next(self): 238 if self.i: 239 self.i = 0 240 return 'a' 241 raise Exc 242 return BogonIter() 243 def __getitem__(self, key): 244 return key 245 self.assertRaises(Exc, d.update, FailingUserDict()) 246 247 class FailingUserDict: 248 def keys(self): 249 class BogonIter: 250 def __init__(self): 251 self.i = ord('a') 252 def __iter__(self): 253 return self 254 def next(self): 255 if self.i <= ord('z'): 256 rtn = chr(self.i) 257 self.i += 1 258 return rtn 259 raise StopIteration 260 return BogonIter() 261 def __getitem__(self, key): 262 raise Exc 263 self.assertRaises(Exc, d.update, FailingUserDict()) 264 265 d = self._empty_mapping() 266 class badseq(object): 267 def __iter__(self): 268 return self 269 def next(self): 270 raise Exc() 271 272 self.assertRaises(Exc, d.update, badseq()) 273 274 self.assertRaises(ValueError, d.update, [(1, 2, 3)]) 275 276 # no test_fromkeys or test_copy as both os.environ and selves don't support it 277 278 def test_get(self): 279 d = self._empty_mapping() 280 self.assertTrue(d.get(self.other.keys()[0]) is None) 281 self.assertEqual(d.get(self.other.keys()[0], 3), 3) 282 d = self.reference 283 self.assertTrue(d.get(self.other.keys()[0]) is None) 284 self.assertEqual(d.get(self.other.keys()[0], 3), 3) 285 self.assertEqual(d.get(self.inmapping.keys()[0]), self.inmapping.values()[0]) 286 self.assertEqual(d.get(self.inmapping.keys()[0], 3), self.inmapping.values()[0]) 287 self.assertRaises(TypeError, d.get) 288 self.assertRaises(TypeError, d.get, None, None, None) 289 290 def test_setdefault(self): 291 d = self._empty_mapping() 292 self.assertRaises(TypeError, d.setdefault) 293 294 def test_popitem(self): 295 d = self._empty_mapping() 296 self.assertRaises(KeyError, d.popitem) 297 self.assertRaises(TypeError, d.popitem, 42) 298 299 def test_pop(self): 300 d = self._empty_mapping() 301 k, v = self.inmapping.items()[0] 302 d[k] = v 303 self.assertRaises(KeyError, d.pop, self.other.keys()[0]) 304 305 self.assertEqual(d.pop(k), v) 306 self.assertEqual(len(d), 0) 307 308 self.assertRaises(KeyError, d.pop, k) 309 310 311class TestMappingProtocol(BasicTestMappingProtocol): 312 def test_constructor(self): 313 BasicTestMappingProtocol.test_constructor(self) 314 self.assertTrue(self._empty_mapping() is not self._empty_mapping()) 315 self.assertEqual(self.type2test(x=1, y=2), {"x": 1, "y": 2}) 316 317 def test_bool(self): 318 BasicTestMappingProtocol.test_bool(self) 319 self.assertTrue(not self._empty_mapping()) 320 self.assertTrue(self._full_mapping({"x": "y"})) 321 self.assertTrue(bool(self._empty_mapping()) is False) 322 self.assertTrue(bool(self._full_mapping({"x": "y"})) is True) 323 324 def test_keys(self): 325 BasicTestMappingProtocol.test_keys(self) 326 d = self._empty_mapping() 327 self.assertEqual(d.keys(), []) 328 d = self._full_mapping({'a': 1, 'b': 2}) 329 k = d.keys() 330 self.assertIn('a', k) 331 self.assertIn('b', k) 332 self.assertNotIn('c', k) 333 334 def test_values(self): 335 BasicTestMappingProtocol.test_values(self) 336 d = self._full_mapping({1:2}) 337 self.assertEqual(d.values(), [2]) 338 339 def test_items(self): 340 BasicTestMappingProtocol.test_items(self) 341 342 d = self._full_mapping({1:2}) 343 self.assertEqual(d.items(), [(1, 2)]) 344 345 def test_has_key(self): 346 d = self._empty_mapping() 347 self.assertTrue(not d.has_key('a')) 348 d = self._full_mapping({'a': 1, 'b': 2}) 349 k = d.keys() 350 k.sort(key=lambda k: (id(type(k)), k)) 351 self.assertEqual(k, ['a', 'b']) 352 353 self.assertRaises(TypeError, d.has_key) 354 355 def test_contains(self): 356 d = self._empty_mapping() 357 self.assertNotIn('a', d) 358 self.assertTrue(not ('a' in d)) 359 self.assertTrue('a' not in d) 360 d = self._full_mapping({'a': 1, 'b': 2}) 361 self.assertIn('a', d) 362 self.assertIn('b', d) 363 self.assertNotIn('c', d) 364 365 self.assertRaises(TypeError, d.__contains__) 366 367 def test_len(self): 368 BasicTestMappingProtocol.test_len(self) 369 d = self._full_mapping({'a': 1, 'b': 2}) 370 self.assertEqual(len(d), 2) 371 372 def test_getitem(self): 373 BasicTestMappingProtocol.test_getitem(self) 374 d = self._full_mapping({'a': 1, 'b': 2}) 375 self.assertEqual(d['a'], 1) 376 self.assertEqual(d['b'], 2) 377 d['c'] = 3 378 d['a'] = 4 379 self.assertEqual(d['c'], 3) 380 self.assertEqual(d['a'], 4) 381 del d['b'] 382 self.assertEqual(d, {'a': 4, 'c': 3}) 383 384 self.assertRaises(TypeError, d.__getitem__) 385 386 def test_clear(self): 387 d = self._full_mapping({1:1, 2:2, 3:3}) 388 d.clear() 389 self.assertEqual(d, {}) 390 391 self.assertRaises(TypeError, d.clear, None) 392 393 def test_update(self): 394 BasicTestMappingProtocol.test_update(self) 395 # mapping argument 396 d = self._empty_mapping() 397 d.update({1:100}) 398 d.update({2:20}) 399 d.update({1:1, 2:2, 3:3}) 400 self.assertEqual(d, {1:1, 2:2, 3:3}) 401 402 # no argument 403 d.update() 404 self.assertEqual(d, {1:1, 2:2, 3:3}) 405 406 # keyword arguments 407 d = self._empty_mapping() 408 d.update(x=100) 409 d.update(y=20) 410 d.update(x=1, y=2, z=3) 411 self.assertEqual(d, {"x":1, "y":2, "z":3}) 412 413 # item sequence 414 d = self._empty_mapping() 415 d.update([("x", 100), ("y", 20)]) 416 self.assertEqual(d, {"x":100, "y":20}) 417 418 # Both item sequence and keyword arguments 419 d = self._empty_mapping() 420 d.update([("x", 100), ("y", 20)], x=1, y=2) 421 self.assertEqual(d, {"x":1, "y":2}) 422 423 # iterator 424 d = self._full_mapping({1:3, 2:4}) 425 d.update(self._full_mapping({1:2, 3:4, 5:6}).iteritems()) 426 self.assertEqual(d, {1:2, 2:4, 3:4, 5:6}) 427 428 class SimpleUserDict: 429 def __init__(self): 430 self.d = {1:1, 2:2, 3:3} 431 def keys(self): 432 return self.d.keys() 433 def __getitem__(self, i): 434 return self.d[i] 435 d.clear() 436 d.update(SimpleUserDict()) 437 self.assertEqual(d, {1:1, 2:2, 3:3}) 438 439 def test_fromkeys(self): 440 self.assertEqual(self.type2test.fromkeys('abc'), {'a':None, 'b':None, 'c':None}) 441 d = self._empty_mapping() 442 self.assertTrue(not(d.fromkeys('abc') is d)) 443 self.assertEqual(d.fromkeys('abc'), {'a':None, 'b':None, 'c':None}) 444 self.assertEqual(d.fromkeys((4,5),0), {4:0, 5:0}) 445 self.assertEqual(d.fromkeys([]), {}) 446 def g(): 447 yield 1 448 self.assertEqual(d.fromkeys(g()), {1:None}) 449 self.assertRaises(TypeError, {}.fromkeys, 3) 450 class dictlike(self.type2test): pass 451 self.assertEqual(dictlike.fromkeys('a'), {'a':None}) 452 self.assertEqual(dictlike().fromkeys('a'), {'a':None}) 453 self.assertTrue(dictlike.fromkeys('a').__class__ is dictlike) 454 self.assertTrue(dictlike().fromkeys('a').__class__ is dictlike) 455 # FIXME: the following won't work with UserDict, because it's an old style class 456 # self.assertTrue(type(dictlike.fromkeys('a')) is dictlike) 457 class mydict(self.type2test): 458 def __new__(cls): 459 return UserDict.UserDict() 460 ud = mydict.fromkeys('ab') 461 self.assertEqual(ud, {'a':None, 'b':None}) 462 # FIXME: the following won't work with UserDict, because it's an old style class 463 # self.assertIsInstance(ud, UserDict.UserDict) 464 self.assertRaises(TypeError, dict.fromkeys) 465 466 class Exc(Exception): pass 467 468 class baddict1(self.type2test): 469 def __init__(self): 470 raise Exc() 471 472 self.assertRaises(Exc, baddict1.fromkeys, [1]) 473 474 class BadSeq(object): 475 def __iter__(self): 476 return self 477 def next(self): 478 raise Exc() 479 480 self.assertRaises(Exc, self.type2test.fromkeys, BadSeq()) 481 482 class baddict2(self.type2test): 483 def __setitem__(self, key, value): 484 raise Exc() 485 486 self.assertRaises(Exc, baddict2.fromkeys, [1]) 487 488 def test_copy(self): 489 d = self._full_mapping({1:1, 2:2, 3:3}) 490 self.assertEqual(d.copy(), {1:1, 2:2, 3:3}) 491 d = self._empty_mapping() 492 self.assertEqual(d.copy(), d) 493 self.assertIsInstance(d.copy(), d.__class__) 494 self.assertRaises(TypeError, d.copy, None) 495 496 def test_get(self): 497 BasicTestMappingProtocol.test_get(self) 498 d = self._empty_mapping() 499 self.assertTrue(d.get('c') is None) 500 self.assertEqual(d.get('c', 3), 3) 501 d = self._full_mapping({'a' : 1, 'b' : 2}) 502 self.assertTrue(d.get('c') is None) 503 self.assertEqual(d.get('c', 3), 3) 504 self.assertEqual(d.get('a'), 1) 505 self.assertEqual(d.get('a', 3), 1) 506 507 def test_setdefault(self): 508 BasicTestMappingProtocol.test_setdefault(self) 509 d = self._empty_mapping() 510 self.assertTrue(d.setdefault('key0') is None) 511 d.setdefault('key0', []) 512 self.assertTrue(d.setdefault('key0') is None) 513 d.setdefault('key', []).append(3) 514 self.assertEqual(d['key'][0], 3) 515 d.setdefault('key', []).append(4) 516 self.assertEqual(len(d['key']), 2) 517 518 def test_popitem(self): 519 BasicTestMappingProtocol.test_popitem(self) 520 for copymode in -1, +1: 521 # -1: b has same structure as a 522 # +1: b is a.copy() 523 for log2size in range(12): 524 size = 2**log2size 525 a = self._empty_mapping() 526 b = self._empty_mapping() 527 for i in range(size): 528 a[repr(i)] = i 529 if copymode < 0: 530 b[repr(i)] = i 531 if copymode > 0: 532 b = a.copy() 533 for i in range(size): 534 ka, va = ta = a.popitem() 535 self.assertEqual(va, int(ka)) 536 kb, vb = tb = b.popitem() 537 self.assertEqual(vb, int(kb)) 538 self.assertTrue(not(copymode < 0 and ta != tb)) 539 self.assertTrue(not a) 540 self.assertTrue(not b) 541 542 def test_pop(self): 543 BasicTestMappingProtocol.test_pop(self) 544 545 # Tests for pop with specified key 546 d = self._empty_mapping() 547 k, v = 'abc', 'def' 548 549 # verify longs/ints get same value when key > 32 bits (for 64-bit archs) 550 # see SF bug #689659 551 x = 4503599627370496L 552 y = 4503599627370496 553 h = self._full_mapping({x: 'anything', y: 'something else'}) 554 self.assertEqual(h[x], h[y]) 555 556 self.assertEqual(d.pop(k, v), v) 557 d[k] = v 558 self.assertEqual(d.pop(k, 1), v) 559 560 561class TestHashMappingProtocol(TestMappingProtocol): 562 563 def test_getitem(self): 564 TestMappingProtocol.test_getitem(self) 565 class Exc(Exception): pass 566 567 class BadEq(object): 568 def __eq__(self, other): 569 raise Exc() 570 def __hash__(self): 571 return 24 572 573 d = self._empty_mapping() 574 d[BadEq()] = 42 575 self.assertRaises(KeyError, d.__getitem__, 23) 576 577 class BadHash(object): 578 fail = False 579 def __hash__(self): 580 if self.fail: 581 raise Exc() 582 else: 583 return 42 584 585 d = self._empty_mapping() 586 x = BadHash() 587 d[x] = 42 588 x.fail = True 589 self.assertRaises(Exc, d.__getitem__, x) 590 591 def test_fromkeys(self): 592 TestMappingProtocol.test_fromkeys(self) 593 class mydict(self.type2test): 594 def __new__(cls): 595 return UserDict.UserDict() 596 ud = mydict.fromkeys('ab') 597 self.assertEqual(ud, {'a':None, 'b':None}) 598 self.assertIsInstance(ud, UserDict.UserDict) 599 600 def test_pop(self): 601 TestMappingProtocol.test_pop(self) 602 603 class Exc(Exception): pass 604 605 class BadHash(object): 606 fail = False 607 def __hash__(self): 608 if self.fail: 609 raise Exc() 610 else: 611 return 42 612 613 d = self._empty_mapping() 614 x = BadHash() 615 d[x] = 42 616 x.fail = True 617 self.assertRaises(Exc, d.pop, x) 618 619 def test_mutatingiteration(self): 620 d = self._empty_mapping() 621 d[1] = 1 622 try: 623 for i in d: 624 d[i+1] = 1 625 except RuntimeError: 626 pass 627 else: 628 self.fail("changing dict size during iteration doesn't raise Error") 629 630 def test_repr(self): 631 d = self._empty_mapping() 632 self.assertEqual(repr(d), '{}') 633 d[1] = 2 634 self.assertEqual(repr(d), '{1: 2}') 635 d = self._empty_mapping() 636 d[1] = d 637 self.assertEqual(repr(d), '{1: {...}}') 638 639 class Exc(Exception): pass 640 641 class BadRepr(object): 642 def __repr__(self): 643 raise Exc() 644 645 d = self._full_mapping({1: BadRepr()}) 646 self.assertRaises(Exc, repr, d) 647 648 def test_le(self): 649 self.assertTrue(not (self._empty_mapping() < self._empty_mapping())) 650 self.assertTrue(not (self._full_mapping({1: 2}) < self._full_mapping({1L: 2L}))) 651 652 class Exc(Exception): pass 653 654 class BadCmp(object): 655 def __eq__(self, other): 656 raise Exc() 657 def __hash__(self): 658 return 42 659 660 d1 = self._full_mapping({BadCmp(): 1}) 661 d2 = self._full_mapping({1: 1}) 662 try: 663 d1 < d2 664 except Exc: 665 pass 666 else: 667 self.fail("< didn't raise Exc") 668 669 def test_setdefault(self): 670 TestMappingProtocol.test_setdefault(self) 671 672 class Exc(Exception): pass 673 674 class BadHash(object): 675 fail = False 676 def __hash__(self): 677 if self.fail: 678 raise Exc() 679 else: 680 return 42 681 682 d = self._empty_mapping() 683 x = BadHash() 684 d[x] = 42 685 x.fail = True 686 self.assertRaises(Exc, d.setdefault, x, []) 687