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