8000 gh-110525: Add tests for internal `set` CAPI (GH-110630) · python/cpython@9cfb4e0 · GitHub
[go: up one dir, main page]

Skip to content

Commit 9cfb4e0

Browse files
authored
gh-110525: Add tests for internal set CAPI (GH-110630)
1 parent 66a9b10 commit 9cfb4e0

File tree

6 files changed

+117
-3
lines changed

6 files changed

+117
-3
lines changed

Lib/test/test_capi/test_set.py

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22

33
from test.support import import_helper
44

5-
# Skip this test if the _testcapi module isn't available.
5+
# Skip this test if the _testcapi or _testinternalcapi modules aren't available.
66
_testcapi = import_helper.import_module('_testcapi')
7+
_testinternalcapi = import_helper.import_module('_testinternalcapi')
78

89
class set_subclass(set):
910
pass
@@ -12,13 +13,15 @@ class frozenset_subclass(frozenset):
1213
pass
1314

1415

15-
class TestSetCAPI(unittest.TestCase):
16+
class BaseSetTests:
1617
def assertImmutable(self, action, *args):
1718
self.assertRaises(SystemError, action, frozenset(), *args)
1819
self.assertRaises(SystemError, action, frozenset({1}), *args)
1920
self.assertRaises(SystemError, action, frozenset_subclass(), *args)
2021
self.assertRaises(SystemError, action, frozenset_subclass({1}), *args)
2122

23+
24+
class TestSetCAPI(BaseSetTests, unittest.TestCase):
2225
def test_set_check(self):
2326
check = _testcapi.set_check
2427
self.assertTrue(check(set()))
@@ -213,3 +216,50 @@ def test_clear(self):
213216
clear(object())
214217
self.assertImmutable(clear)
215218
# CRASHES: clear(NULL)
219+
220+
221+
class TestInternalCAPI(BaseSetTests, unittest.TestCase):
222+
def test_set_update(self):
223+
update = _testinternalcapi.set_update
224+
for cls in (set, set_subclass):
225+
for it in ('ab', ('a', 'b'), ['a', 'b'],
226+
set('ab'), set_subclass('ab'),
227+
frozenset('ab'), frozenset_subclass('ab')):
228+
with self.subTest(cls=cls, it=it):
229+
instance = cls()
230+
self.assertEqual(update(instance, it), 0)
231+
self.assertEqual(instance, {'a', 'b'})
232+
instance = cls(it)
233+
self.assertEqual(update(instance, it), 0)
234+
self.assertEqual(instance, {'a', 'b'})
235+
with self.assertRaisesRegex(TypeError, 'object is not iterable'):
236+
update(cls(), 1)
237+
with self.assertRaisesRegex(TypeError, "unhashable type: 'dict'"):
238+
update(cls(), [{}])
239+
with self.assertRaises(SystemError):
240+
update(object(), 'ab')
241+
self.assertImmutable(update, 'ab')
242+
# CRASHES: update(NULL, object())
243+
# CRASHES: update(instance, NULL)
244+
# CRASHES: update(NULL, NULL)
245+
246+
def test_set_next_entry(self):
247+
set_next = _tes 8000 tinternalcapi.set_next_entry
248+
for cls in (set, set_subclass, frozenset, frozenset_subclass):
249+
with self.subTest(cls=cls):
250+
instance = cls('abc')
251+
pos = 0
252+
items = []
253+
while True:
254+
res = set_next(instance, pos)
255+
if res is None:
256+
break
257+
rc, pos, hash_, item = res
258+
items.append(item)
259+
self.assertEqual(rc, 1)
260+
self.assertIn(item, instance)
261+
self.assertEqual(hash(item), hash_)
262+
self.assertEqual(items, list(instance))
263+
with self.assertRaises(SystemError):
264+
set_next(object(), 0)
265+
# CRASHES: set_next(NULL, 0)

