Skip to content

Commit 5c19de2

Browse files
committed
Fully write test in C
1 parent 71d9eba commit 5c19de2

2 files changed

Lines changed: 153 additions & 0 deletions

File tree

Lib/test/test_capi/test_set.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,10 @@ def test_clear(self):
222222

223223

224224
class TestPySet_Add(unittest.TestCase):
225+
def test_pyset_add(self):
226+
# Run C-level tests for PySet_Add
227+
_testcapi.test_pyset_add()
228+
225229
def test_set(self):
226230
# Test the PySet_Add c-api for set objects
227231
s = set()

Modules/_testcapimodule.c

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2434,6 +2434,153 @@ test_critical_sections(PyObject *module, PyObject *Py_UNUSED(args))
24342434
Py_RETURN_NONE;
24352435
}
24362436

2437+
static PyObject *
2438+
test_pyset_add_exact_set(PyObject *self, PyObject *Py_UNUSED(ignored))
2439+
{
2440+
// Test: Adding to a regular set
2441+
PyObject *set = PySet_New(NULL);
2442+
if (set == NULL) {
2443+
return NULL;
2444+
}
2445+
PyObject *one = PyLong_FromLong(1);
2446+
assert(one);
2447+
2448+
if (PySet_Add(set, one) < 0) {
2449+
Py_DECREF(set);
2450+
return raiseTestError(self, "test_pyset_add",
2451+
"PySet_Add to empty set failed");
2452+
}
2453+
if (PySet_Size(set) != 1) {
2454+
Py_DECREF(set);
2455+
return raiseTestError(self, "test_pyset_add",
2456+
"set size should be 1 after adding one element");
2457+
}
2458+
if (PySet_Contains(set, one) != 1) {
2459+
Py_DECREF(set);
2460+
return raiseTestError(self, "test_pyset_add",
2461+
"set should contain the added element");
2462+
}
2463+
Py_DECREF(set);
2464+
2465+
// Test: Adding unhashable item should raise TypeError
2466+
set = PySet_New(NULL);
2467+
if (set == NULL) {
2468+
return NULL;
2469+
}
2470+
PyObject *unhashable = PyList_New(0);
2471+
if (unhashable == NULL) {
2472+
Py_DECREF(set);
2473+
return NULL;
2474+
}
2475+
if (PySet_Add(set, unhashable) != -1) {
2476+
Py_DECREF(unhashable);
2477+
Py_DECREF(set);
2478+
return raiseTestError(self, "test_pyset_add",
2479+
"PySet_Add with unhashable should fail");
2480+
}
2481+
if (!PyErr_ExceptionMatches(PyExc_TypeError)) {
2482+
Py_DECREF(unhashable);
2483+
Py_DECREF(set);
2484+
return raiseTestError(self, "test_pyset_add",
2485+
"PySet_Add with unhashable should raise TypeError");
2486+
}
2487+
PyErr_Clear();
2488+
Py_DECREF(unhashable);
2489+
Py_DECREF(set);
2490+
2491+
Py_RETURN_NONE;
2492+
}
2493+
2494+
static PyObject *
2495+
test_pyset_add_frozenset(PyObject *self, PyObject *Py_UNUSED(ignored))
2496+
{
2497+
PyObject *one = PyLong_FromLong(1);
2498+
assert(one);
2499+
2500+
// Test: Adding to uniquely-referenced frozenset should succeed
2501+
PyObject *frozenset = PyFrozenSet_New(NULL);
2502+
if (frozenset == NULL) {
2503+
return NULL;
2504+
}
2505+
2506+
// frozenset is uniquely referenced here, so PySet_Add should work
2507+
if (PySet_Add(frozenset, one) < 0) {
2508+
Py_DECREF(frozenset);
2509+
return raiseTestError(self, "test_pyset_add_frozenset",
2510+
"PySet_Add to uniquely-referenced frozenset failed");
2511+
}
2512+
Py_DECREF(frozenset);
2513+
2514+
// Test: Adding to non-uniquely-referenced frozenset should raise SystemError
2515+
frozenset = PyFrozenSet_New(NULL);
2516+
if (frozenset == NULL) {
2517+
return NULL;
2518+
}
2519+
Py_INCREF(frozenset); // Make it non-uniquely referenced
2520+
2521+
if (PySet_Add(frozenset, one) != -1) {
2522+
Py_DECREF(frozenset);
2523+
Py_DECREF(frozenset);
2524+
return raiseTestError(self, "test_pyset_add_frozenset",
2525+
"PySet_Add to non-uniquely-referenced frozenset should fail");
2526+
}
2527+
if (!PyErr_ExceptionMatches(PyExc_SystemError)) {
2528+
Py_DECREF(frozenset);
2529+
Py_DECREF(frozenset);
2530+
return raiseTestError(self, "test_pyset_add_frozenset",
2531+
"PySet_Add to non-uniquely-referenced frozenset should raise SystemError");
2532+
}
2533+
PyErr_Clear();
2534+
Py_DECREF(frozenset);
2535+
Py_DECREF(frozenset);
2536+
2537+
// Test: GC tracking - frozenset with only immutable items should not be tracked
2538+
frozenset = PyFrozenSet_New(NULL);
2539+
if (frozenset == NULL) {
2540+
return NULL;
2541+
}
2542+
if (PySet_Add(frozenset, one) < 0) {
2543+
Py_DECREF(frozenset);
2544+
return NULL;
2545+
}
2546+
if (PyObject_GC_IsTracked(frozenset)) {
2547+
Py_DECREF(frozenset);
2548+
return raiseTestError(self, "test_pyset_add_frozenset",
2549+
"frozenset with only int should not be GC tracked");
2550+
}
2551+
Py_DECREF(frozenset);
2552+
2553+
// Test: GC tracking - frozenset with tracked object should be tracked
2554+
frozenset = PyFrozenSet_New(NULL);
2555+
if (frozenset == NULL) {
2556+
return NULL;
2557+
}
2558+
2559+
PyObject *tracked_obj = PyErr_NewException("hashable_and_tracked", NULL, NULL);
2560+
if (tracked_obj == NULL) {
2561+
Py_DECREF(frozenset);
2562+
return NULL;
2563+
}
2564+
if (!PyObject_GC_IsTracked(tracked_obj)) {
2565+
return raiseTestError(self, "test_pyset_add_frozenset",
2566+
"test object should be tracked");
2567+
}
2568+
if (PySet_Add(frozenset, tracked_obj) < 0) {
2569+
Py_DECREF(frozenset);
2570+
Py_DECREF(tracked_obj);
2571+
return NULL;
2572+
}
2573+
2574+
if (!PyObject_GC_IsTracked(frozenset)) {
2575+
Py_DECREF(frozenset);
2576+
Py_DECREF(tracked_obj);
2577+
return raiseTestError(self, "test_pyset_add_frozenset",
2578+
"frozenset with with GC tracked object should be tracked");
2579+
}
2580+
2581+
Py_RETURN_NONE;
2582+
}
2583+
24372584

24382585
// Used by `finalize_thread_hang`.
24392586
#if defined(_POSIX_THREADS) && !defined(__wasi__)
@@ -2685,6 +2832,8 @@ static PyMethodDef TestMethods[] = {
26852832
{"test_weakref_capi", test_weakref_capi, METH_NOARGS},
26862833
{"function_set_warning", function_set_warning, METH_NOARGS},
26872834
{"test_critical_sections", test_critical_sections, METH_NOARGS},
2835+
{"test_pyset_add_exact_set", test_pyset_add_exact_set, METH_NOARGS},
2836+
{"test_pyset_add_frozenset", test_pyset_add_frozenset, METH_NOARGS},
26882837
{"finalize_thread_hang", finalize_thread_hang, METH_O, NULL},
26892838
{"test_atexit", test_atexit, METH_NOARGS},
26902839
{"code_offset_to_line", _PyCFunction_CAST(code_offset_to_line), METH_FASTCALL},

0 commit comments

Comments
 (0)