@@ -227,14 +227,19 @@ def setUp(self):
227227 self .diagnostic = 'inspector diagnostic\n '
228228 self .inspector_exit = 0
229229 self .popen = subprocess .Popen
230+ self .bash = Path (shutil .which ('bash' )).resolve ()
231+ self .converted_configure = '/fixture source/configure'
230232 environment = patch .dict (os .environ )
231233 environment .start ()
232234 self .addCleanup (environment .stop )
233235
234236 def create_process (self , argv , ** options ):
235- if argv [0 ] == 'bash' :
236- prefix = self .output / 'tls-no/prefix/lib/pkgconfig'
237- code = f'from pathlib import Path; p=Path({ str (prefix )!r} ); p.mkdir(parents=True); (p/"libhttpserver.pc").write_text("fixture metadata")'
237+ if argv [0 ] in ('bash' , str (self .bash )):
238+ if argv [1 :3 ] == ['-c' , 'cygpath -u "$1"' ]:
239+ code = f'print({ self .converted_configure !r} )'
240+ else :
241+ prefix = self .output / 'tls-no/prefix/lib/pkgconfig'
242+ code = f'from pathlib import Path; p=Path({ str (prefix )!r} ); p.mkdir(parents=True); (p/"libhttpserver.pc").write_text("fixture metadata")'
238243 elif argv [0 ] == 'fixture-make' :
239244 code = ''
240245 elif argv [0 ] == 'pkg-config' :
@@ -322,28 +327,91 @@ def write(path, *args, **kwargs):
322327 self .assertEqual (self .runner .audit .COMMANDS [- 1 ]['stdout' ], self .dynamic )
323328
324329
330+ class InstalledInspectionWindowsShellTest (InstalledInspectionFailureTest ):
331+ """Selected Windows shell branch with real host compilation and recording.
332+
333+ The shell/converter outputs are controlled; this is not a Windows receipt.
334+ """
335+ def setUp (self ):
336+ super ().setUp ()
337+ selected = self .root / 'selected tools'
338+ selected .mkdir ()
339+ self .bash = selected / ('bash.exe' if os .name == 'nt' else 'bash' )
340+ self .bash .write_text ('controlled producer shell' )
341+ self .bash .chmod (0o755 )
342+ self .runner .platform = SimpleNamespace (system = lambda : 'Windows' )
343+ os .environ ['PATH' ] = str (selected ) + os .pathsep + os .environ ['PATH' ]
344+
345+ def fail_lane (self ):
346+ error = super ().fail_lane ()
347+ records = json .loads ((self .output / 'tls-no/commands.json' ).read_text ())
348+ self .assertEqual (records [0 ]['argv' ], [str (self .bash ), '-c' , 'cygpath -u "$1"' ,
349+ 'configure-path' , (self .source / 'configure' ).as_posix ()])
350+ self .assertEqual (records [0 ]['exit' ], 0 )
351+ self .assertEqual (records [1 ]['argv' ][0 :2 ], [str (self .bash ), self .converted_configure ])
352+ self .assertEqual (records [1 ]['exit' ], 0 )
353+ return error
354+
355+
325356class MatrixTest (unittest .TestCase ):
326357 def setUp (self ):
327358 self .inventory = matrix .load ()
359+ self .temp = tempfile .TemporaryDirectory ()
360+ self .addCleanup (self .temp .cleanup )
361+ self .root = Path (self .temp .name ).resolve ()
328362
329363 def test_optimized_package_configure_selects_release_flags_without_changing_default (self ):
330364 spec = importlib .util .spec_from_file_location ('installed_runner' , Path (__file__ ).with_name ('check-v3-installed-consumer.py' ))
331365 runner = importlib .util .module_from_spec (spec ); spec .loader .exec_module (runner )
332366 with tempfile .TemporaryDirectory () as temp :
333- root = Path (temp )
334- (root / 'configure' ).write_text ('printf "%s\\ n" "$CXXFLAGS" > selected-flags\n exit 23\n ' )
335- for optimized , flags in ((False , '-O0 -g' ), (True , '-O3 -g' )):
336- with self .subTest (optimized = optimized ):
337- output = root / str (optimized ); output .mkdir ()
338- args = SimpleNamespace (compiler = 'selected-cxx' , cc = 'selected-cc' , make = 'make' ,
339- prerequisite_prefix = [], pkg_config_dir = [], provider_prefix = root ,
340- optimized = optimized )
341- with self .assertRaises (RuntimeError ):
342- runner .package_lane (args , root , output , 'no' , self .inventory )
343- self .assertEqual ((output / 'tls-no/build/selected-flags' ).read_text ().strip (), flags )
344- records = json .loads ((output / 'tls-no/commands.json' ).read_text ())
345- self .assertEqual (records [0 ]['exit' ], 23 )
346- self .assertEqual (records [0 ]['environment' ]['CXXFLAGS' ], flags )
367+ self .exercise_configure_flags (runner , Path (temp ).resolve ())
368+
369+ def test_configure_flags_receipt_follows_successful_path_conversion (self ):
370+ spec = importlib .util .spec_from_file_location ('installed_flags_runner' ,
371+ Path (__file__ ).with_name ('check-v3-installed-consumer.py' ))
372+ runner = importlib .util .module_from_spec (spec )
373+ spec .loader .exec_module (runner )
374+ runner .platform = SimpleNamespace (system = lambda : 'Windows' )
375+ popen = subprocess .Popen
376+
377+ def create_process (argv , ** options ):
378+ if argv [1 :3 ] == ['-c' , 'cygpath -u "$1"' ]:
379+ configure = Path (os .path .relpath (argv [- 1 ], options ['cwd' ])).as_posix ()
380+ return popen ([sys .executable , '-c' , f'print({ configure !r} )' ], ** options )
381+ return popen (argv , ** options )
382+
383+ with tempfile .TemporaryDirectory () as temp , \
384+ patch .object (subprocess , 'Popen' , side_effect = create_process ):
385+ self .exercise_configure_flags (runner , Path (temp ).resolve ())
386+
387+ def exercise_configure_flags (self , runner , root ):
388+ (root / 'configure' ).write_text ('printf "%s\\ n" "$CXXFLAGS" > selected-flags\n exit 23\n ' )
389+ for optimized , flags in ((False , '-O0 -g' ), (True , '-O3 -g' )):
390+ with self .subTest (optimized = optimized ):
391+ output = root / str (optimized ); output .mkdir ()
392+ args = SimpleNamespace (compiler = 'selected-cxx' , cc = 'selected-cc' , make = 'make' ,
393+ prerequisite_prefix = [], pkg_config_dir = [], provider_prefix = root ,
394+ optimized = optimized )
395+ with self .assertRaises (RuntimeError ):
396+ runner .package_lane (args , root , output , 'no' , self .inventory )
397+ self .assertEqual ((output / 'tls-no/build/selected-flags' ).read_text ().strip (), flags )
398+ records = json .loads ((output / 'tls-no/commands.json' ).read_text ())
399+ configure = [record for record in records if record ['argv' ][2 :] == [
400+ '--enable-v3-tls=no' , '--disable-examples' ,
401+ '--prefix=' + (output / 'tls-no/prefix' ).as_posix ()]]
402+ self .assertEqual (len (configure ), 1 )
403+ self .assertEqual (configure [0 ]['exit' ], 23 )
404+ self .assertEqual (configure [0 ]['environment' ]['CXXFLAGS' ], flags )
405+ self .assertEqual (records [- 1 ], configure [0 ])
406+ if runner .platform .system () == 'Windows' :
407+ self .assertEqual (len (records ), 2 )
408+ conversion = records [0 ]
409+ self .assertEqual (conversion ['argv' ], [configure [0 ]['argv' ][0 ], '-c' ,
410+ 'cygpath -u "$1"' , 'configure-path' , (root / 'configure' ).as_posix ()])
411+ self .assertEqual (conversion ['exit' ], 0 )
412+ self .assertEqual (Path (conversion ['log' ]).read_text ().strip (), configure [0 ]['argv' ][1 ])
413+ else :
414+ self .assertEqual (records , configure )
347415
348416 def test_complete_matrix_and_identical_cases (self ):
349417 cells = matrix .cells (self .inventory , 'Linux' )
@@ -408,21 +476,24 @@ def test_empty_skipped_failed_suite_is_rejected(self):
408476 matrix .suite_result (output , status )
409477
410478 def test_shared_suite_requires_installed_library_and_static_forbids_it (self ):
411- graph = {'nodes' : [{'id' : '/prefix/lib/libhttpserver.so' }, {'id' : '/consumer' }], 'edges' : []}
412- matrix .check_linkage (graph , 'shared' , Path ('/prefix' ))
479+ prefix = self .root / 'prefix'
480+ consumer = {'id' : str (self .root / 'consumer' )}
481+ graph = {'nodes' : [{'id' : str (prefix / 'lib/libhttpserver.so' )}, consumer ], 'edges' : []}
482+ matrix .check_linkage (graph , 'shared' , prefix )
413483 with self .assertRaises (ValueError ):
414- matrix .check_linkage (graph , 'shared' , Path ( '/ elsewhere') )
484+ matrix .check_linkage (graph , 'shared' , self . root / ' elsewhere' )
415485 with self .assertRaises (ValueError ):
416- matrix .check_linkage (graph , 'static' , Path ( '/ prefix' ) )
417- matrix .check_linkage ({'nodes' : [{ 'id' : '/ consumer' } ], 'edges' : []}, 'static' , Path ( '/ prefix' ) )
486+ matrix .check_linkage (graph , 'static' , prefix )
487+ matrix .check_linkage ({'nodes' : [consumer ], 'edges' : []}, 'static' , prefix )
418488
419489 def test_public_header_contamination_is_rejected_in_private_probes (self ):
420- matrix .check_dependencies (['/prefix/include/httpserver.hpp' , '/source/src/httpserver/detail/io.hpp' ],
421- Path ('/prefix' ), Path ('/source' ), Path ('/build' ), private = True )
490+ prefix , source , build = (self .root / name for name in ('prefix' , 'source' , 'build' ))
491+ matrix .check_dependencies ([str (prefix / 'include/httpserver.hpp' ), str (source / 'src/httpserver/detail/io.hpp' )],
492+ prefix , source , build , private = True )
422493 for private in (False , True ):
423494 with self .assertRaises (ValueError ):
424- matrix .check_dependencies (['/ source/ src/httpserver/server/server.hpp' ],
425- Path ( '/ prefix' ), Path ( '/ source' ), Path ( '/ build' ) , private )
495+ matrix .check_dependencies ([str ( source / ' src/httpserver/server/server.hpp') ],
496+ prefix , source , build , private )
426497
427498 def test_missing_configuration_case_or_different_outcome_is_rejected (self ):
428499 for tls in ('yes' , 'no' ):
@@ -448,11 +519,12 @@ def test_credentials_backed_supported_configuration_expectations(self):
448519 with self .assertRaises (ValueError ): matrix .supported_configuration_results (bad , tls )
449520
450521 def test_private_external_probe_can_use_the_named_host_helper_only (self ):
451- matrix .check_dependencies (['/source/examples/host_poll.hpp' ], Path ('/prefix' ),
452- Path ('/source' ), Path ('/build' ), private = True )
522+ prefix , source , build = (self .root / name for name in ('prefix' , 'source' , 'build' ))
523+ matrix .check_dependencies ([str (source / 'examples/host_poll.hpp' )], prefix ,
524+ source , build , private = True )
453525 with self .assertRaises (ValueError ):
454- matrix .check_dependencies (['/ source/ examples/other.hpp' ], Path ( '/ prefix' ) ,
455- Path ( '/ source' ), Path ( '/ build' ) , private = True )
526+ matrix .check_dependencies ([str ( source / ' examples/other.hpp') ], prefix ,
527+ source , build , private = True )
456528
457529 def test_parity_backend_replays_preserve_unique_release_observations (self ):
458530 case = dict (id = 'h1.1-tls:routing.tseq:hello' , case = 'routing.tseq:hello' , mode = 'h1.1-tls' )
0 commit comments