Skip to content

Commit 15f6f04

Browse files
gh-114392: Improve test_capi.test_structmembers (GH-114393)
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.
1 parent 929d44e commit 15f6f04

File tree

1 file changed

+93
-124
lines changed

1 file changed

+93
-124
lines changed

Lib/test/test_capi/test_structmembers.py

+93-124
Original file line numberDiff line numberDiff line change
@@ -45,83 +45,115 @@ class ReadWriteTests:
4545
def setUp(self):
4646
self.ts = _make_test_object(self.cls)
4747

48+
def _test_write(self, name, value, expected=None):
49+
if expected is None:
50+
expected = value
51+
ts = self.ts
52+
setattr(ts, name, value)
53+
self.assertEqual(getattr(ts, name), expected)
54+
55+
def _test_warn(self, name, value, expected=None):
56+
ts = self.ts
57+
self.assertWarns(RuntimeWarning, setattr, ts, name, value)
58+
if expected is not None:
59+
self.assertEqual(getattr(ts, name), expected)
60+
61+
def _test_overflow(self, name, value):
62+
ts = self.ts
63+
self.assertRaises(OverflowError, setattr, ts, name, value)
64+
65+
def _test_int_range(self, name, minval, maxval, *, hardlimit=None,
66+
indexlimit=None):
67+
if hardlimit is None:
68+
hardlimit = (minval, maxval)
69+
ts = self.ts
70+
self._test_write(name, minval)
71+
self._test_write(name, maxval)
72+
hardminval, hardmaxval = hardlimit
73+
self._test_overflow(name, hardminval-1)
74+
self._test_overflow(name, hardmaxval+1)
75+
self._test_overflow(name, 2**1000)
76+
self._test_overflow(name, -2**1000)
77+
if hardminval < minval:
78+
self._test_warn(name, hardminval)
79+
self._test_warn(name, minval-1, maxval)
80+
if maxval < hardmaxval:
81+
self._test_warn(name, maxval+1, minval)
82+
self._test_warn(name, hardmaxval)
83+
84+
if indexlimit is None:
85+
indexlimit = hardlimit
86+
if not indexlimit:
87+
self.assertRaises(TypeError, setattr, ts, name, Index(minval))
88+
self.assertRaises(TypeError, setattr, ts, name, Index(maxval))
89+
else:
90+
hardminindexval, hardmaxindexval = indexlimit
91+
self._test_write(name, Index(minval), minval)
92+
if minval < hardminindexval:
93+
self._test_write(name, Index(hardminindexval), hardminindexval)
94+
if maxval < hardmaxindexval:
95+
self._test_write(name, Index(maxval), maxval)
96+
else:
97+
self._test_write(name, Index(hardmaxindexval), hardmaxindexval)
98+
self._test_overflow(name, Index(hardminindexval-1))
99+
if name in ('T_UINT', 'T_ULONG'):
100+
self.assertRaises(TypeError, setattr, self.ts, name,
101+
Index(hardmaxindexval+1))
102+
self.assertRaises(TypeError, setattr, self.ts, name,
103+
Index(2**1000))
104+
else:
105+
self._test_overflow(name, Index(hardmaxindexval+1))
106+
self._test_overflow(name, Index(2**1000))
107+
self._test_overflow(name, Index(-2**1000))
108+
if hardminindexval < minval and name != 'T_ULONGLONG':
109+
self._test_warn(name, Index(hardminindexval))
110+
self._test_warn(name, Index(minval-1))
111+
if maxval < hardmaxindexval:
112+
self._test_warn(name, Index(maxval+1))
113+
self._test_warn(name, Index(hardmaxindexval))
114+
48115
def test_bool(self):
49116
ts = self.ts
50117
ts.T_BOOL = True
51-
self.assertEqual(ts.T_BOOL, True)
118+
self.assertIs(ts.T_BOOL, True)
52119
ts.T_BOOL = False
53-
self.assertEqual(ts.T_BOOL, False)
120+
self.assertIs(ts.T_BOOL, False)
54121
self.assertRaises(TypeError, setattr, ts, 'T_BOOL', 1)
122+
self.assertRaises(TypeError, setattr, ts, 'T_BOOL', 0)
123+
self.assertRaises(TypeError, setattr, ts, 'T_BOOL', None)
55124

