diff --git a/src/subcommand.rs b/src/subcommand.rs index be36912b..1c2ff857 100644 --- a/src/subcommand.rs +++ b/src/subcommand.rs @@ -92,20 +92,20 @@ impl Subcommand { arguments: &[String], overrides: &BTreeMap, ) -> Result<(), Error<'src>> { - if config.unstable - && matches!( - config.search_config, - SearchConfig::FromInvocationDirectory | SearchConfig::FromSearchDirectory { .. } - ) - { - let mut path = match &config.search_config { + if matches!( + config.search_config, + SearchConfig::FromInvocationDirectory | SearchConfig::FromSearchDirectory { .. } + ) { + let starting_path = match &config.search_config { SearchConfig::FromInvocationDirectory => config.invocation_directory.clone(), - SearchConfig::FromSearchDirectory { search_directory } => std::env::current_dir() - .unwrap() - .join(search_directory.clone()), + SearchConfig::FromSearchDirectory { search_directory } => { + std::env::current_dir().unwrap().join(search_directory) + } _ => unreachable!(), }; + let mut path = starting_path.clone(); + let mut unknown_recipes_errors = None; loop { @@ -116,11 +116,10 @@ impl Subcommand { }, Err(err) => return Err(err.into()), Ok(search) => { - if config.verbosity.loud() && path != config.invocation_directory { + if config.verbosity.loud() && path != starting_path { eprintln!( "Trying {}", - config - .invocation_directory + starting_path .strip_prefix(path) .unwrap() .components() diff --git a/tests/allow_duplicate_recipes.rs b/tests/allow_duplicate_recipes.rs index 9e873e4d..f4fc65df 100644 --- a/tests/allow_duplicate_recipes.rs +++ b/tests/allow_duplicate_recipes.rs @@ -31,7 +31,7 @@ fn allow_duplicate_recipes_with_args() { set allow-duplicate-recipes ", ) - .args(&["b", "one", "two"]) + .args(["b", "one", "two"]) .stdout("bar one two\n") .stderr("echo bar one two\n") .run(); diff --git a/tests/changelog.rs b/tests/changelog.rs index 73fc0ff9..a1a88a0b 100644 --- a/tests/changelog.rs +++ b/tests/changelog.rs @@ -3,7 +3,7 @@ use super::*; #[test] fn print_changelog() { Test::new() - .args(&["--changelog"]) + .args(["--changelog"]) .stdout(fs::read_to_string("CHANGELOG.md").unwrap()) .run(); } diff --git a/tests/choose.rs b/tests/choose.rs index 6444f2a7..d89c31bc 100644 --- a/tests/choose.rs +++ b/tests/choose.rs @@ -128,7 +128,7 @@ fn invoke_error_function() { .stderr_regex("error: Chooser `/ -cu fzf` invocation failed: .*") .status(EXIT_FAILURE) .shell(false) - .args(&["--shell", "/", "--choose"]) + .args(["--shell", "/", "--choose"]) .run(); } diff --git a/tests/dotenv.rs b/tests/dotenv.rs index 257a2d6a..a1182f60 100644 --- a/tests/dotenv.rs +++ b/tests/dotenv.rs @@ -2,26 +2,14 @@ use super::*; #[test] fn dotenv() { - let tmp = temptree! { - ".env": "KEY=ROOT", - sub: { - ".env": "KEY=SUB", - justfile: "default:\n\techo KEY=${KEY:-unset}", - }, - }; - - let binary = executable_path("just"); - - let output = Command::new(binary) - .current_dir(tmp.path()) - .arg("sub/default") - .output() - .expect("just invocation failed"); - - assert_eq!(output.status.code().unwrap(), 0); - - let stdout = str::from_utf8(&output.stdout).unwrap(); - assert_eq!(stdout, "KEY=unset\n"); + Test::new() + .write(".env", "KEY=ROOT") + .write("sub/.env", "KEY=SUB") + .write("sub/justfile", "default:\n\techo KEY=${KEY:-unset}") + .args(["sub/default"]) + .stdout("KEY=unset\n") + .stderr("echo KEY=${KEY:-unset}\n") + .run(); } test! { @@ -83,7 +71,7 @@ fn path_not_found() { echo $NAME ", ) - .args(&["--dotenv-path", ".env.prod"]) + .args(["--dotenv-path", ".env.prod"]) .stderr(if cfg!(windows) { "error: Failed to load environment file: The system cannot find the file specified. (os \ error 2)\n" @@ -108,7 +96,7 @@ fn path_resolves() { ".env": "NAME=bar" } }) - .args(&["--dotenv-path", "subdir/.env"]) + .args(["--dotenv-path", "subdir/.env"]) .stdout("bar\n") .status(EXIT_SUCCESS) .run(); @@ -126,7 +114,7 @@ fn filename_resolves() { .tree(tree! { ".env.special": "NAME=bar" }) - .args(&["--dotenv-filename", ".env.special"]) + .args(["--dotenv-filename", ".env.special"]) .stdout("bar\n") .status(EXIT_SUCCESS) .run(); @@ -146,7 +134,7 @@ fn filename_flag_overwrites_no_load() { .tree(tree! { ".env.special": "NAME=bar" }) - .args(&["--dotenv-filename", ".env.special"]) + .args(["--dotenv-filename", ".env.special"]) .stdout("bar\n") .status(EXIT_SUCCESS) .run(); @@ -168,7 +156,7 @@ fn path_flag_overwrites_no_load() { ".env": "NAME=bar" } }) - .args(&["--dotenv-path", "subdir/.env"]) + .args(["--dotenv-path", "subdir/.env"]) .stdout("bar\n") .status(EXIT_SUCCESS) .run(); diff --git a/tests/error_messages.rs b/tests/error_messages.rs index d5c2300c..8e5fb36a 100644 --- a/tests/error_messages.rs +++ b/tests/error_messages.rs @@ -40,7 +40,7 @@ test! { fn argument_count_mismatch() { Test::new() .justfile("foo a b:") - .args(&["foo"]) + .args(["foo"]) .stderr( " error: Recipe `foo` got 0 arguments but takes 2 diff --git a/tests/fall_back_to_parent.rs b/tests/fallback.rs similarity index 85% rename from tests/fall_back_to_parent.rs rename to tests/fallback.rs index ea4771a4..8a1e2117 100644 --- a/tests/fall_back_to_parent.rs +++ b/tests/fallback.rs @@ -1,5 +1,45 @@ use super::*; +#[test] +fn fallback_from_subdir_bugfix() { + Test::new() + .write( + "sub/justfile", + unindent( + " + set fallback + + @default: + echo foo + ", + ), + ) + .args(["sub/default"]) + .stdout("foo\n") + .run(); +} + +#[test] +fn fallback_from_subdir_message() { + Test::new() + .justfile("bar:\n echo bar") + .write( + "sub/justfile", + unindent( + " + set fallback + + @foo: + echo foo + ", + ), + ) + .args(["sub/bar"]) + .stderr(path("Trying ../justfile\necho bar\n")) + .stdout("bar\n") + .run(); +} + #[test] fn runs_recipe_in_parent_if_not_found_in_current() { Test::new() @@ -19,7 +59,7 @@ fn runs_recipe_in_parent_if_not_found_in_current() { echo root ", ) - .args(&["--unstable", "foo"]) + .args(["foo"]) .current_dir("bar") .stderr(format!( " @@ -51,7 +91,7 @@ fn setting_accepts_value() { echo root ", ) - .args(&["--unstable", "foo"]) + .args(["foo"]) .current_dir("bar") .stderr(format!( " @@ -78,7 +118,7 @@ fn print_error_from_parent_if_recipe_not_found_in_current() { } }) .justfile("foo:\n echo {{bar}}") - .args(&["--unstable", "foo"]) + .args(["foo"]) .current_dir("bar") .stderr(format!( " @@ -95,31 +135,6 @@ fn print_error_from_parent_if_recipe_not_found_in_current() { } #[test] -fn requires_unstable() { - Test::new() - .tree(tree! { - bar: { - justfile: " - baz: - echo subdir - " - } - }) - .justfile( - " - foo: - echo root - ", - ) - .args(&["foo"]) - .current_dir("bar") - .status(EXIT_FAILURE) - .stderr("error: Justfile does not contain recipe `foo`.\n") - .run(); -} - -#[test] -#[ignore] fn requires_setting() { Test::new() .tree(tree! { @@ -136,7 +151,7 @@ fn requires_setting() { echo root ", ) - .args(&["--unstable", "foo"]) + .args(["foo"]) .current_dir("bar") .status(EXIT_FAILURE) .stderr("error: Justfile does not contain recipe `foo`.\n") @@ -162,7 +177,7 @@ fn works_with_provided_search_directory() { echo root ", ) - .args(&["--unstable", "./foo"]) + .args(["./foo"]) .stdout("root\n") .stderr(format!( " @@ -192,7 +207,7 @@ fn doesnt_work_with_justfile() { echo root ", ) - .args(&["--unstable", "--justfile", "justfile", "foo"]) + .args(["--justfile", "justfile", "foo"]) .current_dir("bar") .status(EXIT_FAILURE) .stderr("error: Justfile does not contain recipe `foo`.\n") @@ -216,14 +231,7 @@ fn doesnt_work_with_justfile_and_working_directory() { echo root ", ) - .args(&[ - "--unstable", - "--justfile", - "justfile", - "--working-directory", - ".", - "foo", - ]) + .args(["--justfile", "justfile", "--working-directory", ".", "foo"]) .current_dir("bar") .status(EXIT_FAILURE) .stderr("error: Justfile does not contain recipe `foo`.\n") @@ -249,7 +257,7 @@ fn prints_correct_error_message_when_recipe_not_found() { echo root ", ) - .args(&["--unstable", "foo"]) + .args(["foo"]) .current_dir("bar") .status(EXIT_FAILURE) .stderr(format!( @@ -289,7 +297,7 @@ fn multiple_levels_of_fallback_work() { echo root ", ) - .args(&["--unstable", "baz"]) + .args(["baz"]) .current_dir("a/b") .stdout("root\n") .stderr(format!( @@ -328,7 +336,7 @@ fn stop_fallback_when_fallback_is_false() { echo root ", ) - .args(&["--unstable", "baz"]) + .args(["baz"]) .current_dir("a/b") .stderr(format!( " diff --git a/tests/fmt.rs b/tests/fmt.rs index 37862424..1b46dcd7 100644 --- a/tests/fmt.rs +++ b/tests/fmt.rs @@ -105,7 +105,7 @@ fn write_error() { let test = Test::with_tempdir(tempdir) .no_justfile() - .args(&["--fmt", "--unstable"]) + .args(["--fmt", "--unstable"]) .status(EXIT_FAILURE) .stderr_regex(if cfg!(windows) { r"error: Failed to write justfile to `.*`: Access is denied. \(os error 5\)\n" @@ -1055,7 +1055,7 @@ test! { fn exported_parameter() { Test::new() .justfile("foo +$f:") - .args(&["--dump"]) + .args(["--dump"]) .stdout("foo +$f:\n") .run(); } diff --git a/tests/functions.rs b/tests/functions.rs index 97472b34..14ec4e2f 100644 --- a/tests/functions.rs +++ b/tests/functions.rs @@ -414,7 +414,7 @@ test! { fn assert_eval_eq(expression: &str, result: &str) { Test::new() .justfile(format!("x := {}", expression)) - .args(&["--evaluate", "x"]) + .args(["--evaluate", "x"]) .stdout(result) .unindent_stdout(false) .run(); @@ -478,7 +478,7 @@ fn join() { fn join_argument_count_error() { Test::new() .justfile("x := join('a')") - .args(&["--evaluate"]) + .args(["--evaluate"]) .stderr( " error: Function `join` called with 1 argument but takes 2 or more @@ -498,7 +498,7 @@ fn test_path_exists_filepath_exist() { testfile: "" }) .justfile("x := path_exists('testfile')") - .args(&["--evaluate", "x"]) + .args(["--evaluate", "x"]) .stdout("true") .run(); } @@ -507,7 +507,7 @@ fn test_path_exists_filepath_exist() { fn test_path_exists_filepath_doesnt_exist() { Test::new() .justfile("x := path_exists('testfile')") - .args(&["--evaluate", "x"]) + .args(["--evaluate", "x"]) .stdout("false") .run(); } @@ -516,7 +516,7 @@ fn test_path_exists_filepath_doesnt_exist() { fn error_errors_with_message() { Test::new() .justfile("x := error ('Thing Not Supported')") - .args(&["--evaluate"]) + .args(["--evaluate"]) .status(1) .stderr("error: Call to function `error` failed: Thing Not Supported\n |\n1 | x := error ('Thing Not Supported')\n | ^^^^^\n") .run(); @@ -526,7 +526,7 @@ fn error_errors_with_message() { fn test_absolute_path_resolves() { let test_object = Test::new() .justfile("path := absolute_path('./test_file')") - .args(&["--evaluate", "path"]); + .args(["--evaluate", "path"]); let mut tempdir = test_object.tempdir.path().to_owned(); @@ -546,7 +546,7 @@ fn test_absolute_path_resolves() { fn test_absolute_path_resolves_parent() { let test_object = Test::new() .justfile("path := absolute_path('../test_file')") - .args(&["--evaluate", "path"]); + .args(["--evaluate", "path"]); let mut tempdir = test_object.tempdir.path().to_owned(); @@ -580,7 +580,7 @@ fn path_exists_subdir() { }) .justfile("x := path_exists('foo')") .current_dir("bar") - .args(&["--evaluate", "x"]) + .args(["--evaluate", "x"]) .stdout("true") .run(); } @@ -589,7 +589,7 @@ fn path_exists_subdir() { fn uuid() { Test::new() .justfile("x := uuid()") - .args(&["--evaluate", "x"]) + .args(["--evaluate", "x"]) .stdout_regex("........-....-....-....-............") .run(); } @@ -598,7 +598,7 @@ fn uuid() { fn sha256() { Test::new() .justfile("x := sha256('5943ee37-0000-1000-8000-010203040506')") - .args(&["--evaluate", "x"]) + .args(["--evaluate", "x"]) .stdout("2330d7f5eb94a820b54fed59a8eced236f80b633a504289c030b6a65aef58871") .run(); } @@ -613,7 +613,7 @@ fn sha256_file() { } }) .current_dir("sub") - .args(&["--evaluate", "x"]) + .args(["--evaluate", "x"]) .stdout("177b3d79aaafb53a7a4d7aaba99a82f27c73370e8cb0295571aade1e4fea1cd2") .run(); } diff --git a/tests/init.rs b/tests/init.rs index 7ef27666..deab5bda 100644 --- a/tests/init.rs +++ b/tests/init.rs @@ -46,7 +46,7 @@ fn write_error() { test .no_justfile() - .args(&["--init"]) + .args(["--init"]) .status(EXIT_FAILURE) .stderr_regex(if cfg!(windows) { r"error: Failed to write justfile to `.*`: Access is denied. \(os error 5\)\n" diff --git a/tests/json.rs b/tests/json.rs index a00b2b9f..599bdc01 100644 --- a/tests/json.rs +++ b/tests/json.rs @@ -3,7 +3,7 @@ use super::*; fn test(justfile: &str, value: Value) { Test::new() .justfile(justfile) - .args(&["--dump", "--dump-format", "json", "--unstable"]) + .args(["--dump", "--dump-format", "json", "--unstable"]) .stdout(format!("{}\n", serde_json::to_string(&value).unwrap())) .run(); } @@ -709,7 +709,7 @@ fn quiet() { fn requires_unstable() { Test::new() .justfile("foo:") - .args(&["--dump", "--dump-format", "json"]) + .args(["--dump", "--dump-format", "json"]) .stderr("error: The JSON dump format is currently unstable. Invoke `just` with the `--unstable` flag to enable unstable features.\n") .status(EXIT_FAILURE) .run(); diff --git a/tests/lib.rs b/tests/lib.rs index 506942d3..ce246688 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -47,7 +47,7 @@ mod error_messages; mod evaluate; mod examples; mod export; -mod fall_back_to_parent; +mod fallback; mod fmt; mod functions; mod ignore_comments; @@ -83,3 +83,11 @@ mod undefined_variables; #[cfg(target_family = "windows")] mod windows_shell; mod working_directory; + +fn path(s: &str) -> String { + if cfg!(windows) { + s.replace('/', "\\") + } else { + s.into() + } +} diff --git a/tests/private.rs b/tests/private.rs index 13dcacf5..9ab0cd82 100644 --- a/tests/private.rs +++ b/tests/private.rs @@ -9,7 +9,7 @@ fn private_attribute_for_recipe() { foo: ", ) - .args(&["--list"]) + .args(["--list"]) .stdout( " Available recipes: @@ -29,7 +29,7 @@ fn private_attribute_for_alias() { foo: ", ) - .args(&["--list"]) + .args(["--list"]) .stdout( " Available recipes: diff --git a/tests/quote.rs b/tests/quote.rs index bc6afc40..080a9967 100644 --- a/tests/quote.rs +++ b/tests/quote.rs @@ -8,7 +8,7 @@ fn single_quotes_are_prepended_and_appended() { x := quote('abc') ", ) - .args(&["--evaluate", "x"]) + .args(["--evaluate", "x"]) .stdout("'abc'") .run(); } @@ -21,7 +21,7 @@ fn quotes_are_escaped() { x := quote("'") "#, ) - .args(&["--evaluate", "x"]) + .args(["--evaluate", "x"]) .stdout(r"''\'''") .run(); } diff --git a/tests/run.rs b/tests/run.rs index bad51f8a..7f10cc99 100644 --- a/tests/run.rs +++ b/tests/run.rs @@ -9,7 +9,7 @@ fn dont_run_duplicate_recipes() { # foo ", ) - .args(&["foo", "foo"]) + .args(["foo", "foo"]) .stderr( " # foo diff --git a/tests/slash_operator.rs b/tests/slash_operator.rs index 31859e3b..ab91559f 100644 --- a/tests/slash_operator.rs +++ b/tests/slash_operator.rs @@ -4,7 +4,7 @@ use super::*; fn once() { Test::new() .justfile("x := 'a' / 'b'") - .args(&["--evaluate", "x"]) + .args(["--evaluate", "x"]) .stdout("a/b") .run(); } @@ -13,7 +13,7 @@ fn once() { fn twice() { Test::new() .justfile("x := 'a' / 'b' / 'c'") - .args(&["--evaluate", "x"]) + .args(["--evaluate", "x"]) .stdout("a/b/c") .run(); } @@ -22,7 +22,7 @@ fn twice() { fn no_lhs_once() { Test::new() .justfile("x := / 'a'") - .args(&["--evaluate", "x"]) + .args(["--evaluate", "x"]) .stdout("/a") .run(); } @@ -31,12 +31,12 @@ fn no_lhs_once() { fn no_lhs_twice() { Test::new() .justfile("x := / 'a' / 'b'") - .args(&["--evaluate", "x"]) + .args(["--evaluate", "x"]) .stdout("/a/b") .run(); Test::new() .justfile("x := // 'a'") - .args(&["--evaluate", "x"]) + .args(["--evaluate", "x"]) .stdout("//a") .run(); } diff --git a/tests/test.rs b/tests/test.rs index 58c54221..62bc0895 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -78,8 +78,8 @@ impl Test { self } - pub(crate) fn args(mut self, args: &[&str]) -> Self { - for arg in args { + pub(crate) fn args<'a>(mut self, args: impl AsRef<[&'a str]>) -> Self { + for arg in args.as_ref() { self = self.arg(arg); } self @@ -154,6 +154,13 @@ impl Test { self.unindent_stdout = unindent_stdout; self } + + pub(crate) fn write(self, path: impl AsRef, content: impl AsRef<[u8]>) -> Self { + let path = self.tempdir.path().join(path); + std::fs::create_dir_all(path.parent().unwrap()).unwrap(); + std::fs::write(path, content).unwrap(); + self + } } impl Test {