]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-114392: Improve test_capi.test_structmembers (GH-114393)
authorSerhiy Storchaka <storchaka@gmail.com>
Sun, 4 Feb 2024 20:19:06 +0000 (22:19 +0200)
committerGitHub <noreply@github.com>
Sun, 4 Feb 2024 20:19:06 +0000 (22:19 +0200)
Test all integer member types with extreme values and values outside of
the valid range. Test support of integer-like objects. Test warnings for
wrapped out values.

Lib/test/test_capi/test_structmembers.py

index 415b8033bd16b3c9799f24fbdf90225811f83a47..a294c3b13a5c30c0c11d9bd308dd18906c59e010 100644 (file)
@@ -45,83 +45,115 @@ class ReadWriteTests:
     def setUp(self):
         self.ts = _make_test_object(self.cls)
 
+    def _test_write(self, name, value, expected=None):
+        if expected is None:
+            expected = value
+        ts = self.ts
+        setattr(ts, name, value)
+        self.assertEqual(getattr(ts, name), expected)
+
+    def _test_warn(self, name, value, expected=None):
+        ts = self.ts
+        self.assertWarns(RuntimeWarning, setattr, ts, name, value)
+        if expected is not None:
+            self.assertEqual(getattr(ts, name), expected)
+
+    def _test_overflow(self, name, value):
+        ts = self.ts
+        self.assertRaises(OverflowError, setattr, ts, name, value)
+
+    def _test_int_range(self, name, minval, maxval, *, hardlimit=None,
+                        indexlimit=None):
+        if hardlimit is None:
+            hardlimit = (minval, maxval)
+        ts = self.ts
+        self._test_write(name, minval)
+        self._test_write(name, maxval)
+        hardminval, hardmaxval = hardlimit
+        self._test_overflow(name, hardminval-1)
+        self._test_overflow(name, hardmaxval+1)
+        self._test_overflow(name, 2**1000)
+        self._test_overflow(name, -2**1000)
+        if hardminval < minval:
+            self._test_warn(name, hardminval)
+            self._test_warn(name, minval-1, maxval)
+        if maxval < hardmaxval:
+            self._test_warn(name, maxval+1, minval)
+            self._test_warn(name, hardmaxval)
+
+        if indexlimit is None:
+            indexlimit = hardlimit
+        if not indexlimit:
+            self.assertRaises(TypeError, setattr, ts, name, Index(minval))
+            self.assertRaises(TypeError, setattr, ts, name, Index(maxval))
+        else:
+            hardminindexval, hardmaxindexval = indexlimit
+            self._test_write(name, Index(minval), minval)
+            if minval < hardminindexval:
+                self._test_write(name, Index(hardminindexval), hardminindexval)
+            if maxval < hardmaxindexval:
+                self._test_write(name, Index(maxval), maxval)
+            else:
+                self._test_write(name, Index(hardmaxindexval), hardmaxindexval)
+            self._test_overflow(name, Index(hardminindexval-1))
+            if name in ('T_UINT', 'T_ULONG'):
+                self.assertRaises(TypeError, setattr, self.ts, name,
+                                  Index(hardmaxindexval+1))
+                self.assertRaises(TypeError, setattr, self.ts, name,
+                                  Index(2**1000))
+            else:
+                self._test_overflow(name, Index(hardmaxindexval+1))
+                self._test_overflow(name, Index(2**1000))
+            self._test_overflow(name, Index(-2**1000))
+            if hardminindexval < minval and name != 'T_ULONGLONG':
+                self._test_warn(name, Index(hardminindexval))
+                self._test_warn(name, Index(minval-1))
+            if maxval < hardmaxindexval:
+                self._test_warn(name, Index(maxval+1))
+                self._test_warn(name, Index(hardmaxindexval))
+
     def test_bool(self):
         ts = self.ts
         ts.T_BOOL = True
-        self.assertEqual(ts.T_BOOL, True)
+        self.assertIs(ts.T_BOOL, True)
         ts.T_BOOL = False
-        self.assertEqual(ts.T_BOOL, False)
+        self.assertIs(ts.T_BOOL, False)
         self.assertRaises(TypeError, setattr, ts, 'T_BOOL', 1)
