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