use std::fs::{create_dir_all, write}; use anyhow::Error; use which::which; mod acceptance_helpers; use acceptance_helpers::{assert_cmd, set_executable, setup}; #[test] fn test_basic() -> Result<(), Error> { let harness = setup()?; write(harness.join(".envrc"), "export PATH=bogus:$PATH\n")?; create_dir_all(harness.join("bogus"))?; write(harness.join("bogus/hello"), "#!/bin/sh\necho hello world")?; set_executable(harness.join("bogus/hello"))?; assert_cmd!(harness, quickenv "reload", @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- [WARN quickenv] 1 unshimmed commands (1 new). Use 'quickenv shim' to make them available. Set QUICKENV_NO_SHIM_WARNINGS=1 to silence this message. "###); harness.which("hello").unwrap_err(); assert_cmd!(harness, quickenv "shim" "hello", @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Created 1 new shims in [scrubbed $HOME]/.quickenv/bin/. Use 'quickenv unshim ' to remove them again. "###); harness.which("hello")?; assert_cmd!(harness, hello, @r###" success: true exit_code: 0 ----- stdout ----- hello world ----- stderr ----- "###); assert_cmd!(harness, quickenv "unshim" "hello", @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Removed 1 shims from [scrubbed $HOME]/.quickenv/bin/. Use 'quickenv shim ' to add them again "###); which("hello").unwrap_err(); assert_cmd!(harness, quickenv "reload", @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- [WARN quickenv] 1 unshimmed commands. Use 'quickenv shim' to make them available. Set QUICKENV_NO_SHIM_WARNINGS=1 to silence this message. "###); Ok(()) } #[test] fn test_shadowed() -> Result<(), Error> { let mut harness = setup()?; harness.prepend_path(harness.join("bogus")); create_dir_all(harness.join("bogus"))?; write(harness.join("bogus/hello"), "#!/bin/sh\necho hello world")?; set_executable(harness.join("bogus/hello"))?; assert_cmd!(harness, hello, @r###" success: true exit_code: 0 ----- stdout ----- hello world ----- stderr ----- "###); assert_cmd!(harness, quickenv "shim" "hello", @r###" success: false exit_code: 1 ----- stdout ----- ----- stderr ----- [ERROR quickenv] [scrubbed $HOME]/.quickenv/bin/hello is shadowed by an executable of the same name at [scrubbed $HOME]/project/bogus/hello "###); Ok(()) } #[test] fn test_shadowing() -> Result<(), Error> { let harness = setup()?; assert_cmd!(harness, quickenv "shim" "true", @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Created 1 new shims in [scrubbed $HOME]/.quickenv/bin/. Use 'quickenv unshim ' to remove them again. "###); Ok(()) } #[test] fn test_shim_self() -> Result<(), Error> { let harness = setup()?; assert_cmd!(harness, quickenv "unshim" "quickenv", @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- [WARN quickenv] not unshimming own binary Removed 0 shims from [scrubbed $HOME]/.quickenv/bin/. Use 'quickenv shim ' to add them again "###); assert_cmd!(harness, quickenv "shim" "quickenv", @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- [WARN quickenv] not shimming own binary created no new shims. "###); assert_cmd!(harness, quickenv "unshim" "quickenv", @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- [WARN quickenv] not unshimming own binary Removed 0 shims from [scrubbed $HOME]/.quickenv/bin/. Use 'quickenv shim ' to add them again "###); Ok(()) } #[test] fn test_verbosity() -> Result<(), Error> { let mut harness = setup()?; assert_cmd!(harness, quickenv "vars", @r###" success: false exit_code: 1 ----- stdout ----- ----- stderr ----- [ERROR quickenv] failed to find .envrc in current or any parent directory "###); harness.set_var("QUICKENV_LOG", "debug"); assert_cmd!(harness, quickenv "vars", @r###" success: false exit_code: 1 ----- stdout ----- ----- stderr ----- [DEBUG quickenv] argv[0] is "[scrubbed $HOME]/.quickenv/quickenv_bin/quickenv" [DEBUG quickenv] own program name is quickenv, so no shim running [ERROR quickenv] failed to find .envrc in current or any parent directory "###); Ok(()) } #[test] fn test_script_failure() -> Result<(), Error> { let harness = setup()?; write(harness.join(".envrc"), "exit 1")?; assert_cmd!(harness, quickenv "reload", @r###" success: false exit_code: 1 ----- stdout ----- ----- stderr ----- [ERROR quickenv] .envrc exited with status exit status: 1 "###); Ok(()) } #[test] fn test_eating_own_tail() -> Result<(), Error> { let harness = setup()?; assert_cmd!(harness, quickenv "shim" "bash", @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Created 1 new shims in [scrubbed $HOME]/.quickenv/bin/. Use 'quickenv unshim ' to remove them again. "###); write( harness.join(".envrc"), "bash -c 'echo hello world'; export PATH=bogus:$PATH", )?; assert_cmd!(harness, quickenv "reload", @r###" success: true exit_code: 0 ----- stdout ----- hello world ----- stderr ----- "###); create_dir_all(harness.join("bogus"))?; write(harness.join("bogus/hello"), "#!/bin/sh\necho hello world")?; set_executable(harness.join("bogus/hello"))?; assert_cmd!(harness, quickenv "shim" "hello", @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Created 1 new shims in [scrubbed $HOME]/.quickenv/bin/. Use 'quickenv unshim ' to remove them again. "###); assert_cmd!(harness, hello, @r###" success: true exit_code: 0 ----- stdout ----- hello world ----- stderr ----- "###); Ok(()) } #[test] fn test_eating_own_tail2() -> Result<(), Error> { let harness = setup()?; assert_cmd!(harness, quickenv "shim" "bash", @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Created 1 new shims in [scrubbed $HOME]/.quickenv/bin/. Use 'quickenv unshim ' to remove them again. "###); write( harness.join(".envrc"), "echo the value is $MYVALUE\nexport MYVALUE=canary", )?; assert_cmd!(harness, quickenv "reload", @r###" success: true exit_code: 0 ----- stdout ----- the value is ----- stderr ----- "###); // assert that during reloading, we're not shimming bash and accidentally sourcing the old // envvar values. canary should not appear during reload. assert_cmd!(harness, quickenv "reload", @r###" success: true exit_code: 0 ----- stdout ----- the value is ----- stderr ----- "###); Ok(()) } #[test] fn test_exec() -> Result<(), Error> { let harness = setup()?; write(harness.join(".envrc"), "export PATH=bogus:$PATH\n")?; create_dir_all(harness.join("bogus"))?; write(harness.join("bogus/hello"), "#!/bin/sh\necho hello world")?; set_executable(harness.join("bogus/hello"))?; assert_cmd!(harness, quickenv "reload", @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- [WARN quickenv] 1 unshimmed commands (1 new). Use 'quickenv shim' to make them available. Set QUICKENV_NO_SHIM_WARNINGS=1 to silence this message. "###); harness.which("hello").unwrap_err(); assert_cmd!(harness, quickenv "exec" "hello", @r###" success: true exit_code: 0 ----- stdout ----- hello world ----- stderr ----- "###); Ok(()) } #[test] fn test_shim_creating_shims() -> Result<(), Error> { let harness = setup()?; write(harness.join(".envrc"), "export PATH=bogus:$PATH\n")?; assert_cmd!(harness, quickenv "reload", @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- "###); create_dir_all(harness.join("bogus"))?; write(harness.join("bogus/hello"), "#!/bin/sh\necho hello world")?; set_executable(harness.join("bogus/hello"))?; // there is a command. it does not create more commands. quickenv should not amend any output assert_cmd!(harness, quickenv "exec" "hello", @r###" success: true exit_code: 0 ----- stdout ----- hello world ----- stderr ----- "###); // shimming the command should work assert_cmd!(harness, quickenv "shim" "--yes", @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Found these unshimmed commands in your .envrc: hello Quickenv will create this new shim binary in [scrubbed $HOME]/.quickenv/bin/. Inside of [scrubbed $HOME]/project, those commands will run with .envrc enabled. Outside, they will run normally. Created 1 new shims in [scrubbed $HOME]/.quickenv/bin/. Use 'quickenv unshim ' to remove them again. Use 'quickenv shim ' to run additional commands with .envrc enabled. "###); // change the command such that it creates another command, and run it write( harness.join("bogus/hello"), "#!/bin/sh\necho 'echo hello world' > bogus/hello2 && chmod +x bogus/hello2", )?; set_executable(harness.join("bogus/hello"))?; // quickenv should warn that more commands need shimming now assert_cmd!(harness, quickenv "exec" "hello", @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- [WARN quickenv] 1 unshimmed commands (1 new). Use 'quickenv shim' to make them available. Set QUICKENV_NO_SHIM_WARNINGS=1 to silence this message. "###); // quickenv shim should find the new command assert_cmd!(harness, quickenv "shim" "--yes", @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Found these unshimmed commands in your .envrc: hello2 Quickenv will create this new shim binary in [scrubbed $HOME]/.quickenv/bin/. Inside of [scrubbed $HOME]/project, those commands will run with .envrc enabled. Outside, they will run normally. Created 1 new shims in [scrubbed $HOME]/.quickenv/bin/. Use 'quickenv unshim ' to remove them again. Use 'quickenv shim ' to run additional commands with .envrc enabled. "###); Ok(()) } #[test] fn test_auto_shimming() -> Result<(), Error> { let harness = setup()?; write(harness.join(".envrc"), "export PATH=bogus:$PATH\n")?; create_dir_all(harness.join("bogus"))?; write(harness.join("bogus/hello"), "#!/bin/sh\necho hello world")?; set_executable(harness.join("bogus/hello"))?; assert_cmd!(harness, quickenv "reload", @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- [WARN quickenv] 1 unshimmed commands (1 new). Use 'quickenv shim' to make them available. Set QUICKENV_NO_SHIM_WARNINGS=1 to silence this message. "###); assert_cmd!(harness, quickenv "shim" "-y", @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Found these unshimmed commands in your .envrc: hello Quickenv will create this new shim binary in [scrubbed $HOME]/.quickenv/bin/. Inside of [scrubbed $HOME]/project, those commands will run with .envrc enabled. Outside, they will run normally. Created 1 new shims in [scrubbed $HOME]/.quickenv/bin/. Use 'quickenv unshim ' to remove them again. Use 'quickenv shim ' to run additional commands with .envrc enabled. "###); assert_cmd!(harness, quickenv "shim" "-y", @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- created no new shims. Use 'quickenv shim ' to run additional commands with .envrc enabled. "###); Ok(()) } #[test] fn test_no_envrc_context() -> Result<(), Error> { let harness = setup()?; assert_cmd!(harness, quickenv "shim" "echo", @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Created 1 new shims in [scrubbed $HOME]/.quickenv/bin/. Use 'quickenv unshim ' to remove them again. "###); assert_cmd!(harness, echo "hello world", @r###" success: true exit_code: 0 ----- stdout ----- hello world ----- stderr ----- "###); Ok(()) } #[test] fn test_eating_own_tail3() -> Result<(), Error> { // regression: we removed our own PATH from the PATH envvar, but: // 1) the path is actually duplicated, so we didn't remove all copies, and we recurse into // the shim // 2) the shim re-adds the PATH through its envrc cache let mut harness = setup()?; harness.prepend_path(std::fs::canonicalize(harness.join("../.quickenv/bin")).unwrap()); write(harness.join(".envrc"), "export PATH=hello:$PATH:")?; assert_cmd!(harness, quickenv "reload", @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- "###); assert_cmd!(harness, quickenv "shim" "hello", @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Created 1 new shims in [scrubbed $HOME]/.quickenv/bin/. Use 'quickenv unshim ' to remove them again. "###); harness.set_var("QUICKENV_LOG", "debug"); assert_cmd!(harness, hello, @r###" success: false exit_code: 1 ----- stdout ----- ----- stderr ----- [DEBUG quickenv] argv[0] is "[scrubbed $HOME]/.quickenv/bin/hello" [DEBUG quickenv] attempting to launch shim for "[scrubbed $HOME]/.quickenv/bin/hello" [DEBUG quickenv] loading [scrubbed $HOME]/project/.envrc [DEBUG quickenv] removing own entry from PATH: [scrubbed $HOME]/.quickenv/bin [DEBUG quickenv] removing own entry from PATH: [scrubbed $HOME]/.quickenv/bin [ERROR quickenv] failed to run shimmed command Caused by: 0: failed to find actual binary 1: failed to find hello 2: cannot find binary path "###); Ok(()) } #[test] fn test_which() -> Result<(), Error> { let harness = setup()?; write(harness.join(".envrc"), "export PATH=bogus:$PATH\n")?; create_dir_all(harness.join("bogus"))?; write(harness.join("bogus/hello"), "#!/bin/sh\necho hello world")?; set_executable(harness.join("bogus/hello"))?; assert_cmd!(harness, quickenv "reload", @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- [WARN quickenv] 1 unshimmed commands (1 new). Use 'quickenv shim' to make them available. Set QUICKENV_NO_SHIM_WARNINGS=1 to silence this message. "###); assert_cmd!(harness, quickenv "which" "hello", @r###" success: false exit_code: 1 ----- stdout ----- ----- stderr ----- [ERROR quickenv] cannot find binary path "###); assert_cmd!(harness, quickenv "shim" "hello", @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- Created 1 new shims in [scrubbed $HOME]/.quickenv/bin/. Use 'quickenv unshim ' to remove them again. "###); assert_cmd!(harness, quickenv "which" "hello", @r###" success: true exit_code: 0 ----- stdout ----- bogus/hello ----- stderr ----- "###); Ok(()) } #[test] fn test_which_pretend_shimmed() -> Result<(), Error> { let harness = setup()?; write(harness.join(".envrc"), "export PATH=bogus:$PATH\n")?; create_dir_all(harness.join("bogus"))?; assert_cmd!(harness, quickenv "which" "bash", @r###" success: false exit_code: 1 ----- stdout ----- ----- stderr ----- [ERROR quickenv] "bash" is not shimmed by quickenv "###); assert_cmd!(harness, quickenv "reload", @r###" success: true exit_code: 0 ----- stdout ----- ----- stderr ----- "###); assert_cmd!(harness, quickenv "which" "bash", @r###" success: false exit_code: 1 ----- stdout ----- ----- stderr ----- [ERROR quickenv] "bash" is not shimmed by quickenv "###); write(harness.join("bogus/bash"), "#!/bin/sh\necho hello world")?; set_executable(harness.join("bogus/bash"))?; assert_cmd!(harness, quickenv "which" "bash", @r###" success: false exit_code: 1 ----- stdout ----- ----- stderr ----- [ERROR quickenv] "bash" is not shimmed by quickenv "###); assert_cmd!(harness, quickenv "which" "bash" "--pretend-shimmed", @r###" success: true exit_code: 0 ----- stdout ----- bogus/bash ----- stderr ----- "###); Ok(()) }