1 | # Minimal tests for dis module
|
---|
2 |
|
---|
3 | from test.test_support import run_unittest
|
---|
4 | import unittest
|
---|
5 | import sys
|
---|
6 | import dis
|
---|
7 | import StringIO
|
---|
8 |
|
---|
9 |
|
---|
10 | def _f(a):
|
---|
11 | print a
|
---|
12 | return 1
|
---|
13 |
|
---|
14 | dis_f = """\
|
---|
15 | %-4d 0 LOAD_FAST 0 (a)
|
---|
16 | 3 PRINT_ITEM
|
---|
17 | 4 PRINT_NEWLINE
|
---|
18 |
|
---|
19 | %-4d 5 LOAD_CONST 1 (1)
|
---|
20 | 8 RETURN_VALUE
|
---|
21 | """%(_f.func_code.co_firstlineno + 1,
|
---|
22 | _f.func_code.co_firstlineno + 2)
|
---|
23 |
|
---|
24 |
|
---|
25 | def bug708901():
|
---|
26 | for res in range(1,
|
---|
27 | 10):
|
---|
28 | pass
|
---|
29 |
|
---|
30 | dis_bug708901 = """\
|
---|
31 | %-4d 0 SETUP_LOOP 23 (to 26)
|
---|
32 | 3 LOAD_GLOBAL 0 (range)
|
---|
33 | 6 LOAD_CONST 1 (1)
|
---|
34 |
|
---|
35 | %-4d 9 LOAD_CONST 2 (10)
|
---|
36 | 12 CALL_FUNCTION 2
|
---|
37 | 15 GET_ITER
|
---|
38 | >> 16 FOR_ITER 6 (to 25)
|
---|
39 | 19 STORE_FAST 0 (res)
|
---|
40 |
|
---|
41 | %-4d 22 JUMP_ABSOLUTE 16
|
---|
42 | >> 25 POP_BLOCK
|
---|
43 | >> 26 LOAD_CONST 0 (None)
|
---|
44 | 29 RETURN_VALUE
|
---|
45 | """%(bug708901.func_code.co_firstlineno + 1,
|
---|
46 | bug708901.func_code.co_firstlineno + 2,
|
---|
47 | bug708901.func_code.co_firstlineno + 3)
|
---|
48 |
|
---|
49 |
|
---|
50 | def bug1333982(x=[]):
|
---|
51 | assert 0, ([s for s in x] +
|
---|
52 | 1)
|
---|
53 | pass
|
---|
54 |
|
---|
55 | dis_bug1333982 = """\
|
---|
56 | %-4d 0 LOAD_CONST 1 (0)
|
---|
57 | 3 POP_JUMP_IF_TRUE 41
|
---|
58 | 6 LOAD_GLOBAL 0 (AssertionError)
|
---|
59 | 9 BUILD_LIST 0
|
---|
60 | 12 LOAD_FAST 0 (x)
|
---|
61 | 15 GET_ITER
|
---|
62 | >> 16 FOR_ITER 12 (to 31)
|
---|
63 | 19 STORE_FAST 1 (s)
|
---|
64 | 22 LOAD_FAST 1 (s)
|
---|
65 | 25 LIST_APPEND 2
|
---|
66 | 28 JUMP_ABSOLUTE 16
|
---|
67 |
|
---|
68 | %-4d >> 31 LOAD_CONST 2 (1)
|
---|
69 | 34 BINARY_ADD
|
---|
70 | 35 CALL_FUNCTION 1
|
---|
71 | 38 RAISE_VARARGS 1
|
---|
72 |
|
---|
73 | %-4d >> 41 LOAD_CONST 0 (None)
|
---|
74 | 44 RETURN_VALUE
|
---|
75 | """%(bug1333982.func_code.co_firstlineno + 1,
|
---|
76 | bug1333982.func_code.co_firstlineno + 2,
|
---|
77 | bug1333982.func_code.co_firstlineno + 3)
|
---|
78 |
|
---|
79 | _BIG_LINENO_FORMAT = """\
|
---|
80 | %3d 0 LOAD_GLOBAL 0 (spam)
|
---|
81 | 3 POP_TOP
|
---|
82 | 4 LOAD_CONST 0 (None)
|
---|
83 | 7 RETURN_VALUE
|
---|
84 | """
|
---|
85 |
|
---|
86 | class DisTests(unittest.TestCase):
|
---|
87 | def do_disassembly_test(self, func, expected):
|
---|
88 | s = StringIO.StringIO()
|
---|
89 | save_stdout = sys.stdout
|
---|
90 | sys.stdout = s
|
---|
91 | dis.dis(func)
|
---|
92 | sys.stdout = save_stdout
|
---|
93 | got = s.getvalue()
|
---|
94 | # Trim trailing blanks (if any).
|
---|
95 | lines = got.split('\n')
|
---|
96 | lines = [line.rstrip() for line in lines]
|
---|
97 | expected = expected.split("\n")
|
---|
98 | import difflib
|
---|
99 | if expected != lines:
|
---|
100 | self.fail(
|
---|
101 | "events did not match expectation:\n" +
|
---|
102 | "\n".join(difflib.ndiff(expected,
|
---|
103 | lines)))
|
---|
104 |
|
---|
105 | def test_opmap(self):
|
---|
106 | self.assertEqual(dis.opmap["STOP_CODE"], 0)
|
---|
107 | self.assertIn(dis.opmap["LOAD_CONST"], dis.hasconst)
|
---|
108 | self.assertIn(dis.opmap["STORE_NAME"], dis.hasname)
|
---|
109 |
|
---|
110 | def test_opname(self):
|
---|
111 | self.assertEqual(dis.opname[dis.opmap["LOAD_FAST"]], "LOAD_FAST")
|
---|
112 |
|
---|
113 | def test_boundaries(self):
|
---|
114 | self.assertEqual(dis.opmap["EXTENDED_ARG"], dis.EXTENDED_ARG)
|
---|
115 | self.assertEqual(dis.opmap["STORE_NAME"], dis.HAVE_ARGUMENT)
|
---|
116 |
|
---|
117 | def test_dis(self):
|
---|
118 | self.do_disassembly_test(_f, dis_f)
|
---|
119 |
|
---|
120 | def test_bug_708901(self):
|
---|
121 | self.do_disassembly_test(bug708901, dis_bug708901)
|
---|
122 |
|
---|
123 | def test_bug_1333982(self):
|
---|
124 | # This one is checking bytecodes generated for an `assert` statement,
|
---|
125 | # so fails if the tests are run with -O. Skip this test then.
|
---|
126 | if __debug__:
|
---|
127 | self.do_disassembly_test(bug1333982, dis_bug1333982)
|
---|
128 |
|
---|
129 | def test_big_linenos(self):
|
---|
130 | def func(count):
|
---|
131 | namespace = {}
|
---|
132 | func = "def foo():\n " + "".join(["\n "] * count + ["spam\n"])
|
---|
133 | exec func in namespace
|
---|
134 | return namespace['foo']
|
---|
135 |
|
---|
136 | # Test all small ranges
|
---|
137 | for i in xrange(1, 300):
|
---|
138 | expected = _BIG_LINENO_FORMAT % (i + 2)
|
---|
139 | self.do_disassembly_test(func(i), expected)
|
---|
140 |
|
---|
141 | # Test some larger ranges too
|
---|
142 | for i in xrange(300, 5000, 10):
|
---|
143 | expected = _BIG_LINENO_FORMAT % (i + 2)
|
---|
144 | self.do_disassembly_test(func(i), expected)
|
---|
145 |
|
---|
146 | def test_main():
|
---|
147 | run_unittest(DisTests)
|
---|
148 |
|
---|
149 |
|
---|
150 | if __name__ == "__main__":
|
---|
151 | test_main()
|
---|