-
-
Notifications
You must be signed in to change notification settings - Fork 32.1k
gh-110525: Add CAPI tests for set
and frozenset
objects
#110526
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
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_child(set): | ||
pass | ||
|
||
class frozenset_child(frozenset): | ||
pass | ||
|
||
|
||
class TestSetCAPI(unittest.TestCase): | ||
def assertImmutable(self, action, *args): | ||
self.assertRaises(SystemError, action, frozenset(), *args) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. SystemError? That's a surprising error. Usually, it's used when the C API is misused, like passing NULL or the wrong type. frozenset is a "wrong type" here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, immutable frozenset is a wrong type for mutation-based functions :) |
||
self.assertRaises(SystemError, action, frozenset({1}), *args) | ||
self.assertRaises(SystemError, action, frozenset_child(), *args) | ||
self.assertRaises(SystemError, action, frozenset_child({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_child())) | ||
self.assertFalse(check(frozenset_child())) | ||
self.assertFalse(check(object())) | ||
|
||
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_child())) | ||
self.assertFalse(check(frozenset_child())) | ||
self.assertFalse(check(object())) | ||
|
||
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_child())) | ||
self.assertTrue(check(frozenset_child())) | ||
self.assertFalse(check(object())) | ||
|
||
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_child())) | ||
self.assertFalse(check(frozenset_child())) | ||
self.assertFalse(check(object())) | ||
|
||
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_child())) | ||
self.assertTrue(check(frozenset_child())) | ||
self.assertFalse(check(object())) | ||
|
||
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_child())) | ||
self.assertFalse(check(frozenset_child())) | ||
self.assertFalse(check(object())) | ||
|
||
def test_set_new(self): | ||
new = _testcapi.set_new | ||
sobolevn marked this conversation as resolved.
Show resolved
Hide resolved
|
||
self.assertEqual(new().__class__, set) | ||
self.assertEqual(new(), set()) | ||
self.assertEqual(new((1, 1, 2)), {1, 2}) | ||
with self.assertRaisesRegex(TypeError, 'object is not iterable'): | ||
new(object()) | ||
with self.assertRaisesRegex(TypeError, "unhashable type: 'dict'"): | ||
new((1, {})) | ||
|
||
def test_frozenset_new(self): | ||
new = _testcapi.frozenset_new | ||
self.assertEqual(new().__class__, frozenset) | ||
self.assertEqual(new(), frozenset()) | ||
self.assertEqual(new((1, 1, 2)), frozenset({1, 2})) | ||
with self.assertRaisesRegex(TypeError, 'object is not iterable'): | ||
new(object()) | ||
with self.assertRaisesRegex(TypeError, "unhashable type: 'dict'"): | ||
new((1, {})) | ||
|
||
def test_set_size(self): | ||
l = _testcapi.set_size | ||
sobolevn marked this conversation as resolved.
Show resolved
Hide resolved
|
||
self.assertEqual(l(set()), 0) | ||
self.assertEqual(l(frozenset()), 0) | ||
self.assertEqual(l({1, 1, 2}), 2) | ||
self.assertEqual(l(frozenset({1, 1, 2})), 2) | ||
self.assertEqual(l(set_child((1, 2, 3))), 3) | ||
self.assertEqual(l(frozenset_child((1, 2, 3))), 3) | ||
with self.assertRaises(SystemError): | ||
l([]) | ||
|
||
def test_set_get_size(self): | ||
l = _testcapi.set_get_size | ||
sobolevn marked this conversation as resolved.
Show resolved
Hide resolved
|
||
self.assertEqual(l(set()), 0) | ||
self.assertEqual(l(frozenset()), 0) | ||
self.assertEqual(l({1, 1, 2}), 2) | ||
self.assertEqual(l(frozenset({1, 1, 2})), 2) | ||
self.assertEqual(l(set_child((1, 2, 3))), 3) | ||
self.assertEqual(l(frozenset_child((1, 2, 3))), 3) | ||
# CRASHES: l([]) | ||
|
||
def test_set_contains(self): | ||
c = _testcapi.set_contains | ||
for cls in (set, frozenset, set_child, frozenset_child): | ||
with self.subTest(cls=cls): | ||
instance = cls((1, 2)) | ||
self.assertTrue(c(instance, 1)) | ||
self.assertFalse(c(instance, 'missing')) | ||
|
||
def test_add(self): | ||
add = _testcapi.set_add | ||
for cls in (set, set_child): | ||
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}) | ||
self.assertImmutable(add, 1) | ||
|
||
def test_discard(self): | ||
discard = _testcapi.set_discard | ||
for cls in (set, set_child): | ||
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()) | ||
# Discarding from empty set works | ||
self.assertEqual(discard(instance, 2), 0) | ||
self.assertEqual(instance, set()) | ||
self.assertImmutable(discard, 1) | ||
|
||
def test_pop(self): | ||
pop = _testcapi.set_pop | ||
orig = (1, 2) | ||
for cls in (set, set_child): | ||
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) | ||
self.assertImmutable(pop) | ||
|
||
def test_clear(self): | ||
clear = _testcapi.set_clear | ||
for cls in (set, set_child): | ||
with self.subTest(cls=cls): | ||
instance = cls((1, 2)) | ||
self.assertEqual(clear(instance), 0) | ||
self.assertEqual(instance, set()) | ||
self.assertImmutable(clear) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
#include <stddef.h> // ptrdiff_t | ||
|
||
#include "parts.h" | ||
#include "util.h" | ||
|
||
static PyObject * | ||
set_check(PyObject *self, PyObject *obj) | ||
{ | ||
RETURN_INT(PySet_Check(obj)); | ||
} | ||
|
||
static PyObject * | ||
set_checkexact(PyObject *self, PyObject *obj) | ||
{ | ||
RETURN_INT(PySet_CheckExact(obj)); | ||
} | ||
|
||
static PyObject * | ||
frozenset_check(PyObject *self, PyObject *obj) | ||
{ | ||
RETURN_INT(PyFrozenSet_Check(obj)); | ||
} | ||
|
||
static PyObject * | ||
frozenset_checkexact(PyObject *self, PyObject *obj) | ||
{ | ||
RETURN_INT(PyFrozenSet_CheckExact(obj)); | ||
} | ||
|
||
static PyObject * | ||
anyset_check(PyObject *self, PyObject *obj) | ||
{ | ||
RETURN_INT(PyAnySet_Check(obj)); | ||
} | ||
|
||
static PyObject * | ||
anyset_checkexact(PyObject *self, PyObject *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; | ||
} |
Uh oh!
There was an error while loading. Please reload this page.