mirror of https://github.com/python/cpython
gh-110525: Add CAPI tests for set and frozenset objects (GH-110526)
This commit is contained in:
parent
dd4bb0529e
commit
c49edd7d9c
|
@ -0,0 +1,215 @@
|
|||
import unittest
|
||||
|
||||
from test.support import import_helper
|
||||
|
||||
# Skip this test if the _testcapi module isn't available.
|
||||
_testcapi = import_helper.import_module('_testcapi')
|
||||
|
||||
class set_subclass(set):
|
||||
pass
|
||||
|
||||
class frozenset_subclass(frozenset):
|
||||
pass
|
||||
|
||||
|
||||
class TestSetCAPI(unittest.TestCase):
|
||||
def assertImmutable(self, action, *args):
|
||||
self.assertRaises(SystemError, action, frozenset(), *args)
|
||||
self.assertRaises(SystemError, action, frozenset({1}), *args)
|
||||
self.assertRaises(SystemError, action, frozenset_subclass(), *args)
|
||||
self.assertRaises(SystemError, action, frozenset_subclass({1}), *args)
|
||||
|
||||
def test_set_check(self):
|
||||
check = _testcapi.set_check
|
||||
self.assertTrue(check(set()))
|
||||
self.assertTrue(check({1, 2}))
|
||||
self.assertFalse(check(frozenset()))
|
||||
self.assertTrue(check(set_subclass()))
|
||||
self.assertFalse(check(frozenset_subclass()))
|
||||
self.assertFalse(check(object()))
|
||||
# CRASHES: check(NULL)
|
||||
|
||||
def test_set_check_exact(self):
|
||||
check = _testcapi.set_checkexact
|
||||
self.assertTrue(check(set()))
|
||||
self.assertTrue(check({1, 2}))
|
||||
self.assertFalse(check(frozenset()))
|
||||
self.assertFalse(check(set_subclass()))
|
||||
self.assertFalse(check(frozenset_subclass()))
|
||||
self.assertFalse(check(object()))
|
||||
# CRASHES: check(NULL)
|
||||
|
||||
def test_frozenset_check(self):
|
||||
check = _testcapi.frozenset_check
|
||||
self.assertFalse(check(set()))
|
||||
self.assertTrue(check(frozenset()))
|
||||
self.assertTrue(check(frozenset({1, 2})))
|
||||
self.assertFalse(check(set_subclass()))
|
||||
self.assertTrue(check(frozenset_subclass()))
|
||||
self.assertFalse(check(object()))
|
||||
# CRASHES: check(NULL)
|
||||
|
||||
def test_frozenset_check_exact(self):
|
||||
check = _testcapi.frozenset_checkexact
|
||||
self.assertFalse(check(set()))
|
||||
self.assertTrue(check(frozenset()))
|
||||
self.assertTrue(check(frozenset({1, 2})))
|
||||
self.assertFalse(check(set_subclass()))
|
||||
self.assertFalse(check(frozenset_subclass()))
|
||||
self.assertFalse(check(object()))
|
||||
# CRASHES: check(NULL)
|
||||
|
||||
def test_anyset_check(self):
|
||||
check = _testcapi.anyset_check
|
||||
self.assertTrue(check(set()))
|
||||
self.assertTrue(check({1, 2}))
|
||||
self.assertTrue(check(frozenset()))
|
||||
self.assertTrue(check(frozenset({1, 2})))
|
||||
self.assertTrue(check(set_subclass()))
|
||||
self.assertTrue(check(frozenset_subclass()))
|
||||
self.assertFalse(check(object()))
|
||||
# CRASHES: check(NULL)
|
||||
|
||||
def test_anyset_check_exact(self):
|
||||
check = _testcapi.anyset_checkexact
|
||||
self.assertTrue(check(set()))
|
||||
self.assertTrue(check({1, 2}))
|
||||
self.assertTrue(check(frozenset()))
|
||||
self.assertTrue(check(frozenset({1, 2})))
|
||||
self.assertFalse(check(set_subclass()))
|
||||
self.assertFalse(check(frozenset_subclass()))
|
||||
self.assertFalse(check(object()))
|
||||
# CRASHES: check(NULL)
|
||||
|
||||
def test_set_new(self):
|
||||
set_new = _testcapi.set_new
|
||||
self.assertEqual(set_new().__class__, set)
|
||||
self.assertEqual(set_new(), set())
|
||||
self.assertEqual(set_new((1, 1, 2)), {1, 2})
|
||||
self.assertEqual(set_new([1, 1, 2]), {1, 2})
|
||||
with self.assertRaisesRegex(TypeError, 'object is not iterable'):
|
||||
set_new(object())
|
||||
with self.assertRaisesRegex(TypeError, 'object is not iterable'):
|
||||
set_new(1)
|
||||
with self.assertRaisesRegex(TypeError, "unhashable type: 'dict'"):
|
||||
set_new((1, {}))
|
||||
|
||||
def test_frozenset_new(self):
|
||||
frozenset_new = _testcapi.frozenset_new
|
||||
self.assertEqual(frozenset_new().__class__, frozenset)
|
||||
self.assertEqual(frozenset_new(), frozenset())
|
||||
self.assertEqual(frozenset_new((1, 1, 2)), frozenset({1, 2}))
|
||||
self.assertEqual(frozenset_new([1, 1, 2]), frozenset({1, 2}))
|
||||
with self.assertRaisesRegex(TypeError, 'object is not iterable'):
|
||||
frozenset_new(object())
|
||||
with self.assertRaisesRegex(TypeError, 'object is not iterable'):
|
||||
frozenset_new(1)
|
||||
with self.assertRaisesRegex(TypeError, "unhashable type: 'dict'"):
|
||||
frozenset_new((1, {}))
|
||||
|
||||
def test_set_size(self):
|
||||
get_size = _testcapi.set_size
|
||||
self.assertEqual(get_size(set()), 0)
|
||||
self.assertEqual(get_size(frozenset()), 0)
|
||||
self.assertEqual(get_size({1, 1, 2}), 2)
|
||||
self.assertEqual(get_size(frozenset({1, 1, 2})), 2)
|
||||
self.assertEqual(get_size(set_subclass((1, 2, 3))), 3)
|
||||
self.assertEqual(get_size(frozenset_subclass((1, 2, 3))), 3)
|
||||
with self.assertRaises(SystemError):
|
||||
get_size(object())
|
||||
# CRASHES: get_size(NULL)
|
||||
|
||||
def test_set_get_size(self):
|
||||
get_size = _testcapi.set_get_size
|
||||
self.assertEqual(get_size(set()), 0)
|
||||
self.assertEqual(get_size(frozenset()), 0)
|
||||
self.assertEqual(get_size({1, 1, 2}), 2)
|
||||
self.assertEqual(get_size(frozenset({1, 1, 2})), 2)
|
||||
self.assertEqual(get_size(set_subclass((1, 2, 3))), 3)
|
||||
self.assertEqual(get_size(frozenset_subclass((1, 2, 3))), 3)
|
||||
# CRASHES: get_size(NULL)
|
||||
# CRASHES: get_size(object())
|
||||
|
||||
def test_set_contains(self):
|
||||
contains = _testcapi.set_contains
|
||||
for cls in (set, frozenset, set_subclass, frozenset_subclass):
|
||||
with self.subTest(cls=cls):
|
||||
instance = cls((1, 2))
|
||||
self.assertTrue(contains(instance, 1))
|
||||
self.assertFalse(contains(instance, 'missing'))
|
||||
with self.assertRaisesRegex(TypeError, "unhashable type: 'list'"):
|
||||
contains(instance, [])
|
||||
# CRASHES: contains(instance, NULL)
|
||||
# CRASHES: contains(NULL, object())
|
||||
# CRASHES: contains(NULL, NULL)
|
||||
|
||||
def test_add(self):
|
||||
add = _testcapi.set_add
|
||||
for cls in (set, set_subclass):
|
||||
with self.subTest(cls=cls):
|
||||
instance = cls((1, 2))
|
||||
self.assertEqual(add(instance, 1), 0)
|
||||
self.assertEqual(instance, {1, 2})
|
||||
self.assertEqual(add(instance, 3), 0)
|
||||
self.assertEqual(instance, {1, 2, 3})
|
||||
with self.assertRaisesRegex(TypeError, "unhashable type: 'list'"):
|
||||
add(instance, [])
|
||||
with self.assertRaises(SystemError):
|
||||
add(object(), 1)
|
||||
self.assertImmutable(add, 1)
|
||||
# CRASHES: add(NULL, object())
|
||||
# CRASHES: add(instance, NULL)
|
||||
# CRASHES: add(NULL, NULL)
|
||||
|
||||
def test_discard(self):
|
||||
discard = _testcapi.set_discard
|
||||
for cls in (set, set_subclass):
|
||||
with self.subTest(cls=cls):
|
||||
instance = cls((1, 2))
|
||||
self.assertEqual(discard(instance, 3), 0)
|
||||
self.assertEqual(instance, {1, 2})
|
||||
self.assertEqual(discard(instance, 1), 1)
|
||||
self.assertEqual(instance, {2})
|
||||
self.assertEqual(discard(instance, 2), 1)
|
||||
self.assertEqual(instance, set())
|
||||
self.assertEqual(discard(instance, 2), 0)
|
||||
self.assertEqual(instance, set())
|
||||
with self.assertRaisesRegex(TypeError, "unhashable type: 'list'"):
|
||||
discard(instance, [])
|
||||
with self.assertRaises(SystemError):
|
||||
discard(object(), 1)
|
||||
self.assertImmutable(discard, 1)
|
||||
# CRASHES: discard(NULL, object())
|
||||
# CRASHES: discard(instance, NULL)
|
||||
# CRASHES: discard(NULL, NULL)
|
||||
|
||||
def test_pop(self):
|
||||
pop = _testcapi.set_pop
|
||||
orig = (1, 2)
|
||||
for cls in (set, set_subclass):
|
||||
with self.subTest(cls=cls):
|
||||
instance = cls(orig)
|
||||
self.assertIn(pop(instance), orig)
|
||||
self.assertEqual(len(instance), 1)
|
||||
self.assertIn(pop(instance), orig)
|
||||
self.assertEqual(len(instance), 0)
|
||||
with self.assertRaises(KeyError):
|
||||
pop(instance)
|
||||
with self.assertRaises(SystemError):
|
||||
pop(object())
|
||||
self.assertImmutable(pop)
|
||||
# CRASHES: pop(NULL)
|
||||
|
||||
def test_clear(self):
|
||||
clear = _testcapi.set_clear
|
||||
for cls in (set, set_subclass):
|
||||
with self.subTest(cls=cls):
|
||||
instance = cls((1, 2))
|
||||
self.assertEqual(clear(instance), 0)
|
||||
self.assertEqual(instance, set())
|
||||
self.assertEqual(clear(instance), 0)
|
||||
self.assertEqual(instance, set())
|
||||
with self.assertRaises(SystemError):
|
||||
clear(object())
|
||||
self.assertImmutable(clear)
|
||||
# CRASHES: clear(NULL)
|
|
@ -159,7 +159,7 @@
|
|||
@MODULE__XXTESTFUZZ_TRUE@_xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c
|
||||
@MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c
|
||||
@MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c _testinternalcapi/test_lock.c _testinternalcapi/pytime.c
|
||||
@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
|
||||
@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
|
||||
@MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c
|
||||
@MODULE__TESTCLINIC_LIMITED_TRUE@_testclinic_limited _testclinic_limited.c
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ int _PyTestCapi_Init_Watchers(PyObject *module);
|
|||
int _PyTestCapi_Init_Long(PyObject *module);
|
||||
int _PyTestCapi_Init_Float(PyObject *module);
|
||||
int _PyTestCapi_Init_Dict(PyObject *module);
|
||||
int _PyTestCapi_Init_Set(PyObject *module);
|
||||
int _PyTestCapi_Init_Structmember(PyObject *module);
|
||||
int _PyTestCapi_Init_Exceptions(PyObject *module);
|
||||
int _PyTestCapi_Init_Code(PyObject *module);
|
||||
|
|
|
@ -0,0 +1,162 @@
|
|||
#include <stddef.h> // ptrdiff_t
|
||||
|
||||
#include "parts.h"
|
||||
#include "util.h"
|
||||
|
||||
static PyObject *
|
||||
set_check(PyObject *self, PyObject *obj)
|
||||
{
|
||||
NULLABLE(obj);
|
||||
RETURN_INT(PySet_Check(obj));
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
set_checkexact(PyObject *self, PyObject *obj)
|
||||
{
|
||||
NULLABLE(obj);
|
||||
RETURN_INT(PySet_CheckExact(obj));
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
frozenset_check(PyObject *self, PyObject *obj)
|
||||
{
|
||||
NULLABLE(obj);
|
||||
RETURN_INT(PyFrozenSet_Check(obj));
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
frozenset_checkexact(PyObject *self, PyObject *obj)
|
||||
{
|
||||
NULLABLE(obj);
|
||||
RETURN_INT(PyFrozenSet_CheckExact(obj));
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
anyset_check(PyObject *self, PyObject *obj)
|
||||
{
|
||||
NULLABLE(obj);
|
||||
RETURN_INT(PyAnySet_Check(obj));
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
anyset_checkexact(PyObject *self, PyObject *obj)
|
||||
{
|
||||
NULLABLE(obj);
|
||||
RETURN_INT(PyAnySet_CheckExact(obj));
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
set_new(PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *iterable = NULL;
|
||||
if (!PyArg_ParseTuple(args, "|O", &iterable)) {
|
||||
return NULL;
|
||||
}
|
||||
return PySet_New(iterable);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
frozenset_new(PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *iterable = NULL;
|
||||
if (!PyArg_ParseTuple(args, "|O", &iterable)) {
|
||||
return NULL;
|
||||
}
|
||||
return PyFrozenSet_New(iterable);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
set_size(PyObject *self, PyObject *obj)
|
||||
{
|
||||
NULLABLE(obj);
|
||||
RETURN_SIZE(PySet_Size(obj));
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
set_get_size(PyObject *self, PyObject *obj)
|
||||
{
|
||||
NULLABLE(obj);
|
||||
RETURN_SIZE(PySet_GET_SIZE(obj));
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
set_contains(PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *obj, *item;
|
||||
if (!PyArg_ParseTuple(args, "OO", &obj, &item)) {
|
||||
return NULL;
|
||||
}
|
||||
NULLABLE(obj);
|
||||
NULLABLE(item);
|
||||
RETURN_INT(PySet_Contains(obj, item));
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
set_add(PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *obj, *item;
|
||||
if (!PyArg_ParseTuple(args, "OO", &obj, &item)) {
|
||||
return NULL;
|
||||
}
|
||||
NULLABLE(obj);
|
||||
NULLABLE(item);
|
||||
RETURN_INT(PySet_Add(obj, item));
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
set_discard(PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *obj, *item;
|
||||
if (!PyArg_ParseTuple(args, "OO", &obj, &item)) {
|
||||
return NULL;
|
||||
}
|
||||
NULLABLE(obj);
|
||||
NULLABLE(item);
|
||||
RETURN_INT(PySet_Discard(obj, item));
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
set_pop(PyObject *self, PyObject *obj)
|
||||
{
|
||||
NULLABLE(obj);
|
||||
return PySet_Pop(obj);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
set_clear(PyObject *self, PyObject *obj)
|
||||
{
|
||||
NULLABLE(obj);
|
||||
RETURN_INT(PySet_Clear(obj));
|
||||
}
|
||||
|
||||
static PyMethodDef test_methods[] = {
|
||||
{"set_check", set_check, METH_O},
|
||||
{"set_checkexact", set_checkexact, METH_O},
|
||||
{"frozenset_check", frozenset_check, METH_O},
|
||||
{"frozenset_checkexact", frozenset_checkexact, METH_O},
|
||||
{"anyset_check", anyset_check, METH_O},
|
||||
{"anyset_checkexact", anyset_checkexact, METH_O},
|
||||
|
||||
{"set_new", set_new, METH_VARARGS},
|
||||
{"frozenset_new", frozenset_new, METH_VARARGS},
|
||||
|
||||
{"set_size", set_size, METH_O},
|
||||
{"set_get_size", set_get_size, METH_O},
|
||||
{"set_contains", set_contains, METH_VARARGS},
|
||||
{"set_add", set_add, METH_VARARGS},
|
||||
{"set_discard", set_discard, METH_VARARGS},
|
||||
{"set_pop", set_pop, METH_O},
|
||||
{"set_clear", set_clear, METH_O},
|
||||
|
||||
{NULL},
|
||||
};
|
||||
|
||||
int
|
||||
_PyTestCapi_Init_Set(PyObject *m)
|
||||
{
|
||||
if (PyModule_AddFunctions(m, test_methods) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -3981,6 +3981,9 @@ PyInit__testcapi(void)
|
|||
if (_PyTestCapi_Init_Dict(m) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
if (_PyTestCapi_Init_Set(m) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
if (_PyTestCapi_Init_Structmember(m) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -102,6 +102,7 @@
|
|||
<ClCompile Include="..\Modules\_testcapi\abstract.c" />
|
||||
<ClCompile Include="..\Modules\_testcapi\unicode.c" />
|
||||
<ClCompile Include="..\Modules\_testcapi\dict.c" />
|
||||
<ClCompile Include="..\Modules\_testcapi\set.c" />
|
||||
<ClCompile Include="..\Modules\_testcapi\datetime.c" />
|
||||
<ClCompile Include="..\Modules\_testcapi\docstring.c" />
|
||||
<ClCompile Include="..\Modules\_testcapi\mem.c" />
|
||||
|
|
Loading…
Reference in New Issue