1""" 2Tests for the Key-Value Coding for hybrid python objects. 3 4NOTE: Testcases here should be synchronized with the Key-Value Coding tests 5in PyObjCTools.test.test_keyvalue and objc.test.test_keyvalue. 6 7TODO: 8 - This test uses C code, that code should be added to this package! 9 - Tests that access properties in the parent Objective-C class! 10 - More key-error tests, the tests don't cover all relevant code yet. 11""" 12import objc 13from PyObjCTools.TestSupport import * 14import sys 15from PyObjCTest.testhelper import PyObjC_TestClass3 as STUB 16from Foundation import * 17 18class KeyValueClass1 (NSObject): 19 def init(self): 20 self = super(KeyValueClass1, self).init() 21 self.key3 = 3 22 self._key4 = u"4" 23 self.__private = u"private" 24 return self 25 26 def addMultiple(self): 27 self.multiple = KeyValueClass1.alloc().init() 28 self.multiple.level2 = KeyValueClass1.alloc().init() 29 self.multiple.level2.level3 = KeyValueClass1.alloc().init() 30 self.multiple.level2.level3.keyA = u"hello" 31 self.multiple.level2.level3.keyB = u"world" 32 33 def getKey1(self): 34 return 1 35 36 def key2(self): 37 return 2 38 39 def setKey4_(self, value): 40 self._key4 = value * 4 41 42 def setKey5_(self, value): 43 self.key5 = value * 5 44 45 def keyRaisingValueError(self): 46 raise ValueError, "42" 47 48 def keyRaisingNSUnknownKeyException(self): 49 return self.valueForKey_("thisKeyDoesNotExist") 50 51 def keyReturningSameSlector(self): 52 return self.keyReturningSameSelector 53 54 def keyReturningOtherSelector(self): 55 return self.getKey1 56 57class KeyValueClass1Explicit (NSObject): 58 def init(self): 59 self = super(KeyValueClass1Explicit, self).init() 60 self._values = {} 61 self._values[u'key3'] = 3 62 self._values[u'key4'] = u"4" 63 self._values['_private'] = u"private" 64 return self 65 66 def addMultiple(self): 67 self._values["multiple"] = KeyValueClass1Explicit.alloc().init() 68 self._values["multiple"]._values["level2"] = KeyValueClass1Explicit.alloc().init() 69 self._values["multiple"]._values["level2"]._values["level3"] = KeyValueClass1Explicit.alloc().init() 70 self._values["multiple"]._values["level2"]._values["level3"]._values["keyA"] = u"hello" 71 self._values["multiple"]._values["level2"]._values["level3"]._values["keyB"] = u"world" 72 73 def valueForKey_(self, key): 74 if key == "key1": 75 return 1 76 77 elif key == "key2": 78 return 2 79 80 return self._values[key] 81 82 def storedValueForKey_(self, key): 83 return self.valueForKey_(key) 84 85 def setValue_forKey_(self, value, key): 86 if key == "key4": 87 value = value * 4 88 elif key == "key5": 89 value = value * 5 90 91 self._values[key] = value 92 93 def takeStoredValue_forKey_(self, value, key): 94 self.setValue_forKey_(value, key) 95 96 def takeValue_forKey_(self, value, key): 97 self.setValue_forKey_(value, key) 98 99class KeyValueClass4 (NSObject): 100 __slots__ = ('foo', ) 101 102 def init(self): 103 self = super(KeyValueClass4, self).init() 104 self.foo = u"foobar" 105 return self 106 107 # Definition for property 'bar'. Use odd names for the methods 108 # because the KeyValue support recognizes the usual names. 109 def read_bar(self): 110 return self.foo + self.foo 111 112 def write_bar (self, value): 113 self.foo = value + value 114 115 bar = property(read_bar, write_bar) 116 117 roprop = property(lambda self: u"read-only") 118 119class KVOClass(NSObject): 120 def automaticallyNotifiesObserversForKey_(self, aKey): 121 return objc.NO 122 123 def test(self): return u"test" 124 125 126class KeyValueObserver (NSObject): 127 def init(self): 128 self.observed = [] 129 return self 130 131 def observeValueForKeyPath_ofObject_change_context_( 132 self, keyPath, object, change, context): 133 self.observed.append( (keyPath, object, change) ) 134 135 136class PyKeyValueCoding (TestCase): 137 def testNoPrivateVars(self): 138 # Private instance variables ('anObject.__value') are not accessible using 139 # key-value coding. 140 o = KeyValueClass1.alloc().init() 141 self.assertRaises(KeyError, STUB.keyValue_forObject_key_, 0, o, u"private") 142 143 def testValueForKey(self): 144 o = KeyValueClass1.alloc().init() 145 o.addMultiple() 146 147 self.assertEquals(STUB.keyValue_forObject_key_(0, o, u"key1"), 1) 148 149 self.assertEquals(STUB.keyValue_forObject_key_(0, o, u"key2"), 2) 150 self.assertEquals(STUB.keyValue_forObject_key_(0, o, u"key3"), 3) 151 self.assertEquals(STUB.keyValue_forObject_key_(0, o, u"key4"), "4") 152 self.assertEquals(STUB.keyValue_forObject_key_(0, o, u"multiple"), o.multiple) 153 154 self.assertRaises(KeyError, STUB.keyValue_forObject_key_, 0, o, u"nokey") 155 156 self.assertRaises(ValueError, STUB.keyValue_forObject_key_, 0, o, 157 u"keyRaisingValueError") 158 self.assertRaises(KeyError, STUB.keyValue_forObject_key_, 0, o, 159 u"keyRaisingNSUnknownKeyException") 160 self.assertRaises(KeyError, STUB.keyValue_forObject_key_, 0, o, 161 u"keyReturningSameSelector") 162 163 obj = STUB.keyValue_forObject_key_( 0, o, u"keyReturningOtherSelector") 164 self.failUnless( isinstance(obj, objc.selector) ) 165 self.assertEquals(obj.selector, "getKey1") 166 self.failUnless( obj.self is o ) 167 168 169 def testValueForKey2(self): 170 o = KeyValueClass4.alloc().init() 171 172 self.assertEquals(STUB.keyValue_forObject_key_(0, o, u"foo"), u"foobar") 173 self.assertEquals(STUB.keyValue_forObject_key_(0, o, u"bar"), u"foobarfoobar") 174 self.assertEquals(STUB.keyValue_forObject_key_(0, o, u"roprop"), u"read-only") 175 176 177 def testStoredValueForKey(self): 178 o = KeyValueClass1.alloc().init() 179 o.addMultiple() 180 181 self.assertEquals(STUB.keyValue_forObject_key_(2, o, u"key1"), 1) 182 self.assertEquals(STUB.keyValue_forObject_key_(2, o, u"key2"), 2) 183 self.assertEquals(STUB.keyValue_forObject_key_(2, o, u"key3"), 3) 184 self.assertEquals(STUB.keyValue_forObject_key_(2, o, u"key4"), "4") 185 self.assertEquals(STUB.keyValue_forObject_key_(2, o, u"multiple"), o.multiple) 186 187 self.assertRaises(KeyError, STUB.keyValue_forObject_key_, 2, o, u"nokey") 188 189 def testStoredValueForKey2(self): 190 o = KeyValueClass4.alloc().init() 191 192 self.assertEquals(STUB.keyValue_forObject_key_(2, o, u"foo"), u"foobar") 193 self.assertEquals(STUB.keyValue_forObject_key_(2, o, u"bar"), u"foobarfoobar") 194 self.assertEquals(STUB.keyValue_forObject_key_(2, o, u"roprop"), u"read-only") 195 196 def testValueForKeyPath(self): 197 o = KeyValueClass1.alloc().init() 198 o.addMultiple() 199 200 self.assertEquals(STUB.keyValue_forObject_key_(1, o, u"multiple"), o.multiple) 201 self.assertEquals(STUB.keyValue_forObject_key_(1, o, u"multiple.level2"), o.multiple.level2) 202 self.assertEquals(STUB.keyValue_forObject_key_(1, o, u"multiple.level2.level3.keyA"), 203 o.multiple.level2.level3.keyA) 204 self.assertEquals(STUB.keyValue_forObject_key_(1, o, u"multiple.level2.level3.keyB"), 205 o.multiple.level2.level3.keyB) 206 207 self.assertRaises(KeyError, STUB.keyValue_forObject_key_, 1, o, u"multiple.level2.nokey") 208 209 def testValuesForKeys(self): 210 o = KeyValueClass1.alloc().init() 211 212 self.assertEquals(STUB.keyValue_forObject_key_(3, o, [u"key1", u"key2", u"key3", u"key4"]), { u"key1":1, u"key2":2, u"key3": 3, u"key4": u"4"} ) 213 214 self.assertRaises(KeyError, STUB.keyValue_forObject_key_, 3, o, [u"key1", u"key3", u"nosuchkey"]) 215 216 def testTakeValueForKey(self): 217 o = KeyValueClass1.alloc().init() 218 219 self.assertEquals(o.key3, 3) 220 STUB.setKeyValue_forObject_key_value_(0, o, u'key3', u'drie') 221 self.assertEquals(o.key3, u"drie") 222 223 self.assertEquals(o._key4, u"4") 224 STUB.setKeyValue_forObject_key_value_(0, o, u'key4', u'vier') 225 self.assert_(not hasattr(o, u"key4")) 226 self.assertEquals(o._key4, u"viervierviervier") 227 228 o.key5 = 1 229 STUB.setKeyValue_forObject_key_value_(0, o, u'key5', u'V') 230 self.assertEquals(o.key5, u"VVVVV") 231 232 self.assert_(not hasattr(o, u'key9')) 233 STUB.setKeyValue_forObject_key_value_(0, o, u'key9', u'IX') 234 self.assert_(hasattr(o, u'key9')) 235 self.assertEquals(o.key9, u'IX') 236 237 def testTakeValueForKey2(self): 238 o = KeyValueClass4.alloc().init() 239 240 self.assertEquals(o.foo, u"foobar") 241 STUB.setKeyValue_forObject_key_value_(0, o, u'foo', u'FOO') 242 self.assertEquals(o.foo, u"FOO") 243 244 self.assertRaises(KeyError, STUB.setKeyValue_forObject_key_value_, 0, o, u'key9', u'IX') 245 246 247 def testTakeStoredValueForKey(self): 248 o = KeyValueClass1.alloc().init() 249 250 self.assertEquals(o.key3, 3) 251 STUB.setKeyValue_forObject_key_value_(2, o, u'key3', u'drie') 252 self.assertEquals(o.key3, u"drie") 253 254 self.assertEquals(o._key4, u"4") 255 STUB.setKeyValue_forObject_key_value_(2, o, u'key4', u'vier') 256 self.assertEquals(o._key4, u"viervierviervier") 257 258 o.key5 = 1 259 STUB.setKeyValue_forObject_key_value_(2, o, u'key5', u'V') 260 self.assertEquals(o.key5, u"VVVVV") 261 262 self.assert_(not hasattr(o, u'key9')) 263 STUB.setKeyValue_forObject_key_value_(2, o, u'key9', u'IX') 264 self.assert_(hasattr(o, u'key9')) 265 self.assertEquals(o.key9, u'IX') 266 267 def testStoredTakeValueForKey2(self): 268 o = KeyValueClass4.alloc().init() 269 270 self.assertEquals(o.foo, u"foobar") 271 STUB.setKeyValue_forObject_key_value_(2, o, u'foo', u'FOO') 272 self.assertEquals(o.foo, u"FOO") 273 274 self.assertRaises(KeyError, STUB.setKeyValue_forObject_key_value_, 2, o, u'key9', u'IX') 275 self.assertRaises(KeyError, STUB.setKeyValue_forObject_key_value_, 2, o, u'roprop', u'IX') 276 277 def testTakeValuesFromDictionary(self): 278 o = KeyValueClass1.alloc().init() 279 280 self.assertEquals(o.key3, 3) 281 self.assertEquals(o._key4, u"4") 282 o.key5 = 1 283 self.assert_(not hasattr(o, u'key9')) 284 285 STUB.setKeyValue_forObject_key_value_(3, o, None, 286 { 287 u'key3': u'drie', 288 u'key4': u'vier', 289 u'key5': u'V', 290 u'key9': u'IX', 291 }) 292 293 self.assertEquals(o.key3, u"drie") 294 self.assertEquals(o._key4, u"viervierviervier") 295 self.assertEquals(o.key5, u"VVVVV") 296 self.assert_(hasattr(o, u'key9')) 297 self.assertEquals(o.key9, u'IX') 298 299 def testTakeValuesFromDictionary2(self): 300 o = KeyValueClass4.alloc().init() 301 302 self.assertEquals(o.foo, u"foobar") 303 STUB.setKeyValue_forObject_key_value_(3, o, None, { u'foo': u'FOO' }) 304 self.assertEquals(o.foo, u"FOO") 305 306 self.assertRaises(KeyError, STUB.setKeyValue_forObject_key_value_, 3, o, None, { u'key9': u'IX' }) 307 self.assertRaises(KeyError, STUB.setKeyValue_forObject_key_value_, 3, o, None, { u'roprop': u'IX' }) 308 309 def testTakeValueForKeyPath(self): 310 o = KeyValueClass1.alloc().init() 311 o.addMultiple() 312 313 self.assertEquals(o.multiple.level2.level3.keyA, u"hello") 314 self.assertEquals(o.multiple.level2.level3.keyB, u"world") 315 316 STUB.setKeyValue_forObject_key_value_(1, o, u"multiple.level2.level3.keyA", u"KeyAValue") 317 self.assertEquals(o.multiple.level2.level3.keyA, u"KeyAValue") 318 319 STUB.setKeyValue_forObject_key_value_(1, o, u"multiple.level2.level3.keyB", 9.999) 320 self.assertEquals(o.multiple.level2.level3.keyB, 9.999) 321 322 if hasattr(NSObject, u"willChangeValueForKey_"): 323 # NSKeyValueObserving is only available on Panther and beyond 324 def testKVO1(self): 325 o = KVOClass.alloc().init() 326 o.addObserver_forKeyPath_options_context_(self, u"test", 0, None) 327 o.removeObserver_forKeyPath_(self, u"test") 328 329 def testKVO2(self): 330 """ 331 Check if observations work for python-based keys on ObjC classes 332 """ 333 observer = KeyValueObserver.alloc().init() 334 self.assertEquals(observer.observed, []) 335 336 o = KeyValueClass1.alloc().init() 337 338 o.addObserver_forKeyPath_options_context_(observer, u"key3", 0, 0) 339 try: 340 STUB.setKeyValue_forObject_key_value_(2, o, u'key3', u'drie') 341 self.assertEquals(o.key3, u"drie") 342 343 self.assertEquals(len(observer.observed), 1) 344 345 keyPath, object, change = observer.observed[0] 346 self.assertEquals(keyPath, u"key3") 347 self.assert_(object is o) 348 self.assertEquals(change, {NSKeyValueChangeKindKey: 1 }) 349 350 finally: 351 o.removeObserver_forKeyPath_(observer, u'key3') 352 353 def testKVO3(self): 354 """ 355 Check if observations work for python-based keys on ObjC classes 356 """ 357 observer = KeyValueObserver.alloc().init() 358 self.assertEquals(observer.observed, []) 359 360 o = KeyValueClass1.alloc().init() 361 STUB.setKeyValue_forObject_key_value_(2, o, u'key3', u'three') 362 363 o.addObserver_forKeyPath_options_context_(observer, u"key3", 364 NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld, 365 0) 366 try: 367 STUB.setKeyValue_forObject_key_value_(2, o, u'key3', u'drie') 368 self.assertEquals(o.key3, u"drie") 369 370 self.assertEquals(len(observer.observed), 1) 371 372 keyPath, object, change = observer.observed[0] 373 self.assertEquals(keyPath, u"key3") 374 self.assert_(object is o) 375 self.assertEquals(change, 376 { 377 NSKeyValueChangeKindKey:1, 378 NSKeyValueChangeNewKey:u'drie', 379 NSKeyValueChangeOldKey:u'three' 380 }) 381 382 finally: 383 o.removeObserver_forKeyPath_(observer, u'key3') 384 385class PyKeyValueCodingExplicit (TestCase): 386 387 def testValueForKey(self): 388 o = KeyValueClass1Explicit.alloc().init() 389 o.addMultiple() 390 391 self.assertEquals(STUB.keyValue_forObject_key_(0, o, u"key1"), 1) 392 393 self.assertEquals(STUB.keyValue_forObject_key_(0, o, u"key2"), 2) 394 self.assertEquals(STUB.keyValue_forObject_key_(0, o, u"key3"), 3) 395 self.assertEquals(STUB.keyValue_forObject_key_(0, o, u"key4"), "4") 396 self.assertEquals(STUB.keyValue_forObject_key_(0, o, u"multiple"), o._values['multiple']) 397 398 self.assertRaises(KeyError, STUB.keyValue_forObject_key_, 0, o, u"nokey") 399 400 def testStoredValueForKey(self): 401 o = KeyValueClass1Explicit.alloc().init() 402 o.addMultiple() 403 404 self.assertEquals(STUB.keyValue_forObject_key_(2, o, u"key1"), 1) 405 self.assertEquals(STUB.keyValue_forObject_key_(2, o, u"key2"), 2) 406 self.assertEquals(STUB.keyValue_forObject_key_(2, o, u"key3"), 3) 407 self.assertEquals(STUB.keyValue_forObject_key_(2, o, u"key4"), "4") 408 self.assertEquals(STUB.keyValue_forObject_key_(2, o, u"multiple"), o._values['multiple']) 409 410 self.assertRaises(KeyError, STUB.keyValue_forObject_key_, 2, o, u"nokey") 411 412 def testValueForKeyPath(self): 413 o = KeyValueClass1Explicit.alloc().init() 414 o.addMultiple() 415 416 self.assertEquals(STUB.keyValue_forObject_key_(1, o, u"multiple"), o._values['multiple']) 417 self.assertEquals(STUB.keyValue_forObject_key_(1, o, u"multiple.level2"), o._values['multiple']._values['level2']) 418 self.assertEquals(STUB.keyValue_forObject_key_(1, o, u"multiple.level2.level3.keyA"), 419 o._values['multiple']._values['level2']._values['level3']._values['keyA']) 420 self.assertEquals(STUB.keyValue_forObject_key_(1, o, u"multiple.level2.level3.keyB"), 421 o._values['multiple']._values['level2']._values['level3']._values['keyB']) 422 423 self.assertRaises(KeyError, STUB.keyValue_forObject_key_, 1, o, u"multiple.level2.nokey") 424 425 def testValuesForKeys(self): 426 o = KeyValueClass1Explicit.alloc().init() 427 428 self.assertEquals(STUB.keyValue_forObject_key_(3, o, [u"key1", u"key2", u"key3", u"key4"]), { u"key1":1, u"key2":2, u"key3": 3, u"key4": u"4"} ) 429 430 self.assertRaises(KeyError, STUB.keyValue_forObject_key_, 3, o, [u"key1", u"key3", u"nosuchkey"]) 431 432 def testTakeValueForKey(self): 433 o = KeyValueClass1Explicit.alloc().init() 434 435 self.assertEquals(o._values['key3'], 3) 436 STUB.setKeyValue_forObject_key_value_(0, o, u'key3', u'drie') 437 self.assertEquals(o._values['key3'], u"drie") 438 439 self.assertEquals(o._values['key4'], u"4") 440 STUB.setKeyValue_forObject_key_value_(0, o, u'key4', u'vier') 441 self.assert_(not hasattr(o, u"key4")) 442 self.assertEquals(o._values['key4'], u"viervierviervier") 443 444 o._values['key5'] = 1 445 STUB.setKeyValue_forObject_key_value_(0, o, u'key5', u'V') 446 self.assertEquals(o._values['key5'], u"VVVVV") 447 448 self.assert_(not hasattr(o, u'key9')) 449 self.assert_('key9' not in o._values) 450 STUB.setKeyValue_forObject_key_value_(0, o, u'key9', u'IX') 451 self.assert_(not hasattr(o, u'key9')) 452 self.assert_('key9' in o._values) 453 self.assertEquals(o._values['key9'], u'IX') 454 455 def testTakeStoredValueForKey(self): 456 o = KeyValueClass1Explicit.alloc().init() 457 458 self.assertEquals(o._values['key3'], 3) 459 STUB.setKeyValue_forObject_key_value_(2, o, u'key3', u'drie') 460 self.assertEquals(o._values['key3'], u"drie") 461 462 self.assertEquals(o._values['key4'], u"4") 463 STUB.setKeyValue_forObject_key_value_(2, o, u'key4', u'vier') 464 self.assertEquals(o._values['key4'], u"viervierviervier") 465 466 o.key5 = 1 467 STUB.setKeyValue_forObject_key_value_(2, o, u'key5', u'V') 468 self.assertEquals(o._values['key5'], u"VVVVV") 469 470 self.assert_('key9' not in o._values) 471 STUB.setKeyValue_forObject_key_value_(2, o, u'key9', u'IX') 472 self.assert_('key9' in o._values) 473 self.assertEquals(o._values['key9'], u'IX') 474 475 def testTakeValuesFromDictionary(self): 476 o = KeyValueClass1Explicit.alloc().init() 477 478 self.assertEquals(o._values['key3'], 3) 479 self.assertEquals(o._values['key4'], u"4") 480 o._values['key5'] = 1 481 self.assert_('key9' not in o._values) 482 483 STUB.setKeyValue_forObject_key_value_(3, o, None, 484 { 485 u'key3': u'drie', 486 u'key4': u'vier', 487 u'key5': u'V', 488 u'key9': u'IX', 489 }) 490 491 self.assertEquals(o._values['key3'], u"drie") 492 self.assertEquals(o._values['key4'], u"viervierviervier") 493 self.assertEquals(o._values['key5'], u"VVVVV") 494 self.assertEquals(o._values['key9'], u'IX') 495 496 def testTakeValueForKeyPath(self): 497 o = KeyValueClass1Explicit.alloc().init() 498 o.addMultiple() 499 500 self.assertEquals(o._values['multiple']._values['level2']._values['level3']._values['keyA'], u"hello") 501 self.assertEquals(o._values['multiple']._values['level2']._values['level3']._values['keyB'], u"world") 502 503 STUB.setKeyValue_forObject_key_value_(1, o, u"multiple.level2.level3.keyA", u"KeyAValue") 504 self.assertEquals(o._values['multiple']._values['level2']._values['level3']._values['keyA'], u"KeyAValue") 505 506 STUB.setKeyValue_forObject_key_value_(1, o, u"multiple.level2.level3.keyB", 9.999) 507 self.assertEquals(o._values['multiple']._values['level2']._values['level3']._values['keyB'], 9.999) 508 509 510class TestBaseExceptions (TestCase): 511 """ 512 Check that NSObject implementation of Key-Value coding raises the 513 exception that we expect it to raise. 514 """ 515 def testValueForKey(self): 516 o = NSObject.alloc().init() 517 518 self.assertRaises(KeyError, o.valueForKey_, u"unknownKey") 519 520 def testStoredValueForKey(self): 521 o = NSObject.alloc().init() 522 523 self.assertRaises(KeyError, o.storedValueForKey_, u"unknownKey") 524 525 def testTakeStoredValue(self): 526 o = NSObject.alloc().init() 527 528 self.assertRaises(KeyError, 529 o.takeStoredValue_forKey_, u"value", u"unknownKey") 530 531 532 533if __name__ == "__main__": 534 main() 535