Skip to content

[3.12] gh-114392: Improve test_capi.test_structmembers (GH-114393) #115010

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 4, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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()