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