1from PyObjCTools.TestSupport import *
2import objc
3import warnings
4import platform
5import sys
6
7# Most useful systems will at least have 'NSObject'.
8NSObject = objc.lookUpClass('NSObject')
9
10
11# XXX : This is a really dumb way to detect < 10.3
12if not NSObject.instancesRespondToSelector_('setValue:forKey:'):
13    # Defining protocols in an MH_BUNDLE makes < 10.3 explode
14    OC_TestProtocol = None
15else:
16    from PyObjCTest.protocol import OC_TestProtocol
17
18
19MyProto3 = objc.informal_protocol("MyProto3", (
20    objc.selector(None, selector=b"testMethod", signature=b"I@:", isRequired=1),
21    objc.selector(None, selector=b"testMethod2:", signature=b"v@:i", isRequired=0)
22))
23
24class Test3InformalProtocols(TestCase):
25    def testOptional(self):
26        class ProtoClass3 (NSObject, protocols=[MyProto3]):
27            def testMethod(self):
28                pass
29
30
31
32
33if (sys.maxsize < 2 ** 32) or (platform.mac_ver()[0] >= '10.7'):
34    EmptyProtocol3 = objc.formal_protocol("EmptyProtocol3", None, ())
35
36
37    MyProtocol3 = objc.formal_protocol("MyProtocol3", None, (
38        objc.selector(None, selector=b"protoMethod", signature=b"I@:"),
39        objc.selector(None, selector=b"anotherProto:with:", signature=b"v@:ii"),
40    ))
41
42    MyOtherProtocol3 = objc.formal_protocol("MyOtherProtocol3",
43            (MyProtocol3,), [
44                objc.selector(None, selector=b"yetAnother:", signature=b"i@:I")
45            ])
46
47    MyClassProtocol3 = objc.formal_protocol("MyClassProtocol3", None, [
48        objc.selector(None, selector=b"anAnotherOne:", signature=b"i@:i"),
49        objc.selector(None, selector=b"aClassOne:", signature=b"@@:i", isClassMethod=1),
50    ])
51
52    if OC_TestProtocol is not None:
53
54        class TestFormalOCProtocols(TestCase):
55
56            def testImplementFormalProtocol(self):
57
58                class MyClassNotImplementingProtocol(NSObject):
59                    pass
60
61                self.assertFalse(MyClassNotImplementingProtocol.pyobjc_classMethods.conformsToProtocol_(OC_TestProtocol))
62
63                try:
64                    class MyClassNotAlsoImplementingProtocol(NSObject, protocols=[OC_TestProtocol]):
65                        def method1(self): pass
66
67                    self.fail("class not implementing protocol, yet created")
68                except TypeError:
69                    pass
70
71                class MyClassImplementingProtocol(NSObject, protocols=[OC_TestProtocol]):
72                    def method1(self): pass
73                    def method2_(self, a): pass
74
75                self.assertTrue(MyClassImplementingProtocol.pyobjc_classMethods.conformsToProtocol_(OC_TestProtocol))
76
77
78
79                # The PyObjC implementation of formal protocols is slightly looser
80                # than Objective-C itself: you can inherit part of the protocol
81                # from the superclass.
82                # XXX: not really: you won't inherit the right signatures by default
83
84                class MyClassImplementingHalfOfProtocol(NSObject):
85                    def method1(self): pass
86                    method1 = objc.selector(method1, signature=b'i@:')
87
88                self.assertFalse(MyClassImplementingHalfOfProtocol.pyobjc_classMethods.conformsToProtocol_(OC_TestProtocol))
89
90                class MyClassImplementingAllOfProtocol(MyClassImplementingHalfOfProtocol, protocols=[OC_TestProtocol]):
91                    def method2_(self, v): pass
92
93                self.assertTrue(MyClassImplementingAllOfProtocol.pyobjc_classMethods.conformsToProtocol_(OC_TestProtocol))
94
95
96
97
98    class TestFormalProtocols (TestCase):
99        # Implement unittests for formal protocols here.
100        #
101
102        def testImplementAnotherObject(self):
103            anObject = NSObject.alloc().init()
104
105            try:
106                class MyClassImplementingAnotherObject(NSObject, protocols=[anObject]):
107                    pass
108                self.fail("Can create class that implements an object???")
109            except TypeError:
110                pass
111
112            try:
113                class MyClassImplementingAnotherObject(NSObject, protocols=[10]):
114                    pass
115                self.fail()
116            except TypeError:
117                pass
118
119            try:
120                class MyClassImplementingAnotherObject(NSObject, protocols=[int]):
121                    pass
122                self.fail()
123            except TypeError:
124                pass
125
126
127
128        def testIncorrectlyDefiningFormalProtocols(self):
129            # Some bad calls to objc.formal_protocol
130            self.assertRaises(TypeError, objc.formal_protocol, [], None, ())
131            self.assertRaises(TypeError, objc.formal_protocol, 'supers', (NSObject,) , ())
132            self.assertRaises(TypeError, objc.formal_protocol, 'supers', objc.protocolNamed('NSLocking') , ())
133            self.assertRaises(TypeError, objc.formal_protocol, 'supers', [
134                    objc.protocolNamed('NSLocking'),
135                    "hello",
136                ], ())
137            self.assertRaises(TypeError, objc.formal_protocol, 'supers', None, [
138                    objc.selector(None, selector=b'fooMethod:', signature=b'v@:i'),
139                    "hello",
140                ])
141
142        def testMethodInfo(self):
143            self.assertEqual(MyProtocol3.instanceMethods(), [
144                {'typestr': b'I@:', 'required': True, 'selector': b'protoMethod'},
145                {'typestr': b'v@:ii', 'required': True, 'selector': b'anotherProto:with:'},
146            ])
147            self.assertEqual(MyProtocol3.classMethods(), [
148            ])
149            self.assertEqual(
150                    MyProtocol3.descriptionForInstanceMethod_(b"protoMethod"),
151                        (b"protoMethod", b"I@:"))
152
153            self.assertEqual(
154                    MyProtocol3.descriptionForInstanceMethod_(b"nosuchmethod"),
155                        None)
156
157            self.assertEqual(MyClassProtocol3.classMethods(), [
158                {'required': True, 'selector': b'aClassOne:', 'typestr': b'@@:i'}
159            ])
160            self.assertEqual(MyProtocol3.classMethods(), [
161            ])
162            self.assertEqual(
163                    MyClassProtocol3.descriptionForClassMethod_(b"aClassOne:"),
164                        (b"aClassOne:", b"@@:i"))
165
166            self.assertEqual(
167                    MyClassProtocol3.descriptionForClassMethod_(b"nosuchmethod"),
168                        None)
169
170
171if __name__ == '__main__':
172    main()
173