Commits

Ronald Oussoren committed 48cc31c

Further improvements to _callable_docstr test coverage

The code still needs tests for the metadata for "difficult"
arguments (in/out, buffers) in the __doc__ generator.

  • Participants
  • Parent commits 72ce868

Comments (0)

Files changed (2)

pyobjc-core/Lib/objc/_callable_docstr.py

         hdr_name = []
         if len(metadata['arguments']) > arg_offset:
             for idx, (nm, info) in enumerate(zip(name_parts, metadata['arguments'][arg_offset:])):
+                if hdr_name:
+                    hdr_name.append(' ')
                 hdr_name.append(nm)
                 hdr_name.append(':(')
                 hdr_name.append(describe_type(info['type']))
-                hdr_name.append(')arg%d '%(idx,))
+                hdr_name.append(')arg%d'%(idx,))
 
                 if info['type'][:1] in prefixes and info['type'][:1] not in (objc._C_ONEWAY, objc._C_CONST):
                     arg_info.append((idx, info))
                 if info.get('callable'):
                     arg_info.append((idx, info))
 
-
-            if metadata.get('variadic'):
-                hdr_name.append(", ...")
         else:
             hdr_name.append(name)
 
+        if metadata.get('variadic'):
+            hdr_name.append(", ...")
 
         header = "%s (%s)%s;"%(
                 "+" if metadata['classmethod'] else "-",
         if metadata.get('variadic'):
             hdr_name.append(", ...")
 
+        if not hdr_name:
+            hdr_name.append('void')
+
         header = "%s %s(%s);"%(
                 describe_type(metadata['retval']['type']),
                 name,

pyobjc-core/PyObjCTest/test_callable_docstr.py

         handle = objc.createOpaquePointerType("NamedPointer", b"^{NamedTestPointer1=}")
         self.assertEqual(mod.describe_type(b"^{NamedTestPointer1=}"), "NamedPointer")
 
+    def test_unknown(self):
+        self.assertEqual(mod.describe_type(b'?'), '<?>')
+        self.assertEqual(mod.describe_type(b'X'), '<?>')
+
     def test_callable(self):
         self.assertEqual(mod.describe_type(objc._C_ID + b'?'), "<BLOCK>")
         self.assertEqual(mod.describe_type(objc._C_PTR + b'?'), "<FUNCTION>")
 
     def test_struct(self):
         self.assertEqual(mod.describe_type(objc._C_STRUCT_B + b"=" + objc._C_ID + objc._C_STRUCT_E), "struct <?>")
+        self.assertEqual(mod.describe_type(objc._C_STRUCT_B + objc._C_STRUCT_E), "struct <?>")
         self.assertEqual(mod.describe_type(objc._C_STRUCT_B + b"name=" + objc._C_ID + objc._C_INT + objc._C_STRUCT_E), "struct name")
         self.assertEqual(mod.describe_type(objc._C_STRUCT_B + b"name=\"field\"" + objc._C_ID + b'"field2"' + objc._C_INT + objc._C_STRUCT_E), "struct name")
 
 
     def test_union(self):
         self.assertEqual(mod.describe_type(objc._C_UNION_B + b"=" + objc._C_ID + objc._C_UNION_E), "union <?>")
+        self.assertEqual(mod.describe_type(objc._C_UNION_B + objc._C_UNION_E), "union <?>")
         self.assertEqual(mod.describe_type(objc._C_UNION_B + b"name=" + objc._C_ID + objc._C_INT + objc._C_UNION_E), "union name")
         self.assertEqual(mod.describe_type(objc._C_UNION_B + b"name=\"field\"" + objc._C_ID + b'"field2"' + objc._C_INT + objc._C_UNION_E), "union name")
 
 class TestDescribeCallable (TestCase):
+
+    def setUp(self):
+        dct = {}
+        func = objc.loadBundleFunctions(None, dct, [
+            ('NSTemporaryDirectory', objc._C_ID),
+            ('NSSearchPathForDirectoriesInDomains', objc._C_ID + objc._C_NSUInteger + objc._C_NSUInteger + objc._C_NSBOOL),
+        ])
+        self.NSTemporaryDirectory = dct['NSTemporaryDirectory']
+        self.NSSearchPathForDirectoriesInDomains = dct['NSSearchPathForDirectoriesInDomains']
+
     def test_not_for_regular_types(self):
         self.assertRaises(AttributeError, mod.describe_callable, 42)
         self.assertRaises(AttributeError, mod.describe_callable, int)
         self.assertRaises(AttributeError, mod.describe_callable, dir)
         self.assertRaises(AttributeError, mod.describe_callable, lambda x: x*2)
 
-    def test_sel(self):
-        # Basicly just test that this calls the metadata function
-        self.fail()
+    def test_sel_func(self):
+        # Basicly just test that mod.describe_callable calls
+        # mod.describe_callable_metadata with the right arguments.
+        orig = mod.describe_callable_metadata
+        try:
+            recording = []
+            def record(*args, **kwds):
+                recording.append((args, kwds))
+                return 42
+            mod.describe_callable_metadata = record
 
-    def test_func(self):
-        # Basicly just test that this calls the metadata function
-        self.fail()
+            self.assertEqual(mod.describe_callable(NSArray.array), 42)
+            self.assertEqual(mod.describe_callable(self.NSTemporaryDirectory), 42)
+            self.assertEqual(recording, [
+                ((NSArray.array.__name__, NSArray.array.__metadata__()), dict(ismethod=True)),
+                ((self.NSTemporaryDirectory.__name__, self.NSTemporaryDirectory.__metadata__()), dict(ismethod=False)),
+            ])
 
-    def test_metadata(self):
+        finally:
+            mod.describe_callable_metadata = orig
+
+    def test_metadata_header_func(self):
         # Add variants for the various types of metadata.
+        self.assertEqual(mod.describe_callable_metadata('array', {'arguments':[], 'retval': { 'type': b'v'}}, ismethod=False), 'void array(void);')
+        self.assertEqual(mod.describe_callable_metadata('array', {'arguments':[ {'type': b'i' }, {'type': b'f'} ], 'retval': { 'type': b'v'}}, ismethod=False), 'void array(int arg0, float arg1);')
+        self.assertEqual(mod.describe_callable_metadata('array', {'variadic': 1, 'arguments':[ {'type': b'i' }, {'type': b'f'} ], 'retval': { 'type': b'v'}}, ismethod=False), 'void array(int arg0, float arg1, ...);')
+
+        # This is metadata is nonsense (C doesn't allow variadic functions where all arguments are variadic)
+        self.assertEqual(mod.describe_callable_metadata('array', {'variadic':1 , 'arguments':[], 'retval': { 'type': b'v'}}, ismethod=False), 'void array(, ...);')
+
+    def test_metadata_header_sel(self):
+        self.assertEqual(mod.describe_callable_metadata('array', {'classmethod': 1, 'arguments':[ {'type': b'@'}, {'type': b':' }], 'retval': { 'type': b'v'}}, ismethod=True), '+ (void)array;')
+        self.assertEqual(mod.describe_callable_metadata('array', {'classmethod': 0, 'arguments':[ {'type': b'@'}, {'type': b':' }], 'retval': { 'type': b'v'}}, ismethod=True), '- (void)array;')
+        self.assertEqual(mod.describe_callable_metadata('initWithObjects:', {'classmethod': 0, 'arguments':[ {'type': b'@'}, {'type': b':' }, {'type': b'f'}], 'retval': { 'type': b'v'}}, ismethod=True),
+            '- (void)initWithObjects:(float)arg0;')
+        self.assertEqual(mod.describe_callable_metadata('initWithObjects:length:', {'classmethod': 0, 'arguments':[ {'type': b'@'}, {'type': b':' }, {'type': b'f'}, {'type': b'@'}], 'retval': { 'type': b'v'}}, ismethod=True),
+            '- (void)initWithObjects:(float)arg0 length:(id)arg1;')
+        self.assertEqual(mod.describe_callable_metadata('initWithObjects:', {'classmethod': 0, 'variadic': 1, 'arguments':[ {'type': b'@'}, {'type': b':' }, {'type': b'f'}], 'retval': { 'type': b'v'}}, ismethod=True),
+            '- (void)initWithObjects:(float)arg0, ...;')
+
+        # This metadata is nonsense, but shouldn't cause problems
+        self.assertEqual(mod.describe_callable_metadata('array', {'classmethod': 0, 'variadic': 1, 'arguments':[ {'type': b'@'}, {'type': b':' }], 'retval': { 'type': b'v'}}, ismethod=True), '- (void)array, ...;')
+
+    def test_metadata_special_arguments(self):
+        # - in/out/inout
+        # - function pointers
+        # - block pointers
+        # - array arguments (fixed size, size in argument(s), ...)
+        # - 1, 2 special arguments
+        # - printf_format
+        # - description of variadic arguments
+        # ...
         self.fail()
 
     def test_docattr(self):
         self.assertEqual(NSArray.arrayWithObjects_.__doc__, mod.describe_callable(NSArray.arrayWithObjects_))
         self.assertEqual(NSArray.array.__doc__, mod.describe_callable(NSArray.array))
 
-        # TODO: Same for functions
+        self.assertEqual(self.NSTemporaryDirectory.__doc__, mod.describe_callable(self.NSTemporaryDirectory))
+        self.assertEqual(self.NSSearchPathForDirectoriesInDomains.__doc__, mod.describe_callable(self.NSSearchPathForDirectoriesInDomains))
+
 
 if sys.version_info[:2] >= (3, 3):
     class TestCallableSignature (TestCase):
         def test_function(self):
-            self.fail()
+            dct = {}
+            func = objc.loadBundleFunctions(None, dct, [
+                ('NSTemporaryDirectory', objc._C_ID),
+                ('NSSearchPathForDirectoriesInDomains', objc._C_ID + objc._C_NSUInteger + objc._C_NSUInteger + objc._C_NSBOOL),
+            ])
+            NSTemporaryDirectory = dct['NSTemporaryDirectory']
+            NSSearchPathForDirectoriesInDomains = dct['NSSearchPathForDirectoriesInDomains']
 
-            # Also: Check that someFunction.__signature__ == desribe_signature(someFunction),
-            # and likewise for a class and instance selectors.
-            self.fail()
+            self.assertEqual(NSTemporaryDirectory.__signature__, mod.callable_signature(NSTemporaryDirectory))
+            self.assertEqual(NSSearchPathForDirectoriesInDomains.__signature__, mod.callable_signature(NSSearchPathForDirectoriesInDomains))
+
+            sig = NSTemporaryDirectory.__signature__
+            self.assertIsInstance(sig, inspect.Signature)
+            self.assertEqual(len(sig.parameters), 0)
+
+            sig = NSSearchPathForDirectoriesInDomains.__signature__
+            self.assertIsInstance(sig, inspect.Signature)
+            self.assertEqual(len(sig.parameters), 3)
+            self.assertEqual(sig.parameters['arg0'], inspect.Parameter('arg0', inspect.Parameter.POSITIONAL_ONLY))
+            self.assertEqual(sig.parameters['arg1'], inspect.Parameter('arg1', inspect.Parameter.POSITIONAL_ONLY))
+            self.assertEqual(sig.parameters['arg2'], inspect.Parameter('arg2', inspect.Parameter.POSITIONAL_ONLY))
+            self.assertEqual(list(sig.parameters), ['arg0', 'arg1', 'arg2'])
 
         def test_selector(self):
             m = NSArray.array