Home | History | Annotate | Download | only in test
      1 from ctypes import *
      2 from ctypes.test import need_symbol
      3 import 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 
     25 import _ctypes_test
     26 testdll = 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().
     31 def 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 += 1L << num_bits
     38     assert a >= 0
     39     return a
     40 
     41 def c_wbuffer(init):
     42     n = len(init) + 1
     43     return (c_wchar * n)(*init)
     44 
     45 class 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, 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         func.restype = c_long
     73         self.assertEqual(0, func(0))
     74 
     75         ci = c_int(0)
     76 
     77         func.argtypes = POINTER(c_int),
     78         self.assertEqual(positive_address(addressof(ci)),
     79                              positive_address(func(byref(ci))))
     80 
     81         func.argtypes = c_char_p,
     82         self.assertRaises(ArgumentError, func, byref(ci))
     83 
     84         func.argtypes = POINTER(c_short),
     85         self.assertRaises(ArgumentError, func, byref(ci))
     86 
     87         func.argtypes = POINTER(c_double),
     88         self.assertRaises(ArgumentError, func, byref(ci))
     89 
     90     def test_POINTER_c_char_arg(self):
     91         func = testdll._testfunc_p_p
     92         func.restype = c_char_p
     93         func.argtypes = POINTER(c_char),
     94 
     95         self.assertEqual(None, func(None))
     96         self.assertEqual("123", func("123"))
     97         self.assertEqual(None, func(c_char_p(None)))
     98         self.assertEqual("123", func(c_char_p("123")))
     99 
    100         self.assertEqual("123", func(c_buffer("123")))
    101         ca = c_char("a")
    102         self.assertEqual("a", func(pointer(ca))[0])
    103         self.assertEqual("a", func(byref(ca))[0])
    104 
    105     def test_c_char_p_arg(self):
    106         func = testdll._testfunc_p_p
    107         func.restype = c_char_p
    108         func.argtypes = c_char_p,
    109 
    110         self.assertEqual(None, func(None))
    111         self.assertEqual("123", func("123"))
    112         self.assertEqual(None, func(c_char_p(None)))
    113         self.assertEqual("123", func(c_char_p("123")))
    114 
    115         self.assertEqual("123", func(c_buffer("123")))
    116         ca = c_char("a")
    117         self.assertEqual("a", func(pointer(ca))[0])
    118         self.assertEqual("a", func(byref(ca))[0])
    119 
    120     def test_c_void_p_arg(self):
    121         func = testdll._testfunc_p_p
    122         func.restype = c_char_p
    123         func.argtypes = c_void_p,
    124 
    125         self.assertEqual(None, func(None))
    126         self.assertEqual("123", func("123"))
    127         self.assertEqual("123", func(c_char_p("123")))
    128         self.assertEqual(None, func(c_char_p(None)))
    129 
    130         self.assertEqual("123", func(c_buffer("123")))
    131         ca = c_char("a")
    132         self.assertEqual("a", func(pointer(ca))[0])
    133         self.assertEqual("a", func(byref(ca))[0])
    134 
    135         func(byref(c_int()))
    136         func(pointer(c_int()))
    137         func((c_int * 3)())
    138 
    139     @need_symbol('c_wchar_p')
    140     def test_c_void_p_arg_with_c_wchar_p(self):
    141         func = testdll._testfunc_p_p
    142         func.restype = c_wchar_p
    143         func.argtypes = c_void_p,
    144 
    145         self.assertEqual(None, func(c_wchar_p(None)))
    146         self.assertEqual(u"123", func(c_wchar_p(u"123")))
    147 
    148     def test_instance(self):
    149         func = testdll._testfunc_p_p
    150         func.restype = c_void_p
    151 
    152         class X:
    153             _as_parameter_ = None
    154 
    155         func.argtypes = c_void_p,
    156         self.assertEqual(None, func(X()))
    157 
    158         func.argtypes = None
    159         self.assertEqual(None, func(X()))
    160 
    161 @need_symbol('c_wchar')
    162 class WCharPointersTestCase(unittest.TestCase):
    163 
    164     def setUp(self):
    165         func = testdll._testfunc_p_p
    166         func.restype = c_int
    167         func.argtypes = None
    168 
    169 
    170     def test_POINTER_c_wchar_arg(self):
    171         func = testdll._testfunc_p_p
    172         func.restype = c_wchar_p
    173         func.argtypes = POINTER(c_wchar),
    174 
    175         self.assertEqual(None, func(None))
    176         self.assertEqual(u"123", func(u"123"))
    177         self.assertEqual(None, func(c_wchar_p(None)))
    178         self.assertEqual(u"123", func(c_wchar_p(u"123")))
    179 
    180         self.assertEqual(u"123", func(c_wbuffer(u"123")))
    181         ca = c_wchar("a")
    182         self.assertEqual(u"a", func(pointer(ca))[0])
    183         self.assertEqual(u"a", func(byref(ca))[0])
    184 
    185     def test_c_wchar_p_arg(self):
    186         func = testdll._testfunc_p_p
    187         func.restype = c_wchar_p
    188         func.argtypes = c_wchar_p,
    189 
    190         c_wchar_p.from_param(u"123")
    191 
    192         self.assertEqual(None, func(None))
    193         self.assertEqual("123", func(u"123"))
    194         self.assertEqual(None, func(c_wchar_p(None)))
    195         self.assertEqual("123", func(c_wchar_p("123")))
    196 
    197         # XXX Currently, these raise TypeErrors, although they shouldn't:
    198         self.assertEqual("123", func(c_wbuffer("123")))
    199         ca = c_wchar("a")
    200         self.assertEqual("a", func(pointer(ca))[0])
    201         self.assertEqual("a", func(byref(ca))[0])
    202 
    203 class ArrayTest(unittest.TestCase):
    204     def test(self):
    205         func = testdll._testfunc_ai8
    206         func.restype = POINTER(c_int)
    207         func.argtypes = c_int * 8,
    208 
    209         func((c_int * 8)(1, 2, 3, 4, 5, 6, 7, 8))
    210 
    211         # This did crash before:
    212 
    213         def func(): pass
    214         CFUNCTYPE(None, c_int * 3)(func)
    215 
    216 ################################################################
    217 
    218 if __name__ == '__main__':
    219     unittest.main()
    220