Home | History | Annotate | Download | only in test
      1 """Test cases for traceback module"""
      2 
      3 from StringIO import StringIO
      4 import sys
      5 import unittest
      6 from imp import reload
      7 from test.test_support import (run_unittest, is_jython, Error, cpython_only,
      8                                captured_output)
      9 
     10 import traceback
     11 
     12 
     13 class TracebackCases(unittest.TestCase):
     14     # For now, a very minimal set of tests.  I want to be sure that
     15     # formatting of SyntaxErrors works based on changes for 2.1.
     16 
     17     def get_exception_format(self, func, exc):
     18         try:
     19             func()
     20         except exc, value:
     21             return traceback.format_exception_only(exc, value)
     22         else:
     23             raise ValueError, "call did not raise exception"
     24 
     25     def syntax_error_with_caret(self):
     26         compile("def fact(x):\n\treturn x!\n", "?", "exec")
     27 
     28     def syntax_error_with_caret_2(self):
     29         compile("1 +\n", "?", "exec")
     30 
     31     def syntax_error_without_caret(self):
     32         # XXX why doesn't compile raise the same traceback?
     33         import test.badsyntax_nocaret
     34 
     35     def syntax_error_bad_indentation(self):
     36         compile("def spam():\n  print 1\n print 2", "?", "exec")
     37 
     38     def syntax_error_bad_indentation2(self):
     39         compile(" print(2)", "?", "exec")
     40 
     41     def test_caret(self):
     42         err = self.get_exception_format(self.syntax_error_with_caret,
     43                                         SyntaxError)
     44         self.assertTrue(len(err) == 4)
     45         self.assertTrue(err[1].strip() == "return x!")
     46         self.assertIn("^", err[2]) # third line has caret
     47         self.assertTrue(err[1].find("!") == err[2].find("^")) # in the right place
     48 
     49         err = self.get_exception_format(self.syntax_error_with_caret_2,
     50                                         SyntaxError)
     51         self.assertIn("^", err[2]) # third line has caret
     52         self.assertTrue(err[2].count('\n') == 1) # and no additional newline
     53         self.assertTrue(err[1].find("+") == err[2].find("^")) # in the right place
     54 
     55     def test_nocaret(self):
     56         if is_jython:
     57             # jython adds a caret in this case (why shouldn't it?)
     58             return
     59         err = self.get_exception_format(self.syntax_error_without_caret,
     60                                         SyntaxError)
     61         self.assertTrue(len(err) == 3)
     62         self.assertTrue(err[1].strip() == "[x for x in x] = x")
     63 
     64     def test_bad_indentation(self):
     65         err = self.get_exception_format(self.syntax_error_bad_indentation,
     66                                         IndentationError)
     67         self.assertTrue(len(err) == 4)
     68         self.assertTrue(err[1].strip() == "print 2")
     69         self.assertIn("^", err[2])
     70         self.assertTrue(err[1].find("2") == err[2].find("^"))
     71 
     72     def test_bug737473(self):
     73         import os, tempfile, time
     74 
     75         savedpath = sys.path[:]
     76         testdir = tempfile.mkdtemp()
     77         try:
     78             sys.path.insert(0, testdir)
     79             testfile = os.path.join(testdir, 'test_bug737473.py')
     80             print >> open(testfile, 'w'), """
     81 def test():
     82     raise ValueError"""
     83 
     84             if 'test_bug737473' in sys.modules:
     85                 del sys.modules['test_bug737473']
     86             import test_bug737473
     87 
     88             try:
     89                 test_bug737473.test()
     90             except ValueError:
     91                 # this loads source code to linecache
     92                 traceback.extract_tb(sys.exc_traceback)
     93 
     94             # If this test runs too quickly, test_bug737473.py's mtime
     95             # attribute will remain unchanged even if the file is rewritten.
     96             # Consequently, the file would not reload.  So, added a sleep()
     97             # delay to assure that a new, distinct timestamp is written.
     98             # Since WinME with FAT32 has multisecond resolution, more than
     99             # three seconds are needed for this test to pass reliably :-(
    100             time.sleep(4)
    101 
    102             print >> open(testfile, 'w'), """
    103 def test():
    104     raise NotImplementedError"""
    105             reload(test_bug737473)
    106             try:
    107                 test_bug737473.test()
    108             except NotImplementedError:
    109                 src = traceback.extract_tb(sys.exc_traceback)[-1][-1]
    110                 self.assertEqual(src, 'raise NotImplementedError')
    111         finally:
    112             sys.path[:] = savedpath
    113             for f in os.listdir(testdir):
    114                 os.unlink(os.path.join(testdir, f))
    115             os.rmdir(testdir)
    116 
    117         err = self.get_exception_format(self.syntax_error_bad_indentation2,
    118                                         IndentationError)
    119         self.assertEqual(len(err), 4)
    120         self.assertEqual(err[1].strip(), "print(2)")
    121         self.assertIn("^", err[2])
    122         self.assertEqual(err[1].find("p"), err[2].find("^"))
    123 
    124     def test_base_exception(self):
    125         # Test that exceptions derived from BaseException are formatted right
    126         e = KeyboardInterrupt()
    127         lst = traceback.format_exception_only(e.__class__, e)
    128         self.assertEqual(lst, ['KeyboardInterrupt\n'])
    129 
    130     # String exceptions are deprecated, but legal.  The quirky form with
    131     # separate "type" and "value" tends to break things, because
    132     #     not isinstance(value, type)
    133     # and a string cannot be the first argument to issubclass.
    134     #
    135     # Note that sys.last_type and sys.last_value do not get set if an
    136     # exception is caught, so we sort of cheat and just emulate them.
    137     #
    138     # test_string_exception1 is equivalent to
    139     #
    140     # >>> raise "String Exception"
    141     #
    142     # test_string_exception2 is equivalent to
    143     #
    144     # >>> raise "String Exception", "String Value"
    145     #
    146     def test_string_exception1(self):
    147         str_type = "String Exception"
    148         err = traceback.format_exception_only(str_type, None)
    149         self.assertEqual(len(err), 1)
    150         self.assertEqual(err[0], str_type + '\n')
    151 
    152     def test_string_exception2(self):
    153         str_type = "String Exception"
    154         str_value = "String Value"
    155         err = traceback.format_exception_only(str_type, str_value)
    156         self.assertEqual(len(err), 1)
    157         self.assertEqual(err[0], str_type + ': ' + str_value + '\n')
    158 
    159     def test_format_exception_only_bad__str__(self):
    160         class X(Exception):
    161             def __str__(self):
    162                 1 // 0
    163         err = traceback.format_exception_only(X, X())
    164         self.assertEqual(len(err), 1)
    165         str_value = '<unprintable %s object>' % X.__name__
    166         self.assertEqual(err[0], X.__name__ + ': ' + str_value + '\n')
    167 
    168     def test_without_exception(self):
    169         err = traceback.format_exception_only(None, None)
    170         self.assertEqual(err, ['None\n'])
    171 
    172     def test_unicode(self):
    173         err = AssertionError('\xff')
    174         lines = traceback.format_exception_only(type(err), err)
    175         self.assertEqual(lines, ['AssertionError: \xff\n'])
    176 
    177         err = AssertionError(u'\xe9')
    178         lines = traceback.format_exception_only(type(err), err)
    179         self.assertEqual(lines, ['AssertionError: \\xe9\n'])
    180 
    181 
    182 class TracebackFormatTests(unittest.TestCase):
    183 
    184     @cpython_only
    185     def test_traceback_format(self):
    186         from _testcapi import traceback_print
    187         try:
    188             raise KeyError('blah')
    189         except KeyError:
    190             type_, value, tb = sys.exc_info()
    191             traceback_fmt = 'Traceback (most recent call last):\n' + \
    192                             ''.join(traceback.format_tb(tb))
    193             file_ = StringIO()
    194             traceback_print(tb, file_)
    195             python_fmt  = file_.getvalue()
    196         else:
    197             raise Error("unable to create test traceback string")
    198 
    199         # Make sure that Python and the traceback module format the same thing
    200         self.assertEqual(traceback_fmt, python_fmt)
    201 
    202         # Make sure that the traceback is properly indented.
    203         tb_lines = python_fmt.splitlines()
    204         self.assertEqual(len(tb_lines), 3)
    205         banner, location, source_line = tb_lines
    206         self.assertTrue(banner.startswith('Traceback'))
    207         self.assertTrue(location.startswith('  File'))
    208         self.assertTrue(source_line.startswith('    raise'))
    209 
    210     def test_print_stack(self):
    211         def prn():
    212             traceback.print_stack()
    213         with captured_output("stderr") as stderr:
    214             prn()
    215         lineno = prn.__code__.co_firstlineno
    216         file = prn.__code__.co_filename
    217         self.assertEqual(stderr.getvalue().splitlines()[-4:], [
    218             '  File "%s", line %d, in test_print_stack' % (file, lineno+3),
    219             '    prn()',
    220             '  File "%s", line %d, in prn' % (file, lineno+1),
    221             '    traceback.print_stack()',
    222         ])
    223 
    224     def test_format_stack(self):
    225         def fmt():
    226             return traceback.format_stack()
    227         result = fmt()
    228         lineno = fmt.__code__.co_firstlineno
    229         file = fmt.__code__.co_filename
    230         self.assertEqual(result[-2:], [
    231             '  File "%s", line %d, in test_format_stack\n'
    232             '    result = fmt()\n' % (file, lineno+2),
    233             '  File "%s", line %d, in fmt\n'
    234             '    return traceback.format_stack()\n' % (file, lineno+1),
    235         ])
    236 
    237 
    238 class MiscTracebackCases(unittest.TestCase):
    239     #
    240     # Check non-printing functions in traceback module
    241     #
    242 
    243     def test_extract_stack(self):
    244         def extract():
    245             return traceback.extract_stack()
    246         result = extract()
    247         lineno = extract.__code__.co_firstlineno
    248         file = extract.__code__.co_filename
    249         self.assertEqual(result[-2:], [
    250             (file, lineno+2, 'test_extract_stack', 'result = extract()'),
    251             (file, lineno+1, 'extract', 'return traceback.extract_stack()'),
    252         ])
    253 
    254 
    255 def test_main():
    256     run_unittest(TracebackCases, TracebackFormatTests, MiscTracebackCases)
    257 
    258 
    259 if __name__ == "__main__":
    260     test_main()
    261