Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 3ed5cb0

Browse files
authored
[3.12] gh-110525: Add CAPI tests for set and frozenset objects (GH-110526). (GH-110547)
(cherry picked from commit c49edd7)
1 parent a7fe709 commit 3ed5cb0

File tree

6 files changed

+383
-1
lines changed

6 files changed

+383
-1
lines changed

Lib/test/test_capi/test_set.py

+215
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
import unittest
2+
3+
from test.support import import_helper
4+
5+
# Skip this test if the _testcapi module isn't available.
6+
_testcapi = import_helper.import_module('_testcapi')
7+
8+
class set_subclass(set):
9+
pass
10+
11+
class frozenset_subclass(frozenset):
12+
pass
13+
14+
15+
class TestSetCAPI(unittest.TestCase):
16+
def assertImmutable(self, action, *args):
17+
self.assertRaises(SystemError, action, frozenset(), *args)
18+
self.assertRaises(SystemError, action, frozenset({1}), *args)
19+
self.assertRaises(SystemError, action, frozenset_subclass(), *args)
20+
self.assertRaises(SystemError, action, frozenset_subclass({1}), *args)
21+
22+
def test_set_check(self):
23+
check = _testcapi.set_check
24+
self.assertTrue(check(set()))
25+
self.assertTrue(check({1, 2}))
26+
self.assertFalse(check(frozenset()))
27+
self.assertTrue(check(set_subclass()))
28+
self.assertFalse(check(frozenset_subclass()))
29+
self.assertFalse(check(object()))
30+
# CRASHES: check(NULL)
31+
32+
def test_set_check_exact(self):
33+
check = _testcapi.set_checkexact
34+
self.assertTrue(check(set()))
35+
self.assertTrue(check({1, 2}))
36+
self.assertFalse(check(frozenset()))
37+
self.assertFalse(check(set_subclass()))
38+
self.assertFalse(check(frozenset_subclass()))
39+
self.assertFalse(check(object()))
40+
# CRASHES: check(NULL)
41+
42+
def test_frozenset_check(self):
43+
check = _testcapi.frozenset_check
44+
self.assertFalse(check(set()))
45+
self.assertTrue(check(frozenset()))
46+
self.assertTrue(check(frozenset({1, 2})))
47+
self.assertFalse(check(set_subclass()))
48+
self.assertTrue(check(frozenset_subclass()))
49+
self.assertFalse(check(object()))
50+
# CRASHES: check(NULL)
51+
52+
def test_frozenset_check_exact(self):
53+
check = _testcapi.frozenset_checkexact
54+
self.assertFalse(check(set()))
55+
self.assertTrue(check(frozenset()))
56+
self.assertTrue(check(frozenset({1, 2})))
57+
self.assertFalse(check(set_subclass()))
58+
self.assertFalse(check(frozenset_subclass()))
59+
self.assertFalse(check(object()))
60+
# CRASHES: check(NULL)
61+
62+
def test_anyset_check(self):
63+
check = _testcapi.anyset_check
64+
self.assertTrue(check(set()))
65+
self.assertTrue(check({1, 2}))
66+
self.assertTrue(check(frozenset()))
67+
self.assertTrue(check(frozenset({1, 2})))
68+
self.assertTrue(check(set_subclass()))
69+
self.assertTrue(check(frozenset_subclass()))
70+
self.assertFalse(check(object()))
71+
# CRASHES: check(NULL)
72+
73+
def test_anyset_check_exact(self):
74+
check = _testcapi.anyset_checkexact
75+
self.assertTrue(check(set()))
76+
self.assertTrue(check({1, 2}))
77+
self.assertTrue(check(frozenset()))
78+
self.assertTrue(check(frozenset({1, 2})))
79+
self.assertFalse(check(set_subclass()))
80+
self.assertFalse(check(frozenset_subclass()))
81+
self.assertFalse(check(object()))
82+
# CRASHES: check(NULL)
83+
84+
def test_set_new(self):
85+
set_new = _testcapi.set_new
86+
self.assertEqual(set_new().__class__, set)
87+
self.assertEqual(set_new(), set())
88+
self.assertEqual(set_new((1, 1, 2)), {1, 2})
89+
self.assertEqual(set_new([1, 1, 2]), {1, 2})
90+
with self.assertRaisesRegex(TypeError, 'object is not iterable'):
91+
set_new(object())
92+
with self.assertRaisesRegex(TypeError, 'object is not iterable'):
93+
set_new(1)
94+
with self.assertRaisesRegex(TypeError, "unhashable type: 'dict'"):
95+
set_new((1, {}))
96+
97+
def test_frozenset_new(self):
98+
frozenset_new = _testcapi.frozenset_new
99+
self.assertEqual(frozenset_new().__class__, frozenset)
100+
self.assertEqual(frozenset_new(), frozenset())
101+
self.assertEqual(frozenset_new((1, 1, 2)), frozenset({1, 2}))
102+
self.assertEqual(frozenset_new([1, 1, 2]), frozenset({1, 2}))
103+
with self.assertRaisesRegex(TypeError, 'object is not iterable'):
104+
frozenset_new(object())
105+
with self.assertRaisesRegex(TypeError, 'object is not iterable'):
106+
frozenset_new(1)
107+
with self.assertRaisesRegex(TypeError, "unhashable type: 'dict'"):
108+
frozenset_new((1, {}))
109+
110+
def test_set_size(self):
111+
get_size = _testcapi.set_size
112+
self.assertEqual(get_size(set()), 0)
113+
self.assertEqual(get_size(frozenset()), 0)
114+
self.assertEqual(get_size({1, 1, 2}), 2)
115+
self.assertEqual(get_size(frozenset({1, 1, 2})), 2)
116+
self.assertEqual(get_size(set_subclass((1, 2, 3))), 3)
117+
self.assertEqual(get_size(frozenset_subclass((1, 2, 3))), 3)
118+
with self.assertRaises(SystemError):
119+
get_size(object())
120+
# CRASHES: get_size(NULL)
121+
122+
def test_set_get_size(self):
123+
get_size = _testcapi.set_get_size
124+
self.assertEqual(get_size(set()), 0)
125+
self.assertEqual(get_size(frozenset()), 0)
126+
self.assertEqual(get_size({1, 1, 2}), 2)
127+
self.assertEqual(get_size(frozenset({1, 1, 2})), 2)
128+
self.assertEqual(get_size(set_subclass((1, 2, 3))), 3)
129+
self.assertEqual(get_size(frozenset_subclass((1, 2, 3))), 3)
130+
# CRASHES: get_size(NULL)
131+
# CRASHES: get_size(object())
132+
133+
def test_set_contains(self):
134+
contains = _testcapi.set_contains
135+
for cls in (set, frozenset, set_subclass, frozenset_subclass):
136+
with self.subTest(cls=cls):
137+
instance = cls((1, 2))
138+
self.assertTrue(contains(instance, 1))
139+
self.assertFalse(contains(instance, 'missing'))
140+
with self.assertRaisesRegex(TypeError, "unhashable type: 'list'"):
141+
contains(instance, [])
142+
# CRASHES: contains(instance, NULL)
143+
# CRASHES: contains(NULL, object())
144+
# CRASHES: contains(NULL, NULL)
145+
146+
def test_add(self):
147+
add = _testcapi.set_add
148+
for cls in (set, set_subclass):
149+
with self.subTest(cls=cls):
150+
instance = cls((1, 2))
151+
self.assertEqual(add(instance, 1), 0)
152+
self.assertEqual(instance, {1, 2})
153+
self.assertEqual(add(instance, 3), 0)
154+
self.assertEqual(instance, {1, 2, 3})
155+
with self.assertRaisesRegex(TypeError, "unhashable type: 'list'"):
156+
add(instance, [])
157+
with self.assertRaises(SystemError):
158+
add(object(), 1)
159+
self.assertImmutable(add, 1)
160+
# CRASHES: add(NULL, object())
161+
# CRASHES: add(instance, NULL)
162+
# CRASHES: add(NULL, NULL)
163+
164+
def test_discard(self):
165+
discard = _testcapi.set_discard
166+
for cls in (set, set_subclass):
167+
with self.subTest(cls=cls):
168+
instance = cls((1, 2))
169+
self.assertEqual(discard(instance, 3), 0)
170+
self.assertEqual(instance, {1, 2})
171+
self.assertEqual(discard(instance, 1), 1)
172+
self.assertEqual(instance, {2})
173+
self.assertEqual(discard(instance, 2), 1)
174+
self.assertEqual(instance, set())
175+
self.assertEqual(discard(instance, 2), 0)
176+
self.assertEqual(instance, set())
177+
with self.assertRaisesRegex(TypeError, "unhashable type: 'list'"):
178+
discard(instance, [])
179+
with self.assertRaises(SystemError):
180+
discard(object(), 1)
181+
self.assertImmutable(discard, 1)
182+
# CRASHES: discard(NULL, object())
183+
# CRASHES: discard(instance, NULL)
184+
# CRASHES: discard(NULL, NULL)
185+
186+
def test_pop(self):
187+
pop = _testcapi.set_pop
188+
orig = (1, 2)
189+
for cls in (set, set_subclass):
190+
with self.subTest(cls=cls):
191+
instance = cls(orig)
192+
self.assertIn(pop(instance), orig)
193+
self.assertEqual(len(instance), 1)
194+
self.assertIn(pop(instance), orig)
195+
self.assertEqual(len(instance), 0)
196+
with self.assertRaises(KeyError):
197+
pop(instance)
198+
with self.assertRaises(SystemError):
199+
pop(object())
200+
self.assertImmutable(pop)
201+
# CRASHES: pop(NULL)
202+
203+
def test_clear(self):
204+
clear = _testcapi.set_clear
205+
for cls in (set, set_subclass):
206+
with self.subTest(cls=cls):
207+
instance = cls((1, 2))
208+
self.assertEqual(clear(instance), 0)
209+
self.assertEqual(instance, set())
210+
self.assertEqual(clear(instance), 0)
211+
self.assertEqual(instance, set())
212+
with self.assertRaises(SystemError):
213+
clear(object())
214+
self.assertImmutable(clear)
215+
# CRASHES: clear(NULL)

