1from PyObjCTools.TestSupport import * 2import objc 3from PyObjCTest.testbndl import PyObjC_TestClass3 4import sys 5import types 6 7# Most useful systems will at least have 'NSObject'. 8NSObject = objc.lookUpClass('NSObject') 9NSArray = objc.lookUpClass('NSArray') 10NSAutoreleasePool = objc.lookUpClass('NSAutoreleasePool') 11 12class TestSubclassing(TestCase): 13 def testMethodRaise(self): 14 # Defining a method whose name is a keyword followed by two underscores 15 # should define the method name without underscores in the runtime, 16 # and this method should be accesible both with and without the 17 # underscores. 18 19 class RaiseClass (NSObject): 20 def raise__(self): 21 pass 22 23 self.assertNotHasAttr(NSObject, 'raise__') 24 self.assertNotHasAttr(NSObject, 'raise') 25 26 self.assertHasAttr(RaiseClass, 'raise__') 27 self.assertHasAttr(RaiseClass, 'raise') 28 self.assertEqual(RaiseClass.raise__.selector, b'raise') 29 self.assertEqual(getattr(RaiseClass, 'raise').selector, b'raise') 30 31 def testMIObjC(self): 32 try: 33 class MIClass1(NSObject, NSArray): 34 pass 35 self.fail("Can multiple inherit from two objc classes") 36 except TypeError: 37 pass 38 39 def testSubclassOfSubclass(self): 40 class Level1Class (NSObject): 41 def hello(self): 42 return "level1" 43 44 class Level2Class (Level1Class): 45 def hello(self): 46 return "level2" 47 48 def superHello(self): 49 return objc.super(Level2Class, self).hello() 50 51 def description(self): 52 return objc.super(Level2Class, self).description() 53 54 obj = Level1Class.alloc().init() 55 v = obj.hello() 56 self.assertEqual(v, "level1") 57 58 obj = Level2Class.alloc().init() 59 v = obj.hello() 60 self.assertEqual(v, "level2") 61 62 v = obj.superHello() 63 self.assertEqual(v, "level1") 64 65 v = obj.description() 66 # this may be a bit hardwired for comfort 67 self.assertEqual(v.find("<Level2Class"), 0) 68 69 def testMethodSignature(self): 70 class Signature (NSObject): 71 def test_x_(self, arg, x): 72 pass 73 test_x_ = objc.selector(test_x_, signature=b'v@:@i') 74 75 v = Signature.new() 76 77 self.assertIsInstance(v, Signature) 78 79 self.assertEqual(v.methodSignatureForSelector_('foo:'), None) 80 81 x = v.methodSignatureForSelector_('test:x:') 82 self.assertIsNotNone(x) 83 84 self.assertEqual(x.methodReturnType(), b'v') 85 self.assertEqual(x.numberOfArguments(), 4) 86 self.assertEqual(x.getArgumentTypeAtIndex_(0), b'@') 87 self.assertEqual(x.getArgumentTypeAtIndex_(1), b':') 88 self.assertEqual(x.getArgumentTypeAtIndex_(2), b'@') 89 self.assertEqual(x.getArgumentTypeAtIndex_(3), b'i') 90 91 92class TestSelectors(TestCase): 93 def testSelectorRepr(self): 94 class SelectorRepr(NSObject): 95 def foo(self): 96 pass 97 98 self.assertTrue(repr(SelectorRepr.foo).startswith('<unbound selector foo of SelectorRepr at')) 99 100 101class TestCopying (TestCase): 102 103 def testCopy(self): 104 class MyCopyClass (NSObject): 105 def copyWithZone_(self, zone): 106 # NSObject doesn't implement the copying protocol 107 #o = super(MyCopyClass, self).copyWithZone_(zone) 108 o = self.__class__.alloc().init() 109 o.foobar = 2 110 return o 111 copyWithZone_ = objc.selector( 112 copyWithZone_, 113 signature=NSObject.copyWithZone_.signature, 114 isClassMethod=0) 115 116 117 # Make sure the runtime correctly marked our copyWithZone_ 118 # implementation. 119 o = MyCopyClass.alloc().init() 120 121 self.assertFalse((o.copyWithZone_.__metadata__()['classmethod'])) 122 self.assertTrue(o.copyWithZone_.__metadata__()['retval']['already_retained']) 123 #self.assertTrue(o.copyWithZone_.callable == MyCopyClass.__dict__['copyWithZone_'].callable) 124 125 o = MyCopyClass.alloc().init() 126 o.foobar = 1 127 128 self.assertEqual(o.foobar, 1) 129 130 # Make a copy from ObjC (see testbundle.m) 131 c = PyObjC_TestClass3.copyValue_(o) 132 133 self.assertIsInstance(c, MyCopyClass) 134 self.assertEqual(c.foobar, 2) 135 136 137 def testMultipleInheritance1(self): 138 # New-style class mixin 139 class MixinClass1 (object): 140 def mixinMethod(self): 141 return "foo" 142 143 class MITestClass1 (NSObject, MixinClass1): 144 def init(self): 145 return NSObject.pyobjc_instanceMethods.init(self) 146 147 self.assertHasAttr(MITestClass1, 'mixinMethod') 148 149 o = MITestClass1.alloc().init() 150 self.assertEqual(o.mixinMethod(), "foo") 151 152 def testMultipleInheritance2(self): 153 # old-style class mixin 154 class MixinClass2: 155 def mixinMethod(self): 156 return "foo" 157 158 class MITestClass2 (NSObject, MixinClass2): 159 def init(self): 160 return NSObject.pyobjc_instanceMethods.init(self) 161 162 self.assertHasAttr(MITestClass2, 'mixinMethod') 163 164 o = MITestClass2.alloc().init() 165 self.assertEqual(o.mixinMethod(), "foo") 166 167class TestClassMethods (TestCase): 168 169 def testClassMethod(self): 170 """ check that classmethod()-s are converted to selectors """ 171 172 class ClassMethodTest (NSObject): 173 def clsMeth(self): 174 return "hello" 175 clsMeth = classmethod(clsMeth) 176 177 self.assertIsInstance(ClassMethodTest.clsMeth, objc.selector) 178 self.assertTrue(ClassMethodTest.clsMeth.isClassMethod) 179 180 def testStaticMethod(self): 181 """ check that staticmethod()-s are not converted to selectors """ 182 183 class StaticMethodTest (NSObject): 184 def stMeth(self): 185 return "hello" 186 stMeth = staticmethod(stMeth) 187 188 def func(): pass 189 190 self.assertIsInstance(StaticMethodTest.stMeth, type(func)) 191 192 193class TestOverridingSpecials(TestCase): 194 def testOverrideSpecialMethods(self): 195 aList = [0] 196 197 class ClassWithAlloc(NSObject): 198 def alloc(cls): 199 aList[0] += 1 200 return objc.super(ClassWithAlloc, cls).alloc() 201 202 203 self.assertEqual(aList[0], 0) 204 o = ClassWithAlloc.alloc().init() 205 self.assertEqual(aList[0], 1) 206 self.assertIsInstance(o, NSObject) 207 del o 208 209 class ClassWithRetaining(NSObject): 210 def retain(self): 211 aList.append('retain') 212 v = objc.super(ClassWithRetaining, self).retain() 213 return v 214 215 def release(self): 216 aList.append('release') 217 return objc.super(ClassWithRetaining, self).release() 218 219 def __del__(self): 220 aList.append('__del__') 221 222 223 del aList[:] 224 o = ClassWithRetaining.alloc().init() 225 v = o.retainCount() 226 o.retain() 227 self.assertEqual(aList, ['retain']) 228 self.assertEqual(o.retainCount(), v+1) 229 o.release() 230 self.assertEqual(aList, ['retain', 'release']) 231 self.assertEqual(o.retainCount(), v) 232 del o 233 234 self.assertEqual(aList, ['retain', 'release', 'release', '__del__']) 235 236 # Test again, now remove all python references and create one 237 # again. 238 del aList[:] 239 pool = NSAutoreleasePool.alloc().init() 240 o = ClassWithRetaining.alloc().init() 241 v = NSArray.arrayWithArray_([o]) 242 del o 243 self.assertEqual(aList, ['retain']) 244 o = v[0] 245 self.assertEqual(aList, ['retain']) 246 del v 247 del o 248 del pool 249 250 self.assertEqual(aList, ['retain', 'release', 'release', '__del__']) 251 252 class ClassWithRetainCount(NSObject): 253 def retainCount(self): 254 aList.append('retainCount') 255 return objc.super(ClassWithRetainCount, self).retainCount() 256 257 del aList[:] 258 o = ClassWithRetainCount.alloc().init() 259 self.assertEqual(aList, []) 260 v = o.retainCount() 261 self.assertIsInstance(v, int) 262 self.assertEqual(aList, ['retainCount']) 263 del o 264 265 def testOverrideDealloc(self): 266 aList = [] 267 268 class Dummy: 269 def __del__(self): 270 aList.append('__del__') 271 272 self.assertEqual(aList, []) 273 Dummy() 274 self.assertEqual(aList, ['__del__']) 275 276 class ClassWithDealloc(NSObject): 277 def init(self): 278 self = objc.super(ClassWithDealloc, self).init() 279 if self is not None: 280 self.obj = Dummy() 281 return self 282 283 def dealloc(self): 284 aList.append('dealloc') 285 return objc.super(ClassWithDealloc, self).dealloc() 286 287 del aList[:] 288 o = ClassWithDealloc.alloc().init() 289 self.assertEqual(aList, []) 290 del o 291 self.assertEqual(len(aList), 2) 292 self.assertIn('dealloc', aList) 293 self.assertIn('__del__', aList) 294 295 class SubClassWithDealloc(ClassWithDealloc): 296 def dealloc(self): 297 aList.append('dealloc.dealloc') 298 return objc.super(SubClassWithDealloc, self).dealloc() 299 300 del aList[:] 301 o = SubClassWithDealloc.alloc().init() 302 self.assertEqual(aList, []) 303 del o 304 self.assertEqual(len(aList), 3) 305 self.assertIn('dealloc.dealloc', aList) 306 self.assertIn('dealloc', aList) 307 self.assertIn('__del__', aList) 308 309 class ClassWithDeallocAndDel(NSObject): 310 def init(self): 311 self = objc.super(ClassWithDeallocAndDel, self).init() 312 if self is not None: 313 self.obj = Dummy() 314 return self 315 316 def dealloc(self): 317 aList.append('dealloc') 318 return objc.super(ClassWithDeallocAndDel, self).dealloc() 319 320 def __del__(self): 321 aList.append('mydel') 322 323 del aList[:] 324 o = ClassWithDeallocAndDel.alloc().init() 325 self.assertEqual(aList, []) 326 del o 327 self.assertEqual(len(aList), 3) 328 self.assertIn('mydel', aList) 329 self.assertIn('dealloc', aList) 330 self.assertIn('__del__', aList) 331 332 def testMethodNames(self): 333 334 class MethodNamesClass (NSObject): 335 def someName_andArg_(self, name, arg): 336 pass 337 338 def _someName_andArg_(self, name, arg): 339 pass 340 341 342 def raise__(self): 343 pass 344 345 def froobnicate__(self, a, b): 346 pass 347 348 # XXX: workaround for a 'feature' in class-builder.m, that code 349 # ignores methods whose name starts with two underscores. That code 350 # is not necessary, or the other ways of adding methods to a class 351 # should be changed. 352 def __foo_bar__(self, a, b, c): 353 pass 354 355 MethodNamesClass.__foo_bar__ = __foo_bar__ 356 357 self.assertEqual(MethodNamesClass.someName_andArg_.selector, 358 b'someName:andArg:') 359 self.assertEqual(MethodNamesClass._someName_andArg_.selector, 360 b'_someName:andArg:') 361 self.assertEqual(MethodNamesClass.__foo_bar__.selector, 362 b'__foo_bar__') 363 self.assertEqual(MethodNamesClass.raise__.selector, 364 b'raise') 365 self.assertEqual(MethodNamesClass.froobnicate__.selector, 366 b'froobnicate::') 367 368 def testOverrideRespondsToSelector(self): 369 class OC_RespondsClass (NSObject): 370 def initWithList_(self, lst): 371 objc.super(OC_RespondsClass, self).init() 372 self.lst = lst 373 return self 374 375 def respondsToSelector_(self, selector): 376 self.lst.append(selector) 377 return objc.super(OC_RespondsClass, self).respondsToSelector_(selector) 378 379 lst = [] 380 o = OC_RespondsClass.alloc().initWithList_(lst) 381 382 self.assertEqual(lst, []) 383 384 b = o.respondsToSelector_('init') 385 self.assertTrue(b) 386 self.assertEqual(lst, ['init']) 387 388 b = o.respondsToSelector_('alloc') 389 self.assertFalse(b) 390 self.assertEqual(lst, ['init', 'alloc']) 391 392 def testOverrideInstancesRespondToSelector(self): 393 lst = [] 394 class OC_InstancesRespondClass (NSObject): 395 396 @classmethod 397 def instancesRespondToSelector_(cls, selector): 398 lst.append(selector) 399 return objc.super(OC_InstancesRespondClass, cls).instancesRespondToSelector_(selector) 400 401 self.assertEqual(lst, []) 402 403 b = OC_InstancesRespondClass.instancesRespondToSelector_('init') 404 self.assertTrue(b) 405 self.assertEqual(lst, ['init']) 406 407 b = OC_InstancesRespondClass.instancesRespondToSelector_('alloc') 408 self.assertFalse(b) 409 self.assertEqual(lst, ['init', 'alloc']) 410 411 def testImplementingSetValueForKey(self): 412 values = {} 413 class CrashTest (NSObject): 414 def setValue_forKey_(self, v, k): 415 values[k] = v 416 417 o = CrashTest.alloc().init() 418 o.setValue_forKey_(42,"key") 419 420 self.assertEqual(values, {"key":42}) 421 422 423if __name__ == '__main__': 424 main() 425