// 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###" [38;5;3m<<diff header::Modified regular file file2:>>[39m [38;5;1m<<diff removed line_number:: 1>>[39m<<diff:: >>[38;5;2m<<diff added line_number:: 1>>[39m<<diff::: 1>> [38;5;1m<<diff removed line_number:: 2>>[39m<<diff:: >>[38;5;2m<<diff added line_number:: 2>>[39m<<diff::: >>[4m[38;5;1m<<diff removed token::2>>[38;5;2m<<diff added token::5>>[24m[39m<<diff::>> [38;5;1m<<diff removed line_number:: 3>>[39m<<diff:: >>[38;5;2m<<diff added line_number:: 3>>[39m<<diff::: 3>> [38;5;1m<<diff removed line_number:: 4>>[39m<<diff:: : >>[4m[38;5;1m<<diff removed token::4>>[24m[39m [38;5;3m<<diff header::Modified regular file file3 (file1 => file3):>>[39m [38;5;3m<<diff header::Modified regular file file4 (file2 => file4):>>[39m "###); 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###" [1m<<diff file_header::diff --git a/file2 b/file2>>[0m [1m<<diff file_header::index 94ebaf9001..1ffc51b472 100644>>[0m [1m<<diff file_header::--- a/file2>>[0m [1m<<diff file_header::+++ b/file2>>[0m [38;5;6m<<diff hunk_header::@@ -1,4 +1,3 @@>>[39m <<diff context:: 1>> [38;5;1m<<diff removed::->>[4m<<diff removed token::2>>[24m<<diff removed::>>[39m [38;5;2m<<diff added::+>>[4m<<diff added token::5>>[24m<<diff added::>>[39m <<diff context:: 3>> [38;5;1m<<diff removed::->>[4m<<diff removed token::4>>[24m[39m [1m<<diff file_header::diff --git a/file1 b/file3>>[0m [1m<<diff file_header::rename from file1>>[0m [1m<<diff file_header::rename to file3>>[0m [1m<<diff file_header::diff --git a/file2 b/file4>>[0m [1m<<diff file_header::copy from file2>>[0m [1m<<diff file_header::copy to file4>>[0m "###); 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. 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 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###" [38;5;3m<<diff header::Modified regular file file2:>>[39m [38;5;1m<<diff removed line_number:: 1>>[39m<<diff:: >>[38;5;2m<<diff added line_number:: 1>>[39m<<diff::: 1>> [38;5;1m<<diff removed line_number:: 2>>[39m<<diff:: >>[38;5;2m<<diff added line_number:: 2>>[39m<<diff::: >>[4m[38;5;1m<<diff removed token::2>>[38;5;2m<<diff added token::5>>[24m[39m<<diff::>> [38;5;1m<<diff removed line_number:: 3>>[39m<<diff:: >>[38;5;2m<<diff added line_number:: 3>>[39m<<diff::: 3>> [38;5;1m<<diff removed line_number:: 4>>[39m<<diff:: : >>[4m[38;5;1m<<diff removed token::4>>[24m[39m [38;5;3m<<diff header::Modified regular file file3 (file1 => file3):>>[39m [38;5;3m<<diff header::Modified regular file file4 (file2 => file4):>>[39m "###); 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###" [1m<<diff file_header::diff --git a/file2 b/file2>>[0m [1m<<diff file_header::index 94ebaf9001..1ffc51b472 100644>>[0m [1m<<diff file_header::--- a/file2>>[0m [1m<<diff file_header::+++ b/file2>>[0m [38;5;6m<<diff hunk_header::@@ -1,4 +1,3 @@>>[39m <<diff context:: 1>> [38;5;1m<<diff removed::->>[4m<<diff removed token::2>>[24m<<diff removed::>>[39m [38;5;2m<<diff added::+>>[4m<<diff added token::5>>[24m<<diff added::>>[39m <<diff context:: 3>> [38;5;1m<<diff removed::->>[4m<<diff removed token::4>>[24m[39m [1m<<diff file_header::diff --git a/file1 b/file3>>[0m [1m<<diff file_header::rename from file1>>[0m [1m<<diff file_header::rename to file3>>[0m [1m<<diff file_header::diff --git a/file2 b/file4>>[0m [1m<<diff file_header::copy from file2>>[0m [1m<<diff file_header::copy to file4>>[0m "###); 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]...