3 # Copyright (c) 2006 Johannes E. Schindelin
4 # Copyright (c) 2023 Google LLC
6 test_description
='Test special whitespace in diff engine.
11 .
"$TEST_DIRECTORY"/lib-diff.sh
13 for opt_res
in --patch --quiet -s --stat --shortstat --dirstat=lines \
14 --raw! --name-only! --name-status!
16 opts
=${opt_res%!} expect_failure
=
17 test "$opts" = "$opt_res" ||
18 expect_failure
="test_expect_code 1"
20 test_expect_success
"status with $opts (different)" '
24 test_expect_code 1 git diff -w $opts --exit-code x
27 test_expect_success POSIXPERM
"status with $opts (mode differs)" '
28 test_when_finished "git update-index --chmod=-x x" &&
31 git update-index --chmod=+x x &&
32 test_expect_code 1 git diff -w $opts --exit-code x
35 test_expect_success
"status with $opts (removing an empty file)" '
39 test_expect_code 1 git diff -w $opts --exit-code -- x
42 test_expect_success
"status with $opts (different but equivalent)" '
46 $expect_failure git diff -w $opts --exit-code x
50 test_expect_success
"Ray Lehtiniemi's example" '
56 git update-index --add x &&
57 old_hash_x=$(git hash-object x) &&
58 before=$(git rev-parse --short "$old_hash_x") &&
67 new_hash_x=$(git hash-object x) &&
68 after=$(git rev-parse --short "$new_hash_x") &&
72 index $before..$after 100644
86 test_cmp expect out &&
89 test_cmp expect out &&
95 test_expect_success
'another test, without options' '
96 tr Q "\015" <<-\EOF >x &&
97 whitespace at beginning
99 whitespace in the middle
105 git update-index x &&
106 old_hash_x=$(git hash-object x) &&
107 before=$(git rev-parse --short "$old_hash_x") &&
109 tr "_" " " <<-\EOF >x &&
110 _ whitespace at beginning
112 white space in the middle
117 new_hash_x=$(git hash-object x) &&
118 after=$(git rev-parse --short "$new_hash_x") &&
120 tr "Q_" "\015 " <<-EOF >expect &&
122 index $before..$after 100644
126 -whitespace at beginning
128 -whitespace in the middle
130 + whitespace at beginning
132 +white space in the middle
140 test_cmp expect out &&
143 test_must_be_empty out &&
145 git diff -w -b >out &&
146 test_must_be_empty out &&
148 git diff -w --ignore-space-at-eol >out &&
149 test_must_be_empty out &&
151 git diff -w -b --ignore-space-at-eol >out &&
152 test_must_be_empty out &&
154 git diff -w --ignore-cr-at-eol >out &&
155 test_must_be_empty out &&
157 tr "Q_" "\015 " <<-EOF >expect &&
159 index $before..$after 100644
163 -whitespace at beginning
164 +_ whitespace at beginning
166 -whitespace in the middle
167 +white space in the middle
173 test_cmp expect out &&
175 git diff -b --ignore-space-at-eol >out &&
176 test_cmp expect out &&
178 git diff -b --ignore-cr-at-eol >out &&
179 test_cmp expect out &&
181 tr "Q_" "\015 " <<-EOF >expect &&
183 index $before..$after 100644
187 -whitespace at beginning
189 -whitespace in the middle
190 +_ whitespace at beginning
192 +white space in the middle
197 git diff --ignore-space-at-eol >out &&
198 test_cmp expect out &&
200 git diff --ignore-space-at-eol --ignore-cr-at-eol >out &&
201 test_cmp expect out &&
203 tr "Q_" "\015 " <<-EOF >expect &&
205 index_$before..$after 100644
209 -whitespace at beginning
211 -whitespace in the middle
213 +_ whitespace at beginning
215 +white space in the middle
220 git diff --ignore-cr-at-eol >out &&
224 test_expect_success
'ignore-blank-lines: only new lines' '
226 git update-index x &&
227 test_seq 5 | sed "/3/i\\
229 git diff --ignore-blank-lines >out &&
230 test_must_be_empty out
233 test_expect_success
'ignore-blank-lines: only new lines with space' '
235 git update-index x &&
236 test_seq 5 | sed "/3/i\\
238 git diff -w --ignore-blank-lines >out &&
239 test_must_be_empty out
242 test_expect_success
'ignore-blank-lines: after change' '
254 git update-index x &&
267 git diff --inter-hunk-context=100 --ignore-blank-lines >out.tmp &&
268 cat <<-\EOF >expected &&
282 compare_diff_patch expected out.tmp
285 test_expect_success
'ignore-blank-lines: before change' '
296 git update-index x &&
309 git diff --inter-hunk-context=100 --ignore-blank-lines >out.tmp &&
310 cat <<-\EOF >expected &&
323 compare_diff_patch expected out.tmp
326 test_expect_success
'ignore-blank-lines: between changes' '
341 git update-index x &&
358 git diff --ignore-blank-lines >out.tmp &&
359 cat <<-\EOF >expected &&
380 compare_diff_patch expected out.tmp
383 test_expect_success
'ignore-blank-lines: between changes (with interhunkctx)' '
385 git update-index x &&
403 git diff --inter-hunk-context=2 --ignore-blank-lines >out.tmp &&
404 cat <<-\EOF >expected &&
425 compare_diff_patch expected out.tmp
428 test_expect_success
'ignore-blank-lines: scattered spaces' '
430 git update-index x &&
451 git diff --inter-hunk-context=4 --ignore-blank-lines >out.tmp &&
452 cat <<-\EOF >expected &&
467 compare_diff_patch expected out.tmp
470 test_expect_success
'ignore-blank-lines: spaces coalesce' '
472 git update-index x &&
486 git diff --inter-hunk-context=4 --ignore-blank-lines >out.tmp &&
487 cat <<-\EOF >expected &&
504 compare_diff_patch expected out.tmp
507 test_expect_success
'ignore-blank-lines: mix changes and blank lines' '
509 git update-index x &&
535 git diff --ignore-blank-lines >out.tmp &&
536 cat <<-\EOF >expected &&
565 compare_diff_patch expected out.tmp
568 test_expect_success
'check mixed spaces and tabs in indent' '
569 # This is indented with SP HT SP.
571 test_must_fail git diff --check >check &&
572 grep "space before tab in indent" check
575 test_expect_success
'check mixed tabs and spaces in indent' '
576 # This is indented with HT SP HT.
578 test_must_fail git diff --check >check &&
579 grep "space before tab in indent" check
582 test_expect_success
'check with no whitespace errors' '
583 git commit -m "snapshot" &&
588 test_expect_success
'check with trailing whitespace' '
590 test_must_fail git diff --check
593 test_expect_success
'check with space before tab in indent' '
594 # indent has space followed by hard tab
596 test_must_fail git diff --check
599 test_expect_success
'--check and --exit-code are not exclusive' '
601 git diff --check --exit-code
604 test_expect_success
'--check and --quiet are not exclusive' '
605 git diff --check --quiet
608 test_expect_success
'-w and --exit-code interact sensibly' '
609 test_when_finished "git checkout x" &&
614 test_must_fail git diff --exit-code &&
615 git diff -w >actual &&
616 test_must_be_empty actual &&
617 git diff -w --exit-code
620 test_expect_success
'-I and --exit-code interact sensibly' '
621 test_when_finished "git checkout x" &&
626 test_must_fail git diff --exit-code &&
627 git diff -I. >actual &&
628 test_must_be_empty actual &&
629 git diff -I. --exit-code
632 test_expect_success
'check staged with no whitespace errors' '
635 git diff --cached --check
638 test_expect_success
'check staged with trailing whitespace' '
641 test_must_fail git diff --cached --check
644 test_expect_success
'check staged with space before tab in indent' '
645 # indent has space followed by hard tab
648 test_must_fail git diff --cached --check
651 test_expect_success
'check with no whitespace errors (diff-index)' '
654 git diff-index --check HEAD
657 test_expect_success
'check with trailing whitespace (diff-index)' '
660 test_must_fail git diff-index --check HEAD
663 test_expect_success
'check with space before tab in indent (diff-index)' '
664 # indent has space followed by hard tab
667 test_must_fail git diff-index --check HEAD
670 test_expect_success
'check staged with no whitespace errors (diff-index)' '
673 git diff-index --cached --check HEAD
676 test_expect_success
'check staged with trailing whitespace (diff-index)' '
679 test_must_fail git diff-index --cached --check HEAD
682 test_expect_success
'check staged with space before tab in indent (diff-index)' '
683 # indent has space followed by hard tab
686 test_must_fail git diff-index --cached --check HEAD
689 test_expect_success
'check with no whitespace errors (diff-tree)' '
691 git commit -m "new commit" x &&
692 git diff-tree --check HEAD^ HEAD
695 test_expect_success
'check with trailing whitespace (diff-tree)' '
697 git commit -m "another commit" x &&
698 test_must_fail git diff-tree --check HEAD^ HEAD
701 test_expect_success
'check with space before tab in indent (diff-tree)' '
702 # indent has space followed by hard tab
704 git commit -m "yet another" x &&
705 test_must_fail git diff-tree --check HEAD^ HEAD
708 test_expect_success
'check with ignored trailing whitespace attr (diff-tree)' '
709 test_when_finished "git reset --hard HEAD^" &&
711 # create a whitespace error that should be ignored
712 echo "* -whitespace" >.gitattributes &&
713 git add .gitattributes &&
716 git commit -m "add trailing space" &&
718 # with a worktree diff-tree ignores the whitespace error
719 git diff-tree --root --check HEAD &&
721 # without a worktree diff-tree still ignores the whitespace error
722 git -C .git diff-tree --root --check HEAD
725 test_expect_success
'check trailing whitespace (trailing-space: off)' '
726 git config core.whitespace "-trailing-space" &&
727 echo "foo (); " >x &&
731 test_expect_success
'check trailing whitespace (trailing-space: on)' '
732 git config core.whitespace "trailing-space" &&
733 echo "foo (); " >x &&
734 test_must_fail git diff --check
737 test_expect_success
'check space before tab in indent (space-before-tab: off)' '
738 # indent contains space followed by HT
739 git config core.whitespace "-space-before-tab" &&
740 echo " foo ();" >x &&
744 test_expect_success
'check space before tab in indent (space-before-tab: on)' '
745 # indent contains space followed by HT
746 git config core.whitespace "space-before-tab" &&
747 echo " foo (); " >x &&
748 test_must_fail git diff --check
751 test_expect_success
'check spaces as indentation (indent-with-non-tab: off)' '
752 git config core.whitespace "-indent-with-non-tab" &&
753 echo " foo ();" >x &&
757 test_expect_success
'check spaces as indentation (indent-with-non-tab: on)' '
758 git config core.whitespace "indent-with-non-tab" &&
759 echo " foo ();" >x &&
760 test_must_fail git diff --check
763 test_expect_success
'ditto, but tabwidth=9' '
764 git config core.whitespace "indent-with-non-tab,tabwidth=9" &&
768 test_expect_success
'check tabs and spaces as indentation (indent-with-non-tab: on)' '
769 git config core.whitespace "indent-with-non-tab" &&
770 echo " foo ();" >x &&
771 test_must_fail git diff --check
774 test_expect_success
'ditto, but tabwidth=10' '
775 git config core.whitespace "indent-with-non-tab,tabwidth=10" &&
776 test_must_fail git diff --check
779 test_expect_success
'ditto, but tabwidth=20' '
780 git config core.whitespace "indent-with-non-tab,tabwidth=20" &&
784 test_expect_success
'check tabs as indentation (tab-in-indent: off)' '
785 git config core.whitespace "-tab-in-indent" &&
786 echo " foo ();" >x &&
790 test_expect_success
'check tabs as indentation (tab-in-indent: on)' '
791 git config core.whitespace "tab-in-indent" &&
792 echo " foo ();" >x &&
793 test_must_fail git diff --check
796 test_expect_success
'check tabs and spaces as indentation (tab-in-indent: on)' '
797 git config core.whitespace "tab-in-indent" &&
798 echo " foo ();" >x &&
799 test_must_fail git diff --check
802 test_expect_success
'ditto, but tabwidth=1 (must be irrelevant)' '
803 git config core.whitespace "tab-in-indent,tabwidth=1" &&
804 test_must_fail git diff --check
807 test_expect_success
'check tab-in-indent and indent-with-non-tab conflict' '
808 git config core.whitespace "tab-in-indent,indent-with-non-tab" &&
810 test_must_fail git diff --check
813 test_expect_success
'check tab-in-indent excluded from wildcard whitespace attribute' '
814 git config --unset core.whitespace &&
815 echo "x whitespace" >.gitattributes &&
816 echo " foo ();" >x &&
821 test_expect_success
'line numbers in --check output are correct' '
823 echo "foo(); " >>x &&
824 test_must_fail git diff --check >check &&
828 test_expect_success
'checkdiff detects new trailing blank lines (1)' '
831 test_must_fail git diff --check >check &&
832 grep "new blank line" check
835 test_expect_success
'checkdiff detects new trailing blank lines (2)' '
836 test_write_lines a b "" "" >x &&
838 test_write_lines a "" "" "" "" >x &&
839 test_must_fail git diff --check >check &&
840 grep "new blank line" check
843 test_expect_success
'checkdiff allows new blank lines' '
847 echo "/* This is new */" &&
854 test_expect_success
'whitespace-only changes not reported (diff)' '
856 echo >x "hello world" &&
858 git commit -m "hello 1" &&
859 echo >x "hello world" &&
860 git diff -b >actual &&
861 test_must_be_empty actual
864 test_expect_success
'whitespace-only changes not reported (diffstat)' '
865 # reuse state from previous test
866 git diff --stat -b >actual &&
867 test_must_be_empty actual
870 test_expect_success
'whitespace changes with modification reported (diffstat)' '
872 echo >x "hello world" &&
873 git update-index --chmod=+x x &&
874 git diff --stat --cached -b >actual &&
875 cat <<-EOF >expect &&
877 1 file changed, 0 insertions(+), 0 deletions(-)
879 test_cmp expect actual
882 test_expect_success
'whitespace-only changes reported across renames (diffstat)' '
884 for i in 1 2 3 4 5 6 7 8 9; do echo "$i$i$i$i$i$i" || return 1; done >x &&
886 git commit -m "base" &&
887 sed -e "5s/^/ /" x >z &&
890 git diff -w -M --cached --stat >actual &&
891 cat <<-EOF >expect &&
893 1 file changed, 0 insertions(+), 0 deletions(-)
895 test_cmp expect actual
898 test_expect_success
'whitespace-only changes reported across renames' '
899 git reset --hard HEAD~1 &&
900 for i in 1 2 3 4 5 6 7 8 9; do echo "$i$i$i$i$i$i" || return 1; done >x &&
902 hash_x=$(git hash-object x) &&
903 before=$(git rev-parse --short "$hash_x") &&
904 git commit -m "base" &&
905 sed -e "5s/^/ /" x >z &&
908 hash_z=$(git hash-object z) &&
909 after=$(git rev-parse --short "$hash_z") &&
910 git diff -w -M --cached >actual.raw &&
911 sed -e "/^similarity index /s/[0-9][0-9]*/NUM/" actual.raw >actual &&
912 cat <<-EOF >expect &&
914 similarity index NUM%
917 index $before..$after 100644
919 test_cmp expect actual
923 diff --git a
/empty b
/void
924 similarity index
100%
929 test_expect_success
'rename empty' '
933 git commit -m empty &&
935 git diff -w --cached -M >current &&
936 test_cmp expected current
939 test_expect_success
'combined diff with autocrlf conversion' '
942 test_commit "one side" x hello one-side &&
943 git checkout HEAD^ &&
945 git commit -m "the other side" x &&
946 git config core.autocrlf true &&
947 test_must_fail git merge one-side >actual &&
948 test_grep "Automatic merge failed" actual &&
950 git diff >actual.raw &&
951 sed -e "1,/^@@@/d" actual.raw >actual &&
956 # Start testing the colored format for whitespace checks
958 test_expect_success
'setup diff colors' '
959 git config color.diff.plain normal &&
960 git config color.diff.meta bold &&
961 git config color.diff.frag cyan &&
962 git config color.diff.func normal &&
963 git config color.diff.old red &&
964 git config color.diff.new green &&
965 git config color.diff.commit yellow &&
966 git config color.diff.whitespace blue &&
968 git config core.autocrlf false
971 test_expect_success
'diff that introduces a line with only tabs' '
972 git config core.whitespace blank-at-eol &&
975 old_hash_x=$(git hash-object x) &&
976 before=$(git rev-parse --short "$old_hash_x") &&
977 git commit -m "initial" x &&
978 echo "{NTN}" | tr "NT" "\n\t" >>x &&
979 new_hash_x=$(git hash-object x) &&
980 after=$(git rev-parse --short "$new_hash_x") &&
981 git diff --color >current.raw &&
982 test_decode_color <current.raw >current &&
984 cat >expected <<-EOF &&
985 <BOLD>diff --git a/x b/x<RESET>
986 <BOLD>index $before..$after 100644<RESET>
989 <CYAN>@@ -1 +1,4 @@<RESET>
991 <GREEN>+<RESET><GREEN>{<RESET>
992 <GREEN>+<RESET><BLUE> <RESET>
993 <GREEN>+<RESET><GREEN>}<RESET>
996 test_cmp expected current
999 test_expect_success
'diff that introduces and removes ws breakages' '
1002 echo "0. blank-at-eol " &&
1003 echo "1. blank-at-eol "
1005 old_hash_x=$(git hash-object x) &&
1006 before=$(git rev-parse --short "$old_hash_x") &&
1007 git commit -a --allow-empty -m preimage &&
1009 echo "0. blank-at-eol " &&
1010 echo "1. still-blank-at-eol " &&
1011 echo "2. and a new line "
1013 new_hash_x=$(git hash-object x) &&
1014 after=$(git rev-parse --short "$new_hash_x") &&
1016 git diff --color >current.raw &&
1017 test_decode_color <current.raw >current &&
1019 cat >expected <<-EOF &&
1020 <BOLD>diff --git a/x b/x<RESET>
1021 <BOLD>index $before..$after 100644<RESET>
1022 <BOLD>--- a/x<RESET>
1023 <BOLD>+++ b/x<RESET>
1024 <CYAN>@@ -1,2 +1,3 @@<RESET>
1025 0. blank-at-eol <RESET>
1026 <RED>-1. blank-at-eol <RESET>
1027 <GREEN>+<RESET><GREEN>1. still-blank-at-eol<RESET><BLUE> <RESET>
1028 <GREEN>+<RESET><GREEN>2. and a new line<RESET><BLUE> <RESET>
1031 test_cmp expected current
1034 test_expect_success
'ws-error-highlight test setup' '
1038 echo "0. blank-at-eol " &&
1039 echo "1. blank-at-eol "
1041 old_hash_x=$(git hash-object x) &&
1042 before=$(git rev-parse --short "$old_hash_x") &&
1043 git commit -a --allow-empty -m preimage &&
1045 echo "0. blank-at-eol " &&
1046 echo "1. still-blank-at-eol " &&
1047 echo "2. and a new line "
1049 new_hash_x=$(git hash-object x) &&
1050 after=$(git rev-parse --short "$new_hash_x") &&
1052 cat >expect.default-old <<-EOF &&
1053 <BOLD>diff --git a/x b/x<RESET>
1054 <BOLD>index $before..$after 100644<RESET>
1055 <BOLD>--- a/x<RESET>
1056 <BOLD>+++ b/x<RESET>
1057 <CYAN>@@ -1,2 +1,3 @@<RESET>
1058 0. blank-at-eol <RESET>
1059 <RED>-<RESET><RED>1. blank-at-eol<RESET><BLUE> <RESET>
1060 <GREEN>+<RESET><GREEN>1. still-blank-at-eol<RESET><BLUE> <RESET>
1061 <GREEN>+<RESET><GREEN>2. and a new line<RESET><BLUE> <RESET>
1064 cat >expect.all <<-EOF &&
1065 <BOLD>diff --git a/x b/x<RESET>
1066 <BOLD>index $before..$after 100644<RESET>
1067 <BOLD>--- a/x<RESET>
1068 <BOLD>+++ b/x<RESET>
1069 <CYAN>@@ -1,2 +1,3 @@<RESET>
1070 <RESET>0. blank-at-eol<RESET><BLUE> <RESET>
1071 <RED>-<RESET><RED>1. blank-at-eol<RESET><BLUE> <RESET>
1072 <GREEN>+<RESET><GREEN>1. still-blank-at-eol<RESET><BLUE> <RESET>
1073 <GREEN>+<RESET><GREEN>2. and a new line<RESET><BLUE> <RESET>
1076 cat >expect.none <<-EOF
1077 <BOLD>diff --git a/x b/x<RESET>
1078 <BOLD>index $before..$after 100644<RESET>
1079 <BOLD>--- a/x<RESET>
1080 <BOLD>+++ b/x<RESET>
1081 <CYAN>@@ -1,2 +1,3 @@<RESET>
1082 0. blank-at-eol <RESET>
1083 <RED>-1. blank-at-eol <RESET>
1084 <GREEN>+1. still-blank-at-eol <RESET>
1085 <GREEN>+2. and a new line <RESET>
1090 test_expect_success
'test --ws-error-highlight option' '
1092 git diff --color --ws-error-highlight=default,old >current.raw &&
1093 test_decode_color <current.raw >current &&
1094 test_cmp expect.default-old current &&
1096 git diff --color --ws-error-highlight=all >current.raw &&
1097 test_decode_color <current.raw >current &&
1098 test_cmp expect.all current &&
1100 git diff --color --ws-error-highlight=none >current.raw &&
1101 test_decode_color <current.raw >current &&
1102 test_cmp expect.none current
1106 test_expect_success
'test diff.wsErrorHighlight config' '
1108 git -c diff.wsErrorHighlight=default,old diff --color >current.raw &&
1109 test_decode_color <current.raw >current &&
1110 test_cmp expect.default-old current &&
1112 git -c diff.wsErrorHighlight=all diff --color >current.raw &&
1113 test_decode_color <current.raw >current &&
1114 test_cmp expect.all current &&
1116 git -c diff.wsErrorHighlight=none diff --color >current.raw &&
1117 test_decode_color <current.raw >current &&
1118 test_cmp expect.none current
1122 test_expect_success
'option overrides diff.wsErrorHighlight' '
1124 git -c diff.wsErrorHighlight=none \
1125 diff --color --ws-error-highlight=default,old >current.raw &&
1126 test_decode_color <current.raw >current &&
1127 test_cmp expect.default-old current &&
1129 git -c diff.wsErrorHighlight=default \
1130 diff --color --ws-error-highlight=all >current.raw &&
1131 test_decode_color <current.raw >current &&
1132 test_cmp expect.all current &&
1134 git -c diff.wsErrorHighlight=all \
1135 diff --color --ws-error-highlight=none >current.raw &&
1136 test_decode_color <current.raw >current &&
1137 test_cmp expect.none current
1141 test_expect_success
'detect moved code, complete file' '
1143 cat <<-\EOF >test.c &&
1147 printf("Hello World");
1151 git commit -m "add main function" &&
1152 file=$(git rev-parse --short HEAD:test.c) &&
1153 git mv test.c main.c &&
1154 test_config color.diff.oldMoved "normal red" &&
1155 test_config color.diff.newMoved "normal green" &&
1156 git diff HEAD --color-moved=zebra --color --no-renames >actual.raw &&
1157 test_decode_color <actual.raw >actual &&
1158 cat >expected <<-EOF &&
1159 <BOLD>diff --git a/main.c b/main.c<RESET>
1160 <BOLD>new file mode 100644<RESET>
1161 <BOLD>index 0000000..$file<RESET>
1162 <BOLD>--- /dev/null<RESET>
1163 <BOLD>+++ b/main.c<RESET>
1164 <CYAN>@@ -0,0 +1,5 @@<RESET>
1165 <BGREEN>+<RESET><BGREEN>#include<stdio.h><RESET>
1166 <BGREEN>+<RESET><BGREEN>main()<RESET>
1167 <BGREEN>+<RESET><BGREEN>{<RESET>
1168 <BGREEN>+<RESET><BGREEN>printf("Hello World");<RESET>
1169 <BGREEN>+<RESET><BGREEN>}<RESET>
1170 <BOLD>diff --git a/test.c b/test.c<RESET>
1171 <BOLD>deleted file mode 100644<RESET>
1172 <BOLD>index $file..0000000<RESET>
1173 <BOLD>--- a/test.c<RESET>
1174 <BOLD>+++ /dev/null<RESET>
1175 <CYAN>@@ -1,5 +0,0 @@<RESET>
1176 <BRED>-#include<stdio.h><RESET>
1177 <BRED>-main()<RESET>
1179 <BRED>-printf("Hello World");<RESET>
1183 test_cmp expected actual
1186 test_expect_success
'--color-moved with --no-ext-diff' '
1187 test_config color.diff.oldMoved "yellow" &&
1188 test_config color.diff.newMoved "blue" &&
1189 args="--color --color-moved=zebra --no-renames HEAD" &&
1190 git diff $args >expect &&
1191 git -c diff.external=echo diff --no-ext-diff $args >actual &&
1192 test_cmp expect actual
1195 test_expect_success
'detect malicious moved code, inside file' '
1196 test_config color.diff.oldMoved "normal red" &&
1197 test_config color.diff.newMoved "normal green" &&
1198 test_config color.diff.oldMovedAlternative "blue" &&
1199 test_config color.diff.newMovedAlternative "yellow" &&
1201 cat <<-\EOF >main.c &&
1209 int secure_foo(struct user *u)
1211 if (!u->is_allowed_foo)
1221 cat <<-\EOF >test.c &&
1225 printf("Hello World, but different\n");
1228 int another_function()
1233 git add main.c test.c &&
1234 git commit -m "add main and test file" &&
1235 before_main=$(git rev-parse --short HEAD:main.c) &&
1236 before_test=$(git rev-parse --short HEAD:test.c) &&
1237 cat <<-\EOF >main.c &&
1250 cat <<-\EOF >test.c &&
1254 printf("Hello World, but different\n");
1257 int secure_foo(struct user *u)
1260 if (!u->is_allowed_foo)
1264 int another_function()
1269 hash_main=$(git hash-object main.c) &&
1270 after_main=$(git rev-parse --short "$hash_main") &&
1271 hash_test=$(git hash-object test.c) &&
1272 after_test=$(git rev-parse --short "$hash_test") &&
1273 git diff HEAD --no-renames --color-moved=zebra --color >actual.raw &&
1274 test_decode_color <actual.raw >actual &&
1275 cat <<-EOF >expected &&
1276 <BOLD>diff --git a/main.c b/main.c<RESET>
1277 <BOLD>index $before_main..$after_main 100644<RESET>
1278 <BOLD>--- a/main.c<RESET>
1279 <BOLD>+++ b/main.c<RESET>
1280 <CYAN>@@ -5,13 +5,6 @@<RESET> <RESET>printf("Hello ");<RESET>
1281 printf("World\n");<RESET>
1284 <BRED>-int secure_foo(struct user *u)<RESET>
1286 <BLUE>-if (!u->is_allowed_foo)<RESET>
1287 <BLUE>-return;<RESET>
1288 <RED>-foo(u);<RESET>
1294 <BOLD>diff --git a/test.c b/test.c<RESET>
1295 <BOLD>index $before_test..$after_test 100644<RESET>
1296 <BOLD>--- a/test.c<RESET>
1297 <BOLD>+++ b/test.c<RESET>
1298 <CYAN>@@ -4,6 +4,13 @@<RESET> <RESET>int bar()<RESET>
1299 printf("Hello World, but different\n");<RESET>
1302 <BGREEN>+<RESET><BGREEN>int secure_foo(struct user *u)<RESET>
1303 <BGREEN>+<RESET><BGREEN>{<RESET>
1304 <GREEN>+<RESET><GREEN>foo(u);<RESET>
1305 <BGREEN>+<RESET><BGREEN>if (!u->is_allowed_foo)<RESET>
1306 <BGREEN>+<RESET><BGREEN>return;<RESET>
1307 <GREEN>+<RESET><GREEN>}<RESET>
1309 int another_function()<RESET>
1314 test_cmp expected actual
1317 test_expect_success
'plain moved code, inside file' '
1318 test_config color.diff.oldMoved "normal red" &&
1319 test_config color.diff.newMoved "normal green" &&
1320 test_config color.diff.oldMovedAlternative "blue" &&
1321 test_config color.diff.newMovedAlternative "yellow" &&
1322 # needs previous test as setup
1323 git diff HEAD --no-renames --color-moved=plain --color >actual.raw &&
1324 test_decode_color <actual.raw >actual &&
1325 cat <<-EOF >expected &&
1326 <BOLD>diff --git a/main.c b/main.c<RESET>
1327 <BOLD>index $before_main..$after_main 100644<RESET>
1328 <BOLD>--- a/main.c<RESET>
1329 <BOLD>+++ b/main.c<RESET>
1330 <CYAN>@@ -5,13 +5,6 @@<RESET> <RESET>printf("Hello ");<RESET>
1331 printf("World\n");<RESET>
1334 <BRED>-int secure_foo(struct user *u)<RESET>
1336 <BRED>-if (!u->is_allowed_foo)<RESET>
1337 <BRED>-return;<RESET>
1338 <BRED>-foo(u);<RESET>
1344 <BOLD>diff --git a/test.c b/test.c<RESET>
1345 <BOLD>index $before_test..$after_test 100644<RESET>
1346 <BOLD>--- a/test.c<RESET>
1347 <BOLD>+++ b/test.c<RESET>
1348 <CYAN>@@ -4,6 +4,13 @@<RESET> <RESET>int bar()<RESET>
1349 printf("Hello World, but different\n");<RESET>
1352 <BGREEN>+<RESET><BGREEN>int secure_foo(struct user *u)<RESET>
1353 <BGREEN>+<RESET><BGREEN>{<RESET>
1354 <BGREEN>+<RESET><BGREEN>foo(u);<RESET>
1355 <BGREEN>+<RESET><BGREEN>if (!u->is_allowed_foo)<RESET>
1356 <BGREEN>+<RESET><BGREEN>return;<RESET>
1357 <BGREEN>+<RESET><BGREEN>}<RESET>
1359 int another_function()<RESET>
1364 test_cmp expected actual
1367 test_expect_success
'detect blocks of moved code' '
1369 cat <<-\EOF >lines.txt &&
1387 git add lines.txt &&
1388 git commit -m "add poetry" &&
1389 cat <<-\EOF >lines.txt &&
1407 test_config color.diff.oldMoved "magenta" &&
1408 test_config color.diff.newMoved "cyan" &&
1409 test_config color.diff.oldMovedAlternative "blue" &&
1410 test_config color.diff.newMovedAlternative "yellow" &&
1411 test_config color.diff.oldMovedDimmed "normal magenta" &&
1412 test_config color.diff.newMovedDimmed "normal cyan" &&
1413 test_config color.diff.oldMovedAlternativeDimmed "normal blue" &&
1414 test_config color.diff.newMovedAlternativeDimmed "normal yellow" &&
1415 git diff HEAD --no-renames --color-moved=blocks --color >actual.raw &&
1416 grep -v "index" actual.raw | test_decode_color >actual &&
1417 cat <<-\EOF >expected &&
1418 <BOLD>diff --git a/lines.txt b/lines.txt<RESET>
1419 <BOLD>--- a/lines.txt<RESET>
1420 <BOLD>+++ b/lines.txt<RESET>
1421 <CYAN>@@ -1,16 +1,16 @@<RESET>
1422 <MAGENTA>-long line 1<RESET>
1423 <MAGENTA>-long line 2<RESET>
1424 <MAGENTA>-long line 3<RESET>
1431 <CYAN>+<RESET><CYAN>long line 1<RESET>
1432 <CYAN>+<RESET><CYAN>long line 2<RESET>
1433 <CYAN>+<RESET><CYAN>long line 3<RESET>
1434 <CYAN>+<RESET><CYAN>long line 14<RESET>
1435 <CYAN>+<RESET><CYAN>long line 15<RESET>
1436 <CYAN>+<RESET><CYAN>long line 16<RESET>
1441 <MAGENTA>-long line 14<RESET>
1442 <MAGENTA>-long line 15<RESET>
1443 <MAGENTA>-long line 16<RESET>
1445 test_cmp expected actual
1449 test_expect_success
'detect permutations inside moved code -- dimmed-zebra' '
1450 # reuse setup from test before!
1451 test_config color.diff.oldMoved "magenta" &&
1452 test_config color.diff.newMoved "cyan" &&
1453 test_config color.diff.oldMovedAlternative "blue" &&
1454 test_config color.diff.newMovedAlternative "yellow" &&
1455 test_config color.diff.oldMovedDimmed "normal magenta" &&
1456 test_config color.diff.newMovedDimmed "normal cyan" &&
1457 test_config color.diff.oldMovedAlternativeDimmed "normal blue" &&
1458 test_config color.diff.newMovedAlternativeDimmed "normal yellow" &&
1459 git diff HEAD --no-renames --color-moved=dimmed-zebra --color >actual.raw &&
1460 grep -v "index" actual.raw | test_decode_color >actual &&
1461 cat <<-\EOF >expected &&
1462 <BOLD>diff --git a/lines.txt b/lines.txt<RESET>
1463 <BOLD>--- a/lines.txt<RESET>
1464 <BOLD>+++ b/lines.txt<RESET>
1465 <CYAN>@@ -1,16 +1,16 @@<RESET>
1466 <BMAGENTA>-long line 1<RESET>
1467 <BMAGENTA>-long line 2<RESET>
1468 <BMAGENTA>-long line 3<RESET>
1475 <BCYAN>+<RESET><BCYAN>long line 1<RESET>
1476 <BCYAN>+<RESET><BCYAN>long line 2<RESET>
1477 <CYAN>+<RESET><CYAN>long line 3<RESET>
1478 <YELLOW>+<RESET><YELLOW>long line 14<RESET>
1479 <BYELLOW>+<RESET><BYELLOW>long line 15<RESET>
1480 <BYELLOW>+<RESET><BYELLOW>long line 16<RESET>
1485 <BMAGENTA>-long line 14<RESET>
1486 <BMAGENTA>-long line 15<RESET>
1487 <BMAGENTA>-long line 16<RESET>
1489 test_cmp expected actual
1492 test_expect_success
'zebra alternate color is only used when necessary' '
1493 cat >old.txt <<-\EOF &&
1494 line 1A should be marked as oldMoved newMovedAlternate
1495 line 1B should be marked as oldMoved newMovedAlternate
1497 line 2A should be marked as oldMoved newMovedAlternate
1498 line 2B should be marked as oldMoved newMovedAlternate
1499 line 3A should be marked as oldMovedAlternate newMoved
1500 line 3B should be marked as oldMovedAlternate newMoved
1502 line 4A should be marked as oldMoved newMovedAlternate
1503 line 4B should be marked as oldMoved newMovedAlternate
1504 line 5A should be marked as oldMovedAlternate newMoved
1505 line 5B should be marked as oldMovedAlternate newMoved
1506 line 6A should be marked as oldMoved newMoved
1507 line 6B should be marked as oldMoved newMoved
1509 cat >new.txt <<-\EOF &&
1510 line 1A should be marked as oldMoved newMovedAlternate
1511 line 1B should be marked as oldMoved newMovedAlternate
1513 line 3A should be marked as oldMovedAlternate newMoved
1514 line 3B should be marked as oldMovedAlternate newMoved
1515 line 2A should be marked as oldMoved newMovedAlternate
1516 line 2B should be marked as oldMoved newMovedAlternate
1518 line 6A should be marked as oldMoved newMoved
1519 line 6B should be marked as oldMoved newMoved
1520 line 4A should be marked as oldMoved newMovedAlternate
1521 line 4B should be marked as oldMoved newMovedAlternate
1522 line 5A should be marked as oldMovedAlternate newMoved
1523 line 5B should be marked as oldMovedAlternate newMoved
1525 test_expect_code 1 git diff --no-index --color --color-moved=zebra \
1526 --color-moved-ws=allow-indentation-change \
1527 old.txt new.txt >output &&
1528 grep -v index output | test_decode_color >actual &&
1529 cat >expected <<-\EOF &&
1530 <BOLD>diff --git a/old.txt b/new.txt<RESET>
1531 <BOLD>--- a/old.txt<RESET>
1532 <BOLD>+++ b/new.txt<RESET>
1533 <CYAN>@@ -1,14 +1,14 @@<RESET>
1534 <BOLD;MAGENTA>-line 1A should be marked as oldMoved newMovedAlternate<RESET>
1535 <BOLD;MAGENTA>-line 1B should be marked as oldMoved newMovedAlternate<RESET>
1536 <BOLD;CYAN>+<RESET><BOLD;CYAN> line 1A should be marked as oldMoved newMovedAlternate<RESET>
1537 <BOLD;CYAN>+<RESET><BOLD;CYAN> line 1B should be marked as oldMoved newMovedAlternate<RESET>
1539 <BOLD;MAGENTA>-line 2A should be marked as oldMoved newMovedAlternate<RESET>
1540 <BOLD;MAGENTA>-line 2B should be marked as oldMoved newMovedAlternate<RESET>
1541 <BOLD;BLUE>-line 3A should be marked as oldMovedAlternate newMoved<RESET>
1542 <BOLD;BLUE>-line 3B should be marked as oldMovedAlternate newMoved<RESET>
1543 <BOLD;CYAN>+<RESET><BOLD;CYAN> line 3A should be marked as oldMovedAlternate newMoved<RESET>
1544 <BOLD;CYAN>+<RESET><BOLD;CYAN> line 3B should be marked as oldMovedAlternate newMoved<RESET>
1545 <BOLD;YELLOW>+<RESET><BOLD;YELLOW> line 2A should be marked as oldMoved newMovedAlternate<RESET>
1546 <BOLD;YELLOW>+<RESET><BOLD;YELLOW> line 2B should be marked as oldMoved newMovedAlternate<RESET>
1548 <BOLD;MAGENTA>-line 4A should be marked as oldMoved newMovedAlternate<RESET>
1549 <BOLD;MAGENTA>-line 4B should be marked as oldMoved newMovedAlternate<RESET>
1550 <BOLD;BLUE>-line 5A should be marked as oldMovedAlternate newMoved<RESET>
1551 <BOLD;BLUE>-line 5B should be marked as oldMovedAlternate newMoved<RESET>
1552 <BOLD;MAGENTA>-line 6A should be marked as oldMoved newMoved<RESET>
1553 <BOLD;MAGENTA>-line 6B should be marked as oldMoved newMoved<RESET>
1554 <BOLD;CYAN>+<RESET><BOLD;CYAN> line 6A should be marked as oldMoved newMoved<RESET>
1555 <BOLD;CYAN>+<RESET><BOLD;CYAN> line 6B should be marked as oldMoved newMoved<RESET>
1556 <BOLD;YELLOW>+<RESET><BOLD;YELLOW> line 4A should be marked as oldMoved newMovedAlternate<RESET>
1557 <BOLD;YELLOW>+<RESET><BOLD;YELLOW> line 4B should be marked as oldMoved newMovedAlternate<RESET>
1558 <BOLD;CYAN>+<RESET><BOLD;CYAN> line 5A should be marked as oldMovedAlternate newMoved<RESET>
1559 <BOLD;CYAN>+<RESET><BOLD;CYAN> line 5B should be marked as oldMovedAlternate newMoved<RESET>
1561 test_cmp expected actual
1564 test_expect_success
'short lines of opposite sign do not get marked as moved' '
1565 cat >old.txt <<-\EOF &&
1566 this line should be marked as moved
1572 this line should be marked as oldMoved newMoved
1573 this line should be marked as oldMovedAlternate newMoved
1578 this line should be marked as oldMoved newMoved/newMovedAlternate
1580 cat >new.txt <<-\EOF &&
1584 this line should be marked as moved
1588 this line should be marked as oldMoved newMoved/newMovedAlternate
1591 this line should be marked as oldMovedAlternate newMoved
1592 this line should be marked as oldMoved newMoved/newMovedAlternate
1594 this line should be marked as oldMoved newMoved
1597 test_expect_code 1 git diff --no-index --color --color-moved=zebra \
1598 old.txt new.txt >output && cat output &&
1599 grep -v index output | test_decode_color >actual &&
1600 cat >expect <<-\EOF &&
1601 <BOLD>diff --git a/old.txt b/new.txt<RESET>
1602 <BOLD>--- a/old.txt<RESET>
1603 <BOLD>+++ b/new.txt<RESET>
1604 <CYAN>@@ -1,13 +1,15 @@<RESET>
1605 <BOLD;MAGENTA>-this line should be marked as moved<RESET>
1606 <GREEN>+<RESET><GREEN>too short<RESET>
1609 <BOLD;CYAN>+<RESET><BOLD;CYAN>this line should be marked as moved<RESET>
1610 <GREEN>+<RESET><GREEN>too short<RESET>
1613 <RED>-too short<RESET>
1614 <BOLD;MAGENTA>-this line should be marked as oldMoved newMoved<RESET>
1615 <BOLD;BLUE>-this line should be marked as oldMovedAlternate newMoved<RESET>
1616 <BOLD;CYAN>+<RESET><BOLD;CYAN>this line should be marked as oldMoved newMoved/newMovedAlternate<RESET>
1619 <BOLD;CYAN>+<RESET><BOLD;CYAN>this line should be marked as oldMovedAlternate newMoved<RESET>
1620 <BOLD;YELLOW>+<RESET><BOLD;YELLOW>this line should be marked as oldMoved newMoved/newMovedAlternate<RESET>
1622 <BOLD;CYAN>+<RESET><BOLD;CYAN>this line should be marked as oldMoved newMoved<RESET>
1624 <BOLD;MAGENTA>-this line should be marked as oldMoved newMoved/newMovedAlternate<RESET>
1626 test_cmp expect actual
1629 test_expect_success
'cmd option assumes configured colored-moved' '
1630 test_config color.diff.oldMoved "magenta" &&
1631 test_config color.diff.newMoved "cyan" &&
1632 test_config color.diff.oldMovedAlternative "blue" &&
1633 test_config color.diff.newMovedAlternative "yellow" &&
1634 test_config color.diff.oldMovedDimmed "normal magenta" &&
1635 test_config color.diff.newMovedDimmed "normal cyan" &&
1636 test_config color.diff.oldMovedAlternativeDimmed "normal blue" &&
1637 test_config color.diff.newMovedAlternativeDimmed "normal yellow" &&
1638 test_config diff.colorMoved zebra &&
1639 git diff HEAD --no-renames --color-moved --color >actual.raw &&
1640 grep -v "index" actual.raw | test_decode_color >actual &&
1641 cat <<-\EOF >expected &&
1642 <BOLD>diff --git a/lines.txt b/lines.txt<RESET>
1643 <BOLD>--- a/lines.txt<RESET>
1644 <BOLD>+++ b/lines.txt<RESET>
1645 <CYAN>@@ -1,16 +1,16 @@<RESET>
1646 <MAGENTA>-long line 1<RESET>
1647 <MAGENTA>-long line 2<RESET>
1648 <MAGENTA>-long line 3<RESET>
1655 <CYAN>+<RESET><CYAN>long line 1<RESET>
1656 <CYAN>+<RESET><CYAN>long line 2<RESET>
1657 <CYAN>+<RESET><CYAN>long line 3<RESET>
1658 <YELLOW>+<RESET><YELLOW>long line 14<RESET>
1659 <YELLOW>+<RESET><YELLOW>long line 15<RESET>
1660 <YELLOW>+<RESET><YELLOW>long line 16<RESET>
1665 <MAGENTA>-long line 14<RESET>
1666 <MAGENTA>-long line 15<RESET>
1667 <MAGENTA>-long line 16<RESET>
1669 test_cmp expected actual
1672 test_expect_success
'no effect on diff from --color-moved with --word-diff' '
1673 cat <<-\EOF >text.txt &&
1674 Lorem Ipsum is simply dummy text of the printing and typesetting industry.
1677 git commit -a -m "clean state" &&
1678 cat <<-\EOF >text.txt &&
1679 simply Lorem Ipsum dummy is text of the typesetting and printing industry.
1681 git diff --color-moved --word-diff >actual &&
1682 git diff --word-diff >expect &&
1683 test_cmp expect actual
1686 test_expect_success
'no effect on show from --color-moved with --word-diff' '
1687 git show --color-moved --word-diff >actual &&
1688 git show --word-diff >expect &&
1689 test_cmp expect actual
1692 test_expect_success
'set up whitespace tests' '
1694 # Note that these lines have no leading or trailing whitespace.
1695 cat <<-\EOF >lines.txt &&
1706 git add lines.txt &&
1707 git commit -m "add poetry" &&
1708 git config color.diff.oldMoved "magenta" &&
1709 git config color.diff.newMoved "cyan"
1712 test_expect_success
'move detection ignoring whitespace ' '
1713 q_to_tab <<-\EOF >lines.txt &&
1717 Qchanged long line 9
1724 git diff HEAD --no-renames --color-moved --color >actual.raw &&
1725 grep -v "index" actual.raw | test_decode_color >actual &&
1726 cat <<-\EOF >expected &&
1727 <BOLD>diff --git a/lines.txt b/lines.txt<RESET>
1728 <BOLD>--- a/lines.txt<RESET>
1729 <BOLD>+++ b/lines.txt<RESET>
1730 <CYAN>@@ -1,9 +1,9 @@<RESET>
1731 <GREEN>+<RESET> <GREEN>long line 6<RESET>
1732 <GREEN>+<RESET> <GREEN>long line 7<RESET>
1733 <GREEN>+<RESET> <GREEN>long line 8<RESET>
1734 <GREEN>+<RESET> <GREEN>changed long line 9<RESET>
1740 <RED>-long line 6<RESET>
1741 <RED>-long line 7<RESET>
1742 <RED>-long line 8<RESET>
1743 <RED>-long line 9<RESET>
1745 test_cmp expected actual &&
1747 git diff HEAD --no-renames --color-moved --color \
1748 --color-moved-ws=ignore-all-space >actual.raw &&
1749 grep -v "index" actual.raw | test_decode_color >actual &&
1750 cat <<-\EOF >expected &&
1751 <BOLD>diff --git a/lines.txt b/lines.txt<RESET>
1752 <BOLD>--- a/lines.txt<RESET>
1753 <BOLD>+++ b/lines.txt<RESET>
1754 <CYAN>@@ -1,9 +1,9 @@<RESET>
1755 <CYAN>+<RESET> <CYAN>long line 6<RESET>
1756 <CYAN>+<RESET> <CYAN>long line 7<RESET>
1757 <CYAN>+<RESET> <CYAN>long line 8<RESET>
1758 <GREEN>+<RESET> <GREEN>changed long line 9<RESET>
1764 <MAGENTA>-long line 6<RESET>
1765 <MAGENTA>-long line 7<RESET>
1766 <MAGENTA>-long line 8<RESET>
1767 <RED>-long line 9<RESET>
1769 test_cmp expected actual
1772 test_expect_success
'move detection ignoring whitespace changes' '
1774 # Lines 6-8 have a space change, but 9 is new whitespace
1775 q_to_tab <<-\EOF >lines.txt &&
1787 git diff HEAD --no-renames --color-moved --color >actual.raw &&
1788 grep -v "index" actual.raw | test_decode_color >actual &&
1789 cat <<-\EOF >expected &&
1790 <BOLD>diff --git a/lines.txt b/lines.txt<RESET>
1791 <BOLD>--- a/lines.txt<RESET>
1792 <BOLD>+++ b/lines.txt<RESET>
1793 <CYAN>@@ -1,9 +1,9 @@<RESET>
1794 <GREEN>+<RESET><GREEN>long line 6<RESET>
1795 <GREEN>+<RESET><GREEN>long line 7<RESET>
1796 <GREEN>+<RESET><GREEN>long line 8<RESET>
1797 <GREEN>+<RESET><GREEN>long li ne 9<RESET>
1803 <RED>-long line 6<RESET>
1804 <RED>-long line 7<RESET>
1805 <RED>-long line 8<RESET>
1806 <RED>-long line 9<RESET>
1808 test_cmp expected actual &&
1810 git diff HEAD --no-renames --color-moved --color \
1811 --color-moved-ws=ignore-space-change >actual.raw &&
1812 grep -v "index" actual.raw | test_decode_color >actual &&
1813 cat <<-\EOF >expected &&
1814 <BOLD>diff --git a/lines.txt b/lines.txt<RESET>
1815 <BOLD>--- a/lines.txt<RESET>
1816 <BOLD>+++ b/lines.txt<RESET>
1817 <CYAN>@@ -1,9 +1,9 @@<RESET>
1818 <CYAN>+<RESET><CYAN>long line 6<RESET>
1819 <CYAN>+<RESET><CYAN>long line 7<RESET>
1820 <CYAN>+<RESET><CYAN>long line 8<RESET>
1821 <GREEN>+<RESET><GREEN>long li ne 9<RESET>
1827 <MAGENTA>-long line 6<RESET>
1828 <MAGENTA>-long line 7<RESET>
1829 <MAGENTA>-long line 8<RESET>
1830 <RED>-long line 9<RESET>
1832 test_cmp expected actual
1835 test_expect_success
'move detection ignoring whitespace at eol' '
1837 # Lines 6-9 have new eol whitespace, but 9 also has it in the middle
1838 q_to_tab <<-\EOF >lines.txt &&
1850 # avoid cluttering the output with complaints about our eol whitespace
1851 test_config core.whitespace -blank-at-eol &&
1853 git diff HEAD --no-renames --color-moved --color >actual.raw &&
1854 grep -v "index" actual.raw | test_decode_color >actual &&
1855 cat <<-\EOF >expected &&
1856 <BOLD>diff --git a/lines.txt b/lines.txt<RESET>
1857 <BOLD>--- a/lines.txt<RESET>
1858 <BOLD>+++ b/lines.txt<RESET>
1859 <CYAN>@@ -1,9 +1,9 @@<RESET>
1860 <GREEN>+<RESET><GREEN>long line 6 <RESET>
1861 <GREEN>+<RESET><GREEN>long line 7 <RESET>
1862 <GREEN>+<RESET><GREEN>long line 8 <RESET>
1863 <GREEN>+<RESET><GREEN>long line 9 <RESET>
1869 <RED>-long line 6<RESET>
1870 <RED>-long line 7<RESET>
1871 <RED>-long line 8<RESET>
1872 <RED>-long line 9<RESET>
1874 test_cmp expected actual &&
1876 git diff HEAD --no-renames --color-moved --color \
1877 --color-moved-ws=ignore-space-at-eol >actual.raw &&
1878 grep -v "index" actual.raw | test_decode_color >actual &&
1879 cat <<-\EOF >expected &&
1880 <BOLD>diff --git a/lines.txt b/lines.txt<RESET>
1881 <BOLD>--- a/lines.txt<RESET>
1882 <BOLD>+++ b/lines.txt<RESET>
1883 <CYAN>@@ -1,9 +1,9 @@<RESET>
1884 <CYAN>+<RESET><CYAN>long line 6 <RESET>
1885 <CYAN>+<RESET><CYAN>long line 7 <RESET>
1886 <CYAN>+<RESET><CYAN>long line 8 <RESET>
1887 <GREEN>+<RESET><GREEN>long line 9 <RESET>
1893 <MAGENTA>-long line 6<RESET>
1894 <MAGENTA>-long line 7<RESET>
1895 <MAGENTA>-long line 8<RESET>
1896 <RED>-long line 9<RESET>
1898 test_cmp expected actual
1901 test_expect_success
'clean up whitespace-test colors' '
1902 git config --unset color.diff.oldMoved &&
1903 git config --unset color.diff.newMoved
1906 test_expect_success
'--color-moved block at end of diff output respects MIN_ALNUM_COUNT' '
1923 git diff HEAD --color-moved=zebra --color --no-renames >actual.raw &&
1924 grep -v "index" actual.raw | test_decode_color >actual &&
1925 cat >expected <<-\EOF &&
1926 <BOLD>diff --git a/bar b/bar<RESET>
1927 <BOLD>--- a/bar<RESET>
1928 <BOLD>+++ b/bar<RESET>
1929 <CYAN>@@ -0,0 +1 @@<RESET>
1930 <GREEN>+<RESET><GREEN>line1<RESET>
1931 <BOLD>diff --git a/foo b/foo<RESET>
1932 <BOLD>--- a/foo<RESET>
1933 <BOLD>+++ b/foo<RESET>
1934 <CYAN>@@ -1,2 +1 @@<RESET>
1935 irrelevant_line<RESET>
1939 test_cmp expected actual
1942 test_expect_success
'--color-moved respects MIN_ALNUM_COUNT' '
1945 nineteen chars 456789
1947 twenty chars 234567890
1957 twenty chars 234567890
1958 nineteen chars 456789
1961 git diff HEAD --color-moved=zebra --color --no-renames >actual.raw &&
1962 grep -v "index" actual.raw | test_decode_color >actual &&
1963 cat >expected <<-\EOF &&
1964 <BOLD>diff --git a/bar b/bar<RESET>
1965 <BOLD>--- a/bar<RESET>
1966 <BOLD>+++ b/bar<RESET>
1967 <CYAN>@@ -0,0 +1,2 @@<RESET>
1968 <BOLD;CYAN>+<RESET><BOLD;CYAN>twenty chars 234567890<RESET>
1969 <GREEN>+<RESET><GREEN>nineteen chars 456789<RESET>
1970 <BOLD>diff --git a/foo b/foo<RESET>
1971 <BOLD>--- a/foo<RESET>
1972 <BOLD>+++ b/foo<RESET>
1973 <CYAN>@@ -1,3 +1 @@<RESET>
1974 <RED>-nineteen chars 456789<RESET>
1975 irrelevant_line<RESET>
1976 <BOLD;MAGENTA>-twenty chars 234567890<RESET>
1979 test_cmp expected actual
1982 test_expect_success
'--color-moved treats adjacent blocks as separate for MIN_ALNUM_COUNT' '
2003 git diff HEAD --color-moved=zebra --color --no-renames >actual.raw &&
2004 grep -v "index" actual.raw | test_decode_color >actual &&
2005 cat >expected <<-\EOF &&
2006 <BOLD>diff --git a/bar b/bar<RESET>
2007 <BOLD>--- a/bar<RESET>
2008 <BOLD>+++ b/bar<RESET>
2009 <CYAN>@@ -0,0 +1,3 @@<RESET>
2010 <GREEN>+<RESET><GREEN>7charsB<RESET>
2011 <GREEN>+<RESET><GREEN>7charsC<RESET>
2012 <GREEN>+<RESET><GREEN>7charsA<RESET>
2013 <BOLD>diff --git a/foo b/foo<RESET>
2014 <BOLD>--- a/foo<RESET>
2015 <BOLD>+++ b/foo<RESET>
2016 <CYAN>@@ -1,4 +1 @@<RESET>
2017 <RED>-7charsA<RESET>
2018 irrelevant_line<RESET>
2019 <RED>-7charsB<RESET>
2020 <RED>-7charsC<RESET>
2023 test_cmp expected actual
2026 test_expect_success
'--color-moved rewinds for MIN_ALNUM_COUNT' '
2028 test_write_lines >file \
2029 A B C one two three four five six seven D E F G H I J &&
2031 test_write_lines >file \
2032 one two A B C D E F G H I J two three four five six seven &&
2033 git diff --color-moved=zebra -- file &&
2035 git diff --color-moved=zebra --color -- file >actual.raw &&
2036 grep -v "index" actual.raw | test_decode_color >actual &&
2037 cat >expected <<-\EOF &&
2038 <BOLD>diff --git a/file b/file<RESET>
2039 <BOLD>--- a/file<RESET>
2040 <BOLD>+++ b/file<RESET>
2041 <CYAN>@@ -1,13 +1,8 @@<RESET>
2042 <GREEN>+<RESET><GREEN>one<RESET>
2043 <GREEN>+<RESET><GREEN>two<RESET>
2048 <BOLD;MAGENTA>-two<RESET>
2049 <BOLD;MAGENTA>-three<RESET>
2050 <BOLD;MAGENTA>-four<RESET>
2051 <BOLD;MAGENTA>-five<RESET>
2052 <BOLD;MAGENTA>-six<RESET>
2053 <BOLD;MAGENTA>-seven<RESET>
2057 <CYAN>@@ -15,3 +10,9 @@<RESET> <RESET>G<RESET>
2061 <BOLD;CYAN>+<RESET><BOLD;CYAN>two<RESET>
2062 <BOLD;CYAN>+<RESET><BOLD;CYAN>three<RESET>
2063 <BOLD;CYAN>+<RESET><BOLD;CYAN>four<RESET>
2064 <BOLD;CYAN>+<RESET><BOLD;CYAN>five<RESET>
2065 <BOLD;CYAN>+<RESET><BOLD;CYAN>six<RESET>
2066 <BOLD;CYAN>+<RESET><BOLD;CYAN>seven<RESET>
2069 test_cmp expected actual
2072 test_expect_success
'move detection with submodules' '
2073 test_create_repo bananas &&
2074 echo ripe >bananas/recipe &&
2075 git -C bananas add recipe &&
2076 test_commit fruit &&
2077 test_commit -C bananas recipe &&
2078 git submodule add ./bananas &&
2080 git commit -a -m "bananas are like a heavy library?" &&
2081 echo foul >bananas/recipe &&
2082 echo ripe >fruit.t &&
2084 git diff --submodule=diff --color-moved --color >actual &&
2086 # no move detection as the moved line is across repository boundaries.
2087 test_decode_color <actual >decoded_actual &&
2088 ! grep BGREEN decoded_actual &&
2089 ! grep BRED decoded_actual &&
2091 # nor did we mess with it another way
2092 git diff --submodule=diff --color >expect.raw &&
2093 test_decode_color <expect.raw >expect &&
2094 test_cmp expect decoded_actual &&
2096 git submodule deinit bananas
2099 test_expect_success
'only move detection ignores white spaces' '
2101 q_to_tab <<-\EOF >text.txt &&
2102 a long line to exceed per-line minimum
2103 another long line to exceed per-line minimum
2107 git commit -m "add text" &&
2108 q_to_tab <<-\EOF >text.txt &&
2109 Qa long line to exceed per-line minimum
2110 Qanother long line to exceed per-line minimum
2114 # Make sure we get a different diff using -w
2115 git diff --color --color-moved -w >actual.raw &&
2116 grep -v "index" actual.raw | test_decode_color >actual &&
2117 q_to_tab <<-\EOF >expected &&
2118 <BOLD>diff --git a/text.txt b/text.txt<RESET>
2119 <BOLD>--- a/text.txt<RESET>
2120 <BOLD>+++ b/text.txt<RESET>
2121 <CYAN>@@ -1,3 +1,3 @@<RESET>
2122 Qa long line to exceed per-line minimum<RESET>
2123 Qanother long line to exceed per-line minimum<RESET>
2124 <RED>-original file<RESET>
2125 <GREEN>+<RESET><GREEN>new file<RESET>
2127 test_cmp expected actual &&
2129 # And now ignoring white space only in the move detection
2130 git diff --color --color-moved \
2131 --color-moved-ws=ignore-all-space,ignore-space-change,ignore-space-at-eol >actual.raw &&
2132 grep -v "index" actual.raw | test_decode_color >actual &&
2133 q_to_tab <<-\EOF >expected &&
2134 <BOLD>diff --git a/text.txt b/text.txt<RESET>
2135 <BOLD>--- a/text.txt<RESET>
2136 <BOLD>+++ b/text.txt<RESET>
2137 <CYAN>@@ -1,3 +1,3 @@<RESET>
2138 <BOLD;MAGENTA>-a long line to exceed per-line minimum<RESET>
2139 <BOLD;MAGENTA>-another long line to exceed per-line minimum<RESET>
2140 <RED>-original file<RESET>
2141 <BOLD;CYAN>+<RESET>Q<BOLD;CYAN>a long line to exceed per-line minimum<RESET>
2142 <BOLD;CYAN>+<RESET>Q<BOLD;CYAN>another long line to exceed per-line minimum<RESET>
2143 <GREEN>+<RESET><GREEN>new file<RESET>
2145 test_cmp expected actual
2148 test_expect_success
'compare whitespace delta across moved blocks' '
2151 q_to_tab <<-\EOF >text.txt &&
2155 QBut! <- this stands out
2157 QQdifferent starting
2163 QQQthat has similar lines
2164 QQQto previous blocks, but with different indent
2165 QQQYetQAnotherQoutlierQ
2166 QLine with internal w h i t e s p a c e change
2170 git commit -m "add text.txt" &&
2172 q_to_tab <<-\EOF >text.txt &&
2176 QQQBut! <- this stands out
2184 QQthat has similar lines
2185 QQto previous blocks, but with different indent
2186 QQYetQAnotherQoutlier
2187 QLine with internal whitespace change
2190 git diff --color --color-moved --color-moved-ws=allow-indentation-change >actual.raw &&
2191 grep -v "index" actual.raw | test_decode_color >actual &&
2193 q_to_tab <<-\EOF >expected &&
2194 <BOLD>diff --git a/text.txt b/text.txt<RESET>
2195 <BOLD>--- a/text.txt<RESET>
2196 <BOLD>+++ b/text.txt<RESET>
2197 <CYAN>@@ -1,15 +1,15 @@<RESET>
2198 <BOLD;MAGENTA>-QIndented<RESET>
2199 <BOLD;MAGENTA>-QText across<RESET>
2200 <BOLD;MAGENTA>-Qsome lines<RESET>
2201 <RED>-QBut! <- this stands out<RESET>
2202 <BOLD;MAGENTA>-QAdjusting with<RESET>
2203 <BOLD;MAGENTA>-QQdifferent starting<RESET>
2204 <BOLD;MAGENTA>-Qwhite spaces<RESET>
2205 <RED>-QAnother outlier<RESET>
2206 <BOLD;MAGENTA>-QQQIndented<RESET>
2207 <BOLD;MAGENTA>-QQQText across<RESET>
2208 <BOLD;MAGENTA>-QQQfive lines<RESET>
2209 <BOLD;MAGENTA>-QQQthat has similar lines<RESET>
2210 <BOLD;MAGENTA>-QQQto previous blocks, but with different indent<RESET>
2211 <RED>-QQQYetQAnotherQoutlierQ<RESET>
2212 <RED>-QLine with internal w h i t e s p a c e change<RESET>
2213 <BOLD;CYAN>+<RESET>QQ<BOLD;CYAN>Indented<RESET>
2214 <BOLD;CYAN>+<RESET>QQ<BOLD;CYAN>Text across<RESET>
2215 <BOLD;CYAN>+<RESET>QQ<BOLD;CYAN>some lines<RESET>
2216 <GREEN>+<RESET>QQQ<GREEN>But! <- this stands out<RESET>
2217 <BOLD;CYAN>+<RESET><BOLD;CYAN>Adjusting with<RESET>
2218 <BOLD;CYAN>+<RESET>Q<BOLD;CYAN>different starting<RESET>
2219 <BOLD;CYAN>+<RESET><BOLD;CYAN>white spaces<RESET>
2220 <GREEN>+<RESET><GREEN>AnotherQoutlier<RESET>
2221 <BOLD;CYAN>+<RESET>QQ<BOLD;CYAN>Indented<RESET>
2222 <BOLD;CYAN>+<RESET>QQ<BOLD;CYAN>Text across<RESET>
2223 <BOLD;CYAN>+<RESET>QQ<BOLD;CYAN>five lines<RESET>
2224 <BOLD;CYAN>+<RESET>QQ<BOLD;CYAN>that has similar lines<RESET>
2225 <BOLD;CYAN>+<RESET>QQ<BOLD;CYAN>to previous blocks, but with different indent<RESET>
2226 <GREEN>+<RESET>QQ<GREEN>YetQAnotherQoutlier<RESET>
2227 <GREEN>+<RESET>Q<GREEN>Line with internal whitespace change<RESET>
2230 test_cmp expected actual
2233 test_expect_success
'bogus settings in move detection erroring out' '
2234 test_must_fail git diff --color-moved=bogus 2>err &&
2235 test_grep "must be one of" err &&
2236 test_grep bogus err &&
2238 test_must_fail git -c diff.colormoved=bogus diff 2>err &&
2239 test_grep "must be one of" err &&
2240 test_grep "from command-line config" err &&
2242 test_must_fail git diff --color-moved-ws=bogus 2>err &&
2243 test_grep "possible values" err &&
2244 test_grep bogus err &&
2246 test_must_fail git -c diff.colormovedws=bogus diff 2>err &&
2247 test_grep "possible values" err &&
2248 test_grep "from command-line config" err
2251 test_expect_success
'compare whitespace delta incompatible with other space options' '
2252 test_must_fail git diff \
2253 --color-moved-ws=allow-indentation-change,ignore-all-space \
2255 test_grep allow-indentation-change err
2259 test_expect_success
'compare mixed whitespace delta across moved blocks' '
2262 tr "^|Q_" "\f\v\t " <<-EOF >text.txt &&
2264 |____too short without
2266 ___being grouped across blank line
2272 ____Indented text to
2273 _Q____be further indented by four spaces across
2275 QQ____These two lines have had their
2276 ____indentation reduced by four spaces
2277 Qdifferent indentation change
2282 git commit -m "add text.txt" &&
2284 tr "^|Q_" "\f\v\t " <<-EOF >text.txt &&
2290 QQbe further indented by four spaces across
2295 ^Q_______being grouped across blank line
2297 Q_QThese two lines have had their
2298 indentation reduced by four spaces
2299 QQdifferent indentation change
2303 git -c color.diff.whitespace="normal red" \
2304 -c core.whitespace=space-before-tab \
2305 diff --color --color-moved --ws-error-highlight=all \
2306 --color-moved-ws=allow-indentation-change >actual.raw &&
2307 grep -v "index" actual.raw | tr "\f\v" "^|" | test_decode_color >actual &&
2309 cat <<-\EOF >expected &&
2310 <BOLD>diff --git a/text.txt b/text.txt<RESET>
2311 <BOLD>--- a/text.txt<RESET>
2312 <BOLD>+++ b/text.txt<RESET>
2313 <CYAN>@@ -1,16 +1,16 @@<RESET>
2314 <BOLD;MAGENTA>-<RESET><BOLD;MAGENTA>^<RESET><BRED> <RESET>
2315 <BOLD;MAGENTA>-<RESET><BOLD;MAGENTA>| too short without<RESET>
2316 <BOLD;MAGENTA>-<RESET><BOLD;MAGENTA>^<RESET>
2317 <BOLD;MAGENTA>-<RESET><BOLD;MAGENTA> being grouped across blank line<RESET>
2318 <BOLD;MAGENTA>-<RESET>
2319 <RESET>context<RESET>
2322 <RESET>anchor<RESET>
2323 <BOLD;MAGENTA>-<RESET><BOLD;MAGENTA> Indented text to<RESET>
2324 <BOLD;MAGENTA>-<RESET><BRED> <RESET> <BOLD;MAGENTA> be further indented by four spaces across<RESET>
2325 <BOLD;MAGENTA>-<RESET><BRED> <RESET> <BOLD;MAGENTA>several lines<RESET>
2326 <BOLD;BLUE>-<RESET> <BOLD;BLUE> These two lines have had their<RESET>
2327 <BOLD;BLUE>-<RESET><BOLD;BLUE> indentation reduced by four spaces<RESET>
2328 <BOLD;MAGENTA>-<RESET> <BOLD;MAGENTA>different indentation change<RESET>
2329 <RED>-<RESET><RED> too short<RESET>
2330 <BOLD;CYAN>+<RESET> <BOLD;CYAN>Indented text to<RESET>
2331 <BOLD;CYAN>+<RESET> <BOLD;CYAN>be further indented by four spaces across<RESET>
2332 <BOLD;CYAN>+<RESET> <BOLD;CYAN> several lines<RESET>
2333 <BOLD;YELLOW>+<RESET>
2334 <BOLD;YELLOW>+<RESET> <BOLD;YELLOW>too short without<RESET>
2335 <BOLD;YELLOW>+<RESET>
2336 <BOLD;YELLOW>+<RESET><BOLD;YELLOW>^ being grouped across blank line<RESET>
2337 <BOLD;YELLOW>+<RESET>
2338 <BOLD;CYAN>+<RESET> <BRED> <RESET> <BOLD;CYAN>These two lines have had their<RESET>
2339 <BOLD;CYAN>+<RESET><BOLD;CYAN>indentation reduced by four spaces<RESET>
2340 <BOLD;YELLOW>+<RESET> <BOLD;YELLOW>different indentation change<RESET>
2341 <GREEN>+<RESET><BRED> <RESET> <GREEN>too short<RESET>
2344 test_cmp expected actual
2347 test_expect_success
'combine --ignore-blank-lines with --function-context' '
2348 test_write_lines 1 "" 2 3 4 5 >a &&
2349 test_write_lines 1 2 3 4 >b &&
2350 test_must_fail git diff --no-index \
2351 --ignore-blank-lines --function-context a b >actual.raw &&
2352 sed -n "/@@/,\$p" <actual.raw >actual &&
2353 cat <<-\EOF >expect &&
2362 test_cmp expect actual
2365 test_expect_success
'combine --ignore-blank-lines with --function-context 2' '
2366 test_write_lines a b c "" function 1 2 3 4 5 "" 6 7 8 9 >a &&
2367 test_write_lines "" a b c "" function 1 2 3 4 5 6 7 8 >b &&
2368 test_must_fail git diff --no-index \
2369 --ignore-blank-lines --function-context a b >actual.raw &&
2370 sed -n "/@@/,\$p" <actual.raw >actual &&
2371 cat <<-\EOF >expect &&
2385 test_cmp expect actual