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 += 1 << 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 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')
    165 class 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 
    206 class 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 
    221 if __name__ == '__main__':
    222     unittest.main()
    223