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 opt_res
in --patch --quiet -s --stat --shortstat --dirstat=lines \
15 --raw! --name-only! --name-status!
17 opts
=${opt_res%!} expect_failure
=
18 test "$opts" = "$opt_res" ||
19 expect_failure
="test_expect_code 1"
21 test_expect_success
"status with $opts (different)" '
25 test_expect_code 1 git diff -w $opts --exit-code x
28 test_expect_success POSIXPERM
"status with $opts (mode differs)" '
29 test_when_finished "git update-index --chmod=-x x" &&
32 git update-index --chmod=+x x &&
33 test_expect_code 1 git diff -w $opts --exit-code x
36 test_expect_success
"status with $opts (removing an empty file)" '
40 test_expect_code 1 git diff -w $opts --exit-code -- x
43 test_expect_success
"status with $opts (different but equivalent)" '
47 $expect_failure git diff -w $opts --exit-code x
51 test_expect_success
"Ray Lehtiniemi's example" '
57 git update-index --add x &&
58 old_hash_x=$(git hash-object x) &&
59 before=$(git rev-parse --short "$old_hash_x") &&
68 new_hash_x=$(git hash-object x) &&
69 after=$(git rev-parse --short "$new_hash_x") &&
73 index $before..$after 100644
87 test_cmp expect out &&
90 test_cmp expect out &&
96 test_expect_success
'another test, without options' '
97 tr Q "\015" <<-\EOF >x &&
98 whitespace at beginning
100 whitespace in the middle
106 git update-index x &&
107 old_hash_x=$(git hash-object x) &&
108 before=$(git rev-parse --short "$old_hash_x") &&
110 tr "_" " " <<-\EOF >x &&
111 _ whitespace at beginning
113 white space in the middle
118 new_hash_x=$(git hash-object x) &&
119 after=$(git rev-parse --short "$new_hash_x") &&
121 tr "Q_" "\015 " <<-EOF >expect &&
123 index $before..$after 100644
127 -whitespace at beginning
129 -whitespace in the middle
131 + whitespace at beginning
133 +white space in the middle
141 test_cmp expect out &&
144 test_must_be_empty out &&
146 git diff -w -b >out &&
147 test_must_be_empty out &&
149 git diff -w --ignore-space-at-eol >out &&
150 test_must_be_empty out &&
152 git diff -w -b --ignore-space-at-eol >out &&
153 test_must_be_empty out &&
155 git diff -w --ignore-cr-at-eol >out &&
156 test_must_be_empty out &&
158 tr "Q_" "\015 " <<-EOF >expect &&
160 index $before..$after 100644
164 -whitespace at beginning
165 +_ whitespace at beginning
167 -whitespace in the middle
168 +white space in the middle
174 test_cmp expect out &&
176 git diff -b --ignore-space-at-eol >out &&
177 test_cmp expect out &&
179 git diff -b --ignore-cr-at-eol >out &&
180 test_cmp expect out &&
182 tr "Q_" "\015 " <<-EOF >expect &&
184 index $before..$after 100644
188 -whitespace at beginning
190 -whitespace in the middle
191 +_ whitespace at beginning
193 +white space in the middle
198 git diff --ignore-space-at-eol >out &&
199 test_cmp expect out &&
201 git diff --ignore-space-at-eol --ignore-cr-at-eol >out &&
202 test_cmp expect out &&
204 tr "Q_" "\015 " <<-EOF >expect &&
206 index_$before..$after 100644
210 -whitespace at beginning
212 -whitespace in the middle
214 +_ whitespace at beginning
216 +white space in the middle
221 git diff --ignore-cr-at-eol >out &&
225 test_expect_success
'ignore-blank-lines: only new lines' '
227 git update-index x &&
228 test_seq 5 | sed "/3/i\\
230 git diff --ignore-blank-lines >out &&
231 test_must_be_empty out
234 test_expect_success
'ignore-blank-lines: only new lines with space' '
236 git update-index x &&
237 test_seq 5 | sed "/3/i\\
239 git diff -w --ignore-blank-lines >out &&
240 test_must_be_empty out
243 test_expect_success
'ignore-blank-lines: after change' '
255 git update-index x &&
268 git diff --inter-hunk-context=100 --ignore-blank-lines >out.tmp &&
269 cat <<-\EOF >expected &&
283 compare_diff_patch expected out.tmp
286 test_expect_success
'ignore-blank-lines: before change' '
297 git update-index x &&
310 git diff --inter-hunk-context=100 --ignore-blank-lines >out.tmp &&
311 cat <<-\EOF >expected &&
324 compare_diff_patch expected out.tmp
327 test_expect_success
'ignore-blank-lines: between changes' '
342 git update-index x &&
359 git diff --ignore-blank-lines >out.tmp &&
360 cat <<-\EOF >expected &&
381 compare_diff_patch expected out.tmp
384 test_expect_success
'ignore-blank-lines: between changes (with interhunkctx)' '
386 git update-index x &&
404 git diff --inter-hunk-context=2 --ignore-blank-lines >out.tmp &&
405 cat <<-\EOF >expected &&
426 compare_diff_patch expected out.tmp
429 test_expect_success
'ignore-blank-lines: scattered spaces' '
431 git update-index x &&
452 git diff --inter-hunk-context=4 --ignore-blank-lines >out.tmp &&
453 cat <<-\EOF >expected &&
468 compare_diff_patch expected out.tmp
471 test_expect_success
'ignore-blank-lines: spaces coalesce' '
473 git update-index x &&
487 git diff --inter-hunk-context=4 --ignore-blank-lines >out.tmp &&
488 cat <<-\EOF >expected &&
505 compare_diff_patch expected out.tmp
508 test_expect_success
'ignore-blank-lines: mix changes and blank lines' '
510 git update-index x &&
536 git diff --ignore-blank-lines >out.tmp &&
537 cat <<-\EOF >expected &&
566 compare_diff_patch expected out.tmp
569 test_expect_success
'check mixed spaces and tabs in indent' '
570 # This is indented with SP HT SP.
572 test_must_fail git diff --check >check &&
573 grep "space before tab in indent" check
576 test_expect_success
'check mixed tabs and spaces in indent' '
577 # This is indented with HT SP HT.
579 test_must_fail git diff --check >check &&
580 grep "space before tab in indent" check
583 test_expect_success
'check with no whitespace errors' '
584 git commit -m "snapshot" &&
589 test_expect_success
'check with trailing whitespace' '
591 test_must_fail git diff --check
594 test_expect_success
'check with space before tab in indent' '
595 # indent has space followed by hard tab
597 test_must_fail git diff --check
600 test_expect_success
'--check and --exit-code are not exclusive' '
602 git diff --check --exit-code
605 test_expect_success
'--check and --quiet are not exclusive' '
606 git diff --check --quiet
609 test_expect_success
'-w and --exit-code interact sensibly' '
610 test_when_finished "git checkout x" &&
615 test_must_fail git diff --exit-code &&
616 git diff -w >actual &&
617 test_must_be_empty actual &&
618 git diff -w --exit-code
621 test_expect_success
'-I and --exit-code interact sensibly' '
622 test_when_finished "git checkout x" &&
627 test_must_fail git diff --exit-code &&
628 git diff -I. >actual &&
629 test_must_be_empty actual &&
630 git diff -I. --exit-code
633 test_expect_success
'check staged with no whitespace errors' '
636 git diff --cached --check
639 test_expect_success
'check staged with trailing whitespace' '
642 test_must_fail git diff --cached --check
645 test_expect_success
'check staged with space before tab in indent' '
646 # indent has space followed by hard tab
649 test_must_fail git diff --cached --check
652 test_expect_success
'check with no whitespace errors (diff-index)' '
655 git diff-index --check HEAD
658 test_expect_success
'check with trailing whitespace (diff-index)' '
661 test_must_fail git diff-index --check HEAD
664 test_expect_success
'check with space before tab in indent (diff-index)' '
665 # indent has space followed by hard tab
668 test_must_fail git diff-index --check HEAD
671 test_expect_success
'check staged with no whitespace errors (diff-index)' '
674 git diff-index --cached --check HEAD
677 test_expect_success
'check staged with trailing whitespace (diff-index)' '
680 test_must_fail git diff-index --cached --check HEAD
683 test_expect_success
'check staged with space before tab in indent (diff-index)' '
684 # indent has space followed by hard tab
687 test_must_fail git diff-index --cached --check HEAD
690 test_expect_success
'check with no whitespace errors (diff-tree)' '
692 git commit -m "new commit" x &&
693 git diff-tree --check HEAD^ HEAD
696 test_expect_success
'check with trailing whitespace (diff-tree)' '
698 git commit -m "another commit" x &&
699 test_must_fail git diff-tree --check HEAD^ HEAD
702 test_expect_success
'check with space before tab in indent (diff-tree)' '
703 # indent has space followed by hard tab
705 git commit -m "yet another" x &&
706 test_must_fail git diff-tree --check HEAD^ HEAD
709 test_expect_success
'check with ignored trailing whitespace attr (diff-tree)' '
710 test_when_finished "git reset --hard HEAD^" &&
712 # create a whitespace error that should be ignored
713 echo "* -whitespace" >.gitattributes &&
714 git add .gitattributes &&
717 git commit -m "add trailing space" &&
719 # with a worktree diff-tree ignores the whitespace error
720 git diff-tree --root --check HEAD &&
722 # without a worktree diff-tree still ignores the whitespace error
723 git -C .git diff-tree --root --check HEAD
726 test_expect_success
'check trailing whitespace (trailing-space: off)' '
727 git config core.whitespace "-trailing-space" &&
728 echo "foo (); " >x &&
732 test_expect_success
'check trailing whitespace (trailing-space: on)' '
733 git config core.whitespace "trailing-space" &&
734 echo "foo (); " >x &&
735 test_must_fail git diff --check
738 test_expect_success
'check space before tab in indent (space-before-tab: off)' '
739 # indent contains space followed by HT
740 git config core.whitespace "-space-before-tab" &&
741 echo " foo ();" >x &&
745 test_expect_success
'check space before tab in indent (space-before-tab: on)' '
746 # indent contains space followed by HT
747 git config core.whitespace "space-before-tab" &&
748 echo " foo (); " >x &&
749 test_must_fail git diff --check
752 test_expect_success
'check spaces as indentation (indent-with-non-tab: off)' '
753 git config core.whitespace "-indent-with-non-tab" &&
754 echo " foo ();" >x &&
758 test_expect_success
'check spaces as indentation (indent-with-non-tab: on)' '
759 git config core.whitespace "indent-with-non-tab" &&
760 echo " foo ();" >x &&
761 test_must_fail git diff --check
764 test_expect_success
'ditto, but tabwidth=9' '
765 git config core.whitespace "indent-with-non-tab,tabwidth=9" &&
769 test_expect_success
'check tabs and spaces as indentation (indent-with-non-tab: on)' '
770 git config core.whitespace "indent-with-non-tab" &&
771 echo " foo ();" >x &&
772 test_must_fail git diff --check
775 test_expect_success
'ditto, but tabwidth=10' '
776 git config core.whitespace "indent-with-non-tab,tabwidth=10" &&
777 test_must_fail git diff --check
780 test_expect_success
'ditto, but tabwidth=20' '
781 git config core.whitespace "indent-with-non-tab,tabwidth=20" &&
785 test_expect_success
'check tabs as indentation (tab-in-indent: off)' '
786 git config core.whitespace "-tab-in-indent" &&
787 echo " foo ();" >x &&
791 test_expect_success
'check tabs as indentation (tab-in-indent: on)' '
792 git config core.whitespace "tab-in-indent" &&
793 echo " foo ();" >x &&
794 test_must_fail git diff --check
797 test_expect_success
'check tabs and spaces as indentation (tab-in-indent: on)' '
798 git config core.whitespace "tab-in-indent" &&
799 echo " foo ();" >x &&
800 test_must_fail git diff --check
803 test_expect_success
'ditto, but tabwidth=1 (must be irrelevant)' '
804 git config core.whitespace "tab-in-indent,tabwidth=1" &&
805 test_must_fail git diff --check
808 test_expect_success
'check tab-in-indent and indent-with-non-tab conflict' '
809 git config core.whitespace "tab-in-indent,indent-with-non-tab" &&
811 test_must_fail git diff --check
814 test_expect_success
'check tab-in-indent excluded from wildcard whitespace attribute' '
815 git config --unset core.whitespace &&
816 echo "x whitespace" >.gitattributes &&
817 echo " foo ();" >x &&
822 test_expect_success
'line numbers in --check output are correct' '
824 echo "foo(); " >>x &&
825 test_must_fail git diff --check >check &&
829 test_expect_success
'checkdiff detects new trailing blank lines (1)' '
832 test_must_fail git diff --check >check &&
833 grep "new blank line" check
836 test_expect_success
'checkdiff detects new trailing blank lines (2)' '
837 test_write_lines a b "" "" >x &&
839 test_write_lines a "" "" "" "" >x &&
840 test_must_fail git diff --check >check &&
841 grep "new blank line" check
844 test_expect_success
'checkdiff allows new blank lines' '
848 echo "/* This is new */" &&
855 test_expect_success
'whitespace-only changes not reported (diff)' '
857 echo >x "hello world" &&
859 git commit -m "hello 1" &&
860 echo >x "hello world" &&
861 git diff -b >actual &&
862 test_must_be_empty actual
865 test_expect_success
'whitespace-only changes not reported (diffstat)' '
866 # reuse state from previous test
867 git diff --stat -b >actual &&
868 test_must_be_empty actual
871 test_expect_success
'whitespace changes with modification reported (diffstat)' '
873 echo >x "hello world" &&
874 git update-index --chmod=+x x &&
875 git diff --stat --cached -b >actual &&
876 cat <<-EOF >expect &&
878 1 file changed, 0 insertions(+), 0 deletions(-)
880 test_cmp expect actual
883 test_expect_success
'whitespace-only changes reported across renames (diffstat)' '
885 for i in 1 2 3 4 5 6 7 8 9; do echo "$i$i$i$i$i$i" || return 1; done >x &&
887 git commit -m "base" &&
888 sed -e "5s/^/ /" x >z &&
891 git diff -w -M --cached --stat >actual &&
892 cat <<-EOF >expect &&
894 1 file changed, 0 insertions(+), 0 deletions(-)
896 test_cmp expect actual
899 test_expect_success
'whitespace-only changes reported across renames' '
900 git reset --hard HEAD~1 &&
901 for i in 1 2 3 4 5 6 7 8 9; do echo "$i$i$i$i$i$i" || return 1; done >x &&
903 hash_x=$(git hash-object x) &&
904 before=$(git rev-parse --short "$hash_x") &&
905 git commit -m "base" &&
906 sed -e "5s/^/ /" x >z &&
909 hash_z=$(git hash-object z) &&
910 after=$(git rev-parse --short "$hash_z") &&
911 git diff -w -M --cached >actual.raw &&
912 sed -e "/^similarity index /s/[0-9][0-9]*/NUM/" actual.raw >actual &&
913 cat <<-EOF >expect &&
915 similarity index NUM%
918 index $before..$after 100644
920 test_cmp expect actual
924 diff --git a
/empty b
/void
925 similarity index
100%
930 test_expect_success
'rename empty' '
934 git commit -m empty &&
936 git diff -w --cached -M >current &&
937 test_cmp expected current
940 test_expect_success
'combined diff with autocrlf conversion' '
943 test_commit "one side" x hello one-side &&
944 git checkout HEAD^ &&
946 git commit -m "the other side" x &&
947 git config core.autocrlf true &&
948 test_must_fail git merge one-side >actual &&
949 test_grep "Automatic merge failed" actual &&
951 git diff >actual.raw &&
952 sed -e "1,/^@@@/d" actual.raw >actual &&
957 # Start testing the colored format for whitespace checks
959 test_expect_success
'setup diff colors' '
960 git config color.diff.plain normal &&
961 git config color.diff.meta bold &&
962 git config color.diff.frag cyan &&
963 git config color.diff.func normal &&
964 git config color.diff.old red &&
965 git config color.diff.new green &&
966 git config color.diff.commit yellow &&
967 git config color.diff.whitespace blue &&
969 git config core.autocrlf false
972 test_expect_success
'diff that introduces a line with only tabs' '
973 git config core.whitespace blank-at-eol &&
976 old_hash_x=$(git hash-object x) &&
977 before=$(git rev-parse --short "$old_hash_x") &&
978 git commit -m "initial" x &&
979 echo "{NTN}" | tr "NT" "\n\t" >>x &&
980 new_hash_x=$(git hash-object x) &&
981 after=$(git rev-parse --short "$new_hash_x") &&
982 git diff --color >current.raw &&
983 test_decode_color <current.raw >current &&
985 cat >expected <<-EOF &&
986 <BOLD>diff --git a/x b/x<RESET>
987 <BOLD>index $before..$after 100644<RESET>
990 <CYAN>@@ -1 +1,4 @@<RESET>
992 <GREEN>+<RESET><GREEN>{<RESET>
993 <GREEN>+<RESET><BLUE> <RESET>
994 <GREEN>+<RESET><GREEN>}<RESET>
997 test_cmp expected current
1000 test_expect_success
'diff that introduces and removes ws breakages' '
1003 echo "0. blank-at-eol " &&
1004 echo "1. blank-at-eol "
1006 old_hash_x=$(git hash-object x) &&
1007 before=$(git rev-parse --short "$old_hash_x") &&
1008 git commit -a --allow-empty -m preimage &&
1010 echo "0. blank-at-eol " &&
1011 echo "1. still-blank-at-eol " &&
1012 echo "2. and a new line "
1014 new_hash_x=$(git hash-object x) &&
1015 after=$(git rev-parse --short "$new_hash_x") &&
1017 git diff --color >current.raw &&
1018 test_decode_color <current.raw >current &&
1020 cat >expected <<-EOF &&
1021 <BOLD>diff --git a/x b/x<RESET>
1022 <BOLD>index $before..$after 100644<RESET>
1023 <BOLD>--- a/x<RESET>
1024 <BOLD>+++ b/x<RESET>
1025 <CYAN>@@ -1,2 +1,3 @@<RESET>
1026 0. blank-at-eol <RESET>
1027 <RED>-1. blank-at-eol <RESET>
1028 <GREEN>+<RESET><GREEN>1. still-blank-at-eol<RESET><BLUE> <RESET>
1029 <GREEN>+<RESET><GREEN>2. and a new line<RESET><BLUE> <RESET>
1032 test_cmp expected current
1035 test_expect_success
'ws-error-highlight test setup' '
1039 echo "0. blank-at-eol " &&
1040 echo "1. blank-at-eol "
1042 old_hash_x=$(git hash-object x) &&
1043 before=$(git rev-parse --short "$old_hash_x") &&
1044 git commit -a --allow-empty -m preimage &&
1046 echo "0. blank-at-eol " &&
1047 echo "1. still-blank-at-eol " &&
1048 echo "2. and a new line "
1050 new_hash_x=$(git hash-object x) &&
1051 after=$(git rev-parse --short "$new_hash_x") &&
1053 cat >expect.default-old <<-EOF &&
1054 <BOLD>diff --git a/x b/x<RESET>
1055 <BOLD>index $before..$after 100644<RESET>
1056 <BOLD>--- a/x<RESET>
1057 <BOLD>+++ b/x<RESET>
1058 <CYAN>@@ -1,2 +1,3 @@<RESET>
1059 0. blank-at-eol <RESET>
1060 <RED>-<RESET><RED>1. blank-at-eol<RESET><BLUE> <RESET>
1061 <GREEN>+<RESET><GREEN>1. still-blank-at-eol<RESET><BLUE> <RESET>
1062 <GREEN>+<RESET><GREEN>2. and a new line<RESET><BLUE> <RESET>
1065 cat >expect.all <<-EOF &&
1066 <BOLD>diff --git a/x b/x<RESET>
1067 <BOLD>index $before..$after 100644<RESET>
1068 <BOLD>--- a/x<RESET>
1069 <BOLD>+++ b/x<RESET>
1070 <CYAN>@@ -1,2 +1,3 @@<RESET>
1071 <RESET>0. blank-at-eol<RESET><BLUE> <RESET>
1072 <RED>-<RESET><RED>1. blank-at-eol<RESET><BLUE> <RESET>
1073 <GREEN>+<RESET><GREEN>1. still-blank-at-eol<RESET><BLUE> <RESET>
1074 <GREEN>+<RESET><GREEN>2. and a new line<RESET><BLUE> <RESET>
1077 cat >expect.none <<-EOF
1078 <BOLD>diff --git a/x b/x<RESET>
1079 <BOLD>index $before..$after 100644<RESET>
1080 <BOLD>--- a/x<RESET>
1081 <BOLD>+++ b/x<RESET>
1082 <CYAN>@@ -1,2 +1,3 @@<RESET>
1083 0. blank-at-eol <RESET>
1084 <RED>-1. blank-at-eol <RESET>
1085 <GREEN>+1. still-blank-at-eol <RESET>
1086 <GREEN>+2. and a new line <RESET>
1091 test_expect_success
'test --ws-error-highlight option' '
1093 git diff --color --ws-error-highlight=default,old >current.raw &&
1094 test_decode_color <current.raw >current &&
1095 test_cmp expect.default-old current &&
1097 git diff --color --ws-error-highlight=all >current.raw &&
1098 test_decode_color <current.raw >current &&
1099 test_cmp expect.all current &&
1101 git diff --color --ws-error-highlight=none >current.raw &&
1102 test_decode_color <current.raw >current &&
1103 test_cmp expect.none current
1107 test_expect_success
'test diff.wsErrorHighlight config' '
1109 git -c diff.wsErrorHighlight=default,old diff --color >current.raw &&
1110 test_decode_color <current.raw >current &&
1111 test_cmp expect.default-old current &&
1113 git -c diff.wsErrorHighlight=all diff --color >current.raw &&
1114 test_decode_color <current.raw >current &&
1115 test_cmp expect.all current &&
1117 git -c diff.wsErrorHighlight=none diff --color >current.raw &&
1118 test_decode_color <current.raw >current &&
1119 test_cmp expect.none current
1123 test_expect_success
'option overrides diff.wsErrorHighlight' '
1125 git -c diff.wsErrorHighlight=none \
1126 diff --color --ws-error-highlight=default,old >current.raw &&
1127 test_decode_color <current.raw >current &&
1128 test_cmp expect.default-old current &&
1130 git -c diff.wsErrorHighlight=default \
1131 diff --color --ws-error-highlight=all >current.raw &&
1132 test_decode_color <current.raw >current &&
1133 test_cmp expect.all current &&
1135 git -c diff.wsErrorHighlight=all \
1136 diff --color --ws-error-highlight=none >current.raw &&
1137 test_decode_color <current.raw >current &&
1138 test_cmp expect.none current
1142 test_expect_success
'detect moved code, complete file' '
1144 cat <<-\EOF >test.c &&
1148 printf("Hello World");
1152 git commit -m "add main function" &&
1153 file=$(git rev-parse --short HEAD:test.c) &&
1154 git mv test.c main.c &&
1155 test_config color.diff.oldMoved "normal red" &&
1156 test_config color.diff.newMoved "normal green" &&
1157 git diff HEAD --color-moved=zebra --color --no-renames >actual.raw &&
1158 test_decode_color <actual.raw >actual &&
1159 cat >expected <<-EOF &&
1160 <BOLD>diff --git a/main.c b/main.c<RESET>
1161 <BOLD>new file mode 100644<RESET>
1162 <BOLD>index 0000000..$file<RESET>
1163 <BOLD>--- /dev/null<RESET>
1164 <BOLD>+++ b/main.c<RESET>
1165 <CYAN>@@ -0,0 +1,5 @@<RESET>
1166 <BGREEN>+<RESET><BGREEN>#include<stdio.h><RESET>
1167 <BGREEN>+<RESET><BGREEN>main()<RESET>
1168 <BGREEN>+<RESET><BGREEN>{<RESET>
1169 <BGREEN>+<RESET><BGREEN>printf("Hello World");<RESET>
1170 <BGREEN>+<RESET><BGREEN>}<RESET>
1171 <BOLD>diff --git a/test.c b/test.c<RESET>
1172 <BOLD>deleted file mode 100644<RESET>
1173 <BOLD>index $file..0000000<RESET>
1174 <BOLD>--- a/test.c<RESET>
1175 <BOLD>+++ /dev/null<RESET>
1176 <CYAN>@@ -1,5 +0,0 @@<RESET>
1177 <BRED>-#include<stdio.h><RESET>
1178 <BRED>-main()<RESET>
1180 <BRED>-printf("Hello World");<RESET>
1184 test_cmp expected actual
1187 test_expect_success
'--color-moved with --no-ext-diff' '
1188 test_config color.diff.oldMoved "yellow" &&
1189 test_config color.diff.newMoved "blue" &&
1190 args="--color --color-moved=zebra --no-renames HEAD" &&
1191 git diff $args >expect &&
1192 git -c diff.external=echo diff --no-ext-diff $args >actual &&
1193 test_cmp expect actual
1196 test_expect_success
'detect malicious moved code, inside file' '
1197 test_config color.diff.oldMoved "normal red" &&
1198 test_config color.diff.newMoved "normal green" &&
1199 test_config color.diff.oldMovedAlternative "blue" &&
1200 test_config color.diff.newMovedAlternative "yellow" &&
1202 cat <<-\EOF >main.c &&
1210 int secure_foo(struct user *u)
1212 if (!u->is_allowed_foo)
1222 cat <<-\EOF >test.c &&
1226 printf("Hello World, but different\n");
1229 int another_function()
1234 git add main.c test.c &&
1235 git commit -m "add main and test file" &&
1236 before_main=$(git rev-parse --short HEAD:main.c) &&
1237 before_test=$(git rev-parse --short HEAD:test.c) &&
1238 cat <<-\EOF >main.c &&
1251 cat <<-\EOF >test.c &&
1255 printf("Hello World, but different\n");
1258 int secure_foo(struct user *u)
1261 if (!u->is_allowed_foo)
1265 int another_function()
1270 hash_main=$(git hash-object main.c) &&
1271 after_main=$(git rev-parse --short "$hash_main") &&
1272 hash_test=$(git hash-object test.c) &&
1273 after_test=$(git rev-parse --short "$hash_test") &&
1274 git diff HEAD --no-renames --color-moved=zebra --color >actual.raw &&
1275 test_decode_color <actual.raw >actual &&
1276 cat <<-EOF >expected &&
1277 <BOLD>diff --git a/main.c b/main.c<RESET>
1278 <BOLD>index $before_main..$after_main 100644<RESET>
1279 <BOLD>--- a/main.c<RESET>
1280 <BOLD>+++ b/main.c<RESET>
1281 <CYAN>@@ -5,13 +5,6 @@<RESET> <RESET>printf("Hello ");<RESET>
1282 printf("World\n");<RESET>
1285 <BRED>-int secure_foo(struct user *u)<RESET>
1287 <BLUE>-if (!u->is_allowed_foo)<RESET>
1288 <BLUE>-return;<RESET>
1289 <RED>-foo(u);<RESET>
1295 <BOLD>diff --git a/test.c b/test.c<RESET>
1296 <BOLD>index $before_test..$after_test 100644<RESET>
1297 <BOLD>--- a/test.c<RESET>
1298 <BOLD>+++ b/test.c<RESET>
1299 <CYAN>@@ -4,6 +4,13 @@<RESET> <RESET>int bar()<RESET>
1300 printf("Hello World, but different\n");<RESET>
1303 <BGREEN>+<RESET><BGREEN>int secure_foo(struct user *u)<RESET>
1304 <BGREEN>+<RESET><BGREEN>{<RESET>
1305 <GREEN>+<RESET><GREEN>foo(u);<RESET>
1306 <BGREEN>+<RESET><BGREEN>if (!u->is_allowed_foo)<RESET>
1307 <BGREEN>+<RESET><BGREEN>return;<RESET>
1308 <GREEN>+<RESET><GREEN>}<RESET>
1310 int another_function()<RESET>
1315 test_cmp expected actual
1318 test_expect_success
'plain moved code, inside file' '
1319 test_config color.diff.oldMoved "normal red" &&
1320 test_config color.diff.newMoved "normal green" &&
1321 test_config color.diff.oldMovedAlternative "blue" &&
1322 test_config color.diff.newMovedAlternative "yellow" &&
1323 # needs previous test as setup
1324 git diff HEAD --no-renames --color-moved=plain --color >actual.raw &&
1325 test_decode_color <actual.raw >actual &&
1326 cat <<-EOF >expected &&
1327 <BOLD>diff --git a/main.c b/main.c<RESET>
1328 <BOLD>index $before_main..$after_main 100644<RESET>
1329 <BOLD>--- a/main.c<RESET>
1330 <BOLD>+++ b/main.c<RESET>
1331 <CYAN>@@ -5,13 +5,6 @@<RESET> <RESET>printf("Hello ");<RESET>
1332 printf("World\n");<RESET>
1335 <BRED>-int secure_foo(struct user *u)<RESET>
1337 <BRED>-if (!u->is_allowed_foo)<RESET>
1338 <BRED>-return;<RESET>
1339 <BRED>-foo(u);<RESET>
1345 <BOLD>diff --git a/test.c b/test.c<RESET>
1346 <BOLD>index $before_test..$after_test 100644<RESET>
1347 <BOLD>--- a/test.c<RESET>
1348 <BOLD>+++ b/test.c<RESET>
1349 <CYAN>@@ -4,6 +4,13 @@<RESET> <RESET>int bar()<RESET>
1350 printf("Hello World, but different\n");<RESET>
1353 <BGREEN>+<RESET><BGREEN>int secure_foo(struct user *u)<RESET>
1354 <BGREEN>+<RESET><BGREEN>{<RESET>
1355 <BGREEN>+<RESET><BGREEN>foo(u);<RESET>
1356 <BGREEN>+<RESET><BGREEN>if (!u->is_allowed_foo)<RESET>
1357 <BGREEN>+<RESET><BGREEN>return;<RESET>
1358 <BGREEN>+<RESET><BGREEN>}<RESET>
1360 int another_function()<RESET>
1365 test_cmp expected actual
1368 test_expect_success
'detect blocks of moved code' '
1370 cat <<-\EOF >lines.txt &&
1388 git add lines.txt &&
1389 git commit -m "add poetry" &&
1390 cat <<-\EOF >lines.txt &&
1408 test_config color.diff.oldMoved "magenta" &&
1409 test_config color.diff.newMoved "cyan" &&
1410 test_config color.diff.oldMovedAlternative "blue" &&
1411 test_config color.diff.newMovedAlternative "yellow" &&
1412 test_config color.diff.oldMovedDimmed "normal magenta" &&
1413 test_config color.diff.newMovedDimmed "normal cyan" &&
1414 test_config color.diff.oldMovedAlternativeDimmed "normal blue" &&
1415 test_config color.diff.newMovedAlternativeDimmed "normal yellow" &&
1416 git diff HEAD --no-renames --color-moved=blocks --color >actual.raw &&
1417 grep -v "index" actual.raw | test_decode_color >actual &&
1418 cat <<-\EOF >expected &&
1419 <BOLD>diff --git a/lines.txt b/lines.txt<RESET>
1420 <BOLD>--- a/lines.txt<RESET>
1421 <BOLD>+++ b/lines.txt<RESET>
1422 <CYAN>@@ -1,16 +1,16 @@<RESET>
1423 <MAGENTA>-long line 1<RESET>
1424 <MAGENTA>-long line 2<RESET>
1425 <MAGENTA>-long line 3<RESET>
1432 <CYAN>+<RESET><CYAN>long line 1<RESET>
1433 <CYAN>+<RESET><CYAN>long line 2<RESET>
1434 <CYAN>+<RESET><CYAN>long line 3<RESET>
1435 <CYAN>+<RESET><CYAN>long line 14<RESET>
1436 <CYAN>+<RESET><CYAN>long line 15<RESET>
1437 <CYAN>+<RESET><CYAN>long line 16<RESET>
1442 <MAGENTA>-long line 14<RESET>
1443 <MAGENTA>-long line 15<RESET>
1444 <MAGENTA>-long line 16<RESET>
1446 test_cmp expected actual
1450 test_expect_success
'detect permutations inside moved code -- dimmed-zebra' '
1451 # reuse setup from test before!
1452 test_config color.diff.oldMoved "magenta" &&
1453 test_config color.diff.newMoved "cyan" &&
1454 test_config color.diff.oldMovedAlternative "blue" &&
1455 test_config color.diff.newMovedAlternative "yellow" &&
1456 test_config color.diff.oldMovedDimmed "normal magenta" &&
1457 test_config color.diff.newMovedDimmed "normal cyan" &&
1458 test_config color.diff.oldMovedAlternativeDimmed "normal blue" &&
1459 test_config color.diff.newMovedAlternativeDimmed "normal yellow" &&
1460 git diff HEAD --no-renames --color-moved=dimmed-zebra --color >actual.raw &&
1461 grep -v "index" actual.raw | test_decode_color >actual &&
1462 cat <<-\EOF >expected &&
1463 <BOLD>diff --git a/lines.txt b/lines.txt<RESET>
1464 <BOLD>--- a/lines.txt<RESET>
1465 <BOLD>+++ b/lines.txt<RESET>
1466 <CYAN>@@ -1,16 +1,16 @@<RESET>
1467 <BMAGENTA>-long line 1<RESET>
1468 <BMAGENTA>-long line 2<RESET>
1469 <BMAGENTA>-long line 3<RESET>
1476 <BCYAN>+<RESET><BCYAN>long line 1<RESET>
1477 <BCYAN>+<RESET><BCYAN>long line 2<RESET>
1478 <CYAN>+<RESET><CYAN>long line 3<RESET>
1479 <YELLOW>+<RESET><YELLOW>long line 14<RESET>
1480 <BYELLOW>+<RESET><BYELLOW>long line 15<RESET>
1481 <BYELLOW>+<RESET><BYELLOW>long line 16<RESET>
1486 <BMAGENTA>-long line 14<RESET>
1487 <BMAGENTA>-long line 15<RESET>
1488 <BMAGENTA>-long line 16<RESET>
1490 test_cmp expected actual
1493 test_expect_success
'zebra alternate color is only used when necessary' '
1494 cat >old.txt <<-\EOF &&
1495 line 1A should be marked as oldMoved newMovedAlternate
1496 line 1B should be marked as oldMoved newMovedAlternate
1498 line 2A should be marked as oldMoved newMovedAlternate
1499 line 2B should be marked as oldMoved newMovedAlternate
1500 line 3A should be marked as oldMovedAlternate newMoved
1501 line 3B should be marked as oldMovedAlternate newMoved
1503 line 4A should be marked as oldMoved newMovedAlternate
1504 line 4B should be marked as oldMoved newMovedAlternate
1505 line 5A should be marked as oldMovedAlternate newMoved
1506 line 5B should be marked as oldMovedAlternate newMoved
1507 line 6A should be marked as oldMoved newMoved
1508 line 6B should be marked as oldMoved newMoved
1510 cat >new.txt <<-\EOF &&
1511 line 1A should be marked as oldMoved newMovedAlternate
1512 line 1B should be marked as oldMoved newMovedAlternate
1514 line 3A should be marked as oldMovedAlternate newMoved
1515 line 3B should be marked as oldMovedAlternate newMoved
1516 line 2A should be marked as oldMoved newMovedAlternate
1517 line 2B should be marked as oldMoved newMovedAlternate
1519 line 6A should be marked as oldMoved newMoved
1520 line 6B should be marked as oldMoved newMoved
1521 line 4A should be marked as oldMoved newMovedAlternate
1522 line 4B should be marked as oldMoved newMovedAlternate
1523 line 5A should be marked as oldMovedAlternate newMoved
1524 line 5B should be marked as oldMovedAlternate newMoved
1526 test_expect_code 1 git diff --no-index --color --color-moved=zebra \
1527 --color-moved-ws=allow-indentation-change \
1528 old.txt new.txt >output &&
1529 grep -v index output | test_decode_color >actual &&
1530 cat >expected <<-\EOF &&
1531 <BOLD>diff --git a/old.txt b/new.txt<RESET>
1532 <BOLD>--- a/old.txt<RESET>
1533 <BOLD>+++ b/new.txt<RESET>
1534 <CYAN>@@ -1,14 +1,14 @@<RESET>
1535 <BOLD;MAGENTA>-line 1A should be marked as oldMoved newMovedAlternate<RESET>
1536 <BOLD;MAGENTA>-line 1B should be marked as oldMoved newMovedAlternate<RESET>
1537 <BOLD;CYAN>+<RESET><BOLD;CYAN> line 1A should be marked as oldMoved newMovedAlternate<RESET>
1538 <BOLD;CYAN>+<RESET><BOLD;CYAN> line 1B should be marked as oldMoved newMovedAlternate<RESET>
1540 <BOLD;MAGENTA>-line 2A should be marked as oldMoved newMovedAlternate<RESET>
1541 <BOLD;MAGENTA>-line 2B should be marked as oldMoved newMovedAlternate<RESET>
1542 <BOLD;BLUE>-line 3A should be marked as oldMovedAlternate newMoved<RESET>
1543 <BOLD;BLUE>-line 3B should be marked as oldMovedAlternate newMoved<RESET>
1544 <BOLD;CYAN>+<RESET><BOLD;CYAN> line 3A should be marked as oldMovedAlternate newMoved<RESET>
1545 <BOLD;CYAN>+<RESET><BOLD;CYAN> line 3B should be marked as oldMovedAlternate newMoved<RESET>
1546 <BOLD;YELLOW>+<RESET><BOLD;YELLOW> line 2A should be marked as oldMoved newMovedAlternate<RESET>
1547 <BOLD;YELLOW>+<RESET><BOLD;YELLOW> line 2B should be marked as oldMoved newMovedAlternate<RESET>
1549 <BOLD;MAGENTA>-line 4A should be marked as oldMoved newMovedAlternate<RESET>
1550 <BOLD;MAGENTA>-line 4B should be marked as oldMoved newMovedAlternate<RESET>
1551 <BOLD;BLUE>-line 5A should be marked as oldMovedAlternate newMoved<RESET>
1552 <BOLD;BLUE>-line 5B should be marked as oldMovedAlternate newMoved<RESET>
1553 <BOLD;MAGENTA>-line 6A should be marked as oldMoved newMoved<RESET>
1554 <BOLD;MAGENTA>-line 6B should be marked as oldMoved newMoved<RESET>
1555 <BOLD;CYAN>+<RESET><BOLD;CYAN> line 6A should be marked as oldMoved newMoved<RESET>
1556 <BOLD;CYAN>+<RESET><BOLD;CYAN> line 6B should be marked as oldMoved newMoved<RESET>
1557 <BOLD;YELLOW>+<RESET><BOLD;YELLOW> line 4A should be marked as oldMoved newMovedAlternate<RESET>
1558 <BOLD;YELLOW>+<RESET><BOLD;YELLOW> line 4B should be marked as oldMoved newMovedAlternate<RESET>
1559 <BOLD;CYAN>+<RESET><BOLD;CYAN> line 5A should be marked as oldMovedAlternate newMoved<RESET>
1560 <BOLD;CYAN>+<RESET><BOLD;CYAN> line 5B should be marked as oldMovedAlternate newMoved<RESET>
1562 test_cmp expected actual
1565 test_expect_success
'short lines of opposite sign do not get marked as moved' '
1566 cat >old.txt <<-\EOF &&
1567 this line should be marked as moved
1573 this line should be marked as oldMoved newMoved
1574 this line should be marked as oldMovedAlternate newMoved
1579 this line should be marked as oldMoved newMoved/newMovedAlternate
1581 cat >new.txt <<-\EOF &&
1585 this line should be marked as moved
1589 this line should be marked as oldMoved newMoved/newMovedAlternate
1592 this line should be marked as oldMovedAlternate newMoved
1593 this line should be marked as oldMoved newMoved/newMovedAlternate
1595 this line should be marked as oldMoved newMoved
1598 test_expect_code 1 git diff --no-index --color --color-moved=zebra \
1599 old.txt new.txt >output && cat output &&
1600 grep -v index output | test_decode_color >actual &&
1601 cat >expect <<-\EOF &&
1602 <BOLD>diff --git a/old.txt b/new.txt<RESET>
1603 <BOLD>--- a/old.txt<RESET>
1604 <BOLD>+++ b/new.txt<RESET>
1605 <CYAN>@@ -1,13 +1,15 @@<RESET>
1606 <BOLD;MAGENTA>-this line should be marked as moved<RESET>
1607 <GREEN>+<RESET><GREEN>too short<RESET>
1610 <BOLD;CYAN>+<RESET><BOLD;CYAN>this line should be marked as moved<RESET>
1611 <GREEN>+<RESET><GREEN>too short<RESET>
1614 <RED>-too short<RESET>
1615 <BOLD;MAGENTA>-this line should be marked as oldMoved newMoved<RESET>
1616 <BOLD;BLUE>-this line should be marked as oldMovedAlternate newMoved<RESET>
1617 <BOLD;CYAN>+<RESET><BOLD;CYAN>this line should be marked as oldMoved newMoved/newMovedAlternate<RESET>
1620 <BOLD;CYAN>+<RESET><BOLD;CYAN>this line should be marked as oldMovedAlternate newMoved<RESET>
1621 <BOLD;YELLOW>+<RESET><BOLD;YELLOW>this line should be marked as oldMoved newMoved/newMovedAlternate<RESET>
1623 <BOLD;CYAN>+<RESET><BOLD;CYAN>this line should be marked as oldMoved newMoved<RESET>
1625 <BOLD;MAGENTA>-this line should be marked as oldMoved newMoved/newMovedAlternate<RESET>
1627 test_cmp expect actual
1630 test_expect_success
'cmd option assumes configured colored-moved' '
1631 test_config color.diff.oldMoved "magenta" &&
1632 test_config color.diff.newMoved "cyan" &&
1633 test_config color.diff.oldMovedAlternative "blue" &&
1634 test_config color.diff.newMovedAlternative "yellow" &&
1635 test_config color.diff.oldMovedDimmed "normal magenta" &&
1636 test_config color.diff.newMovedDimmed "normal cyan" &&
1637 test_config color.diff.oldMovedAlternativeDimmed "normal blue" &&
1638 test_config color.diff.newMovedAlternativeDimmed "normal yellow" &&
1639 test_config diff.colorMoved zebra &&
1640 git diff HEAD --no-renames --color-moved --color >actual.raw &&
1641 grep -v "index" actual.raw | test_decode_color >actual &&
1642 cat <<-\EOF >expected &&
1643 <BOLD>diff --git a/lines.txt b/lines.txt<RESET>
1644 <BOLD>--- a/lines.txt<RESET>
1645 <BOLD>+++ b/lines.txt<RESET>
1646 <CYAN>@@ -1,16 +1,16 @@<RESET>
1647 <MAGENTA>-long line 1<RESET>
1648 <MAGENTA>-long line 2<RESET>
1649 <MAGENTA>-long line 3<RESET>
1656 <CYAN>+<RESET><CYAN>long line 1<RESET>
1657 <CYAN>+<RESET><CYAN>long line 2<RESET>
1658 <CYAN>+<RESET><CYAN>long line 3<RESET>
1659 <YELLOW>+<RESET><YELLOW>long line 14<RESET>
1660 <YELLOW>+<RESET><YELLOW>long line 15<RESET>
1661 <YELLOW>+<RESET><YELLOW>long line 16<RESET>
1666 <MAGENTA>-long line 14<RESET>
1667 <MAGENTA>-long line 15<RESET>
1668 <MAGENTA>-long line 16<RESET>
1670 test_cmp expected actual
1673 test_expect_success
'no effect on diff from --color-moved with --word-diff' '
1674 cat <<-\EOF >text.txt &&
1675 Lorem Ipsum is simply dummy text of the printing and typesetting industry.
1678 git commit -a -m "clean state" &&
1679 cat <<-\EOF >text.txt &&
1680 simply Lorem Ipsum dummy is text of the typesetting and printing industry.
1682 git diff --color-moved --word-diff >actual &&
1683 git diff --word-diff >expect &&
1684 test_cmp expect actual
1687 test_expect_success
'no effect on show from --color-moved with --word-diff' '
1688 git show --color-moved --word-diff >actual &&
1689 git show --word-diff >expect &&
1690 test_cmp expect actual
1693 test_expect_success
'set up whitespace tests' '
1695 # Note that these lines have no leading or trailing whitespace.
1696 cat <<-\EOF >lines.txt &&
1707 git add lines.txt &&
1708 git commit -m "add poetry" &&
1709 git config color.diff.oldMoved "magenta" &&
1710 git config color.diff.newMoved "cyan"
1713 test_expect_success
'move detection ignoring whitespace ' '
1714 q_to_tab <<-\EOF >lines.txt &&
1718 Qchanged long line 9
1725 git diff HEAD --no-renames --color-moved --color >actual.raw &&
1726 grep -v "index" actual.raw | test_decode_color >actual &&
1727 cat <<-\EOF >expected &&
1728 <BOLD>diff --git a/lines.txt b/lines.txt<RESET>
1729 <BOLD>--- a/lines.txt<RESET>
1730 <BOLD>+++ b/lines.txt<RESET>
1731 <CYAN>@@ -1,9 +1,9 @@<RESET>
1732 <GREEN>+<RESET> <GREEN>long line 6<RESET>
1733 <GREEN>+<RESET> <GREEN>long line 7<RESET>
1734 <GREEN>+<RESET> <GREEN>long line 8<RESET>
1735 <GREEN>+<RESET> <GREEN>changed long line 9<RESET>
1741 <RED>-long line 6<RESET>
1742 <RED>-long line 7<RESET>
1743 <RED>-long line 8<RESET>
1744 <RED>-long line 9<RESET>
1746 test_cmp expected actual &&
1748 git diff HEAD --no-renames --color-moved --color \
1749 --color-moved-ws=ignore-all-space >actual.raw &&
1750 grep -v "index" actual.raw | test_decode_color >actual &&
1751 cat <<-\EOF >expected &&
1752 <BOLD>diff --git a/lines.txt b/lines.txt<RESET>
1753 <BOLD>--- a/lines.txt<RESET>
1754 <BOLD>+++ b/lines.txt<RESET>
1755 <CYAN>@@ -1,9 +1,9 @@<RESET>
1756 <CYAN>+<RESET> <CYAN>long line 6<RESET>
1757 <CYAN>+<RESET> <CYAN>long line 7<RESET>
1758 <CYAN>+<RESET> <CYAN>long line 8<RESET>
1759 <GREEN>+<RESET> <GREEN>changed long line 9<RESET>
1765 <MAGENTA>-long line 6<RESET>
1766 <MAGENTA>-long line 7<RESET>
1767 <MAGENTA>-long line 8<RESET>
1768 <RED>-long line 9<RESET>
1770 test_cmp expected actual
1773 test_expect_success
'move detection ignoring whitespace changes' '
1775 # Lines 6-8 have a space change, but 9 is new whitespace
1776 q_to_tab <<-\EOF >lines.txt &&
1788 git diff HEAD --no-renames --color-moved --color >actual.raw &&
1789 grep -v "index" actual.raw | test_decode_color >actual &&
1790 cat <<-\EOF >expected &&
1791 <BOLD>diff --git a/lines.txt b/lines.txt<RESET>
1792 <BOLD>--- a/lines.txt<RESET>
1793 <BOLD>+++ b/lines.txt<RESET>
1794 <CYAN>@@ -1,9 +1,9 @@<RESET>
1795 <GREEN>+<RESET><GREEN>long line 6<RESET>
1796 <GREEN>+<RESET><GREEN>long line 7<RESET>
1797 <GREEN>+<RESET><GREEN>long line 8<RESET>
1798 <GREEN>+<RESET><GREEN>long li ne 9<RESET>
1804 <RED>-long line 6<RESET>
1805 <RED>-long line 7<RESET>
1806 <RED>-long line 8<RESET>
1807 <RED>-long line 9<RESET>
1809 test_cmp expected actual &&
1811 git diff HEAD --no-renames --color-moved --color \
1812 --color-moved-ws=ignore-space-change >actual.raw &&
1813 grep -v "index" actual.raw | test_decode_color >actual &&
1814 cat <<-\EOF >expected &&
1815 <BOLD>diff --git a/lines.txt b/lines.txt<RESET>
1816 <BOLD>--- a/lines.txt<RESET>
1817 <BOLD>+++ b/lines.txt<RESET>
1818 <CYAN>@@ -1,9 +1,9 @@<RESET>
1819 <CYAN>+<RESET><CYAN>long line 6<RESET>
1820 <CYAN>+<RESET><CYAN>long line 7<RESET>
1821 <CYAN>+<RESET><CYAN>long line 8<RESET>
1822 <GREEN>+<RESET><GREEN>long li ne 9<RESET>
1828 <MAGENTA>-long line 6<RESET>
1829 <MAGENTA>-long line 7<RESET>
1830 <MAGENTA>-long line 8<RESET>
1831 <RED>-long line 9<RESET>
1833 test_cmp expected actual
1836 test_expect_success
'move detection ignoring whitespace at eol' '
1838 # Lines 6-9 have new eol whitespace, but 9 also has it in the middle
1839 q_to_tab <<-\EOF >lines.txt &&
1851 # avoid cluttering the output with complaints about our eol whitespace
1852 test_config core.whitespace -blank-at-eol &&
1854 git diff HEAD --no-renames --color-moved --color >actual.raw &&
1855 grep -v "index" actual.raw | test_decode_color >actual &&
1856 cat <<-\EOF >expected &&
1857 <BOLD>diff --git a/lines.txt b/lines.txt<RESET>
1858 <BOLD>--- a/lines.txt<RESET>
1859 <BOLD>+++ b/lines.txt<RESET>
1860 <CYAN>@@ -1,9 +1,9 @@<RESET>
1861 <GREEN>+<RESET><GREEN>long line 6 <RESET>
1862 <GREEN>+<RESET><GREEN>long line 7 <RESET>
1863 <GREEN>+<RESET><GREEN>long line 8 <RESET>
1864 <GREEN>+<RESET><GREEN>long line 9 <RESET>
1870 <RED>-long line 6<RESET>
1871 <RED>-long line 7<RESET>
1872 <RED>-long line 8<RESET>
1873 <RED>-long line 9<RESET>
1875 test_cmp expected actual &&
1877 git diff HEAD --no-renames --color-moved --color \
1878 --color-moved-ws=ignore-space-at-eol >actual.raw &&
1879 grep -v "index" actual.raw | test_decode_color >actual &&
1880 cat <<-\EOF >expected &&
1881 <BOLD>diff --git a/lines.txt b/lines.txt<RESET>
1882 <BOLD>--- a/lines.txt<RESET>
1883 <BOLD>+++ b/lines.txt<RESET>
1884 <CYAN>@@ -1,9 +1,9 @@<RESET>
1885 <CYAN>+<RESET><CYAN>long line 6 <RESET>
1886 <CYAN>+<RESET><CYAN>long line 7 <RESET>
1887 <CYAN>+<RESET><CYAN>long line 8 <RESET>
1888 <GREEN>+<RESET><GREEN>long line 9 <RESET>
1894 <MAGENTA>-long line 6<RESET>
1895 <MAGENTA>-long line 7<RESET>
1896 <MAGENTA>-long line 8<RESET>
1897 <RED>-long line 9<RESET>
1899 test_cmp expected actual
1902 test_expect_success
'clean up whitespace-test colors' '
1903 git config --unset color.diff.oldMoved &&
1904 git config --unset color.diff.newMoved
1907 test_expect_success
'--color-moved block at end of diff output respects MIN_ALNUM_COUNT' '
1924 git diff HEAD --color-moved=zebra --color --no-renames >actual.raw &&
1925 grep -v "index" actual.raw | test_decode_color >actual &&
1926 cat >expected <<-\EOF &&
1927 <BOLD>diff --git a/bar b/bar<RESET>
1928 <BOLD>--- a/bar<RESET>
1929 <BOLD>+++ b/bar<RESET>
1930 <CYAN>@@ -0,0 +1 @@<RESET>
1931 <GREEN>+<RESET><GREEN>line1<RESET>
1932 <BOLD>diff --git a/foo b/foo<RESET>
1933 <BOLD>--- a/foo<RESET>
1934 <BOLD>+++ b/foo<RESET>
1935 <CYAN>@@ -1,2 +1 @@<RESET>
1936 irrelevant_line<RESET>
1940 test_cmp expected actual
1943 test_expect_success
'--color-moved respects MIN_ALNUM_COUNT' '
1946 nineteen chars 456789
1948 twenty chars 234567890
1958 twenty chars 234567890
1959 nineteen chars 456789
1962 git diff HEAD --color-moved=zebra --color --no-renames >actual.raw &&
1963 grep -v "index" actual.raw | test_decode_color >actual &&
1964 cat >expected <<-\EOF &&
1965 <BOLD>diff --git a/bar b/bar<RESET>
1966 <BOLD>--- a/bar<RESET>
1967 <BOLD>+++ b/bar<RESET>
1968 <CYAN>@@ -0,0 +1,2 @@<RESET>
1969 <BOLD;CYAN>+<RESET><BOLD;CYAN>twenty chars 234567890<RESET>
1970 <GREEN>+<RESET><GREEN>nineteen chars 456789<RESET>
1971 <BOLD>diff --git a/foo b/foo<RESET>
1972 <BOLD>--- a/foo<RESET>
1973 <BOLD>+++ b/foo<RESET>
1974 <CYAN>@@ -1,3 +1 @@<RESET>
1975 <RED>-nineteen chars 456789<RESET>
1976 irrelevant_line<RESET>
1977 <BOLD;MAGENTA>-twenty chars 234567890<RESET>
1980 test_cmp expected actual
1983 test_expect_success
'--color-moved treats adjacent blocks as separate for MIN_ALNUM_COUNT' '
2004 git diff HEAD --color-moved=zebra --color --no-renames >actual.raw &&
2005 grep -v "index" actual.raw | test_decode_color >actual &&
2006 cat >expected <<-\EOF &&
2007 <BOLD>diff --git a/bar b/bar<RESET>
2008 <BOLD>--- a/bar<RESET>
2009 <BOLD>+++ b/bar<RESET>
2010 <CYAN>@@ -0,0 +1,3 @@<RESET>
2011 <GREEN>+<RESET><GREEN>7charsB<RESET>
2012 <GREEN>+<RESET><GREEN>7charsC<RESET>
2013 <GREEN>+<RESET><GREEN>7charsA<RESET>
2014 <BOLD>diff --git a/foo b/foo<RESET>
2015 <BOLD>--- a/foo<RESET>
2016 <BOLD>+++ b/foo<RESET>
2017 <CYAN>@@ -1,4 +1 @@<RESET>
2018 <RED>-7charsA<RESET>
2019 irrelevant_line<RESET>
2020 <RED>-7charsB<RESET>
2021 <RED>-7charsC<RESET>
2024 test_cmp expected actual
2027 test_expect_success
'--color-moved rewinds for MIN_ALNUM_COUNT' '
2029 test_write_lines >file \
2030 A B C one two three four five six seven D E F G H I J &&
2032 test_write_lines >file \
2033 one two A B C D E F G H I J two three four five six seven &&
2034 git diff --color-moved=zebra -- file &&
2036 git diff --color-moved=zebra --color -- file >actual.raw &&
2037 grep -v "index" actual.raw | test_decode_color >actual &&
2038 cat >expected <<-\EOF &&
2039 <BOLD>diff --git a/file b/file<RESET>
2040 <BOLD>--- a/file<RESET>
2041 <BOLD>+++ b/file<RESET>
2042 <CYAN>@@ -1,13 +1,8 @@<RESET>
2043 <GREEN>+<RESET><GREEN>one<RESET>
2044 <GREEN>+<RESET><GREEN>two<RESET>
2049 <BOLD;MAGENTA>-two<RESET>
2050 <BOLD;MAGENTA>-three<RESET>
2051 <BOLD;MAGENTA>-four<RESET>
2052 <BOLD;MAGENTA>-five<RESET>
2053 <BOLD;MAGENTA>-six<RESET>
2054 <BOLD;MAGENTA>-seven<RESET>
2058 <CYAN>@@ -15,3 +10,9 @@<RESET> <RESET>G<RESET>
2062 <BOLD;CYAN>+<RESET><BOLD;CYAN>two<RESET>
2063 <BOLD;CYAN>+<RESET><BOLD;CYAN>three<RESET>
2064 <BOLD;CYAN>+<RESET><BOLD;CYAN>four<RESET>
2065 <BOLD;CYAN>+<RESET><BOLD;CYAN>five<RESET>
2066 <BOLD;CYAN>+<RESET><BOLD;CYAN>six<RESET>
2067 <BOLD;CYAN>+<RESET><BOLD;CYAN>seven<RESET>
2070 test_cmp expected actual
2073 test_expect_success
'move detection with submodules' '
2074 test_create_repo bananas &&
2075 echo ripe >bananas/recipe &&
2076 git -C bananas add recipe &&
2077 test_commit fruit &&
2078 test_commit -C bananas recipe &&
2079 git submodule add ./bananas &&
2081 git commit -a -m "bananas are like a heavy library?" &&
2082 echo foul >bananas/recipe &&
2083 echo ripe >fruit.t &&
2085 git diff --submodule=diff --color-moved --color >actual &&
2087 # no move detection as the moved line is across repository boundaries.
2088 test_decode_color <actual >decoded_actual &&
2089 ! grep BGREEN decoded_actual &&
2090 ! grep BRED decoded_actual &&
2092 # nor did we mess with it another way
2093 git diff --submodule=diff --color >expect.raw &&
2094 test_decode_color <expect.raw >expect &&
2095 test_cmp expect decoded_actual &&
2097 git submodule deinit bananas
2100 test_expect_success
'only move detection ignores white spaces' '
2102 q_to_tab <<-\EOF >text.txt &&
2103 a long line to exceed per-line minimum
2104 another long line to exceed per-line minimum
2108 git commit -m "add text" &&
2109 q_to_tab <<-\EOF >text.txt &&
2110 Qa long line to exceed per-line minimum
2111 Qanother long line to exceed per-line minimum
2115 # Make sure we get a different diff using -w
2116 git diff --color --color-moved -w >actual.raw &&
2117 grep -v "index" actual.raw | test_decode_color >actual &&
2118 q_to_tab <<-\EOF >expected &&
2119 <BOLD>diff --git a/text.txt b/text.txt<RESET>
2120 <BOLD>--- a/text.txt<RESET>
2121 <BOLD>+++ b/text.txt<RESET>
2122 <CYAN>@@ -1,3 +1,3 @@<RESET>
2123 Qa long line to exceed per-line minimum<RESET>
2124 Qanother long line to exceed per-line minimum<RESET>
2125 <RED>-original file<RESET>
2126 <GREEN>+<RESET><GREEN>new file<RESET>
2128 test_cmp expected actual &&
2130 # And now ignoring white space only in the move detection
2131 git diff --color --color-moved \
2132 --color-moved-ws=ignore-all-space,ignore-space-change,ignore-space-at-eol >actual.raw &&
2133 grep -v "index" actual.raw | test_decode_color >actual &&
2134 q_to_tab <<-\EOF >expected &&
2135 <BOLD>diff --git a/text.txt b/text.txt<RESET>
2136 <BOLD>--- a/text.txt<RESET>
2137 <BOLD>+++ b/text.txt<RESET>
2138 <CYAN>@@ -1,3 +1,3 @@<RESET>
2139 <BOLD;MAGENTA>-a long line to exceed per-line minimum<RESET>
2140 <BOLD;MAGENTA>-another long line to exceed per-line minimum<RESET>
2141 <RED>-original file<RESET>
2142 <BOLD;CYAN>+<RESET>Q<BOLD;CYAN>a long line to exceed per-line minimum<RESET>
2143 <BOLD;CYAN>+<RESET>Q<BOLD;CYAN>another long line to exceed per-line minimum<RESET>
2144 <GREEN>+<RESET><GREEN>new file<RESET>
2146 test_cmp expected actual
2149 test_expect_success
'compare whitespace delta across moved blocks' '
2152 q_to_tab <<-\EOF >text.txt &&
2156 QBut! <- this stands out
2158 QQdifferent starting
2164 QQQthat has similar lines
2165 QQQto previous blocks, but with different indent
2166 QQQYetQAnotherQoutlierQ
2167 QLine with internal w h i t e s p a c e change
2171 git commit -m "add text.txt" &&
2173 q_to_tab <<-\EOF >text.txt &&
2177 QQQBut! <- this stands out
2185 QQthat has similar lines
2186 QQto previous blocks, but with different indent
2187 QQYetQAnotherQoutlier
2188 QLine with internal whitespace change
2191 git diff --color --color-moved --color-moved-ws=allow-indentation-change >actual.raw &&
2192 grep -v "index" actual.raw | test_decode_color >actual &&
2194 q_to_tab <<-\EOF >expected &&
2195 <BOLD>diff --git a/text.txt b/text.txt<RESET>
2196 <BOLD>--- a/text.txt<RESET>
2197 <BOLD>+++ b/text.txt<RESET>
2198 <CYAN>@@ -1,15 +1,15 @@<RESET>
2199 <BOLD;MAGENTA>-QIndented<RESET>
2200 <BOLD;MAGENTA>-QText across<RESET>
2201 <BOLD;MAGENTA>-Qsome lines<RESET>
2202 <RED>-QBut! <- this stands out<RESET>
2203 <BOLD;MAGENTA>-QAdjusting with<RESET>
2204 <BOLD;MAGENTA>-QQdifferent starting<RESET>
2205 <BOLD;MAGENTA>-Qwhite spaces<RESET>
2206 <RED>-QAnother outlier<RESET>
2207 <BOLD;MAGENTA>-QQQIndented<RESET>
2208 <BOLD;MAGENTA>-QQQText across<RESET>
2209 <BOLD;MAGENTA>-QQQfive lines<RESET>
2210 <BOLD;MAGENTA>-QQQthat has similar lines<RESET>
2211 <BOLD;MAGENTA>-QQQto previous blocks, but with different indent<RESET>
2212 <RED>-QQQYetQAnotherQoutlierQ<RESET>
2213 <RED>-QLine with internal w h i t e s p a c e change<RESET>
2214 <BOLD;CYAN>+<RESET>QQ<BOLD;CYAN>Indented<RESET>
2215 <BOLD;CYAN>+<RESET>QQ<BOLD;CYAN>Text across<RESET>
2216 <BOLD;CYAN>+<RESET>QQ<BOLD;CYAN>some lines<RESET>
2217 <GREEN>+<RESET>QQQ<GREEN>But! <- this stands out<RESET>
2218 <BOLD;CYAN>+<RESET><BOLD;CYAN>Adjusting with<RESET>
2219 <BOLD;CYAN>+<RESET>Q<BOLD;CYAN>different starting<RESET>
2220 <BOLD;CYAN>+<RESET><BOLD;CYAN>white spaces<RESET>
2221 <GREEN>+<RESET><GREEN>AnotherQoutlier<RESET>
2222 <BOLD;CYAN>+<RESET>QQ<BOLD;CYAN>Indented<RESET>
2223 <BOLD;CYAN>+<RESET>QQ<BOLD;CYAN>Text across<RESET>
2224 <BOLD;CYAN>+<RESET>QQ<BOLD;CYAN>five lines<RESET>
2225 <BOLD;CYAN>+<RESET>QQ<BOLD;CYAN>that has similar lines<RESET>
2226 <BOLD;CYAN>+<RESET>QQ<BOLD;CYAN>to previous blocks, but with different indent<RESET>
2227 <GREEN>+<RESET>QQ<GREEN>YetQAnotherQoutlier<RESET>
2228 <GREEN>+<RESET>Q<GREEN>Line with internal whitespace change<RESET>
2231 test_cmp expected actual
2234 test_expect_success
'bogus settings in move detection erroring out' '
2235 test_must_fail git diff --color-moved=bogus 2>err &&
2236 test_grep "must be one of" err &&
2237 test_grep bogus err &&
2239 test_must_fail git -c diff.colormoved=bogus diff 2>err &&
2240 test_grep "must be one of" err &&
2241 test_grep "from command-line config" err &&
2243 test_must_fail git diff --color-moved-ws=bogus 2>err &&
2244 test_grep "possible values" err &&
2245 test_grep bogus err &&
2247 test_must_fail git -c diff.colormovedws=bogus diff 2>err &&
2248 test_grep "possible values" err &&
2249 test_grep "from command-line config" err
2252 test_expect_success
'compare whitespace delta incompatible with other space options' '
2253 test_must_fail git diff \
2254 --color-moved-ws=allow-indentation-change,ignore-all-space \
2256 test_grep allow-indentation-change err
2260 test_expect_success
'compare mixed whitespace delta across moved blocks' '
2263 tr "^|Q_" "\f\v\t " <<-EOF >text.txt &&
2265 |____too short without
2267 ___being grouped across blank line
2273 ____Indented text to
2274 _Q____be further indented by four spaces across
2276 QQ____These two lines have had their
2277 ____indentation reduced by four spaces
2278 Qdifferent indentation change
2283 git commit -m "add text.txt" &&
2285 tr "^|Q_" "\f\v\t " <<-EOF >text.txt &&
2291 QQbe further indented by four spaces across
2296 ^Q_______being grouped across blank line
2298 Q_QThese two lines have had their
2299 indentation reduced by four spaces
2300 QQdifferent indentation change
2304 git -c color.diff.whitespace="normal red" \
2305 -c core.whitespace=space-before-tab \
2306 diff --color --color-moved --ws-error-highlight=all \
2307 --color-moved-ws=allow-indentation-change >actual.raw &&
2308 grep -v "index" actual.raw | tr "\f\v" "^|" | test_decode_color >actual &&
2310 cat <<-\EOF >expected &&
2311 <BOLD>diff --git a/text.txt b/text.txt<RESET>
2312 <BOLD>--- a/text.txt<RESET>
2313 <BOLD>+++ b/text.txt<RESET>
2314 <CYAN>@@ -1,16 +1,16 @@<RESET>
2315 <BOLD;MAGENTA>-<RESET><BOLD;MAGENTA>^<RESET><BRED> <RESET>
2316 <BOLD;MAGENTA>-<RESET><BOLD;MAGENTA>| too short without<RESET>
2317 <BOLD;MAGENTA>-<RESET><BOLD;MAGENTA>^<RESET>
2318 <BOLD;MAGENTA>-<RESET><BOLD;MAGENTA> being grouped across blank line<RESET>
2319 <BOLD;MAGENTA>-<RESET>
2320 <RESET>context<RESET>
2323 <RESET>anchor<RESET>
2324 <BOLD;MAGENTA>-<RESET><BOLD;MAGENTA> Indented text to<RESET>
2325 <BOLD;MAGENTA>-<RESET><BRED> <RESET> <BOLD;MAGENTA> be further indented by four spaces across<RESET>
2326 <BOLD;MAGENTA>-<RESET><BRED> <RESET> <BOLD;MAGENTA>several lines<RESET>
2327 <BOLD;BLUE>-<RESET> <BOLD;BLUE> These two lines have had their<RESET>
2328 <BOLD;BLUE>-<RESET><BOLD;BLUE> indentation reduced by four spaces<RESET>
2329 <BOLD;MAGENTA>-<RESET> <BOLD;MAGENTA>different indentation change<RESET>
2330 <RED>-<RESET><RED> too short<RESET>
2331 <BOLD;CYAN>+<RESET> <BOLD;CYAN>Indented text to<RESET>
2332 <BOLD;CYAN>+<RESET> <BOLD;CYAN>be further indented by four spaces across<RESET>
2333 <BOLD;CYAN>+<RESET> <BOLD;CYAN> several lines<RESET>
2334 <BOLD;YELLOW>+<RESET>
2335 <BOLD;YELLOW>+<RESET> <BOLD;YELLOW>too short without<RESET>
2336 <BOLD;YELLOW>+<RESET>
2337 <BOLD;YELLOW>+<RESET><BOLD;YELLOW>^ being grouped across blank line<RESET>
2338 <BOLD;YELLOW>+<RESET>
2339 <BOLD;CYAN>+<RESET> <BRED> <RESET> <BOLD;CYAN>These two lines have had their<RESET>
2340 <BOLD;CYAN>+<RESET><BOLD;CYAN>indentation reduced by four spaces<RESET>
2341 <BOLD;YELLOW>+<RESET> <BOLD;YELLOW>different indentation change<RESET>
2342 <GREEN>+<RESET><BRED> <RESET> <GREEN>too short<RESET>
2345 test_cmp expected actual
2348 test_expect_success
'combine --ignore-blank-lines with --function-context' '
2349 test_write_lines 1 "" 2 3 4 5 >a &&
2350 test_write_lines 1 2 3 4 >b &&
2351 test_must_fail git diff --no-index \
2352 --ignore-blank-lines --function-context a b >actual.raw &&
2353 sed -n "/@@/,\$p" <actual.raw >actual &&
2354 cat <<-\EOF >expect &&
2363 test_cmp expect actual
2366 test_expect_success
'combine --ignore-blank-lines with --function-context 2' '
2367 test_write_lines a b c "" function 1 2 3 4 5 "" 6 7 8 9 >a &&
2368 test_write_lines "" a b c "" function 1 2 3 4 5 6 7 8 >b &&
2369 test_must_fail git diff --no-index \
2370 --ignore-blank-lines --function-context a b >actual.raw &&
2371 sed -n "/@@/,\$p" <actual.raw >actual &&
2372 cat <<-\EOF >expect &&
2386 test_cmp expect actual