--- /dev/null
+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)
--- /dev/null
+#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;
+}