Home | History | Annotate | Download | only in test
      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()
     76