from test.support import import_helper
-# Skip this test if the _testcapi module isn't available.
+# Skip this test if the _testcapi or _testinternalcapi modules aren't available.
_testcapi = import_helper.import_module('_testcapi')
+_testinternalcapi = import_helper.import_module('_testinternalcapi')
class set_subclass(set):
pass
pass
-class TestSetCAPI(unittest.TestCase):
+class BaseSetTests:
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)
+
+class TestSetCAPI(BaseSetTests, unittest.TestCase):
def test_set_check(self):
check = _testcapi.set_check
self.assertTrue(check(set()))
clear(object())
self.assertImmutable(clear)
# CRASHES: clear(NULL)
+
+
+class TestInternalCAPI(BaseSetTests, unittest.TestCase):
+ def test_set_update(self):
+ update = _testinternalcapi.set_update
+ for cls in (set, set_subclass):
+ for it in ('ab', ('a', 'b'), ['a', 'b'],
+ set('ab'), set_subclass('ab'),
+ frozenset('ab'), frozenset_subclass('ab')):
+ with self.subTest(cls=cls, it=it):
+ instance = cls()
+ self.assertEqual(update(instance, it), 0)
+ self.assertEqual(instance, {'a', 'b'})
+ instance = cls(it)
+ self.assertEqual(update(instance, it), 0)
+ self.assertEqual(instance, {'a', 'b'})
+ with self.assertRaisesRegex(TypeError, 'object is not iterable'):
+ update(cls(), 1)
+ with self.assertRaisesRegex(TypeError, "unhashable type: 'dict'"):
+ update(cls(), [{}])
+ with self.assertRaises(SystemError):
+ update(object(), 'ab')
+ self.assertImmutable(update, 'ab')
+ # CRASHES: update(NULL, object())
+ # CRASHES: update(instance, NULL)
+ # CRASHES: update(NULL, NULL)
+
+ def test_set_next_entry(self):
+ set_next = _testinternalcapi.set_next_entry
+ for cls in (set, set_subclass, frozenset, frozenset_subclass):
+ with self.subTest(cls=cls):
+ instance = cls('abc')
+ pos = 0
+ items = []
+ while True:
+ res = set_next(instance, pos)
+ if res is None:
+ break
+ rc, pos, hash_, item = res
+ items.append(item)
+ self.assertEqual(rc, 1)
+ self.assertIn(item, instance)
+ self.assertEqual(hash(item), hash_)
+ self.assertEqual(items, list(instance))
+ with self.assertRaises(SystemError):
+ set_next(object(), 0)
+ # CRASHES: set_next(NULL, 0)
--- /dev/null
+#include "parts.h"
+#include "../_testcapi/util.h" // NULLABLE, RETURN_INT
+
+#include "pycore_setobject.h"
+
+
+static PyObject *
+set_update(PyObject *self, PyObject *args)
+{
+ PyObject *set, *iterable;
+ if (!PyArg_ParseTuple(args, "OO", &set, &iterable)) {
+ return NULL;
+ }
+ NULLABLE(set);
+ NULLABLE(iterable);
+ RETURN_INT(_PySet_Update(set, iterable));
+}
+
+static PyObject *
+set_next_entry(PyObject *self, PyObject *args)
+{
+ int rc;
+ Py_ssize_t pos;
+ Py_hash_t hash = (Py_hash_t)UNINITIALIZED_SIZE;
+ PyObject *set, *item = UNINITIALIZED_PTR;
+ if (!PyArg_ParseTuple(args, "On", &set, &pos)) {
+ return NULL;
+ }
+ NULLABLE(set);
+
+ rc = _PySet_NextEntry(set, &pos, &item, &hash);
+ if (rc == 1) {
+ return Py_BuildValue("innO", rc, pos, hash, item);
+ }
+ assert(item == UNINITIALIZED_PTR);
+ assert(hash == (Py_hash_t)UNINITIALIZED_SIZE);
+ if (rc == -1) {
+ return NULL;
+ }
+ assert(rc == 0);
+ Py_RETURN_NONE;
+}
+
+
+static PyMethodDef TestMethods[] = {
+ {"set_update", set_update, METH_VARARGS},
+ {"set_next_entry", set_next_entry, METH_VARARGS},
+
+ {NULL},
+};
+
+int
+_PyTestInternalCapi_Init_Set(PyObject *m)
+{
+ if (PyModule_AddFunctions(m, TestMethods) < 0) {
+ return -1;
+ }
+ return 0;
+}