56125
def test_byte(self):
57-
ts = self.ts
58-
ts.T_BYTE = CHAR_MAX
59-
self.assertEqual(ts.T_BYTE, CHAR_MAX)
60-
ts.T_BYTE = CHAR_MIN
61-
self.assertEqual(ts.T_BYTE, CHAR_MIN)
62-
ts.T_UBYTE = UCHAR_MAX
63-
self.assertEqual(ts.T_UBYTE, UCHAR_MAX)
126+
self._test_int_range('T_BYTE', CHAR_MIN, CHAR_MAX,
127+
hardlimit=(LONG_MIN, LONG_MAX))
128+
self._test_int_range('T_UBYTE', 0, UCHAR_MAX,
129+
hardlimit=(LONG_MIN, LONG_MAX))
64130

65131
def test_short(self):
66-
ts = self.ts
67-
ts.T_SHORT = SHRT_MAX
68-
self.assertEqual(ts.T_SHORT, SHRT_MAX)
69-
ts.T_SHORT = SHRT_MIN
70-
self.assertEqual(ts.T_SHORT, SHRT_MIN)
71-
ts.T_USHORT = USHRT_MAX
72-
self.assertEqual(ts.T_USHORT, USHRT_MAX)
132+
self._test_int_range('T_SHORT', SHRT_MIN, SHRT_MAX,
133+
hardlimit=(LONG_MIN, LONG_MAX))
134+
self._test_int_range('T_USHORT', 0, USHRT_MAX,
135+
hardlimit=(LONG_MIN, LONG_MAX))
73136

74137
def test_int(self):
75-
ts = self.ts
76-
ts.T_INT = INT_MAX
77-
self.assertEqual(ts.T_INT, INT_MAX)
78-
ts.T_INT = INT_MIN
79-
self.assertEqual(ts.T_INT, INT_MIN)
80-
ts.T_UINT = UINT_MAX
81-
self.assertEqual(ts.T_UINT, UINT_MAX)
82-
ts.T_UINT = Index(0)
83-
self.assertEqual(ts.T_UINT, 0)
84-
ts.T_UINT = Index(INT_MAX)
85-
self.assertEqual(ts.T_UINT, INT_MAX)
138+
self._test_int_range('T_INT', INT_MIN, INT_MAX,
139+
hardlimit=(LONG_MIN, LONG_MAX))
140+
self._test_int_range('T_UINT', 0, UINT_MAX,
141+
hardlimit=(LONG_MIN, ULONG_MAX),
142+
indexlimit=(LONG_MIN, LONG_MAX))
86143

87144
def test_long(self):
88-
ts = self.ts
89-
ts.T_LONG = LONG_MAX
90-
self.assertEqual(ts.T_LONG, LONG_MAX)
91-
ts.T_LONG = LONG_MIN
92-
self.assertEqual(ts.T_LONG, LONG_MIN)
93-
ts.T_ULONG = ULONG_MAX
94-
self.assertEqual(ts.T_ULONG, ULONG_MAX)
95-
ts.T_ULONG = Index(0)
96-
self.assertEqual(ts.T_ULONG, 0)
97-
ts.T_ULONG = Index(LONG_MAX)
98-
self.assertEqual(ts.T_ULONG, LONG_MAX)
145+
self._test_int_range('T_LONG', LONG_MIN, LONG_MAX)
146+
self._test_int_range('T_ULONG', 0, ULONG_MAX,
147+
hardlimit=(LONG_MIN, ULONG_MAX),
148+
indexlimit=(LONG_MIN, LONG_MAX))
99149

100150
def test_py_ssize_t(self):
101-
ts = self.ts
102-
ts.T_PYSSIZET = PY_SSIZE_T_MAX
103-
self.assertEqual(ts.T_PYSSIZET, PY_SSIZE_T_MAX)
104-
ts.T_PYSSIZET = PY_SSIZE_T_MIN
105-
self.assertEqual(ts.T_PYSSIZET, PY_SSIZE_T_MIN)
151+
self._test_int_range('T_PYSSIZET', PY_SSIZE_T_MIN, PY_SSIZE_T_MAX, indexlimit=False)
106152

