blob: 5f578d26732b485ec343d1ef7a69c9b0baf47995 [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
Brett Cannon229cee22007-05-05 01:34:02 +00009def ignore_message_warning():
10 """Ignore the DeprecationWarning for BaseException.message."""
11 warnings.resetwarnings()
12 warnings.filterwarnings("ignore", "BaseException.message",
13 DeprecationWarning)
14
15
Brett Cannonbf364092006-03-01 04:25:17 +000016class ExceptionClassTests(unittest.TestCase):
17
18 """Tests for anything relating to exception objects themselves (e.g.,
19 inheritance hierarchy)"""
20
21 def test_builtins_new_style(self):
22 self.failUnless(issubclass(Exception, object))
23
24 def verify_instance_interface(self, ins):
Brett Cannon672237d2008-09-09 00:49:16 +000025 with warnings.catch_warnings():
Brett Cannon229cee22007-05-05 01:34:02 +000026 ignore_message_warning()
27 for attr in ("args", "message", "__str__", "__repr__",
28 "__getitem__"):
Georg Brandl19e79f72009-06-03 23:23:45 +000029 self.assertTrue(hasattr(ins, attr),
Brett Cannon229cee22007-05-05 01:34:02 +000030 "%s missing %s attribute" %
31 (ins.__class__.__name__, attr))
Brett Cannonbf364092006-03-01 04:25:17 +000032
33 def test_inheritance(self):
34 # Make sure the inheritance hierarchy matches the documentation
35 exc_set = set(x for x in dir(exceptions) if not x.startswith('_'))
36 inheritance_tree = open(os.path.join(os.path.split(__file__)[0],
37 'exception_hierarchy.txt'))
38 try:
39 superclass_name = inheritance_tree.readline().rstrip()
40 try:
41 last_exc = getattr(__builtin__, superclass_name)
42 except AttributeError:
43 self.fail("base class %s not a built-in" % superclass_name)
44 self.failUnless(superclass_name in exc_set)
45 exc_set.discard(superclass_name)
46 superclasses = [] # Loop will insert base exception
47 last_depth = 0
48 for exc_line in inheritance_tree:
49 exc_line = exc_line.rstrip()
50 depth = exc_line.rindex('-')
51 exc_name = exc_line[depth+2:] # Slice past space
52 if '(' in exc_name:
53 paren_index = exc_name.index('(')
54 platform_name = exc_name[paren_index+1:-1]
Brett Cannon6b4ed742006-03-01 06:10:48 +000055 exc_name = exc_name[:paren_index-1] # Slice off space
Brett Cannonbf364092006-03-01 04:25:17 +000056 if platform_system() != platform_name:
57 exc_set.discard(exc_name)
58 continue
59 if '[' in exc_name:
60 left_bracket = exc_name.index('[')
61 exc_name = exc_name[:left_bracket-1] # cover space
62 try:
63 exc = getattr(__builtin__, exc_name)
64 except AttributeError:
65 self.fail("%s not a built-in exception" % exc_name)
66 if last_depth < depth:
67 superclasses.append((last_depth, last_exc))
68 elif last_depth > depth:
69 while superclasses[-1][0] >= depth:
70 superclasses.pop()
71 self.failUnless(issubclass(exc, superclasses[-1][1]),
72 "%s is not a subclass of %s" % (exc.__name__,
73 superclasses[-1][1].__name__))
74 try: # Some exceptions require arguments; just skip them
75 self.verify_instance_interface(exc())
76 except TypeError:
77 pass
78 self.failUnless(exc_name in exc_set)
79 exc_set.discard(exc_name)
80 last_exc = exc
81 last_depth = depth
82 finally:
83 inheritance_tree.close()
84 self.failUnlessEqual(len(exc_set), 0, "%s not accounted for" % exc_set)
85
86 interface_tests = ("length", "args", "message", "str", "unicode", "repr",
87 "indexing")
88
89 def interface_test_driver(self, results):
90 for test_name, (given, expected) in zip(self.interface_tests, results):
Georg Brandl19e79f72009-06-03 23:23:45 +000091 self.assertEqual(given, expected, "%s: %s != %s" % (test_name,
Brett Cannonbf364092006-03-01 04:25:17 +000092 given, expected))
93
94 def test_interface_single_arg(self):
95 # Make sure interface works properly when given a single argument
96 arg = "spam"
97 exc = Exception(arg)
Brett Cannon672237d2008-09-09 00:49:16 +000098 with warnings.catch_warnings():
Brett Cannon229cee22007-05-05 01:34:02 +000099 ignore_message_warning()
100 results = ([len(exc.args), 1], [exc.args[0], arg],
101 [exc.message, arg],
102 [str(exc), str(arg)], [unicode(exc), unicode(arg)],
103 [repr(exc), exc.__class__.__name__ + repr(exc.args)], [exc[0],
104 arg])
105 self.interface_test_driver(results)
Brett Cannonbf364092006-03-01 04:25:17 +0000106
107 def test_interface_multi_arg(self):
108 # Make sure interface correct when multiple arguments given
109 arg_count = 3
110 args = tuple(range(arg_count))
111 exc = Exception(*args)
Brett Cannon672237d2008-09-09 00:49:16 +0000112 with warnings.catch_warnings():
Brett Cannon229cee22007-05-05 01:34:02 +0000113 ignore_message_warning()
114 results = ([len(exc.args), arg_count], [exc.args, args],
115 [exc.message, ''], [str(exc), str(args)],
116 [unicode(exc), unicode(args)],
117 [repr(exc), exc.__class__.__name__ + repr(exc.args)],
118 [exc[-1], args[-1]])
119 self.interface_test_driver(results)
Brett Cannonbf364092006-03-01 04:25:17 +0000120
121 def test_interface_no_arg(self):
122 # Make sure that with no args that interface is correct
123 exc = Exception()
Brett Cannon672237d2008-09-09 00:49:16 +0000124 with warnings.catch_warnings():
Brett Cannon229cee22007-05-05 01:34:02 +0000125 ignore_message_warning()
126 results = ([len(exc.args), 0], [exc.args, tuple()],
127 [exc.message, ''],
128 [str(exc), ''], [unicode(exc), u''],
129 [repr(exc), exc.__class__.__name__ + '()'], [True, True])
130 self.interface_test_driver(results)
131
132
133 def test_message_deprecation(self):
134 # As of Python 2.6, BaseException.message is deprecated.
Brett Cannon672237d2008-09-09 00:49:16 +0000135 with warnings.catch_warnings():
Brett Cannon229cee22007-05-05 01:34:02 +0000136 warnings.resetwarnings()
137 warnings.filterwarnings('error')
138
139 try:
140 BaseException().message
141 except DeprecationWarning:
142 pass
143 else:
144 self.fail("BaseException.message not deprecated")
145
146 exc = BaseException()
147 try:
148 exc.message = ''
149 except DeprecationWarning:
150 pass
151 else:
152 self.fail("BaseException.message assignment not deprecated")
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
Brett Cannonbf364092006-03-01 04:25:17 +0000189 def test_raise_classic(self):
Brett Cannon129bd522007-01-30 21:34:36 +0000190 # Raising a classic class is okay (for now).
Brett Cannonbf364092006-03-01 04:25:17 +0000191 class ClassicClass:
192 pass
193 try:
194 raise ClassicClass
195 except ClassicClass:
196 pass
197 except:
198 self.fail("unable to raise classic class")
199 try:
200 raise ClassicClass()
201 except ClassicClass:
202 pass
203 except:
204 self.fail("unable to raise class class instance")
205
206 def test_raise_new_style_non_exception(self):
Brett Cannon129bd522007-01-30 21:34:36 +0000207 # You cannot raise a new-style class that does not inherit from
208 # BaseException; the ability was not possible until BaseException's
209 # introduction so no need to support new-style objects that do not
210 # inherit from it.
Brett Cannonbf364092006-03-01 04:25:17 +0000211 class NewStyleClass(object):
212 pass
Brett Cannon6fbb96e2007-02-23 14:28:25 +0000213 self.raise_fails(NewStyleClass)
214 self.raise_fails(NewStyleClass())
Brett Cannonbf364092006-03-01 04:25:17 +0000215
216 def test_raise_string(self):
Brett Cannon129bd522007-01-30 21:34:36 +0000217 # Raising a string raises TypeError.
Brett Cannon6fbb96e2007-02-23 14:28:25 +0000218 self.raise_fails("spam")
Brett Cannonbf364092006-03-01 04:25:17 +0000219
220 def test_catch_string(self):
Brett Cannon129bd522007-01-30 21:34:36 +0000221 # Catching a string should trigger a DeprecationWarning.
Brett Cannon672237d2008-09-09 00:49:16 +0000222 with warnings.catch_warnings():
Brett Cannon129bd522007-01-30 21:34:36 +0000223 warnings.resetwarnings()
224 warnings.filterwarnings("error")
225 str_exc = "spam"
226 try:
227 try:
228 raise StandardError
229 except str_exc:
230 pass
231 except DeprecationWarning:
232 pass
233 except StandardError:
234 self.fail("catching a string exception did not raise "
235 "DeprecationWarning")
236 # Make sure that even if the string exception is listed in a tuple
237 # that a warning is raised.
238 try:
239 try:
240 raise StandardError
241 except (AssertionError, str_exc):
242 pass
243 except DeprecationWarning:
244 pass
245 except StandardError:
246 self.fail("catching a string exception specified in a tuple did "
247 "not raise DeprecationWarning")
248
Brett Cannonbf364092006-03-01 04:25:17 +0000249
250def test_main():
251 run_unittest(ExceptionClassTests, UsageTests)
252
253
254
255if __name__ == '__main__':
256 test_main()