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