• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1from ctypes import *
2from ctypes.test import need_symbol
3import unittest
4
5# IMPORTANT INFO:
6#
7# Consider this call:
8#    func.restype = c_char_p
9#    func(c_char_p("123"))
10# It returns
11#    "123"
12#
13# WHY IS THIS SO?
14#
15# argument tuple (c_char_p("123"), ) is destroyed after the function
16# func is called, but NOT before the result is actually built.
17#
18# If the arglist would be destroyed BEFORE the result has been built,
19# the c_char_p("123") object would already have a zero refcount,
20# and the pointer passed to (and returned by) the function would
21# probably point to deallocated space.
22#
23# In this case, there would have to be an additional reference to the argument...
24
25import _ctypes_test
26testdll = CDLL(_ctypes_test.__file__)
27
28# Return machine address `a` as a (possibly long) non-negative integer.
29# Starting with Python 2.5, id(anything) is always non-negative, and
30# the ctypes addressof() inherits that via PyLong_FromVoidPtr().
31def positive_address(a):
32    if a >= 0:
33        return a
34    # View the bits in `a` as unsigned instead.
35    import struct
36    num_bits = struct.calcsize("P") * 8 # num bits in native machine address
37    a += 1 << num_bits
38    assert a >= 0
39    return a
40
41def c_wbuffer(init):
42    n = len(init) + 1
43    return (c_wchar * n)(*init)
44
45class CharPointersTestCase(unittest.TestCase):
46
47    def setUp(self):
48        func = testdll._testfunc_p_p
49        func.restype = c_long
50        func.argtypes = None
51
52    def test_paramflags(self):
53        # function returns c_void_p result,
54        # and has a required parameter named 'input'
55        prototype = CFUNCTYPE(c_void_p, c_void_p)
56        func = prototype(("_testfunc_p_p", testdll),
57                         ((1, "input"),))
58
59        try:
60            func()
61        except TypeError as details:
62            self.assertEqual(str(details), "required argument 'input' missing")
63        else:
64            self.fail("TypeError not raised")
65
66        self.assertEqual(func(None), None)
67        self.assertEqual(func(input=None), None)
68
69
70    def test_int_pointer_arg(self):
71        func = testdll._testfunc_p_p
72        if sizeof(c_longlong) == sizeof(c_void_p):
73            func.restype = c_longlong
74        else:
75            func.restype = c_long
76        self.assertEqual(0, func(0))
77
78        ci = c_int(0)
79
80        func.argtypes = POINTER(c_int),
81        self.assertEqual(positive_address(addressof(ci)),
82                             positive_address(func(byref(ci))))
83
84        func.argtypes = c_char_p,
85        self.assertRaises(ArgumentError, func, byref(ci))
86
87        func.argtypes = POINTER(c_short),
88        self.assertRaises(ArgumentError, func, byref(ci))
89
90        func.argtypes = POINTER(c_double),
91        self.assertRaises(ArgumentError, func, byref(ci))
92
93    def test_POINTER_c_char_arg(self):
94        func = testdll._testfunc_p_p
95        func.restype = c_char_p
96        func.argtypes = POINTER(c_char),
97
98        self.assertEqual(None, func(None))
99        self.assertEqual(b"123", func(b"123"))
100        self.assertEqual(None, func(c_char_p(None)))
101        self.assertEqual(b"123", func(c_char_p(b"123")))
102
103        self.assertEqual(b"123", func(c_buffer(b"123")))
104        ca = c_char(b"a")
105        self.assertEqual(ord(b"a"), func(pointer(ca))[0])
106        self.assertEqual(ord(b"a"), func(byref(ca))[0])
107
108    def test_c_char_p_arg(self):
109        func = testdll._testfunc_p_p
110        func.restype = c_char_p
111        func.argtypes = c_char_p,
112
113        self.assertEqual(None, func(None))
114        self.assertEqual(b"123", func(b"123"))
115        self.assertEqual(None, func(c_char_p(None)))
116        self.assertEqual(b"123", func(c_char_p(b"123")))
117
118        self.assertEqual(b"123", func(c_buffer(b"123")))
119        ca = c_char(b"a")
120        self.assertEqual(ord(b"a"), func(pointer(ca))[0])
121        self.assertEqual(ord(b"a"), func(byref(ca))[0])
122
123    def test_c_void_p_arg(self):
124        func = testdll._testfunc_p_p
125        func.restype = c_char_p
126        func.argtypes = c_void_p,
127
128        self.assertEqual(None, func(None))
129        self.assertEqual(b"123", func(b"123"))
130        self.assertEqual(b"123", func(c_char_p(b"123")))
131        self.assertEqual(None, func(c_char_p(None)))
132
133        self.assertEqual(b"123", func(c_buffer(b"123")))
134        ca = c_char(b"a")
135        self.assertEqual(ord(b"a"), func(pointer(ca))[0])
136        self.assertEqual(ord(b"a"), func(byref(ca))[0])
137
138        func(byref(c_int()))
139        func(pointer(c_int()))
140        func((c_int * 3)())
141
142    @need_symbol('c_wchar_p')
143    def test_c_void_p_arg_with_c_wchar_p(self):
144        func = testdll._testfunc_p_p
145        func.restype = c_wchar_p
146        func.argtypes = c_void_p,
147
148        self.assertEqual(None, func(c_wchar_p(None)))
149        self.assertEqual("123", func(c_wchar_p("123")))
150
151    def test_instance(self):
152        func = testdll._testfunc_p_p
153        func.restype = c_void_p
154
155        class X:
156            _as_parameter_ = None
157
158        func.argtypes = c_void_p,
159        self.assertEqual(None, func(X()))
160
161        func.argtypes = None
162        self.assertEqual(None, func(X()))
163
164@need_symbol('c_wchar')
165class WCharPointersTestCase(unittest.TestCase):
166
167    def setUp(self):
168        func = testdll._testfunc_p_p
169        func.restype = c_int
170        func.argtypes = None
171
172
173    def test_POINTER_c_wchar_arg(self):
174        func = testdll._testfunc_p_p
175        func.restype = c_wchar_p
176        func.argtypes = POINTER(c_wchar),
177
178        self.assertEqual(None, func(None))
179        self.assertEqual("123", func("123"))
180        self.assertEqual(None, func(c_wchar_p(None)))
181        self.assertEqual("123", func(c_wchar_p("123")))
182
183        self.assertEqual("123", func(c_wbuffer("123")))
184        ca = c_wchar("a")
185        self.assertEqual("a", func(pointer(ca))[0])
186        self.assertEqual("a", func(byref(ca))[0])
187
188    def test_c_wchar_p_arg(self):
189        func = testdll._testfunc_p_p
190        func.restype = c_wchar_p
191        func.argtypes = c_wchar_p,
192
193        c_wchar_p.from_param("123")
194
195        self.assertEqual(None, func(None))
196        self.assertEqual("123", func("123"))
197        self.assertEqual(None, func(c_wchar_p(None)))
198        self.assertEqual("123", func(c_wchar_p("123")))
199
200        # XXX Currently, these raise TypeErrors, although they shouldn't:
201        self.assertEqual("123", func(c_wbuffer("123")))
202        ca = c_wchar("a")
203        self.assertEqual("a", func(pointer(ca))[0])
204        self.assertEqual("a", func(byref(ca))[0])
205
206class ArrayTest(unittest.TestCase):
207    def test(self):
208        func = testdll._testfunc_ai8
209        func.restype = POINTER(c_int)
210        func.argtypes = c_int * 8,
211
212        func((c_int * 8)(1, 2, 3, 4, 5, 6, 7, 8))
213
214        # This did crash before:
215
216        def func(): pass
217        CFUNCTYPE(None, c_int * 3)(func)
218
219################################################################
220
221if __name__ == '__main__':
222    unittest.main()
223