Skip to content

Commit

Permalink
pythongh-114392: Improve test_capi.test_structmembers (pythonGH-114393)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
serhiy-storchaka authored Feb 4, 2024
1 parent 929d44e commit 15f6f04
Showing 1 changed file with 93 additions and 124 deletions.
217 changes: 93 additions & 124 deletions Lib/test/test_capi/test_structmembers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -131,10 +163,9 @@ def test_bad_assignments(self):
'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
Expand All @@ -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()

0 comments on commit 15f6f04

Please sign in to comment.