// Copyright 2022 The Jujutsu Authors//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at//// https://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License. use std::ffi::OsString; use indoc::indoc;use itertools::Itertools as _;use regex::Regex; use crate::common::TestEnvironment;use crate::common::TestWorkDir; #[test]fn test_non_utf8_arg() { let test_env = TestEnvironment::default(); #[cfg(unix)] let invalid_utf = { use std::os::unix::ffi::OsStringExt as _; OsString::from_vec(vec![0x66, 0x6f, 0x80, 0x6f]) }; #[cfg(windows)] let invalid_utf = { use std::os::windows::prelude::*; OsString::from_wide(&[0x0066, 0x006f, 0xD800, 0x006f]) }; let output = test_env.run_jj_in(".", [&invalid_utf]); insta::assert_snapshot!(output, @r" ------- stderr ------- Error: Non-UTF-8 argument [EOF] [exit status: 2] ");} #[test]fn test_version() { let test_env = TestEnvironment::default(); let output = test_env.run_jj_in(".", ["--version"]).success(); let stdout = output.stdout.into_raw(); let sanitized = stdout.replace(|c: char| c.is_ascii_hexdigit(), "?"); let expected = [ "jj ?.??.?\n", "jj ?.??.?-????????????????????????????????????????\n", // This test could be made to succeed when `jj` is compiled at a merge commit by adding a // few entries like "jj ?.??.?-????????????????????????????????????????-????????????????? // ???????????????????????\n" here. However, it might be best to keep it failing, so that // we avoid releasing `jj` with such `--version` output. ]; assert!( expected.contains(&sanitized.as_str()), "`jj version` output: {stdout:?}.\nSanitized: {sanitized:?}\nExpected one of: {expected:?}" );} #[test]fn test_no_subcommand() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); // Outside of a repo. let output = test_env.run_jj_in(".", [""; 0]); insta::assert_snapshot!(output, @r#" ------- stderr ------- Hint: Use `jj -h` for a list of available commands. Run `jj config set --user ui.default-command log` to disable this message. Error: There is no jj repo in "." [EOF] [exit status: 1] "#); test_env.add_config(r#"ui.default-command="log""#); let output = test_env.run_jj_in(".", [""; 0]); insta::assert_snapshot!(output, @r#" ------- stderr ------- Error: There is no jj repo in "." [EOF] [exit status: 1] "#); let output = test_env.run_jj_in(".", ["--help"]).success(); insta::assert_snapshot!( output.stdout.normalized().lines().next().unwrap(), @"Jujutsu (An experimental VCS)"); insta::assert_snapshot!(output.stderr, @""); let output = test_env.run_jj_in(".", ["-R", "repo"]).success(); assert_eq!(output, work_dir.run_jj(["log"])); // Inside of a repo. let output = work_dir.run_jj([""; 0]).success(); assert_eq!(output, work_dir.run_jj(["log"])); // Command argument that looks like a command name. work_dir .run_jj(["bookmark", "create", "-r@", "help"]) .success(); work_dir .run_jj(["bookmark", "create", "-r@", "log"]) .success(); work_dir .run_jj(["bookmark", "create", "-r@", "show"]) .success(); // TODO: test_env.run_jj(["-r", "help"]).success() insta::assert_snapshot!(work_dir.run_jj(["-r", "log"]), @r" @ qpvuntsm test.user@example.com 2001-02-03 08:05:07 help log show e8849ae1 │ (empty) (no description set) ~ [EOF] "); insta::assert_snapshot!(work_dir.run_jj(["-r", "show"]), @r" @ qpvuntsm test.user@example.com 2001-02-03 08:05:07 help log show e8849ae1 │ (empty) (no description set) ~ [EOF] "); // Multiple default command strings work. test_env.add_config(r#"ui.default-command=["commit", "-m", "foo"]"#); work_dir.run_jj(["new"]).success(); work_dir.write_file("file.txt", "file"); let output = work_dir.run_jj([""; 0]); insta::assert_snapshot!(output, @r" ------- stderr ------- Working copy (@) now at: kxryzmor 8db1ba9a (empty) (no description set) Parent commit (@-) : lylxulpl 19f3adb2 foo [EOF] ");} #[test]fn test_ignore_working_copy() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); work_dir.write_file("file", "initial"); let output = work_dir.run_jj(["log", "-T", "commit_id"]); insta::assert_snapshot!(output, @r" @ 82a10a4d9ef783fd68b661f40ce10dd80d599d9e ◆ 0000000000000000000000000000000000000000 [EOF] "); // Modify the file. With --ignore-working-copy, we still get the same commit // ID. work_dir.write_file("file", "modified"); let output_again = work_dir.run_jj(["log", "-T", "commit_id", "--ignore-working-copy"]); assert_eq!(output_again, output); // But without --ignore-working-copy, we get a new commit ID. let output = work_dir.run_jj(["log", "-T", "commit_id"]); insta::assert_snapshot!(output, @r" @ 00fc09f48ccf5c8b025a0f93b0ec3b0e4294a598 ◆ 0000000000000000000000000000000000000000 [EOF] ");} #[test]fn test_repo_arg_with_git_init() { let test_env = TestEnvironment::default(); let output = test_env.run_jj_in(".", ["git", "init", "-R=.", "repo"]); insta::assert_snapshot!(output, @r#" ------- stderr ------- Error: There is no jj repo in "." [EOF] [exit status: 1] "#);} #[test]fn test_repo_arg_with_git_clone() { let test_env = TestEnvironment::default(); let output = test_env.run_jj_in(".", ["git", "clone", "-R=.", "remote"]); insta::assert_snapshot!(output, @r#" ------- stderr ------- Error: There is no jj repo in "." [EOF] [exit status: 1] "#);} #[test]fn test_resolve_workspace_directory() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); let sub_dir = work_dir.create_dir_all("dir/subdir"); // Ancestor of cwd let output = sub_dir.run_jj(["status"]); insta::assert_snapshot!(output, @r" The working copy has no changes. Working copy (@) : qpvuntsm e8849ae1 (empty) (no description set) Parent commit (@-): zzzzzzzz 00000000 (empty) (no description set) [EOF] "); // Explicit subdirectory path let output = sub_dir.run_jj(["status", "-R", "."]); insta::assert_snapshot!(output, @r#" ------- stderr ------- Error: There is no jj repo in "." [EOF] [exit status: 1] "#); // Valid explicit path let output = sub_dir.run_jj(["status", "-R", "../.."]); insta::assert_snapshot!(output, @r" The working copy has no changes. Working copy (@) : qpvuntsm e8849ae1 (empty) (no description set) Parent commit (@-): zzzzzzzz 00000000 (empty) (no description set) [EOF] "); // "../../..".ancestors() contains "../..", but it should never be looked up. let output = sub_dir.run_jj(["status", "-R", "../../.."]); insta::assert_snapshot!(output, @r#" ------- stderr ------- Error: There is no jj repo in "../../.." [EOF] [exit status: 1] "#);} #[test]fn test_no_workspace_directory() { let test_env = TestEnvironment::default(); let work_dir = test_env.work_dir("repo"); work_dir.create_dir_all(""); let output = work_dir.run_jj(["status"]); insta::assert_snapshot!(output, @r#" ------- stderr ------- Error: There is no jj repo in "." [EOF] [exit status: 1] "#); let output = test_env.run_jj_in(".", ["status", "-R", "repo"]); insta::assert_snapshot!(output, @r#" ------- stderr ------- Error: There is no jj repo in "repo" [EOF] [exit status: 1] "#); work_dir.create_dir_all(".git"); let output = work_dir.run_jj(["status"]); insta::assert_snapshot!(output, @r#" ------- stderr ------- Error: There is no jj repo in "." Hint: It looks like this is a git repo. You can create a jj repo backed by it by running this: jj git init [EOF] [exit status: 1] "#);} #[test]fn test_bad_path() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); let sub_dir = work_dir.create_dir_all("dir"); // cwd == workspace_root let output = work_dir.run_jj(["file", "show", "../out"]); insta::assert_snapshot!(output.normalize_backslash(), @r#" ------- stderr ------- Error: Failed to parse fileset: Invalid file pattern Caused by: 1: --> 1:1 | 1 | ../out | ^----^ | = Invalid file pattern 2: Path "../out" is not in the repo "." 3: Invalid component ".." in repo-relative path "../out" [EOF] [exit status: 1] "#); // cwd != workspace_root, can't be parsed as repo-relative path let output = sub_dir.run_jj(["file", "show", "../.."]); insta::assert_snapshot!(output.normalize_backslash(), @r#" ------- stderr ------- Error: Failed to parse fileset: Invalid file pattern Caused by: 1: --> 1:1 | 1 | ../.. | ^---^ | = Invalid file pattern 2: Path "../.." is not in the repo "../" 3: Invalid component ".." in repo-relative path "../" [EOF] [exit status: 1] "#); // cwd != workspace_root, can be parsed as repo-relative path let output = test_env.run_jj_in(".", ["file", "show", "-Rrepo", "out"]); insta::assert_snapshot!(output.normalize_backslash(), @r#" ------- stderr ------- Error: Failed to parse fileset: Invalid file pattern Caused by: 1: --> 1:1 | 1 | out | ^-^ | = Invalid file pattern 2: Path "out" is not in the repo "repo" 3: Invalid component ".." in repo-relative path "../out" Hint: Consider using root:"out" to specify repo-relative path [EOF] [exit status: 1] "#);} #[test]fn test_invalid_filesets_looking_like_filepaths() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); let output = work_dir.run_jj(["file", "show", "abc~"]); insta::assert_snapshot!(output, @r" ------- stderr ------- Error: Failed to parse fileset: Syntax error Caused by: --> 1:5 | 1 | abc~ | ^--- | = expected `~` or <primary> Hint: See https://jj-vcs.github.io/jj/latest/filesets/ or use `jj help -k filesets` for filesets syntax and how to match file paths. [EOF] [exit status: 1] ");} #[test]fn test_broken_repo_structure() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); let store_path = work_dir.root().join(".jj").join("repo").join("store"); let store_type_path = store_path.join("type"); // Test the error message when the git repository can't be located. work_dir.remove_file(store_path.join("git_target")); let output = work_dir.run_jj(["log"]); insta::assert_snapshot!(output.strip_stderr_last_line(), @r" ------- stderr ------- Internal error: The repository appears broken or inaccessible Caused by: 1: Cannot access $TEST_ENV/repo/.jj/repo/store/git_target [EOF] [exit status: 255] "); // Test the error message when the commit backend is of unknown type. work_dir.write_file(&store_type_path, "unknown"); let output = work_dir.run_jj(["log"]); insta::assert_snapshot!(output, @r" ------- stderr ------- Internal error: This version of the jj binary doesn't support this type of repo Caused by: Unsupported commit backend type 'unknown' [EOF] [exit status: 255] "); // Test the error message when the file indicating the commit backend type // cannot be read. work_dir.remove_file(&store_type_path); work_dir.create_dir(&store_type_path); let output = work_dir.run_jj(["log"]); insta::assert_snapshot!(output.strip_stderr_last_line(), @r" ------- stderr ------- Internal error: The repository appears broken or inaccessible Caused by: 1: Failed to read commit backend type 2: Cannot access $TEST_ENV/repo/.jj/repo/store/type [EOF] [exit status: 255] "); // Test when the .jj directory is empty. The error message is identical to // the previous one, but writing the default type file would also fail. work_dir.remove_dir_all(".jj"); work_dir.create_dir(".jj"); let output = work_dir.run_jj(["log"]); insta::assert_snapshot!(output.strip_stderr_last_line(), @r" ------- stderr ------- Internal error: The repository appears broken or inaccessible Caused by: 1: Failed to read commit backend type 2: Cannot access $TEST_ENV/repo/.jj/repo/store/type [EOF] [exit status: 255] ");} #[test]fn test_color_config() { let mut test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); // Test that --color=always is respected. let output = work_dir.run_jj(["--color=always", "log", "-T", "commit_id"]); insta::assert_snapshot!(output, @r" [1m[38;5;2m@[0m [38;5;4me8849ae12c709f2321908879bc724fdb2ab8a781[39m [1m[38;5;14m◆[0m [38;5;4m0000000000000000000000000000000000000000[39m [EOF] "); // Test that color is used if it's requested in the config file test_env.add_config(r#"ui.color="always""#); let output = work_dir.run_jj(["log", "-T", "commit_id"]); insta::assert_snapshot!(output, @r" [1m[38;5;2m@[0m [38;5;4me8849ae12c709f2321908879bc724fdb2ab8a781[39m [1m[38;5;14m◆[0m [38;5;4m0000000000000000000000000000000000000000[39m [EOF] "); // Test that --color=never overrides the config. let output = work_dir.run_jj(["--color=never", "log", "-T", "commit_id"]); insta::assert_snapshot!(output, @r" @ e8849ae12c709f2321908879bc724fdb2ab8a781 ◆ 0000000000000000000000000000000000000000 [EOF] "); // Test that --color=auto overrides the config. let output = work_dir.run_jj(["--color=auto", "log", "-T", "commit_id"]); insta::assert_snapshot!(output, @r" @ e8849ae12c709f2321908879bc724fdb2ab8a781 ◆ 0000000000000000000000000000000000000000 [EOF] "); // Test that --config 'ui.color=never' overrides the config. let output = work_dir.run_jj(["--config=ui.color=never", "log", "-T", "commit_id"]); insta::assert_snapshot!(output, @r" @ e8849ae12c709f2321908879bc724fdb2ab8a781 ◆ 0000000000000000000000000000000000000000 [EOF] "); // --color overrides --config 'ui.color=...'. let output = work_dir.run_jj([ "--color", "never", "--config=ui.color=always", "log", "-T", "commit_id", ]); insta::assert_snapshot!(output, @r" @ e8849ae12c709f2321908879bc724fdb2ab8a781 ◆ 0000000000000000000000000000000000000000 [EOF] "); // Test that NO_COLOR does NOT override the request for color in the config file test_env.add_env_var("NO_COLOR", "1"); let work_dir = test_env.work_dir("repo"); let output = work_dir.run_jj(["log", "-T", "commit_id"]); insta::assert_snapshot!(output, @r" [1m[38;5;2m@[0m [38;5;4me8849ae12c709f2321908879bc724fdb2ab8a781[39m [1m[38;5;14m◆[0m [38;5;4m0000000000000000000000000000000000000000[39m [EOF] "); // Test that per-repo config overrides the user config. work_dir.write_file(".jj/repo/config.toml", r#"ui.color = "never""#); let output = work_dir.run_jj(["log", "-T", "commit_id"]); insta::assert_snapshot!(output, @r" @ e8849ae12c709f2321908879bc724fdb2ab8a781 ◆ 0000000000000000000000000000000000000000 [EOF]Lines 1–500 of 1092. Load more
// Copyright 2022 The Jujutsu Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. use std::ffi::OsString; use indoc::indoc; use itertools::Itertools as _; use regex::Regex; use crate::common::TestEnvironment; use crate::common::TestWorkDir; #[test] fn test_non_utf8_arg() { let test_env = TestEnvironment::default(); #[cfg(unix)] let invalid_utf = { use std::os::unix::ffi::OsStringExt as _; OsString::from_vec(vec![0x66, 0x6f, 0x80, 0x6f]) }; #[cfg(windows)] let invalid_utf = { use std::os::windows::prelude::*; OsString::from_wide(&[0x0066, 0x006f, 0xD800, 0x006f]) }; let output = test_env.run_jj_in(".", [&invalid_utf]); insta::assert_snapshot!(output, @r" ------- stderr ------- Error: Non-UTF-8 argument [EOF] [exit status: 2] "); } #[test] fn test_version() { let test_env = TestEnvironment::default(); let output = test_env.run_jj_in(".", ["--version"]).success(); let stdout = output.stdout.into_raw(); let sanitized = stdout.replace(|c: char| c.is_ascii_hexdigit(), "?"); let expected = [ "jj ?.??.?\n", "jj ?.??.?-????????????????????????????????????????\n", // This test could be made to succeed when `jj` is compiled at a merge commit by adding a // few entries like "jj ?.??.?-????????????????????????????????????????-????????????????? // ???????????????????????\n" here. However, it might be best to keep it failing, so that // we avoid releasing `jj` with such `--version` output. ]; assert!( expected.contains(&sanitized.as_str()), "`jj version` output: {stdout:?}.\nSanitized: {sanitized:?}\nExpected one of: {expected:?}" ); } #[test] fn test_no_subcommand() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); // Outside of a repo. let output = test_env.run_jj_in(".", [""; 0]); insta::assert_snapshot!(output, @r#" ------- stderr ------- Hint: Use `jj -h` for a list of available commands. Run `jj config set --user ui.default-command log` to disable this message. Error: There is no jj repo in "." [EOF] [exit status: 1] "#); test_env.add_config(r#"ui.default-command="log""#); let output = test_env.run_jj_in(".", [""; 0]); insta::assert_snapshot!(output, @r#" ------- stderr ------- Error: There is no jj repo in "." [EOF] [exit status: 1] "#); let output = test_env.run_jj_in(".", ["--help"]).success(); insta::assert_snapshot!( output.stdout.normalized().lines().next().unwrap(), @"Jujutsu (An experimental VCS)"); insta::assert_snapshot!(output.stderr, @""); let output = test_env.run_jj_in(".", ["-R", "repo"]).success(); assert_eq!(output, work_dir.run_jj(["log"])); // Inside of a repo. let output = work_dir.run_jj([""; 0]).success(); assert_eq!(output, work_dir.run_jj(["log"])); // Command argument that looks like a command name. work_dir .run_jj(["bookmark", "create", "-r@", "help"]) .success(); work_dir .run_jj(["bookmark", "create", "-r@", "log"]) .success(); work_dir .run_jj(["bookmark", "create", "-r@", "show"]) .success(); // TODO: test_env.run_jj(["-r", "help"]).success() insta::assert_snapshot!(work_dir.run_jj(["-r", "log"]), @r" @ qpvuntsm test.user@example.com 2001-02-03 08:05:07 help log show e8849ae1 │ (empty) (no description set) ~ [EOF] "); insta::assert_snapshot!(work_dir.run_jj(["-r", "show"]), @r" @ qpvuntsm test.user@example.com 2001-02-03 08:05:07 help log show e8849ae1 │ (empty) (no description set) ~ [EOF] "); // Multiple default command strings work. test_env.add_config(r#"ui.default-command=["commit", "-m", "foo"]"#); work_dir.run_jj(["new"]).success(); work_dir.write_file("file.txt", "file"); let output = work_dir.run_jj([""; 0]); insta::assert_snapshot!(output, @r" ------- stderr ------- Working copy (@) now at: kxryzmor 8db1ba9a (empty) (no description set) Parent commit (@-) : lylxulpl 19f3adb2 foo [EOF] "); } #[test] fn test_ignore_working_copy() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); work_dir.write_file("file", "initial"); let output = work_dir.run_jj(["log", "-T", "commit_id"]); insta::assert_snapshot!(output, @r" @ 82a10a4d9ef783fd68b661f40ce10dd80d599d9e ◆ 0000000000000000000000000000000000000000 [EOF] "); // Modify the file. With --ignore-working-copy, we still get the same commit // ID. work_dir.write_file("file", "modified"); let output_again = work_dir.run_jj(["log", "-T", "commit_id", "--ignore-working-copy"]); assert_eq!(output_again, output); // But without --ignore-working-copy, we get a new commit ID. let output = work_dir.run_jj(["log", "-T", "commit_id"]); insta::assert_snapshot!(output, @r" @ 00fc09f48ccf5c8b025a0f93b0ec3b0e4294a598 ◆ 0000000000000000000000000000000000000000 [EOF] "); } #[test] fn test_repo_arg_with_git_init() { let test_env = TestEnvironment::default(); let output = test_env.run_jj_in(".", ["git", "init", "-R=.", "repo"]); insta::assert_snapshot!(output, @r#" ------- stderr ------- Error: There is no jj repo in "." [EOF] [exit status: 1] "#); } #[test] fn test_repo_arg_with_git_clone() { let test_env = TestEnvironment::default(); let output = test_env.run_jj_in(".", ["git", "clone", "-R=.", "remote"]); insta::assert_snapshot!(output, @r#" ------- stderr ------- Error: There is no jj repo in "." [EOF] [exit status: 1] "#); } #[test] fn test_resolve_workspace_directory() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); let sub_dir = work_dir.create_dir_all("dir/subdir"); // Ancestor of cwd let output = sub_dir.run_jj(["status"]); insta::assert_snapshot!(output, @r" The working copy has no changes. Working copy (@) : qpvuntsm e8849ae1 (empty) (no description set) Parent commit (@-): zzzzzzzz 00000000 (empty) (no description set) [EOF] "); // Explicit subdirectory path let output = sub_dir.run_jj(["status", "-R", "."]); insta::assert_snapshot!(output, @r#" ------- stderr ------- Error: There is no jj repo in "." [EOF] [exit status: 1] "#); // Valid explicit path let output = sub_dir.run_jj(["status", "-R", "../.."]); insta::assert_snapshot!(output, @r" The working copy has no changes. Working copy (@) : qpvuntsm e8849ae1 (empty) (no description set) Parent commit (@-): zzzzzzzz 00000000 (empty) (no description set) [EOF] "); // "../../..".ancestors() contains "../..", but it should never be looked up. let output = sub_dir.run_jj(["status", "-R", "../../.."]); insta::assert_snapshot!(output, @r#" ------- stderr ------- Error: There is no jj repo in "../../.." [EOF] [exit status: 1] "#); } #[test] fn test_no_workspace_directory() { let test_env = TestEnvironment::default(); let work_dir = test_env.work_dir("repo"); work_dir.create_dir_all(""); let output = work_dir.run_jj(["status"]); insta::assert_snapshot!(output, @r#" ------- stderr ------- Error: There is no jj repo in "." [EOF] [exit status: 1] "#); let output = test_env.run_jj_in(".", ["status", "-R", "repo"]); insta::assert_snapshot!(output, @r#" ------- stderr ------- Error: There is no jj repo in "repo" [EOF] [exit status: 1] "#); work_dir.create_dir_all(".git"); let output = work_dir.run_jj(["status"]); insta::assert_snapshot!(output, @r#" ------- stderr ------- Error: There is no jj repo in "." Hint: It looks like this is a git repo. You can create a jj repo backed by it by running this: jj git init [EOF] [exit status: 1] "#); } #[test] fn test_bad_path() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); let sub_dir = work_dir.create_dir_all("dir"); // cwd == workspace_root let output = work_dir.run_jj(["file", "show", "../out"]); insta::assert_snapshot!(output.normalize_backslash(), @r#" ------- stderr ------- Error: Failed to parse fileset: Invalid file pattern Caused by: 1: --> 1:1 | 1 | ../out | ^----^ | = Invalid file pattern 2: Path "../out" is not in the repo "." 3: Invalid component ".." in repo-relative path "../out" [EOF] [exit status: 1] "#); // cwd != workspace_root, can't be parsed as repo-relative path let output = sub_dir.run_jj(["file", "show", "../.."]); insta::assert_snapshot!(output.normalize_backslash(), @r#" ------- stderr ------- Error: Failed to parse fileset: Invalid file pattern Caused by: 1: --> 1:1 | 1 | ../.. | ^---^ | = Invalid file pattern 2: Path "../.." is not in the repo "../" 3: Invalid component ".." in repo-relative path "../" [EOF] [exit status: 1] "#); // cwd != workspace_root, can be parsed as repo-relative path let output = test_env.run_jj_in(".", ["file", "show", "-Rrepo", "out"]); insta::assert_snapshot!(output.normalize_backslash(), @r#" ------- stderr ------- Error: Failed to parse fileset: Invalid file pattern Caused by: 1: --> 1:1 | 1 | out | ^-^ | = Invalid file pattern 2: Path "out" is not in the repo "repo" 3: Invalid component ".." in repo-relative path "../out" Hint: Consider using root:"out" to specify repo-relative path [EOF] [exit status: 1] "#); } #[test] fn test_invalid_filesets_looking_like_filepaths() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); let output = work_dir.run_jj(["file", "show", "abc~"]); insta::assert_snapshot!(output, @r" ------- stderr ------- Error: Failed to parse fileset: Syntax error Caused by: --> 1:5 | 1 | abc~ | ^--- | = expected `~` or <primary> Hint: See https://jj-vcs.github.io/jj/latest/filesets/ or use `jj help -k filesets` for filesets syntax and how to match file paths. [EOF] [exit status: 1] "); } #[test] fn test_broken_repo_structure() { let test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); let store_path = work_dir.root().join(".jj").join("repo").join("store"); let store_type_path = store_path.join("type"); // Test the error message when the git repository can't be located. work_dir.remove_file(store_path.join("git_target")); let output = work_dir.run_jj(["log"]); insta::assert_snapshot!(output.strip_stderr_last_line(), @r" ------- stderr ------- Internal error: The repository appears broken or inaccessible Caused by: 1: Cannot access $TEST_ENV/repo/.jj/repo/store/git_target [EOF] [exit status: 255] "); // Test the error message when the commit backend is of unknown type. work_dir.write_file(&store_type_path, "unknown"); let output = work_dir.run_jj(["log"]); insta::assert_snapshot!(output, @r" ------- stderr ------- Internal error: This version of the jj binary doesn't support this type of repo Caused by: Unsupported commit backend type 'unknown' [EOF] [exit status: 255] "); // Test the error message when the file indicating the commit backend type // cannot be read. work_dir.remove_file(&store_type_path); work_dir.create_dir(&store_type_path); let output = work_dir.run_jj(["log"]); insta::assert_snapshot!(output.strip_stderr_last_line(), @r" ------- stderr ------- Internal error: The repository appears broken or inaccessible Caused by: 1: Failed to read commit backend type 2: Cannot access $TEST_ENV/repo/.jj/repo/store/type [EOF] [exit status: 255] "); // Test when the .jj directory is empty. The error message is identical to // the previous one, but writing the default type file would also fail. work_dir.remove_dir_all(".jj"); work_dir.create_dir(".jj"); let output = work_dir.run_jj(["log"]); insta::assert_snapshot!(output.strip_stderr_last_line(), @r" ------- stderr ------- Internal error: The repository appears broken or inaccessible Caused by: 1: Failed to read commit backend type 2: Cannot access $TEST_ENV/repo/.jj/repo/store/type [EOF] [exit status: 255] "); } #[test] fn test_color_config() { let mut test_env = TestEnvironment::default(); test_env.run_jj_in(".", ["git", "init", "repo"]).success(); let work_dir = test_env.work_dir("repo"); // Test that --color=always is respected. let output = work_dir.run_jj(["--color=always", "log", "-T", "commit_id"]); insta::assert_snapshot!(output, @r" [1m[38;5;2m@[0m [38;5;4me8849ae12c709f2321908879bc724fdb2ab8a781[39m [1m[38;5;14m◆[0m [38;5;4m0000000000000000000000000000000000000000[39m [EOF] "); // Test that color is used if it's requested in the config file test_env.add_config(r#"ui.color="always""#); let output = work_dir.run_jj(["log", "-T", "commit_id"]); insta::assert_snapshot!(output, @r" [1m[38;5;2m@[0m [38;5;4me8849ae12c709f2321908879bc724fdb2ab8a781[39m [1m[38;5;14m◆[0m [38;5;4m0000000000000000000000000000000000000000[39m [EOF] "); // Test that --color=never overrides the config. let output = work_dir.run_jj(["--color=never", "log", "-T", "commit_id"]); insta::assert_snapshot!(output, @r" @ e8849ae12c709f2321908879bc724fdb2ab8a781 ◆ 0000000000000000000000000000000000000000 [EOF] "); // Test that --color=auto overrides the config. let output = work_dir.run_jj(["--color=auto", "log", "-T", "commit_id"]); insta::assert_snapshot!(output, @r" @ e8849ae12c709f2321908879bc724fdb2ab8a781 ◆ 0000000000000000000000000000000000000000 [EOF] "); // Test that --config 'ui.color=never' overrides the config. let output = work_dir.run_jj(["--config=ui.color=never", "log", "-T", "commit_id"]); insta::assert_snapshot!(output, @r" @ e8849ae12c709f2321908879bc724fdb2ab8a781 ◆ 0000000000000000000000000000000000000000 [EOF] "); // --color overrides --config 'ui.color=...'. let output = work_dir.run_jj([ "--color", "never", "--config=ui.color=always", "log", "-T", "commit_id", ]); insta::assert_snapshot!(output, @r" @ e8849ae12c709f2321908879bc724fdb2ab8a781 ◆ 0000000000000000000000000000000000000000 [EOF] "); // Test that NO_COLOR does NOT override the request for color in the config file test_env.add_env_var("NO_COLOR", "1"); let work_dir = test_env.work_dir("repo"); let output = work_dir.run_jj(["log", "-T", "commit_id"]); insta::assert_snapshot!(output, @r" [1m[38;5;2m@[0m [38;5;4me8849ae12c709f2321908879bc724fdb2ab8a781[39m [1m[38;5;14m◆[0m [38;5;4m0000000000000000000000000000000000000000[39m [EOF] "); // Test that per-repo config overrides the user config. work_dir.write_file(".jj/repo/config.toml", r#"ui.color = "never""#); let output = work_dir.run_jj(["log", "-T", "commit_id"]); insta::assert_snapshot!(output, @r" @ e8849ae12c709f2321908879bc724fdb2ab8a781 ◆ 0000000000000000000000000000000000000000 [EOF]