Modules/Setup.stdlib.in

+1-1
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@
168168
@MODULE__XXTESTFUZZ_TRUE@_xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c
169169
@MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c
170170
@MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c
171-
@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/getargs.c _testcapi/pytime.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/pyos.c _testcapi/immortal.c _testcapi/heaptype_relative.c _testcapi/gc.c
171+
@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/pytime.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/pyos.c _testcapi/immortal.c _testcapi/heaptype_relative.c _testcapi/gc.c
172172
@MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c
173173

174174
# Some testing modules MUST be built as shared libraries.

Modules/_testcapi/parts.h

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ int _PyTestCapi_Init_Watchers(PyObject *module);
3737
int _PyTestCapi_Init_Long(PyObject *module);
3838
int _PyTestCapi_Init_Float(PyObject *module);
3939
int _PyTestCapi_Init_Dict(PyObject *module);
40+
int _PyTestCapi_Init_Set(PyObject *module);
4041
int _PyTestCapi_Init_Structmember(PyObject *module);
4142
int _PyTestCapi_Init_Exceptions(PyObject *module);
4243
int _PyTestCapi_Init_Code(PyObject *module);

Modules/_testcapi/set.c

+162
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
#include <stddef.h> // ptrdiff_t
2+
3+
#include "parts.h"
4+
#include "util.h"
5+
6+
static PyObject *
7+
set_check(PyObject *self, PyObject *obj)
8+
{
9+
NULLABLE(obj);
10+
RETURN_INT(PySet_Check(obj));
11+
}
12+
13+
static PyObject *
14+
set_checkexact(PyObject *self, PyObject *obj)
15+
{
16+
NULLABLE(obj);
17+
RETURN_INT(PySet_CheckExact(obj));
18+
}
19+
20+
static PyObject *
21+
frozenset_check(PyObject *self, PyObject *obj)
22+
{
23+
NULLABLE(obj);
24+
RETURN_INT(PyFrozenSet_Check(obj));
25+
}
26+
27+
static PyObject *
28+
frozenset_checkexact(PyObject *self, PyObject *obj)
29+
{
30+
NULLABLE(obj);
31+
RETURN_INT(PyFrozenSet_CheckExact(obj));
32+
}
33+
34+
static PyObject *
35+
anyset_check(PyObject *self, PyObject *obj)
36+
{
37+
NULLABLE(obj);
38+
RETURN_INT(PyAnySet_Check(obj));
39+
}
40+
41+
static PyObject *
42+
anyset_checkexact(PyObject *self, PyObject *obj)
43+
{
44+
NULLABLE(obj);
45+
RETURN_INT(PyAnySet_CheckExact(obj));
46+
}
47+
48+
static PyObject *
49+
set_new(PyObject *self, PyObject *args)
50+
{
51+
PyObject *iterable = NULL;
52+
if (!PyArg_ParseTuple(args, "|O", &iterable)) {
53+
return NULL;
54+
}
55+
return PySet_New(iterable);
56+
}
57+
58+
static PyObject *
59+
frozenset_new(PyObject *self, PyObject *args)
60+
{
61+
PyObject *iterable = NULL;
62+
if (!PyArg_ParseTuple(args, "|O", &iterable)) {
63+
return NULL;
64+
}
65+
return PyFrozenSet_New(iterable);
66+
}
67+
68+
static PyObject *
69+
set_size(PyObject *self, PyObject *obj)
70+
{
71+
NULLABLE(obj);
72+
RETURN_SIZE(PySet_Size(obj));
73+
}
74+
75+
static PyObject *
76+
set_get_size(PyObject *self, PyObject *obj)
77+
{
78+
NULLABLE(obj);
79+
RETURN_SIZE(PySet_GET_SIZE(obj));
80+
}
81+
82+
static PyObject *
83+
set_contains(PyObject *self, PyObject *args)
84+
{
85+
PyObject *obj, *item;
86+
if (!PyArg_ParseTuple(args, "OO", &obj, &item)) {
87+
return NULL;
88+
}
89+
NULLABLE(obj);
90+
NULLABLE(item);
91+
RETURN_INT(PySet_Contains(obj, item));
92+
}
93+
94+
static PyObject *
95+
set_add(PyObject *self, PyObject *args)
96+
{
97+
PyObject *obj, *item;
98+
if (!PyArg_ParseTuple(args, "OO", &obj, &item)) {
99+
return NULL;
100+
}
101+
NULLABLE(obj);
102+
NULLABLE(item);
103+
RETURN_INT(PySet_Add(obj, item));
104+
}
105+
106+
static PyObject *
107+
set_discard(PyObject *self, PyObject *args)
108+
{
109+
PyObject *obj, *item;
110+
if (!PyArg_ParseTuple(args, "OO", &obj, &item)) {
111+
return NULL;
112+
}
113+
NULLABLE(obj);
114+
NULLABLE(item);
115+
RETURN_INT(PySet_Discard(obj, item));
116+
}
117+
118+
static PyObject *
119+
set_pop(PyObject *self, PyObject *obj)
120+
{
121+
NULLABLE(obj);
122+
return PySet_Pop(obj);
123+
}
124+
125+
static PyObject *
126+
set_clear(PyObject *self, PyObject *obj)
127+
{
128+
NULLABLE(obj);
129+
RETURN_INT(PySet_Clear(obj));
130+
}
131+
132+
static PyMethodDef test_methods[] = {
133+
{"set_check", set_check, METH_O},
134+
{"set_checkexact", set_checkexact, METH_O},
135+
{"frozenset_check", frozenset_check, METH_O},
136+
{"frozenset_checkexact", frozenset_checkexact, METH_O},
137+
{"anyset_check", anyset_check, METH_O},
138+
{"anyset_checkexact", anyset_checkexact, METH_O},
139+
140+
{"set_new", set_new, METH_VARARGS},
141+
{"frozenset_new", frozenset_new, METH_VARARGS},
142+
143+
{"set_size", set_size, METH_O},
144+
{"set_get_size", set_get_size, METH_O},
145+
{"set_contains", set_contains, METH_VARARGS},
146+
{"set_add", set_add, METH_VARARGS},
147+
{"set_discard", set_discard, METH_VARARGS},
148+
{"set_pop", set_pop, METH_O},
149+
{"set_clear", set_clear, METH_O},
150+
151+
{NULL},
152+
};
153+
154+
int
155+
_PyTestCapi_Init_Set(PyObject *m)
156+
{
157+
if (PyModule_AddFunctions(m, test_methods) < 0) {
158+
return -1;
159+
}
160+
161+
return 0;
162+
}

0 commit comments

Comments
 (0)