1import unittest
2from ctypes import *
3import os
4
5import _ctypes_test
6
7class ReturnFuncPtrTestCase(unittest.TestCase):
8
9    def test_with_prototype(self):
10        # The _ctypes_test shared lib/dll exports quite some functions for testing.
11        # The get_strchr function returns a *pointer* to the C strchr function.
12        dll = CDLL(_ctypes_test.__file__)
13        get_strchr = dll.get_strchr
14        get_strchr.restype = CFUNCTYPE(c_char_p, c_char_p, c_char)
15        strchr = get_strchr()
16        self.assertEqual(strchr("abcdef", "b"), "bcdef")
17        self.assertEqual(strchr("abcdef", "x"), None)
18        self.assertRaises(ArgumentError, strchr, "abcdef", 3)
19        self.assertRaises(TypeError, strchr, "abcdef")
20
21    def test_without_prototype(self):
22        dll = CDLL(_ctypes_test.__file__)
23        get_strchr = dll.get_strchr
24        # the default 'c_int' would not work on systems where sizeof(int) != sizeof(void *)
25        get_strchr.restype = c_void_p
26        addr = get_strchr()
27        # _CFuncPtr instances are now callable with an integer argument
28        # which denotes a function address:
29        strchr = CFUNCTYPE(c_char_p, c_char_p, c_char)(addr)
30        self.assertTrue(strchr("abcdef", "b"), "bcdef")
31        self.assertEqual(strchr("abcdef", "x"), None)
32        self.assertRaises(ArgumentError, strchr, "abcdef", 3)
33        self.assertRaises(TypeError, strchr, "abcdef")
34
35    def test_from_dll(self):
36        dll = CDLL(_ctypes_test.__file__)
37        # _CFuncPtr instances are now callable with a tuple argument
38        # which denotes a function name and a dll:
39        strchr = CFUNCTYPE(c_char_p, c_char_p, c_char)(("my_strchr", dll))
40        self.assertTrue(strchr(b"abcdef", b"b"), "bcdef")
41        self.assertEqual(strchr(b"abcdef", b"x"), None)
42        self.assertRaises(ArgumentError, strchr, b"abcdef", 3.0)
43        self.assertRaises(TypeError, strchr, b"abcdef")
44
45    # Issue 6083: Reference counting bug
46    def test_from_dll_refcount(self):
47        class BadSequence(tuple):
48            def __getitem__(self, key):
49                if key == 0:
50                    return "my_strchr"
51                if key == 1:
52                    return CDLL(_ctypes_test.__file__)
53                raise IndexError
54
55        # _CFuncPtr instances are now callable with a tuple argument
56        # which denotes a function name and a dll:
57        strchr = CFUNCTYPE(c_char_p, c_char_p, c_char)(
58                BadSequence(("my_strchr", CDLL(_ctypes_test.__file__))))
59        self.assertTrue(strchr(b"abcdef", b"b"), "bcdef")
60        self.assertEqual(strchr(b"abcdef", b"x"), None)
61        self.assertRaises(ArgumentError, strchr, b"abcdef", 3.0)
62        self.assertRaises(TypeError, strchr, b"abcdef")
63
64if __name__ == "__main__":
65    unittest.main()
66