OILS / opy / _regtest / src / opy / byterun / vmtest.py View on Github | oils.pub

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