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