1# Minimal tests for dis module 2 3from test.test_support import run_unittest 4import unittest 5import sys 6import dis 7import StringIO 8 9 10def _f(a): 11 print a 12 return 1 13 14dis_f = """\ 15%3d 0 LOAD_FAST 0 (a) 16 3 PRINT_ITEM 17 4 PRINT_NEWLINE 18 19%3d 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 25def bug708901(): 26 for res in range(1, 27 10): 28 pass 29 30dis_bug708901 = """\ 31%3d 0 SETUP_LOOP 23 (to 26) 32 3 LOAD_GLOBAL 0 (range) 33 6 LOAD_CONST 1 (1) 34 35%3d 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%3d 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 50def bug1333982(x=[]): 51 assert 0, ([s for s in x] + 52 1) 53 pass 54 55dis_bug1333982 = """\ 56%3d 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%3d >> 31 LOAD_CONST 2 (1) 69 34 BINARY_ADD 70 35 CALL_FUNCTION 1 71 38 RAISE_VARARGS 1 72 73%3d >> 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 86class 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 else: 129 self.skipTest('need asserts, run without -O') 130 131 def test_big_linenos(self): 132 def func(count): 133 namespace = {} 134 func = "def foo():\n " + "".join(["\n "] * count + ["spam\n"]) 135 exec func in namespace 136 return namespace['foo'] 137 138 # Test all small ranges 139 for i in xrange(1, 300): 140 expected = _BIG_LINENO_FORMAT % (i + 2) 141 self.do_disassembly_test(func(i), expected) 142 143 # Test some larger ranges too 144 for i in xrange(300, 5000, 10): 145 expected = _BIG_LINENO_FORMAT % (i + 2) 146 self.do_disassembly_test(func(i), expected) 147 148def test_main(): 149 run_unittest(DisTests) 150 151 152if __name__ == "__main__": 153 test_main() 154