2222import signal
2323from dataclasses import dataclass
2424from typing import NamedTuple
25+ from unittest .mock import patch
2526
2627import pytest
2728
@@ -252,14 +253,36 @@ def test_bitonic_sort_comparable_items() -> None:
252253 bitonic_sort ([1 , "two" , 3 , "four" ], 0 , 4 , 1 )
253254
254255
255- def _check_parallel_odd_even_transposition (case : list [object ], rejects : bool ) -> None :
256+ @dataclass
257+ class UnpicklableComparison :
258+ value : int
259+
260+ def __lt__ (self , _other : object , / ) -> bool :
261+ class LocalComparisonError (TypeError ):
262+ pass
263+
264+ raise LocalComparisonError ("comparison failed" )
265+
266+
267+ def _check_parallel_odd_even_transposition (
268+ case : list [object ], error : type [Exception ] | None
269+ ) -> None :
256270 # Give this probe and its workers a process group that the test alone owns.
257271 os .setsid ()
258272 collection = list (case )
259- if rejects :
260- with pytest .raises (TypeError ) :
273+ if error is not None :
274+ with pytest .raises (error ) as caught :
261275 parallel_odd_even_transposition (collection )
276+ if isinstance (case [0 ], UnpicklableComparison ):
277+ assert "LocalComparisonError: comparison failed" in str (caught .value )
262278 assert collection == case
279+ elif len (collection ) < 2 :
280+ with patch (
281+ "multiprocessing.process.BaseProcess.start" ,
282+ side_effect = AssertionError ("trivial input must not start a worker" ),
283+ ):
284+ assert parallel_odd_even_transposition (collection ) is collection
285+ assert all (item is original for item , original in zip (collection , case ))
263286 else :
264287 assert parallel_odd_even_transposition (collection ) is collection
265288 assert collection == sorted (case )
@@ -270,19 +293,25 @@ def _check_parallel_odd_even_transposition(case: list[object], rejects: bool) ->
270293 os .name != "posix" , reason = "timeout cleanup requires process groups"
271294)
272295@pytest .mark .parametrize (
273- ("case" , "rejects " ),
296+ ("case" , "error " ),
274297 [
275- (["c" , "a" , "b" ], False ),
276- ([2.5 , - 1 , 0.0 ], False ),
277- ([Person (cost = 100.0 ), Person (cost = - 100.0 ), Person (name = "Al" )], False ),
278- ([Dog (weight = 15.5 ), Dog (weight = 15.1 ), Dog (name = "Buddy" )], False ),
279- ([1 , "a" ], True ),
280- ([3 , 2 , "a" , 1 ], True ),
298+ ([], None ),
299+ ([1 ], None ),
300+ ([Person ()], None ),
301+ (["c" , "a" , "b" ], None ),
302+ ([2.5 , - 1 , 0.0 ], None ),
303+ ([Person (cost = 100.0 ), Person (cost = - 100.0 ), Person (name = "Al" )], None ),
304+ ([Dog (weight = 15.5 ), Dog (weight = 15.1 ), Dog (name = "Buddy" )], None ),
305+ ([1 , "a" ], TypeError ),
306+ ([3 , 2 , "a" , 1 ], TypeError ),
307+ ([UnpicklableComparison (3 ), UnpicklableComparison (2 )], RuntimeError ),
281308 ],
282309)
283- def test_parallel_odd_even_transposition (case : list [object ], rejects : bool ) -> None :
310+ def test_parallel_odd_even_transposition (
311+ case : list [object ], error : type [Exception ] | None
312+ ) -> None :
284313 process = mp .get_context ("spawn" ).Process (
285- target = _check_parallel_odd_even_transposition , args = (case , rejects )
314+ target = _check_parallel_odd_even_transposition , args = (case , error )
286315 )
287316 process .start ()
288317 try :
0 commit comments