+        self.assertRaises(TypeError, setattr, ts, 'T_BOOL', 0)
+        self.assertRaises(TypeError, setattr, ts, 'T_BOOL', None)
 
     def test_byte(self):
-        ts = self.ts
-        ts.T_BYTE = CHAR_MAX
-        self.assertEqual(ts.T_BYTE, CHAR_MAX)
-        ts.T_BYTE = CHAR_MIN
-        self.assertEqual(ts.T_BYTE, CHAR_MIN)
-        ts.T_UBYTE = UCHAR_MAX
-        self.assertEqual(ts.T_UBYTE, UCHAR_MAX)
+        self._test_int_range('T_BYTE', CHAR_MIN, CHAR_MAX,
+                             hardlimit=(LONG_MIN, LONG_MAX))
+        self._test_int_range('T_UBYTE', 0, UCHAR_MAX,
+                             hardlimit=(LONG_MIN, LONG_MAX))
 
     def test_short(self):
-        ts = self.ts
-        ts.T_SHORT = SHRT_MAX
-        self.assertEqual(ts.T_SHORT, SHRT_MAX)
-        ts.T_SHORT = SHRT_MIN
-        self.assertEqual(ts.T_SHORT, SHRT_MIN)
-        ts.T_USHORT = USHRT_MAX
-        self.assertEqual(ts.T_USHORT, USHRT_MAX)
+        self._test_int_range('T_SHORT', SHRT_MIN, SHRT_MAX,
+                             hardlimit=(LONG_MIN, LONG_MAX))
+        self._test_int_range('T_USHORT', 0, USHRT_MAX,
+                             hardlimit=(LONG_MIN, LONG_MAX))
 
     def test_int(self):
-        ts = self.ts
-        ts.T_INT = INT_MAX
-        self.assertEqual(ts.T_INT, INT_MAX)
-        ts.T_INT = INT_MIN
-        self.assertEqual(ts.T_INT, INT_MIN)
-        ts.T_UINT = UINT_MAX
-        self.assertEqual(ts.T_UINT, UINT_MAX)
-        ts.T_UINT = Index(0)
-        self.assertEqual(ts.T_UINT, 0)
-        ts.T_UINT = Index(INT_MAX)
-        self.assertEqual(ts.T_UINT, INT_MAX)
+        self._test_int_range('T_INT', INT_MIN, INT_MAX,
+                             hardlimit=(LONG_MIN, LONG_MAX))
+        self._test_int_range('T_UINT', 0, UINT_MAX,
+                             hardlimit=(LONG_MIN, ULONG_MAX),
+                             indexlimit=(LONG_MIN, LONG_MAX))
 
     def test_long(self):
-        ts = self.ts
-        ts.T_LONG = LONG_MAX
-        self.assertEqual(ts.T_LONG, LONG_MAX)
-        ts.T_LONG = LONG_MIN
-        self.assertEqual(ts.T_LONG, LONG_MIN)
-        ts.T_ULONG = ULONG_MAX
-        self.assertEqual(ts.T_ULONG, ULONG_MAX)
-        ts.T_ULONG = Index(0)
-        self.assertEqual(ts.T_ULONG, 0)
-        ts.T_ULONG = Index(LONG_MAX)
-        self.assertEqual(ts.T_ULONG, LONG_MAX)
+        self._test_int_range('T_LONG', LONG_MIN, LONG_MAX)
+        self._test_int_range('T_ULONG', 0, ULONG_MAX,
+                             hardlimit=(LONG_MIN, ULONG_MAX),
+                             indexlimit=(LONG_MIN, LONG_MAX))
 
     def test_py_ssize_t(self):
-        ts = self.ts
-        ts.T_PYSSIZET = PY_SSIZE_T_MAX
-        self.assertEqual(ts.T_PYSSIZET, PY_SSIZE_T_MAX)
-        ts.T_PYSSIZET = PY_SSIZE_T_MIN
-        self.assertEqual(ts.T_PYSSIZET, PY_SSIZE_T_MIN)
+        self._test_int_range('T_PYSSIZET', PY_SSIZE_T_MIN, PY_SSIZE_T_MAX, indexlimit=False)
 
     def test_longlong(self):
