blob: 103d8356f85f15840cc04da530637bc0bbb914b5 [file] [log] [blame]
Brett Cannonbf364092006-03-01 04:25:17 +00001import unittest
2import __builtin__
3import exceptions
4import warnings
Brett Cannon672237d2008-09-09 00:49:16 +00005from test.test_support import run_unittest
Brett Cannonbf364092006-03-01 04:25:17 +00006import os
7from platform import system as platform_system
8
Senthil Kumaran3ddc4352010-01-08 18:41:40 +00009DEPRECATION_WARNINGS = (
10 "BaseException.message has been deprecated",
11 "exceptions must derive from BaseException",
12 "catching classes that don't inherit from BaseException is not allowed",
13 "__getitem__ not supported for exception classes",
14)
Brett Cannon229cee22007-05-05 01:34:02 +000015
Senthil Kumaran3ddc4352010-01-08 18:41:40 +000016# Silence Py3k and other deprecation warnings
17def ignore_deprecation_warnings(func):
18 """Ignore the known DeprecationWarnings."""
19 def wrapper(*args, **kw):
20 with warnings.catch_warnings():
21 warnings.resetwarnings()
22 for text in DEPRECATION_WARNINGS:
23 warnings.filterwarnings("ignore", text, DeprecationWarning)
24 return func(*args, **kw)
25 return wrapper
Brett Cannon229cee22007-05-05 01:34:02 +000026
Brett Cannonbf364092006-03-01 04:25:17 +000027class ExceptionClassTests(unittest.TestCase):
28
29 """Tests for anything relating to exception objects themselves (e.g.,
30 inheritance hierarchy)"""
31
32 def test_builtins_new_style(self):
Benjamin Peterson5c8da862009-06-30 22:57:08 +000033 self.assertTrue(issubclass(Exception, object))
Brett Cannonbf364092006-03-01 04:25:17 +000034
Senthil Kumaran3ddc4352010-01-08 18:41:40 +000035 @ignore_deprecation_warnings
Brett Cannonbf364092006-03-01 04:25:17 +000036 def verify_instance_interface(self, ins):
Senthil Kumaran3ddc4352010-01-08 18:41:40 +000037 for attr in ("args", "message", "__str__", "__repr__", "__getitem__"):
38 self.assertTrue(hasattr(ins, attr),
39 "%s missing %s attribute" %
40 (ins.__class__.__name__, attr))
Brett Cannonbf364092006-03-01 04:25:17 +000041
42 def test_inheritance(self):
43 # Make sure the inheritance hierarchy matches the documentation
44 exc_set = set(x for x in dir(exceptions) if not x.startswith('_'))
45 inheritance_tree = open(os.path.join(os.path.split(__file__)[0],
46 'exception_hierarchy.txt'))
47 try:
48 superclass_name = inheritance_tree.readline().rstrip()
49 try:
50 last_exc = getattr(__builtin__, superclass_name)
51 except AttributeError:
52 self.fail("base class %s not a built-in" % superclass_name)
Benjamin Peterson5c8da862009-06-30 22:57:08 +000053 self.assertTrue(superclass_name in exc_set)
Brett Cannonbf364092006-03-01 04:25:17 +000054 exc_set.discard(superclass_name)
55 superclasses = [] # Loop will insert base exception
56 last_depth = 0
57 for exc_line in inheritance_tree:
58 exc_line = exc_line.rstrip()
59 depth = exc_line.rindex('-')
60 exc_name = exc_line[depth+2:] # Slice past space
61 if '(' in exc_name:
62 paren_index = exc_name.index('(')
63 platform_name = exc_name[paren_index+1:-1]
Brett Cannon6b4ed742006-03-01 06:10:48 +000064 exc_name = exc_name[:paren_index-1] # Slice off space
Brett Cannonbf364092006-03-01 04:25:17 +000065 if platform_system() != platform_name:
66 exc_set.discard(exc_name)
67 continue
68 if '[' in exc_name:
69 left_bracket = exc_name.index('[')
70 exc_name = exc_name[:left_bracket-1] # cover space
71 try:
72 exc = getattr(__builtin__, exc_name)
73 except AttributeError:
74 self.fail("%s not a built-in exception" % exc_name)
75 if last_depth < depth:
76 superclasses.append((last_depth, last_exc))
77 elif last_depth > depth:
78 while superclasses[-1][0] >= depth:
79 superclasses.pop()
Benjamin Peterson5c8da862009-06-30 22:57:08 +000080 self.assertTrue(issubclass(exc, superclasses[-1][1]),
Brett Cannonbf364092006-03-01 04:25:17 +000081 "%s is not a subclass of %s" % (exc.__name__,
82 superclasses[-1][1].__name__))
83 try: # Some exceptions require arguments; just skip them
84 self.verify_instance_interface(exc())
85 except TypeError:
86 pass
Benjamin Peterson5c8da862009-06-30 22:57:08 +000087 self.assertTrue(exc_name in exc_set)
Brett Cannonbf364092006-03-01 04:25:17 +000088 exc_set.discard(exc_name)
89 last_exc = exc
90 last_depth = depth
91 finally:
92 inheritance_tree.close()
Benjamin Peterson5c8da862009-06-30 22:57:08 +000093 self.assertEqual(len(exc_set), 0, "%s not accounted for" % exc_set)
Brett Cannonbf364092006-03-01 04:25:17 +000094
95 interface_tests = ("length", "args", "message", "str", "unicode", "repr",
96 "indexing")
97
98 def interface_test_driver(self, results):
99 for test_name, (given, expected) in zip(self.interface_tests, results):
Georg Brandl19e79f72009-06-03 23:23:45 +0000100 self.assertEqual(given, expected, "%s: %s != %s" % (test_name,
Brett Cannonbf364092006-03-01 04:25:17 +0000101 given, expected))
102
Senthil Kumaran3ddc4352010-01-08 18:41:40 +0000103 @ignore_deprecation_warnings
Brett Cannonbf364092006-03-01 04:25:17 +0000104 def test_interface_single_arg(self):
105 # Make sure interface works properly when given a single argument
106 arg = "spam"
107 exc = Exception(arg)
Senthil Kumaran3ddc4352010-01-08 18:41:40 +0000108 results = ([len(exc.args), 1], [exc.args[0], arg], [exc.message, arg],
109 [str(exc), str(arg)], [unicode(exc), unicode(arg)],
110 [repr(exc), exc.__class__.__name__ + repr(exc.args)],
111 [exc[0], arg])
112 self.interface_test_driver(results)
Brett Cannonbf364092006-03-01 04:25:17 +0000113
Senthil Kumaran3ddc4352010-01-08 18:41:40 +0000114 @ignore_deprecation_warnings
Brett Cannonbf364092006-03-01 04:25:17 +0000115 def test_interface_multi_arg(self):
116 # Make sure interface correct when multiple arguments given
117 arg_count = 3
118 args = tuple(range(arg_count))
119 exc = Exception(*args)
Senthil Kumaran3ddc4352010-01-08 18:41:40 +0000120 results = ([len(exc.args), arg_count], [exc.args, args],
121 [exc.message, ''], [str(exc), str(args)],
122 [unicode(exc), unicode(args)],
123 [repr(exc), exc.__class__.__name__ + repr(exc.args)],
124 [exc[-1], args[-1]])
125 self.interface_test_driver(results)
Brett Cannonbf364092006-03-01 04:25:17 +0000126
Senthil Kumaran3ddc4352010-01-08 18:41:40 +0000127 @ignore_deprecation_warnings
Brett Cannonbf364092006-03-01 04:25:17 +0000128 def test_interface_no_arg(self):
129 # Make sure that with no args that interface is correct
130 exc = Exception()
Senthil Kumaran3ddc4352010-01-08 18:41:40 +0000131 results = ([len(exc.args), 0], [exc.args, tuple()],
132 [exc.message, ''],
133 [str(exc), ''], [unicode(exc), u''],
134 [repr(exc), exc.__class__.__name__ + '()'], [True, True])
135 self.interface_test_driver(results)
Brett Cannon229cee22007-05-05 01:34:02 +0000136
137
138 def test_message_deprecation(self):
139 # As of Python 2.6, BaseException.message is deprecated.
Brett Cannon672237d2008-09-09 00:49:16 +0000140 with warnings.catch_warnings():
Brett Cannon229cee22007-05-05 01:34:02 +0000141 warnings.resetwarnings()
142 warnings.filterwarnings('error')
143
144 try:
145 BaseException().message
146 except DeprecationWarning:
147 pass
148 else:
149 self.fail("BaseException.message not deprecated")
150
Brett Cannonbf364092006-03-01 04:25:17 +0000151
152class UsageTests(unittest.TestCase):
153
154 """Test usage of exceptions"""
155
Brett Cannon6fbb96e2007-02-23 14:28:25 +0000156 def raise_fails(self, object_):
157 """Make sure that raising 'object_' triggers a TypeError."""
158 try:
159 raise object_
160 except TypeError:
161 return # What is expected.
162 self.fail("TypeError expected for raising %s" % type(object_))
163
164 def catch_fails(self, object_):
165 """Catching 'object_' should raise a TypeError."""
166 try:
167 try:
168 raise StandardError
169 except object_:
170 pass
171 except TypeError:
172 pass
173 except StandardError:
174 self.fail("TypeError expected when catching %s" % type(object_))
175
176 try:
177 try:
178 raise StandardError
179 except (object_,):
180 pass
181 except TypeError:
182 return
183 except StandardError:
184 self.fail("TypeError expected when catching %s as specified in a "
185 "tuple" % type(object_))
186
Senthil Kumaran3ddc4352010-01-08 18:41:40 +0000187 @ignore_deprecation_warnings
Brett Cannonbf364092006-03-01 04:25:17 +0000188 def test_raise_classic(self):
Brett Cannon129bd522007-01-30 21:34:36 +0000189 # Raising a classic class is okay (for now).
Brett Cannonbf364092006-03-01 04:25:17 +0000190 class ClassicClass:
191 pass
192 try:
193 raise ClassicClass
194 except ClassicClass:
195 pass
196 except:
197 self.fail("unable to raise classic class")
198 try:
199 raise ClassicClass()
200 except ClassicClass:
201 pass
202 except:
203 self.fail("unable to raise class class instance")
204
205 def test_raise_new_style_non_exception(self):
Brett Cannon129bd522007-01-30 21:34:36 +0000206 # You cannot raise a new-style class that does not inherit from
207 # BaseException; the ability was not possible until BaseException's
208 # introduction so no need to support new-style objects that do not
209 # inherit from it.
Brett Cannonbf364092006-03-01 04:25:17 +0000210 class NewStyleClass(object):
211 pass
Brett Cannon6fbb96e2007-02-23 14:28:25 +0000212 self.raise_fails(NewStyleClass)
213 self.raise_fails(NewStyleClass())
Brett Cannonbf364092006-03-01 04:25:17 +0000214
215 def test_raise_string(self):
Brett Cannon129bd522007-01-30 21:34:36 +0000216 # Raising a string raises TypeError.
Brett Cannon6fbb96e2007-02-23 14:28:25 +0000217 self.raise_fails("spam")
Brett Cannonbf364092006-03-01 04:25:17 +0000218
219 def test_catch_string(self):
Brett Cannon129bd522007-01-30 21:34:36 +0000220 # Catching a string should trigger a DeprecationWarning.
Brett Cannon672237d2008-09-09 00:49:16 +0000221 with warnings.catch_warnings():
Brett Cannon129bd522007-01-30 21:34:36 +0000222 warnings.resetwarnings()
223 warnings.filterwarnings("error")
224 str_exc = "spam"
225 try:
226 try:
227 raise StandardError
228 except str_exc:
229 pass
230 except DeprecationWarning:
231 pass
232 except StandardError:
233 self.fail("catching a string exception did not raise "
234 "DeprecationWarning")
235 # Make sure that even if the string exception is listed in a tuple
236 # that a warning is raised.
237 try:
238 try:
239 raise StandardError
240 except (AssertionError, str_exc):
241 pass
242 except DeprecationWarning:
243 pass
244 except StandardError:
245 self.fail("catching a string exception specified in a tuple did "
246 "not raise DeprecationWarning")
247
Brett Cannonbf364092006-03-01 04:25:17 +0000248
249def test_main():
250 run_unittest(ExceptionClassTests, UsageTests)
251
252
253
254if __name__ == '__main__':
255 test_main()