3 # Copyright (c) 2006 Johannes E. Schindelin
4 # Copyright (c) 2023 Google LLC
6 test_description
='Test special whitespace in diff engine.
10 TEST_PASSES_SANITIZE_LEAK
=true
12 .
"$TEST_DIRECTORY"/lib-diff.sh
14 for opts
in --patch --quiet -s --stat --shortstat --dirstat=lines
17 test_expect_success
"status with $opts (different)" '
21 test_expect_code 1 git diff -w $opts --exit-code x
24 test_expect_success POSIXPERM
"status with $opts (mode differs)" '
25 test_when_finished "git update-index --chmod=-x x" &&
28 git update-index --chmod=+x x &&
29 test_expect_code 1 git diff -w $opts --exit-code x
32 test_expect_success
"status with $opts (removing an empty file)" '
36 test_expect_code 1 git diff -w $opts --exit-code -- x
39 test_expect_success
"status with $opts (different but equivalent)" '
43 git diff -w $opts --exit-code x
47 test_expect_success
"Ray Lehtiniemi's example" '
53 git update-index --add x &&
54 old_hash_x=$(git hash-object x) &&
55 before=$(git rev-parse --short "$old_hash_x") &&
64 new_hash_x=$(git hash-object x) &&
65 after=$(git rev-parse --short "$new_hash_x") &&
69 index $before..$after 100644
83 test_cmp expect out &&
86 test_cmp expect out &&
92 test_expect_success
'another test, without options' '
93 tr Q "\015" <<-\EOF >x &&
94 whitespace at beginning
96 whitespace in the middle
102 git update-index x &&
103 old_hash_x=$(git hash-object x) &&
104 before=$(git rev-parse --short "$old_hash_x") &&
106 tr "_" " " <<-\EOF >x &&
107 _ whitespace at beginning
109 white space in the middle
114 new_hash_x=$(git hash-object x) &&
115 after=$(git rev-parse --short "$new_hash_x") &&
117 tr "Q_" "\015 " <<-EOF >expect &&
119 index $before..$after 100644
123 -whitespace at beginning
125 -whitespace in the middle
127 + whitespace at beginning
129 +white space in the middle
137 test_cmp expect out &&
140 test_must_be_empty out &&
142 git diff -w -b >out &&
143 test_must_be_empty out &&
145 git diff -w --ignore-space-at-eol >out &&
146 test_must_be_empty out &&
148 git diff -w -b --ignore-space-at-eol >out &&
149 test_must_be_empty out &&
151 git diff -w --ignore-cr-at-eol >out &&
152 test_must_be_empty out &&
154 tr "Q_" "\015 " <<-EOF >expect &&
156 index $before..$after 100644
160 -whitespace at beginning
161 +_ whitespace at beginning
163 -whitespace in the middle
164 +white space in the middle
170 test_cmp expect out &&
172 git diff -b --ignore-space-at-eol >out &&
173 test_cmp expect out &&
175 git diff -b --ignore-cr-at-eol >out &&
176 test_cmp expect out &&
178 tr "Q_" "\015 " <<-EOF >expect &&
180 index $before..$after 100644
184 -whitespace at beginning
186 -whitespace in the middle
187 +_ whitespace at beginning
189 +white space in the middle
194 git diff --ignore-space-at-eol >out &&
195 test_cmp expect out &&
197 git diff --ignore-space-at-eol --ignore-cr-at-eol >out &&
198 test_cmp expect out &&
200 tr "Q_" "\015 " <<-EOF >expect &&
202 index_$before..$after 100644
206 -whitespace at beginning
208 -whitespace in the middle
210 +_ whitespace at beginning
212 +white space in the middle
217 git diff --ignore-cr-at-eol >out &&
221 test_expect_success
'ignore-blank-lines: only new lines' '
223 git update-index x &&
224 test_seq 5 | sed "/3/i\\
226 git diff --ignore-blank-lines >out &&
227 test_must_be_empty out
230 test_expect_success
'ignore-blank-lines: only new lines with space' '
232 git update-index x &&
233 test_seq 5 | sed "/3/i\\
235 git diff -w --ignore-blank-lines >out &&
236 test_must_be_empty out
239 test_expect_success
'ignore-blank-lines: after change' '
251 git update-index x &&
264 git diff --inter-hunk-context=100 --ignore-blank-lines >out.tmp &&
265 cat <<-\EOF >expected &&
279 compare_diff_patch expected out.tmp
282 test_expect_success
'ignore-blank-lines: before change' '
293 git update-index x &&
306 git diff --inter-hunk-context=100 --ignore-blank-lines >out.tmp &&
307 cat <<-\EOF >expected &&
320 compare_diff_patch expected out.tmp
323 test_expect_success
'ignore-blank-lines: between changes' '
338 git update-index x &&
355 git diff --ignore-blank-lines >out.tmp &&
356 cat <<-\EOF >expected &&
377 compare_diff_patch expected out.tmp
380 test_expect_success
'ignore-blank-lines: between changes (with interhunkctx)' '
382 git update-index x &&
400 git diff --inter-hunk-context=2 --ignore-blank-lines >out.tmp &&
401 cat <<-\EOF >expected &&
422 compare_diff_patch expected out.tmp
425 test_expect_success
'ignore-blank-lines: scattered spaces' '
427 git update-index x &&
448 git diff --inter-hunk-context=4 --ignore-blank-lines >out.tmp &&
449 cat <<-\EOF >expected &&
464 compare_diff_patch expected out.tmp
467 test_expect_success
'ignore-blank-lines: spaces coalesce' '
469 git update-index x &&
483 git diff --inter-hunk-context=4 --ignore-blank-lines >out.tmp &&
484 cat <<-\EOF >expected &&
501 compare_diff_patch expected out.tmp
504 test_expect_success
'ignore-blank-lines: mix changes and blank lines' '
506 git update-index x &&
532 git diff --ignore-blank-lines >out.tmp &&
533 cat <<-\EOF >expected &&
562 compare_diff_patch expected out.tmp
565 test_expect_success
'check mixed spaces and tabs in indent' '
566 # This is indented with SP HT SP.
568 test_must_fail git diff --check >check &&
569 grep "space before tab in indent" check
572 test_expect_success
'check mixed tabs and spaces in indent' '
573 # This is indented with HT SP HT.
575 test_must_fail git diff --check >check &&
576 grep "space before tab in indent" check
579 test_expect_success
'check with no whitespace errors' '
580 git commit -m "snapshot" &&
585 test_expect_success
'check with trailing whitespace' '
587 test_must_fail git diff --check
590 test_expect_success
'check with space before tab in indent' '
591 # indent has space followed by hard tab
593 test_must_fail git diff --check
596 test_expect_success
'--check and --exit-code are not exclusive' '
598 git diff --check --exit-code
601 test_expect_success
'--check and --quiet are not exclusive' '
602 git diff --check --quiet
605 test_expect_success
'-w and --exit-code interact sensibly' '
606 test_when_finished "git checkout x" &&
611 test_must_fail git diff --exit-code &&
612 git diff -w >actual &&
613 test_must_be_empty actual &&
614 git diff -w --exit-code
617 test_expect_success
'-I and --exit-code interact sensibly' '
618 test_when_finished "git checkout x" &&
623 test_must_fail git diff --exit-code &&
624 git diff -I. >actual &&
625 test_must_be_empty actual &&
626 git diff -I. --exit-code
629 test_expect_success
'check staged with no whitespace errors' '
632 git diff --cached --check
635 test_expect_success
'check staged with trailing whitespace' '
638 test_must_fail git diff --cached --check
641 test_expect_success
'check staged with space before tab in indent' '
642 # indent has space followed by hard tab
645 test_must_fail git diff --cached --check
648 test_expect_success
'check with no whitespace errors (diff-index)' '
651 git diff-index --check HEAD
654 test_expect_success
'check with trailing whitespace (diff-index)' '
657 test_must_fail git diff-index --check HEAD
660 test_expect_success
'check with space before tab in indent (diff-index)' '
661 # indent has space followed by hard tab
664 test_must_fail git diff-index --check HEAD
667 test_expect_success
'check staged with no whitespace errors (diff-index)' '
670 git diff-index --cached --check HEAD
673 test_expect_success
'check staged with trailing whitespace (diff-index)' '
676 test_must_fail git diff-index --cached --check HEAD
679 test_expect_success
'check staged with space before tab in indent (diff-index)' '
680 # indent has space followed by hard tab
683 test_must_fail git diff-index --cached --check HEAD
686 test_expect_success
'check with no whitespace errors (diff-tree)' '
688 git commit -m "new commit" x &&
689 git diff-tree --check HEAD^ HEAD
692 test_expect_success
'check with trailing whitespace (diff-tree)' '
694 git commit -m "another commit" x &&
695 test_must_fail git diff-tree --check HEAD^ HEAD
698 test_expect_success
'check with space before tab in indent (diff-tree)' '
699 # indent has space followed by hard tab
701 git commit -m "yet another" x &&
702 test_must_fail git diff-tree --check HEAD^ HEAD
705 test_expect_success
'check with ignored trailing whitespace attr (diff-tree)' '
706 test_when_finished "git reset --hard HEAD^" &&
708 # create a whitespace error that should be ignored
709 echo "* -whitespace" >.gitattributes &&
710 git add .gitattributes &&
713 git commit -m "add trailing space" &&
715 # with a worktree diff-tree ignores the whitespace error
716 git diff-tree --root --check HEAD &&
718 # without a worktree diff-tree still ignores the whitespace error
719 git -C .git diff-tree --root --check HEAD
722 test_expect_success
'check trailing whitespace (trailing-space: off)' '
723 git config core.whitespace "-trailing-space" &&
724 echo "foo (); " >x &&
728 test_expect_success
'check trailing whitespace (trailing-space: on)' '
729 git config core.whitespace "trailing-space" &&
730 echo "foo (); " >x &&
731 test_must_fail git diff --check
734 test_expect_success
'check space before tab in indent (space-before-tab: off)' '
735 # indent contains space followed by HT
736 git config core.whitespace "-space-before-tab" &&
737 echo " foo ();" >x &&
741 test_expect_success
'check space before tab in indent (space-before-tab: on)' '
742 # indent contains space followed by HT
743 git config core.whitespace "space-before-tab" &&
744 echo " foo (); " >x &&
745 test_must_fail git diff --check
748 test_expect_success
'check spaces as indentation (indent-with-non-tab: off)' '
749 git config core.whitespace "-indent-with-non-tab" &&
750 echo " foo ();" >x &&
754 test_expect_success
'check spaces as indentation (indent-with-non-tab: on)' '
755 git config core.whitespace "indent-with-non-tab" &&
756 echo " foo ();" >x &&
757 test_must_fail git diff --check
760 test_expect_success
'ditto, but tabwidth=9' '
761 git config core.whitespace "indent-with-non-tab,tabwidth=9" &&
765 test_expect_success
'check tabs and spaces as indentation (indent-with-non-tab: on)' '
766 git config core.whitespace "indent-with-non-tab" &&
767 echo " foo ();" >x &&
768 test_must_fail git diff --check
771 test_expect_success
'ditto, but tabwidth=10' '
772 git config core.whitespace "indent-with-non-tab,tabwidth=10" &&
773 test_must_fail git diff --check
776 test_expect_success
'ditto, but tabwidth=20' '
777 git config core.whitespace "indent-with-non-tab,tabwidth=20" &&
781 test_expect_success
'check tabs as indentation (tab-in-indent: off)' '
782 git config core.whitespace "-tab-in-indent" &&
783 echo " foo ();" >x &&
787 test_expect_success
'check tabs as indentation (tab-in-indent: on)' '
788 git config core.whitespace "tab-in-indent" &&
789 echo " foo ();" >x &&
790 test_must_fail git diff --check
793 test_expect_success
'check tabs and spaces as indentation (tab-in-indent: on)' '
794 git config core.whitespace "tab-in-indent" &&
795 echo " foo ();" >x &&
796 test_must_fail git diff --check
799 test_expect_success
'ditto, but tabwidth=1 (must be irrelevant)' '
800 git config core.whitespace "tab-in-indent,tabwidth=1" &&
801 test_must_fail git diff --check
804 test_expect_success
'check tab-in-indent and indent-with-non-tab conflict' '
805 git config core.whitespace "tab-in-indent,indent-with-non-tab" &&
807 test_must_fail git diff --check
810 test_expect_success
'check tab-in-indent excluded from wildcard whitespace attribute' '
811 git config --unset core.whitespace &&
812 echo "x whitespace" >.gitattributes &&
813 echo " foo ();" >x &&
818 test_expect_success
'line numbers in --check output are correct' '
820 echo "foo(); " >>x &&
821 test_must_fail git diff --check >check &&
825 test_expect_success
'checkdiff detects new trailing blank lines (1)' '
828 test_must_fail git diff --check >check &&
829 grep "new blank line" check
832 test_expect_success
'checkdiff detects new trailing blank lines (2)' '
833 test_write_lines a b "" "" >x &&
835 test_write_lines a "" "" "" "" >x &&
836 test_must_fail git diff --check >check &&
837 grep "new blank line" check
840 test_expect_success
'checkdiff allows new blank lines' '
844 echo "/* This is new */" &&
851 test_expect_success
'whitespace-only changes not reported (diff)' '
853 echo >x "hello world" &&
855 git commit -m "hello 1" &&
856 echo >x "hello world" &&
857 git diff -b >actual &&
858 test_must_be_empty actual
861 test_expect_success
'whitespace-only changes not reported (diffstat)' '
862 # reuse state from previous test
863 git diff --stat -b >actual &&
864 test_must_be_empty actual
867 test_expect_success
'whitespace changes with modification reported (diffstat)' '
869 echo >x "hello world" &&
870 git update-index --chmod=+x x &&
871 git diff --stat --cached -b >actual &&
872 cat <<-EOF >expect &&
874 1 file changed, 0 insertions(+), 0 deletions(-)
876 test_cmp expect actual
879 test_expect_success
'whitespace-only changes reported across renames (diffstat)' '
881 for i in 1 2 3 4 5 6 7 8 9; do echo "$i$i$i$i$i$i" || return 1; done >x &&
883 git commit -m "base" &&
884 sed -e "5s/^/ /" x >z &&
887 git diff -w -M --cached --stat >actual &&
888 cat <<-EOF >expect &&
890 1 file changed, 0 insertions(+), 0 deletions(-)
892 test_cmp expect actual
895 test_expect_success
'whitespace-only changes reported across renames' '
896 git reset --hard HEAD~1 &&
897 for i in 1 2 3 4 5 6 7 8 9; do echo "$i$i$i$i$i$i" || return 1; done >x &&
899 hash_x=$(git hash-object x) &&
900 before=$(git rev-parse --short "$hash_x") &&
901 git commit -m "base" &&
902 sed -e "5s/^/ /" x >z &&
905 hash_z=$(git hash-object z) &&
906 after=$(git rev-parse --short "$hash_z") &&
907 git diff -w -M --cached >actual.raw &&
908 sed -e "/^similarity index /s/[0-9][0-9]*/NUM/" actual.raw >actual &&
909 cat <<-EOF >expect &&
911 similarity index NUM%
914 index $before..$after 100644
916 test_cmp expect actual
920 diff --git a
/empty b
/void
921 similarity index
100%
926 test_expect_success
'rename empty' '
930 git commit -m empty &&
932 git diff -w --cached -M >current &&
933 test_cmp expected current
936 test_expect_success
'combined diff with autocrlf conversion' '
939 test_commit "one side" x hello one-side &&
940 git checkout HEAD^ &&
942 git commit -m "the other side" x &&
943 git config core.autocrlf true &&
944 test_must_fail git merge one-side >actual &&
945 test_i18ngrep "Automatic merge failed" actual &&
947 git diff >actual.raw &&
948 sed -e "1,/^@@@/d" actual.raw >actual &&
953 # Start testing the colored format for whitespace checks
955 test_expect_success
'setup diff colors' '
956 git config color.diff.plain normal &&
957 git config color.diff.meta bold &&
958 git config color.diff.frag cyan &&
959 git config color.diff.func normal &&
960 git config color.diff.old red &&
961 git config color.diff.new green &&
962 git config color.diff.commit yellow &&
963 git config color.diff.whitespace blue &&
965 git config core.autocrlf false
968 test_expect_success
'diff that introduces a line with only tabs' '
969 git config core.whitespace blank-at-eol &&
972 old_hash_x=$(git hash-object x) &&
973 before=$(git rev-parse --short "$old_hash_x") &&
974 git commit -m "initial" x &&
975 echo "{NTN}" | tr "NT" "\n\t" >>x &&
976 new_hash_x=$(git hash-object x) &&
977 after=$(git rev-parse --short "$new_hash_x") &&
978 git diff --color >current.raw &&
979 test_decode_color <current.raw >current &&
981 cat >expected <<-EOF &&
982 <BOLD>diff --git a/x b/x<RESET>
983 <BOLD>index $before..$after 100644<RESET>
986 <CYAN>@@ -1 +1,4 @@<RESET>
988 <GREEN>+<RESET><GREEN>{<RESET>
989 <GREEN>+<RESET><BLUE> <RESET>
990 <GREEN>+<RESET><GREEN>}<RESET>
993 test_cmp expected current
996 test_expect_success
'diff that introduces and removes ws breakages' '
999 echo "0. blank-at-eol " &&
1000 echo "1. blank-at-eol "
1002 old_hash_x=$(git hash-object x) &&
1003 before=$(git rev-parse --short "$old_hash_x") &&
1004 git commit -a --allow-empty -m preimage &&
1006 echo "0. blank-at-eol " &&
1007 echo "1. still-blank-at-eol " &&
1008 echo "2. and a new line "
1010 new_hash_x=$(git hash-object x) &&
1011 after=$(git rev-parse --short "$new_hash_x") &&
1013 git diff --color >current.raw &&
1014 test_decode_color <current.raw >current &&
1016 cat >expected <<-EOF &&
1017 <BOLD>diff --git a/x b/x<RESET>
1018 <BOLD>index $before..$after 100644<RESET>
1019 <BOLD>--- a/x<RESET>
1020 <BOLD>+++ b/x<RESET>
1021 <CYAN>@@ -1,2 +1,3 @@<RESET>
1022 0. blank-at-eol <RESET>
1023 <RED>-1. blank-at-eol <RESET>
1024 <GREEN>+<RESET><GREEN>1. still-blank-at-eol<RESET><BLUE> <RESET>
1025 <GREEN>+<RESET><GREEN>2. and a new line<RESET><BLUE> <RESET>
1028 test_cmp expected current
1031 test_expect_success
'ws-error-highlight test setup' '
1035 echo "0. blank-at-eol " &&
1036 echo "1. blank-at-eol "
1038 old_hash_x=$(git hash-object x) &&
1039 before=$(git rev-parse --short "$old_hash_x") &&
1040 git commit -a --allow-empty -m preimage &&
1042 echo "0. blank-at-eol " &&
1043 echo "1. still-blank-at-eol " &&
1044 echo "2. and a new line "
1046 new_hash_x=$(git hash-object x) &&
1047 after=$(git rev-parse --short "$new_hash_x") &&
1049 cat >expect.default-old <<-EOF &&
1050 <BOLD>diff --git a/x b/x<RESET>
1051 <BOLD>index $before..$after 100644<RESET>
1052 <BOLD>--- a/x<RESET>
1053 <BOLD>+++ b/x<RESET>
1054 <CYAN>@@ -1,2 +1,3 @@<RESET>
1055 0. blank-at-eol <RESET>
1056 <RED>-<RESET><RED>1. blank-at-eol<RESET><BLUE> <RESET>
1057 <GREEN>+<RESET><GREEN>1. still-blank-at-eol<RESET><BLUE> <RESET>
1058 <GREEN>+<RESET><GREEN>2. and a new line<RESET><BLUE> <RESET>
1061 cat >expect.all <<-EOF &&
1062 <BOLD>diff --git a/x b/x<RESET>
1063 <BOLD>index $before..$after 100644<RESET>
1064 <BOLD>--- a/x<RESET>
1065 <BOLD>+++ b/x<RESET>
1066 <CYAN>@@ -1,2 +1,3 @@<RESET>
1067 <RESET>0. blank-at-eol<RESET><BLUE> <RESET>
1068 <RED>-<RESET><RED>1. blank-at-eol<RESET><BLUE> <RESET>
1069 <GREEN>+<RESET><GREEN>1. still-blank-at-eol<RESET><BLUE> <RESET>
1070 <GREEN>+<RESET><GREEN>2. and a new line<RESET><BLUE> <RESET>
1073 cat >expect.none <<-EOF
1074 <BOLD>diff --git a/x b/x<RESET>
1075 <BOLD>index $before..$after 100644<RESET>
1076 <BOLD>--- a/x<RESET>
1077 <BOLD>+++ b/x<RESET>
1078 <CYAN>@@ -1,2 +1,3 @@<RESET>
1079 0. blank-at-eol <RESET>
1080 <RED>-1. blank-at-eol <RESET>
1081 <GREEN>+1. still-blank-at-eol <RESET>
1082 <GREEN>+2. and a new line <RESET>
1087 test_expect_success
'test --ws-error-highlight option' '
1089 git diff --color --ws-error-highlight=default,old >current.raw &&
1090 test_decode_color <current.raw >current &&
1091 test_cmp expect.default-old current &&
1093 git diff --color --ws-error-highlight=all >current.raw &&
1094 test_decode_color <current.raw >current &&
1095 test_cmp expect.all current &&
1097 git diff --color --ws-error-highlight=none >current.raw &&
1098 test_decode_color <current.raw >current &&
1099 test_cmp expect.none current
1103 test_expect_success
'test diff.wsErrorHighlight config' '
1105 git -c diff.wsErrorHighlight=default,old diff --color >current.raw &&
1106 test_decode_color <current.raw >current &&
1107 test_cmp expect.default-old current &&
1109 git -c diff.wsErrorHighlight=all diff --color >current.raw &&
1110 test_decode_color <current.raw >current &&
1111 test_cmp expect.all current &&
1113 git -c diff.wsErrorHighlight=none diff --color >current.raw &&
1114 test_decode_color <current.raw >current &&
1115 test_cmp expect.none current
1119 test_expect_success
'option overrides diff.wsErrorHighlight' '
1121 git -c diff.wsErrorHighlight=none \
1122 diff --color --ws-error-highlight=default,old >current.raw &&
1123 test_decode_color <current.raw >current &&
1124 test_cmp expect.default-old current &&
1126 git -c diff.wsErrorHighlight=default \
1127 diff --color --ws-error-highlight=all >current.raw &&
1128 test_decode_color <current.raw >current &&
1129 test_cmp expect.all current &&
1131 git -c diff.wsErrorHighlight=all \
1132 diff --color --ws-error-highlight=none >current.raw &&
1133 test_decode_color <current.raw >current &&
1134 test_cmp expect.none current
1138 test_expect_success
'detect moved code, complete file' '
1140 cat <<-\EOF >test.c &&
1144 printf("Hello World");
1148 git commit -m "add main function" &&
1149 file=$(git rev-parse --short HEAD:test.c) &&
1150 git mv test.c main.c &&
1151 test_config color.diff.oldMoved "normal red" &&
1152 test_config color.diff.newMoved "normal green" &&
1153 git diff HEAD --color-moved=zebra --color --no-renames >actual.raw &&
1154 test_decode_color <actual.raw >actual &&
1155 cat >expected <<-EOF &&
1156 <BOLD>diff --git a/main.c b/main.c<RESET>
1157 <BOLD>new file mode 100644<RESET>
1158 <BOLD>index 0000000..$file<RESET>
1159 <BOLD>--- /dev/null<RESET>
1160 <BOLD>+++ b/main.c<RESET>
1161 <CYAN>@@ -0,0 +1,5 @@<RESET>
1162 <BGREEN>+<RESET><BGREEN>#include<stdio.h><RESET>
1163 <BGREEN>+<RESET><BGREEN>main()<RESET>
1164 <BGREEN>+<RESET><BGREEN>{<RESET>
1165 <BGREEN>+<RESET><BGREEN>printf("Hello World");<RESET>
1166 <BGREEN>+<RESET><BGREEN>}<RESET>
1167 <BOLD>diff --git a/test.c b/test.c<RESET>
1168 <BOLD>deleted file mode 100644<RESET>
1169 <BOLD>index $file..0000000<RESET>
1170 <BOLD>--- a/test.c<RESET>
1171 <BOLD>+++ /dev/null<RESET>
1172 <CYAN>@@ -1,5 +0,0 @@<RESET>
1173 <BRED>-#include<stdio.h><RESET>
1174 <BRED>-main()<RESET>
1176 <BRED>-printf("Hello World");<RESET>
1180 test_cmp expected actual
1183 test_expect_success
'detect malicious moved code, inside file' '
1184 test_config color.diff.oldMoved "normal red" &&
1185 test_config color.diff.newMoved "normal green" &&
1186 test_config color.diff.oldMovedAlternative "blue" &&
1187 test_config color.diff.newMovedAlternative "yellow" &&
1189 cat <<-\EOF >main.c &&
1197 int secure_foo(struct user *u)
1199 if (!u->is_allowed_foo)
1209 cat <<-\EOF >test.c &&
1213 printf("Hello World, but different\n");
1216 int another_function()
1221 git add main.c test.c &&
1222 git commit -m "add main and test file" &&
1223 before_main=$(git rev-parse --short HEAD:main.c) &&
1224 before_test=$(git rev-parse --short HEAD:test.c) &&
1225 cat <<-\EOF >main.c &&
1238 cat <<-\EOF >test.c &&
1242 printf("Hello World, but different\n");
1245 int secure_foo(struct user *u)
1248 if (!u->is_allowed_foo)
1252 int another_function()
1257 hash_main=$(git hash-object main.c) &&
1258 after_main=$(git rev-parse --short "$hash_main") &&
1259 hash_test=$(git hash-object test.c) &&
1260 after_test=$(git rev-parse --short "$hash_test") &&
1261 git diff HEAD --no-renames --color-moved=zebra --color >actual.raw &&
1262 test_decode_color <actual.raw >actual &&
1263 cat <<-EOF >expected &&
1264 <BOLD>diff --git a/main.c b/main.c<RESET>
1265 <BOLD>index $before_main..$after_main 100644<RESET>
1266 <BOLD>--- a/main.c<RESET>
1267 <BOLD>+++ b/main.c<RESET>
1268 <CYAN>@@ -5,13 +5,6 @@<RESET> <RESET>printf("Hello ");<RESET>
1269 printf("World\n");<RESET>
1272 <BRED>-int secure_foo(struct user *u)<RESET>
1274 <BLUE>-if (!u->is_allowed_foo)<RESET>
1275 <BLUE>-return;<RESET>
1276 <RED>-foo(u);<RESET>
1282 <BOLD>diff --git a/test.c b/test.c<RESET>
1283 <BOLD>index $before_test..$after_test 100644<RESET>
1284 <BOLD>--- a/test.c<RESET>
1285 <BOLD>+++ b/test.c<RESET>
1286 <CYAN>@@ -4,6 +4,13 @@<RESET> <RESET>int bar()<RESET>
1287 printf("Hello World, but different\n");<RESET>
1290 <BGREEN>+<RESET><BGREEN>int secure_foo(struct user *u)<RESET>
1291 <BGREEN>+<RESET><BGREEN>{<RESET>
1292 <GREEN>+<RESET><GREEN>foo(u);<RESET>
1293 <BGREEN>+<RESET><BGREEN>if (!u->is_allowed_foo)<RESET>
1294 <BGREEN>+<RESET><BGREEN>return;<RESET>
1295 <GREEN>+<RESET><GREEN>}<RESET>
1297 int another_function()<RESET>
1302 test_cmp expected actual
1305 test_expect_success
'plain moved code, inside file' '
1306 test_config color.diff.oldMoved "normal red" &&
1307 test_config color.diff.newMoved "normal green" &&
1308 test_config color.diff.oldMovedAlternative "blue" &&
1309 test_config color.diff.newMovedAlternative "yellow" &&
1310 # needs previous test as setup
1311 git diff HEAD --no-renames --color-moved=plain --color >actual.raw &&
1312 test_decode_color <actual.raw >actual &&
1313 cat <<-EOF >expected &&
1314 <BOLD>diff --git a/main.c b/main.c<RESET>
1315 <BOLD>index $before_main..$after_main 100644<RESET>
1316 <BOLD>--- a/main.c<RESET>
1317 <BOLD>+++ b/main.c<RESET>
1318 <CYAN>@@ -5,13 +5,6 @@<RESET> <RESET>printf("Hello ");<RESET>
1319 printf("World\n");<RESET>
1322 <BRED>-int secure_foo(struct user *u)<RESET>
1324 <BRED>-if (!u->is_allowed_foo)<RESET>
1325 <BRED>-return;<RESET>
1326 <BRED>-foo(u);<RESET>
1332 <BOLD>diff --git a/test.c b/test.c<RESET>
1333 <BOLD>index $before_test..$after_test 100644<RESET>
1334 <BOLD>--- a/test.c<RESET>
1335 <BOLD>+++ b/test.c<RESET>
1336 <CYAN>@@ -4,6 +4,13 @@<RESET> <RESET>int bar()<RESET>
1337 printf("Hello World, but different\n");<RESET>
1340 <BGREEN>+<RESET><BGREEN>int secure_foo(struct user *u)<RESET>
1341 <BGREEN>+<RESET><BGREEN>{<RESET>
1342 <BGREEN>+<RESET><BGREEN>foo(u);<RESET>
1343 <BGREEN>+<RESET><BGREEN>if (!u->is_allowed_foo)<RESET>
1344 <BGREEN>+<RESET><BGREEN>return;<RESET>
1345 <BGREEN>+<RESET><BGREEN>}<RESET>
1347 int another_function()<RESET>
1352 test_cmp expected actual
1355 test_expect_success
'detect blocks of moved code' '
1357 cat <<-\EOF >lines.txt &&
1375 git add lines.txt &&
1376 git commit -m "add poetry" &&
1377 cat <<-\EOF >lines.txt &&
1395 test_config color.diff.oldMoved "magenta" &&
1396 test_config color.diff.newMoved "cyan" &&
1397 test_config color.diff.oldMovedAlternative "blue" &&
1398 test_config color.diff.newMovedAlternative "yellow" &&
1399 test_config color.diff.oldMovedDimmed "normal magenta" &&
1400 test_config color.diff.newMovedDimmed "normal cyan" &&
1401 test_config color.diff.oldMovedAlternativeDimmed "normal blue" &&
1402 test_config color.diff.newMovedAlternativeDimmed "normal yellow" &&
1403 git diff HEAD --no-renames --color-moved=blocks --color >actual.raw &&
1404 grep -v "index" actual.raw | test_decode_color >actual &&
1405 cat <<-\EOF >expected &&
1406 <BOLD>diff --git a/lines.txt b/lines.txt<RESET>
1407 <BOLD>--- a/lines.txt<RESET>
1408 <BOLD>+++ b/lines.txt<RESET>
1409 <CYAN>@@ -1,16 +1,16 @@<RESET>
1410 <MAGENTA>-long line 1<RESET>
1411 <MAGENTA>-long line 2<RESET>
1412 <MAGENTA>-long line 3<RESET>
1419 <CYAN>+<RESET><CYAN>long line 1<RESET>
1420 <CYAN>+<RESET><CYAN>long line 2<RESET>
1421 <CYAN>+<RESET><CYAN>long line 3<RESET>
1422 <CYAN>+<RESET><CYAN>long line 14<RESET>
1423 <CYAN>+<RESET><CYAN>long line 15<RESET>
1424 <CYAN>+<RESET><CYAN>long line 16<RESET>
1429 <MAGENTA>-long line 14<RESET>
1430 <MAGENTA>-long line 15<RESET>
1431 <MAGENTA>-long line 16<RESET>
1433 test_cmp expected actual
1437 test_expect_success
'detect permutations inside moved code -- dimmed-zebra' '
1438 # reuse setup from test before!
1439 test_config color.diff.oldMoved "magenta" &&
1440 test_config color.diff.newMoved "cyan" &&
1441 test_config color.diff.oldMovedAlternative "blue" &&
1442 test_config color.diff.newMovedAlternative "yellow" &&
1443 test_config color.diff.oldMovedDimmed "normal magenta" &&
1444 test_config color.diff.newMovedDimmed "normal cyan" &&
1445 test_config color.diff.oldMovedAlternativeDimmed "normal blue" &&
1446 test_config color.diff.newMovedAlternativeDimmed "normal yellow" &&
1447 git diff HEAD --no-renames --color-moved=dimmed-zebra --color >actual.raw &&
1448 grep -v "index" actual.raw | test_decode_color >actual &&
1449 cat <<-\EOF >expected &&
1450 <BOLD>diff --git a/lines.txt b/lines.txt<RESET>
1451 <BOLD>--- a/lines.txt<RESET>
1452 <BOLD>+++ b/lines.txt<RESET>
1453 <CYAN>@@ -1,16 +1,16 @@<RESET>
1454 <BMAGENTA>-long line 1<RESET>
1455 <BMAGENTA>-long line 2<RESET>
1456 <BMAGENTA>-long line 3<RESET>
1463 <BCYAN>+<RESET><BCYAN>long line 1<RESET>
1464 <BCYAN>+<RESET><BCYAN>long line 2<RESET>
1465 <CYAN>+<RESET><CYAN>long line 3<RESET>
1466 <YELLOW>+<RESET><YELLOW>long line 14<RESET>
1467 <BYELLOW>+<RESET><BYELLOW>long line 15<RESET>
1468 <BYELLOW>+<RESET><BYELLOW>long line 16<RESET>
1473 <BMAGENTA>-long line 14<RESET>
1474 <BMAGENTA>-long line 15<RESET>
1475 <BMAGENTA>-long line 16<RESET>
1477 test_cmp expected actual
1480 test_expect_success
'zebra alternate color is only used when necessary' '
1481 cat >old.txt <<-\EOF &&
1482 line 1A should be marked as oldMoved newMovedAlternate
1483 line 1B should be marked as oldMoved newMovedAlternate
1485 line 2A should be marked as oldMoved newMovedAlternate
1486 line 2B should be marked as oldMoved newMovedAlternate
1487 line 3A should be marked as oldMovedAlternate newMoved
1488 line 3B should be marked as oldMovedAlternate newMoved
1490 line 4A should be marked as oldMoved newMovedAlternate
1491 line 4B should be marked as oldMoved newMovedAlternate
1492 line 5A should be marked as oldMovedAlternate newMoved
1493 line 5B should be marked as oldMovedAlternate newMoved
1494 line 6A should be marked as oldMoved newMoved
1495 line 6B should be marked as oldMoved newMoved
1497 cat >new.txt <<-\EOF &&
1498 line 1A should be marked as oldMoved newMovedAlternate
1499 line 1B should be marked as oldMoved newMovedAlternate
1501 line 3A should be marked as oldMovedAlternate newMoved
1502 line 3B should be marked as oldMovedAlternate newMoved
1503 line 2A should be marked as oldMoved newMovedAlternate
1504 line 2B should be marked as oldMoved newMovedAlternate
1506 line 6A should be marked as oldMoved newMoved
1507 line 6B should be marked as oldMoved newMoved
1508 line 4A should be marked as oldMoved newMovedAlternate
1509 line 4B should be marked as oldMoved newMovedAlternate
1510 line 5A should be marked as oldMovedAlternate newMoved
1511 line 5B should be marked as oldMovedAlternate newMoved
1513 test_expect_code 1 git diff --no-index --color --color-moved=zebra \
1514 --color-moved-ws=allow-indentation-change \
1515 old.txt new.txt >output &&
1516 grep -v index output | test_decode_color >actual &&
1517 cat >expected <<-\EOF &&
1518 <BOLD>diff --git a/old.txt b/new.txt<RESET>
1519 <BOLD>--- a/old.txt<RESET>
1520 <BOLD>+++ b/new.txt<RESET>
1521 <CYAN>@@ -1,14 +1,14 @@<RESET>
1522 <BOLD;MAGENTA>-line 1A should be marked as oldMoved newMovedAlternate<RESET>
1523 <BOLD;MAGENTA>-line 1B should be marked as oldMoved newMovedAlternate<RESET>
1524 <BOLD;CYAN>+<RESET><BOLD;CYAN> line 1A should be marked as oldMoved newMovedAlternate<RESET>
1525 <BOLD;CYAN>+<RESET><BOLD;CYAN> line 1B should be marked as oldMoved newMovedAlternate<RESET>
1527 <BOLD;MAGENTA>-line 2A should be marked as oldMoved newMovedAlternate<RESET>
1528 <BOLD;MAGENTA>-line 2B should be marked as oldMoved newMovedAlternate<RESET>
1529 <BOLD;BLUE>-line 3A should be marked as oldMovedAlternate newMoved<RESET>
1530 <BOLD;BLUE>-line 3B should be marked as oldMovedAlternate newMoved<RESET>
1531 <BOLD;CYAN>+<RESET><BOLD;CYAN> line 3A should be marked as oldMovedAlternate newMoved<RESET>
1532 <BOLD;CYAN>+<RESET><BOLD;CYAN> line 3B should be marked as oldMovedAlternate newMoved<RESET>
1533 <BOLD;YELLOW>+<RESET><BOLD;YELLOW> line 2A should be marked as oldMoved newMovedAlternate<RESET>
1534 <BOLD;YELLOW>+<RESET><BOLD;YELLOW> line 2B should be marked as oldMoved newMovedAlternate<RESET>
1536 <BOLD;MAGENTA>-line 4A should be marked as oldMoved newMovedAlternate<RESET>
1537 <BOLD;MAGENTA>-line 4B should be marked as oldMoved newMovedAlternate<RESET>
1538 <BOLD;BLUE>-line 5A should be marked as oldMovedAlternate newMoved<RESET>
1539 <BOLD;BLUE>-line 5B should be marked as oldMovedAlternate newMoved<RESET>
1540 <BOLD;MAGENTA>-line 6A should be marked as oldMoved newMoved<RESET>
1541 <BOLD;MAGENTA>-line 6B should be marked as oldMoved newMoved<RESET>
1542 <BOLD;CYAN>+<RESET><BOLD;CYAN> line 6A should be marked as oldMoved newMoved<RESET>
1543 <BOLD;CYAN>+<RESET><BOLD;CYAN> line 6B should be marked as oldMoved newMoved<RESET>
1544 <BOLD;YELLOW>+<RESET><BOLD;YELLOW> line 4A should be marked as oldMoved newMovedAlternate<RESET>
1545 <BOLD;YELLOW>+<RESET><BOLD;YELLOW> line 4B should be marked as oldMoved newMovedAlternate<RESET>
1546 <BOLD;CYAN>+<RESET><BOLD;CYAN> line 5A should be marked as oldMovedAlternate newMoved<RESET>
1547 <BOLD;CYAN>+<RESET><BOLD;CYAN> line 5B should be marked as oldMovedAlternate newMoved<RESET>
1549 test_cmp expected actual
1552 test_expect_success
'short lines of opposite sign do not get marked as moved' '
1553 cat >old.txt <<-\EOF &&
1554 this line should be marked as moved
1560 this line should be marked as oldMoved newMoved
1561 this line should be marked as oldMovedAlternate newMoved
1566 this line should be marked as oldMoved newMoved/newMovedAlternate
1568 cat >new.txt <<-\EOF &&
1572 this line should be marked as moved
1576 this line should be marked as oldMoved newMoved/newMovedAlternate
1579 this line should be marked as oldMovedAlternate newMoved
1580 this line should be marked as oldMoved newMoved/newMovedAlternate
1582 this line should be marked as oldMoved newMoved
1585 test_expect_code 1 git diff --no-index --color --color-moved=zebra \
1586 old.txt new.txt >output && cat output &&
1587 grep -v index output | test_decode_color >actual &&
1588 cat >expect <<-\EOF &&
1589 <BOLD>diff --git a/old.txt b/new.txt<RESET>
1590 <BOLD>--- a/old.txt<RESET>
1591 <BOLD>+++ b/new.txt<RESET>
1592 <CYAN>@@ -1,13 +1,15 @@<RESET>
1593 <BOLD;MAGENTA>-this line should be marked as moved<RESET>
1594 <GREEN>+<RESET><GREEN>too short<RESET>
1597 <BOLD;CYAN>+<RESET><BOLD;CYAN>this line should be marked as moved<RESET>
1598 <GREEN>+<RESET><GREEN>too short<RESET>
1601 <RED>-too short<RESET>
1602 <BOLD;MAGENTA>-this line should be marked as oldMoved newMoved<RESET>
1603 <BOLD;BLUE>-this line should be marked as oldMovedAlternate newMoved<RESET>
1604 <BOLD;CYAN>+<RESET><BOLD;CYAN>this line should be marked as oldMoved newMoved/newMovedAlternate<RESET>
1607 <BOLD;CYAN>+<RESET><BOLD;CYAN>this line should be marked as oldMovedAlternate newMoved<RESET>
1608 <BOLD;YELLOW>+<RESET><BOLD;YELLOW>this line should be marked as oldMoved newMoved/newMovedAlternate<RESET>
1610 <BOLD;CYAN>+<RESET><BOLD;CYAN>this line should be marked as oldMoved newMoved<RESET>
1612 <BOLD;MAGENTA>-this line should be marked as oldMoved newMoved/newMovedAlternate<RESET>
1614 test_cmp expect actual
1617 test_expect_success
'cmd option assumes configured colored-moved' '
1618 test_config color.diff.oldMoved "magenta" &&
1619 test_config color.diff.newMoved "cyan" &&
1620 test_config color.diff.oldMovedAlternative "blue" &&
1621 test_config color.diff.newMovedAlternative "yellow" &&
1622 test_config color.diff.oldMovedDimmed "normal magenta" &&
1623 test_config color.diff.newMovedDimmed "normal cyan" &&
1624 test_config color.diff.oldMovedAlternativeDimmed "normal blue" &&
1625 test_config color.diff.newMovedAlternativeDimmed "normal yellow" &&
1626 test_config diff.colorMoved zebra &&
1627 git diff HEAD --no-renames --color-moved --color >actual.raw &&
1628 grep -v "index" actual.raw | test_decode_color >actual &&
1629 cat <<-\EOF >expected &&
1630 <BOLD>diff --git a/lines.txt b/lines.txt<RESET>
1631 <BOLD>--- a/lines.txt<RESET>
1632 <BOLD>+++ b/lines.txt<RESET>
1633 <CYAN>@@ -1,16 +1,16 @@<RESET>
1634 <MAGENTA>-long line 1<RESET>
1635 <MAGENTA>-long line 2<RESET>
1636 <MAGENTA>-long line 3<RESET>
1643 <CYAN>+<RESET><CYAN>long line 1<RESET>
1644 <CYAN>+<RESET><CYAN>long line 2<RESET>
1645 <CYAN>+<RESET><CYAN>long line 3<RESET>
1646 <YELLOW>+<RESET><YELLOW>long line 14<RESET>
1647 <YELLOW>+<RESET><YELLOW>long line 15<RESET>
1648 <YELLOW>+<RESET><YELLOW>long line 16<RESET>
1653 <MAGENTA>-long line 14<RESET>
1654 <MAGENTA>-long line 15<RESET>
1655 <MAGENTA>-long line 16<RESET>
1657 test_cmp expected actual
1660 test_expect_success
'no effect on diff from --color-moved with --word-diff' '
1661 cat <<-\EOF >text.txt &&
1662 Lorem Ipsum is simply dummy text of the printing and typesetting industry.
1665 git commit -a -m "clean state" &&
1666 cat <<-\EOF >text.txt &&
1667 simply Lorem Ipsum dummy is text of the typesetting and printing industry.
1669 git diff --color-moved --word-diff >actual &&
1670 git diff --word-diff >expect &&
1671 test_cmp expect actual
1674 test_expect_success
!SANITIZE_LEAK
'no effect on show from --color-moved with --word-diff' '
1675 git show --color-moved --word-diff >actual &&
1676 git show --word-diff >expect &&
1677 test_cmp expect actual
1680 test_expect_success
'set up whitespace tests' '
1682 # Note that these lines have no leading or trailing whitespace.
1683 cat <<-\EOF >lines.txt &&
1694 git add lines.txt &&
1695 git commit -m "add poetry" &&
1696 git config color.diff.oldMoved "magenta" &&
1697 git config color.diff.newMoved "cyan"
1700 test_expect_success
'move detection ignoring whitespace ' '
1701 q_to_tab <<-\EOF >lines.txt &&
1705 Qchanged long line 9
1712 git diff HEAD --no-renames --color-moved --color >actual.raw &&
1713 grep -v "index" actual.raw | test_decode_color >actual &&
1714 cat <<-\EOF >expected &&
1715 <BOLD>diff --git a/lines.txt b/lines.txt<RESET>
1716 <BOLD>--- a/lines.txt<RESET>
1717 <BOLD>+++ b/lines.txt<RESET>
1718 <CYAN>@@ -1,9 +1,9 @@<RESET>
1719 <GREEN>+<RESET> <GREEN>long line 6<RESET>
1720 <GREEN>+<RESET> <GREEN>long line 7<RESET>
1721 <GREEN>+<RESET> <GREEN>long line 8<RESET>
1722 <GREEN>+<RESET> <GREEN>changed long line 9<RESET>
1728 <RED>-long line 6<RESET>
1729 <RED>-long line 7<RESET>
1730 <RED>-long line 8<RESET>
1731 <RED>-long line 9<RESET>
1733 test_cmp expected actual &&
1735 git diff HEAD --no-renames --color-moved --color \
1736 --color-moved-ws=ignore-all-space >actual.raw &&
1737 grep -v "index" actual.raw | test_decode_color >actual &&
1738 cat <<-\EOF >expected &&
1739 <BOLD>diff --git a/lines.txt b/lines.txt<RESET>
1740 <BOLD>--- a/lines.txt<RESET>
1741 <BOLD>+++ b/lines.txt<RESET>
1742 <CYAN>@@ -1,9 +1,9 @@<RESET>
1743 <CYAN>+<RESET> <CYAN>long line 6<RESET>
1744 <CYAN>+<RESET> <CYAN>long line 7<RESET>
1745 <CYAN>+<RESET> <CYAN>long line 8<RESET>
1746 <GREEN>+<RESET> <GREEN>changed long line 9<RESET>
1752 <MAGENTA>-long line 6<RESET>
1753 <MAGENTA>-long line 7<RESET>
1754 <MAGENTA>-long line 8<RESET>
1755 <RED>-long line 9<RESET>
1757 test_cmp expected actual
1760 test_expect_success
'move detection ignoring whitespace changes' '
1762 # Lines 6-8 have a space change, but 9 is new whitespace
1763 q_to_tab <<-\EOF >lines.txt &&
1775 git diff HEAD --no-renames --color-moved --color >actual.raw &&
1776 grep -v "index" actual.raw | test_decode_color >actual &&
1777 cat <<-\EOF >expected &&
1778 <BOLD>diff --git a/lines.txt b/lines.txt<RESET>
1779 <BOLD>--- a/lines.txt<RESET>
1780 <BOLD>+++ b/lines.txt<RESET>
1781 <CYAN>@@ -1,9 +1,9 @@<RESET>
1782 <GREEN>+<RESET><GREEN>long line 6<RESET>
1783 <GREEN>+<RESET><GREEN>long line 7<RESET>
1784 <GREEN>+<RESET><GREEN>long line 8<RESET>
1785 <GREEN>+<RESET><GREEN>long li ne 9<RESET>
1791 <RED>-long line 6<RESET>
1792 <RED>-long line 7<RESET>
1793 <RED>-long line 8<RESET>
1794 <RED>-long line 9<RESET>
1796 test_cmp expected actual &&
1798 git diff HEAD --no-renames --color-moved --color \
1799 --color-moved-ws=ignore-space-change >actual.raw &&
1800 grep -v "index" actual.raw | test_decode_color >actual &&
1801 cat <<-\EOF >expected &&
1802 <BOLD>diff --git a/lines.txt b/lines.txt<RESET>
1803 <BOLD>--- a/lines.txt<RESET>
1804 <BOLD>+++ b/lines.txt<RESET>
1805 <CYAN>@@ -1,9 +1,9 @@<RESET>
1806 <CYAN>+<RESET><CYAN>long line 6<RESET>
1807 <CYAN>+<RESET><CYAN>long line 7<RESET>
1808 <CYAN>+<RESET><CYAN>long line 8<RESET>
1809 <GREEN>+<RESET><GREEN>long li ne 9<RESET>
1815 <MAGENTA>-long line 6<RESET>
1816 <MAGENTA>-long line 7<RESET>
1817 <MAGENTA>-long line 8<RESET>
1818 <RED>-long line 9<RESET>
1820 test_cmp expected actual
1823 test_expect_success
'move detection ignoring whitespace at eol' '
1825 # Lines 6-9 have new eol whitespace, but 9 also has it in the middle
1826 q_to_tab <<-\EOF >lines.txt &&
1838 # avoid cluttering the output with complaints about our eol whitespace
1839 test_config core.whitespace -blank-at-eol &&
1841 git diff HEAD --no-renames --color-moved --color >actual.raw &&
1842 grep -v "index" actual.raw | test_decode_color >actual &&
1843 cat <<-\EOF >expected &&
1844 <BOLD>diff --git a/lines.txt b/lines.txt<RESET>
1845 <BOLD>--- a/lines.txt<RESET>
1846 <BOLD>+++ b/lines.txt<RESET>
1847 <CYAN>@@ -1,9 +1,9 @@<RESET>
1848 <GREEN>+<RESET><GREEN>long line 6 <RESET>
1849 <GREEN>+<RESET><GREEN>long line 7 <RESET>
1850 <GREEN>+<RESET><GREEN>long line 8 <RESET>
1851 <GREEN>+<RESET><GREEN>long line 9 <RESET>
1857 <RED>-long line 6<RESET>
1858 <RED>-long line 7<RESET>
1859 <RED>-long line 8<RESET>
1860 <RED>-long line 9<RESET>
1862 test_cmp expected actual &&
1864 git diff HEAD --no-renames --color-moved --color \
1865 --color-moved-ws=ignore-space-at-eol >actual.raw &&
1866 grep -v "index" actual.raw | test_decode_color >actual &&
1867 cat <<-\EOF >expected &&
1868 <BOLD>diff --git a/lines.txt b/lines.txt<RESET>
1869 <BOLD>--- a/lines.txt<RESET>
1870 <BOLD>+++ b/lines.txt<RESET>
1871 <CYAN>@@ -1,9 +1,9 @@<RESET>
1872 <CYAN>+<RESET><CYAN>long line 6 <RESET>
1873 <CYAN>+<RESET><CYAN>long line 7 <RESET>
1874 <CYAN>+<RESET><CYAN>long line 8 <RESET>
1875 <GREEN>+<RESET><GREEN>long line 9 <RESET>
1881 <MAGENTA>-long line 6<RESET>
1882 <MAGENTA>-long line 7<RESET>
1883 <MAGENTA>-long line 8<RESET>
1884 <RED>-long line 9<RESET>
1886 test_cmp expected actual
1889 test_expect_success
'clean up whitespace-test colors' '
1890 git config --unset color.diff.oldMoved &&
1891 git config --unset color.diff.newMoved
1894 test_expect_success
'--color-moved block at end of diff output respects MIN_ALNUM_COUNT' '
1911 git diff HEAD --color-moved=zebra --color --no-renames >actual.raw &&
1912 grep -v "index" actual.raw | test_decode_color >actual &&
1913 cat >expected <<-\EOF &&
1914 <BOLD>diff --git a/bar b/bar<RESET>
1915 <BOLD>--- a/bar<RESET>
1916 <BOLD>+++ b/bar<RESET>
1917 <CYAN>@@ -0,0 +1 @@<RESET>
1918 <GREEN>+<RESET><GREEN>line1<RESET>
1919 <BOLD>diff --git a/foo b/foo<RESET>
1920 <BOLD>--- a/foo<RESET>
1921 <BOLD>+++ b/foo<RESET>
1922 <CYAN>@@ -1,2 +1 @@<RESET>
1923 irrelevant_line<RESET>
1927 test_cmp expected actual
1930 test_expect_success
'--color-moved respects MIN_ALNUM_COUNT' '
1933 nineteen chars 456789
1935 twenty chars 234567890
1945 twenty chars 234567890
1946 nineteen chars 456789
1949 git diff HEAD --color-moved=zebra --color --no-renames >actual.raw &&
1950 grep -v "index" actual.raw | test_decode_color >actual &&
1951 cat >expected <<-\EOF &&
1952 <BOLD>diff --git a/bar b/bar<RESET>
1953 <BOLD>--- a/bar<RESET>
1954 <BOLD>+++ b/bar<RESET>
1955 <CYAN>@@ -0,0 +1,2 @@<RESET>
1956 <BOLD;CYAN>+<RESET><BOLD;CYAN>twenty chars 234567890<RESET>
1957 <GREEN>+<RESET><GREEN>nineteen chars 456789<RESET>
1958 <BOLD>diff --git a/foo b/foo<RESET>
1959 <BOLD>--- a/foo<RESET>
1960 <BOLD>+++ b/foo<RESET>
1961 <CYAN>@@ -1,3 +1 @@<RESET>
1962 <RED>-nineteen chars 456789<RESET>
1963 irrelevant_line<RESET>
1964 <BOLD;MAGENTA>-twenty chars 234567890<RESET>
1967 test_cmp expected actual
1970 test_expect_success
'--color-moved treats adjacent blocks as separate for MIN_ALNUM_COUNT' '
1991 git diff HEAD --color-moved=zebra --color --no-renames >actual.raw &&
1992 grep -v "index" actual.raw | test_decode_color >actual &&
1993 cat >expected <<-\EOF &&
1994 <BOLD>diff --git a/bar b/bar<RESET>
1995 <BOLD>--- a/bar<RESET>
1996 <BOLD>+++ b/bar<RESET>
1997 <CYAN>@@ -0,0 +1,3 @@<RESET>
1998 <GREEN>+<RESET><GREEN>7charsB<RESET>
1999 <GREEN>+<RESET><GREEN>7charsC<RESET>
2000 <GREEN>+<RESET><GREEN>7charsA<RESET>
2001 <BOLD>diff --git a/foo b/foo<RESET>
2002 <BOLD>--- a/foo<RESET>
2003 <BOLD>+++ b/foo<RESET>
2004 <CYAN>@@ -1,4 +1 @@<RESET>
2005 <RED>-7charsA<RESET>
2006 irrelevant_line<RESET>
2007 <RED>-7charsB<RESET>
2008 <RED>-7charsC<RESET>
2011 test_cmp expected actual
2014 test_expect_success
'--color-moved rewinds for MIN_ALNUM_COUNT' '
2016 test_write_lines >file \
2017 A B C one two three four five six seven D E F G H I J &&
2019 test_write_lines >file \
2020 one two A B C D E F G H I J two three four five six seven &&
2021 git diff --color-moved=zebra -- file &&
2023 git diff --color-moved=zebra --color -- file >actual.raw &&
2024 grep -v "index" actual.raw | test_decode_color >actual &&
2025 cat >expected <<-\EOF &&
2026 <BOLD>diff --git a/file b/file<RESET>
2027 <BOLD>--- a/file<RESET>
2028 <BOLD>+++ b/file<RESET>
2029 <CYAN>@@ -1,13 +1,8 @@<RESET>
2030 <GREEN>+<RESET><GREEN>one<RESET>
2031 <GREEN>+<RESET><GREEN>two<RESET>
2036 <BOLD;MAGENTA>-two<RESET>
2037 <BOLD;MAGENTA>-three<RESET>
2038 <BOLD;MAGENTA>-four<RESET>
2039 <BOLD;MAGENTA>-five<RESET>
2040 <BOLD;MAGENTA>-six<RESET>
2041 <BOLD;MAGENTA>-seven<RESET>
2045 <CYAN>@@ -15,3 +10,9 @@<RESET> <RESET>G<RESET>
2049 <BOLD;CYAN>+<RESET><BOLD;CYAN>two<RESET>
2050 <BOLD;CYAN>+<RESET><BOLD;CYAN>three<RESET>
2051 <BOLD;CYAN>+<RESET><BOLD;CYAN>four<RESET>
2052 <BOLD;CYAN>+<RESET><BOLD;CYAN>five<RESET>
2053 <BOLD;CYAN>+<RESET><BOLD;CYAN>six<RESET>
2054 <BOLD;CYAN>+<RESET><BOLD;CYAN>seven<RESET>
2057 test_cmp expected actual
2060 test_expect_success
!SANITIZE_LEAK
'move detection with submodules' '
2061 test_create_repo bananas &&
2062 echo ripe >bananas/recipe &&
2063 git -C bananas add recipe &&
2064 test_commit fruit &&
2065 test_commit -C bananas recipe &&
2066 git submodule add ./bananas &&
2068 git commit -a -m "bananas are like a heavy library?" &&
2069 echo foul >bananas/recipe &&
2070 echo ripe >fruit.t &&
2072 git diff --submodule=diff --color-moved --color >actual &&
2074 # no move detection as the moved line is across repository boundaries.
2075 test_decode_color <actual >decoded_actual &&
2076 ! grep BGREEN decoded_actual &&
2077 ! grep BRED decoded_actual &&
2079 # nor did we mess with it another way
2080 git diff --submodule=diff --color >expect.raw &&
2081 test_decode_color <expect.raw >expect &&
2082 test_cmp expect decoded_actual &&
2084 git submodule deinit bananas
2087 test_expect_success
'only move detection ignores white spaces' '
2089 q_to_tab <<-\EOF >text.txt &&
2090 a long line to exceed per-line minimum
2091 another long line to exceed per-line minimum
2095 git commit -m "add text" &&
2096 q_to_tab <<-\EOF >text.txt &&
2097 Qa long line to exceed per-line minimum
2098 Qanother long line to exceed per-line minimum
2102 # Make sure we get a different diff using -w
2103 git diff --color --color-moved -w >actual.raw &&
2104 grep -v "index" actual.raw | test_decode_color >actual &&
2105 q_to_tab <<-\EOF >expected &&
2106 <BOLD>diff --git a/text.txt b/text.txt<RESET>
2107 <BOLD>--- a/text.txt<RESET>
2108 <BOLD>+++ b/text.txt<RESET>
2109 <CYAN>@@ -1,3 +1,3 @@<RESET>
2110 Qa long line to exceed per-line minimum<RESET>
2111 Qanother long line to exceed per-line minimum<RESET>
2112 <RED>-original file<RESET>
2113 <GREEN>+<RESET><GREEN>new file<RESET>
2115 test_cmp expected actual &&
2117 # And now ignoring white space only in the move detection
2118 git diff --color --color-moved \
2119 --color-moved-ws=ignore-all-space,ignore-space-change,ignore-space-at-eol >actual.raw &&
2120 grep -v "index" actual.raw | test_decode_color >actual &&
2121 q_to_tab <<-\EOF >expected &&
2122 <BOLD>diff --git a/text.txt b/text.txt<RESET>
2123 <BOLD>--- a/text.txt<RESET>
2124 <BOLD>+++ b/text.txt<RESET>
2125 <CYAN>@@ -1,3 +1,3 @@<RESET>
2126 <BOLD;MAGENTA>-a long line to exceed per-line minimum<RESET>
2127 <BOLD;MAGENTA>-another long line to exceed per-line minimum<RESET>
2128 <RED>-original file<RESET>
2129 <BOLD;CYAN>+<RESET>Q<BOLD;CYAN>a long line to exceed per-line minimum<RESET>
2130 <BOLD;CYAN>+<RESET>Q<BOLD;CYAN>another long line to exceed per-line minimum<RESET>
2131 <GREEN>+<RESET><GREEN>new file<RESET>
2133 test_cmp expected actual
2136 test_expect_success
'compare whitespace delta across moved blocks' '
2139 q_to_tab <<-\EOF >text.txt &&
2143 QBut! <- this stands out
2145 QQdifferent starting
2151 QQQthat has similar lines
2152 QQQto previous blocks, but with different indent
2153 QQQYetQAnotherQoutlierQ
2154 QLine with internal w h i t e s p a c e change
2158 git commit -m "add text.txt" &&
2160 q_to_tab <<-\EOF >text.txt &&
2164 QQQBut! <- this stands out
2172 QQthat has similar lines
2173 QQto previous blocks, but with different indent
2174 QQYetQAnotherQoutlier
2175 QLine with internal whitespace change
2178 git diff --color --color-moved --color-moved-ws=allow-indentation-change >actual.raw &&
2179 grep -v "index" actual.raw | test_decode_color >actual &&
2181 q_to_tab <<-\EOF >expected &&
2182 <BOLD>diff --git a/text.txt b/text.txt<RESET>
2183 <BOLD>--- a/text.txt<RESET>
2184 <BOLD>+++ b/text.txt<RESET>
2185 <CYAN>@@ -1,15 +1,15 @@<RESET>
2186 <BOLD;MAGENTA>-QIndented<RESET>
2187 <BOLD;MAGENTA>-QText across<RESET>
2188 <BOLD;MAGENTA>-Qsome lines<RESET>
2189 <RED>-QBut! <- this stands out<RESET>
2190 <BOLD;MAGENTA>-QAdjusting with<RESET>
2191 <BOLD;MAGENTA>-QQdifferent starting<RESET>
2192 <BOLD;MAGENTA>-Qwhite spaces<RESET>
2193 <RED>-QAnother outlier<RESET>
2194 <BOLD;MAGENTA>-QQQIndented<RESET>
2195 <BOLD;MAGENTA>-QQQText across<RESET>
2196 <BOLD;MAGENTA>-QQQfive lines<RESET>
2197 <BOLD;MAGENTA>-QQQthat has similar lines<RESET>
2198 <BOLD;MAGENTA>-QQQto previous blocks, but with different indent<RESET>
2199 <RED>-QQQYetQAnotherQoutlierQ<RESET>
2200 <RED>-QLine with internal w h i t e s p a c e change<RESET>
2201 <BOLD;CYAN>+<RESET>QQ<BOLD;CYAN>Indented<RESET>
2202 <BOLD;CYAN>+<RESET>QQ<BOLD;CYAN>Text across<RESET>
2203 <BOLD;CYAN>+<RESET>QQ<BOLD;CYAN>some lines<RESET>
2204 <GREEN>+<RESET>QQQ<GREEN>But! <- this stands out<RESET>
2205 <BOLD;CYAN>+<RESET><BOLD;CYAN>Adjusting with<RESET>
2206 <BOLD;CYAN>+<RESET>Q<BOLD;CYAN>different starting<RESET>
2207 <BOLD;CYAN>+<RESET><BOLD;CYAN>white spaces<RESET>
2208 <GREEN>+<RESET><GREEN>AnotherQoutlier<RESET>
2209 <BOLD;CYAN>+<RESET>QQ<BOLD;CYAN>Indented<RESET>
2210 <BOLD;CYAN>+<RESET>QQ<BOLD;CYAN>Text across<RESET>
2211 <BOLD;CYAN>+<RESET>QQ<BOLD;CYAN>five lines<RESET>
2212 <BOLD;CYAN>+<RESET>QQ<BOLD;CYAN>that has similar lines<RESET>
2213 <BOLD;CYAN>+<RESET>QQ<BOLD;CYAN>to previous blocks, but with different indent<RESET>
2214 <GREEN>+<RESET>QQ<GREEN>YetQAnotherQoutlier<RESET>
2215 <GREEN>+<RESET>Q<GREEN>Line with internal whitespace change<RESET>
2218 test_cmp expected actual
2221 test_expect_success
'bogus settings in move detection erroring out' '
2222 test_must_fail git diff --color-moved=bogus 2>err &&
2223 test_i18ngrep "must be one of" err &&
2224 test_i18ngrep bogus err &&
2226 test_must_fail git -c diff.colormoved=bogus diff 2>err &&
2227 test_i18ngrep "must be one of" err &&
2228 test_i18ngrep "from command-line config" err &&
2230 test_must_fail git diff --color-moved-ws=bogus 2>err &&
2231 test_i18ngrep "possible values" err &&
2232 test_i18ngrep bogus err &&
2234 test_must_fail git -c diff.colormovedws=bogus diff 2>err &&
2235 test_i18ngrep "possible values" err &&
2236 test_i18ngrep "from command-line config" err
2239 test_expect_success
'compare whitespace delta incompatible with other space options' '
2240 test_must_fail git diff \
2241 --color-moved-ws=allow-indentation-change,ignore-all-space \
2243 test_i18ngrep allow-indentation-change err
2247 test_expect_success
'compare mixed whitespace delta across moved blocks' '
2250 tr "^|Q_" "\f\v\t " <<-EOF >text.txt &&
2252 |____too short without
2254 ___being grouped across blank line
2260 ____Indented text to
2261 _Q____be further indented by four spaces across
2263 QQ____These two lines have had their
2264 ____indentation reduced by four spaces
2265 Qdifferent indentation change
2270 git commit -m "add text.txt" &&
2272 tr "^|Q_" "\f\v\t " <<-EOF >text.txt &&
2278 QQbe further indented by four spaces across
2283 ^Q_______being grouped across blank line
2285 Q_QThese two lines have had their
2286 indentation reduced by four spaces
2287 QQdifferent indentation change
2291 git -c color.diff.whitespace="normal red" \
2292 -c core.whitespace=space-before-tab \
2293 diff --color --color-moved --ws-error-highlight=all \
2294 --color-moved-ws=allow-indentation-change >actual.raw &&
2295 grep -v "index" actual.raw | tr "\f\v" "^|" | test_decode_color >actual &&
2297 cat <<-\EOF >expected &&
2298 <BOLD>diff --git a/text.txt b/text.txt<RESET>
2299 <BOLD>--- a/text.txt<RESET>
2300 <BOLD>+++ b/text.txt<RESET>
2301 <CYAN>@@ -1,16 +1,16 @@<RESET>
2302 <BOLD;MAGENTA>-<RESET><BOLD;MAGENTA>^<RESET><BRED> <RESET>
2303 <BOLD;MAGENTA>-<RESET><BOLD;MAGENTA>| too short without<RESET>
2304 <BOLD;MAGENTA>-<RESET><BOLD;MAGENTA>^<RESET>
2305 <BOLD;MAGENTA>-<RESET><BOLD;MAGENTA> being grouped across blank line<RESET>
2306 <BOLD;MAGENTA>-<RESET>
2307 <RESET>context<RESET>
2310 <RESET>anchor<RESET>
2311 <BOLD;MAGENTA>-<RESET><BOLD;MAGENTA> Indented text to<RESET>
2312 <BOLD;MAGENTA>-<RESET><BRED> <RESET> <BOLD;MAGENTA> be further indented by four spaces across<RESET>
2313 <BOLD;MAGENTA>-<RESET><BRED> <RESET> <BOLD;MAGENTA>several lines<RESET>
2314 <BOLD;BLUE>-<RESET> <BOLD;BLUE> These two lines have had their<RESET>
2315 <BOLD;BLUE>-<RESET><BOLD;BLUE> indentation reduced by four spaces<RESET>
2316 <BOLD;MAGENTA>-<RESET> <BOLD;MAGENTA>different indentation change<RESET>
2317 <RED>-<RESET><RED> too short<RESET>
2318 <BOLD;CYAN>+<RESET> <BOLD;CYAN>Indented text to<RESET>
2319 <BOLD;CYAN>+<RESET> <BOLD;CYAN>be further indented by four spaces across<RESET>
2320 <BOLD;CYAN>+<RESET> <BOLD;CYAN> several lines<RESET>
2321 <BOLD;YELLOW>+<RESET>
2322 <BOLD;YELLOW>+<RESET> <BOLD;YELLOW>too short without<RESET>
2323 <BOLD;YELLOW>+<RESET>
2324 <BOLD;YELLOW>+<RESET><BOLD;YELLOW>^ being grouped across blank line<RESET>
2325 <BOLD;YELLOW>+<RESET>
2326 <BOLD;CYAN>+<RESET> <BRED> <RESET> <BOLD;CYAN>These two lines have had their<RESET>
2327 <BOLD;CYAN>+<RESET><BOLD;CYAN>indentation reduced by four spaces<RESET>
2328 <BOLD;YELLOW>+<RESET> <BOLD;YELLOW>different indentation change<RESET>
2329 <GREEN>+<RESET><BRED> <RESET> <GREEN>too short<RESET>
2332 test_cmp expected actual
2335 test_expect_success
'combine --ignore-blank-lines with --function-context' '
2336 test_write_lines 1 "" 2 3 4 5 >a &&
2337 test_write_lines 1 2 3 4 >b &&
2338 test_must_fail git diff --no-index \
2339 --ignore-blank-lines --function-context a b >actual.raw &&
2340 sed -n "/@@/,\$p" <actual.raw >actual &&
2341 cat <<-\EOF >expect &&
2350 test_cmp expect actual
2353 test_expect_success
'combine --ignore-blank-lines with --function-context 2' '
2354 test_write_lines a b c "" function 1 2 3 4 5 "" 6 7 8 9 >a &&
2355 test_write_lines "" a b c "" function 1 2 3 4 5 6 7 8 >b &&
2356 test_must_fail git diff --no-index \
2357 --ignore-blank-lines --function-context a b >actual.raw &&
2358 sed -n "/@@/,\$p" <actual.raw >actual &&
2359 cat <<-\EOF >expect &&
2373 test_cmp expect actual