-        ts = self.ts
-        if not hasattr(ts, "T_LONGLONG"):
-            self.skipTest("long long not present")
-
-        ts.T_LONGLONG = LLONG_MAX
-        self.assertEqual(ts.T_LONGLONG, LLONG_MAX)
-        ts.T_LONGLONG = LLONG_MIN
-        self.assertEqual(ts.T_LONGLONG, LLONG_MIN)
-
-        ts.T_ULONGLONG = ULLONG_MAX
-        self.assertEqual(ts.T_ULONGLONG, ULLONG_MAX)
-
-        ## make sure these will accept a plain int as well as a long
-        ts.T_LONGLONG = 3
-        self.assertEqual(ts.T_LONGLONG, 3)
-        ts.T_ULONGLONG = 4
-        self.assertEqual(ts.T_ULONGLONG, 4)
+        self._test_int_range('T_LONGLONG', LLONG_MIN, LLONG_MAX)
+        self._test_int_range('T_ULONGLONG', 0, ULLONG_MAX,
+                             indexlimit=(LONG_MIN, LONG_MAX))
 
     def test_bad_assignments(self):
         ts = self.ts
@@ -131,10 +163,9 @@ class ReadWriteTests:
             'T_SHORT', 'T_USHORT',
             'T_INT', 'T_UINT',
             'T_LONG', 'T_ULONG',
+            'T_LONGLONG', 'T_ULONGLONG',
             'T_PYSSIZET'
             ]
-        if hasattr(ts, 'T_LONGLONG'):
-            integer_attributes.extend(['T_LONGLONG', 'T_ULONGLONG'])
 
         # issue8014: this produced 'bad argument to internal function'
         # internal error
@@ -154,68 +185,6 @@ class ReadWriteTests_OldAPI(ReadWriteTests, unittest.TestCase):
 class ReadWriteTests_NewAPI(ReadWriteTests, unittest.TestCase):
     cls = _test_structmembersType_NewAPI
 
-class TestWarnings:
-    def setUp(self):
-        self.ts = _make_test_object(self.cls)
-
-    def test_byte_max(self):
-        ts = self.ts
-        with warnings_helper.check_warnings(('', RuntimeWarning)):
-            ts.T_BYTE = CHAR_MAX+1
-
-    def test_byte_min(self):
-        ts = self.ts
-        with warnings_helper.check_warnings(('', RuntimeWarning)):
-            ts.T_BYTE = CHAR_MIN-1
-
-    def test_ubyte_max(self):
-        ts = self.ts
-        with warnings_helper.check_warnings(('', RuntimeWarning)):
-            ts.T_UBYTE = UCHAR_MAX+1
-
-    def test_short_max(self):
-        ts = self.ts
-        with warnings_helper.check_warnings(('', RuntimeWarning)):
-            ts.T_SHORT = SHRT_MAX+1
-
-    def test_short_min(self):
-        ts = self.ts
-        with warnings_helper.check_warnings(('', RuntimeWarning)):
-            ts.T_SHORT = SHRT_MIN-1
-
-    def test_ushort_max(self):
-        ts = self.ts
-        with warnings_helper.check_warnings(('', RuntimeWarning)):
-            ts.T_USHORT = USHRT_MAX+1
-
-    def test_int(self):
-        ts = self.ts
-        if LONG_MIN < INT_MIN:
-            with self.assertWarns(RuntimeWarning):
-                ts.T_INT = INT_MIN-1
-        if LONG_MAX > INT_MAX:
-            with self.assertWarns(RuntimeWarning):
-                ts.T_INT = INT_MAX+1
-
-    def test_uint(self):
-        ts = self.ts
-        with self.assertWarns(RuntimeWarning):
-            ts.T_UINT = -1
-        if ULONG_MAX > UINT_MAX:
-            with self.assertWarns(RuntimeWarning):
-                ts.T_UINT = UINT_MAX+1
-
-    def test_ulong(self):
-        ts = self.ts
-        with self.assertWarns(RuntimeWarning):
-            ts.T_ULONG = -1
-
-class TestWarnings_OldAPI(TestWarnings, unittest.TestCase):
-    cls = _test_structmembersType_OldAPI
-
-class TestWarnings_NewAPI(TestWarnings, unittest.TestCase):
-    cls = _test_structmembersType_NewAPI
-
 
 if __name__ == "__main__":
     unittest.main()