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 i1.sort() 213 i2.sort() 214 self.assertEqual(i1, i2) 215 216 class Exc(Exception): pass 217 218 d = self._empty_mapping() 219 class FailingUserDict: 220 def keys(self): 221 raise Exc 222 self.assertRaises(Exc, d.update, FailingUserDict()) 223 224 d.clear() 225 226 class FailingUserDict: 227 def keys(self): 228 class BogonIter: 229 def __init__(self): 230 self.i = 1 231 def __iter__(self): 232 return self 233 def next(self): 234 if self.i: 235 self.i = 0 236 return 'a' 237 raise Exc 238 return BogonIter() 239 def __getitem__(self, key): 240 return key 241 self.assertRaises(Exc, d.update, FailingUserDict()) 242 243 class FailingUserDict: 244 def keys(self): 245 class BogonIter: 246 def __init__(self): 247 self.i = ord('a') 248 def __iter__(self): 249 return self 250 def next(self): 251 if self.i <= ord('z'): 252 rtn = chr(self.i) 253 self.i += 1 254 return rtn 255 raise StopIteration 256 return BogonIter() 257 def __getitem__(self, key): 258 raise Exc 259 self.assertRaises(Exc, d.update, FailingUserDict()) 260 261 d = self._empty_mapping() 262 class badseq(object): 263 def __iter__(self): 264 return self 265 def next(self): 266 raise Exc() 267 268 self.assertRaises(Exc, d.update, badseq()) 269 270 self.assertRaises(ValueError, d.update, [(1, 2, 3)]) 271 272 # no test_fromkeys or test_copy as both os.environ and selves don't support it 273 274 def test_get(self): 275 d = self._empty_mapping() 276 self.assertTrue(d.get(self.other.keys()[0]) is None) 277 self.assertEqual(d.get(self.other.keys()[0], 3), 3) 278 d = self.reference 279 self.assertTrue(d.get(self.other.keys()[0]) is None) 280 self.assertEqual(d.get(self.other.keys()[0], 3), 3) 281 self.assertEqual(d.get(self.inmapping.keys()[0]), self.inmapping.values()[0]) 282 self.assertEqual(d.get(self.inmapping.keys()[0], 3), self.inmapping.values()[0]) 283 self.assertRaises(TypeError, d.get) 284 self.assertRaises(TypeError, d.get, None, None, None) 285 286 def test_setdefault(self): 287 d = self._empty_mapping() 288 self.assertRaises(TypeError, d.setdefault) 289 290 def test_popitem(self): 291 d = self._empty_mapping() 292 self.assertRaises(KeyError, d.popitem) 293 self.assertRaises(TypeError, d.popitem, 42) 294 295 def test_pop(self): 296 d = self._empty_mapping() 297 k, v = self.inmapping.items()[0] 298 d[k] = v 299 self.assertRaises(KeyError, d.pop, self.other.keys()[0]) 300 301 self.assertEqual(d.pop(k), v) 302 self.assertEqual(len(d), 0) 303 304 self.assertRaises(KeyError, d.pop, k) 305 306 307class TestMappingProtocol(BasicTestMappingProtocol): 308 def test_constructor(self): 309 BasicTestMappingProtocol.test_constructor(self) 310 self.assertTrue(self._empty_mapping() is not self._empty_mapping()) 311 self.assertEqual(self.type2test(x=1, y=2), {"x": 1, "y": 2}) 312 313 def test_bool(self): 314 BasicTestMappingProtocol.test_bool(self) 315 self.assertTrue(not self._empty_mapping()) 316 self.assertTrue(self._full_mapping({"x": "y"})) 317 self.assertTrue(bool(self._empty_mapping()) is False) 318 self.assertTrue(bool(self._full_mapping({"x": "y"})) is True) 319 320 def test_keys(self): 321 BasicTestMappingProtocol.test_keys(self) 322 d = self._empty_mapping() 323 self.assertEqual(d.keys(), []) 324 d = self._full_mapping({'a': 1, 'b': 2}) 325 k = d.keys() 326 self.assertIn('a', k) 327 self.assertIn('b', k) 328 self.assertNotIn('c', k) 329 330 def test_values(self): 331 BasicTestMappingProtocol.test_values(self) 332 d = self._full_mapping({1:2}) 333 self.assertEqual(d.values(), [2]) 334 335 def test_items(self): 336 BasicTestMappingProtocol.test_items(self) 337 338 d = self._full_mapping({1:2}) 339 self.assertEqual(d.items(), [(1, 2)]) 340 341 def test_has_key(self): 342 d = self._empty_mapping() 343 self.assertTrue(not d.has_key('a')) 344 d = self._full_mapping({'a': 1, 'b': 2}) 345 k = d.keys() 346 k.sort() 347 self.assertEqual(k, ['a', 'b']) 348 349 self.assertRaises(TypeError, d.has_key) 350 351 def test_contains(self): 352 d = self._empty_mapping() 353 self.assertNotIn('a', d) 354 self.assertTrue(not ('a' in d)) 355 self.assertTrue('a' not in d) 356 d = self._full_mapping({'a': 1, 'b': 2}) 357 self.assertIn('a', d) 358 self.assertIn('b', d) 359 self.assertNotIn('c', d) 360 361 self.assertRaises(TypeError, d.__contains__) 362 363 def test_len(self): 364 BasicTestMappingProtocol.test_len(self) 365 d = self._full_mapping({'a': 1, 'b': 2}) 366 self.assertEqual(len(d), 2) 367 368 def test_getitem(self): 369 BasicTestMappingProtocol.test_getitem(self) 370 d = self._full_mapping({'a': 1, 'b': 2}) 371 self.assertEqual(d['a'], 1) 372 self.assertEqual(d['b'], 2) 373 d['c'] = 3 374 d['a'] = 4 375 self.assertEqual(d['c'], 3) 376 self.assertEqual(d['a'], 4) 377 del d['b'] 378 self.assertEqual(d, {'a': 4, 'c': 3}) 379 380 self.assertRaises(TypeError, d.__getitem__) 381 382 def test_clear(self): 383 d = self._full_mapping({1:1, 2:2, 3:3}) 384 d.clear() 385 self.assertEqual(d, {}) 386 387 self.assertRaises(TypeError, d.clear, None) 388 389 def test_update(self): 390 BasicTestMappingProtocol.test_update(self) 391 # mapping argument 392 d = self._empty_mapping() 393 d.update({1:100}) 394 d.update({2:20}) 395 d.update({1:1, 2:2, 3:3}) 396 self.assertEqual(d, {1:1, 2:2, 3:3}) 397 398 # no argument 399 d.update() 400 self.assertEqual(d, {1:1, 2:2, 3:3}) 401 402 # keyword arguments 403 d = self._empty_mapping() 404 d.update(x=100) 405 d.update(y=20) 406 d.update(x=1, y=2, z=3) 407 self.assertEqual(d, {"x":1, "y":2, "z":3}) 408 409 # item sequence 410 d = self._empty_mapping() 411 d.update([("x", 100), ("y", 20)]) 412 self.assertEqual(d, {"x":100, "y":20}) 413 414 # Both item sequence and keyword arguments 415 d = self._empty_mapping() 416 d.update([("x", 100), ("y", 20)], x=1, y=2) 417 self.assertEqual(d, {"x":1, "y":2}) 418 419 # iterator 420 d = self._full_mapping({1:3, 2:4}) 421 d.update(self._full_mapping({1:2, 3:4, 5:6}).iteritems()) 422 self.assertEqual(d, {1:2, 2:4, 3:4, 5:6}) 423 424 class SimpleUserDict: 425 def __init__(self): 426 self.d = {1:1, 2:2, 3:3} 427 def keys(self): 428 return self.d.keys() 429 def __getitem__(self, i): 430 return self.d[i] 431 d.clear() 432 d.update(SimpleUserDict()) 433 self.assertEqual(d, {1:1, 2:2, 3:3}) 434 435 def test_fromkeys(self): 436 self.assertEqual(self.type2test.fromkeys('abc'), {'a':None, 'b':None, 'c':None}) 437 d = self._empty_mapping() 438 self.assertTrue(not(d.fromkeys('abc') is d)) 439 self.assertEqual(d.fromkeys('abc'), {'a':None, 'b':None, 'c':None}) 440 self.assertEqual(d.fromkeys((4,5),0), {4:0, 5:0}) 441 self.assertEqual(d.fromkeys([]), {}) 442 def g(): 443 yield 1 444 self.assertEqual(d.fromkeys(g()), {1:None}) 445 self.assertRaises(TypeError, {}.fromkeys, 3) 446 class dictlike(self.type2test): pass 447 self.assertEqual(dictlike.fromkeys('a'), {'a':None}) 448 self.assertEqual(dictlike().fromkeys('a'), {'a':None}) 449 self.assertTrue(dictlike.fromkeys('a').__class__ is dictlike) 450 self.assertTrue(dictlike().fromkeys('a').__class__ is dictlike) 451 # FIXME: the following won't work with UserDict, because it's an old style class 452 # self.assertTrue(type(dictlike.fromkeys('a')) is dictlike) 453 class mydict(self.type2test): 454 def __new__(cls): 455 return UserDict.UserDict() 456 ud = mydict.fromkeys('ab') 457 self.assertEqual(ud, {'a':None, 'b':None}) 458 # FIXME: the following won't work with UserDict, because it's an old style class 459 # self.assertIsInstance(ud, UserDict.UserDict) 460 self.assertRaises(TypeError, dict.fromkeys) 461 462 class Exc(Exception): pass 463 464 class baddict1(self.type2test): 465 def __init__(self): 466 raise Exc() 467 468 self.assertRaises(Exc, baddict1.fromkeys, [1]) 469 470 class BadSeq(object): 471 def __iter__(self): 472 return self 473 def next(self): 474 raise Exc() 475 476 self.assertRaises(Exc, self.type2test.fromkeys, BadSeq()) 477 478 class baddict2(self.type2test): 479 def __setitem__(self, key, value): 480 raise Exc() 481 482 self.assertRaises(Exc, baddict2.fromkeys, [1]) 483 484 def test_copy(self): 485 d = self._full_mapping({1:1, 2:2, 3:3}) 486 self.assertEqual(d.copy(), {1:1, 2:2, 3:3}) 487 d = self._empty_mapping() 488 self.assertEqual(d.copy(), d) 489 self.assertIsInstance(d.copy(), d.__class__) 490 self.assertRaises(TypeError, d.copy, None) 491 492 def test_get(self): 493 BasicTestMappingProtocol.test_get(self) 494 d = self._empty_mapping() 495 self.assertTrue(d.get('c') is None) 496 self.assertEqual(d.get('c', 3), 3) 497 d = self._full_mapping({'a' : 1, 'b' : 2}) 498 self.assertTrue(d.get('c') is None) 499 self.assertEqual(d.get('c', 3), 3) 500 self.assertEqual(d.get('a'), 1) 501 self.assertEqual(d.get('a', 3), 1) 502 503 def test_setdefault(self): 504 BasicTestMappingProtocol.test_setdefault(self) 505 d = self._empty_mapping() 506 self.assertTrue(d.setdefault('key0') is None) 507 d.setdefault('key0', []) 508 self.assertTrue(d.setdefault('key0') is None) 509 d.setdefault('key', []).append(3) 510 self.assertEqual(d['key'][0], 3) 511 d.setdefault('key', []).append(4) 512 self.assertEqual(len(d['key']), 2) 513 514 def test_popitem(self): 515 BasicTestMappingProtocol.test_popitem(self) 516 for copymode in -1, +1: 517 # -1: b has same structure as a 518 # +1: b is a.copy() 519 for log2size in range(12): 520 size = 2**log2size 521 a = self._empty_mapping() 522 b = self._empty_mapping() 523 for i in range(size): 524 a[repr(i)] = i 525 if copymode < 0: 526 b[repr(i)] = i 527 if copymode > 0: 528 b = a.copy() 529 for i in range(size): 530 ka, va = ta = a.popitem() 531 self.assertEqual(va, int(ka)) 532 kb, vb = tb = b.popitem() 533 self.assertEqual(vb, int(kb)) 534 self.assertTrue(not(copymode < 0 and ta != tb)) 535 self.assertTrue(not a) 536 self.assertTrue(not b) 537 538 def test_pop(self): 539 BasicTestMappingProtocol.test_pop(self) 540 541 # Tests for pop with specified key 542 d = self._empty_mapping() 543 k, v = 'abc', 'def' 544 545 # verify longs/ints get same value when key > 32 bits (for 64-bit archs) 546 # see SF bug #689659 547 x = 4503599627370496L 548 y = 4503599627370496 549 h = self._full_mapping({x: 'anything', y: 'something else'}) 550 self.assertEqual(h[x], h[y]) 551 552 self.assertEqual(d.pop(k, v), v) 553 d[k] = v 554 self.assertEqual(d.pop(k, 1), v) 555 556 557class TestHashMappingProtocol(TestMappingProtocol): 558 559 def test_getitem(self): 560 TestMappingProtocol.test_getitem(self) 561 class Exc(Exception): pass 562 563 class BadEq(object): 564 def __eq__(self, other): 565 raise Exc() 566 def __hash__(self): 567 return 24 568 569 d = self._empty_mapping() 570 d[BadEq()] = 42 571 self.assertRaises(KeyError, d.__getitem__, 23) 572 573 class BadHash(object): 574 fail = False 575 def __hash__(self): 576 if self.fail: 577 raise Exc() 578 else: 579 return 42 580 581 d = self._empty_mapping() 582 x = BadHash() 583 d[x] = 42 584 x.fail = True 585 self.assertRaises(Exc, d.__getitem__, x) 586 587 def test_fromkeys(self): 588 TestMappingProtocol.test_fromkeys(self) 589 class mydict(self.type2test): 590 def __new__(cls): 591 return UserDict.UserDict() 592 ud = mydict.fromkeys('ab') 593 self.assertEqual(ud, {'a':None, 'b':None}) 594 self.assertIsInstance(ud, UserDict.UserDict) 595 596 def test_pop(self): 597 TestMappingProtocol.test_pop(self) 598 599 class Exc(Exception): pass 600 601 class BadHash(object): 602 fail = False 603 def __hash__(self): 604 if self.fail: 605 raise Exc() 606 else: 607 return 42 608 609 d = self._empty_mapping() 610 x = BadHash() 611 d[x] = 42 612 x.fail = True 613 self.assertRaises(Exc, d.pop, x) 614 615 def test_mutatingiteration(self): 616 d = self._empty_mapping() 617 d[1] = 1 618 try: 619 for i in d: 620 d[i+1] = 1 621 except RuntimeError: 622 pass 623 else: 624 self.fail("changing dict size during iteration doesn't raise Error") 625 626 def test_repr(self): 627 d = self._empty_mapping() 628 self.assertEqual(repr(d), '{}') 629 d[1] = 2 630 self.assertEqual(repr(d), '{1: 2}') 631 d = self._empty_mapping() 632 d[1] = d 633 self.assertEqual(repr(d), '{1: {...}}') 634 635 class Exc(Exception): pass 636 637 class BadRepr(object): 638 def __repr__(self): 639 raise Exc() 640 641 d = self._full_mapping({1: BadRepr()}) 642 self.assertRaises(Exc, repr, d) 643 644 def test_le(self): 645 self.assertTrue(not (self._empty_mapping() < self._empty_mapping())) 646 self.assertTrue(not (self._full_mapping({1: 2}) < self._full_mapping({1L: 2L}))) 647 648 class Exc(Exception): pass 649 650 class BadCmp(object): 651 def __eq__(self, other): 652 raise Exc() 653 def __hash__(self): 654 return 42 655 656 d1 = self._full_mapping({BadCmp(): 1}) 657 d2 = self._full_mapping({1: 1}) 658 try: 659 d1 < d2 660 except Exc: 661 pass 662 else: 663 self.fail("< didn't raise Exc") 664 665 def test_setdefault(self): 666 TestMappingProtocol.test_setdefault(self) 667 668 class Exc(Exception): pass 669 670 class BadHash(object): 671 fail = False 672 def __hash__(self): 673 if self.fail: 674 raise Exc() 675 else: 676 return 42 677 678 d = self._empty_mapping() 679 x = BadHash() 680 d[x] = 42 681 x.fail = True 682 self.assertRaises(Exc, d.setdefault, x, []) 683