@@ -1799,6 +1799,192 @@ def __eq__(self, o):
1799
1799
s = {0 }
1800
1800
s .update (other )
1801
1801
1802
+
1803
+ class TestOperationsMutating :
1804
+ """Regression test for bpo-46615"""
1805
+
1806
+ constructor1 = None
1807
+ constructor2 = None
1808
+
1809
+ def make_sets_of_bad_objects (self ):
1810
+ class Bad :
1811
+ def __eq__ (self , other ):
1812
+ if not enabled :
1813
+ return False
1814
+ if randrange (20 ) == 0 :
1815
+ set1 .clear ()
1816
+ if randrange (20 ) == 0 :
1817
+ set2 .clear ()
1818
+ return bool (randrange (2 ))
1819
+ def __hash__ (self ):
1820
+ return randrange (2 )
1821
+ # Don't behave poorly during construction.
1822
+ enabled = False
1823
+ set1 = self .constructor1 (Bad () for _ in range (randrange (50 )))
1824
+ set2 = self .constructor2 (Bad () for _ in range (randrange (50 )))
1825
+ # Now start behaving poorly
1826
+ enabled = True
1827
+ return set1 , set2
1828
+
1829
+ def check_set_op_does_not_crash (self , function ):
1830
+ for _ in range (100 ):
1831
+ set1 , set2 = self .make_sets_of_bad_objects ()
1832
+ try :
1833
+ function (set1 , set2 )
1834
+ except RuntimeError as e :
1835
+ # Just make sure we don't crash here.
1836
+ self .assertIn ("changed size during iteration" , str (e ))
1837
+
1838
+
1839
+ class TestBinaryOpsMutating (TestOperationsMutating ):
1840
+
1841
+ def test_eq_with_mutation (self ):
1842
+ self .check_set_op_does_not_crash (lambda a , b : a == b )
1843
+
1844
+ def test_ne_with_mutation (self ):
1845
+ self .check_set_op_does_not_crash (lambda a , b : a != b )
1846
+
1847
+ def test_lt_with_mutation (self ):
1848
+ self .check_set_op_does_not_crash (lambda a , b : a < b )
1849
+
1850
+ def test_le_with_mutation (self ):
1851
+ self .check_set_op_does_not_crash (lambda a , b : a <= b )
1852
+
1853
+ def test_gt_with_mutation (self ):
1854
+ self .check_set_op_does_not_crash (lambda a , b : a > b )
1855
+
1856
+ def test_ge_with_mutation (self ):
1857
+ self .check_set_op_does_not_crash (lambda a , b : a >= b )
1858
+
1859
+ def test_and_with_mutation (self ):
1860
+ self .check_set_op_does_not_crash (lambda a , b : a & b )
1861
+
1862
+ def test_or_with_mutation (self ):
1863
+ self .check_set_op_does_not_crash (lambda a , b : a | b )
1864
+
1865
+ def test_sub_with_mutation (self ):
1866
+ self .check_set_op_does_not_crash (lambda a , b : a - b )
1867
+
1868
+ def test_xor_with_mutation (self ):
1869
+ self .check_set_op_does_not_crash (lambda a , b : a ^ b )
1870
+
1871
+ def test_iadd_with_mutation (self ):
1872
+ def f (a , b ):
1873
+ a &= b
1874
+ self .check_set_op_does_not_crash (f )
1875
+
1876
+ def test_ior_with_mutation (self ):
1877
+ def f (a , b ):
1878
+ a |= b
1879
+ self .check_set_op_does_not_crash (f )
1880
+
1881
+ def test_isub_with_mutation (self ):
1882
+ def f (a , b ):
1883
+ a -= b
1884
+ self .check_set_op_does_not_crash (f )
1885
+
1886
+ def test_ixor_with_mutation (self ):
1887
+ def f (a , b ):
1888
+ a ^= b
1889
+ self .check_set_op_does_not_crash (f )
1890
+
1891
+ def test_iteration_with_mutation (self ):
1892
+ def f1 (a , b ):
1893
+ for x in a :
1894
+ pass
1895
+ for y in b :
1896
+ pass
1897
+ def f2 (a , b ):
1898
+ for y in b :
1899
+ pass
1900
+ for x in a :
1901
+ pass
1902
+ def f3 (a , b ):
1903
+ for x , y in zip (a , b ):
1904
+ pass
1905
+ self .check_set_op_does_not_crash (f1 )
1906
+ self .check_set_op_does_not_crash (f2 )
1907
+ self .check_set_op_does_not_crash (f3 )
1908
+
1909
+
1910
+ class TestBinaryOpsMutating_Set_Set (TestBinaryOpsMutating , unittest .TestCase ):
1911
+ constructor1 = set
1912
+ constructor2 = set
1913
+
1914
+ class TestBinaryOpsMutating_Subclass_Subclass (TestBinaryOpsMutating , unittest .TestCase ):
1915
+ constructor1 = SetSubclass
1916
+ constructor2 = SetSubclass
1917
+
1918
+ class TestBinaryOpsMutating_Set_Subclass (TestBinaryOpsMutating , unittest .TestCase ):
1919
+ constructor1 = set
1920
+ constructor2 = SetSubclass
1921
+
1922
+ class TestBinaryOpsMutating_Subclass_Set (TestBinaryOpsMutating , unittest .TestCase ):
1923
+ constructor1 = SetSubclass
1924
+ constructor2 = set
1925
+
1926
+
1927
+ class TestMethodsMutating (TestOperationsMutating ):
1928
+
1929
+ def test_issubset_with_mutation (self ):
1930
+ self .check_set_op_does_not_crash (set .issubset )
1931
+
1932
+ def test_issuperset_with_mutation (self ):
1933
+ self .check_set_op_does_not_crash (set .issuperset )
1934
+
1935
+ def test_intersection_with_mutation (self ):
1936
+ self .check_set_op_does_not_crash (set .intersection )
1937
+
1938
+ def test_union_with_mutation (self ):
1939
+ self .check_set_op_does_not_crash (set .union )
1940
+
1941
+ def test_difference_with_mutation (self ):
1942
+ self .check_set_op_does_not_crash (set .difference )
1943
+
1944
+ def test_symmetric_difference_with_mutation (self ):
1945
+ self .check_set_op_does_not_crash (set .symmetric_difference )
1946
+
1947
+ def test_isdisjoint_with_mutation (self ):
1948
+ self .check_set_op_does_not_crash (set .isdisjoint )
1949
+
1950
+ def test_difference_update_with_mutation (self ):
1951
+ self .check_set_op_does_not_crash (set .difference_update )
1952
+
1953
+ def test_intersection_update_with_mutation (self ):
1954
+ self .check_set_op_does_not_crash (set .intersection_update )
1955
+
1956
+ def test_symmetric_difference_update_with_mutation (self ):
1957
+ self .check_set_op_does_not_crash (set .symmetric_difference_update )
1958
+
1959
+ def test_update_with_mutation (self ):
1960
+ self .check_set_op_does_not_crash (set .update )
1961
+
1962
+
1963
+ class TestMethodsMutating_Set_Set (TestMethodsMutating , unittest .TestCase ):
1964
+ constructor1 = set
1965
+ constructor2 = set
1966
+
1967
+ class TestMethodsMutating_Subclass_Subclass (TestMethodsMutating , unittest .TestCase ):
1968
+ constructor1 = SetSubclass
1969
+ constructor2 = SetSubclass
1970
+
1971
+ class TestMethodsMutating_Set_Subclass (TestMethodsMutating , unittest .TestCase ):
1972
+ constructor1 = set
1973
+ constructor2 = SetSubclass
1974
+
1975
+ class TestMethodsMutating_Subclass_Set (TestMethodsMutating , unittest .TestCase ):
1976
+ constructor1 = SetSubclass
1977
+ constructor2 = set
1978
+
1979
+ class TestMethodsMutating_Set_Dict (TestMethodsMutating , unittest .TestCase ):
1980
+ constructor1 = set
1981
+ constructor2 = dict .fromkeys
1982
+
1983
+ class TestMethodsMutating_Set_List (TestMethodsMutating , unittest .TestCase ):
1984
+ constructor1 = set
1985
+ constructor2 = list
1986
+
1987
+
1802
1988
# Application tests (based on David Eppstein's graph recipes ====================================
1803
1989
1804
1990
def powerset (U ):
0 commit comments