Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 3ed5cb0

Browse filesBrowse 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
Copy full SHA for 3ed5cb0

File tree

6 files changed

+383
-1
lines changed
Filter options

6 files changed

+383
-1
lines changed

‎Lib/test/test_capi/test_set.py

Copy file name to clipboard
+215Lines changed: 215 additions & 0 deletions
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

Copy file name to clipboardExpand all lines: Modules/Setup.stdlib.in
+1-1Lines changed: 1 addition & 1 deletion
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

Copy file name to clipboardExpand all lines: Modules/_testcapi/parts.h
+1Lines changed: 1 addition & 0 deletions
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

Copy file name to clipboard
+162Lines changed: 162 additions & 0 deletions
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 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.