/Lib/ctypes/test/test_funcptr.py

http://unladen-swallow.googlecode.com/ · Python · 127 lines · 80 code · 31 blank · 16 comment · 6 complexity · 910303d64b2b5585e8ede93434ff7ef6 MD5 · raw file

  1. import os, unittest
  2. from ctypes import *
  3. try:
  4. WINFUNCTYPE
  5. except NameError:
  6. # fake to enable this test on Linux
  7. WINFUNCTYPE = CFUNCTYPE
  8. import _ctypes_test
  9. lib = CDLL(_ctypes_test.__file__)
  10. class CFuncPtrTestCase(unittest.TestCase):
  11. def test_basic(self):
  12. X = WINFUNCTYPE(c_int, c_int, c_int)
  13. def func(*args):
  14. return len(args)
  15. x = X(func)
  16. self.failUnlessEqual(x.restype, c_int)
  17. self.failUnlessEqual(x.argtypes, (c_int, c_int))
  18. self.failUnlessEqual(sizeof(x), sizeof(c_voidp))
  19. self.failUnlessEqual(sizeof(X), sizeof(c_voidp))
  20. def test_first(self):
  21. StdCallback = WINFUNCTYPE(c_int, c_int, c_int)
  22. CdeclCallback = CFUNCTYPE(c_int, c_int, c_int)
  23. def func(a, b):
  24. return a + b
  25. s = StdCallback(func)
  26. c = CdeclCallback(func)
  27. self.failUnlessEqual(s(1, 2), 3)
  28. self.failUnlessEqual(c(1, 2), 3)
  29. # The following no longer raises a TypeError - it is now
  30. # possible, as in C, to call cdecl functions with more parameters.
  31. #self.assertRaises(TypeError, c, 1, 2, 3)
  32. self.failUnlessEqual(c(1, 2, 3, 4, 5, 6), 3)
  33. if not WINFUNCTYPE is CFUNCTYPE and os.name != "ce":
  34. self.assertRaises(TypeError, s, 1, 2, 3)
  35. def test_structures(self):
  36. WNDPROC = WINFUNCTYPE(c_long, c_int, c_int, c_int, c_int)
  37. def wndproc(hwnd, msg, wParam, lParam):
  38. return hwnd + msg + wParam + lParam
  39. HINSTANCE = c_int
  40. HICON = c_int
  41. HCURSOR = c_int
  42. LPCTSTR = c_char_p
  43. class WNDCLASS(Structure):
  44. _fields_ = [("style", c_uint),
  45. ("lpfnWndProc", WNDPROC),
  46. ("cbClsExtra", c_int),
  47. ("cbWndExtra", c_int),
  48. ("hInstance", HINSTANCE),
  49. ("hIcon", HICON),
  50. ("hCursor", HCURSOR),
  51. ("lpszMenuName", LPCTSTR),
  52. ("lpszClassName", LPCTSTR)]
  53. wndclass = WNDCLASS()
  54. wndclass.lpfnWndProc = WNDPROC(wndproc)
  55. WNDPROC_2 = WINFUNCTYPE(c_long, c_int, c_int, c_int, c_int)
  56. # This is no longer true, now that WINFUNCTYPE caches created types internally.
  57. ## # CFuncPtr subclasses are compared by identity, so this raises a TypeError:
  58. ## self.assertRaises(TypeError, setattr, wndclass,
  59. ## "lpfnWndProc", WNDPROC_2(wndproc))
  60. # instead:
  61. self.failUnless(WNDPROC is WNDPROC_2)
  62. # 'wndclass.lpfnWndProc' leaks 94 references. Why?
  63. self.failUnlessEqual(wndclass.lpfnWndProc(1, 2, 3, 4), 10)
  64. f = wndclass.lpfnWndProc
  65. del wndclass
  66. del wndproc
  67. self.failUnlessEqual(f(10, 11, 12, 13), 46)
  68. def test_dllfunctions(self):
  69. def NoNullHandle(value):
  70. if not value:
  71. raise WinError()
  72. return value
  73. strchr = lib.my_strchr
  74. strchr.restype = c_char_p
  75. strchr.argtypes = (c_char_p, c_char)
  76. self.failUnlessEqual(strchr("abcdefghi", "b"), "bcdefghi")
  77. self.failUnlessEqual(strchr("abcdefghi", "x"), None)
  78. strtok = lib.my_strtok
  79. strtok.restype = c_char_p
  80. # Neither of this does work: strtok changes the buffer it is passed
  81. ## strtok.argtypes = (c_char_p, c_char_p)
  82. ## strtok.argtypes = (c_string, c_char_p)
  83. def c_string(init):
  84. size = len(init) + 1
  85. return (c_char*size)(*init)
  86. s = "a\nb\nc"
  87. b = c_string(s)
  88. ## b = (c_char * (len(s)+1))()
  89. ## b.value = s
  90. ## b = c_string(s)
  91. self.failUnlessEqual(strtok(b, "\n"), "a")
  92. self.failUnlessEqual(strtok(None, "\n"), "b")
  93. self.failUnlessEqual(strtok(None, "\n"), "c")
  94. self.failUnlessEqual(strtok(None, "\n"), None)
  95. if __name__ == '__main__':
  96. unittest.main()