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_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, ...;')
Example #4
0
    def test_metadata_special_arguments(self):
        # - in/out/inout
        self.assertEqual(
            mod.describe_callable_metadata(
                "array",
                {
                    "arguments": [{
                        "type": b"nf"
                    }],
                    "retval": {
                        "type": b"v"
                    }
                },
                ismethod=False,
            ),
            "void array(in float arg0);\n\narg0: pass-by-reference in argument",
        )
        self.assertEqual(
            mod.describe_callable_metadata(
                "array",
                {
                    "arguments": [{
                        "type": b"Nf"
                    }],
                    "retval": {
                        "type": b"v"
                    }
                },
                ismethod=False,
            ),
            "void array(inout float arg0);\n\narg0: pass-by-reference inout argument",
        )
        self.assertEqual(
            mod.describe_callable_metadata(
                "array",
                {
                    "arguments": [{
                        "type": b"of"
                    }],
                    "retval": {
                        "type": b"v"
                    }
                },
                ismethod=False,
            ),
            "void array(out float arg0);\n\narg0: pass-by-reference out argument",
        )
        self.assertEqual(
            mod.describe_callable_metadata(
                "array",
                {
                    "arguments": [{
                        "type": b"rf"
                    }],
                    "retval": {
                        "type": b"v"
                    }
                },
                ismethod=False,
            ),
            "void array(const float arg0);",
        )
        self.assertEqual(
            mod.describe_callable_metadata(
                "array",
                {
                    "arguments": [{
                        "type": b"of"
                    }, {
                        "type": b"ni"
                    }],
                    "retval": {
                        "type": b"v"
                    },
                },
                ismethod=False,
            ),
            "void array(out float arg0, in int arg1);\n\n"
            "arg0: pass-by-reference out argument\n"
            "arg1: pass-by-reference in argument",
        )

        self.assertEqual(
            mod.describe_callable_metadata(
                "array:",
                {
                    "classmethod": False,
                    "arguments": [{
                        "type": b"@"
                    }, {
                        "type": b":"
                    }, {
                        "type": b"nf"
                    }],
                    "retval": {
                        "type": b"v"
                    },
                },
                ismethod=True,
            ),
            "- (void)array:(in float)arg0;\n\narg0: pass-by-reference in argument",
        )

        # - function pointers (simple and nested)
        self.assertEqual(
            mod.describe_callable_metadata(
                "function",
                {
                    "arguments": [{
                        "type": b"^?",
                        "callable": {
                            "retval": {
                                "type": b"i"
                            },
                            "arguments": []
                        },
                    }],
                    "retval": {
                        "type": b"v"
                    },
                },
                ismethod=False,
            ),
            "void function(<FUNCTION> arg0);\n\narg0: int callback(void);",
        )

        self.assertEqual(
            mod.describe_callable_metadata(
                "function",
                {
                    "arguments": [{
                        "type": b"^?",
                        "callable": {
                            "retval": {
                                "type": b"i"
                            },
                            "arguments": [{
                                "type": b"f"
                            }, {
                                "type": b"d"
                            }],
                        },
                    }],
                    "retval": {
                        "type": b"v"
                    },
                },
                ismethod=False,
            ),
            "void function(<FUNCTION> arg0);\n\narg0: int callback(float arg0, double arg1);",
        )

        self.maxDiff = None
        self.assertEqual(
            mod.describe_callable_metadata(
                "function",
                {
                    "arguments": [{
                        "type": b"^?",
                        "callable": {
                            "retval": {
                                "type": b"i"
                            },
                            "arguments": [{
                                "type": b"^?",
                                "callable": {
                                    "retval": {
                                        "type": b"d"
                                    },
                                    "arguments": [
                                        {
                                            "type": b"n@",
                                            "c_array_length_in_arg": 1,
                                        },
                                        {
                                            "type": b"@"
                                        },
                                    ],
                                },
                            }],
                        },
                    }],
                    "retval": {
                        "type": b"v"
                    },
                },
                ismethod=False,
            ),
            "void function(<FUNCTION> arg0);\n\n"
            "arg0: int callback(<FUNCTION> arg0);\n\n"
            "    arg0: double callback(in id arg0, id arg1);\n\n"
            "        arg0: array with length in arg1",
        )

        # - block pointers (simple and nested)
        self.assertEqual(
            mod.describe_callable_metadata(
                "function",
                {
                    "arguments": [{
                        "type": b"@?",
                        "callable": {
                            "retval": {
                                "type": b"i"
                            },
                            "arguments": []
                        },
                    }],
                    "retval": {
                        "type": b"v"
                    },
                },
                ismethod=False,
            ),
            "void function(<BLOCK> arg0);\n\narg0: int callback(void);",
        )

        self.assertEqual(
            mod.describe_callable_metadata(
                "performCallback:",
                {
                    "classmethod":
                    False,
                    "arguments": [
                        {
                            "type": b"@"
                        },
                        {
                            "type": b":"
                        },
                        {
                            "type": b"@?",
                            "callable": {
                                "retval": {
                                    "type": b"i"
                                },
                                "arguments": []
                            },
                        },
                    ],
                    "retval": {
                        "type": b"v"
                    },
                },
                ismethod=True,
            ),
            "- (void)performCallback:(<BLOCK>)arg0;\n\narg0: int callback(void);",
        )

        self.assertEqual(
            mod.describe_callable_metadata(
                "function",
                {
                    "arguments": [{
                        "type": b"@?",
                        "callable": {
                            "retval": {
                                "type": b"i"
                            },
                            "arguments": [{
                                "type": b"f"
                            }, {
                                "type": b"d"
                            }],
                        },
                    }],
                    "retval": {
                        "type": b"v"
                    },
                },
                ismethod=False,
            ),
            "void function(<BLOCK> arg0);\n\narg0: int callback(float arg0, double arg1);",
        )

        self.maxDiff = None
        self.assertEqual(
            mod.describe_callable_metadata(
                "function",
                {
                    "arguments": [{
                        "type": b"@?",
                        "callable": {
                            "retval": {
                                "type": b"i"
                            },
                            "arguments": [{
                                "type": b"@?",
                                "callable": {
                                    "retval": {
                                        "type": b"d"
                                    },
                                    "arguments": [
                                        {
                                            "type": b"n@",
                                            "c_array_length_in_arg": 1,
                                        },
                                        {
                                            "type": b"@"
                                        },
                                    ],
                                },
                            }],
                        },
                    }],
                    "retval": {
                        "type": b"v"
                    },
                },
                ismethod=False,
            ),
            "void function(<BLOCK> arg0);\n\n"
            "arg0: int callback(<BLOCK> arg0);\n\n"
            "    arg0: double callback(in id arg0, id arg1);\n\n"
            "        arg0: array with length in arg1",
        )

        # - variadic arguments
        self.assertEqual(
            mod.describe_callable_metadata(
                "printf",
                {
                    "variadic": True,
                    "c_array_delimited_by_null": True,
                    "arguments": [{
                        "type": b"@"
                    }],
                    "retval": {
                        "type": b"v"
                    },
                },
                ismethod=False,
            ),
            "void printf(id arg0, ...);\n\nVariadic arguments form an array of C type id",
        )
        self.assertEqual(
            mod.describe_callable_metadata(
                "printf",
                {
                    "variadic": True,
                    "c_array_delimited_by_null": True,
                    "arguments": [{
                        "type": b"@"
                    }, {
                        "type": b"i"
                    }],
                    "retval": {
                        "type": b"v"
                    },
                },
                ismethod=False,
            ),
            "void printf(id arg0, int arg1, ...);\n\n"
            "Variadic arguments form an array of C type int",
        )
        self.assertEqual(
            mod.describe_callable_metadata(
                "printf",
                {
                    "variadic": True,
                    "c_array_delimited_by_null": True,
                    "arguments": [{
                        "type": b"n@"
                    }, {
                        "type": b"i"
                    }],
                    "retval": {
                        "type": b"v"
                    },
                },
                ismethod=False,
            ),
            "void printf(in id arg0, int arg1, ...);\n\n"
            "arg0: pass-by-reference in argument\n"
            "Variadic arguments form an array of C type int",
        )

        # - printf_format
        self.assertEqual(
            mod.describe_callable_metadata(
                "printf",
                {
                    "variadic":
                    True,
                    "arguments": [{
                        "type": b"n^" + objc._C_CHAR_AS_TEXT,
                        "printf_format": True
                    }],
                    "retval": {
                        "type": b"v"
                    },
                },
                ismethod=False,
            ),
            "void printf(in char* arg0, ...);\n\narg0: %-style format string",
        )
        self.assertEqual(
            mod.describe_callable_metadata(
                "printf",
                {
                    "variadic": True,
                    "arguments": [{
                        "type": objc._C_CHARPTR,
                        "printf_format": True
                    }],
                    "retval": {
                        "type": b"i"
                    },
                },
                ismethod=False,
            ),
            "int printf(char* arg0, ...);\n\narg0: %-style format string",
        )
        self.assertEqual(
            mod.describe_callable_metadata(
                "printf:",
                {
                    "classmethod":
                    False,
                    "variadic":
                    True,
                    "arguments": [
                        {
                            "type": b"@"
                        },
                        {
                            "type": b":"
                        },
                        {
                            "type": objc._C_CHARPTR,
                            "printf_format": True
                        },
                    ],
                    "retval": {
                        "type": b"i"
                    },
                },
                ismethod=True,
            ),
            "- (int)printf:(char*)arg0, ...;\n\narg0: %-style format string",
        )

        # - description of variadic arguments
        self.assertEqual(
            mod.describe_callable_metadata(
                "array",
                {
                    "arguments": [{
                        "type": b"ni"
                    }],
                    "retval": {
                        "type": b"v"
                    }
                },
                ismethod=False,
            ),
            "void array(in int arg0);\n\narg0: pass-by-reference in argument",
        )
        self.assertEqual(
            mod.describe_callable_metadata(
                "array",
                {
                    "arguments": [{
                        "type": b"ni",
                        "c_array_length_in_arg": 2
                    }],
                    "retval": {
                        "type": b"v"
                    },
                },
                ismethod=False,
            ),
            "void array(in int arg0);\n\narg0: array with length in arg2",
        )
        self.assertEqual(
            mod.describe_callable_metadata(
                "array",
                {
                    "arguments": [{
                        "type": b"ni",
                        "c_array_length_in_arg": (2, 3)
                    }],
                    "retval": {
                        "type": b"v"
                    },
                },
                ismethod=False,
            ),
            "void array(in int arg0);\n\n"
            "arg0: array with length on input in arg2, and output in arg3",
        )
        self.assertEqual(
            mod.describe_callable_metadata(
                "array",
                {
                    "arguments": [{
                        "type": b"ni",
                        "c_array_length_in_arg": 2,
                        "c_array_length_in_result": True,
                    }],
                    "retval": {
                        "type": b"v"
                    },
                },
                ismethod=False,
            ),
            "void array(in int arg0);\n\n"
            "arg0: array with length on input in arg2, and output "
            "in return value",
        )
        self.assertEqual(
            mod.describe_callable_metadata(
                "array",
                {
                    "arguments": [{
                        "type": b"ni",
                        "c_array_length_in_result": True
                    }],
                    "retval": {
                        "type": b"v"
                    },
                },
                ismethod=False,
            ),
            "void array(in int arg0);\n\narg0: array with length in return value",
        )
        self.assertEqual(
            mod.describe_callable_metadata(
                "array",
                {
                    "arguments": [{
                        "type": b"ni",
                        "c_array_of_fixed_length": 42
                    }],
                    "retval": {
                        "type": b"v"
                    },
                },
                ismethod=False,
            ),
            "void array(in int arg0);\n\narg0: array with length 42",
        )
        self.assertEqual(
            mod.describe_callable_metadata(
                "array",
                {
                    "arguments": [{
                        "type": b"ni",
                        "c_array_of_variable_length": True
                    }],
                    "retval": {
                        "type": b"v"
                    },
                },
                ismethod=False,
            ),
            "void array(in int arg0);\n\narg0: array with unknown length",
        )
        self.assertEqual(
            mod.describe_callable_metadata(
                "array",
                {
                    "arguments": [{
                        "type": b"ni",
                        "c_array_delimited_by_null": True
                    }],
                    "retval": {
                        "type": b"v"
                    },
                },
                ismethod=False,
            ),
            "void array(in int arg0);\n\narg0: array (will be NULL terminated in C)",
        )

        self.assertEqual(
            mod.describe_callable_metadata(
                "array:",
                {
                    "classmethod":
                    False,
                    "arguments": [
                        {
                            "type": b"@"
                        },
                        {
                            "type": b":"
                        },
                        {
                            "type": b"ni",
                            "c_array_length_in_arg": 2
                        },
                    ],
                    "retval": {
                        "type": b"v"
                    },
                },
                ismethod=True,
            ),
            "- (void)array:(in int)arg0;\n\narg0: array with length in arg0",
        )
        self.assertEqual(
            mod.describe_callable_metadata(
                "array:",
                {
                    "classmethod":
                    False,
                    "arguments": [
                        {
                            "type": b"@"
                        },
                        {
                            "type": b":"
                        },
                        {
                            "type": b"ni",
                            "c_array_length_in_arg": (2, 3)
                        },
                    ],
                    "retval": {
                        "type": b"v"
                    },
                },
                ismethod=True,
            ),
            "- (void)array:(in int)arg0;\n\n"
            "arg0: array with length on input in arg0, and output in arg1",
        )
        self.assertEqual(
            mod.describe_callable_metadata(
                "array:",
                {
                    "classmethod":
                    False,
                    "arguments": [
                        {
                            "type": b"@"
                        },
                        {
                            "type": b":"
                        },
                        {
                            "type": b"ni",
                            "c_array_length_in_arg": 2,
                            "c_array_length_in_result": True,
                        },
                    ],
                    "retval": {
                        "type": b"v"
                    },
                },
                ismethod=True,
            ),
            "- (void)array:(in int)arg0;\n\n"
            "arg0: array with length on input in arg0, and "
            "output in return value",
        )

        # - warnings
        self.assertEqual(
            mod.describe_callable_metadata(
                "array",
                {
                    "arguments": [],
                    "retval": {
                        "type": b"v"
                    },
                    "suggestion": "Please don't",
                },
                ismethod=False,
            ),
            "void array(void);\n\nWARNING: Please don't",
        )
        self.assertEqual(
            mod.describe_callable_metadata(
                "array",
                {
                    "arguments": [{
                        "type": b"ni"
                    }],
                    "retval": {
                        "type": b"v"
                    },
                    "suggestion": "Please don't",
                },
                ismethod=False,
            ),
            "void array(in int arg0);\n\n"
            "WARNING: Please don't\n\n"
            "arg0: pass-by-reference in argument",
        )
