Home | History | Annotate | Download | only in test
      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