1from PyObjCTools.TestSupport import * 2import objc 3import warnings 4import sys 5 6# Most useful systems will at least have 'NSObject'. 7NSObject = objc.lookUpClass('NSObject') 8 9# XXX : This is a really dumb way to detect < 10.3 10if not NSObject.instancesRespondToSelector_('setValue:forKey:'): 11 # Defining protocols in an MH_BUNDLE makes < 10.3 explode 12 OC_TestProtocol = None 13else: 14 from PyObjCTest.protocol import OC_TestProtocol 15 16MyProto = objc.informal_protocol("MyProto", ( 17 objc.selector(None, selector="testMethod", signature="I@:", isRequired=1), 18 objc.selector(None, selector="testMethod2:", signature="v@:i", isRequired=0) 19)) 20 21class TestInformalProtocols(TestCase): 22 23 24 def testMissingProto(self): 25 class ProtoClass1 (NSObject): 26 def testMethod(self): 27 pass 28 self.assertEquals(ProtoClass1.testMethod.signature, "I@:") 29 30 31 def doIncompleteClass(self): 32 class ProtoClass2 (NSObject, MyProto): 33 def testMethod2_(self, x): 34 pass 35 36 def testIncompleteClass(self): 37 self.assertRaises(TypeError, self.doIncompleteClass) 38 39 40 def testOptional(self): 41 class ProtoClass3 (NSObject, MyProto): 42 def testMethod(self): 43 pass 44 45 46 47if sys.maxint < 2 ** 32: 48 EmptyProtocol = objc.formal_protocol("EmptyProtocol", None, ()) 49 50 MyProtocol = objc.formal_protocol("MyProtocol", None, ( 51 objc.selector(None, selector="protoMethod", signature="I@:"), 52 objc.selector(None, selector="anotherProto:with:", signature="v@:ii"), 53 )) 54 55 MyOtherProtocol = objc.formal_protocol("MyOtherProtocol", 56 (MyProtocol,), [ 57 objc.selector(None, selector="yetAnother:", signature="i@:I") 58 ]) 59 60 MyClassProtocol = objc.formal_protocol("MyClassProtocol", None, [ 61 objc.selector(None, selector="anAnotherOne:", signature="i@:i"), 62 objc.selector(None, selector="aClassOne:", signature="@@:i", isClassMethod=1), 63 ]) 64 65 if OC_TestProtocol is not None: 66 67 class TestFormalOCProtocols(TestCase): 68 69 def testImplementFormalProtocol(self): 70 71 class MyClassNotImplementingProtocol(NSObject): 72 pass 73 74 self.assert_(not MyClassNotImplementingProtocol.pyobjc_classMethods.conformsToProtocol_(OC_TestProtocol)) 75 76 try: 77 class MyClassNotAlsoImplementingProtocol(NSObject, OC_TestProtocol): 78 def method1(self): pass 79 80 self.fail("class not implementing protocol, yet created") 81 except TypeError: 82 pass 83 84 class MyClassImplementingProtocol(NSObject, OC_TestProtocol): 85 def method1(self): pass 86 def method2_(self, a): pass 87 88 self.assert_(MyClassImplementingProtocol.pyobjc_classMethods.conformsToProtocol_(OC_TestProtocol)) 89 90 91 92 # The PyObjC implementation of formal protocols is slightly looser 93 # than Objective-C itself: you can inherit part of the protocol 94 # from the superclass. 95 # XXX: not really: you won't inherit the right signatures by default 96 97 class MyClassImplementingHalfOfProtocol(NSObject): 98 def method1(self): pass 99 method1 = objc.selector(method1, signature='i@:') 100 101 self.assert_(not MyClassImplementingHalfOfProtocol.pyobjc_classMethods.conformsToProtocol_(OC_TestProtocol)) 102 103 class MyClassImplementingAllOfProtocol(MyClassImplementingHalfOfProtocol, OC_TestProtocol): 104 def method2_(self, v): pass 105 106 self.assert_(MyClassImplementingAllOfProtocol.pyobjc_classMethods.conformsToProtocol_(OC_TestProtocol)) 107 108 109 110 111 class TestFormalProtocols (TestCase): 112 # Implement unittests for formal protocols here. 113 # 114 115 def testImplementAnotherObject(self): 116 anObject = NSObject.alloc().init() 117 118 try: 119 class MyClassImplementingAnotherObject(NSObject, anObject): 120 pass 121 self.fail() 122 except TypeError: 123 pass 124 125 try: 126 class MyClassImplementingAnotherObject(NSObject, 10): 127 pass 128 self.fail() 129 except TypeError: 130 pass 131 132 try: 133 class MyClassImplementingAnotherObject(NSObject, int): 134 pass 135 self.fail() 136 except TypeError: 137 pass 138 139 def dont_testDefiningingProtocols(self): 140 141 # Pretty useless, but should work 142 143 self.assert_(MyOtherProtocol.conformsTo_(MyProtocol)) 144 145 146 try: 147 class MyClassImplementingMyProtocol(NSObject, MyProtocol): 148 pass 149 150 # Declare to implement a protocol, but don't do it? 151 self.fail() 152 except TypeError: 153 pass 154 155 156 class MyClassImplementingMyProtocol(NSObject, MyProtocol): 157 def protoMethod(self): 158 return 1 159 160 def anotherProto_with_(self, a1, a2): 161 pass 162 163 self.assertEquals(MyClassImplementingMyProtocol.protoMethod.signature, "I@:") 164 self.assertEquals(MyClassImplementingMyProtocol.anotherProto_with_.signature, "v@:ii") 165 self.assert_(MyClassImplementingMyProtocol.pyobjc_classMethods.conformsToProtocol_(MyProtocol)) 166 167 class MyClassImplementingMyOtherProtocol(NSObject, MyOtherProtocol): 168 def protoMethod(self): pass 169 def anotherProto_with_(self, a1, a2): pass 170 def yetAnother_(self, a): pass 171 172 self.assertEquals(MyClassImplementingMyOtherProtocol.protoMethod.signature, "I@:") 173 self.assertEquals(MyClassImplementingMyOtherProtocol.anotherProto_with_.signature, "v@:ii") 174 self.assertEquals(MyClassImplementingMyOtherProtocol.yetAnother_.signature, "i@:I") 175 self.assert_(MyClassImplementingMyOtherProtocol.pyobjc_classMethods.conformsToProtocol_(MyProtocol)) 176 self.assert_(MyClassImplementingMyOtherProtocol.pyobjc_classMethods.conformsToProtocol_(MyOtherProtocol)) 177 178 try: 179 class ImplementingMyClassProtocol(NSObject, MyClassProtocol): 180 pass 181 182 self.fail() 183 except TypeError: 184 pass 185 186 class ImplementingMyClassProtocol(NSObject, MyClassProtocol): 187 def anAnotherOne_(self, a): 188 pass 189 190 def aClassOne_(self, a): 191 pass 192 193 aClassOne_ = classmethod(aClassOne_) 194 195 self.assertEquals(ImplementingMyClassProtocol.anAnotherOne_.signature, 'i@:i') 196 self.assertEquals(ImplementingMyClassProtocol.aClassOne_.isClassMethod, True) 197 self.assertEquals(ImplementingMyClassProtocol.aClassOne_.signature,'@@:i') 198 199 # TODO: protocol with class and instance method with different 200 # signatures. 201 # TODO: should not need to specify classmethod() if it can be 202 # deduced from the protocol 203 204 205 def testIncorrectlyDefiningFormalProtocols(self): 206 # Some bad calls to objc.formal_protocol 207 self.assertRaises(TypeError, objc.formal_protocol, [], None, ()) 208 self.assertRaises(TypeError, objc.formal_protocol, 'supers', (NSObject,) , ()) 209 self.assertRaises(TypeError, objc.formal_protocol, 'supers', objc.protocolNamed('NSLocking') , ()) 210 self.assertRaises(TypeError, objc.formal_protocol, 'supers', [ 211 objc.protocolNamed('NSLocking'), 212 "hello", 213 ], ()) 214 self.assertRaises(TypeError, objc.formal_protocol, 'supers', None, [ 215 objc.selector(None, selector='fooMethod:', signature='v@:i'), 216 "hello", 217 ]) 218 219 def testMethodInfo(self): 220 self.assertEquals( 221 MyProtocol.descriptionForInstanceMethod_("protoMethod"), 222 ("protoMethod", "I@:")) 223 224 self.assertEquals( 225 MyProtocol.descriptionForInstanceMethod_("nosuchmethod"), 226 None) 227 228 self.assertEquals( 229 MyClassProtocol.descriptionForClassMethod_("aClassOne:"), 230 ("aClassOne:", "@@:i")) 231 232 self.assertEquals( 233 MyClassProtocol.descriptionForClassMethod_("nosuchmethod"), 234 None) 235 236 237 def dont_testObjCInterface(self): 238 # TODO: tests that access the Objective-C interface of protocols 239 # (those methods should be forwarded to the underlying object, as 240 # with objc.pyobjc_unicode). 241 # NOTE: This is not very important, the only methods that are not 242 # explicitly wrapped should be compatibility methods that will 243 # cause a warning when called. 244 self.assertEquals(1, 0) 245 246if __name__ == '__main__': 247 main() 248