1# FIXME: This test suite seems to polute it's environment, other tests fail 2# when this test suite is active! 3from __future__ import unicode_literals 4from PyObjCTools.TestSupport import * 5import sys 6 7from PyObjCTools.TestSupport import onlyPython2 8 9import objc 10 11NSObject = objc.lookUpClass('NSObject') 12 13class MEClass(NSObject): 14 pass 15 16preEverythingInstance = MEClass.new() 17 18class Methods(NSObject): 19 def description(self): 20 return "<methods>" 21 22 def newMethod(self): 23 return "<new-method>" 24 25class MethodsSub(NSObject): 26 def description(self): 27 return "<sub-methods>" 28 29 def newMethod(self): 30 return "<sub-new-method>" 31 32 def newSubMethod(self): 33 return "<new-method-sub>" 34 35class PurePython: 36 def description(self): 37 return "<pure>" 38 39 def newMethod(self): 40 return "<pure-new>" 41 42 def purePythonMethod(self): 43 return "<pure-py>" 44 45class TestFromObjCSuperToObjCClass(TestCase): 46 def testClassAddMethod(self): 47 import objc._category as mod 48 49 orig_classAddMethods = mod.classAddMethods 50 try: 51 l = [] 52 def classAddMethods(cls, values): 53 self.assertIsInstance(cls, objc.objc_class) 54 for item in values: 55 self.assertIsInstance(item, objc.selector) 56 l.append((cls, values)) 57 58 mod.classAddMethods = classAddMethods 59 60 def my_python_description(self): 61 return "foo the bar" 62 63 objc.classAddMethod(NSObject, b"python_description", my_python_description) 64 self.assertEqual(len(l), 1) 65 self.assertIs(l[0][0], NSObject) 66 self.assertEqual(len(l[0][1]), 1) 67 m = l[0][1][0] 68 self.assertIsInstance(m, objc.selector) 69 self.assertIs(m.callable, my_python_description) 70 self.assertEqual(m.selector, b"python_description") 71 self.assertEqual(m.signature, b"@@:") 72 73 @objc.typedSelector(b"q@:") 74 def myAction(self): 75 return 1 76 77 l[:] = [] 78 objc.classAddMethod(NSObject, b"value", myAction) 79 self.assertIs(l[0][0], NSObject) 80 self.assertEqual(len(l[0][1]), 1) 81 m = l[0][1][0] 82 self.assertIsInstance(m, objc.selector) 83 self.assertIs(m.callable, myAction.callable) 84 self.assertEqual(m.selector, b"value") 85 self.assertEqual(m.signature, b"q@:") 86 87 88 # Cannot add native selectors: 89 self.assertRaises(AttributeError, objc.classAddMethod, NSObject, b"descriptionAlias", NSObject.description) 90 91 finally: 92 mod.classAddMethods = orig_classAddMethods 93 94 95 def testBasicBehavior(self): 96 anInstance = Methods.new() 97 self.assertEqual(anInstance.description(), "<methods>") 98 self.assertEqual(anInstance.newMethod(), "<new-method>") 99 100 def testDescriptionOverride(self): 101 objc.classAddMethods(MEClass, [Methods.pyobjc_instanceMethods.description]) 102 103 self.assertTrue(MEClass.instancesRespondToSelector_("description")) 104 105 newInstance = MEClass.new() 106 107 self.assertEqual(newInstance.description(), "<methods>") 108 self.assertEqual(preEverythingInstance.description(), "<methods>") 109 110 def testNewMethod(self): 111 objc.classAddMethods(MEClass, [Methods.pyobjc_instanceMethods.newMethod]) 112 113 self.assertTrue(MEClass.instancesRespondToSelector_("newMethod")) 114 115 newInstance = MEClass.new() 116 117 self.assertEqual(newInstance.newMethod(), "<new-method>") 118 self.assertEqual(preEverythingInstance.newMethod(), "<new-method>") 119 120 def testSubDescriptionOverride(self): 121 objc.classAddMethods(MEClass, [MethodsSub.pyobjc_instanceMethods.description]) 122 123 self.assertTrue(MEClass.instancesRespondToSelector_("description")) 124 125 newInstance = MEClass.new() 126 127 self.assertEqual(newInstance.description(), "<sub-methods>") 128 self.assertEqual(preEverythingInstance.description(), "<sub-methods>") 129 130 def testSubNewMethod(self): 131 objc.classAddMethods(MEClass, [MethodsSub.newMethod, MethodsSub.newSubMethod]) 132 133 self.assertTrue(MEClass.instancesRespondToSelector_("newMethod")) 134 self.assertTrue(MEClass.instancesRespondToSelector_("newSubMethod")) 135 136 newInstance = MEClass.new() 137 138 self.assertEqual(newInstance.newMethod(), "<sub-new-method>") 139 self.assertEqual(preEverythingInstance.newMethod(), "<sub-new-method>") 140 self.assertEqual(newInstance.newSubMethod(), "<new-method-sub>") 141 self.assertEqual(preEverythingInstance.newSubMethod(), "<new-method-sub>") 142 143 def testNewClassMethod(self): 144 145 def aNewClassMethod(cls): 146 return "Foo cls" 147 aNewClassMethod = classmethod(aNewClassMethod) 148 149 self.assertTrue(not MEClass.pyobjc_classMethods.respondsToSelector_("aNewClassMethod")) 150 objc.classAddMethods(MEClass, [aNewClassMethod]) 151 self.assertTrue(MEClass.pyobjc_classMethods.respondsToSelector_("aNewClassMethod")) 152 153 self.assertTrue(MEClass.aNewClassMethod.isClassMethod) 154 self.assertEqual(MEClass.aNewClassMethod(), 'Foo cls') 155 156 def testAddedMethodType(self): 157 def anotherNewClassMethod(cls): 158 "CLS DOC STRING" 159 return "BAR CLS" 160 anotherNewClassMethod = classmethod(anotherNewClassMethod) 161 162 def anotherNewMethod(self): 163 "INST DOC STRING" 164 return "BAR SELF" 165 166 self.assertTrue(not MEClass.pyobjc_classMethods.respondsToSelector_("anotherNewClassMethod")) 167 self.assertTrue(not MEClass.pyobjc_classMethods.instancesRespondToSelector_("anotherNewMethod")) 168 169 objc.classAddMethods(MEClass, [anotherNewClassMethod, anotherNewMethod]) 170 self.assertTrue(MEClass.pyobjc_classMethods.respondsToSelector_("anotherNewClassMethod")) 171 self.assertTrue(MEClass.pyobjc_classMethods.instancesRespondToSelector_("anotherNewMethod")) 172 173 self.assertEqual(MEClass.anotherNewClassMethod.__doc__, "CLS DOC STRING") 174 self.assertEqual(MEClass.anotherNewMethod.__doc__, "INST DOC STRING") 175 176 177 178 179class TestFromPythonClassToObjCClass(TestCase): 180 181 @onlyPython2 182 def testPythonSourcedMethods(self): 183 # 20031227, Ronald: Assigning the methods works alright, but actually 184 # using them won't because the new methods are actually still methods 185 # of a different class and will therefore complain about the type 186 # of 'self'. 187 objc.classAddMethods(MEClass, [PurePython.description, 188 PurePython.newMethod, 189 PurePython.purePythonMethod]) 190 191 192 self.assertTrue(MEClass.instancesRespondToSelector_("description")) 193 self.assertTrue(MEClass.instancesRespondToSelector_("newMethod")) 194 self.assertTrue(MEClass.instancesRespondToSelector_("purePythonMethod")) 195 196 newInstance = MEClass.new() 197 198 # This is bogus, see above: 199 #self.assertEqual(newInstance.description(), "<pure>") 200 #self.assertEqual(newInstance.newMethod(), "<pure-new>") 201 #self.assertEqual(newInstance.purePythonMethod(), "<pure-py>") 202 203 #self.assertEqual(preEverythingInstance.description(), "<pure>") 204 #self.assertEqual(preEverythingInstance.newMethod(), "<pure-new>") 205 #self.assertEqual(preEverythingInstance.purePythonMethod(), "<pure-py>") 206 207 self.assertRaises(TypeError, newInstance.description) 208 self.assertRaises(TypeError, newInstance.newMethod) 209 self.assertRaises(TypeError, newInstance.purePythonMethod) 210 self.assertRaises(TypeError, preEverythingInstance.description) 211 self.assertRaises(TypeError, preEverythingInstance.newMethod) 212 self.assertRaises(TypeError, preEverythingInstance.purePythonMethod) 213 214 def testPythonSourcedFunctions(self): 215 # Same as testPythonSourcedMethods, but using function objects instead 216 # of method objects. 217 218 219 if sys.version_info[0] == 2: 220 objc.classAddMethods(MEClass, [ 221 PurePython.description.im_func, 222 PurePython.newMethod.im_func, 223 PurePython.purePythonMethod.im_func, 224 ]) 225 else: 226 objc.classAddMethods(MEClass, [ 227 PurePython.description, 228 PurePython.newMethod, 229 PurePython.purePythonMethod, 230 ]) 231 232 self.assertTrue(MEClass.instancesRespondToSelector_("description")) 233 self.assertTrue(MEClass.instancesRespondToSelector_("newMethod")) 234 self.assertTrue(MEClass.instancesRespondToSelector_("purePythonMethod")) 235 236 newInstance = MEClass.new() 237 238 self.assertEqual(newInstance.description(), "<pure>") 239 self.assertEqual(newInstance.newMethod(), "<pure-new>") 240 self.assertEqual(newInstance.purePythonMethod(), "<pure-py>") 241 242 self.assertEqual(preEverythingInstance.description(), "<pure>") 243 self.assertEqual(preEverythingInstance.newMethod(), "<pure-new>") 244 self.assertEqual(preEverythingInstance.purePythonMethod(), "<pure-py>") 245 246 247 248class TestClassAsignments (TestCase): 249 def testAssignAMethod(self): 250 MEClass.doSomethingElse = lambda self: 2*2 251 MEClass.doDuplicate_ = lambda self, x: 2*x 252 253 self.assertTrue(MEClass.instancesRespondToSelector_("doSomethingElse")) 254 self.assertTrue(MEClass.instancesRespondToSelector_("doDuplicate:")) 255 256 o = MEClass.alloc().init() 257 258 self.assertEqual(4, o.doSomethingElse()) 259 self.assertEqual(8, o.doDuplicate_(4)) 260 261 def testAssignAClassMethod(self): 262 MEClass.classSomethingElse = classmethod(lambda self: 2*2) 263 MEClass.classDuplicate_ = classmethod(lambda self, x: 2*x) 264 265 self.assertTrue(MEClass.pyobjc_classMethods.respondsToSelector_(b"classSomethingElse")) 266 self.assertTrue(MEClass.pyobjc_classMethods.respondsToSelector_(b"classDuplicate:")) 267 268 self.assertEqual(4, MEClass.classSomethingElse()) 269 self.assertEqual(8, MEClass.classDuplicate_(4)) 270 271 def testAssignFuzzyMethod(self): 272 self.assertRaises((ValueError, TypeError), setattr, MEClass, 'fuzzyMethod', objc.selector(None, selector=b'fuzzy', signature=b'@@:')) 273 274 def testRemovingMethods(self): 275 theClass = NSObject 276 277 self.assertRaises(AttributeError, delattr, theClass, 'alloc') 278 self.assertRaises(AttributeError, delattr, theClass, 'init') 279 280class TestCategory (TestCase): 281 # Tests of objc.Category 282 283 def testPyClassCategory(self): 284 global Methods 285 286 o = Methods.alloc().init() 287 self.assertRaises(AttributeError, getattr, o, 'categoryMethod') 288 289 class Methods (objc.Category(Methods)): 290 def categoryMethod(self): 291 return True 292 293 def categoryMethod2(self): 294 return False 295 296 def anotherClassMethod(self): 297 return "hello" 298 anotherClassMethod = classmethod(anotherClassMethod) 299 300 self.assertTrue(o.categoryMethod()) 301 self.assertTrue(not o.categoryMethod2()) 302 self.assertEqual(Methods.anotherClassMethod(), "hello") 303 304 def testNoInstanceVariables(self): 305 global Methods 306 307 try: 308 class Methods(objc.Category(Methods)): 309 outlet = objc.IBOutlet() 310 311 except TypeError: 312 pass 313 314 else: 315 self.fail("Can add instance variable in a category") 316 317 def testObjCClassCategory(self): 318 NSObject = objc.lookUpClass('NSObject') 319 320 o = NSObject.alloc().init() 321 self.assertRaises(AttributeError, getattr, o, 'myCategoryMethod') 322 323 class NSObject (objc.Category(NSObject)): 324 def myCategoryMethod(self): 325 return True 326 327 def myCategoryMethod2(self): 328 return False 329 330 self.assertTrue(o.myCategoryMethod()) 331 self.assertTrue(not o.myCategoryMethod2()) 332 333 def testCategoryMultipleInheritance(self): 334 335 NSObject = objc.lookUpClass('NSObject') 336 337 338 try: 339 340 class NSObject ( objc.Category(NSObject), object ): 341 pass 342 343 self.fail("Can use objc.Category with MI") 344 except TypeError: 345 pass 346 347 def testCategoryName(self): 348 try: 349 class NSFoo (objc.Category(NSObject)): 350 pass 351 352 self.fail("Category name != class name") 353 354 except TypeError: 355 pass 356 357 def testCategoryOnPurePython(self): 358 try: 359 global list 360 361 class list (objc.Category(list)): 362 pass 363 364 self.fail("Category on list???") 365 366 except TypeError: 367 pass 368 369 def testCategoryRedefiningPythonMethod(self): 370 class BaseClassRedef(NSObject): 371 def foo(self): 372 return 1 373 374 class BaseClassRedef(objc.Category(BaseClassRedef)): 375 def foo(self): 376 return 2 377 378 obj = BaseClassRedef.alloc().init() 379 380 self.assertEqual(obj.foo(), 2) 381 382 def foo(self): 383 return 3 384 BaseClassRedef.foo = foo 385 386 self.assertEqual(obj.foo(), 3) 387 388 def testCategeryWithDocString (self): 389 class NSObjectCat (NSObject): 390 pass 391 392 class NSObjectCat (objc.Category(NSObjectCat)): 393 """ 394 This is a docstring 395 """ 396 397 def withDocStringMethod(self): 398 return 42 399 400 o = NSObjectCat.alloc().init() 401 self.assertEqual(o.withDocStringMethod(), 42) 402 403 def testCategoryWithClassMethod(self): 404 class NSObjectCat2 (NSObject): 405 pass 406 407 class NSObjectCat2 (objc.Category(NSObjectCat2)): 408 @classmethod 409 def aClassMethod(cls): 410 return 1 411 412 self.assertEqual(NSObjectCat2.aClassMethod(), 1) 413 414 def testCategoryWithVariables(self): 415 class NSObjectCat3 (NSObject): 416 pass 417 418 class NSObjectCat3 (objc.Category(NSObjectCat3)): 419 classValue = "aap" 420 421 def getClassValue(self): 422 return self.classValue 423 424 425 self.assertHasAttr(NSObjectCat3, "classValue") 426 o = NSObjectCat3.alloc().init() 427 self.assertEqual(o.getClassValue(), "aap") 428 429 430 431 432if __name__ == '__main__': 433 main() 434