Example #5
0
    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
        self.assertEqual(mod.describe_callable_metadata('array', {'arguments':[ { 'type': b'nf' } ], 'retval': { 'type': b'v'}}, ismethod=False), 'void array(in float arg0);\n\narg0: pass-by-reference in argument')
        self.assertEqual(mod.describe_callable_metadata('array', {'arguments':[ { 'type': b'Nf' } ], 'retval': { 'type': b'v'}}, ismethod=False), 'void array(inout float arg0);\n\narg0: pass-by-reference inout argument')
        self.assertEqual(mod.describe_callable_metadata('array', {'arguments':[ { 'type': b'of' } ], 'retval': { 'type': b'v'}}, ismethod=False), 'void array(out float arg0);\n\narg0: pass-by-reference out argument')
        self.assertEqual(mod.describe_callable_metadata('array', {'arguments':[ { 'type': b'rf' } ], 'retval': { 'type': b'v'}}, ismethod=False), 'void array(const float arg0);')
        self.assertEqual(mod.describe_callable_metadata('array', {'arguments':[ { 'type': b'of' }, {'type': b'ni' } ], 'retval': { 'type': b'v'}}, ismethod=False),
                'void array(out float arg0, in int arg1);\n\narg0: pass-by-reference out argument\narg1: pass-by-reference in argument')

        self.assertEqual(mod.describe_callable_metadata('array:', {'classmethod': False, 'arguments':[ { 'type': b'@' }, {'type': b':' }, { 'type': b'nf' } ], 'retval': { 'type': b'v'}}, ismethod=True),
                '- (void)array:(in float)arg0;\n\narg0: pass-by-reference in argument')

        # - function pointers (simple and nested)
        self.assertEqual(
            mod.describe_callable_metadata('function', {
                'arguments':[
                    {
                        'type': b'^?',
                        'callable': {
                            'retval': { 'type': b'i' },
                            'arguments': [],
                        }
                    }
                ], 'retval': { 'type': b'v'}}, ismethod=False
            ), 'void function(<FUNCTION> arg0);\n\narg0: int callback(void);')

        self.assertEqual(
            mod.describe_callable_metadata('function', {
                'arguments':[
                    {
                        'type': b'^?',
                        'callable': {
                            'retval': { 'type': b'i' },
                            'arguments': [
                                { 'type': b'f' },
                                { 'type': b'd' },
                            ],
                        }
                    }
                ], 'retval': { 'type': b'v'}}, ismethod=False
            ), 'void function(<FUNCTION> arg0);\n\narg0: int callback(float arg0, double arg1);')

        self.maxDiff = None
        self.assertEqual(
            mod.describe_callable_metadata('function', {
                'arguments':[
                    {
                        'type': b'^?',
                        'callable': {
                            'retval': { 'type': b'i' },
                            'arguments': [
                                { 'type': b'^?',
                                    'callable': {
                                        'retval': { 'type': b'd' },
                                        'arguments': [
                                            { 'type': b'n@', 'c_array_length_in_arg': 1 },
                                            { 'type': b'@' },
                                        ],
                                    }
                                },
                            ],
                        }
                    }
                ], 'retval': { 'type': b'v'}}, ismethod=False
            ), 'void function(<FUNCTION> arg0);\n\narg0: int callback(<FUNCTION> arg0);\n\n    arg0: double callback(in id arg0, id arg1);\n\n        arg0: array with length in arg1')

        # - block pointers (simple and nested)
        self.assertEqual(
            mod.describe_callable_metadata('function', {
                'arguments':[
                    {
                        'type': b'@?',
                        'callable': {
                            'retval': { 'type': b'i' },
                            'arguments': [],
                        }
                    }
                ], 'retval': { 'type': b'v'}}, ismethod=False
            ), 'void function(<BLOCK> arg0);\n\narg0: int callback(void);')

        self.assertEqual(
            mod.describe_callable_metadata('performCallback:', {
                'classmethod': False,
                'arguments':[
                    { 'type': b'@' },
                    { 'type': b':' },
                    {
                        'type': b'@?',
                        'callable': {
                            'retval': { 'type': b'i' },
                            'arguments': [],
                        }
                    }
                ], 'retval': { 'type': b'v'}}, ismethod=True
            ), '- (void)performCallback:(<BLOCK>)arg0;\n\narg0: int callback(void);')

        self.assertEqual(
            mod.describe_callable_metadata('function', {
                'arguments':[
                    {
                        'type': b'@?',
                        'callable': {
                            'retval': { 'type': b'i' },
                            'arguments': [
                                { 'type': b'f' },
                                { 'type': b'd' },
                            ],
                        }
                    }
                ], 'retval': { 'type': b'v'}}, ismethod=False
            ), 'void function(<BLOCK> arg0);\n\narg0: int callback(float arg0, double arg1);')

        self.maxDiff = None
        self.assertEqual(
            mod.describe_callable_metadata('function', {
                'arguments':[
                    {
                        'type': b'@?',
                        'callable': {
                            'retval': { 'type': b'i' },
                            'arguments': [
                                { 'type': b'@?',
                                    'callable': {
                                        'retval': { 'type': b'd' },
                                        'arguments': [
                                            { 'type': b'n@', 'c_array_length_in_arg': 1 },
                                            { 'type': b'@' },
                                        ],
                                    }
                                },
                            ],
                        }
                    }
                ], 'retval': { 'type': b'v'}}, ismethod=False
            ), 'void function(<BLOCK> arg0);\n\narg0: int callback(<BLOCK> arg0);\n\n    arg0: double callback(in id arg0, id arg1);\n\n        arg0: array with length in arg1')

        # - variadic arguments
        self.assertEqual(mod.describe_callable_metadata('printf', {'variadic': True, 'c_array_delimited_by_null': True, 'arguments':[ { 'type': b'@' } ], 'retval': { 'type': b'v'}}, ismethod=False),
                'void printf(id arg0, ...);\n\nVariadic arguments form an array of C type id')
        self.assertEqual(mod.describe_callable_metadata('printf', {'variadic': True, 'c_array_delimited_by_null': True, 'arguments':[ {'type': b'@' }, { 'type': b'i' } ], 'retval': { 'type': b'v'}}, ismethod=False),
                'void printf(id arg0, int arg1, ...);\n\nVariadic arguments form an array of C type int')
        self.assertEqual(mod.describe_callable_metadata('printf', {'variadic': True, 'c_array_delimited_by_null': True, 'arguments':[ {'type': b'n@' }, { 'type': b'i' } ], 'retval': { 'type': b'v'}}, ismethod=False),
                'void printf(in id arg0, int arg1, ...);\n\narg0: pass-by-reference in argument\nVariadic arguments form an array of C type int')

        # - printf_format
        self.assertEqual(mod.describe_callable_metadata('printf', {'variadic': True, 'arguments':[ { 'type': b'n^' + objc._C_CHAR_AS_TEXT, 'printf_format': True } ], 'retval': { 'type': b'v'}}, ismethod=False),
                'void printf(in char* arg0, ...);\n\narg0: %-style format string')
        self.assertEqual(mod.describe_callable_metadata('printf', {'variadic': True, 'arguments':[ { 'type': objc._C_CHARPTR, 'printf_format': True } ], 'retval': { 'type': b'i'}}, ismethod=False),
                'int printf(char* arg0, ...);\n\narg0: %-style format string')
        self.assertEqual(mod.describe_callable_metadata('printf:', {'classmethod': False, 'variadic': True, 'arguments':[ {'type': b'@'}, {'type': b':' }, { 'type': objc._C_CHARPTR, 'printf_format': True } ], 'retval': { 'type': b'i'}}, ismethod=True),
                '- (int)printf:(char*)arg0, ...;\n\narg0: %-style format string')

        # - description of variadic arguments
        self.assertEqual(mod.describe_callable_metadata('array', {'arguments':[ { 'type': b'ni' } ], 'retval': { 'type': b'v'}}, ismethod=False),
                "void array(in int arg0);\n\narg0: pass-by-reference in argument")
        self.assertEqual(mod.describe_callable_metadata('array', {'arguments':[ { 'type': b'ni', 'c_array_length_in_arg': 2 } ], 'retval': { 'type': b'v'}}, ismethod=False),
                "void array(in int arg0);\n\narg0: array with length in arg2")
        self.assertEqual(mod.describe_callable_metadata('array', {'arguments':[ { 'type': b'ni', 'c_array_length_in_arg': (2, 3) } ], 'retval': { 'type': b'v'}}, ismethod=False),
                "void array(in int arg0);\n\narg0: array with length on input in arg2, and output in arg3")
        self.assertEqual(mod.describe_callable_metadata('array', {'arguments':[ { 'type': b'ni', 'c_array_length_in_arg': 2, 'c_array_length_in_result': True } ], 'retval': { 'type': b'v'}}, ismethod=False),
                "void array(in int arg0);\n\narg0: array with length on input in arg2, and output in return value")
        self.assertEqual(mod.describe_callable_metadata('array', {'arguments':[ { 'type': b'ni', 'c_array_length_in_result': True } ], 'retval': { 'type': b'v'}}, ismethod=False),
                "void array(in int arg0);\n\narg0: array with length in return value")
        self.assertEqual(mod.describe_callable_metadata('array', {'arguments':[ { 'type': b'ni', 'c_array_of_fixed_length': 42 } ], 'retval': { 'type': b'v'}}, ismethod=False),
                "void array(in int arg0);\n\narg0: array with length 42")
        self.assertEqual(mod.describe_callable_metadata('array', {'arguments':[ { 'type': b'ni', 'c_array_of_variable_length': True } ], 'retval': { 'type': b'v'}}, ismethod=False),
                "void array(in int arg0);\n\narg0: array with unknown length")
        self.assertEqual(mod.describe_callable_metadata('array', {'arguments':[ { 'type': b'ni', 'c_array_delimited_by_null': True } ], 'retval': { 'type': b'v'}}, ismethod=False),
                "void array(in int arg0);\n\narg0: array (will be NULL terminated in C)")

        self.assertEqual(mod.describe_callable_metadata('array:', {'classmethod': False, 'arguments':[ {'type':b'@'}, {'type': b':'}, { 'type': b'ni', 'c_array_length_in_arg': 2 } ], 'retval': { 'type': b'v'}}, ismethod=True),
                "- (void)array:(in int)arg0;\n\narg0: array with length in arg0")
        self.assertEqual(mod.describe_callable_metadata('array:', {'classmethod': False, 'arguments':[ {'type':b'@'}, {'type': b':'}, { 'type': b'ni', 'c_array_length_in_arg': (2, 3) } ], 'retval': { 'type': b'v'}}, ismethod=True),
                "- (void)array:(in int)arg0;\n\narg0: array with length on input in arg0, and output in arg1")
        self.assertEqual(mod.describe_callable_metadata('array:', {'classmethod': False, 'arguments':[ {'type':b'@'}, {'type': b':'}, { 'type': b'ni', 'c_array_length_in_arg': 2, 'c_array_length_in_result': True } ], 'retval': { 'type': b'v'}}, ismethod=True),
                "- (void)array:(in int)arg0;\n\narg0: array with length on input in arg0, and output in return value")


        # - warnings
        self.assertEqual(mod.describe_callable_metadata('array', {'arguments':[], 'retval': { 'type': b'v'}, 'suggestion': "Please don't"}, ismethod=False), "void array(void);\n\nWARNING: Please don't")
        self.assertEqual(mod.describe_callable_metadata('array', {'arguments':[ { 'type': b'ni' } ], 'retval': { 'type': b'v'}, 'suggestion': "Please don't"}, ismethod=False), "void array(in int arg0);\n\nWARNING: Please don't\n\narg0: pass-by-reference in argument")