blob: 88b3136651e88383a2285f555b1db1617156376b [file] [log] [blame]
Brett Cannonbf364092006-03-01 04:25:17 +00001import unittest
2import __builtin__
3import exceptions
4import warnings
Florent Xicluna6257a7b2010-03-31 22:01:03 +00005from test.test_support import run_unittest, check_warnings
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
Florent Xicluna6257a7b2010-03-31 22:01:03 +000018_deprecations = [(msg, DeprecationWarning) for msg in DEPRECATION_WARNINGS]
19
Ezio Melotti1f517e12010-02-02 17:34:37 +000020# Silence Py3k and other deprecation warnings
21def ignore_deprecation_warnings(func):
22 """Ignore the known DeprecationWarnings."""
23 def wrapper(*args, **kw):
Florent Xicluna6257a7b2010-03-31 22:01:03 +000024 with check_warnings(*_deprecations, quiet=True):
Ezio Melotti1f517e12010-02-02 17:34:37 +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):
Benjamin Peterson5c8da862009-06-30 22:57:08 +000034 self.assertTrue(issubclass(Exception, object))
Brett Cannonbf364092006-03-01 04:25:17 +000035
Ezio Melotti1f517e12010-02-02 17:34:37 +000036 @ignore_deprecation_warnings
Brett Cannonbf364092006-03-01 04:25:17 +000037 def verify_instance_interface(self, ins):
Ezio Melotti1f517e12010-02-02 17:34:37 +000038 for attr in ("args", "message", "__str__", "__repr__", "__getitem__"):
39 self.assertTrue(hasattr(ins, attr),
40 "%s missing %s attribute" %
Senthil Kumarance8e33a2010-01-08 19:04:16 +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)
Ezio Melottiaa980582010-01-23 23:04:36 +000054 self.assertIn(superclass_name, exc_set)
Brett Cannonbf364092006-03-01 04:25:17 +000055 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()
Benjamin Peterson5c8da862009-06-30 22:57:08 +000081 self.assertTrue(issubclass(exc, superclasses[-1][1]),
Brett Cannonbf364092006-03-01 04:25:17 +000082 "%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
Ezio Melottiaa980582010-01-23 23:04:36 +000088 self.assertIn(exc_name, exc_set)
Brett Cannonbf364092006-03-01 04:25:17 +000089 exc_set.discard(exc_name)
90 last_exc = exc
91 last_depth = depth
92 finally:
93 inheritance_tree.close()
Benjamin Peterson5c8da862009-06-30 22:57:08 +000094 self.assertEqual(len(exc_set), 0, "%s not accounted for" % exc_set)
Brett Cannonbf364092006-03-01 04:25:17 +000095
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):
Georg Brandl19e79f72009-06-03 23:23:45 +0000101 self.assertEqual(given, expected, "%s: %s != %s" % (test_name,
Brett Cannonbf364092006-03-01 04:25:17 +0000102 given, expected))
103
Ezio Melotti1f517e12010-02-02 17:34:37 +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 Melotti1f517e12010-02-02 17:34:37 +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 Melotti1f517e12010-02-02 17:34:37 +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 Melotti1f517e12010-02-02 17:34:37 +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 Melotti1f517e12010-02-02 17:34:37 +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 Melotti1f517e12010-02-02 17:34:37 +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.
Florent Xicluna6257a7b2010-03-31 22:01:03 +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 Melotti1f517e12010-02-02 17:34:37 +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 Melotti1f517e12010-02-02 17:34:37 +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"
Florent Xicluna6257a7b2010-03-31 22:01:03 +0000218 with self.assertRaises(DeprecationWarning):
Brett Cannon129bd522007-01-30 21:34:36 +0000219 try:
220 raise StandardError
221 except str_exc:
222 pass
Florent Xicluna6257a7b2010-03-31 22:01:03 +0000223
Brett Cannon129bd522007-01-30 21:34:36 +0000224 # Make sure that even if the string exception is listed in a tuple
225 # that a warning is raised.
Florent Xicluna6257a7b2010-03-31 22:01:03 +0000226 with self.assertRaises(DeprecationWarning):
Brett Cannon129bd522007-01-30 21:34:36 +0000227 try:
228 raise StandardError
229 except (AssertionError, str_exc):
230 pass
Brett Cannon129bd522007-01-30 21:34:36 +0000231
Brett Cannonbf364092006-03-01 04:25:17 +0000232
233def test_main():
234 run_unittest(ExceptionClassTests, UsageTests)
235
236
237
238if __name__ == '__main__':
239 test_main()