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 2bce9fd

Browse filesBrowse files
sobolevnGlyphack
authored andcommitted
pythongh-110525: Add CAPI tests for set and frozenset objects (pythonGH-110526)
1 parent 87e9631 commit 2bce9fd
Copy full SHA for 2bce9fd

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
@@ -159,7 +159,7 @@
159159
@MODULE__XXTESTFUZZ_TRUE@_xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c
160160
@MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c
161161
@MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c _testinternalcapi/test_lock.c _testinternalcapi/pytime.c
162-
@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/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
162+
@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
165165

‎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
@@ -34,6 +34,7 @@ int _PyTestCapi_Init_Watchers(PyObject *module);
3434
int _PyTestCapi_Init_Long(PyObject *module);
3535
int _PyTestCapi_Init_Float(PyObject *module);
3636
int _PyTestCapi_Init_Dict(PyObject *module);
37+
int _PyTestCapi_Init_Set(PyObject *module);
3738
int _PyTestCapi_Init_Structmember(PyObject *module);
3839
int _PyTestCapi_Init_Exceptions(PyObject *module);
3940
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.