@@ -391,10 +391,13 @@ fn cargo_subcommand_env() {
391391 . canonicalize ( )
392392 . unwrap ( ) ;
393393 let envtest_bin = envtest_bin. to_str ( ) . unwrap ( ) ;
394+ // Previously, `$CARGO` would be left at `envtest_bin`. However, with the
395+ // fix for #15099, `$CARGO` is now overwritten with the path to the current
396+ // exe when it is detected to be a cargo binary.
394397 cargo_process ( "envtest" )
395398 . env ( "PATH" , & path)
396399 . env ( cargo:: CARGO_ENV , & envtest_bin)
397- . with_stdout_data ( format ! ( "{}\n " , envtest_bin ) . raw ( ) . raw ( ) )
400+ . with_stdout_data ( format ! ( "{}\n " , cargo . display ( ) ) . raw ( ) )
398401 . run ( ) ;
399402}
400403
@@ -570,3 +573,87 @@ fn full_did_you_mean() {
570573"# ] ] )
571574 . run ( ) ;
572575}
576+
577+ #[ cargo_test]
578+ fn overwrite_cargo_environment_variable ( ) {
579+ // If passed arguments `arg1 arg2 ...`, this program runs them as a command.
580+ // If passed no arguments, this program simply prints `$CARGO`.
581+ let p = project ( )
582+ . file ( "Cargo.toml" , & basic_manifest ( "foo" , "1.0.0" ) )
583+ . file (
584+ "src/main.rs" ,
585+ r#"
586+ fn main() {
587+ let mut args = std::env::args().skip(1);
588+ if let Some(arg1) = args.next() {
589+ let status = std::process::Command::new(arg1)
590+ .args(args)
591+ .status()
592+ .unwrap();
593+ assert!(status.success());
594+ } else {
595+ eprintln!("{}", std::env::var("CARGO").unwrap());
596+ }
597+ }
598+ "# ,
599+ )
600+ . build ( ) ;
601+
602+ // Create two other cargo binaries in the project root, one with the wrong
603+ // name and one with the right name.
604+ let cargo_exe = cargo_test_support:: cargo_exe ( ) ;
605+ let wrong_name_path = p
606+ . root ( )
607+ . join ( format ! ( "wrong_name{}" , env:: consts:: EXE_SUFFIX ) ) ;
608+ let other_cargo_path = p. root ( ) . join ( cargo_exe. file_name ( ) . unwrap ( ) ) ;
609+ std:: fs:: hard_link ( & cargo_exe, & wrong_name_path) . unwrap ( ) ;
610+ std:: fs:: hard_link ( & cargo_exe, & other_cargo_path) . unwrap ( ) ;
611+
612+ // The output of each of the following commands should be `path-to-cargo`:
613+ // ```
614+ // cargo run
615+ // cargo run -- cargo run
616+ // cargo run -- wrong_name run
617+ // ```
618+
619+ let cargo = cargo_exe. display ( ) . to_string ( ) ;
620+ let wrong_name = wrong_name_path. display ( ) . to_string ( ) ;
621+ let stderr_cargo = format ! (
622+ "{}[EXE]\n " ,
623+ cargo_exe
624+ . canonicalize( )
625+ . unwrap( )
626+ . with_extension( "" )
627+ . to_str( )
628+ . unwrap( )
629+ ) ;
630+
631+ for cmd in [
632+ "run" ,
633+ & format ! ( "run -- {cargo} run" ) ,
634+ & format ! ( "run -- {wrong_name} run" ) ,
635+ ] {
636+ p. cargo ( cmd) . with_stderr_contains ( & stderr_cargo) . run ( ) ;
637+ }
638+
639+ // The output of the following command should be `path-to-other-cargo`:
640+ // ```
641+ // cargo run -- other_cargo run
642+ // ```
643+
644+ let other_cargo = other_cargo_path. display ( ) . to_string ( ) ;
645+ let stderr_other_cargo = format ! (
646+ "{}[EXE]\n " ,
647+ other_cargo_path
648+ . canonicalize( )
649+ . unwrap( )
650+ . with_extension( "" )
651+ . to_str( )
652+ . unwrap( )
653+ . replace( p. root( ) . parent( ) . unwrap( ) . to_str( ) . unwrap( ) , "[ROOT]" )
654+ ) ;
655+
656+ p. cargo ( & format ! ( "run -- {other_cargo} run" ) )
657+ . with_stderr_contains ( stderr_other_cargo)
658+ . run ( ) ;
659+ }
0 commit comments