blob: 3f23af5addeb68254e3d1148ac4dcf245bd600d9 [file] [log] [blame]
Brett Cannonbf364092006-03-01 04:25:17 +00001import unittest
2import __builtin__
3import exceptions
4import warnings
Ezio Melotti1d55ec32010-08-02 23:34:49 +00005from test.test_support import run_unittest, check_warnings
Brett Cannonbf364092006-03-01 04:25:17 +00006import os
Ezio Melotti38a58002010-08-02 03:14:27 +00007import sys
Brett Cannonbf364092006-03-01 04:25:17 +00008from platform import system as platform_system
9
Ezio Melotti38a58002010-08-02 03:14:27 +000010DEPRECATION_WARNINGS = ["BaseException.message has been deprecated"]
Brett Cannon229cee22007-05-05 01:34:02 +000011
Ezio Melotti38a58002010-08-02 03:14:27 +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
Ezio Melotti1d55ec32010-08-02 23:34:49 +000018_deprecations = [(msg, DeprecationWarning) for msg in DEPRECATION_WARNINGS]
19
Ezio Melotti38a58002010-08-02 03:14:27 +000020# Silence Py3k and other deprecation warnings
21def ignore_deprecation_warnings(func):
22 """Ignore the known DeprecationWarnings."""
23 def wrapper(*args, **kw):
Ezio Melotti1d55ec32010-08-02 23:34:49 +000024 with check_warnings(*_deprecations, quiet=True):
Ezio Melotti38a58002010-08-02 03:14:27 +000025 return func(*args, **kw)
26 return wrapper
Brett Cannon229cee22007-05-05 01:34:02 +000027
Brett Cannonbf364092006-03-01 04:25:17 +000028class ExceptionClassTests(unittest.TestCase):
29
30 """Tests for anything relating to exception objects themselves (e.g.,
31 inheritance hierarchy)"""
32
33 def test_builtins_new_style(self):
34 self.failUnless(issubclass(Exception, object))
35
Ezio Melotti38a58002010-08-02 03:14:27 +000036 @ignore_deprecation_warnings
Brett Cannonbf364092006-03-01 04:25:17 +000037 def verify_instance_interface(self, ins):
Ezio Melotti38a58002010-08-02 03:14:27 +000038 for attr in ("args", "message", "__str__", "__repr__", "__getitem__"):
39 self.assertTrue(hasattr(ins, attr),
40 "%s missing %s attribute" %
Brett Cannon229cee22007-05-05 01:34:02 +000041 (ins.__class__.__name__, attr))
Brett Cannonbf364092006-03-01 04:25:17 +000042
43 def test_inheritance(self):
44 # Make sure the inheritance hierarchy matches the documentation
45 exc_set = set(x for x in dir(exceptions) if not x.startswith('_'))
46 inheritance_tree = open(os.path.join(os.path.split(__file__)[0],
47 'exception_hierarchy.txt'))
48 try:
49 superclass_name = inheritance_tree.readline().rstrip()
50 try:
51 last_exc = getattr(__builtin__, superclass_name)
52 except AttributeError:
53 self.fail("base class %s not a built-in" % superclass_name)
54 self.failUnless(superclass_name in exc_set)
55 exc_set.discard(superclass_name)
56 superclasses = [] # Loop will insert base exception
57 last_depth = 0
58 for exc_line in inheritance_tree:
59 exc_line = exc_line.rstrip()
60 depth = exc_line.rindex('-')
61 exc_name = exc_line[depth+2:] # Slice past space
62 if '(' in exc_name:
63 paren_index = exc_name.index('(')
64 platform_name = exc_name[paren_index+1:-1]
Brett Cannon6b4ed742006-03-01 06:10:48 +000065 exc_name = exc_name[:paren_index-1] # Slice off space
Brett Cannonbf364092006-03-01 04:25:17 +000066 if platform_system() != platform_name:
67 exc_set.discard(exc_name)
68 continue
69 if '[' in exc_name:
70 left_bracket = exc_name.index('[')
71 exc_name = exc_name[:left_bracket-1] # cover space
72 try:
73 exc = getattr(__builtin__, exc_name)
74 except AttributeError:
75 self.fail("%s not a built-in exception" % exc_name)
76 if last_depth < depth:
77 superclasses.append((last_depth, last_exc))
78 elif last_depth > depth:
79 while superclasses[-1][0] >= depth:
80 superclasses.pop()
81 self.failUnless(issubclass(exc, superclasses[-1][1]),
82 "%s is not a subclass of %s" % (exc.__name__,
83 superclasses[-1][1].__name__))
84 try: # Some exceptions require arguments; just skip them
85 self.verify_instance_interface(exc())
86 except TypeError:
87 pass
88 self.failUnless(exc_name in exc_set)
89 exc_set.discard(exc_name)
90 last_exc = exc
91 last_depth = depth
92 finally:
93 inheritance_tree.close()
94 self.failUnlessEqual(len(exc_set), 0, "%s not accounted for" % exc_set)
95
96 interface_tests = ("length", "args", "message", "str", "unicode", "repr",
97 "indexing")
98
99 def interface_test_driver(self, results):
100 for test_name, (given, expected) in zip(self.interface_tests, results):
101 self.failUnlessEqual(given, expected, "%s: %s != %s" % (test_name,
102 given, expected))
103
Ezio Melotti38a58002010-08-02 03:14:27 +0000104 @ignore_deprecation_warnings
Brett Cannonbf364092006-03-01 04:25:17 +0000105 def test_interface_single_arg(self):
106 # Make sure interface works properly when given a single argument
107 arg = "spam"
108 exc = Exception(arg)
Ezio Melotti38a58002010-08-02 03:14:27 +0000109 results = ([len(exc.args), 1], [exc.args[0], arg], [exc.message, arg],
110 [str(exc), str(arg)], [unicode(exc), unicode(arg)],
111 [repr(exc), exc.__class__.__name__ + repr(exc.args)],
112 [exc[0], arg])
113 self.interface_test_driver(results)
Brett Cannonbf364092006-03-01 04:25:17 +0000114
Ezio Melotti38a58002010-08-02 03:14:27 +0000115 @ignore_deprecation_warnings
Brett Cannonbf364092006-03-01 04:25:17 +0000116 def test_interface_multi_arg(self):
117 # Make sure interface correct when multiple arguments given
118 arg_count = 3
119 args = tuple(range(arg_count))
120 exc = Exception(*args)
Ezio Melotti38a58002010-08-02 03:14:27 +0000121 results = ([len(exc.args), arg_count], [exc.args, args],
122 [exc.message, ''], [str(exc), str(args)],
123 [unicode(exc), unicode(args)],
124 [repr(exc), exc.__class__.__name__ + repr(exc.args)],
125 [exc[-1], args[-1]])
126 self.interface_test_driver(results)
Brett Cannonbf364092006-03-01 04:25:17 +0000127
Ezio Melotti38a58002010-08-02 03:14:27 +0000128 @ignore_deprecation_warnings
Brett Cannonbf364092006-03-01 04:25:17 +0000129 def test_interface_no_arg(self):
130 # Make sure that with no args that interface is correct
131 exc = Exception()
Ezio Melotti38a58002010-08-02 03:14:27 +0000132 results = ([len(exc.args), 0], [exc.args, tuple()],
133 [exc.message, ''],
134 [str(exc), ''], [unicode(exc), u''],
135 [repr(exc), exc.__class__.__name__ + '()'], [True, True])
136 self.interface_test_driver(results)
Brett Cannon229cee22007-05-05 01:34:02 +0000137
138
139 def test_message_deprecation(self):
140 # As of Python 2.6, BaseException.message is deprecated.
Ezio Melotti1d55ec32010-08-02 23:34:49 +0000141 with check_warnings(("", DeprecationWarning)):
142 BaseException().message
Brett Cannon229cee22007-05-05 01:34:02 +0000143
Brett Cannonbf364092006-03-01 04:25:17 +0000144
145class UsageTests(unittest.TestCase):
146
147 """Test usage of exceptions"""
148
Brett Cannon6fbb96e2007-02-23 14:28:25 +0000149 def raise_fails(self, object_):
150 """Make sure that raising 'object_' triggers a TypeError."""
151 try:
152 raise object_
153 except TypeError:
154 return # What is expected.
155 self.fail("TypeError expected for raising %s" % type(object_))
156
157 def catch_fails(self, object_):
158 """Catching 'object_' should raise a TypeError."""
159 try:
160 try:
161 raise StandardError
162 except object_:
163 pass
164 except TypeError:
165 pass
166 except StandardError:
167 self.fail("TypeError expected when catching %s" % type(object_))
168
169 try:
170 try:
171 raise StandardError
172 except (object_,):
173 pass
174 except TypeError:
175 return
176 except StandardError:
177 self.fail("TypeError expected when catching %s as specified in a "
178 "tuple" % type(object_))
179
Ezio Melotti38a58002010-08-02 03:14:27 +0000180 @ignore_deprecation_warnings
Brett Cannonbf364092006-03-01 04:25:17 +0000181 def test_raise_classic(self):
Brett Cannon129bd522007-01-30 21:34:36 +0000182 # Raising a classic class is okay (for now).
Brett Cannonbf364092006-03-01 04:25:17 +0000183 class ClassicClass:
184 pass
185 try:
186 raise ClassicClass
187 except ClassicClass:
188 pass
189 except:
190 self.fail("unable to raise classic class")
191 try:
192 raise ClassicClass()
193 except ClassicClass:
194 pass
195 except:
Ezio Melotti38a58002010-08-02 03:14:27 +0000196 self.fail("unable to raise classic class instance")
Brett Cannonbf364092006-03-01 04:25:17 +0000197
198 def test_raise_new_style_non_exception(self):
Brett Cannon129bd522007-01-30 21:34:36 +0000199 # You cannot raise a new-style class that does not inherit from
200 # BaseException; the ability was not possible until BaseException's
201 # introduction so no need to support new-style objects that do not
202 # inherit from it.
Brett Cannonbf364092006-03-01 04:25:17 +0000203 class NewStyleClass(object):
204 pass
Brett Cannon6fbb96e2007-02-23 14:28:25 +0000205 self.raise_fails(NewStyleClass)
206 self.raise_fails(NewStyleClass())
Brett Cannonbf364092006-03-01 04:25:17 +0000207
208 def test_raise_string(self):
Brett Cannon129bd522007-01-30 21:34:36 +0000209 # Raising a string raises TypeError.
Brett Cannon6fbb96e2007-02-23 14:28:25 +0000210 self.raise_fails("spam")
Brett Cannonbf364092006-03-01 04:25:17 +0000211
212 def test_catch_string(self):
Brett Cannon129bd522007-01-30 21:34:36 +0000213 # Catching a string should trigger a DeprecationWarning.
Brett Cannon672237d2008-09-09 00:49:16 +0000214 with warnings.catch_warnings():
Brett Cannon129bd522007-01-30 21:34:36 +0000215 warnings.resetwarnings()
216 warnings.filterwarnings("error")
217 str_exc = "spam"
218 try:
219 try:
220 raise StandardError
221 except str_exc:
222 pass
223 except DeprecationWarning:
224 pass
225 except StandardError:
226 self.fail("catching a string exception did not raise "
227 "DeprecationWarning")
228 # Make sure that even if the string exception is listed in a tuple
229 # that a warning is raised.
230 try:
231 try:
232 raise StandardError
233 except (AssertionError, str_exc):
234 pass
235 except DeprecationWarning:
236 pass
237 except StandardError:
238 self.fail("catching a string exception specified in a tuple did "
239 "not raise DeprecationWarning")
240
Brett Cannonbf364092006-03-01 04:25:17 +0000241
242def test_main():
243 run_unittest(ExceptionClassTests, UsageTests)
244
245
246
247if __name__ == '__main__':
248 test_main()