@@ -231,6 +231,8 @@ impl fmt::Display for PythonEnvironment {
231
231
mod tests {
232
232
use super :: * ;
233
233
use std:: fs;
234
+ #[ cfg( unix) ]
235
+ use std:: os:: unix:: fs:: PermissionsExt ; // Needed for setting execute permission
234
236
use tempfile:: tempdir;
235
237
236
238
mod env_discovery {
@@ -289,6 +291,29 @@ mod tests {
289
291
}
290
292
}
291
293
294
+ // Guard struct to temporarily modify the PATH environment variable
295
+ struct PathGuard {
296
+ original_path : Option < String > ,
297
+ }
298
+
299
+ impl PathGuard {
300
+ fn set ( new_path_val : & str ) -> Self {
301
+ let original_path = env:: var ( "PATH" ) . ok ( ) ;
302
+ env:: set_var ( "PATH" , new_path_val) ;
303
+ Self { original_path }
304
+ }
305
+ }
306
+
307
+ impl Drop for PathGuard {
308
+ fn drop ( & mut self ) {
309
+ // Restore original PATH, or remove if it wasn't set initially
310
+ match self . original_path . as_deref ( ) {
311
+ Some ( val) => env:: set_var ( "PATH" , val) ,
312
+ None => env:: remove_var ( "PATH" ) ,
313
+ }
314
+ }
315
+ }
316
+
292
317
#[ test]
293
318
fn test_explicit_venv_path_found ( ) {
294
319
let project_dir = tempdir ( ) . unwrap ( ) ;
@@ -417,31 +442,83 @@ mod tests {
417
442
}
418
443
419
444
#[ test]
420
- #[ ignore = "Relies on system python being available and having standard layout" ]
445
+ // #[ignore = "Relies on system python being available and having standard layout"] // No longer ignored!
421
446
fn test_system_python_fallback ( ) {
422
- let project_dir = tempdir ( ) . unwrap ( ) ;
447
+ let project_dir = tempdir ( ) . unwrap ( ) ; // Dummy project dir, not used for discovery here.
423
448
424
449
// Set VIRTUAL_ENV to something known to be invalid to ensure it's ignored.
425
450
let invalid_virtual_env_path =
426
451
project_dir. path ( ) . join ( "non_existent_venv_sys_fallback" ) ;
427
452
let _guard =
428
453
VirtualEnvGuard :: set ( "VIRTUAL_ENV" , invalid_virtual_env_path. to_str ( ) . unwrap ( ) ) ;
454
+
455
+ // --- Set up mock system python ---
456
+ let mock_sys_python_dir = tempdir ( ) . unwrap ( ) ;
457
+ let mock_sys_python_prefix = mock_sys_python_dir. path ( ) ;
458
+
459
+ #[ cfg( unix) ]
460
+ let ( bin_subdir, python_exe, site_packages_rel_path) = (
461
+ "bin" ,
462
+ "python" ,
463
+ Path :: new ( "lib" ) . join ( "python3.9" ) . join ( "site-packages" ) ,
464
+ ) ;
465
+ #[ cfg( windows) ]
466
+ let ( bin_subdir, python_exe, site_packages_rel_path) = (
467
+ "Scripts" ,
468
+ "python.exe" ,
469
+ Path :: new ( "Lib" ) . join ( "site-packages" ) ,
470
+ ) ;
471
+
472
+ let bin_dir = mock_sys_python_prefix. join ( bin_subdir) ;
473
+ fs:: create_dir_all ( & bin_dir) . unwrap ( ) ;
474
+ let python_path = bin_dir. join ( python_exe) ;
475
+ fs:: write ( & python_path, "" ) . unwrap ( ) ; // Create dummy executable
476
+
477
+ // Ensure the dummy executable has execute permissions (required by `which` on Unix)
478
+ #[ cfg( unix) ]
479
+ {
480
+ let mut perms = fs:: metadata ( & python_path) . unwrap ( ) . permissions ( ) ;
481
+ perms. set_mode ( 0o755 ) ; // rwxr-xr-x
482
+ fs:: set_permissions ( & python_path, perms) . unwrap ( ) ;
483
+ }
484
+
485
+ let site_packages_path = mock_sys_python_prefix. join ( site_packages_rel_path) ;
486
+ fs:: create_dir_all ( & site_packages_path) . unwrap ( ) ;
487
+
488
+ // --- Manipulate PATH ---
489
+ // Completely overwrite PATH to only include the mock bin directory
490
+ let canonical_bin_dir =
491
+ bin_dir. canonicalize ( ) . expect ( "Failed to canonicalize mock bin dir" ) ;
492
+ let new_path = canonical_bin_dir. to_str ( ) . unwrap ( ) . to_string ( ) ;
493
+ let _path_guard = PathGuard :: set ( & new_path) ;
494
+
429
495
// We don't create any venvs in project_dir
430
496
431
497
// This test assumes `which python` works and points to a standard layout
432
498
let system_env = PythonEnvironment :: new ( project_dir. path ( ) , None ) ;
433
499
434
500
assert ! (
435
501
system_env. is_some( ) ,
436
- "Should fall back to system python if available "
502
+ "Should fall back to the mock system python "
437
503
) ;
438
504
439
505
if let Some ( env) = system_env {
440
- // Basic checks - exact paths depend heavily on the test environment
441
- assert ! ( env. python_path. exists( ) ) ;
442
- assert ! ( env. sys_prefix. exists( ) ) ;
443
- assert ! ( !env. sys_path. is_empty( ) ) ;
444
- assert ! ( env. sys_path[ 0 ] . exists( ) ) ; // Should contain the bin/Scripts dir
506
+ assert_eq ! ( env. python_path, python_path, "Python path should match mock" ) ;
507
+ assert_eq ! (
508
+ env. sys_prefix,
509
+ mock_sys_python_prefix,
510
+ "Sys prefix should match mock prefix"
511
+ ) ;
512
+ assert ! (
513
+ env. sys_path. contains( & bin_dir) ,
514
+ "Sys path should contain mock bin dir"
515
+ ) ;
516
+ assert ! (
517
+ env. sys_path. contains( & site_packages_path) ,
518
+ "Sys path should contain mock site-packages"
519
+ ) ;
520
+ } else {
521
+ panic ! ( "Expected to find environment, but got None" ) ; // Should not happen if assert above passed
445
522
}
446
523
}
447
524
0 commit comments