Modules/Setup.stdlib.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@
158158
@MODULE_XXSUBTYPE_TRUE@xxsubtype xxsubtype.c
159159
@MODULE__XXTESTFUZZ_TRUE@_xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c
160160
@MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c
161-
@MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c _testinternalcapi/test_lock.c _testinternalcapi/pytime.c
161+
@MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c _testinternalcapi/test_lock.c _testinternalcapi/pytime.c _testinternalcapi/set.c
162162
@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/abstract.c _testcapi/unicode.c _testcapi/dict.c _testcapi/set.c _testcapi/getargs.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyatomic.c _testcapi/pyos.c _testcapi/immortal.c _testcapi/heaptype_relative.c _testcapi/gc.c
163163
@MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c
164164
@MODULE__TESTCLINIC_LIMITED_TRUE@_testclinic_limited _testclinic_limited.c

Modules/_testinternalcapi.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1602,6 +1602,9 @@ module_exec(PyObject *module)
16021602
if (_PyTestInternalCapi_Init_PyTime(module) < 0) {
16031603
return 1;
16041604
}
1605+
if (_PyTestInternalCapi_Init_Set(module) < 0) {
1606+
return 1;
1607+
}
16051608

16061609
if (PyModule_Add(module, "SIZEOF_PYGC_HEAD",
16071610
PyLong_FromSsize_t(sizeof(PyGC_Head))) < 0) {

Modules/_testinternalcapi/parts.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,6 @@
1212

1313
int _PyTestInternalCapi_Init_Lock(PyObject *module);
1414
int _PyTestInternalCapi_Init_PyTime(PyObject *module);
15+
int _PyTestInternalCapi_Init_Set(PyObject *module);
1516

1617
#endif // Py_TESTINTERNALCAPI_PARTS_H

Modules/_testinternalcapi/set.c

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#include "parts.h"
2+
#include "../_testcapi/util.h" // NULLABLE, RETURN_INT
3+
4+
#include "pycore_setobject.h"
5+
6+
7+
static PyObject *
8+
set_update(PyObject *self, PyObject *args)
9+
{
10+
PyObject *set, *iterable;
11+
if (!PyArg_ParseTuple(args, "OO", &set, &iterable)) {
12+
return NULL;
13+
}
14+
NULLABLE(set);
15+
NULLABLE(iterable);
16+
RETURN_INT(_PySet_Update(set, iterable));
17+
}
18+
19+
static PyObject *
20+
set_next_entry(PyObject *self, PyObject *args)
21+
{
22+
int rc;
23+
Py_ssize_t pos;
24+
Py_hash_t hash = (Py_hash_t)UNINITIALIZED_SIZE;
25+
PyObject *set, *item = UNINITIALIZED_PTR;
26+
if (!PyArg_ParseTuple(args, "On", &set, &pos)) {
27+
return NULL;
28+
}
29+
NULLABLE(set);
30+
31+
rc = _PySet_NextEntry(set, &pos, &item, &hash);
32+
if (rc == 1) {
33+
return Py_BuildValue("innO", rc, pos, hash, item);
34+
}
35+
assert(item == UNINITIALIZED_PTR);
36+
assert(hash == (Py_hash_t)UNINITIALIZED_SIZE);
37+
if (rc == -1) {
38+
return NULL;
39+
}
40+
assert(rc == 0);
41+
Py_RETURN_NONE;
42+
}
43+
44+
45+
static PyMethodDef TestMethods[] = {
46+
{"set_update", set_update, METH_VARARGS},
47+
{"set_next_entry", set_next_entry, METH_VARARGS},
48+
49+
{NULL},
50+
};
51+
52+
int
53+
_PyTestInternalCapi_Init_Set(PyObject *m)
54+
{
55+
if (PyModule_AddFunctions(m, TestMethods) < 0) {
56+
return -1;
57+
}
58+
return 0;
59+
}

PCbuild/_testinternalcapi.vcxproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@
9696
<ClCompile Include="..\Modules\_testinternalcapi.c" />
9797
<ClCompile Include="..\Modules\_testinternalcapi\pytime.c" />
9898
<ClCompile Include="..\Modules\_testinternalcapi\test_lock.c" />
99+
<ClCompile Include="..\Modules\_testinternalcapi\set.c" />
99100
</ItemGroup>
100101
<ItemGroup>
101102
<ResourceCompile Include="..\PC\python_nt.rc" />

0 commit comments

Comments
 (0)
0