| 1 | """Testing tools for byterun."""
 | 
| 2 | 
 | 
| 3 | from __future__ import print_function
 | 
| 4 | 
 | 
| 5 | import cStringIO
 | 
| 6 | import sys
 | 
| 7 | import textwrap
 | 
| 8 | import types
 | 
| 9 | import unittest
 | 
| 10 | 
 | 
| 11 | 
 | 
| 12 | from opy.lib import dis
 | 
| 13 | import pyvm2
 | 
| 14 | 
 | 
| 15 | # Make this false if you need to run the debugger inside a test.
 | 
| 16 | CAPTURE_STDOUT = ('-s' not in sys.argv)
 | 
| 17 | # Make this false to see the traceback from a failure inside pyvm2.
 | 
| 18 | CAPTURE_EXCEPTION = 1
 | 
| 19 | 
 | 
| 20 | 
 | 
| 21 | def dis_code(code):
 | 
| 22 |     """Disassemble `code` and all the code it refers to."""
 | 
| 23 |     return
 | 
| 24 |     for const in code.co_consts:
 | 
| 25 |         if isinstance(const, types.CodeType):
 | 
| 26 |             dis_code(const)
 | 
| 27 | 
 | 
| 28 |     print("")
 | 
| 29 |     print(code)
 | 
| 30 |     dis.dis(code)
 | 
| 31 | 
 | 
| 32 | 
 | 
| 33 | class VmTestCase(unittest.TestCase):
 | 
| 34 | 
 | 
| 35 |     def assert_ok(self, code, raises=None):
 | 
| 36 |         """Run `code` in our VM and in real Python: they behave the same."""
 | 
| 37 | 
 | 
| 38 |         code = textwrap.dedent(code)
 | 
| 39 |         code = compile(code, "<%s>" % self.id(), "exec", 0, 1)
 | 
| 40 | 
 | 
| 41 |         # Print the disassembly so we'll see it if the test fails.
 | 
| 42 |         dis_code(code)
 | 
| 43 | 
 | 
| 44 |         real_stdout = sys.stdout
 | 
| 45 | 
 | 
| 46 |         # Run the code through our VM.
 | 
| 47 | 
 | 
| 48 |         vm_stdout = cStringIO.StringIO()
 | 
| 49 |         if CAPTURE_STDOUT:              # pragma: no branch
 | 
| 50 |             sys.stdout = vm_stdout
 | 
| 51 |         vm = pyvm2.VirtualMachine()
 | 
| 52 | 
 | 
| 53 |         vm_value = vm_exc = None
 | 
| 54 |         try:
 | 
| 55 |             vm_value = pyvm2.run_code(vm, code)
 | 
| 56 |         except pyvm2.VirtualMachineError:         # pragma: no cover
 | 
| 57 |             # If the VM code raises an error, show it.
 | 
| 58 |             raise
 | 
| 59 |         except AssertionError:              # pragma: no cover
 | 
| 60 |             # If test code fails an assert, show it.
 | 
| 61 |             raise
 | 
| 62 |         except Exception as e:
 | 
| 63 |             # Otherwise, keep the exception for comparison later.
 | 
| 64 |             if not CAPTURE_EXCEPTION:       # pragma: no cover
 | 
| 65 |                 raise
 | 
| 66 |             vm_exc = e
 | 
| 67 |         finally:
 | 
| 68 |             real_stdout.write("-- stdout ----------\n")
 | 
| 69 |             real_stdout.write(vm_stdout.getvalue())
 | 
| 70 | 
 | 
| 71 |         # Run the code through the real Python interpreter, for comparison.
 | 
| 72 | 
 | 
| 73 |         py_stdout = cStringIO.StringIO()
 | 
| 74 |         sys.stdout = py_stdout
 | 
| 75 | 
 | 
| 76 |         py_value = py_exc = None
 | 
| 77 |         globs = {}
 | 
| 78 |         try:
 | 
| 79 |             py_value = eval(code, globs, globs)
 | 
| 80 |         except AssertionError:              # pragma: no cover
 | 
| 81 |             raise
 | 
| 82 |         except Exception as e:
 | 
| 83 |             py_exc = e
 | 
| 84 | 
 | 
| 85 |         sys.stdout = real_stdout
 | 
| 86 | 
 | 
| 87 |         self.assert_same_exception(vm_exc, py_exc)
 | 
| 88 |         self.assertEqual(vm_stdout.getvalue(), py_stdout.getvalue())
 | 
| 89 |         self.assertEqual(vm_value, py_value)
 | 
| 90 |         if raises:
 | 
| 91 |             self.assertIsInstance(vm_exc, raises)
 | 
| 92 |         else:
 | 
| 93 |             self.assertIsNone(vm_exc)
 | 
| 94 | 
 | 
| 95 |     def assert_same_exception(self, e1, e2):
 | 
| 96 |         """Exceptions don't implement __eq__, check it ourselves."""
 | 
| 97 |         self.assertEqual(str(e1), str(e2))
 | 
| 98 |         self.assertIs(type(e1), type(e2))
 |