1 | n/a | import unittest |
---|
2 | n/a | import builtins |
---|
3 | n/a | import os |
---|
4 | n/a | from platform import system as platform_system |
---|
5 | n/a | |
---|
6 | n/a | |
---|
7 | n/a | class ExceptionClassTests(unittest.TestCase): |
---|
8 | n/a | |
---|
9 | n/a | """Tests for anything relating to exception objects themselves (e.g., |
---|
10 | n/a | inheritance hierarchy)""" |
---|
11 | n/a | |
---|
12 | n/a | def test_builtins_new_style(self): |
---|
13 | n/a | self.assertTrue(issubclass(Exception, object)) |
---|
14 | n/a | |
---|
15 | n/a | def verify_instance_interface(self, ins): |
---|
16 | n/a | for attr in ("args", "__str__", "__repr__"): |
---|
17 | n/a | self.assertTrue(hasattr(ins, attr), |
---|
18 | n/a | "%s missing %s attribute" % |
---|
19 | n/a | (ins.__class__.__name__, attr)) |
---|
20 | n/a | |
---|
21 | n/a | def test_inheritance(self): |
---|
22 | n/a | # Make sure the inheritance hierarchy matches the documentation |
---|
23 | n/a | exc_set = set() |
---|
24 | n/a | for object_ in builtins.__dict__.values(): |
---|
25 | n/a | try: |
---|
26 | n/a | if issubclass(object_, BaseException): |
---|
27 | n/a | exc_set.add(object_.__name__) |
---|
28 | n/a | except TypeError: |
---|
29 | n/a | pass |
---|
30 | n/a | |
---|
31 | n/a | inheritance_tree = open(os.path.join(os.path.split(__file__)[0], |
---|
32 | n/a | 'exception_hierarchy.txt')) |
---|
33 | n/a | try: |
---|
34 | n/a | superclass_name = inheritance_tree.readline().rstrip() |
---|
35 | n/a | try: |
---|
36 | n/a | last_exc = getattr(builtins, superclass_name) |
---|
37 | n/a | except AttributeError: |
---|
38 | n/a | self.fail("base class %s not a built-in" % superclass_name) |
---|
39 | n/a | self.assertIn(superclass_name, exc_set, |
---|
40 | n/a | '%s not found' % superclass_name) |
---|
41 | n/a | exc_set.discard(superclass_name) |
---|
42 | n/a | superclasses = [] # Loop will insert base exception |
---|
43 | n/a | last_depth = 0 |
---|
44 | n/a | for exc_line in inheritance_tree: |
---|
45 | n/a | exc_line = exc_line.rstrip() |
---|
46 | n/a | depth = exc_line.rindex('-') |
---|
47 | n/a | exc_name = exc_line[depth+2:] # Slice past space |
---|
48 | n/a | if '(' in exc_name: |
---|
49 | n/a | paren_index = exc_name.index('(') |
---|
50 | n/a | platform_name = exc_name[paren_index+1:-1] |
---|
51 | n/a | exc_name = exc_name[:paren_index-1] # Slice off space |
---|
52 | n/a | if platform_system() != platform_name: |
---|
53 | n/a | exc_set.discard(exc_name) |
---|
54 | n/a | continue |
---|
55 | n/a | if '[' in exc_name: |
---|
56 | n/a | left_bracket = exc_name.index('[') |
---|
57 | n/a | exc_name = exc_name[:left_bracket-1] # cover space |
---|
58 | n/a | try: |
---|
59 | n/a | exc = getattr(builtins, exc_name) |
---|
60 | n/a | except AttributeError: |
---|
61 | n/a | self.fail("%s not a built-in exception" % exc_name) |
---|
62 | n/a | if last_depth < depth: |
---|
63 | n/a | superclasses.append((last_depth, last_exc)) |
---|
64 | n/a | elif last_depth > depth: |
---|
65 | n/a | while superclasses[-1][0] >= depth: |
---|
66 | n/a | superclasses.pop() |
---|
67 | n/a | self.assertTrue(issubclass(exc, superclasses[-1][1]), |
---|
68 | n/a | "%s is not a subclass of %s" % (exc.__name__, |
---|
69 | n/a | superclasses[-1][1].__name__)) |
---|
70 | n/a | try: # Some exceptions require arguments; just skip them |
---|
71 | n/a | self.verify_instance_interface(exc()) |
---|
72 | n/a | except TypeError: |
---|
73 | n/a | pass |
---|
74 | n/a | self.assertIn(exc_name, exc_set) |
---|
75 | n/a | exc_set.discard(exc_name) |
---|
76 | n/a | last_exc = exc |
---|
77 | n/a | last_depth = depth |
---|
78 | n/a | finally: |
---|
79 | n/a | inheritance_tree.close() |
---|
80 | n/a | self.assertEqual(len(exc_set), 0, "%s not accounted for" % exc_set) |
---|
81 | n/a | |
---|
82 | n/a | interface_tests = ("length", "args", "str", "repr") |
---|
83 | n/a | |
---|
84 | n/a | def interface_test_driver(self, results): |
---|
85 | n/a | for test_name, (given, expected) in zip(self.interface_tests, results): |
---|
86 | n/a | self.assertEqual(given, expected, "%s: %s != %s" % (test_name, |
---|
87 | n/a | given, expected)) |
---|
88 | n/a | |
---|
89 | n/a | def test_interface_single_arg(self): |
---|
90 | n/a | # Make sure interface works properly when given a single argument |
---|
91 | n/a | arg = "spam" |
---|
92 | n/a | exc = Exception(arg) |
---|
93 | n/a | results = ([len(exc.args), 1], [exc.args[0], arg], |
---|
94 | n/a | [str(exc), str(arg)], |
---|
95 | n/a | [repr(exc), exc.__class__.__name__ + repr(exc.args)]) |
---|
96 | n/a | self.interface_test_driver(results) |
---|
97 | n/a | |
---|
98 | n/a | def test_interface_multi_arg(self): |
---|
99 | n/a | # Make sure interface correct when multiple arguments given |
---|
100 | n/a | arg_count = 3 |
---|
101 | n/a | args = tuple(range(arg_count)) |
---|
102 | n/a | exc = Exception(*args) |
---|
103 | n/a | results = ([len(exc.args), arg_count], [exc.args, args], |
---|
104 | n/a | [str(exc), str(args)], |
---|
105 | n/a | [repr(exc), exc.__class__.__name__ + repr(exc.args)]) |
---|
106 | n/a | self.interface_test_driver(results) |
---|
107 | n/a | |
---|
108 | n/a | def test_interface_no_arg(self): |
---|
109 | n/a | # Make sure that with no args that interface is correct |
---|
110 | n/a | exc = Exception() |
---|
111 | n/a | results = ([len(exc.args), 0], [exc.args, tuple()], |
---|
112 | n/a | [str(exc), ''], |
---|
113 | n/a | [repr(exc), exc.__class__.__name__ + '()']) |
---|
114 | n/a | self.interface_test_driver(results) |
---|
115 | n/a | |
---|
116 | n/a | class UsageTests(unittest.TestCase): |
---|
117 | n/a | |
---|
118 | n/a | """Test usage of exceptions""" |
---|
119 | n/a | |
---|
120 | n/a | def raise_fails(self, object_): |
---|
121 | n/a | """Make sure that raising 'object_' triggers a TypeError.""" |
---|
122 | n/a | try: |
---|
123 | n/a | raise object_ |
---|
124 | n/a | except TypeError: |
---|
125 | n/a | return # What is expected. |
---|
126 | n/a | self.fail("TypeError expected for raising %s" % type(object_)) |
---|
127 | n/a | |
---|
128 | n/a | def catch_fails(self, object_): |
---|
129 | n/a | """Catching 'object_' should raise a TypeError.""" |
---|
130 | n/a | try: |
---|
131 | n/a | try: |
---|
132 | n/a | raise Exception |
---|
133 | n/a | except object_: |
---|
134 | n/a | pass |
---|
135 | n/a | except TypeError: |
---|
136 | n/a | pass |
---|
137 | n/a | except Exception: |
---|
138 | n/a | self.fail("TypeError expected when catching %s" % type(object_)) |
---|
139 | n/a | |
---|
140 | n/a | try: |
---|
141 | n/a | try: |
---|
142 | n/a | raise Exception |
---|
143 | n/a | except (object_,): |
---|
144 | n/a | pass |
---|
145 | n/a | except TypeError: |
---|
146 | n/a | return |
---|
147 | n/a | except Exception: |
---|
148 | n/a | self.fail("TypeError expected when catching %s as specified in a " |
---|
149 | n/a | "tuple" % type(object_)) |
---|
150 | n/a | |
---|
151 | n/a | def test_raise_new_style_non_exception(self): |
---|
152 | n/a | # You cannot raise a new-style class that does not inherit from |
---|
153 | n/a | # BaseException; the ability was not possible until BaseException's |
---|
154 | n/a | # introduction so no need to support new-style objects that do not |
---|
155 | n/a | # inherit from it. |
---|
156 | n/a | class NewStyleClass(object): |
---|
157 | n/a | pass |
---|
158 | n/a | self.raise_fails(NewStyleClass) |
---|
159 | n/a | self.raise_fails(NewStyleClass()) |
---|
160 | n/a | |
---|
161 | n/a | def test_raise_string(self): |
---|
162 | n/a | # Raising a string raises TypeError. |
---|
163 | n/a | self.raise_fails("spam") |
---|
164 | n/a | |
---|
165 | n/a | def test_catch_non_BaseException(self): |
---|
166 | n/a | # Tryinng to catch an object that does not inherit from BaseException |
---|
167 | n/a | # is not allowed. |
---|
168 | n/a | class NonBaseException(object): |
---|
169 | n/a | pass |
---|
170 | n/a | self.catch_fails(NonBaseException) |
---|
171 | n/a | self.catch_fails(NonBaseException()) |
---|
172 | n/a | |
---|
173 | n/a | def test_catch_BaseException_instance(self): |
---|
174 | n/a | # Catching an instance of a BaseException subclass won't work. |
---|
175 | n/a | self.catch_fails(BaseException()) |
---|
176 | n/a | |
---|
177 | n/a | def test_catch_string(self): |
---|
178 | n/a | # Catching a string is bad. |
---|
179 | n/a | self.catch_fails("spam") |
---|
180 | n/a | |
---|
181 | n/a | |
---|
182 | n/a | if __name__ == '__main__': |
---|
183 | n/a | unittest.main() |
---|