@@ -279,6 +279,7 @@ def test_set_next_entry(self):
279279
280280class FrozenSetWriterTests (unittest .TestCase ):
281281 PySet_MINSIZE = _testcapi .PySet_MINSIZE
282+ UNHASHABLE = [1 , 2 , 3 ]
282283
283284 def create_writer (self , size = 0 ):
284285 # Test PyFrozenSetWriter_Create()
@@ -296,6 +297,10 @@ def frozenset_equal(self, result, expected):
296297 self .assertEqual (result , expected )
297298 self .assertEqual (type (result ), frozenset )
298299
300+ def assert_unhashable (self ):
301+ err_msg = f"unhashable type: '{ type (self .UNHASHABLE ).__name__ } '"
302+ return self .assertRaisesRegex (TypeError , err_msg )
303+
299304 def test_get_table_set (self ):
300305 # Test size parameter of PyFrozenSetWriter_Create()
301306 PySet_MINSIZE = self .PySet_MINSIZE
@@ -313,40 +318,78 @@ def create_items(self, nitem):
313318 # Use mortal (and unique) objects to be able to detect reference leaks
314319 return tuple (object () for _ in range (nitem ))
315320
316- def test_add (self ):
317- # Test PyFrozenSetWriter_Append()
321+ def check_add_method (self , add_method ):
318322 items = self .create_items (self .PySet_MINSIZE * 2 - 1 )
319323 table_size = self .compute_table_size (len (items ))
320324 for prealloc in (0 , len (items ) // 2 , len (items ), len (items ) * 10 ):
321325 with self .subTest (size = prealloc ):
322326 writer = self .create_writer ()
327+ add = getattr (writer , add_method )
323328 for item in items :
324- writer . add (item )
329+ add (item )
325330 self .frozenset_equal (writer .finish (), items )
326331
327332 # Test error (unhashable type)
328333 writer = self .create_writer (0 )
329334 writer .update ('abc' )
330- with self .assertRaisesRegex (TypeError , "unhashable type: 'list'" ):
331- writer .add ([])
335+ add = getattr (writer , add_method )
336+ with self .assert_unhashable ():
337+ add (self .UNHASHABLE )
332338 self .frozenset_equal (writer .finish (), frozenset ('abc' ))
333339
334- def test_update (self ):
335- # Test PyFrozenSetWriter_Update()
336- items1 = self .create_items (self .PySet_MINSIZE - 1 )
340+ def test_add (self ):
341+ # Test PyFrozenSetWriter_Add()
342+ self .check_add_method ('add' )
343+
344+ def test_add_steal (self ):
345+ # Test PyFrozenSetWriter_AddSteal()
346+ self .check_add_method ('add_steal' )
347+
348+ def check_update_method (self , update_method ):
349+ items = self .create_items (self .PySet_MINSIZE - 1 )
337350 items2 = self .create_items (self .PySet_MINSIZE - 1 )
338351 common = self .create_items (self .PySet_MINSIZE - 1 )
339- expected = set (items1 ) | set (items2 ) | set (common )
352+ expected = set (items ) | set (items2 ) | set (common )
340353 total = len (expected )
341- self .assertEqual (total , len (items1 ) + len (items2 ) + len (common ))
354+ self .assertEqual (total , len (items ) + len (items2 ) + len (common ))
355+ empty = ()
342356
343357 for prealloc in (0 , total // 2 , total , total * 10 ):
344358 with self .subTest (size = prealloc ):
345359 writer = self .create_writer (prealloc )
346- writer .update (items1 + common )
347- writer .update (common + items2 )
360+ update = getattr (writer , update_method )
361+ update (items + common )
362+ update (common + items2 )
363+ update (empty ) # test nitem=0
348364 self .frozenset_equal (writer .finish (), expected )
349365
366+ # Test error path: first or last item is not hashable
367+ for first in (True , False ):
368+ with self .subTest (first = first ):
369+ if first :
370+ items_error = (self .UNHASHABLE , * items )
371+ expected = frozenset ()
372+ else :
373+ items_error = (* items , self .UNHASHABLE )
374+ expected = frozenset (items )
375+ writer = self .create_writer (0 )
376+ update = getattr (writer , update_method )
377+ with self .assert_unhashable ():
378+ update (items_error )
379+ self .frozenset_equal (writer .finish (), expected )
380+
381+ def test_update (self ):
382+ # Test PyFrozenSetWriter_Update()
383+ self .check_update_method ('update' )
384+
385+ def test_update_array (self ):
386+ # Test PyFrozenSetWriter_UpdateArray()
387+ self .check_update_method ('update_array' )
388+
389+ def test_update_array_steal (self ):
390+ # Test PyFrozenSetWriter_UpdateArraySteal()
391+ self .check_update_method ('update_array_steal' )
392+
350393 def test_finish (self ):
351394 # Test PyFrozenSetWriter_Finish(): track the frozenset in the GC if at
352395 # least one item is tracked by the GC
0 commit comments