PageRenderTime 90ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/python/lib/python2.7/ctypes/test/test_callbacks.py

https://bitbucket.org/lbesson/web-sphinx-scripts
Python | 248 lines | 165 code | 53 blank | 30 comment | 16 complexity | 1c8a4dabdbae23cf9c2927c06b8c9df4 MD5 | raw file
  1. import unittest
  2. from ctypes import *
  3. import _ctypes_test
  4. class Callbacks(unittest.TestCase):
  5. functype = CFUNCTYPE
  6. ## def tearDown(self):
  7. ## import gc
  8. ## gc.collect()
  9. def callback(self, *args):
  10. self.got_args = args
  11. return args[-1]
  12. def check_type(self, typ, arg):
  13. PROTO = self.functype.im_func(typ, typ)
  14. result = PROTO(self.callback)(arg)
  15. if typ == c_float:
  16. self.assertAlmostEqual(result, arg, places=5)
  17. else:
  18. self.assertEqual(self.got_args, (arg,))
  19. self.assertEqual(result, arg)
  20. PROTO = self.functype.im_func(typ, c_byte, typ)
  21. result = PROTO(self.callback)(-3, arg)
  22. if typ == c_float:
  23. self.assertAlmostEqual(result, arg, places=5)
  24. else:
  25. self.assertEqual(self.got_args, (-3, arg))
  26. self.assertEqual(result, arg)
  27. ################
  28. def test_byte(self):
  29. self.check_type(c_byte, 42)
  30. self.check_type(c_byte, -42)
  31. def test_ubyte(self):
  32. self.check_type(c_ubyte, 42)
  33. def test_short(self):
  34. self.check_type(c_short, 42)
  35. self.check_type(c_short, -42)
  36. def test_ushort(self):
  37. self.check_type(c_ushort, 42)
  38. def test_int(self):
  39. self.check_type(c_int, 42)
  40. self.check_type(c_int, -42)
  41. def test_uint(self):
  42. self.check_type(c_uint, 42)
  43. def test_long(self):
  44. self.check_type(c_long, 42)
  45. self.check_type(c_long, -42)
  46. def test_ulong(self):
  47. self.check_type(c_ulong, 42)
  48. def test_longlong(self):
  49. # test some 64-bit values, positive and negative
  50. self.check_type(c_longlong, 5948291757245277467)
  51. self.check_type(c_longlong, -5229388909784190580)
  52. self.check_type(c_longlong, 42)
  53. self.check_type(c_longlong, -42)
  54. def test_ulonglong(self):
  55. # test some 64-bit values, with and without msb set.
  56. self.check_type(c_ulonglong, 10955412242170339782)
  57. self.check_type(c_ulonglong, 3665885499841167458)
  58. self.check_type(c_ulonglong, 42)
  59. def test_float(self):
  60. # only almost equal: double -> float -> double
  61. import math
  62. self.check_type(c_float, math.e)
  63. self.check_type(c_float, -math.e)
  64. def test_double(self):
  65. self.check_type(c_double, 3.14)
  66. self.check_type(c_double, -3.14)
  67. def test_longdouble(self):
  68. self.check_type(c_longdouble, 3.14)
  69. self.check_type(c_longdouble, -3.14)
  70. def test_char(self):
  71. self.check_type(c_char, "x")
  72. self.check_type(c_char, "a")
  73. # disabled: would now (correctly) raise a RuntimeWarning about
  74. # a memory leak. A callback function cannot return a non-integral
  75. # C type without causing a memory leak.
  76. ## def test_char_p(self):
  77. ## self.check_type(c_char_p, "abc")
  78. ## self.check_type(c_char_p, "def")
  79. def test_pyobject(self):
  80. o = ()
  81. from sys import getrefcount as grc
  82. for o in (), [], object():
  83. initial = grc(o)
  84. # This call leaks a reference to 'o'...
  85. self.check_type(py_object, o)
  86. before = grc(o)
  87. # ...but this call doesn't leak any more. Where is the refcount?
  88. self.check_type(py_object, o)
  89. after = grc(o)
  90. self.assertEqual((after, o), (before, o))
  91. def test_unsupported_restype_1(self):
  92. # Only "fundamental" result types are supported for callback
  93. # functions, the type must have a non-NULL stgdict->setfunc.
  94. # POINTER(c_double), for example, is not supported.
  95. prototype = self.functype.im_func(POINTER(c_double))
  96. # The type is checked when the prototype is called
  97. self.assertRaises(TypeError, prototype, lambda: None)
  98. def test_unsupported_restype_2(self):
  99. prototype = self.functype.im_func(object)
  100. self.assertRaises(TypeError, prototype, lambda: None)
  101. def test_issue_7959(self):
  102. proto = self.functype.im_func(None)
  103. class X(object):
  104. def func(self): pass
  105. def __init__(self):
  106. self.v = proto(self.func)
  107. import gc
  108. for i in range(32):
  109. X()
  110. gc.collect()
  111. live = [x for x in gc.get_objects()
  112. if isinstance(x, X)]
  113. self.assertEqual(len(live), 0)
  114. try:
  115. WINFUNCTYPE
  116. except NameError:
  117. pass
  118. else:
  119. class StdcallCallbacks(Callbacks):
  120. functype = WINFUNCTYPE
  121. ################################################################
  122. class SampleCallbacksTestCase(unittest.TestCase):
  123. def test_integrate(self):
  124. # Derived from some then non-working code, posted by David Foster
  125. dll = CDLL(_ctypes_test.__file__)
  126. # The function prototype called by 'integrate': double func(double);
  127. CALLBACK = CFUNCTYPE(c_double, c_double)
  128. # The integrate function itself, exposed from the _ctypes_test dll
  129. integrate = dll.integrate
  130. integrate.argtypes = (c_double, c_double, CALLBACK, c_long)
  131. integrate.restype = c_double
  132. def func(x):
  133. return x**2
  134. result = integrate(0.0, 1.0, CALLBACK(func), 10)
  135. diff = abs(result - 1./3.)
  136. self.assertLess(diff, 0.01, "%s not less than 0.01" % diff)
  137. def test_issue_8959_a(self):
  138. from ctypes.util import find_library
  139. libc_path = find_library("c")
  140. if not libc_path:
  141. return # cannot test
  142. libc = CDLL(libc_path)
  143. @CFUNCTYPE(c_int, POINTER(c_int), POINTER(c_int))
  144. def cmp_func(a, b):
  145. return a[0] - b[0]
  146. array = (c_int * 5)(5, 1, 99, 7, 33)
  147. libc.qsort(array, len(array), sizeof(c_int), cmp_func)
  148. self.assertEqual(array[:], [1, 5, 7, 33, 99])
  149. try:
  150. WINFUNCTYPE
  151. except NameError:
  152. pass
  153. else:
  154. def test_issue_8959_b(self):
  155. from ctypes.wintypes import BOOL, HWND, LPARAM
  156. global windowCount
  157. windowCount = 0
  158. @WINFUNCTYPE(BOOL, HWND, LPARAM)
  159. def EnumWindowsCallbackFunc(hwnd, lParam):
  160. global windowCount
  161. windowCount += 1
  162. return True #Allow windows to keep enumerating
  163. windll.user32.EnumWindows(EnumWindowsCallbackFunc, 0)
  164. def test_callback_register_int(self):
  165. # Issue #8275: buggy handling of callback args under Win64
  166. # NOTE: should be run on release builds as well
  167. dll = CDLL(_ctypes_test.__file__)
  168. CALLBACK = CFUNCTYPE(c_int, c_int, c_int, c_int, c_int, c_int)
  169. # All this function does is call the callback with its args squared
  170. func = dll._testfunc_cbk_reg_int
  171. func.argtypes = (c_int, c_int, c_int, c_int, c_int, CALLBACK)
  172. func.restype = c_int
  173. def callback(a, b, c, d, e):
  174. return a + b + c + d + e
  175. result = func(2, 3, 4, 5, 6, CALLBACK(callback))
  176. self.assertEqual(result, callback(2*2, 3*3, 4*4, 5*5, 6*6))
  177. def test_callback_register_double(self):
  178. # Issue #8275: buggy handling of callback args under Win64
  179. # NOTE: should be run on release builds as well
  180. dll = CDLL(_ctypes_test.__file__)
  181. CALLBACK = CFUNCTYPE(c_double, c_double, c_double, c_double,
  182. c_double, c_double)
  183. # All this function does is call the callback with its args squared
  184. func = dll._testfunc_cbk_reg_double
  185. func.argtypes = (c_double, c_double, c_double,
  186. c_double, c_double, CALLBACK)
  187. func.restype = c_double
  188. def callback(a, b, c, d, e):
  189. return a + b + c + d + e
  190. result = func(1.1, 2.2, 3.3, 4.4, 5.5, CALLBACK(callback))
  191. self.assertEqual(result,
  192. callback(1.1*1.1, 2.2*2.2, 3.3*3.3, 4.4*4.4, 5.5*5.5))
  193. ################################################################
  194. if __name__ == '__main__':
  195. unittest.main()