1092 lines · 38.2 KB · Rust
RawDownload
// 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"    @  e8849ae12c709f2321908879bc724fdb2ab8a781    ◆  0000000000000000000000000000000000000000    [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"    @  e8849ae12c709f2321908879bc724fdb2ab8a781    ◆  0000000000000000000000000000000000000000    [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"    @  e8849ae12c709f2321908879bc724fdb2ab8a781    ◆  0000000000000000000000000000000000000000    [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.