Home | History | Annotate | Download | only in test
      1 """Test cases for traceback module"""
      2 
      3 from _testcapi import traceback_print
      4 from StringIO import StringIO
      5 import sys
      6 import unittest
      7 from imp import reload
      8 from test.test_support import run_unittest, is_jython, Error
      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 test_caret(self):
     39         err = self.get_exception_format(self.syntax_error_with_caret,
     40                                         SyntaxError)
     41         self.assertTrue(len(err) == 4)
     42         self.assertTrue(err[1].strip() == "return x!")
     43         self.assertIn("^", err[2]) # third line has caret
     44         self.assertTrue(err[1].find("!") == err[2].find("^")) # in the right place
     45 
     46         err = self.get_exception_format(self.syntax_error_with_caret_2,
     47                                         SyntaxError)
     48         self.assertIn("^", err[2]) # third line has caret
     49         self.assertTrue(err[2].count('\n') == 1) # and no additional newline
     50         self.assertTrue(err[1].find("+") == err[2].find("^")) # in the right place
     51 
     52     def test_nocaret(self):
     53         if is_jython:
     54             # jython adds a caret in this case (why shouldn't it?)
     55             return
     56         err = self.get_exception_format(self.syntax_error_without_caret,
     57                                         SyntaxError)
     58         self.assertTrue(len(err) == 3)
     59         self.assertTrue(err[1].strip() == "[x for x in x] = x")
     60 
     61     def test_bad_indentation(self):
     62         err = self.get_exception_format(self.syntax_error_bad_indentation,
     63                                         IndentationError)
     64         self.assertTrue(len(err) == 4)
     65         self.assertTrue(err[1].strip() == "print 2")
     66         self.assertIn("^", err[2])
     67         self.assertTrue(err[1].find("2") == err[2].find("^"))
     68 
     69     def test_bug737473(self):
     70         import os, tempfile, time
     71 
     72         savedpath = sys.path[:]
     73         testdir = tempfile.mkdtemp()
     74         try:
     75             sys.path.insert(0, testdir)
     76             testfile = os.path.join(testdir, 'test_bug737473.py')
     77             print >> open(testfile, 'w'), """
     78 def test():
     79     raise ValueError"""
     80 
     81             if 'test_bug737473' in sys.modules:
     82                 del sys.modules['test_bug737473']
     83             import test_bug737473
     84 
     85             try:
     86                 test_bug737473.test()
     87             except ValueError:
     88                 # this loads source code to linecache
     89                 traceback.extract_tb(sys.exc_traceback)
     90 
     91             # If this test runs too quickly, test_bug737473.py's mtime
     92             # attribute will remain unchanged even if the file is rewritten.
     93             # Consequently, the file would not reload.  So, added a sleep()
     94             # delay to assure that a new, distinct timestamp is written.
     95             # Since WinME with FAT32 has multisecond resolution, more than
     96             # three seconds are needed for this test to pass reliably :-(
     97             time.sleep(4)
     98 
     99             print >> open(testfile, 'w'), """
    100 def test():
    101     raise NotImplementedError"""
    102             reload(test_bug737473)
    103             try:
    104                 test_bug737473.test()
    105             except NotImplementedError:
    106                 src = traceback.extract_tb(sys.exc_traceback)[-1][-1]
    107                 self.assertEqual(src, 'raise NotImplementedError')
    108         finally:
    109             sys.path[:] = savedpath
    110             for f in os.listdir(testdir):
    111                 os.unlink(os.path.join(testdir, f))
    112             os.rmdir(testdir)
    113 
    114     def test_base_exception(self):
    115         # Test that exceptions derived from BaseException are formatted right
    116         e = KeyboardInterrupt()
    117         lst = traceback.format_exception_only(e.__class__, e)
    118         self.assertEqual(lst, ['KeyboardInterrupt\n'])
    119 
    120     # String exceptions are deprecated, but legal.  The quirky form with
    121     # separate "type" and "value" tends to break things, because
    122     #     not isinstance(value, type)
    123     # and a string cannot be the first argument to issubclass.
    124     #
    125     # Note that sys.last_type and sys.last_value do not get set if an
    126     # exception is caught, so we sort of cheat and just emulate them.
    127     #
    128     # test_string_exception1 is equivalent to
    129     #
    130     # >>> raise "String Exception"
    131     #
    132     # test_string_exception2 is equivalent to
    133     #
    134     # >>> raise "String Exception", "String Value"
    135     #
    136     def test_string_exception1(self):
    137         str_type = "String Exception"
    138         err = traceback.format_exception_only(str_type, None)
    139         self.assertEqual(len(err), 1)
    140         self.assertEqual(err[0], str_type + '\n')
    141 
    142     def test_string_exception2(self):
    143         str_type = "String Exception"
    144         str_value = "String Value"
    145         err = traceback.format_exception_only(str_type, str_value)
    146         self.assertEqual(len(err), 1)
    147         self.assertEqual(err[0], str_type + ': ' + str_value + '\n')
    148 
    149     def test_format_exception_only_bad__str__(self):
    150         class X(Exception):
    151             def __str__(self):
    152                 1 // 0
    153         err = traceback.format_exception_only(X, X())
    154         self.assertEqual(len(err), 1)
    155         str_value = '<unprintable %s object>' % X.__name__
    156         self.assertEqual(err[0], X.__name__ + ': ' + str_value + '\n')
    157 
    158     def test_without_exception(self):
    159         err = traceback.format_exception_only(None, None)
    160         self.assertEqual(err, ['None\n'])
    161 
    162     def test_unicode(self):
    163         err = AssertionError('\xff')
    164         lines = traceback.format_exception_only(type(err), err)
    165         self.assertEqual(lines, ['AssertionError: \xff\n'])
    166 
    167         err = AssertionError(u'\xe9')
    168         lines = traceback.format_exception_only(type(err), err)
    169         self.assertEqual(lines, ['AssertionError: \\xe9\n'])
    170 
    171 
    172 class TracebackFormatTests(unittest.TestCase):
    173 
    174     def test_traceback_format(self):
    175         try:
    176             raise KeyError('blah')
    177         except KeyError:
    178             type_, value, tb = sys.exc_info()
    179             traceback_fmt = 'Traceback (most recent call last):\n' + \
    180                             ''.join(traceback.format_tb(tb))
    181             file_ = StringIO()
    182             traceback_print(tb, file_)
    183             python_fmt  = file_.getvalue()
    184         else:
    185             raise Error("unable to create test traceback string")
    186 
    187         # Make sure that Python and the traceback module format the same thing
    188         self.assertEqual(traceback_fmt, python_fmt)
    189 
    190         # Make sure that the traceback is properly indented.
    191         tb_lines = python_fmt.splitlines()
    192         self.assertEqual(len(tb_lines), 3)
    193         banner, location, source_line = tb_lines
    194         self.assertTrue(banner.startswith('Traceback'))
    195         self.assertTrue(location.startswith('  File'))
    196         self.assertTrue(source_line.startswith('    raise'))
    197 
    198 
    199 def test_main():
    200     run_unittest(TracebackCases, TracebackFormatTests)
    201 
    202 
    203 if __name__ == "__main__":
    204     test_main()
    205