2503 lines · 83.9 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 indoc::indoc;use itertools::Itertools; use crate::common::escaped_fake_diff_editor_path;use crate::common::strip_last_line;use crate::common::TestEnvironment; #[test]fn test_diff_basic() {    let test_env = TestEnvironment::default();    test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);    let repo_path = test_env.env_root().join("repo");     std::fs::write(repo_path.join("file1"), "foo\n").unwrap();    std::fs::write(repo_path.join("file2"), "1\n2\n3\n4\n").unwrap();    test_env.jj_cmd_ok(&repo_path, &["new"]);    std::fs::remove_file(repo_path.join("file1")).unwrap();    std::fs::write(repo_path.join("file2"), "1\n5\n3\n").unwrap();    std::fs::write(repo_path.join("file3"), "foo\n").unwrap();    std::fs::write(repo_path.join("file4"), "1\n2\n3\n4\n").unwrap();     let stdout = test_env.jj_cmd_success(&repo_path, &["diff"]);    insta::assert_snapshot!(stdout, @r###"    Modified regular file file2:       1    1: 1       2    2: 25       3    3: 3       4     : 4    Modified regular file file3 (file1 => file3):    Modified regular file file4 (file2 => file4):    "###);     let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "--context=0"]);    insta::assert_snapshot!(stdout, @r###"    Modified regular file file2:       1    1: 1       2    2: 25       3    3: 3       4     : 4    Modified regular file file3 (file1 => file3):    Modified regular file file4 (file2 => file4):    "###);     let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "--color=debug"]);    insta::assert_snapshot!(stdout, @r###"    <<diff header::Modified regular file file2:>>    <<diff removed line_number::   1>><<diff:: >><<diff added line_number::   1>><<diff::: 1>>    <<diff removed line_number::   2>><<diff:: >><<diff added line_number::   2>><<diff::: >><<diff removed token::2>><<diff added token::5>><<diff::>>    <<diff removed line_number::   3>><<diff:: >><<diff added line_number::   3>><<diff::: 3>>    <<diff removed line_number::   4>><<diff::     : >><<diff removed token::4>>    <<diff header::Modified regular file file3 (file1 => file3):>>    <<diff header::Modified regular file file4 (file2 => file4):>>    "###);     let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "-s"]);    insta::assert_snapshot!(stdout, @r###"    M file2    R {file1 => file3}    C {file2 => file4}    "###);     let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "--types"]);    insta::assert_snapshot!(stdout, @r###"    FF file2    FF {file1 => file3}    FF {file2 => file4}    "###);     let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "--types", "glob:file[12]"]);    insta::assert_snapshot!(stdout, @r###"    F- file1    FF file2    "###);     let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "--git", "file1"]);    insta::assert_snapshot!(stdout, @r###"    diff --git a/file1 b/file1    deleted file mode 100644    index 257cc5642c..0000000000    --- a/file1    +++ /dev/null    @@ -1,1 +1,0 @@    -foo    "###);     let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "--git"]);    insta::assert_snapshot!(stdout, @r###"    diff --git a/file2 b/file2    index 94ebaf9001..1ffc51b472 100644    --- a/file2    +++ b/file2    @@ -1,4 +1,3 @@     1    -2    +5     3    -4    diff --git a/file1 b/file3    rename from file1    rename to file3    diff --git a/file2 b/file4    copy from file2    copy to file4    "###);     let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "--git", "--context=0"]);    insta::assert_snapshot!(stdout, @r###"    diff --git a/file2 b/file2    index 94ebaf9001..1ffc51b472 100644    --- a/file2    +++ b/file2    @@ -2,1 +2,1 @@    -2    +5    @@ -4,1 +4,0 @@    -4    diff --git a/file1 b/file3    rename from file1    rename to file3    diff --git a/file2 b/file4    copy from file2    copy to file4    "###);     let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "--git", "--color=debug"]);    insta::assert_snapshot!(stdout, @r###"    <<diff file_header::diff --git a/file2 b/file2>>    <<diff file_header::index 94ebaf9001..1ffc51b472 100644>>    <<diff file_header::--- a/file2>>    <<diff file_header::+++ b/file2>>    <<diff hunk_header::@@ -1,4 +1,3 @@>>    <<diff context:: 1>>    <<diff removed::->><<diff removed token::2>><<diff removed::>>    <<diff added::+>><<diff added token::5>><<diff added::>>    <<diff context:: 3>>    <<diff removed::->><<diff removed token::4>>    <<diff file_header::diff --git a/file1 b/file3>>    <<diff file_header::rename from file1>>    <<diff file_header::rename to file3>>    <<diff file_header::diff --git a/file2 b/file4>>    <<diff file_header::copy from file2>>    <<diff file_header::copy to file4>>    "###);     let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "-s", "--git"]);    insta::assert_snapshot!(stdout, @r###"    M file2    R {file1 => file3}    C {file2 => file4}    diff --git a/file2 b/file2    index 94ebaf9001..1ffc51b472 100644    --- a/file2    +++ b/file2    @@ -1,4 +1,3 @@     1    -2    +5     3    -4    diff --git a/file1 b/file3    rename from file1    rename to file3    diff --git a/file2 b/file4    copy from file2    copy to file4    "###);     let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "--stat"]);    insta::assert_snapshot!(stdout, @r###"    file2            | 3 +--    {file1 => file3} | 0    {file2 => file4} | 0    3 files changed, 1 insertion(+), 2 deletions(-)    "###);     // Filter by glob pattern    let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "-s", "glob:file[12]"]);    insta::assert_snapshot!(stdout, @r###"    D file1    M file2    "###);     // Unmatched paths should generate warnings    let (stdout, stderr) = test_env.jj_cmd_ok(        test_env.env_root(),        &[            "diff",            "-Rrepo",            "-s",            "repo",       // matches directory            "repo/file1", // deleted in to_tree, but exists in from_tree            "repo/x",            "repo/y/z",        ],    );    insta::assert_snapshot!(stdout.replace('\\', "/"), @r###"    M repo/file2    R repo/{file1 => file3}    C repo/{file2 => file4}    "###);    insta::assert_snapshot!(stderr.replace('\\', "/"), @r###"    Warning: No matching entries for paths: repo/x, repo/y/z    "###);     // Unmodified paths shouldn't generate warnings    let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["diff", "-s", "--from=@", "file2"]);    insta::assert_snapshot!(stdout, @"");    insta::assert_snapshot!(stderr, @"");} #[test]fn test_diff_empty() {    let test_env = TestEnvironment::default();    test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);    let repo_path = test_env.env_root().join("repo");     std::fs::write(repo_path.join("file1"), "").unwrap();    let stdout = test_env.jj_cmd_success(&repo_path, &["diff"]);    insta::assert_snapshot!(stdout, @r###"    Added regular file file1:        (empty)    "###);     test_env.jj_cmd_ok(&repo_path, &["new"]);    std::fs::remove_file(repo_path.join("file1")).unwrap();    let stdout = test_env.jj_cmd_success(&repo_path, &["diff"]);    insta::assert_snapshot!(stdout, @r###"    Removed regular file file1:        (empty)    "###);     let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "--stat"]);    insta::assert_snapshot!(stdout, @r###"    file1 | 0    1 file changed, 0 insertions(+), 0 deletions(-)    "###);} #[test]fn test_diff_file_mode() {    let test_env = TestEnvironment::default();    test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);    let repo_path = test_env.env_root().join("repo");     // Test content+mode/mode-only changes of empty/non-empty files:    // - file1: ("",  x) -> ("2", n)  empty, content+mode    // - file2: ("1", x) -> ("1", n)  non-empty, mode-only    // - file3: ("1", n) -> ("2", x)  non-empty, content+mode    // - file4: ("",  n) -> ("",  x)  empty, mode-only     std::fs::write(repo_path.join("file1"), "").unwrap();    std::fs::write(repo_path.join("file2"), "1\n").unwrap();    std::fs::write(repo_path.join("file3"), "1\n").unwrap();    std::fs::write(repo_path.join("file4"), "").unwrap();    test_env.jj_cmd_ok(&repo_path, &["file", "chmod", "x", "file1", "file2"]);     test_env.jj_cmd_ok(&repo_path, &["new"]);    std::fs::write(repo_path.join("file1"), "2\n").unwrap();    std::fs::write(repo_path.join("file3"), "2\n").unwrap();    test_env.jj_cmd_ok(&repo_path, &["file", "chmod", "n", "file1", "file2"]);    test_env.jj_cmd_ok(&repo_path, &["file", "chmod", "x", "file3", "file4"]);     test_env.jj_cmd_ok(&repo_path, &["new"]);    std::fs::remove_file(repo_path.join("file1")).unwrap();    std::fs::remove_file(repo_path.join("file2")).unwrap();    std::fs::remove_file(repo_path.join("file3")).unwrap();    std::fs::remove_file(repo_path.join("file4")).unwrap();     let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "-r@--"]);    insta::assert_snapshot!(stdout, @r###"    Added executable file file1:        (empty)    Added executable file file2:            1: 1    Added regular file file3:            1: 1    Added regular file file4:        (empty)    "###);    let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "-r@-"]);    insta::assert_snapshot!(stdout, @r###"    Executable file became non-executable at file1:            1: 2    Executable file became non-executable at file2:    Non-executable file became executable at file3:       1    1: 12    Non-executable file became executable at file4:    "###);    let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "-r@"]);    insta::assert_snapshot!(stdout, @r###"    Removed regular file file1:       1     : 2    Removed regular file file2:       1     : 1    Removed executable file file3:       1     : 2    Removed executable file file4:        (empty)    "###);     let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "-r@--", "--git"]);    insta::assert_snapshot!(stdout, @r###"    diff --git a/file1 b/file1    new file mode 100755    index 0000000000..e69de29bb2    diff --git a/file2 b/file2    new file mode 100755    index 0000000000..d00491fd7e    --- /dev/null    +++ b/file2    @@ -1,0 +1,1 @@    +1    diff --git a/file3 b/file3    new file mode 100644    index 0000000000..d00491fd7e    --- /dev/null    +++ b/file3    @@ -1,0 +1,1 @@    +1    diff --git a/file4 b/file4    new file mode 100644    index 0000000000..e69de29bb2    "###);    let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "-r@-", "--git"]);    insta::assert_snapshot!(stdout, @r###"    diff --git a/file1 b/file1    old mode 100755    new mode 100644    index e69de29bb2..0cfbf08886    --- a/file1    +++ b/file1    @@ -1,0 +1,1 @@    +2    diff --git a/file2 b/file2    old mode 100755    new mode 100644    diff --git a/file3 b/file3    old mode 100644    new mode 100755    index d00491fd7e..0cfbf08886    --- a/file3    +++ b/file3    @@ -1,1 +1,1 @@    -1    +2    diff --git a/file4 b/file4    old mode 100644    new mode 100755    "###);    let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "-r@", "--git"]);    insta::assert_snapshot!(stdout, @r###"    diff --git a/file1 b/file1    deleted file mode 100644    index 0cfbf08886..0000000000    --- a/file1    +++ /dev/null    @@ -1,1 +1,0 @@    -2    diff --git a/file2 b/file2    deleted file mode 100644    index d00491fd7e..0000000000    --- a/file2    +++ /dev/null    @@ -1,1 +1,0 @@    -1    diff --git a/file3 b/file3    deleted file mode 100755    index 0cfbf08886..0000000000    --- a/file3    +++ /dev/null    @@ -1,1 +1,0 @@    -2    diff --git a/file4 b/file4    deleted file mode 100755    index e69de29bb2..0000000000    "###);} #[test]fn test_diff_types() {    let test_env = TestEnvironment::default();    test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);    let repo_path = test_env.env_root().join("repo");     let file_path = repo_path.join("foo");     // Missing    test_env.jj_cmd_ok(&repo_path, &["new", "root()", "-m=missing"]);     // Normal file    test_env.jj_cmd_ok(&repo_path, &["new", "root()", "-m=file"]);    std::fs::write(&file_path, "foo").unwrap();     // Conflict (add/add)    test_env.jj_cmd_ok(&repo_path, &["new", "root()", "-m=conflict"]);    std::fs::write(&file_path, "foo").unwrap();    test_env.jj_cmd_ok(&repo_path, &["new", "root()"]);    std::fs::write(&file_path, "bar").unwrap();    test_env.jj_cmd_ok(&repo_path, &["squash", r#"--into=description("conflict")"#]);     #[cfg(unix)]    {        use std::os::unix::fs::PermissionsExt;        use std::path::PathBuf;         // Executable        test_env.jj_cmd_ok(&repo_path, &["new", "root()", "-m=executable"]);        std::fs::write(&file_path, "foo").unwrap();        std::fs::set_permissions(&file_path, std::fs::Permissions::from_mode(0o755)).unwrap();         // Symlink        test_env.jj_cmd_ok(&repo_path, &["new", "root()", "-m=symlink"]);        std::os::unix::fs::symlink(PathBuf::from("."), &file_path).unwrap();    }     let diff = |from: &str, to: &str| {        test_env.jj_cmd_success(            &repo_path,            &[                "diff",                "--types",                &format!(r#"--from=description("{from}")"#),                &format!(r#"--to=description("{to}")"#),            ],        )    };    insta::assert_snapshot!(diff("missing", "file"), @r###"    -F foo    "###);    insta::assert_snapshot!(diff("file", "conflict"), @r###"    FC foo    "###);    insta::assert_snapshot!(diff("conflict", "missing"), @r###"    C- foo    "###);     #[cfg(unix)]    {        insta::assert_snapshot!(diff("symlink", "file"), @r###"        LF foo        "###);        insta::assert_snapshot!(diff("missing", "executable"), @r###"        -F foo        "###);    }} #[test]fn test_diff_name_only() {    let test_env = TestEnvironment::default();    test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);    let repo_path = test_env.env_root().join("repo");     test_env.jj_cmd_ok(&repo_path, &["new"]);    std::fs::write(repo_path.join("deleted"), "d").unwrap();    std::fs::write(repo_path.join("modified"), "m").unwrap();    insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["diff", "--name-only"]), @r###"    deleted    modified    "###);    test_env.jj_cmd_ok(&repo_path, &["commit", "-mfirst"]);    std::fs::remove_file(repo_path.join("deleted")).unwrap();    std::fs::write(repo_path.join("modified"), "mod").unwrap();    std::fs::write(repo_path.join("added"), "add").unwrap();    std::fs::create_dir(repo_path.join("sub")).unwrap();    std::fs::write(repo_path.join("sub/added"), "sub/add").unwrap();    insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["diff", "--name-only"]).replace('\\', "/"),    @r###"    added    deleted    modified    sub/added    "###);} #[test]fn test_diff_bad_args() {    let test_env = TestEnvironment::default();    test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);    let repo_path = test_env.env_root().join("repo");     let stderr = test_env.jj_cmd_cli_error(&repo_path, &["diff", "-s", "--types"]);    insta::assert_snapshot!(stderr, @r###"    error: the argument '--summary' cannot be used with '--types'     Usage: jj diff --summary [PATHS]...

Lines 1–500 of 2503.