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