1 from ctypes import * 2 import unittest, sys 3 4 def callback_func(arg): 5 42 // arg 6 raise ValueError(arg) 7 8 @unittest.skipUnless(sys.platform == "win32", 'Windows-specific test') 9 class call_function_TestCase(unittest.TestCase): 10 # _ctypes.call_function is deprecated and private, but used by 11 # Gary Bishp's readline module. If we have it, we must test it as well. 12 13 def test(self): 14 from _ctypes import call_function 15 windll.kernel32.LoadLibraryA.restype = c_void_p 16 windll.kernel32.GetProcAddress.argtypes = c_void_p, c_char_p 17 windll.kernel32.GetProcAddress.restype = c_void_p 18 19 hdll = windll.kernel32.LoadLibraryA("kernel32") 20 funcaddr = windll.kernel32.GetProcAddress(hdll, "GetModuleHandleA") 21 22 self.assertEqual(call_function(funcaddr, (None,)), 23 windll.kernel32.GetModuleHandleA(None)) 24 25 class CallbackTracbackTestCase(unittest.TestCase): 26 # When an exception is raised in a ctypes callback function, the C 27 # code prints a traceback. 28 # 29 # This test makes sure the exception types *and* the exception 30 # value is printed correctly. 31 # 32 # Changed in 0.9.3: No longer is '(in callback)' prepended to the 33 # error message - instead an additional frame for the C code is 34 # created, then a full traceback printed. When SystemExit is 35 # raised in a callback function, the interpreter exits. 36 37 def capture_stderr(self, func, *args, **kw): 38 # helper - call function 'func', and return the captured stderr 39 import StringIO 40 old_stderr = sys.stderr 41 logger = sys.stderr = StringIO.StringIO() 42 try: 43 func(*args, **kw) 44 finally: 45 sys.stderr = old_stderr 46 return logger.getvalue() 47 48 def test_ValueError(self): 49 cb = CFUNCTYPE(c_int, c_int)(callback_func) 50 out = self.capture_stderr(cb, 42) 51 self.assertEqual(out.splitlines()[-1], 52 "ValueError: 42") 53 54 def test_IntegerDivisionError(self): 55 cb = CFUNCTYPE(c_int, c_int)(callback_func) 56 out = self.capture_stderr(cb, 0) 57 self.assertEqual(out.splitlines()[-1][:19], 58 "ZeroDivisionError: ") 59 60 def test_FloatDivisionError(self): 61 cb = CFUNCTYPE(c_int, c_double)(callback_func) 62 out = self.capture_stderr(cb, 0.0) 63 self.assertEqual(out.splitlines()[-1][:19], 64 "ZeroDivisionError: ") 65 66 def test_TypeErrorDivisionError(self): 67 cb = CFUNCTYPE(c_int, c_char_p)(callback_func) 68 out = self.capture_stderr(cb, "spam") 69 self.assertEqual(out.splitlines()[-1], 70 "TypeError: " 71 "unsupported operand type(s) for //: 'int' and 'str'") 72 73 if __name__ == '__main__': 74 unittest.main() 75