1""" 2Tests to ensure that NSDictionary and NSMutableDictionary conform 3to the python dict interface 4 5These tests are basicly a port of the Python 3.2 tests for dictionaries 6and dictionary views. 7 8TODO: 9- Port all tests 10- Do the same for python 2.x 11- Do the same for sets (NSSet) and lists (NSArray) 12""" 13from PyObjCTools.TestSupport import * 14import objc 15 16# Import some of the stdlib tests 17from test import mapping_tests 18 19NSDictionary = objc.lookUpClass('NSDictionary') 20NSMutableDictionary = objc.lookUpClass('NSMutableDictionary') 21 22class TestNSDictionaryInterface (TestCase): 23 def dictClass(self): 24 return NSDictionary 25 26 def createDictionary(self, **kwds): 27 return NSDictionary.dictionaryWithDictionary_(kwds) 28 29 def testConstructor(self): 30 value = self.dictClass()() 31 self.assertEqual(value, {}) 32 33 def testBool(self): 34 self.assertIs(not self.createDictionary(), True) 35 self.assertTrue(self.createDictionary(foo='1')) 36 self.assertIs(bool(self.createDictionary()), False) 37 self.assertIs(bool(self.createDictionary(foo='1')), True) 38 39 def testKeys(self): 40 d = self.createDictionary() 41 self.assertEqual(set(d.keys()), set()) 42 43 d = self.createDictionary(a=1, b=2) 44 k = d.keys() 45 46 self.assertIn('a', d) 47 self.assertIn('b', d) 48 self.assertIn('a', k) 49 self.assertIn('b', k) 50 51 self.assertIsNotInstance(k, list) 52 53 self.assertEqual(repr(self.createDictionary(a=1).keys()), 54 "<nsdict_keys(['a'])>") 55 56 def testValues(self): 57 d = self.createDictionary() 58 self.assertEqual(set(d.values()), set()) 59 60 d = self.createDictionary(a=1) 61 62 self.assertEqual(set(d.values()), {1}) 63 self.assertRaises(TypeError, d.values, None) 64 self.assertIsNotInstance(d.values(), list) 65 66 self.assertEqual(repr(self.createDictionary(a=1).values()), 67 "<nsdict_values([1])>") 68 69 def testItems(self): 70 d = self.createDictionary() 71 self.assertEqual(set(d.items()), set()) 72 73 d = self.createDictionary(a=1) 74 self.assertEqual(set(d.items()), {('a', 1)}) 75 self.assertRaises(TypeError, d.items, None) 76 self.assertEqual(repr(self.createDictionary(a=1).items()), 77 "<nsdict_items([('a', 1)])>") 78 79 def testContains(self): 80 d = self.createDictionary() 81 self.assertNotIn('a', d) 82 self.assertFalse('a' in d) 83 self.assertTrue('a' not in d) 84 85 d = self.createDictionary(a=1, b=2) 86 self.assertIn('a', d) 87 self.assertIn('b', d) 88 self.assertNotIn('c', d) 89 90 self.assertRaises(TypeError, d.__contains__) 91 92 def testLen(self): 93 d = self.createDictionary() 94 self.assertEqual(len(d), 0) 95 96 d = self.createDictionary(a=1, b=2) 97 self.assertEqual(len(d), 2) 98 99 def testGetItem(self): 100 d = self.createDictionary(a=1, b=2) 101 self.assertEqual(d['a'], 1) 102 self.assertEqual(d['b'], 2) 103 104 self.assertRaises(TypeError, d.__getitem__) 105 106 def testFromKeys(self): 107 d = self.dictClass().fromkeys('abc') 108 self.assertEqual(d, {'a':None, 'b':None, 'c':None}) 109 110 d = self.createDictionary() 111 self.assertIsNot(d.fromkeys('abc'), d) 112 self.assertEqual(d.fromkeys('abc'), {'a':None, 'b':None, 'c':None}) 113 self.assertEqual(d.fromkeys((4,5),0), {4:0, 5:0}) 114 self.assertEqual(d.fromkeys([]), {}) 115 116 def g(): 117 yield 1 118 119 self.assertEqual(d.fromkeys(g()), {1:None}) 120 self.assertRaises(TypeError, {}.fromkeys, 3) 121 122 d = self.dictClass()(zip(range(6), range(6))) 123 self.assertEqual(dict.fromkeys(d, 0), dict(zip(range(6), [0]*6))) 124 125 def _testCopy(self): 126 self.fail("Decide what to do w.r.t. -copy and -mutableCopy") 127 128 def testGet(self): 129 d = self.createDictionary() 130 self.assertIs(d.get('c'), None) 131 self.assertEqual(d.get('c', 3), 3) 132 133 134 d = self.createDictionary(a=1, b=2) 135 self.assertIs(d.get('c'), None) 136 self.assertEqual(d.get('c', 3), 3) 137 self.assertEqual(d.get('a'), 1) 138 self.assertEqual(d.get('a', 3), 1) 139 self.assertRaises(TypeError, d.get) 140 self.assertRaises(TypeError, d.get, None, None, None) 141 142 143 def testEq(self): 144 self.assertEquals(self.createDictionary(), self.createDictionary()) 145 self.assertEquals(self.createDictionary(a=1), self.createDictionary(a=1)) 146 147 class Exc(Exception): pass 148 149 class BadCmp(object): 150 def __eq__(self, other): 151 raise Exc() 152 def __hash__(self): 153 return 1 154 155 d1 = {BadCmp(): 1} 156 d2 = {BadCmp(): 1} 157 158 with self.assertRaises(Exc): 159 d1 == d2 160 161 162 def testKeysContained(self): 163 self.helper_keys_contained(lambda x: x.keys()) 164 self.helper_keys_contained(lambda x: x.items()) 165 166 def helper_keys_contained(self, fn): 167 # Test rich comparisons against dict key views, which should behave the 168 # same as sets. 169 170 empty = fn(self.createDictionary()) 171 empty2 = fn(self.createDictionary()) 172 smaller = fn(self.createDictionary(a=1, b=2)) 173 larger = fn(self.createDictionary(a=1, b=2, c=3)) 174 larger2 = fn(self.createDictionary(a=1, b=2, c=3)) 175 larger3 = fn(self.createDictionary(d=1, b=2, c=3)) 176 177 self.assertTrue(smaller < larger) 178 self.assertTrue(smaller <= larger) 179 self.assertTrue(larger > smaller) 180 self.assertTrue(larger >= smaller) 181 182 self.assertFalse(smaller >= larger) 183 self.assertFalse(smaller > larger) 184 self.assertFalse(larger <= smaller) 185 self.assertFalse(larger < smaller) 186 187 self.assertFalse(smaller < larger3) 188 self.assertFalse(smaller <= larger3) 189 self.assertFalse(larger3 > smaller) 190 self.assertFalse(larger3 >= smaller) 191 192 # Inequality strictness 193 self.assertTrue(larger2 >= larger) 194 self.assertTrue(larger2 <= larger) 195 self.assertFalse(larger2 > larger) 196 self.assertFalse(larger2 < larger) 197 198 self.assertTrue(larger == larger2) 199 self.assertTrue(smaller != larger) 200 201 # There is an optimization on the zero-element case. 202 self.assertTrue(empty == empty2) 203 self.assertFalse(empty != empty2) 204 self.assertFalse(empty == smaller) 205 self.assertTrue(empty != smaller) 206 207 # With the same size, an elementwise compare happens 208 self.assertTrue(larger != larger3) 209 self.assertFalse(larger == larger3) 210 211 def testErrorsInViewContainmentCheck(self): 212 class C: 213 def __eq__(self, other): 214 raise RuntimeError 215 216 d1 = self.dictClass().dictionaryWithDictionary_({1: C()}) 217 d2 = self.dictClass().dictionaryWithDictionary_({1: C()}) 218 219 with self.assertRaises(RuntimeError): 220 d1.items() == d2.items() 221 with self.assertRaises(RuntimeError): 222 d1.items() != d2.items() 223 with self.assertRaises(RuntimeError): 224 d1.items() <= d2.items() 225 with self.assertRaises(RuntimeError): 226 d1.items() >= d2.items() 227 228 d3 = self.dictClass().dictionaryWithDictionary_({1: C(), 2: C()}) 229 with self.assertRaises(RuntimeError): 230 d2.items() < d3.items() 231 with self.assertRaises(RuntimeError): 232 d3.items() > d2.items() 233 234 k1 = self.dictClass().dictionaryWithDictionary_({1:1, 2:2}).keys() 235 k2 = self.dictClass().dictionaryWithDictionary_({1:1, 2:2, 3:3}).keys() 236 k3 = self.dictClass().dictionaryWithDictionary_({4:4}).keys() 237 238 self.assertEqual(k1 - k2, set()) 239 self.assertEqual(k1 - k3, {1,2}) 240 self.assertEqual(k2 - k1, {3}) 241 self.assertEqual(k3 - k1, {4}) 242 self.assertEqual(k1 & k2, {1,2}) 243 self.assertEqual(k1 & k3, set()) 244 self.assertEqual(k1 | k2, {1,2,3}) 245 self.assertEqual(k1 ^ k2, {3}) 246 self.assertEqual(k1 ^ k3, {1,2,4}) 247 248 def testDictviewSetOperationsOnItems(self): 249 k1 = self.dictClass().dictionaryWithDictionary_({1:1, 2:2}).items() 250 k2 = self.dictClass().dictionaryWithDictionary_({1:1, 2:2, 3:3}).items() 251 k3 = self.dictClass().dictionaryWithDictionary_({4:4}).items() 252 253 self.assertEqual(k1 - k2, set()) 254 self.assertEqual(k1 - k3, {(1,1), (2,2)}) 255 self.assertEqual(k2 - k1, {(3,3)}) 256 self.assertEqual(k3 - k1, {(4,4)}) 257 self.assertEqual(k1 & k2, {(1,1), (2,2)}) 258 self.assertEqual(k1 & k3, set()) 259 self.assertEqual(k1 | k2, {(1,1), (2,2), (3,3)}) 260 self.assertEqual(k1 ^ k2, {(3,3)}) 261 self.assertEqual(k1 ^ k3, {(1,1), (2,2), (4,4)}) 262 263 def testDictviewMixedSetOperations(self): 264 # Just a few for .keys() 265 self.assertTrue(self.dictClass().dictionaryWithDictionary_({1:1}).keys() == {1}) 266 self.assertTrue({1} == self.dictClass().dictionaryWithDictionary_({1:1}).keys()) 267 self.assertEqual(self.dictClass().dictionaryWithDictionary_({1:1}).keys() | {2}, {1, 2}) 268 self.assertEqual({2} | self.dictClass().dictionaryWithDictionary_({1:1}).keys(), {1, 2}) 269 # And a few for .items() 270 self.assertTrue(self.dictClass().dictionaryWithDictionary_({1:1}).items() == {(1,1)}) 271 self.assertTrue({(1,1)} == self.dictClass().dictionaryWithDictionary_({1:1}).items()) 272 self.assertEqual(self.dictClass().dictionaryWithDictionary_({1:1}).items() | {2}, {(1,1), 2}) 273 self.assertEqual({2} | self.dictClass().dictionaryWithDictionary_({1:1}).items(), {(1,1), 2}) 274 275 276class TestNSMutableDictionaryInterface (TestNSDictionaryInterface): 277 def dictClass(self): 278 return NSMutableDictionary 279 280 def createDictionary(self, **kwds): 281 return NSMutableDictionary.dictionaryWithDictionary_(kwds) 282 283 def testKeysMutable(self): 284 d = self.createDictionary() 285 self.assertEqual(set(d.keys()), set()) 286 287 d = self.createDictionary(a=1, b=2) 288 k = d.keys() 289 290 self.assertIn('a', d) 291 self.assertIn('b', d) 292 self.assertIn('a', k) 293 self.assertIn('b', k) 294 295 self.assertIsNotInstance(k, list) 296 297 self.assertNotIn('c', d) 298 self.assertNotIn('c', k) 299 300 d['c'] = 3 301 self.assertIn('c', d) 302 self.assertIn('c', k) 303 304 def testValuesMutable(self): 305 d = self.createDictionary() 306 self.assertEqual(set(d.values()), set()) 307 308 d = self.createDictionary(a=1) 309 v = d.values() 310 311 self.assertEqual(set(v), {1}) 312 313 d['b'] = 2 314 self.assertEqual(set(v), {1, 2}) 315 316 def testItemsMutable(self): 317 d = self.createDictionary() 318 self.assertEqual(set(d.items()), set()) 319 320 d = self.createDictionary(a=1) 321 i = d.items() 322 323 self.assertEqual(set(i), {('a', 1)}) 324 325 d['b'] = 2 326 327 self.assertEqual(set(i), {('a', 1), ('b', 2)}) 328 329 def testGetItem(self): 330 d = self.createDictionary(a=1, b=2) 331 self.assertEqual(d['a'], 1) 332 self.assertEqual(d['b'], 2) 333 334 d['c'] = 3 335 d['a'] = 4 336 self.assertEqual(d['c'], 3) 337 self.assertEqual(d['a'], 4) 338 del d['b'] 339 self.assertEqual(d, {'a': 4, 'c': 3}) 340 341 self.assertRaises(TypeError, d.__getitem__) 342 343 class Exc (Exception): pass 344 345 class BadEq(object): 346 def __eq__(self, other): 347 raise Exc() 348 def __hash__(self): 349 return hash(23) 350 351 d = self.createDictionary() 352 d[BadEq()] = 42 353 self.assertRaises(KeyError, d.__getitem__, 23) 354 355 class BadHash(object): 356 fail = False 357 def __hash__(self): 358 if self.fail: 359 raise Exc() 360 else: 361 return 42 362 363 d = self.createDictionary() 364 x = BadHash() 365 d[x] = 42 366 x.fail = True 367 368 # FIXME 369 #self.assertRaises(Exc, d.__getitem__, x) 370 371 def testClear(self): 372 d = self.createDictionary(a=1, b=2, c=3) 373 d.clear() 374 375 self.assertEqual(d, {}) 376 377 self.assertRaises(TypeError, d.clear, None) 378 379 def testUpdate(self): 380 d = self.createDictionary() 381 d.update({1:100}) 382 d.update({2:20}) 383 d.update({1:1, 2:2, 3:3}) 384 self.assertEqual(d, {1:1, 2:2, 3:3}) 385 386 d.update() 387 self.assertEqual(d, {1:1, 2:2, 3:3}) 388 389 self.assertRaises((TypeError, AttributeError), d.update, None) 390 391 class SimpleUserDict: 392 def __init__(self): 393 self.d = {1:1, 2:2, 3:3} 394 def keys(self): 395 return self.d.keys() 396 def __getitem__(self, i): 397 return self.d[i] 398 399 d = self.createDictionary() 400 d.update(SimpleUserDict()) 401 self.assertEqual(d, {1:1, 2:2, 3:3}) 402 403 class Exc(Exception): pass 404 405 d.clear() 406 407 class FailingUserDict: 408 def keys(self): 409 raise Exc() 410 411 self.assertRaises(Exc, d.update, FailingUserDict()) 412 413 414 class FailingUserDict: 415 def keys(self): 416 class BogonIter: 417 def __init__(self): 418 self.i = 1 419 def __iter__(self): 420 return self 421 def __next__(self): 422 if self.i: 423 self.i = 0 424 return 'a' 425 raise Exc 426 return BogonIter() 427 def __getitem__(self, key): 428 return key 429 430 self.assertRaises(Exc, d.update, FailingUserDict()) 431 432 433 class FailingUserDict: 434 def keys(self): 435 class BogonIter: 436 def __init__(self): 437 self.i = ord('a') 438 def __iter__(self): 439 return self 440 def __next__(self): 441 if self.i <= ord('z'): 442 rtn = chr(self.i) 443 self.i += 1 444 return rtn 445 raise StopIteration 446 return BogonIter() 447 def __getitem__(self, key): 448 raise Exc 449 self.assertRaises(Exc, d.update, FailingUserDict()) 450 451 class badseq(object): 452 def __iter__(self): 453 return self 454 def __next__(self): 455 raise Exc() 456 457 self.assertRaises(Exc, {}.update, badseq()) 458 self.assertRaises(ValueError, {}.update, [(1, 2, 3)]) 459 460 461 def setDefault(self): 462 d = self.createDictionary() 463 self.assertIs(d.setdefault('key0'), None) 464 d.setdefault('key0', []) 465 self.assertIs(d.setdefault('key0'), None) 466 d.setdefault('key', []).append(3) 467 self.assertEqual(d['key'][0], 3) 468 d.setdefault('key', []).append(4) 469 self.assertEqual(len(d['key']), 2) 470 self.assertRaises(TypeError, d.setdefault) 471 472 class Exc (Exception): pass 473 474 class BadHash(object): 475 fail = False 476 def __hash__(self): 477 if self.fail: 478 raise Exc() 479 else: 480 return 42 481 482 x = BadHash() 483 d[x] = 42 484 x.fail = True 485 self.assertRaises(Exc, d.setdefault, x, []) 486 487 def testPopitem(self): 488 for copymode in -1, +1: 489 # -1: b has same structure as a 490 # +1: b is a.copy() 491 for log2size in range(12): 492 size = 2**log2size 493 a = self.createDictionary() 494 b = self.createDictionary() 495 for i in range(size): 496 a[repr(i)] = i 497 if copymode < 0: 498 b[repr(i)] = i 499 if copymode > 0: 500 b = a.mutableCopy() 501 for i in range(size): 502 ka, va = ta = a.popitem() 503 self.assertEqual(va, int(ka)) 504 kb, vb = tb = b.popitem() 505 self.assertEqual(vb, int(kb)) 506 self.assertFalse(copymode < 0 and ta != tb) 507 self.assertFalse(a) 508 self.assertFalse(b) 509 510 d = self.createDictionary() 511 self.assertRaises(KeyError, d.popitem) 512 513 514 def testPop(self): 515 d = self.createDictionary() 516 k, v = 'abc', 'def' 517 d[k] = v 518 self.assertRaises(KeyError, d.pop, 'ghi') 519 520 self.assertEqual(d.pop(k), v) 521 self.assertEqual(len(d), 0) 522 523 self.assertRaises(KeyError, d.pop, k) 524 525 self.assertEqual(d.pop(k, v), v) 526 d[k] = v 527 self.assertEqual(d.pop(k, 1), v) 528 529 self.assertRaises(TypeError, d.pop) 530 531 class Exc(Exception): pass 532 533 class BadHash(object): 534 fail = False 535 def __hash__(self): 536 if self.fail: 537 raise Exc() 538 else: 539 return 42 540 541 #x = BadHash() 542 #d[x] = 42 543 #x.fail = True 544 #self.assertRaises(Exc, d.pop, x) 545 546class DictSetTest (TestCase): 547 testclass = NSDictionary 548 549 def testDictKeys(self): 550 d = self.testclass.dictionaryWithDictionary_({1: 10, "a": "ABC"}) 551 552 keys = d.keys() 553 554 self.assertEqual(len(keys), 2) 555 self.assertEqual(set(keys), {1, "a"}) 556 self.assertEqual(keys, {1, "a"}) 557 self.assertNotEqual(keys, {1, "a", "b"}) 558 self.assertNotEqual(keys, {1, "b"}) 559 self.assertNotEqual(keys, {1}) 560 self.assertNotEqual(keys, 42) 561 self.assertIn(1, keys) 562 self.assertIn("a", keys) 563 self.assertNotIn(10, keys) 564 self.assertNotIn("Z", keys) 565 self.assertEqual(d.keys(), d.keys()) 566 567 e = self.testclass.dictionaryWithDictionary_({1: 11, "a": "def"}) 568 self.assertEqual(d.keys(), e.keys()) 569 570 def testDictItems(self): 571 d = self.testclass.dictionaryWithDictionary_({1: 10, "a": "ABC"}) 572 items = d.items() 573 574 self.assertEqual(len(items), 2) 575 self.assertEqual(set(items), {(1, 10), ("a", "ABC")}) 576 self.assertEqual(items, {(1, 10), ("a", "ABC")}) 577 self.assertNotEqual(items, {(1, 10), ("a", "ABC"), "junk"}) 578 self.assertNotEqual(items, {(1, 10), ("a", "def")}) 579 self.assertNotEqual(items, {(1, 10)}) 580 self.assertNotEqual(items, 42) 581 self.assertIn((1, 10), items) 582 self.assertIn(("a", "ABC"), items) 583 self.assertNotIn((1, 11), items) 584 self.assertNotIn(1, items) 585 self.assertNotIn((), items) 586 self.assertNotIn((1,), items) 587 self.assertNotIn((1, 2, 3), items) 588 self.assertEqual(d.items(), d.items()) 589 590 e = d.copy() 591 self.assertEqual(d.items(), e.items()) 592 593 594 595class DictSetTest (DictSetTest): 596 testclass = NSMutableDictionary 597 598 def testDictKeysMutable(self): 599 d = self.testclass.dictionaryWithDictionary_({1: 10, "a": "ABC"}) 600 e = self.testclass.dictionaryWithDictionary_({1: 11, "a": "def"}) 601 self.assertEqual(d.keys(), e.keys()) 602 603 del e["a"] 604 self.assertNotEqual(d.keys(), e.keys()) 605 606 def testDictItemsMutable(self): 607 d = self.testclass.dictionaryWithDictionary_({1: 10, "a": "ABC"}) 608 609 e = d.copy() 610 self.assertEqual(d.items(), e.items()) 611 d["a"] = "def" 612 self.assertNotEqual(d.items(), e.items()) 613 614 def testDictMixedKeysItems(self): 615 d = self.testclass.dictionaryWithDictionary_( 616 {(1, 1): 11, (2, 2): 22}) 617 e = self.testclass.dictionaryWithDictionary_( 618 {1: 1, 2: 2}) 619 self.assertEqual(d.keys(), e.items()) 620 self.assertNotEqual(d.items(), e.keys()) 621 622 def testDictValues(self): 623 d = self.testclass.dictionaryWithDictionary_( 624 {1: 10, "a": "ABC"}) 625 values = d.values() 626 self.assertEqual(set(values), {10, "ABC"}) 627 self.assertEqual(len(values), 2) 628 629 630 631 632 633class GeneralMappingTestsNSMutableDictionary ( 634 mapping_tests.BasicTestMappingProtocol): 635 type2test = NSMutableDictionary 636 637 638import collections 639 640class TestABC (TestCase): 641 def testDictABC(self): 642 self.assertTrue(issubclass(NSDictionary, collections.Mapping)) 643 self.assertTrue(issubclass(NSMutableDictionary, collections.Mapping)) 644 self.assertTrue(issubclass(NSMutableDictionary, collections.MutableMapping)) 645 646 def testViewABC(self): 647 d = NSDictionary.dictionary() 648 self.assertTrue(isinstance(d.keys(), collections.KeysView)) 649 self.assertTrue(isinstance(d.values(), collections.ValuesView)) 650 self.assertTrue(isinstance(d.items(), collections.ItemsView)) 651 652 d = NSMutableDictionary.dictionary() 653 self.assertTrue(isinstance(d.keys(), collections.KeysView)) 654 self.assertTrue(isinstance(d.values(), collections.ValuesView)) 655 self.assertTrue(isinstance(d.items(), collections.ItemsView)) 656 657if __name__ == "__main__": 658 main() 659