Home | History | Annotate | Download | only in test
      1 """
      2 Here is probably the place to write the docs, since the test-cases
      3 show how the type behave.
      4 
      5 Later...
      6 """
      7 
      8 from ctypes import *
      9 from ctypes.test import need_symbol
     10 import sys, unittest
     11 
     12 try:
     13     WINFUNCTYPE
     14 except NameError:
     15     # fake to enable this test on Linux
     16     WINFUNCTYPE = CFUNCTYPE
     17 
     18 import _ctypes_test
     19 dll = CDLL(_ctypes_test.__file__)
     20 if sys.platform == "win32":
     21     windll = WinDLL(_ctypes_test.__file__)
     22 
     23 class POINT(Structure):
     24     _fields_ = [("x", c_int), ("y", c_int)]
     25 class RECT(Structure):
     26     _fields_ = [("left", c_int), ("top", c_int),
     27                 ("right", c_int), ("bottom", c_int)]
     28 class FunctionTestCase(unittest.TestCase):
     29 
     30     def test_mro(self):
     31         # in Python 2.3, this raises TypeError: MRO conflict among bases classes,
     32         # in Python 2.2 it works.
     33         #
     34         # But in early versions of _ctypes.c, the result of tp_new
     35         # wasn't checked, and it even crashed Python.
     36         # Found by Greg Chapman.
     37 
     38         try:
     39             class X(object, Array):
     40                 _length_ = 5
     41                 _type_ = "i"
     42         except TypeError:
     43             pass
     44 
     45 
     46         from _ctypes import _Pointer
     47         try:
     48             class X(object, _Pointer):
     49                 pass
     50         except TypeError:
     51             pass
     52 
     53         from _ctypes import _SimpleCData
     54         try:
     55             class X(object, _SimpleCData):
     56                 _type_ = "i"
     57         except TypeError:
     58             pass
     59 
     60         try:
     61             class X(object, Structure):
     62                 _fields_ = []
     63         except TypeError:
     64             pass
     65 
     66 
     67     @need_symbol('c_wchar')
     68     def test_wchar_parm(self):
     69         f = dll._testfunc_i_bhilfd
     70         f.argtypes = [c_byte, c_wchar, c_int, c_long, c_float, c_double]
     71         result = f(1, u"x", 3, 4, 5.0, 6.0)
     72         self.assertEqual(result, 139)
     73         self.assertEqual(type(result), int)
     74 
     75     @need_symbol('c_wchar')
     76     def test_wchar_result(self):
     77         f = dll._testfunc_i_bhilfd
     78         f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double]
     79         f.restype = c_wchar
     80         result = f(0, 0, 0, 0, 0, 0)
     81         self.assertEqual(result, u'\x00')
     82 
     83     def test_voidresult(self):
     84         f = dll._testfunc_v
     85         f.restype = None
     86         f.argtypes = [c_int, c_int, POINTER(c_int)]
     87         result = c_int()
     88         self.assertEqual(None, f(1, 2, byref(result)))
     89         self.assertEqual(result.value, 3)
     90 
     91     def test_intresult(self):
     92         f = dll._testfunc_i_bhilfd
     93         f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double]
     94         f.restype = c_int
     95         result = f(1, 2, 3, 4, 5.0, 6.0)
     96         self.assertEqual(result, 21)
     97         self.assertEqual(type(result), int)
     98 
     99         result = f(-1, -2, -3, -4, -5.0, -6.0)
    100         self.assertEqual(result, -21)
    101         self.assertEqual(type(result), int)
    102 
    103         # If we declare the function to return a short,
    104         # is the high part split off?
    105         f.restype = c_short
    106         result = f(1, 2, 3, 4, 5.0, 6.0)
    107         self.assertEqual(result, 21)
    108         self.assertEqual(type(result), int)
    109 
    110         result = f(1, 2, 3, 0x10004, 5.0, 6.0)
    111         self.assertEqual(result, 21)
    112         self.assertEqual(type(result), int)
    113 
    114         # You cannot assign character format codes as restype any longer
    115         self.assertRaises(TypeError, setattr, f, "restype", "i")
    116 
    117     def test_floatresult(self):
    118         f = dll._testfunc_f_bhilfd
    119         f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double]
    120         f.restype = c_float
    121         result = f(1, 2, 3, 4, 5.0, 6.0)
    122         self.assertEqual(result, 21)
    123         self.assertEqual(type(result), float)
    124 
    125         result = f(-1, -2, -3, -4, -5.0, -6.0)
    126         self.assertEqual(result, -21)
    127         self.assertEqual(type(result), float)
    128 
    129     def test_doubleresult(self):
    130         f = dll._testfunc_d_bhilfd
    131         f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double]
    132         f.restype = c_double
    133         result = f(1, 2, 3, 4, 5.0, 6.0)
    134         self.assertEqual(result, 21)
    135         self.assertEqual(type(result), float)
    136 
    137         result = f(-1, -2, -3, -4, -5.0, -6.0)
    138         self.assertEqual(result, -21)
    139         self.assertEqual(type(result), float)
    140 
    141     def test_longdoubleresult(self):
    142         f = dll._testfunc_D_bhilfD
    143         f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_longdouble]
    144         f.restype = c_longdouble
    145         result = f(1, 2, 3, 4, 5.0, 6.0)
    146         self.assertEqual(result, 21)
    147         self.assertEqual(type(result), float)
    148 
    149         result = f(-1, -2, -3, -4, -5.0, -6.0)
    150         self.assertEqual(result, -21)
    151         self.assertEqual(type(result), float)
    152 
    153     @need_symbol('c_longlong')
    154     def test_longlongresult(self):
    155         f = dll._testfunc_q_bhilfd
    156         f.restype = c_longlong
    157         f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double]
    158         result = f(1, 2, 3, 4, 5.0, 6.0)
    159         self.assertEqual(result, 21)
    160 
    161         f = dll._testfunc_q_bhilfdq
    162         f.restype = c_longlong
    163         f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double, c_longlong]
    164         result = f(1, 2, 3, 4, 5.0, 6.0, 21)
    165         self.assertEqual(result, 42)
    166 
    167     def test_stringresult(self):
    168         f = dll._testfunc_p_p
    169         f.argtypes = None
    170         f.restype = c_char_p
    171         result = f("123")
    172         self.assertEqual(result, "123")
    173 
    174         result = f(None)
    175         self.assertEqual(result, None)
    176 
    177     def test_pointers(self):
    178         f = dll._testfunc_p_p
    179         f.restype = POINTER(c_int)
    180         f.argtypes = [POINTER(c_int)]
    181 
    182         # This only works if the value c_int(42) passed to the
    183         # function is still alive while the pointer (the result) is
    184         # used.
    185 
    186         v = c_int(42)
    187 
    188         self.assertEqual(pointer(v).contents.value, 42)
    189         result = f(pointer(v))
    190         self.assertEqual(type(result), POINTER(c_int))
    191         self.assertEqual(result.contents.value, 42)
    192 
    193         # This on works...
    194         result = f(pointer(v))
    195         self.assertEqual(result.contents.value, v.value)
    196 
    197         p = pointer(c_int(99))
    198         result = f(p)
    199         self.assertEqual(result.contents.value, 99)
    200 
    201         arg = byref(v)
    202         result = f(arg)
    203         self.assertNotEqual(result.contents, v.value)
    204 
    205         self.assertRaises(ArgumentError, f, byref(c_short(22)))
    206 
    207         # It is dangerous, however, because you don't control the lifetime
    208         # of the pointer:
    209         result = f(byref(c_int(99)))
    210         self.assertNotEqual(result.contents, 99)
    211 
    212     def test_errors(self):
    213         f = dll._testfunc_p_p
    214         f.restype = c_int
    215 
    216         class X(Structure):
    217             _fields_ = [("y", c_int)]
    218 
    219         self.assertRaises(TypeError, f, X()) #cannot convert parameter
    220 
    221     ################################################################
    222     def test_shorts(self):
    223         f = dll._testfunc_callback_i_if
    224 
    225         args = []
    226         expected = [262144, 131072, 65536, 32768, 16384, 8192, 4096, 2048,
    227                     1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1]
    228 
    229         def callback(v):
    230             args.append(v)
    231             return v
    232 
    233         CallBack = CFUNCTYPE(c_int, c_int)
    234 
    235         cb = CallBack(callback)
    236         f(2**18, cb)
    237         self.assertEqual(args, expected)
    238 
    239     ################################################################
    240 
    241 
    242     def test_callbacks(self):
    243         f = dll._testfunc_callback_i_if
    244         f.restype = c_int
    245         f.argtypes = None
    246 
    247         MyCallback = CFUNCTYPE(c_int, c_int)
    248 
    249         def callback(value):
    250             #print "called back with", value
    251             return value
    252 
    253         cb = MyCallback(callback)
    254         result = f(-10, cb)
    255         self.assertEqual(result, -18)
    256 
    257         # test with prototype
    258         f.argtypes = [c_int, MyCallback]
    259         cb = MyCallback(callback)
    260         result = f(-10, cb)
    261         self.assertEqual(result, -18)
    262 
    263         AnotherCallback = WINFUNCTYPE(c_int, c_int, c_int, c_int, c_int)
    264 
    265         # check that the prototype works: we call f with wrong
    266         # argument types
    267         cb = AnotherCallback(callback)
    268         self.assertRaises(ArgumentError, f, -10, cb)
    269 
    270 
    271     def test_callbacks_2(self):
    272         # Can also use simple datatypes as argument type specifiers
    273         # for the callback function.
    274         # In this case the call receives an instance of that type
    275         f = dll._testfunc_callback_i_if
    276         f.restype = c_int
    277 
    278         MyCallback = CFUNCTYPE(c_int, c_int)
    279 
    280         f.argtypes = [c_int, MyCallback]
    281 
    282         def callback(value):
    283             #print "called back with", value
    284             self.assertEqual(type(value), int)
    285             return value
    286 
    287         cb = MyCallback(callback)
    288         result = f(-10, cb)
    289         self.assertEqual(result, -18)
    290 
    291     @need_symbol('c_longlong')
    292     def test_longlong_callbacks(self):
    293 
    294         f = dll._testfunc_callback_q_qf
    295         f.restype = c_longlong
    296 
    297         MyCallback = CFUNCTYPE(c_longlong, c_longlong)
    298 
    299         f.argtypes = [c_longlong, MyCallback]
    300 
    301         def callback(value):
    302             self.assertIsInstance(value, (int, long))
    303             return value & 0x7FFFFFFF
    304 
    305         cb = MyCallback(callback)
    306 
    307         self.assertEqual(13577625587, f(1000000000000, cb))
    308 
    309     def test_errors(self):
    310         self.assertRaises(AttributeError, getattr, dll, "_xxx_yyy")
    311         self.assertRaises(ValueError, c_int.in_dll, dll, "_xxx_yyy")
    312 
    313     def test_byval(self):
    314 
    315         # without prototype
    316         ptin = POINT(1, 2)
    317         ptout = POINT()
    318         # EXPORT int _testfunc_byval(point in, point *pout)
    319         result = dll._testfunc_byval(ptin, byref(ptout))
    320         got = result, ptout.x, ptout.y
    321         expected = 3, 1, 2
    322         self.assertEqual(got, expected)
    323 
    324         # with prototype
    325         ptin = POINT(101, 102)
    326         ptout = POINT()
    327         dll._testfunc_byval.argtypes = (POINT, POINTER(POINT))
    328         dll._testfunc_byval.restype = c_int
    329         result = dll._testfunc_byval(ptin, byref(ptout))
    330         got = result, ptout.x, ptout.y
    331         expected = 203, 101, 102
    332         self.assertEqual(got, expected)
    333 
    334     def test_struct_return_2H(self):
    335         class S2H(Structure):
    336             _fields_ = [("x", c_short),
    337                         ("y", c_short)]
    338         dll.ret_2h_func.restype = S2H
    339         dll.ret_2h_func.argtypes = [S2H]
    340         inp = S2H(99, 88)
    341         s2h = dll.ret_2h_func(inp)
    342         self.assertEqual((s2h.x, s2h.y), (99*2, 88*3))
    343 
    344     @unittest.skipUnless(sys.platform == "win32", 'Windows-specific test')
    345     def test_struct_return_2H_stdcall(self):
    346         class S2H(Structure):
    347             _fields_ = [("x", c_short),
    348                         ("y", c_short)]
    349 
    350         windll.s_ret_2h_func.restype = S2H
    351         windll.s_ret_2h_func.argtypes = [S2H]
    352         s2h = windll.s_ret_2h_func(S2H(99, 88))
    353         self.assertEqual((s2h.x, s2h.y), (99*2, 88*3))
    354 
    355     def test_struct_return_8H(self):
    356         class S8I(Structure):
    357             _fields_ = [("a", c_int),
    358                         ("b", c_int),
    359                         ("c", c_int),
    360                         ("d", c_int),
    361                         ("e", c_int),
    362                         ("f", c_int),
    363                         ("g", c_int),
    364                         ("h", c_int)]
    365         dll.ret_8i_func.restype = S8I
    366         dll.ret_8i_func.argtypes = [S8I]
    367         inp = S8I(9, 8, 7, 6, 5, 4, 3, 2)
    368         s8i = dll.ret_8i_func(inp)
    369         self.assertEqual((s8i.a, s8i.b, s8i.c, s8i.d, s8i.e, s8i.f, s8i.g, s8i.h),
    370                              (9*2, 8*3, 7*4, 6*5, 5*6, 4*7, 3*8, 2*9))
    371 
    372     @unittest.skipUnless(sys.platform == "win32", 'Windows-specific test')
    373     def test_struct_return_8H_stdcall(self):
    374         class S8I(Structure):
    375             _fields_ = [("a", c_int),
    376                         ("b", c_int),
    377                         ("c", c_int),
    378                         ("d", c_int),
    379                         ("e", c_int),
    380                         ("f", c_int),
    381                         ("g", c_int),
    382                         ("h", c_int)]
    383         windll.s_ret_8i_func.restype = S8I
    384         windll.s_ret_8i_func.argtypes = [S8I]
    385         inp = S8I(9, 8, 7, 6, 5, 4, 3, 2)
    386         s8i = windll.s_ret_8i_func(inp)
    387         self.assertEqual(
    388                 (s8i.a, s8i.b, s8i.c, s8i.d, s8i.e, s8i.f, s8i.g, s8i.h),
    389                 (9*2, 8*3, 7*4, 6*5, 5*6, 4*7, 3*8, 2*9))
    390 
    391     def test_sf1651235(self):
    392         # see http://www.python.org/sf/1651235
    393 
    394         proto = CFUNCTYPE(c_int, RECT, POINT)
    395         def callback(*args):
    396             return 0
    397 
    398         callback = proto(callback)
    399         self.assertRaises(ArgumentError, lambda: callback((1, 2, 3, 4), POINT()))
    400 
    401 if __name__ == '__main__':
    402     unittest.main()
    403