Skip to content

Commit 9e083b5

Browse files
authored
gh-141510: Test frozendict C API (#145081)
Add tests on functions: * PyAnyDict_Check() * PyAnyDict_CheckExact() * PyFrozenDict_Check() * PyFrozenDict_CheckExact() * PyFrozenDict_New()
1 parent 646bd86 commit 9e083b5

File tree

2 files changed

+110
-0
lines changed

2 files changed

+110
-0
lines changed

Lib/test/test_capi/test_dict.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,19 @@ def gen():
2626
yield 'c'
2727

2828

29+
class FrozenDictSubclass(frozendict):
30+
pass
31+
32+
33+
DICT_TYPES = (dict, DictSubclass, OrderedDict)
34+
FROZENDICT_TYPES = (frozendict, FrozenDictSubclass)
35+
ANYDICT_TYPES = DICT_TYPES + FROZENDICT_TYPES
36+
MAPPING_TYPES = (UserDict,)
37+
NOT_FROZENDICT_TYPES = DICT_TYPES + MAPPING_TYPES
38+
NOT_ANYDICT_TYPES = MAPPING_TYPES
39+
OTHER_TYPES = (lambda: [1], lambda: 42, object) # (list, int, object)
40+
41+
2942
class CAPITest(unittest.TestCase):
3043

3144
def test_dict_check(self):
@@ -545,6 +558,61 @@ def test_dict_popstring(self):
545558
# CRASHES dict_popstring({}, NULL)
546559
# CRASHES dict_popstring({"a": 1}, NULL)
547560

561+
def test_frozendict_check(self):
562+
# Test PyFrozenDict_Check()
563+
check = _testcapi.frozendict_check
564+
for dict_type in FROZENDICT_TYPES:
565+
self.assertTrue(check(dict_type(x=1)))
566+
for dict_type in NOT_FROZENDICT_TYPES + OTHER_TYPES:
567+
self.assertFalse(check(dict_type()))
568+
# CRASHES check(NULL)
569+
570+
def test_frozendict_checkexact(self):
571+
# Test PyFrozenDict_CheckExact()
572+
check = _testcapi.frozendict_checkexact
573+
for dict_type in FROZENDICT_TYPES:
574+
self.assertEqual(check(dict_type(x=1)), dict_type == frozendict)
575+
for dict_type in NOT_FROZENDICT_TYPES + OTHER_TYPES:
576+
self.assertFalse(check(dict_type()))
577+
# CRASHES check(NULL)
578+
579+
def test_anydict_check(self):
580+
# Test PyAnyDict_Check()
581+
check = _testcapi.anydict_check
582+
for dict_type in ANYDICT_TYPES:
583+
self.assertTrue(check(dict_type({1: 2})))
584+
for test_type in NOT_ANYDICT_TYPES + OTHER_TYPES:
585+
self.assertFalse(check(test_type()))
586+
# CRASHES check(NULL)
587+
588+
def test_anydict_checkexact(self):
589+
# Test PyAnyDict_CheckExact()
590+
check = _testcapi.anydict_checkexact
591+
for dict_type in ANYDICT_TYPES:
592+
self.assertEqual(check(dict_type(x=1)),
593+
dict_type in (dict, frozendict))
594+
for test_type in NOT_ANYDICT_TYPES + OTHER_TYPES:
595+
self.assertFalse(check(test_type()))
596+
# CRASHES check(NULL)
597+
598+
def test_frozendict_new(self):
599+
# Test PyFrozenDict_New()
600+
frozendict_new = _testcapi.frozendict_new
601+
602+
for dict_type in ANYDICT_TYPES:
603+
dct = frozendict_new(dict_type({'x': 1}))
604+
self.assertEqual(dct, frozendict(x=1))
605+
self.assertIs(type(dct), frozendict)
606+
607+
dct = frozendict_new([('x', 1), ('y', 2)])
608+
self.assertEqual(dct, frozendict(x=1, y=2))
609+
self.assertIs(type(dct), frozendict)
610+
611+
# PyFrozenDict_New(NULL) creates an empty dictionary
612+
dct = frozendict_new(NULL)
613+
self.assertEqual(dct, frozendict())
614+
self.assertIs(type(dct), frozendict)
615+
548616

549617
if __name__ == "__main__":
550618
unittest.main()

Modules/_testcapi/dict.c

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,43 @@ test_dict_iteration(PyObject* self, PyObject *Py_UNUSED(ignored))
258258
}
259259

260260

261+
static PyObject *
262+
frozendict_check(PyObject *self, PyObject *obj)
263+
{
264+
NULLABLE(obj);
265+
return PyLong_FromLong(PyFrozenDict_Check(obj));
266+
}
267+
268+
static PyObject *
269+
frozendict_checkexact(PyObject *self, PyObject *obj)
270+
{
271+
NULLABLE(obj);
272+
return PyLong_FromLong(PyFrozenDict_CheckExact(obj));
273+
}
274+
275+
static PyObject *
276+
anydict_check(PyObject *self, PyObject *obj)
277+
{
278+
NULLABLE(obj);
279+
return PyLong_FromLong(PyAnyDict_Check(obj));
280+
}
281+
282+
static PyObject *
283+
anydict_checkexact(PyObject *self, PyObject *obj)
284+
{
285+
NULLABLE(obj);
286+
return PyLong_FromLong(PyAnyDict_CheckExact(obj));
287+
}
288+
289+
290+
static PyObject *
291+
frozendict_new(PyObject *self, PyObject *obj)
292+
{
293+
NULLABLE(obj);
294+
return PyFrozenDict_New(obj);
295+
}
296+
297+
261298
static PyMethodDef test_methods[] = {
262299
{"dict_containsstring", dict_containsstring, METH_VARARGS},
263300
{"dict_getitemref", dict_getitemref, METH_VARARGS},
@@ -269,6 +306,11 @@ static PyMethodDef test_methods[] = {
269306
{"dict_popstring", dict_popstring, METH_VARARGS},
270307
{"dict_popstring_null", dict_popstring_null, METH_VARARGS},
271308
{"test_dict_iteration", test_dict_iteration, METH_NOARGS},
309+
{"frozendict_check", frozendict_check, METH_O},
310+
{"frozendict_checkexact", frozendict_checkexact, METH_O},
311+
{"anydict_check", anydict_check, METH_O},
312+
{"anydict_checkexact", anydict_checkexact, METH_O},
313+
{"frozendict_new", frozendict_new, METH_O},
272314
{NULL},
273315
};
274316

0 commit comments

Comments
 (0)