| 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))
|