@@ -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