python-2.5.2/win32/Lib/test/test_isinstance.py
changeset 0 ae805ac0140d
equal deleted inserted replaced
-1:000000000000 0:ae805ac0140d
       
     1 # Tests some corner cases with isinstance() and issubclass().  While these
       
     2 # tests use new style classes and properties, they actually do whitebox
       
     3 # testing of error conditions uncovered when using extension types.
       
     4 
       
     5 import unittest
       
     6 from test import test_support
       
     7 import sys
       
     8 
       
     9 
       
    10 
       
    11 class TestIsInstanceExceptions(unittest.TestCase):
       
    12     # Test to make sure that an AttributeError when accessing the instance's
       
    13     # class's bases is masked.  This was actually a bug in Python 2.2 and
       
    14     # 2.2.1 where the exception wasn't caught but it also wasn't being cleared
       
    15     # (leading to an "undetected error" in the debug build).  Set up is,
       
    16     # isinstance(inst, cls) where:
       
    17     #
       
    18     # - inst isn't an InstanceType
       
    19     # - cls isn't a ClassType, a TypeType, or a TupleType
       
    20     # - cls has a __bases__ attribute
       
    21     # - inst has a __class__ attribute
       
    22     # - inst.__class__ as no __bases__ attribute
       
    23     #
       
    24     # Sounds complicated, I know, but this mimics a situation where an
       
    25     # extension type raises an AttributeError when its __bases__ attribute is
       
    26     # gotten.  In that case, isinstance() should return False.
       
    27     def test_class_has_no_bases(self):
       
    28         class I(object):
       
    29             def getclass(self):
       
    30                 # This must return an object that has no __bases__ attribute
       
    31                 return None
       
    32             __class__ = property(getclass)
       
    33 
       
    34         class C(object):
       
    35             def getbases(self):
       
    36                 return ()
       
    37             __bases__ = property(getbases)
       
    38 
       
    39         self.assertEqual(False, isinstance(I(), C()))
       
    40 
       
    41     # Like above except that inst.__class__.__bases__ raises an exception
       
    42     # other than AttributeError
       
    43     def test_bases_raises_other_than_attribute_error(self):
       
    44         class E(object):
       
    45             def getbases(self):
       
    46                 raise RuntimeError
       
    47             __bases__ = property(getbases)
       
    48 
       
    49         class I(object):
       
    50             def getclass(self):
       
    51                 return E()
       
    52             __class__ = property(getclass)
       
    53 
       
    54         class C(object):
       
    55             def getbases(self):
       
    56                 return ()
       
    57             __bases__ = property(getbases)
       
    58 
       
    59         self.assertRaises(RuntimeError, isinstance, I(), C())
       
    60 
       
    61     # Here's a situation where getattr(cls, '__bases__') raises an exception.
       
    62     # If that exception is not AttributeError, it should not get masked
       
    63     def test_dont_mask_non_attribute_error(self):
       
    64         class I: pass
       
    65 
       
    66         class C(object):
       
    67             def getbases(self):
       
    68                 raise RuntimeError
       
    69             __bases__ = property(getbases)
       
    70 
       
    71         self.assertRaises(RuntimeError, isinstance, I(), C())
       
    72 
       
    73     # Like above, except that getattr(cls, '__bases__') raises an
       
    74     # AttributeError, which /should/ get masked as a TypeError
       
    75     def test_mask_attribute_error(self):
       
    76         class I: pass
       
    77 
       
    78         class C(object):
       
    79             def getbases(self):
       
    80                 raise AttributeError
       
    81             __bases__ = property(getbases)
       
    82 
       
    83         self.assertRaises(TypeError, isinstance, I(), C())
       
    84 
       
    85 
       
    86 
       
    87 # These tests are similar to above, but tickle certain code paths in
       
    88 # issubclass() instead of isinstance() -- really PyObject_IsSubclass()
       
    89 # vs. PyObject_IsInstance().
       
    90 class TestIsSubclassExceptions(unittest.TestCase):
       
    91     def test_dont_mask_non_attribute_error(self):
       
    92         class C(object):
       
    93             def getbases(self):
       
    94                 raise RuntimeError
       
    95             __bases__ = property(getbases)
       
    96 
       
    97         class S(C): pass
       
    98 
       
    99         self.assertRaises(RuntimeError, issubclass, C(), S())
       
   100 
       
   101     def test_mask_attribute_error(self):
       
   102         class C(object):
       
   103             def getbases(self):
       
   104                 raise AttributeError
       
   105             __bases__ = property(getbases)
       
   106 
       
   107         class S(C): pass
       
   108 
       
   109         self.assertRaises(TypeError, issubclass, C(), S())
       
   110 
       
   111     # Like above, but test the second branch, where the __bases__ of the
       
   112     # second arg (the cls arg) is tested.  This means the first arg must
       
   113     # return a valid __bases__, and it's okay for it to be a normal --
       
   114     # unrelated by inheritance -- class.
       
   115     def test_dont_mask_non_attribute_error_in_cls_arg(self):
       
   116         class B: pass
       
   117 
       
   118         class C(object):
       
   119             def getbases(self):
       
   120                 raise RuntimeError
       
   121             __bases__ = property(getbases)
       
   122 
       
   123         self.assertRaises(RuntimeError, issubclass, B, C())
       
   124 
       
   125     def test_mask_attribute_error_in_cls_arg(self):
       
   126         class B: pass
       
   127 
       
   128         class C(object):
       
   129             def getbases(self):
       
   130                 raise AttributeError
       
   131             __bases__ = property(getbases)
       
   132 
       
   133         self.assertRaises(TypeError, issubclass, B, C())
       
   134 
       
   135 
       
   136 
       
   137 # meta classes for creating abstract classes and instances
       
   138 class AbstractClass(object):
       
   139     def __init__(self, bases):
       
   140         self.bases = bases
       
   141 
       
   142     def getbases(self):
       
   143         return self.bases
       
   144     __bases__ = property(getbases)
       
   145 
       
   146     def __call__(self):
       
   147         return AbstractInstance(self)
       
   148 
       
   149 class AbstractInstance(object):
       
   150     def __init__(self, klass):
       
   151         self.klass = klass
       
   152 
       
   153     def getclass(self):
       
   154         return self.klass
       
   155     __class__ = property(getclass)
       
   156 
       
   157 # abstract classes
       
   158 AbstractSuper = AbstractClass(bases=())
       
   159 
       
   160 AbstractChild = AbstractClass(bases=(AbstractSuper,))
       
   161 
       
   162 # normal classes
       
   163 class Super:
       
   164     pass
       
   165 
       
   166 class Child(Super):
       
   167     pass
       
   168 
       
   169 # new-style classes
       
   170 class NewSuper(object):
       
   171     pass
       
   172 
       
   173 class NewChild(NewSuper):
       
   174     pass
       
   175 
       
   176 
       
   177 
       
   178 class TestIsInstanceIsSubclass(unittest.TestCase):
       
   179     # Tests to ensure that isinstance and issubclass work on abstract
       
   180     # classes and instances.  Before the 2.2 release, TypeErrors were
       
   181     # raised when boolean values should have been returned.  The bug was
       
   182     # triggered by mixing 'normal' classes and instances were with
       
   183     # 'abstract' classes and instances.  This case tries to test all
       
   184     # combinations.
       
   185 
       
   186     def test_isinstance_normal(self):
       
   187         # normal instances
       
   188         self.assertEqual(True, isinstance(Super(), Super))
       
   189         self.assertEqual(False, isinstance(Super(), Child))
       
   190         self.assertEqual(False, isinstance(Super(), AbstractSuper))
       
   191         self.assertEqual(False, isinstance(Super(), AbstractChild))
       
   192 
       
   193         self.assertEqual(True, isinstance(Child(), Super))
       
   194         self.assertEqual(False, isinstance(Child(), AbstractSuper))
       
   195 
       
   196     def test_isinstance_abstract(self):
       
   197         # abstract instances
       
   198         self.assertEqual(True, isinstance(AbstractSuper(), AbstractSuper))
       
   199         self.assertEqual(False, isinstance(AbstractSuper(), AbstractChild))
       
   200         self.assertEqual(False, isinstance(AbstractSuper(), Super))
       
   201         self.assertEqual(False, isinstance(AbstractSuper(), Child))
       
   202 
       
   203         self.assertEqual(True, isinstance(AbstractChild(), AbstractChild))
       
   204         self.assertEqual(True, isinstance(AbstractChild(), AbstractSuper))
       
   205         self.assertEqual(False, isinstance(AbstractChild(), Super))
       
   206         self.assertEqual(False, isinstance(AbstractChild(), Child))
       
   207 
       
   208     def test_subclass_normal(self):
       
   209         # normal classes
       
   210         self.assertEqual(True, issubclass(Super, Super))
       
   211         self.assertEqual(False, issubclass(Super, AbstractSuper))
       
   212         self.assertEqual(False, issubclass(Super, Child))
       
   213 
       
   214         self.assertEqual(True, issubclass(Child, Child))
       
   215         self.assertEqual(True, issubclass(Child, Super))
       
   216         self.assertEqual(False, issubclass(Child, AbstractSuper))
       
   217 
       
   218     def test_subclass_abstract(self):
       
   219         # abstract classes
       
   220         self.assertEqual(True, issubclass(AbstractSuper, AbstractSuper))
       
   221         self.assertEqual(False, issubclass(AbstractSuper, AbstractChild))
       
   222         self.assertEqual(False, issubclass(AbstractSuper, Child))
       
   223 
       
   224         self.assertEqual(True, issubclass(AbstractChild, AbstractChild))
       
   225         self.assertEqual(True, issubclass(AbstractChild, AbstractSuper))
       
   226         self.assertEqual(False, issubclass(AbstractChild, Super))
       
   227         self.assertEqual(False, issubclass(AbstractChild, Child))
       
   228 
       
   229     def test_subclass_tuple(self):
       
   230         # test with a tuple as the second argument classes
       
   231         self.assertEqual(True, issubclass(Child, (Child,)))
       
   232         self.assertEqual(True, issubclass(Child, (Super,)))
       
   233         self.assertEqual(False, issubclass(Super, (Child,)))
       
   234         self.assertEqual(True, issubclass(Super, (Child, Super)))
       
   235         self.assertEqual(False, issubclass(Child, ()))
       
   236         self.assertEqual(True, issubclass(Super, (Child, (Super,))))
       
   237 
       
   238         self.assertEqual(True, issubclass(NewChild, (NewChild,)))
       
   239         self.assertEqual(True, issubclass(NewChild, (NewSuper,)))
       
   240         self.assertEqual(False, issubclass(NewSuper, (NewChild,)))
       
   241         self.assertEqual(True, issubclass(NewSuper, (NewChild, NewSuper)))
       
   242         self.assertEqual(False, issubclass(NewChild, ()))
       
   243         self.assertEqual(True, issubclass(NewSuper, (NewChild, (NewSuper,))))
       
   244 
       
   245         self.assertEqual(True, issubclass(int, (long, (float, int))))
       
   246         if test_support.have_unicode:
       
   247             self.assertEqual(True, issubclass(str, (unicode, (Child, NewChild, basestring))))
       
   248 
       
   249     def test_subclass_recursion_limit(self):
       
   250         # make sure that issubclass raises RuntimeError before the C stack is
       
   251         # blown
       
   252         self.assertRaises(RuntimeError, blowstack, issubclass, str, str)
       
   253 
       
   254     def test_isinstance_recursion_limit(self):
       
   255         # make sure that issubclass raises RuntimeError before the C stack is
       
   256         # blown
       
   257         self.assertRaises(RuntimeError, blowstack, isinstance, '', str)
       
   258 
       
   259 def blowstack(fxn, arg, compare_to):
       
   260     # Make sure that calling isinstance with a deeply nested tuple for its
       
   261     # argument will raise RuntimeError eventually.
       
   262     tuple_arg = (compare_to,)
       
   263     for cnt in xrange(sys.getrecursionlimit()+5):
       
   264         tuple_arg = (tuple_arg,)
       
   265         fxn(arg, tuple_arg)
       
   266 
       
   267 
       
   268 def test_main():
       
   269     test_support.run_unittest(
       
   270         TestIsInstanceExceptions,
       
   271         TestIsSubclassExceptions,
       
   272         TestIsInstanceIsSubclass
       
   273     )
       
   274 
       
   275 
       
   276 if __name__ == '__main__':
       
   277     test_main()