]> granicus.if.org Git - python/commitdiff
Unit tests for the changes in abstract.c version 2.101. The debug
authorBarry Warsaw <barry@python.org>
Tue, 23 Apr 2002 22:48:42 +0000 (22:48 +0000)
committerBarry Warsaw <barry@python.org>
Tue, 23 Apr 2002 22:48:42 +0000 (22:48 +0000)
build's "undetected error" problems were originally detected with
extension types, but we can whitebox test the same situations with
new-style classes.

Lib/test/test_isinstance.py [new file with mode: 0644]

diff --git a/Lib/test/test_isinstance.py b/Lib/test/test_isinstance.py
new file mode 100644 (file)
index 0000000..7fd6e7a
--- /dev/null
@@ -0,0 +1,144 @@
+# Tests some corner cases with isinstance() and issubclass().  While these
+# tests use new style classes and properties, they actually do whitebox
+# testing of error conditions uncovered when using extension types.
+
+import unittest
+import test_support
+
+
+\f
+class TestIsInstanceWhitebox(unittest.TestCase):
+    # Test to make sure that an AttributeError when accessing the instance's
+    # class's bases is masked.  This was actually a bug in Python 2.2 and
+    # 2.2.1 where the exception wasn't caught but it also wasn't being cleared
+    # (leading to an "undetected error" in the debug build).  Set up is,
+    # isinstance(inst, cls) where:
+    #
+    # - inst isn't an InstanceType
+    # - cls isn't a ClassType, a TypeType, or a TupleType
+    # - cls has a __bases__ attribute
+    # - inst has a __class__ attribute
+    # - inst.__class__ as no __bases__ attribute
+    #
+    # Sounds complicated, I know, but this mimics a situation where an
+    # extension type raises an AttributeError when its __bases__ attribute is
+    # gotten.  In that case, isinstance() should return False.
+    def test_class_has_no_bases(self):
+        class I(object):
+            def getclass(self):
+                # This must return an object that has no __bases__ attribute
+                return None
+            __class__ = property(getclass)
+
+        class C(object):
+            def getbases(self):
+                return ()
+            __bases__ = property(getbases)
+
+        self.assertEqual(False, isinstance(I(), C()))
+
+    # Like above except that inst.__class__.__bases__ raises an exception
+    # other than AttributeError
+    def test_bases_raises_other_than_attribute_error(self):
+        class E(object):
+            def getbases(self):
+                raise RuntimeError
+            __bases__ = property(getbases)
+
+        class I(object):
+            def getclass(self):
+                return E()
+            __class__ = property(getclass)
+
+        class C(object):
+            def getbases(self):
+                return ()
+            __bases__ = property(getbases)
+
+        self.assertRaises(RuntimeError, isinstance, I(), C())
+
+    # Here's a situation where getattr(cls, '__bases__') raises an exception.
+    # If that exception is not AttributeError, it should not get masked
+    def test_dont_mask_non_attribute_error(self):
+        class I: pass
+
+        class C(object):
+            def getbases(self):
+                raise RuntimeError
+            __bases__ = property(getbases)
+
+        self.assertRaises(RuntimeError, isinstance, I(), C())
+
+    # Like above, except that getattr(cls, '__bases__') raises an
+    # AttributeError, which /should/ get masked as a TypeError
+    def test_mask_attribute_error(self):
+        class I: pass
+
+        class C(object):
+            def getbases(self):
+                raise AttributeError
+            __bases__ = property(getbases)
+
+        self.assertRaises(TypeError, isinstance, I(), C())
+
+
+\f
+# These tests are similar to above, but tickle certain code paths in
+# issubclass() instead of isinstance() -- really PyObject_IsSubclass()
+# vs. PyObject_IsInstance().
+class TestIsSubclassWhitebox(unittest.TestCase):
+    def test_dont_mask_non_attribute_error(self):
+        class C(object):
+            def getbases(self):
+                raise RuntimeError
+            __bases__ = property(getbases)
+
+        class S(C): pass
+
+        self.assertRaises(RuntimeError, issubclass, C(), S())
+
+    def test_mask_attribute_error(self):
+        class C(object):
+            def getbases(self):
+                raise AttributeError
+            __bases__ = property(getbases)
+
+        class S(C): pass
+        
+        self.assertRaises(TypeError, issubclass, C(), S())
+
+    # Like above, but test the second branch, where the __bases__ of the
+    # second arg (the cls arg) is tested.  This means the first arg must
+    # return a valid __bases__, and it's okay for it to be a normal --
+    # unrelated by inheritance -- class.
+    def test_dont_mask_non_attribute_error_in_cls_arg(self):
+        class B: pass
+
+        class C(object):
+            def getbases(self):
+                raise RuntimeError
+            __bases__ = property(getbases)
+
+        self.assertRaises(RuntimeError, issubclass, B, C())
+
+    def test_mask_attribute_error_in_cls_arg(self):
+        class B: pass
+
+        class C(object):
+            def getbases(self):
+                raise AttributeError
+            __bases__ = property(getbases)
+
+        self.assertRaises(TypeError, issubclass, B, C())
+
+
+\f
+def test_main():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(TestIsInstanceWhitebox))
+    suite.addTest(unittest.makeSuite(TestIsSubclassWhitebox))
+    test_support.run_suite(suite)
+
+
+if __name__ == '__main__':
+    test_main()