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