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