107153
def test_longlong(self):
108-
ts = self.ts
109-
if not hasattr(ts, "T_LONGLONG"):
110-
self.skipTest("long long not present")
111-
112-
ts.T_LONGLONG = LLONG_MAX
113-
self.assertEqual(ts.T_LONGLONG, LLONG_MAX)
114-
ts.T_LONGLONG = LLONG_MIN
115-
self.assertEqual(ts.T_LONGLONG, LLONG_MIN)
116-
117-
ts.T_ULONGLONG = ULLONG_MAX
118-
self.assertEqual(ts.T_ULONGLONG, ULLONG_MAX)
119-
120-
## make sure these will accept a plain int as well as a long
121-
ts.T_LONGLONG = 3
122-
self.assertEqual(ts.T_LONGLONG, 3)
123-
ts.T_ULONGLONG = 4
124-
self.assertEqual(ts.T_ULONGLONG, 4)
154+
self._test_int_range('T_LONGLONG', LLONG_MIN, LLONG_MAX)
155+
self._test_int_range('T_ULONGLONG', 0, ULLONG_MAX,
156+
indexlimit=(LONG_MIN, LONG_MAX))
125157

126158
def test_bad_assignments(self):
127159
ts = self.ts
@@ -131,10 +163,9 @@ def test_bad_assignments(self):
131163
'T_SHORT', 'T_USHORT',
132164
'T_INT', 'T_UINT',
133165
'T_LONG', 'T_ULONG',
166+
'T_LONGLONG', 'T_ULONGLONG',
134167
'T_PYSSIZET'
135168
]
136-
if hasattr(ts, 'T_LONGLONG'):
137-
integer_attributes.extend(['T_LONGLONG', 'T_ULONGLONG'])
138169

139170
# issue8014: this produced 'bad argument to internal function'
140171
# internal error
@@ -154,68 +185,6 @@ class ReadWriteTests_OldAPI(ReadWriteTests, unittest.TestCase):
154185
class ReadWriteTests_NewAPI(ReadWriteTests, unittest.TestCase):
155186
cls = _test_structmembersType_NewAPI
156187

157-
class TestWarnings:
158-
def setUp(self):
159-
self.ts = _make_test_object(self.cls)
160-
161-
def test_byte_max(self):
162-
ts = self.ts
163-
with warnings_helper.check_warnings(('', RuntimeWarning)):
164-
ts.T_BYTE = CHAR_MAX+1
165-
166-
def test_byte_min(self):
167-
ts = self.ts
168-
with warnings_helper.check_warnings(('', RuntimeWarning)):
169-
ts.T_BYTE = CHAR_MIN-1
170-
171-
def test_ubyte_max(self):
172-
ts = self.ts
173-
with warnings_helper.check_warnings(('', RuntimeWarning)):
174-
ts.T_UBYTE = UCHAR_MAX+1
175-
176-
def test_short_max(self):
177-
ts = self.ts
178-
with warnings_helper.check_warnings(('', RuntimeWarning)):
179-
ts.T_SHORT = SHRT_MAX+1
180-
181-
def test_short_min(self):
182-
ts = self.ts
183-
with warnings_helper.check_warnings(('', RuntimeWarning)):
184-
ts.T_SHORT = SHRT_MIN-1
185-
186-
def test_ushort_max(self):
187-
ts = self.ts
188-
with warnings_helper.check_warnings(('', RuntimeWarning)):
189-
ts.T_USHORT = USHRT_MAX+1
190-
191-
def test_int(self):
192-
ts = self.ts
193-
if LONG_MIN < INT_MIN:
194-
with self.assertWarns(RuntimeWarning):
195-
ts.T_INT = INT_MIN-1
196-
if LONG_MAX > INT_MAX:
197-
with self.assertWarns(RuntimeWarning):
198-
ts.T_INT = INT_MAX+1
199-
200-
def test_uint(self):
201-
ts = self.ts
202-
with self.assertWarns(RuntimeWarning):
203-
ts.T_UINT = -1
204-
if ULONG_MAX > UINT_MAX:
205-
with self.assertWarns(RuntimeWarning):
206-
ts.T_UINT = UINT_MAX+1
207-
208-
def test_ulong(self):
209-
ts = self.ts
210-
with self.assertWarns(RuntimeWarning):
211-
ts.T_ULONG = -1
212-
213-
class TestWarnings_OldAPI(TestWarnings, unittest.TestCase):
214-
cls = _test_structmembersType_OldAPI
215-
216-
class TestWarnings_NewAPI(TestWarnings, unittest.TestCase):
217-
cls = _test_structmembersType_NewAPI
218-
219188

220189
if __name__ == "__main__":
221190
unittest.main()

0 commit comments

Comments
 (0)