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