1from PyObjCTools.TestSupport import *
2
3import objc
4import sys
5
6try:
7    from  Foundation import NSRange
8
9    _C_NSRange = NSRange.__typestr__
10
11except ImportError:
12    if sys.maxsize > 2 ** 32:
13        _C_NSRange = b"{_NSRange=QQ}"
14    else:
15        _C_NSRange = b"{_NSRange=II}"
16
17
18NSObject = objc.lookUpClass("NSObject")
19
20class TestBasicDescriptors (TestCase):
21
22    # IBOutlet is tested in test_ivar
23
24    def test_ibaction(self):
25
26        @objc.IBAction
27        def myAction_(self, sender):
28            return 1
29
30        self.assertIsInstance(myAction_, objc.selector)
31        self.assertEqual(myAction_.signature, b'v@:@')
32        self.assertEqual(myAction_.selector, b'myAction:')
33        self.assertFalse(myAction_.isClassMethod)
34
35
36        self.assertRaises(TypeError, objc.IBAction, None)
37        self.assertRaises(TypeError, objc.IBAction, 42)
38
39    def test_instancemethod(self):
40        class TestDescriptorsClass1 (NSObject):
41            @objc.instancemethod
42            def new(self):
43                pass
44
45        o = NSObject.alloc().init()
46        self.assertFalse(hasattr(o, 'new'))
47        self.assertTrue(hasattr(NSObject, 'new'))
48        self.assertTrue(NSObject.new.isClassMethod)
49
50        o = TestDescriptorsClass1.alloc().init()
51        m = o.new
52        self.assertIsInstance(m, objc.selector)
53        self.assertFalse(m.isClassMethod)
54
55
56        self.assertRaises(TypeError, objc.instancemethod, None)
57        self.assertRaises(TypeError, objc.instancemethod, 42)
58
59    def test_typedSelector(self):
60
61        @objc.typedSelector(b"I@:qq")
62        def mySelector_arg_(self, a, b):
63            return 4
64
65        self.assertIsInstance(mySelector_arg_, objc.selector)
66        self.assertEqual(mySelector_arg_.signature, b"I@:qq")
67        self.assertEqual(mySelector_arg_.selector, b"mySelector:arg:")
68
69        self.assertRaises(TypeError, objc.typedSelector(b"v@:i"), None)
70        self.assertRaises(TypeError, objc.typedSelector(b"v@:i"), 42)
71
72    def testNamedSelector(self):
73        @objc.namedSelector(b'foo:bar:')
74        def mymethod(self, a, b):
75            pass
76
77        self.assertIsInstance(mymethod, objc.selector)
78        self.assertEqual(mymethod.signature, b"v@:@@")
79        self.assertEqual(mymethod.selector, b"foo:bar:")
80
81        self.assertRaises(TypeError, objc.namedSelector(b"foo:bar:"), None)
82        self.assertRaises(TypeError, objc.namedSelector(b"foo:bar:"), 42)
83
84        @objc.namedSelector(b'foo:bar:', signature=b"q@:qq")
85        def mymethod(self, a, b):
86            pass
87
88        self.assertIsInstance(mymethod, objc.selector)
89        self.assertEqual(mymethod.signature, b"q@:qq")
90        self.assertEqual(mymethod.selector, b"foo:bar:")
91
92        self.assertRaises(TypeError, objc.namedSelector(b"foo:bar:", b"q@:qq"), None)
93        self.assertRaises(TypeError, objc.namedSelector(b"foo:bar:", b"q@:qq"), 42)
94
95    def testNamedselector(self):
96        with filterWarnings("ignore", RuntimeWarning):
97            @objc.namedselector(b'foo:bar:')
98            def mymethod(self, a, b):
99                pass
100
101            self.assertIsInstance(mymethod, objc.selector)
102            self.assertEqual(mymethod.signature, b"v@:@@")
103            self.assertEqual(mymethod.selector, b"foo:bar:")
104
105            self.assertRaises(TypeError, objc.namedselector(b"foo:bar:"), None)
106            self.assertRaises(TypeError, objc.namedselector(b"foo:bar:"), 42)
107
108            @objc.namedselector(b'foo:bar:', signature=b"q@:qq")
109            def mymethod(self, a, b):
110                pass
111
112            self.assertIsInstance(mymethod, objc.selector)
113            self.assertEqual(mymethod.signature, b"q@:qq")
114            self.assertEqual(mymethod.selector, b"foo:bar:")
115
116            self.assertRaises(TypeError, objc.namedselector(b"foo:bar:", b"q@:qq"), None)
117            self.assertRaises(TypeError, objc.namedselector(b"foo:bar:", b"q@:qq"), 42)
118
119    # synthesize is tested in test_synthesize
120
121    def test_accessor(self):
122        # NOTE: the optional type argument is tested through the typedAccessor function
123
124        # Basic properties:
125
126        @objc.accessor
127        def color(self):
128            return 42
129
130        @objc.accessor
131        def isColor(self):
132            return 42
133
134        @objc.accessor
135        def setColor_(self, value):
136            pass
137
138        self.assertIsInstance(color, objc.selector)
139        self.assertIsInstance(isColor, objc.selector)
140        self.assertIsInstance(setColor_, objc.selector)
141
142        self.assertEqual(color.signature, b"@@:")
143        self.assertEqual(isColor.signature, b"@@:")
144        self.assertEqual(setColor_.signature, b"v@:@")
145
146
147        # Indexed accessors
148
149        @objc.accessor
150        def countOfFlavors(self):
151            return 2
152
153        @objc.accessor
154        def objectInFlavorsAtIndex_(self, idx):
155            return "sour"
156
157        @objc.accessor
158        def flavorsAtIndexes_(sef, indices):
159            return ["sour", "sweet"]
160
161        @objc.accessor
162        def getFlavors_range_(self, buffer, range):
163            return ["sour", "sweet"]
164
165
166        self.assertIsInstance(countOfFlavors, objc.selector)
167        self.assertIsInstance(objectInFlavorsAtIndex_, objc.selector)
168        self.assertIsInstance(flavorsAtIndexes_, objc.selector)
169        self.assertIsInstance(getFlavors_range_, objc.selector)
170
171        self.assertEqual(countOfFlavors.signature, objc._C_NSUInteger + b"@:")
172        self.assertEqual(objectInFlavorsAtIndex_.signature, b"@@:" + objc._C_NSUInteger)
173        self.assertEqual(flavorsAtIndexes_.signature, b"@@:@")
174
175        # XXX: This needs even more work: also have to add custom metadata!
176        self.assertEqual(getFlavors_range_.signature, b"v@:o^@" + _C_NSRange)
177
178        # Mutable Indexed Accessors
179
180        @objc.accessor
181        def insertObject_inFlavorsAtIndex_(self, value, idx):
182            pass
183
184        @objc.accessor
185        def insertFlavors_atIndexes_(self, values, indices):
186            pass
187
188        @objc.accessor
189        def removeObjectFromFlavorsAtIndex_(self, index):
190            pass
191
192        @objc.accessor
193        def removeFlavorsAtIndexes_(self, indices):
194            pass
195
196        @objc.accessor
197        def replaceObjectInFlavorsAtIndex_withObject_(self, value, idx):
198            pass
199
200        @objc.accessor
201        def replaceFlavorsAtIndexes_withFlavors_(self, indices, values):
202            pass
203
204
205        self.assertIsInstance(insertObject_inFlavorsAtIndex_, objc.selector)
206        self.assertIsInstance(insertFlavors_atIndexes_, objc.selector)
207        self.assertIsInstance(removeObjectFromFlavorsAtIndex_, objc.selector)
208        self.assertIsInstance(removeFlavorsAtIndexes_, objc.selector)
209        self.assertIsInstance(replaceObjectInFlavorsAtIndex_withObject_, objc.selector)
210        self.assertIsInstance(replaceFlavorsAtIndexes_withFlavors_, objc.selector)
211
212        self.assertEqual(insertObject_inFlavorsAtIndex_.signature, b"v@:@" + objc._C_NSUInteger)
213        self.assertEqual(insertFlavors_atIndexes_.signature, b"v@:@@")
214        self.assertEqual(removeObjectFromFlavorsAtIndex_.signature, b"v@:" + objc._C_NSUInteger)
215        self.assertEqual(removeFlavorsAtIndexes_.signature, b"v@:@")
216        self.assertEqual(replaceObjectInFlavorsAtIndex_withObject_.signature, b"v@:" + objc._C_NSUInteger + b"@")
217        self.assertEqual(replaceFlavorsAtIndexes_withFlavors_.signature, b"v@:@@")
218
219
220        # Getter Unordered Accessors
221        @objc.accessor
222        def countOfLanguages(self):
223            pass
224
225        @objc.accessor
226        def enumeratorOfLanguages(self):
227            pass
228
229        @objc.accessor
230        def memberOfLanguages_(self, value):
231            return False
232
233        self.assertIsInstance(countOfLanguages, objc.selector)
234        self.assertIsInstance(enumeratorOfLanguages, objc.selector)
235        self.assertIsInstance(memberOfLanguages_, objc.selector)
236
237        self.assertEqual(countOfLanguages.signature, objc._C_NSUInteger + b"@:")
238        self.assertEqual(enumeratorOfLanguages.signature, b"@@:")
239        self.assertEqual(memberOfLanguages_.signature, objc._C_NSBOOL + b"@:@")
240
241        # Mutable Unordered Accessors
242
243        @objc.accessor
244        def addLanguagesObject_(self, value):
245            pass
246
247        @objc.accessor
248        def addLanguagues_(self, values):
249            pass
250
251        @objc.accessor
252        def intersectLanguagues_(self, values):
253            pass
254
255        self.assertIsInstance(addLanguagesObject_, objc.selector)
256        self.assertIsInstance(addLanguagues_, objc.selector)
257        self.assertIsInstance(intersectLanguagues_, objc.selector)
258
259        self.assertEqual(addLanguagesObject_.signature, b"v@:@")
260        self.assertEqual(addLanguagues_.signature, b"v@:@")
261        self.assertEqual(intersectLanguagues_.signature, b"v@:@")
262
263        # Validation
264        @objc.accessor
265        def validateColor_error_(self, value, error):
266            return (False, None)
267
268        self.assertIsInstance(validateColor_error_, objc.selector)
269        self.assertEqual(validateColor_error_.signature, objc._C_NSBOOL + b'@:N^@o^@')
270
271
272
273        # Keyword arguments (**kwds) and varargs (*args) are
274        # not supported:
275
276        def attrib(self, *args):
277            pass
278        self.assertRaises(TypeError, objc.accessor, attrib)
279
280        def attrib(self, **kwds):
281            pass
282        self.assertRaises(TypeError, objc.accessor, attrib)
283
284        # Not really an accessor
285        def attrib_error_(self, a, b):
286            pass
287        self.assertRaises(TypeError, objc.accessor, attrib_error_)
288
289        # Argument counts that don't match
290        def validateObject_error_(self, a):
291            pass
292        self.assertRaises(TypeError, objc.accessor, validateObject_error_)
293
294        def validateObject_error_(self, a, b, c):
295            pass
296        self.assertRaises(TypeError, objc.accessor, validateObject_error_)
297
298        def validateObject_error_(self, a, b, c, d=1, e=2):
299            pass
300        self.assertRaises(TypeError, objc.accessor, validateObject_error_)
301
302        @objc.accessor
303        def validateObject_error_(self, a, b, c=1):
304            pass
305
306
307
308
309    def test_typedAccessor(self):
310        # NOTE: the optional type argument is tested through the typedAccessor function
311
312        # Basic properties:
313
314        mytype = b"{Struct=qq}"
315
316        @objc.typedAccessor(mytype)
317        def color(self):
318            return 42
319
320        @objc.typedAccessor(mytype)
321        def isColor(self):
322            return 42
323
324        @objc.typedAccessor(mytype)
325        def setColor_(self, value):
326            pass
327
328        self.assertIsInstance(color, objc.selector)
329        self.assertIsInstance(isColor, objc.selector)
330        self.assertIsInstance(setColor_, objc.selector)
331
332        self.assertEqual(color.signature, mytype + b"@:")
333        self.assertEqual(isColor.signature, mytype + b"@:")
334        self.assertEqual(setColor_.signature, b"v@:" + mytype)
335
336
337        # Indexed accessors
338
339        @objc.typedAccessor(mytype)
340        def countOfFlavors(self):
341            return 2
342
343        @objc.typedAccessor(mytype)
344        def objectInFlavorsAtIndex_(self, idx):
345            return "sour"
346
347        @objc.typedAccessor(mytype)
348        def flavorsAtIndexes_(sef, indices):
349            return ["sour", "sweet"]
350
351        @objc.typedAccessor(mytype)
352        def getFlavors_range_(self, buffer, range):
353            return ["sour", "sweet"]
354
355
356        self.assertIsInstance(countOfFlavors, objc.selector)
357        self.assertIsInstance(objectInFlavorsAtIndex_, objc.selector)
358        self.assertIsInstance(flavorsAtIndexes_, objc.selector)
359        self.assertIsInstance(getFlavors_range_, objc.selector)
360
361        self.assertEqual(countOfFlavors.signature, objc._C_NSUInteger + b"@:")
362        self.assertEqual(objectInFlavorsAtIndex_.signature, mytype + b"@:" + objc._C_NSUInteger)
363        self.assertEqual(flavorsAtIndexes_.signature, b"@@:@") #XXX: is this correct?
364
365        # XXX: This needs even more work: also have to add custom metadata!
366        self.assertEqual(getFlavors_range_.signature, b"v@:o^@" + _C_NSRange)
367
368        # Mutable Indexed Accessors
369
370        @objc.typedAccessor(mytype)
371        def insertObject_inFlavorsAtIndex_(self, value, idx):
372            pass
373
374        @objc.typedAccessor(mytype)
375        def insertFlavors_atIndexes_(self, values, indices):
376            pass
377
378        @objc.typedAccessor(mytype)
379        def removeObjectFromFlavorsAtIndex_(self, index):
380            pass
381
382        @objc.typedAccessor(mytype)
383        def removeFlavorsAtIndexes_(self, indices):
384            pass
385
386        @objc.typedAccessor(mytype)
387        def replaceObjectInFlavorsAtIndex_withObject_(self, value, idx):
388            pass
389
390        @objc.typedAccessor(mytype)
391        def replaceFlavorsAtIndexes_withFlavors_(self, indices, values):
392            pass
393
394
395        self.assertIsInstance(insertObject_inFlavorsAtIndex_, objc.selector)
396        self.assertIsInstance(insertFlavors_atIndexes_, objc.selector)
397        self.assertIsInstance(removeObjectFromFlavorsAtIndex_, objc.selector)
398        self.assertIsInstance(removeFlavorsAtIndexes_, objc.selector)
399        self.assertIsInstance(replaceObjectInFlavorsAtIndex_withObject_, objc.selector)
400        self.assertIsInstance(replaceFlavorsAtIndexes_withFlavors_, objc.selector)
401
402        self.assertEqual(insertObject_inFlavorsAtIndex_.signature, b"v@:" + mytype + objc._C_NSUInteger)
403        self.assertEqual(insertFlavors_atIndexes_.signature, b"v@:@@") # XXX: is this correct?
404        self.assertEqual(removeObjectFromFlavorsAtIndex_.signature, b"v@:" + objc._C_NSUInteger)
405        self.assertEqual(removeFlavorsAtIndexes_.signature, b"v@:@")
406        self.assertEqual(replaceObjectInFlavorsAtIndex_withObject_.signature, b"v@:" + objc._C_NSUInteger + mytype)
407        self.assertEqual(replaceFlavorsAtIndexes_withFlavors_.signature, b"v@:@@") # XXX: is this correct?
408
409
410        # Getter Unordered Accessors
411        @objc.typedAccessor(mytype)
412        def countOfLanguages(self):
413            pass
414
415        @objc.typedAccessor(mytype)
416        def enumeratorOfLanguages(self):
417            pass
418
419        @objc.typedAccessor(mytype)
420        def memberOfLanguages_(self, value):
421            return False
422
423        self.assertIsInstance(countOfLanguages, objc.selector)
424        self.assertIsInstance(enumeratorOfLanguages, objc.selector)
425        self.assertIsInstance(memberOfLanguages_, objc.selector)
426
427        self.assertEqual(countOfLanguages.signature, objc._C_NSUInteger + b"@:")
428        self.assertEqual(enumeratorOfLanguages.signature, b"@@:")
429        self.assertEqual(memberOfLanguages_.signature, objc._C_NSBOOL + b"@:" + mytype)
430
431        # Mutable Unordered Accessors
432
433        @objc.typedAccessor(mytype)
434        def addLanguagesObject_(self, value):
435            pass
436
437        @objc.typedAccessor(mytype)
438        def addLanguagues_(self, values):
439            pass
440
441        @objc.typedAccessor(mytype)
442        def intersectLanguagues_(self, values):
443            pass
444
445        self.assertIsInstance(addLanguagesObject_, objc.selector)
446        self.assertIsInstance(addLanguagues_, objc.selector)
447        self.assertIsInstance(intersectLanguagues_, objc.selector)
448
449        self.assertEqual(addLanguagesObject_.signature, b"v@:" + mytype)
450        self.assertEqual(addLanguagues_.signature, b"v@:@") # XXX: is this correct?
451        self.assertEqual(intersectLanguagues_.signature, b"v@:@")
452
453        # Validation
454        @objc.typedAccessor(mytype)
455        def validateColor_error_(self, value, error):
456            return (False, None)
457
458        self.assertIsInstance(validateColor_error_, objc.selector)
459        self.assertEqual(validateColor_error_.signature, objc._C_NSBOOL + b'@:N^@o^@')
460
461    def test_Accessor(self):
462        with filterWarnings("ignore", DeprecationWarning):
463            # NOTE: the optional type argument is tested through the typedAccessor function
464
465            # Basic properties:
466
467            @objc.Accessor
468            def color(self):
469                return 42
470
471            @objc.Accessor
472            def isColor(self):
473                return 42
474
475            @objc.Accessor
476            def setColor_(self, value):
477                pass
478
479            self.assertIsInstance(color, objc.selector)
480            self.assertIsInstance(isColor, objc.selector)
481            self.assertIsInstance(setColor_, objc.selector)
482
483            self.assertEqual(color.signature, b"@@:")
484            self.assertEqual(isColor.signature, b"@@:")
485            self.assertEqual(setColor_.signature, b"v@:@")
486
487
488            # Indexed accessors
489
490            @objc.Accessor
491            def countOfFlavors(self):
492                return 2
493
494            @objc.Accessor
495            def objectInFlavorsAtIndex_(self, idx):
496                return "sour"
497
498            @objc.Accessor
499            def flavorsAtIndexes_(sef, indices):
500                return ["sour", "sweet"]
501
502            @objc.Accessor
503            def getFlavors_range_(self, buffer, range):
504                return ["sour", "sweet"]
505
506
507            self.assertIsInstance(countOfFlavors, objc.selector)
508            self.assertIsInstance(objectInFlavorsAtIndex_, objc.selector)
509            self.assertIsInstance(flavorsAtIndexes_, objc.selector)
510            self.assertIsInstance(getFlavors_range_, objc.selector)
511
512            self.assertEqual(countOfFlavors.signature, objc._C_NSUInteger + b"@:")
513            self.assertEqual(objectInFlavorsAtIndex_.signature, b"@@:" + objc._C_NSUInteger)
514            self.assertEqual(flavorsAtIndexes_.signature, b"@@:@")
515
516            # XXX: This needs even more work: also have to add custom metadata!
517            self.assertEqual(getFlavors_range_.signature, b"v@:o^@" + _C_NSRange)
518
519            # Mutable Indexed Accessors
520
521            @objc.Accessor
522            def insertObject_inFlavorsAtIndex_(self, value, idx):
523                pass
524
525            @objc.Accessor
526            def insertFlavors_atIndexes_(self, values, indices):
527                pass
528
529            @objc.Accessor
530            def removeObjectFromFlavorsAtIndex_(self, index):
531                pass
532
533            @objc.Accessor
534            def removeFlavorsAtIndexes_(self, indices):
535                pass
536
537            @objc.Accessor
538            def replaceObjectInFlavorsAtIndex_withObject_(self, value, idx):
539                pass
540
541            @objc.Accessor
542            def replaceFlavorsAtIndexes_withFlavors_(self, indices, values):
543                pass
544
545
546            self.assertIsInstance(insertObject_inFlavorsAtIndex_, objc.selector)
547            self.assertIsInstance(insertFlavors_atIndexes_, objc.selector)
548            self.assertIsInstance(removeObjectFromFlavorsAtIndex_, objc.selector)
549            self.assertIsInstance(removeFlavorsAtIndexes_, objc.selector)
550            self.assertIsInstance(replaceObjectInFlavorsAtIndex_withObject_, objc.selector)
551            self.assertIsInstance(replaceFlavorsAtIndexes_withFlavors_, objc.selector)
552
553            self.assertEqual(insertObject_inFlavorsAtIndex_.signature, b"v@:@" + objc._C_NSUInteger)
554            self.assertEqual(insertFlavors_atIndexes_.signature, b"v@:@@")
555            self.assertEqual(removeObjectFromFlavorsAtIndex_.signature, b"v@:" + objc._C_NSUInteger)
556            self.assertEqual(removeFlavorsAtIndexes_.signature, b"v@:@")
557            self.assertEqual(replaceObjectInFlavorsAtIndex_withObject_.signature, b"v@:" + objc._C_NSUInteger + b"@")
558            self.assertEqual(replaceFlavorsAtIndexes_withFlavors_.signature, b"v@:@@")
559
560
561            # Getter Unordered Accessors
562            @objc.Accessor
563            def countOfLanguages(self):
564                pass
565
566            @objc.Accessor
567            def enumeratorOfLanguages(self):
568                pass
569
570            @objc.Accessor
571            def memberOfLanguages_(self, value):
572                return False
573
574            self.assertIsInstance(countOfLanguages, objc.selector)
575            self.assertIsInstance(enumeratorOfLanguages, objc.selector)
576            self.assertIsInstance(memberOfLanguages_, objc.selector)
577
578            self.assertEqual(countOfLanguages.signature, objc._C_NSUInteger + b"@:")
579            self.assertEqual(enumeratorOfLanguages.signature, b"@@:")
580            self.assertEqual(memberOfLanguages_.signature, objc._C_NSBOOL + b"@:@")
581
582            # Mutable Unordered Accessors
583
584            @objc.Accessor
585            def addLanguagesObject_(self, value):
586                pass
587
588            @objc.Accessor
589            def addLanguagues_(self, values):
590                pass
591
592            @objc.Accessor
593            def intersectLanguagues_(self, values):
594                pass
595
596            self.assertIsInstance(addLanguagesObject_, objc.selector)
597            self.assertIsInstance(addLanguagues_, objc.selector)
598            self.assertIsInstance(intersectLanguagues_, objc.selector)
599
600            self.assertEqual(addLanguagesObject_.signature, b"v@:@")
601            self.assertEqual(addLanguagues_.signature, b"v@:@")
602            self.assertEqual(intersectLanguagues_.signature, b"v@:@")
603
604            # Validation
605            @objc.Accessor
606            def validateColor_error_(self, value, error):
607                return (False, None)
608
609            self.assertIsInstance(validateColor_error_, objc.selector)
610            self.assertEqual(validateColor_error_.signature, objc._C_NSBOOL + b'@:N^@o^@')
611
612
613
614            # Keyword arguments (**kwds) and varargs (*args) are
615            # not supported:
616
617            def attrib(self, *args):
618                pass
619            self.assertRaises(TypeError, objc.Accessor, attrib)
620
621            def attrib(self, **kwds):
622                pass
623            self.assertRaises(TypeError, objc.Accessor, attrib)
624
625            # Not really an accessor
626            def attrib_error_(self, a, b):
627                pass
628            self.assertRaises(TypeError, objc.Accessor, attrib_error_)
629
630            # Argument counts that don't match
631            def validateObject_error_(self, a):
632                pass
633            self.assertRaises(TypeError, objc.Accessor, validateObject_error_)
634
635            def validateObject_error_(self, a, b, c):
636                pass
637            self.assertRaises(TypeError, objc.Accessor, validateObject_error_)
638
639            def validateObject_error_(self, a, b, c, d=1, e=2):
640                pass
641            self.assertRaises(TypeError, objc.Accessor, validateObject_error_)
642
643            @objc.Accessor
644            def validateObject_error_(self, a, b, c=1):
645                pass
646
647    def test_signature(self):
648
649        @objc.signature(b"d@:ii")
650        def myMethod_arg_(self, a, b):
651            pass
652
653        self.assertIsInstance(myMethod_arg_, objc.selector)
654        self.assertEqual(myMethod_arg_.signature, b'd@:ii')
655        self.assertEqual(myMethod_arg_.selector, b'myMethod:arg:')
656
657        @objc.signature(b'q@:@q', selector=b'foo:bar:')
658        def method(self, a, b):
659            pass
660
661        self.assertIsInstance(method, objc.selector)
662        self.assertEqual(method.signature, b'q@:@q')
663        self.assertEqual(method.selector, b'foo:bar:')
664
665
666
667
668
669
670
671if __name__ == "__main__":
672    main()
673