blob: 4654e26fc192735c2f587ae7c03ca634de9cfba8 [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
Ezio Melotti1f517e12010-02-02 17:34:37 +00007import sys
Brett Cannonbf364092006-03-01 04:25:17 +00008from platform import system as platform_system
9
Ezio Melotti1f517e12010-02-02 17:34:37 +000010DEPRECATION_WARNINGS = ["BaseException.message has been deprecated"]
Brett Cannon229cee22007-05-05 01:34:02 +000011
Ezio Melotti1f517e12010-02-02 17:34:37 +000012if sys.py3kwarning:
13 DEPRECATION_WARNINGS.extend(
14 ["exceptions must derive from BaseException",
15 "catching classes that don't inherit from BaseException is not allowed",
16 "__get(item|slice)__ not supported for exception classes"])
17
18# Silence Py3k and other deprecation warnings
19def ignore_deprecation_warnings(func):
20 """Ignore the known DeprecationWarnings."""
21 def wrapper(*args, **kw):
22 with warnings.catch_warnings():
23 warnings.resetwarnings()
24 for text in DEPRECATION_WARNINGS:
25 warnings.filterwarnings("ignore", text, DeprecationWarning)
26 return func(*args, **kw)
27 return wrapper
Brett Cannon229cee22007-05-05 01:34:02 +000028
Brett Cannonbf364092006-03-01 04:25:17 +000029class ExceptionClassTests(unittest.TestCase):
30
31 """Tests for anything relating to exception objects themselves (e.g.,
32 inheritance hierarchy)"""
33
34 def test_builtins_new_style(self):
Benjamin Peterson5c8da862009-06-30 22:57:08 +000035 self.assertTrue(issubclass(Exception, object))
Brett Cannonbf364092006-03-01 04:25:17 +000036
Ezio Melotti1f517e12010-02-02 17:34:37 +000037 @ignore_deprecation_warnings
Brett Cannonbf364092006-03-01 04:25:17 +000038 def verify_instance_interface(self, ins):
Ezio Melotti1f517e12010-02-02 17:34:37 +000039 for attr in ("args", "message", "__str__", "__repr__", "__getitem__"):
40 self.assertTrue(hasattr(ins, attr),
41 "%s missing %s attribute" %
Senthil Kumarance8e33a2010-01-08 19:04:16 +000042 (ins.__class__.__name__, attr))
Brett Cannonbf364092006-03-01 04:25:17 +000043
44 def test_inheritance(self):
45 # Make sure the inheritance hierarchy matches the documentation
46 exc_set = set(x for x in dir(exceptions) if not x.startswith('_'))
47 inheritance_tree = open(os.path.join(os.path.split(__file__)[0],
48 'exception_hierarchy.txt'))
49 try:
50 superclass_name = inheritance_tree.readline().rstrip()
51 try:
52 last_exc = getattr(__builtin__, superclass_name)
53 except AttributeError:
54 self.fail("base class %s not a built-in" % superclass_name)
Ezio Melottiaa980582010-01-23 23:04:36 +000055 self.assertIn(superclass_name, exc_set)
Brett Cannonbf364092006-03-01 04:25:17 +000056 exc_set.discard(superclass_name)
57 superclasses = [] # Loop will insert base exception
58 last_depth = 0
59 for exc_line in inheritance_tree:
60 exc_line = exc_line.rstrip()
61 depth = exc_line.rindex('-')
62 exc_name = exc_line[depth+2:] # Slice past space
63 if '(' in exc_name:
64 paren_index = exc_name.index('(')
65 platform_name = exc_name[paren_index+1:-1]
Brett Cannon6b4ed742006-03-01 06:10:48 +000066 exc_name = exc_name[:paren_index-1] # Slice off space
Brett Cannonbf364092006-03-01 04:25:17 +000067 if platform_system() != platform_name:
68 exc_set.discard(exc_name)
69 continue
70 if '[' in exc_name:
71 left_bracket = exc_name.index('[')
72 exc_name = exc_name[:left_bracket-1] # cover space
73 try:
74 exc = getattr(__builtin__, exc_name)
75 except AttributeError:
76 self.fail("%s not a built-in exception" % exc_name)
77 if last_depth < depth:
78 superclasses.append((last_depth, last_exc))
79 elif last_depth > depth:
80 while superclasses[-1][0] >= depth:
81 superclasses.pop()
Benjamin Peterson5c8da862009-06-30 22:57:08 +000082 self.assertTrue(issubclass(exc, superclasses[-1][1]),
Brett Cannonbf364092006-03-01 04:25:17 +000083 "%s is not a subclass of %s" % (exc.__name__,
84 superclasses[-1][1].__name__))
85 try: # Some exceptions require arguments; just skip them
86 self.verify_instance_interface(exc())
87 except TypeError:
88 pass
Ezio Melottiaa980582010-01-23 23:04:36 +000089 self.assertIn(exc_name, exc_set)
Brett Cannonbf364092006-03-01 04:25:17 +000090 exc_set.discard(exc_name)
91 last_exc = exc
92 last_depth = depth
93 finally:
94 inheritance_tree.close()
Benjamin Peterson5c8da862009-06-30 22:57:08 +000095 self.assertEqual(len(exc_set), 0, "%s not accounted for" % exc_set)
Brett Cannonbf364092006-03-01 04:25:17 +000096
97 interface_tests = ("length", "args", "message", "str", "unicode", "repr",
98 "indexing")
99
100 def interface_test_driver(self, results):
101 for test_name, (given, expected) in zip(self.interface_tests, results):
Georg Brandl19e79f72009-06-03 23:23:45 +0000102 self.assertEqual(given, expected, "%s: %s != %s" % (test_name,
Brett Cannonbf364092006-03-01 04:25:17 +0000103 given, expected))
104
Ezio Melotti1f517e12010-02-02 17:34:37 +0000105 @ignore_deprecation_warnings
Brett Cannonbf364092006-03-01 04:25:17 +0000106 def test_interface_single_arg(self):
107 # Make sure interface works properly when given a single argument
108 arg = "spam"
109 exc = Exception(arg)
Ezio Melotti1f517e12010-02-02 17:34:37 +0000110 results = ([len(exc.args), 1], [exc.args[0], arg], [exc.message, arg],
111 [str(exc), str(arg)], [unicode(exc), unicode(arg)],
112 [repr(exc), exc.__class__.__name__ + repr(exc.args)],
113 [exc[0], arg])
114 self.interface_test_driver(results)
Brett Cannonbf364092006-03-01 04:25:17 +0000115
Ezio Melotti1f517e12010-02-02 17:34:37 +0000116 @ignore_deprecation_warnings
Brett Cannonbf364092006-03-01 04:25:17 +0000117 def test_interface_multi_arg(self):
118 # Make sure interface correct when multiple arguments given
119 arg_count = 3
120 args = tuple(range(arg_count))
121 exc = Exception(*args)
Ezio Melotti1f517e12010-02-02 17:34:37 +0000122 results = ([len(exc.args), arg_count], [exc.args, args],
123 [exc.message, ''], [str(exc), str(args)],
124 [unicode(exc), unicode(args)],
125 [repr(exc), exc.__class__.__name__ + repr(exc.args)],
126 [exc[-1], args[-1]])
127 self.interface_test_driver(results)
Brett Cannonbf364092006-03-01 04:25:17 +0000128
Ezio Melotti1f517e12010-02-02 17:34:37 +0000129 @ignore_deprecation_warnings
Brett Cannonbf364092006-03-01 04:25:17 +0000130 def test_interface_no_arg(self):
131 # Make sure that with no args that interface is correct
132 exc = Exception()
Ezio Melotti1f517e12010-02-02 17:34:37 +0000133 results = ([len(exc.args), 0], [exc.args, tuple()],
134 [exc.message, ''],
135 [str(exc), ''], [unicode(exc), u''],
136 [repr(exc), exc.__class__.__name__ + '()'], [True, True])
137 self.interface_test_driver(results)
Brett Cannon229cee22007-05-05 01:34:02 +0000138
139
140 def test_message_deprecation(self):
141 # As of Python 2.6, BaseException.message is deprecated.
Brett Cannon672237d2008-09-09 00:49:16 +0000142 with warnings.catch_warnings():
Brett Cannon229cee22007-05-05 01:34:02 +0000143 warnings.resetwarnings()
144 warnings.filterwarnings('error')
145
146 try:
147 BaseException().message
148 except DeprecationWarning:
149 pass
150 else:
151 self.fail("BaseException.message not deprecated")
152
Brett Cannonbf364092006-03-01 04:25:17 +0000153
154class UsageTests(unittest.TestCase):
155
156 """Test usage of exceptions"""
157
Brett Cannon6fbb96e2007-02-23 14:28:25 +0000158 def raise_fails(self, object_):
159 """Make sure that raising 'object_' triggers a TypeError."""
160 try:
161 raise object_
162 except TypeError:
163 return # What is expected.
164 self.fail("TypeError expected for raising %s" % type(object_))
165
166 def catch_fails(self, object_):
167 """Catching 'object_' should raise a TypeError."""
168 try:
169 try:
170 raise StandardError
171 except object_:
172 pass
173 except TypeError:
174 pass
175 except StandardError:
176 self.fail("TypeError expected when catching %s" % type(object_))
177
178 try:
179 try:
180 raise StandardError
181 except (object_,):
182 pass
183 except TypeError:
184 return
185 except StandardError:
186 self.fail("TypeError expected when catching %s as specified in a "
187 "tuple" % type(object_))
188
Ezio Melotti1f517e12010-02-02 17:34:37 +0000189 @ignore_deprecation_warnings
Brett Cannonbf364092006-03-01 04:25:17 +0000190 def test_raise_classic(self):
Brett Cannon129bd522007-01-30 21:34:36 +0000191 # Raising a classic class is okay (for now).
Brett Cannonbf364092006-03-01 04:25:17 +0000192 class ClassicClass:
193 pass
194 try:
195 raise ClassicClass
196 except ClassicClass:
197 pass
198 except:
199 self.fail("unable to raise classic class")
200 try:
201 raise ClassicClass()
202 except ClassicClass:
203 pass
204 except:
Ezio Melotti1f517e12010-02-02 17:34:37 +0000205 self.fail("unable to raise classic class instance")
Brett Cannonbf364092006-03-01 04:25:17 +0000206
207 def test_raise_new_style_non_exception(self):
Brett Cannon129bd522007-01-30 21:34:36 +0000208 # You cannot raise a new-style class that does not inherit from
209 # BaseException; the ability was not possible until BaseException's
210 # introduction so no need to support new-style objects that do not
211 # inherit from it.
Brett Cannonbf364092006-03-01 04:25:17 +0000212 class NewStyleClass(object):
213 pass
Brett Cannon6fbb96e2007-02-23 14:28:25 +0000214 self.raise_fails(NewStyleClass)
215 self.raise_fails(NewStyleClass())
Brett Cannonbf364092006-03-01 04:25:17 +0000216
217 def test_raise_string(self):
Brett Cannon129bd522007-01-30 21:34:36 +0000218 # Raising a string raises TypeError.
Brett Cannon6fbb96e2007-02-23 14:28:25 +0000219 self.raise_fails("spam")
Brett Cannonbf364092006-03-01 04:25:17 +0000220
221 def test_catch_string(self):
Brett Cannon129bd522007-01-30 21:34:36 +0000222 # Catching a string should trigger a DeprecationWarning.
Brett Cannon672237d2008-09-09 00:49:16 +0000223 with warnings.catch_warnings():
Brett Cannon129bd522007-01-30 21:34:36 +0000224 warnings.resetwarnings()
225 warnings.filterwarnings("error")
226 str_exc = "spam"
227 try:
228 try:
229 raise StandardError
230 except str_exc:
231 pass
232 except DeprecationWarning:
233 pass
234 except StandardError:
235 self.fail("catching a string exception did not raise "
236 "DeprecationWarning")
237 # Make sure that even if the string exception is listed in a tuple
238 # that a warning is raised.
239 try:
240 try:
241 raise StandardError
242 except (AssertionError, str_exc):
243 pass
244 except DeprecationWarning:
245 pass
246 except StandardError:
247 self.fail("catching a string exception specified in a tuple did "
248 "not raise DeprecationWarning")
249
Brett Cannonbf364092006-03-01 04:25:17 +0000250
251def test_main():
252 run_unittest(ExceptionClassTests, UsageTests)
253
254
255
256if __name__ == '__main__':
257 test_main()