// 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 as _; use crate::common::CommandOutput; use crate::common::TestEnvironment; use crate::common::TestWorkDir; use crate::common::create_commit; use crate::common::create_commit_with_files; use crate::common::fake_diff_editor_path; use crate::common::to_toml_value; #[test] fn test_diff_basic() { 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("file1", "foo\n"); work_dir.write_file("file2", "1\n2\n3\n4\n"); work_dir.run_jj(["new"]).success(); work_dir.remove_file("file1"); work_dir.write_file("file2", "1\n5\n3\n"); work_dir.write_file("file3", "foo\n"); work_dir.write_file("file4", "1\n2\n3\n4\n"); let output = work_dir.run_jj(["diff"]); insta::assert_snapshot!(output, @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): [EOF] "); let output = work_dir.run_jj(["diff", "--context=0"]); insta::assert_snapshot!(output, @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): [EOF] "); let output = work_dir.run_jj(["diff", "--color=debug"]); insta::assert_snapshot!(output, @r" <> <><><><> <><><><><><><> <><><><> <><><> < file3):>> < file4):>> [EOF] "); let output = work_dir.run_jj(["diff", "-s"]); insta::assert_snapshot!(output, @r" M file2 R {file1 => file3} C {file2 => file4} [EOF] "); let output = work_dir.run_jj(["diff", "--types"]); insta::assert_snapshot!(output, @r" FF file2 FF {file1 => file3} FF {file2 => file4} [EOF] "); let output = work_dir.run_jj(["diff", "--types", "glob:file[12]"]); insta::assert_snapshot!(output, @r" F- file1 FF file2 [EOF] "); let template = r#"source.path() ++ ' => ' ++ target.path() ++ ' (' ++ status ++ ")\n""#; let output = work_dir.run_jj(["diff", "-T", template]); insta::assert_snapshot!(output, @r" file2 => file2 (modified) file1 => file3 (renamed) file2 => file4 (copied) [EOF] "); let output = work_dir.run_jj(["diff", "--git", "file1"]); insta::assert_snapshot!(output, @r" diff --git a/file1 b/file1 deleted file mode 100644 index 257cc5642c..0000000000 --- a/file1 +++ /dev/null @@ -1,1 +0,0 @@ -foo [EOF] "); let output = work_dir.run_jj(["diff", "--git"]); insta::assert_snapshot!(output, @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 [EOF] "); let output = work_dir.run_jj(["diff", "--git", "--context=0"]); insta::assert_snapshot!(output, @r" diff --git a/file2 b/file2 index 94ebaf9001..1ffc51b472 100644 --- a/file2 +++ b/file2 @@ -2,1 +2,1 @@ -2 +5 @@ -4,1 +3,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 [EOF] "); let output = work_dir.run_jj(["diff", "--git", "--color=debug"]); insta::assert_snapshot!(output, @r" <> <> <> <> <> <> <><><> <><><> <> <><> <> <> <> <> <> <> [EOF] "); let output = work_dir.run_jj(["diff", "-s", "--git"]); insta::assert_snapshot!(output, @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 [EOF] "); let output = work_dir.run_jj(["diff", "--stat"]); insta::assert_snapshot!(output, @r" file2 | 3 +-- {file1 => file3} | 0 {file2 => file4} | 0 3 files changed, 1 insertion(+), 2 deletions(-) [EOF] "); // Reverse-order diff let output = work_dir.run_jj(["diff", "--to", "@-", "--git"]); insta::assert_snapshot!(output, @r" diff --git a/file3 b/file1 rename from file3 rename to file1 diff --git a/file2 b/file2 index 1ffc51b472..94ebaf9001 100644 --- a/file2 +++ b/file2 @@ -1,3 +1,4 @@ 1 -5 +2 3 +4 diff --git a/file4 b/file4 deleted file mode 100644 index 94ebaf9001..0000000000 --- a/file4 +++ /dev/null @@ -1,4 +0,0 @@ -1 -2 -3 -4 [EOF] "); // Filter by glob pattern let output = work_dir.run_jj(["diff", "-s", "glob:file[12]"]); insta::assert_snapshot!(output, @r" D file1 M file2 [EOF] "); // Unmatched paths should generate warnings let output = test_env.run_jj_in( ".", [ "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!(output.normalize_backslash(), @r" M repo/file2 R repo/{file1 => file3} C repo/{file2 => file4} [EOF] ------- stderr ------- Warning: No matching entries for paths: repo/x, repo/y/z [EOF] "); // Unmodified paths shouldn't generate warnings let output = work_dir.run_jj(["diff", "-s", "--from=@", "file2"]); insta::assert_snapshot!(output, @""); // --tool=: let output = work_dir.run_jj(["diff", "--tool=:summary", "--color-words", "file2"]); insta::assert_snapshot!(output, @r" M file2 Modified regular file file2: 1 1: 1 2 2: 25 3 3: 3 4 : 4 [EOF] "); let output = work_dir.run_jj(["diff", "--tool=:git", "--stat", "file2"]); insta::assert_snapshot!(output, @r" file2 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/file2 b/file2 index 94ebaf9001..1ffc51b472 100644 --- a/file2 +++ b/file2 @@ -1,4 +1,3 @@ 1 -2 +5 3 -4 [EOF] "); // Bad combination let output = work_dir.run_jj(["diff", "--summary", "--tool=:stat"]); insta::assert_snapshot!(output, @r" ------- stderr ------- Error: --tool=:stat cannot be used with --summary [EOF] [exit status: 2] "); let output = work_dir.run_jj(["diff", "--git", "--tool=:git"]); insta::assert_snapshot!(output, @r" ------- stderr ------- Error: --tool=:git cannot be used with --git [EOF] [exit status: 2] "); let output = work_dir.run_jj(["diff", "--git", "--tool=external"]); insta::assert_snapshot!(output, @r" ------- stderr ------- Error: --tool=external cannot be used with --git [EOF] [exit status: 2] "); let output = work_dir.run_jj(["diff", "-T''", "--summary"]); insta::assert_snapshot!(output, @r" ------- stderr ------- error: the argument '--template