1from PyObjCTools.TestSupport import * 2import objc 3import collections 4 5NSObject = objc.lookUpClass('NSObject') 6NSIndexSet = objc.lookUpClass('NSIndexSet') 7NSMutableIndexSet = objc.lookUpClass('NSMutableIndexSet') 8 9class TestArrayPropertyHelper (NSObject): 10 array = objc.array_property() 11 roArray = objc.array_property(read_only=True) 12 13from PyObjCTest.test_object_property import OCObserve 14 15class TestArrayProperty (TestCase): 16 def _testMissing(self): 17 self.fail("Implement tests") 18 19 def testGetting(self): 20 # Check that default value is an empty value 21 # Check that value is a proxy object 22 o = TestArrayPropertyHelper.alloc().init() 23 24 v = o.array 25 self.failUnlessIsInstance(v, collections.MutableSequence) 26 27 self.failUnlessEqual(len(v), 0) 28 29 v.append(1) 30 self.failUnlessEqual(len(v), 1) 31 32 self.assertEquals(type(v).__name__, 'array_proxy') 33 34 def testSetting(self): 35 # Set value, check that 36 # (1) value gets copied 37 # (2) accessing the property result in proxy 38 observer = OCObserve.alloc().init() 39 l = [1, 2, 3] 40 o = TestArrayPropertyHelper.alloc().init() 41 observer.register(o, 'array') 42 try: 43 self.assertEquals(len(observer.values), 0) 44 self.assertEquals(len(o.array), 0) 45 self.assertEquals(len(observer.values), 0) 46 o.array = l 47 self.assertEquals(len(observer.values), 1) 48 49 50 self.assertEquals(len(o.array), 3) 51 52 # This shouldn't affect the property 53 l.append(4) 54 self.assertEquals(len(o.array), 3) 55 56 self.assertEquals(len(l), 4) 57 o.array.append(5) 58 self.assertEquals(len(l), 4) 59 60 finally: 61 observer.unregister(o, 'array') 62 63 64 65 def testGetSetItem(self): 66 # Use __getitem__, __setitem__ interface and check 67 # that the correct KVO events get emitted. 68 observer = OCObserve.alloc().init() 69 l = [1, 2, 3] 70 o = TestArrayPropertyHelper.alloc().init() 71 observer.register(o, 'array') 72 73 # FIXME: the call to len shouldn't be necessary 74 len(o.array) 75 try: 76 IS = NSIndexSet.alloc().initWithIndex_(0) 77 self.assertEquals(len(observer.values), 0) 78 79 o.array.append(1) 80 81 self.assertEquals(len(observer.values), 1) 82 self.assertEquals(observer.values[-1][-1]['indexes'], IS) 83 self.assertEquals(observer.values[-1][-1]['new'], [1]) 84 85 86 self.assertEquals(o.array[0], 1) 87 o.array[0] = 4 88 self.assertEquals(o.array[0], 4) 89 self.assertEquals(len(observer.values), 2) 90 self.assertEquals(observer.values[-1][-1]['indexes'], IS) 91 self.assertEquals(observer.values[-1][-1]['old'], [1]) 92 self.assertEquals(observer.values[-1][-1]['new'], [4]) 93 94 finally: 95 observer.unregister(o, 'array') 96 97 def testGetSetSlice(self): 98 # Same as testGetSetItem, but using slice 99 observer = OCObserve.alloc().init() 100 l = [1, 2, 3] 101 o = TestArrayPropertyHelper.alloc().init() 102 observer.register(o, 'array') 103 104 try: 105 IS = NSIndexSet.alloc().initWithIndexesInRange_((0, 3)) 106 IS2 = NSIndexSet.alloc().initWithIndexesInRange_((1, 2)) 107 IS3 = NSMutableIndexSet.alloc().init() 108 IS3.addIndex_(0) 109 IS3.addIndex_(2) 110 self.assertEquals(len(observer.values), 0) 111 112 o.array = l 113 114 self.assertEquals(len(observer.values), 1) 115 self.assertNotIn('indexes', observer.values[-1][-1]) 116 self.assertEquals(observer.values[-1][-1]['new'], [1, 2, 3]) 117 118 119 self.assertEquals(o.array[0], 1) 120 o.array[1:3] = [4, 5] 121 self.assertEquals(o.array[1], 4) 122 self.assertEquals(o.array[2], 5) 123 self.assertEquals(len(observer.values), 2) 124 self.assertEquals(observer.values[-1][-1]['indexes'], IS2) 125 self.assertEquals(observer.values[-1][-1]['old'], [2, 3]) 126 self.assertEquals(observer.values[-1][-1]['new'], [4, 5]) 127 128 self.assertEquals(o.array[0], 1) 129 o.array[0:3:2] = [9, 10] 130 self.assertEquals(o.array[0], 9) 131 self.assertEquals(o.array[1], 4) 132 self.assertEquals(o.array[2], 10) 133 self.assertEquals(len(observer.values), 3) 134 self.assertEquals(observer.values[-1][-1]['indexes'], IS3) 135 self.assertEquals(observer.values[-1][-1]['old'], [1, 5]) 136 self.assertEquals(observer.values[-1][-1]['new'], [9, 10]) 137 138 finally: 139 observer.unregister(o, 'array') 140 141 def testInsert(self): 142 # Use insert method and check that the correct 143 # KVO events get emitted 144 # Same as testGetSetItem, but using slice 145 observer = OCObserve.alloc().init() 146 l = [1, 2, 3] 147 o = TestArrayPropertyHelper.alloc().init() 148 observer.register(o, 'array') 149 150 try: 151 IS = NSIndexSet.alloc().initWithIndex_(0) 152 IS1 = NSIndexSet.alloc().initWithIndex_(4) 153 self.assertEquals(len(observer.values), 0) 154 155 o.array = l 156 157 self.assertEquals(len(observer.values), 1) 158 self.assertNotIn('indexes', observer.values[-1][-1]) 159 160 self.assertEquals(o.array[0], 1) 161 162 163 o.array.insert(0, 'a') 164 self.assertEquals(o.array[0], 'a') 165 self.assertEquals(len(o.array), 4) 166 167 self.assertEquals(len(observer.values), 2) 168 self.assertEquals(observer.values[-1][-1]['indexes'], IS) 169 self.assertNotIn('old', observer.values[-1][-1]) 170 self.assertEquals(observer.values[-1][-1]['new'], ['a']) 171 172 o.array.insert(4, 'b') 173 self.assertEquals(o.array[4], 'b') 174 self.assertEquals(len(o.array), 5) 175 176 self.assertEquals(len(observer.values), 3) 177 self.assertEquals(observer.values[-1][-1]['indexes'], IS1) 178 self.assertNotIn('old', observer.values[-1][-1]) 179 self.assertEquals(observer.values[-1][-1]['new'], ['b']) 180 181 finally: 182 observer.unregister(o, 'array') 183 184 def testPop(self): 185 # Use pop method and check that the correct 186 # KVO events get emitted 187 observer = OCObserve.alloc().init() 188 l = [1, 2, 3, 4] 189 o = TestArrayPropertyHelper.alloc().init() 190 observer.register(o, 'array') 191 192 try: 193 IS = NSIndexSet.alloc().initWithIndex_(0) 194 IS2 = NSIndexSet.alloc().initWithIndex_(2) 195 self.assertEquals(len(observer.values), 0) 196 197 o.array = l 198 199 self.assertEquals(len(observer.values), 1) 200 self.assertNotIn('indexes', observer.values[-1][-1]) 201 202 self.assertEquals(o.array[0], 1) 203 204 205 v = o.array.pop(0) 206 self.assertEquals(v, 1) 207 self.assertEquals(o.array[0], 2) 208 self.assertEquals(len(o.array), 3) 209 210 self.assertEquals(len(observer.values), 2) 211 self.assertEquals(observer.values[-1][-1]['indexes'], IS) 212 self.assertNotIn('new', observer.values[-1][-1]) 213 self.assertEquals(observer.values[-1][-1]['old'], [1]) 214 215 v = o.array.pop(2) 216 self.assertEquals(v, 4) 217 self.assertEquals(len(o.array), 2) 218 219 self.assertEquals(len(observer.values), 3) 220 self.assertEquals(observer.values[-1][-1]['indexes'], IS2) 221 self.assertNotIn('new', observer.values[-1][-1]) 222 self.assertEquals(observer.values[-1][-1]['old'], [4]) 223 224 finally: 225 observer.unregister(o, 'array') 226 227 def testDelItem(self): 228 # Use __delitem__and check that the correct 229 # KVO events get emitted 230 observer = OCObserve.alloc().init() 231 l = [1, 2, 3, 4] 232 o = TestArrayPropertyHelper.alloc().init() 233 observer.register(o, 'array') 234 235 try: 236 IS = NSIndexSet.alloc().initWithIndex_(0) 237 IS2 = NSIndexSet.alloc().initWithIndex_(2) 238 self.assertEquals(len(observer.values), 0) 239 240 o.array = l 241 242 self.assertEquals(len(observer.values), 1) 243 self.assertNotIn('indexes', observer.values[-1][-1]) 244 245 self.assertEquals(o.array[0], 1) 246 247 248 del o.array[0] 249 self.assertEquals(o.array[0], 2) 250 self.assertEquals(len(o.array), 3) 251 252 self.assertEquals(len(observer.values), 2) 253 self.assertEquals(observer.values[-1][-1]['indexes'], IS) 254 self.assertNotIn('new', observer.values[-1][-1]) 255 self.assertEquals(observer.values[-1][-1]['old'], [1]) 256 257 del o.array[2] 258 self.assertEquals(len(o.array), 2) 259 260 self.assertEquals(len(observer.values), 3) 261 self.assertEquals(observer.values[-1][-1]['indexes'], IS2) 262 self.assertNotIn('new', observer.values[-1][-1]) 263 self.assertEquals(observer.values[-1][-1]['old'], [4]) 264 265 finally: 266 observer.unregister(o, 'array') 267 268 def testDelSlice(self): 269 # As testDelItem, but using slices 270 observer = OCObserve.alloc().init() 271 l = [1, 2, 3, 4] 272 o = TestArrayPropertyHelper.alloc().init() 273 observer.register(o, 'array') 274 275 try: 276 IS = NSMutableIndexSet.alloc().init() 277 IS.addIndex_(0) 278 IS.addIndex_(2) 279 self.assertEquals(len(observer.values), 0) 280 281 o.array = l 282 283 self.assertEquals(len(observer.values), 1) 284 self.assertNotIn('indexes', observer.values[-1][-1]) 285 286 self.assertEquals(o.array[0], 1) 287 288 289 del o.array[0:4:2] 290 self.assertEquals(o.array[0], 2) 291 self.assertEquals(o.array[1], 4) 292 self.assertEquals(len(o.array), 2) 293 294 self.assertEquals(len(observer.values), 2) 295 self.assertEquals(observer.values[-1][-1]['indexes'], IS) 296 self.assertNotIn('new', observer.values[-1][-1]) 297 self.assertEquals(observer.values[-1][-1]['old'], [1, 3]) 298 299 finally: 300 observer.unregister(o, 'array') 301 302 def testExtend(self): 303 observer = OCObserve.alloc().init() 304 l = [1, 2, 3, 4] 305 l2 = ['a', 'b', 'c'] 306 o = TestArrayPropertyHelper.alloc().init() 307 observer.register(o, 'array') 308 309 try: 310 o.array = l 311 312 self.assertEquals(len(observer.values), 1) 313 self.assertEquals(o.array[0], 1) 314 315 o.array.extend(l2) 316 317 self.assertEquals(len(o.array), 7) 318 self.assertEquals(o.array[4], 'a') 319 320 self.assertEquals(len(observer.values), 2) 321 self.assertEquals(observer.values[-1][-1]['indexes'], NSIndexSet.alloc().initWithIndexesInRange_((4, 3))) 322 self.assertNotIn('old', observer.values[-1][-1]) 323 self.assertEquals(observer.values[-1][-1]['new'], ['a', 'b', 'c']) 324 325 finally: 326 observer.unregister(o, 'array') 327 328 def testIAdd(self): 329 observer = OCObserve.alloc().init() 330 l = [1, 2, 3, 4] 331 l2 = ['a', 'b', 'c'] 332 o = TestArrayPropertyHelper.alloc().init() 333 observer.register(o, 'array') 334 335 try: 336 o.array = l 337 338 self.assertEquals(len(observer.values), 1) 339 self.assertEquals(o.array[0], 1) 340 341 o.array += l2 342 343 self.assertEquals(len(o.array), 7) 344 self.assertEquals(o.array[4], 'a') 345 346 #self.assertEquals(len(observer.values), 3) 347 #self.assertEquals(observer.values[-2][-1]['indexes'], NSIndexSet.alloc().initWithIndexesInRange_((4, 3))) 348 #self.assertNotIn('old', observer.values[-2][-1]) 349 #self.assertEquals(observer.values[-2][-1]['new'], ['a', 'b', 'c']) 350 351 self.assertEquals(len(observer.values), 2) 352 self.assertNotIn('indexes', observer.values[-1][-1]) 353 354 finally: 355 observer.unregister(o, 'array') 356 357 def testIMul(self): 358 observer = OCObserve.alloc().init() 359 l = [1, 2] 360 o = TestArrayPropertyHelper.alloc().init() 361 observer.register(o, 'array') 362 363 try: 364 o.array = l 365 366 self.assertEquals(len(observer.values), 1) 367 self.assertEquals(o.array[0], 1) 368 369 o.array *= 3 370 371 self.assertEquals(len(o.array), 6) 372 self.assertEquals(o.array[0], 1) 373 self.assertEquals(o.array[1], 2) 374 self.assertEquals(o.array[2], 1) 375 self.assertEquals(o.array[3], 2) 376 self.assertEquals(o.array[4], 1) 377 self.assertEquals(o.array[5], 2) 378 379 #self.assertEquals(len(observer.values), 3) 380 #self.assertEquals(observer.values[-2][-1]['indexes'], NSIndexSet.alloc().initWithIndexesInRange_((2, 4))) 381 #self.assertNotIn('old', observer.values[-2][-1]) 382 #self.assertEquals(observer.values[-2][-1]['new'], [1, 2, 1, 2]) 383 384 self.assertEquals(len(observer.values), 2) 385 self.assertNotIn('indexes', observer.values[-1][-1]) 386 387 finally: 388 observer.unregister(o, 'array') 389 390 391 def testSort(self): 392 # Use sort method and check that the correct 393 # KVO events get emitted 394 observer = OCObserve.alloc().init() 395 l = [2, 4, 1, 3] 396 o = TestArrayPropertyHelper.alloc().init() 397 observer.register(o, 'array') 398 399 try: 400 IS = NSIndexSet.alloc().initWithIndexesInRange_((0, 4)) 401 self.assertEquals(len(observer.values), 0) 402 403 orig_l = l[:] 404 o.array = l 405 406 407 self.assertEquals(len(observer.values), 1) 408 self.assertNotIn('indexes', observer.values[-1][-1]) 409 410 self.assertEquals(o.array[0], 2) 411 412 o.array.sort() 413 414 self.assertEquals(o.array[0], 1) 415 self.assertEquals(o.array[1], 2) 416 self.assertEquals(o.array[2], 3) 417 self.assertEquals(o.array[3], 4) 418 self.assertEquals(len(o.array), 4) 419 420 self.assertEquals(len(observer.values), 2) 421 self.assertEquals(observer.values[-1][-1]['indexes'], IS) 422 self.assertEquals(observer.values[-1][-1]['old'], l) 423 self.assertEquals(observer.values[-1][-1]['new'], [1,2,3,4]) 424 self.assertEquals(orig_l, l) 425 426 finally: 427 observer.unregister(o, 'array') 428 429 def testReverse(self): 430 # Use reverse method and check that the correct 431 # KVO events get emitted 432 observer = OCObserve.alloc().init() 433 l = [2, 4, 1, 3] 434 o = TestArrayPropertyHelper.alloc().init() 435 observer.register(o, 'array') 436 437 try: 438 IS = NSIndexSet.alloc().initWithIndexesInRange_((0, 4)) 439 self.assertEquals(len(observer.values), 0) 440 441 orig_l = l[:] 442 o.array = l 443 444 445 self.assertEquals(len(observer.values), 1) 446 self.assertNotIn('indexes', observer.values[-1][-1]) 447 448 self.assertEquals(o.array[0], 2) 449 450 o.array.reverse() 451 452 self.assertEquals(o.array[0], 3) 453 self.assertEquals(o.array[1], 1) 454 self.assertEquals(o.array[2], 4) 455 self.assertEquals(o.array[3], 2) 456 self.assertEquals(len(o.array), 4) 457 458 self.assertEquals(len(observer.values), 2) 459 self.assertEquals(observer.values[-1][-1]['indexes'], IS) 460 self.assertEquals(observer.values[-1][-1]['old'], l) 461 self.assertEquals(observer.values[-1][-1]['new'], [3, 1, 4, 2]) 462 self.assertEquals(orig_l, l) 463 464 finally: 465 observer.unregister(o, 'array') 466 467 def testObjCAccessors(self): 468 # Check that the right ObjC array accessors are defined and work properly 469 self.assertTrue(TestArrayPropertyHelper.instancesRespondToSelector_(b"setArray:")) 470 self.assertTrue(TestArrayPropertyHelper.instancesRespondToSelector_(b"array")) 471 self.assertTrue(TestArrayPropertyHelper.instancesRespondToSelector_(b"countOfArray")) 472 self.assertTrue(TestArrayPropertyHelper.instancesRespondToSelector_(b"objectInArrayAtIndex:")) 473 self.assertTrue(TestArrayPropertyHelper.instancesRespondToSelector_(b"insertObject:inArrayAtIndex:")) 474 self.assertTrue(TestArrayPropertyHelper.instancesRespondToSelector_(b"removeObjectFromArrayAtIndex:")) 475 self.assertTrue(TestArrayPropertyHelper.instancesRespondToSelector_(b"replaceObjectInArrayAtIndex:withObject:")) 476 477 o = TestArrayPropertyHelper.alloc().init() 478 self.assertEquals(0, o.pyobjc_instanceMethods.countOfArray()) 479 self.assertRaises(AttributeError, getattr, o, 'countOfArray') 480 481 o.pyobjc_instanceMethods.insertObject_inArrayAtIndex_('a', 0) 482 self.assertEquals(1, o.pyobjc_instanceMethods.countOfArray()) 483 self.assertEquals('a', o.array[0]) 484 self.assertEquals('a', o.pyobjc_instanceMethods.objectInArrayAtIndex_(0)) 485 o.pyobjc_instanceMethods.replaceObjectInArrayAtIndex_withObject_(0, 'b') 486 self.assertEquals('b', o.array[0]) 487 o.pyobjc_instanceMethods.removeObjectFromArrayAtIndex_(0) 488 self.assertEquals(0, o.pyobjc_instanceMethods.countOfArray()) 489 490 491 # Verify docs and/or implementation to check for other 492 # mutating methods 493 494 def testReadingMethods(self): 495 # Check that all read-only methods work as well 496 497 o = TestArrayPropertyHelper.alloc().init() 498 o.array = [1, 2, 3, 4] 499 500 self.assertNotIsInstance(o.array, list) 501 502 self.assertEquals(o.array, [1,2,3,4]) 503 self.assertNotEquals(o.array, [1,2,3,4, 5]) 504 505 506 self.assertTrue(o.array < [1,2,3,4,5]) 507 self.assertTrue(o.array <= [1,2,3,4,5]) 508 self.assertTrue(o.array <= [1,2,3,4]) 509 self.assertTrue(o.array >= [1,2,3,4]) 510 self.assertTrue(o.array > [1,2,3]) 511 512 self.assertEquals(o.array.count(1), 1) 513 self.assertEquals(o.array.index(4), 3) 514 515 def testMutatingReadonlyProperty(self): 516 # Check that trying to mutate a read-only property 517 # will raise an exception 518 o = TestArrayPropertyHelper.alloc().init() 519 520 o._roArray = [1, 2, 3] 521 522 self.assertEquals(list(o.roArray), [1,2,3]) 523 524 self.assertRaises(ValueError, o.roArray.append,1) 525 self.assertRaises(ValueError, o.roArray.extend, [1,2]) 526 self.assertRaises(ValueError, o.roArray.sort) 527 self.assertRaises(ValueError, o.roArray.reverse) 528 try: 529 o.roArray[0] = 2 530 except ValueError: 531 pass 532 else: 533 self.fail("ValueError not raised") 534 535 try: 536 del o.roArray[0] 537 except ValueError: 538 pass 539 else: 540 self.fail("ValueError not raised") 541 542 try: 543 o.roArray += [4] 544 except ValueError: 545 pass 546 else: 547 self.fail("ValueError not raised") 548 549 try: 550 o.roArray *= 4 551 except ValueError: 552 pass 553 else: 554 self.fail("TypeError not raised") 555 556 557 def testMutatingReadonlyPropertyObjC(self): 558 # Check that trying to mutate a read-only property 559 # from ObjC will raise an exception 560 o = TestArrayPropertyHelper.alloc().init() 561 o._roArray = [1,2,3] 562 self.assertEquals(3, o.pyobjc_instanceMethods.countOfRoArray()) 563 self.assertRaises(AttributeError, getattr, o, 'countOfRoArray') 564 565 try: 566 o.pyobjc_instanceMethods.insertObject_inRoArrayAtIndex_('a', 0) 567 except ValueError: 568 pass 569 else: 570 self.fail("ValueError not raised") 571 572 self.assertEquals(3, o.pyobjc_instanceMethods.countOfRoArray()) 573 self.assertEquals(1, o.pyobjc_instanceMethods.objectInRoArrayAtIndex_(0)) 574 try: 575 o.pyobjc_instanceMethods.replaceObjectInRoArrayAtIndex_withObject_(0, 'b') 576 except ValueError: 577 pass 578 else: 579 self.fail("ValueError not raised") 580 581 try: 582 o.pyobjc_instanceMethods.removeObjectFromRoArrayAtIndex_(0) 583 except ValueError: 584 pass 585 else: 586 self.fail("ValueError not raised") 587 588 589 def testAssingmentInteraction(self): 590 o = TestArrayPropertyHelper.alloc().init() 591 array = o.array 592 593 o.array.append(1) 594 self.assertEquals(len(o.array), 1) 595 self.assertEquals(len(array), 1) 596 597if __name__ == "__main__": 598 main() 599