]> git.ipfire.org Git - thirdparty/git.git/blob - t/t4015-diff-whitespace.sh
diff: teach "--stat -w --exit-code" to notice differences
[thirdparty/git.git] / t / t4015-diff-whitespace.sh
1 #!/bin/sh
2 #
3 # Copyright (c) 2006 Johannes E. Schindelin
4 # Copyright (c) 2023 Google LLC
5
6 test_description='Test special whitespace in diff engine.
7
8 '
9
10 TEST_PASSES_SANITIZE_LEAK=true
11 . ./test-lib.sh
12 . "$TEST_DIRECTORY"/lib-diff.sh
13
14 for opts in --patch --quiet -s --stat --shortstat --dirstat=lines
15 do
16
17 test_expect_success "status with $opts (different)" '
18 echo foo >x &&
19 git add x &&
20 echo bar >x &&
21 test_expect_code 1 git diff -w $opts --exit-code x
22 '
23
24 test_expect_success POSIXPERM "status with $opts (mode differs)" '
25 test_when_finished "git update-index --chmod=-x x" &&
26 echo foo >x &&
27 git add x &&
28 git update-index --chmod=+x x &&
29 test_expect_code 1 git diff -w $opts --exit-code x
30 '
31
32 test_expect_success "status with $opts (removing an empty file)" '
33 : >x &&
34 git add x &&
35 rm x &&
36 test_expect_code 1 git diff -w $opts --exit-code -- x
37 '
38
39 test_expect_success "status with $opts (different but equivalent)" '
40 echo foo >x &&
41 git add x &&
42 echo " foo" >x &&
43 git diff -w $opts --exit-code x
44 '
45 done
46
47 test_expect_success "Ray Lehtiniemi's example" '
48 cat <<-\EOF >x &&
49 do {
50 nothing;
51 } while (0);
52 EOF
53 git update-index --add x &&
54 old_hash_x=$(git hash-object x) &&
55 before=$(git rev-parse --short "$old_hash_x") &&
56
57 cat <<-\EOF >x &&
58 do
59 {
60 nothing;
61 }
62 while (0);
63 EOF
64 new_hash_x=$(git hash-object x) &&
65 after=$(git rev-parse --short "$new_hash_x") &&
66
67 cat <<-EOF >expect &&
68 diff --git a/x b/x
69 index $before..$after 100644
70 --- a/x
71 +++ b/x
72 @@ -1,3 +1,5 @@
73 -do {
74 +do
75 +{
76 nothing;
77 -} while (0);
78 +}
79 +while (0);
80 EOF
81
82 git diff >out &&
83 test_cmp expect out &&
84
85 git diff -w >out &&
86 test_cmp expect out &&
87
88 git diff -b >out &&
89 test_cmp expect out
90 '
91
92 test_expect_success 'another test, without options' '
93 tr Q "\015" <<-\EOF >x &&
94 whitespace at beginning
95 whitespace change
96 whitespace in the middle
97 whitespace at end
98 unchanged line
99 CR at endQ
100 EOF
101
102 git update-index x &&
103 old_hash_x=$(git hash-object x) &&
104 before=$(git rev-parse --short "$old_hash_x") &&
105
106 tr "_" " " <<-\EOF >x &&
107 _ whitespace at beginning
108 whitespace change
109 white space in the middle
110 whitespace at end__
111 unchanged line
112 CR at end
113 EOF
114 new_hash_x=$(git hash-object x) &&
115 after=$(git rev-parse --short "$new_hash_x") &&
116
117 tr "Q_" "\015 " <<-EOF >expect &&
118 diff --git a/x b/x
119 index $before..$after 100644
120 --- a/x
121 +++ b/x
122 @@ -1,6 +1,6 @@
123 -whitespace at beginning
124 -whitespace change
125 -whitespace in the middle
126 -whitespace at end
127 + whitespace at beginning
128 +whitespace change
129 +white space in the middle
130 +whitespace at end__
131 unchanged line
132 -CR at endQ
133 +CR at end
134 EOF
135
136 git diff >out &&
137 test_cmp expect out &&
138
139 git diff -w >out &&
140 test_must_be_empty out &&
141
142 git diff -w -b >out &&
143 test_must_be_empty out &&
144
145 git diff -w --ignore-space-at-eol >out &&
146 test_must_be_empty out &&
147
148 git diff -w -b --ignore-space-at-eol >out &&
149 test_must_be_empty out &&
150
151 git diff -w --ignore-cr-at-eol >out &&
152 test_must_be_empty out &&
153
154 tr "Q_" "\015 " <<-EOF >expect &&
155 diff --git a/x b/x
156 index $before..$after 100644
157 --- a/x
158 +++ b/x
159 @@ -1,6 +1,6 @@
160 -whitespace at beginning
161 +_ whitespace at beginning
162 whitespace change
163 -whitespace in the middle
164 +white space in the middle
165 whitespace at end__
166 unchanged line
167 CR at end
168 EOF
169 git diff -b >out &&
170 test_cmp expect out &&
171
172 git diff -b --ignore-space-at-eol >out &&
173 test_cmp expect out &&
174
175 git diff -b --ignore-cr-at-eol >out &&
176 test_cmp expect out &&
177
178 tr "Q_" "\015 " <<-EOF >expect &&
179 diff --git a/x b/x
180 index $before..$after 100644
181 --- a/x
182 +++ b/x
183 @@ -1,6 +1,6 @@
184 -whitespace at beginning
185 -whitespace change
186 -whitespace in the middle
187 +_ whitespace at beginning
188 +whitespace change
189 +white space in the middle
190 whitespace at end__
191 unchanged line
192 CR at end
193 EOF
194 git diff --ignore-space-at-eol >out &&
195 test_cmp expect out &&
196
197 git diff --ignore-space-at-eol --ignore-cr-at-eol >out &&
198 test_cmp expect out &&
199
200 tr "Q_" "\015 " <<-EOF >expect &&
201 diff --git a/x b/x
202 index_$before..$after 100644
203 --- a/x
204 +++ b/x
205 @@ -1,6 +1,6 @@
206 -whitespace at beginning
207 -whitespace change
208 -whitespace in the middle
209 -whitespace at end
210 +_ whitespace at beginning
211 +whitespace_ _change
212 +white space in the middle
213 +whitespace at end__
214 unchanged line
215 CR at end
216 EOF
217 git diff --ignore-cr-at-eol >out &&
218 test_cmp expect out
219 '
220
221 test_expect_success 'ignore-blank-lines: only new lines' '
222 test_seq 5 >x &&
223 git update-index x &&
224 test_seq 5 | sed "/3/i\\
225 " >x &&
226 git diff --ignore-blank-lines >out &&
227 test_must_be_empty out
228 '
229
230 test_expect_success 'ignore-blank-lines: only new lines with space' '
231 test_seq 5 >x &&
232 git update-index x &&
233 test_seq 5 | sed "/3/i\\
234 " >x &&
235 git diff -w --ignore-blank-lines >out &&
236 test_must_be_empty out
237 '
238
239 test_expect_success 'ignore-blank-lines: after change' '
240 cat <<-\EOF >x &&
241 1
242 2
243
244 3
245 4
246 5
247
248 6
249 7
250 EOF
251 git update-index x &&
252 cat <<-\EOF >x &&
253 change
254
255 1
256 2
257 3
258 4
259 5
260 6
261
262 7
263 EOF
264 git diff --inter-hunk-context=100 --ignore-blank-lines >out.tmp &&
265 cat <<-\EOF >expected &&
266 diff --git a/x b/x
267 --- a/x
268 +++ b/x
269 @@ -1,6 +1,7 @@
270 +change
271 +
272 1
273 2
274 -
275 3
276 4
277 5
278 EOF
279 compare_diff_patch expected out.tmp
280 '
281
282 test_expect_success 'ignore-blank-lines: before change' '
283 cat <<-\EOF >x &&
284 1
285 2
286
287 3
288 4
289 5
290 6
291 7
292 EOF
293 git update-index x &&
294 cat <<-\EOF >x &&
295
296 1
297 2
298 3
299 4
300 5
301
302 6
303 7
304 change
305 EOF
306 git diff --inter-hunk-context=100 --ignore-blank-lines >out.tmp &&
307 cat <<-\EOF >expected &&
308 diff --git a/x b/x
309 --- a/x
310 +++ b/x
311 @@ -4,5 +4,7 @@
312 3
313 4
314 5
315 +
316 6
317 7
318 +change
319 EOF
320 compare_diff_patch expected out.tmp
321 '
322
323 test_expect_success 'ignore-blank-lines: between changes' '
324 cat <<-\EOF >x &&
325 1
326 2
327 3
328 4
329 5
330
331
332 6
333 7
334 8
335 9
336 10
337 EOF
338 git update-index x &&
339 cat <<-\EOF >x &&
340 change
341 1
342 2
343
344 3
345 4
346 5
347 6
348 7
349 8
350
351 9
352 10
353 change
354 EOF
355 git diff --ignore-blank-lines >out.tmp &&
356 cat <<-\EOF >expected &&
357 diff --git a/x b/x
358 --- a/x
359 +++ b/x
360 @@ -1,5 +1,7 @@
361 +change
362 1
363 2
364 +
365 3
366 4
367 5
368 @@ -8,5 +8,7 @@
369 6
370 7
371 8
372 +
373 9
374 10
375 +change
376 EOF
377 compare_diff_patch expected out.tmp
378 '
379
380 test_expect_success 'ignore-blank-lines: between changes (with interhunkctx)' '
381 test_seq 10 >x &&
382 git update-index x &&
383 cat <<-\EOF >x &&
384 change
385 1
386 2
387
388 3
389 4
390 5
391
392 6
393 7
394 8
395 9
396
397 10
398 change
399 EOF
400 git diff --inter-hunk-context=2 --ignore-blank-lines >out.tmp &&
401 cat <<-\EOF >expected &&
402 diff --git a/x b/x
403 --- a/x
404 +++ b/x
405 @@ -1,10 +1,15 @@
406 +change
407 1
408 2
409 +
410 3
411 4
412 5
413 +
414 6
415 7
416 8
417 9
418 +
419 10
420 +change
421 EOF
422 compare_diff_patch expected out.tmp
423 '
424
425 test_expect_success 'ignore-blank-lines: scattered spaces' '
426 test_seq 10 >x &&
427 git update-index x &&
428 cat <<-\EOF >x &&
429 change
430 1
431 2
432 3
433
434 4
435
436 5
437
438 6
439
440
441 7
442
443 8
444 9
445 10
446 change
447 EOF
448 git diff --inter-hunk-context=4 --ignore-blank-lines >out.tmp &&
449 cat <<-\EOF >expected &&
450 diff --git a/x b/x
451 --- a/x
452 +++ b/x
453 @@ -1,3 +1,4 @@
454 +change
455 1
456 2
457 3
458 @@ -8,3 +15,4 @@
459 8
460 9
461 10
462 +change
463 EOF
464 compare_diff_patch expected out.tmp
465 '
466
467 test_expect_success 'ignore-blank-lines: spaces coalesce' '
468 test_seq 6 >x &&
469 git update-index x &&
470 cat <<-\EOF >x &&
471 change
472 1
473 2
474 3
475
476 4
477
478 5
479
480 6
481 change
482 EOF
483 git diff --inter-hunk-context=4 --ignore-blank-lines >out.tmp &&
484 cat <<-\EOF >expected &&
485 diff --git a/x b/x
486 --- a/x
487 +++ b/x
488 @@ -1,6 +1,11 @@
489 +change
490 1
491 2
492 3
493 +
494 4
495 +
496 5
497 +
498 6
499 +change
500 EOF
501 compare_diff_patch expected out.tmp
502 '
503
504 test_expect_success 'ignore-blank-lines: mix changes and blank lines' '
505 test_seq 16 >x &&
506 git update-index x &&
507 cat <<-\EOF >x &&
508 change
509 1
510 2
511
512 3
513 4
514 5
515 change
516 6
517 7
518 8
519
520 9
521 10
522 11
523 change
524 12
525 13
526 14
527
528 15
529 16
530 change
531 EOF
532 git diff --ignore-blank-lines >out.tmp &&
533 cat <<-\EOF >expected &&
534 diff --git a/x b/x
535 --- a/x
536 +++ b/x
537 @@ -1,8 +1,11 @@
538 +change
539 1
540 2
541 +
542 3
543 4
544 5
545 +change
546 6
547 7
548 8
549 @@ -9,8 +13,11 @@
550 9
551 10
552 11
553 +change
554 12
555 13
556 14
557 +
558 15
559 16
560 +change
561 EOF
562 compare_diff_patch expected out.tmp
563 '
564
565 test_expect_success 'check mixed spaces and tabs in indent' '
566 # This is indented with SP HT SP.
567 echo " foo();" >x &&
568 test_must_fail git diff --check >check &&
569 grep "space before tab in indent" check
570 '
571
572 test_expect_success 'check mixed tabs and spaces in indent' '
573 # This is indented with HT SP HT.
574 echo " foo();" >x &&
575 test_must_fail git diff --check >check &&
576 grep "space before tab in indent" check
577 '
578
579 test_expect_success 'check with no whitespace errors' '
580 git commit -m "snapshot" &&
581 echo "foo();" >x &&
582 git diff --check
583 '
584
585 test_expect_success 'check with trailing whitespace' '
586 echo "foo(); " >x &&
587 test_must_fail git diff --check
588 '
589
590 test_expect_success 'check with space before tab in indent' '
591 # indent has space followed by hard tab
592 echo " foo();" >x &&
593 test_must_fail git diff --check
594 '
595
596 test_expect_success '--check and --exit-code are not exclusive' '
597 git checkout x &&
598 git diff --check --exit-code
599 '
600
601 test_expect_success '--check and --quiet are not exclusive' '
602 git diff --check --quiet
603 '
604
605 test_expect_success '-w and --exit-code interact sensibly' '
606 test_when_finished "git checkout x" &&
607 {
608 test_seq 15 &&
609 echo " 16"
610 } >x &&
611 test_must_fail git diff --exit-code &&
612 git diff -w >actual &&
613 test_must_be_empty actual &&
614 git diff -w --exit-code
615 '
616
617 test_expect_success '-I and --exit-code interact sensibly' '
618 test_when_finished "git checkout x" &&
619 {
620 test_seq 15 &&
621 echo " 16"
622 } >x &&
623 test_must_fail git diff --exit-code &&
624 git diff -I. >actual &&
625 test_must_be_empty actual &&
626 git diff -I. --exit-code
627 '
628
629 test_expect_success 'check staged with no whitespace errors' '
630 echo "foo();" >x &&
631 git add x &&
632 git diff --cached --check
633 '
634
635 test_expect_success 'check staged with trailing whitespace' '
636 echo "foo(); " >x &&
637 git add x &&
638 test_must_fail git diff --cached --check
639 '
640
641 test_expect_success 'check staged with space before tab in indent' '
642 # indent has space followed by hard tab
643 echo " foo();" >x &&
644 git add x &&
645 test_must_fail git diff --cached --check
646 '
647
648 test_expect_success 'check with no whitespace errors (diff-index)' '
649 echo "foo();" >x &&
650 git add x &&
651 git diff-index --check HEAD
652 '
653
654 test_expect_success 'check with trailing whitespace (diff-index)' '
655 echo "foo(); " >x &&
656 git add x &&
657 test_must_fail git diff-index --check HEAD
658 '
659
660 test_expect_success 'check with space before tab in indent (diff-index)' '
661 # indent has space followed by hard tab
662 echo " foo();" >x &&
663 git add x &&
664 test_must_fail git diff-index --check HEAD
665 '
666
667 test_expect_success 'check staged with no whitespace errors (diff-index)' '
668 echo "foo();" >x &&
669 git add x &&
670 git diff-index --cached --check HEAD
671 '
672
673 test_expect_success 'check staged with trailing whitespace (diff-index)' '
674 echo "foo(); " >x &&
675 git add x &&
676 test_must_fail git diff-index --cached --check HEAD
677 '
678
679 test_expect_success 'check staged with space before tab in indent (diff-index)' '
680 # indent has space followed by hard tab
681 echo " foo();" >x &&
682 git add x &&
683 test_must_fail git diff-index --cached --check HEAD
684 '
685
686 test_expect_success 'check with no whitespace errors (diff-tree)' '
687 echo "foo();" >x &&
688 git commit -m "new commit" x &&
689 git diff-tree --check HEAD^ HEAD
690 '
691
692 test_expect_success 'check with trailing whitespace (diff-tree)' '
693 echo "foo(); " >x &&
694 git commit -m "another commit" x &&
695 test_must_fail git diff-tree --check HEAD^ HEAD
696 '
697
698 test_expect_success 'check with space before tab in indent (diff-tree)' '
699 # indent has space followed by hard tab
700 echo " foo();" >x &&
701 git commit -m "yet another" x &&
702 test_must_fail git diff-tree --check HEAD^ HEAD
703 '
704
705 test_expect_success 'check with ignored trailing whitespace attr (diff-tree)' '
706 test_when_finished "git reset --hard HEAD^" &&
707
708 # create a whitespace error that should be ignored
709 echo "* -whitespace" >.gitattributes &&
710 git add .gitattributes &&
711 echo "foo(); " >x &&
712 git add x &&
713 git commit -m "add trailing space" &&
714
715 # with a worktree diff-tree ignores the whitespace error
716 git diff-tree --root --check HEAD &&
717
718 # without a worktree diff-tree still ignores the whitespace error
719 git -C .git diff-tree --root --check HEAD
720 '
721
722 test_expect_success 'check trailing whitespace (trailing-space: off)' '
723 git config core.whitespace "-trailing-space" &&
724 echo "foo (); " >x &&
725 git diff --check
726 '
727
728 test_expect_success 'check trailing whitespace (trailing-space: on)' '
729 git config core.whitespace "trailing-space" &&
730 echo "foo (); " >x &&
731 test_must_fail git diff --check
732 '
733
734 test_expect_success 'check space before tab in indent (space-before-tab: off)' '
735 # indent contains space followed by HT
736 git config core.whitespace "-space-before-tab" &&
737 echo " foo ();" >x &&
738 git diff --check
739 '
740
741 test_expect_success 'check space before tab in indent (space-before-tab: on)' '
742 # indent contains space followed by HT
743 git config core.whitespace "space-before-tab" &&
744 echo " foo (); " >x &&
745 test_must_fail git diff --check
746 '
747
748 test_expect_success 'check spaces as indentation (indent-with-non-tab: off)' '
749 git config core.whitespace "-indent-with-non-tab" &&
750 echo " foo ();" >x &&
751 git diff --check
752 '
753
754 test_expect_success 'check spaces as indentation (indent-with-non-tab: on)' '
755 git config core.whitespace "indent-with-non-tab" &&
756 echo " foo ();" >x &&
757 test_must_fail git diff --check
758 '
759
760 test_expect_success 'ditto, but tabwidth=9' '
761 git config core.whitespace "indent-with-non-tab,tabwidth=9" &&
762 git diff --check
763 '
764
765 test_expect_success 'check tabs and spaces as indentation (indent-with-non-tab: on)' '
766 git config core.whitespace "indent-with-non-tab" &&
767 echo " foo ();" >x &&
768 test_must_fail git diff --check
769 '
770
771 test_expect_success 'ditto, but tabwidth=10' '
772 git config core.whitespace "indent-with-non-tab,tabwidth=10" &&
773 test_must_fail git diff --check
774 '
775
776 test_expect_success 'ditto, but tabwidth=20' '
777 git config core.whitespace "indent-with-non-tab,tabwidth=20" &&
778 git diff --check
779 '
780
781 test_expect_success 'check tabs as indentation (tab-in-indent: off)' '
782 git config core.whitespace "-tab-in-indent" &&
783 echo " foo ();" >x &&
784 git diff --check
785 '
786
787 test_expect_success 'check tabs as indentation (tab-in-indent: on)' '
788 git config core.whitespace "tab-in-indent" &&
789 echo " foo ();" >x &&
790 test_must_fail git diff --check
791 '
792
793 test_expect_success 'check tabs and spaces as indentation (tab-in-indent: on)' '
794 git config core.whitespace "tab-in-indent" &&
795 echo " foo ();" >x &&
796 test_must_fail git diff --check
797 '
798
799 test_expect_success 'ditto, but tabwidth=1 (must be irrelevant)' '
800 git config core.whitespace "tab-in-indent,tabwidth=1" &&
801 test_must_fail git diff --check
802 '
803
804 test_expect_success 'check tab-in-indent and indent-with-non-tab conflict' '
805 git config core.whitespace "tab-in-indent,indent-with-non-tab" &&
806 echo "foo ();" >x &&
807 test_must_fail git diff --check
808 '
809
810 test_expect_success 'check tab-in-indent excluded from wildcard whitespace attribute' '
811 git config --unset core.whitespace &&
812 echo "x whitespace" >.gitattributes &&
813 echo " foo ();" >x &&
814 git diff --check &&
815 rm -f .gitattributes
816 '
817
818 test_expect_success 'line numbers in --check output are correct' '
819 echo "" >x &&
820 echo "foo(); " >>x &&
821 test_must_fail git diff --check >check &&
822 grep "x:2:" check
823 '
824
825 test_expect_success 'checkdiff detects new trailing blank lines (1)' '
826 echo "foo();" >x &&
827 echo "" >>x &&
828 test_must_fail git diff --check >check &&
829 grep "new blank line" check
830 '
831
832 test_expect_success 'checkdiff detects new trailing blank lines (2)' '
833 test_write_lines a b "" "" >x &&
834 git add x &&
835 test_write_lines a "" "" "" "" >x &&
836 test_must_fail git diff --check >check &&
837 grep "new blank line" check
838 '
839
840 test_expect_success 'checkdiff allows new blank lines' '
841 git checkout x &&
842 mv x y &&
843 (
844 echo "/* This is new */" &&
845 echo "" &&
846 cat y
847 ) >x &&
848 git diff --check
849 '
850
851 test_expect_success 'whitespace-only changes not reported (diff)' '
852 git reset --hard &&
853 echo >x "hello world" &&
854 git add x &&
855 git commit -m "hello 1" &&
856 echo >x "hello world" &&
857 git diff -b >actual &&
858 test_must_be_empty actual
859 '
860
861 test_expect_success 'whitespace-only changes not reported (diffstat)' '
862 # reuse state from previous test
863 git diff --stat -b >actual &&
864 test_must_be_empty actual
865 '
866
867 test_expect_success 'whitespace changes with modification reported (diffstat)' '
868 git reset --hard &&
869 echo >x "hello world" &&
870 git update-index --chmod=+x x &&
871 git diff --stat --cached -b >actual &&
872 cat <<-EOF >expect &&
873 x | 0
874 1 file changed, 0 insertions(+), 0 deletions(-)
875 EOF
876 test_cmp expect actual
877 '
878
879 test_expect_success 'whitespace-only changes reported across renames (diffstat)' '
880 git reset --hard &&
881 for i in 1 2 3 4 5 6 7 8 9; do echo "$i$i$i$i$i$i" || return 1; done >x &&
882 git add x &&
883 git commit -m "base" &&
884 sed -e "5s/^/ /" x >z &&
885 git rm x &&
886 git add z &&
887 git diff -w -M --cached --stat >actual &&
888 cat <<-EOF >expect &&
889 x => z | 0
890 1 file changed, 0 insertions(+), 0 deletions(-)
891 EOF
892 test_cmp expect actual
893 '
894
895 test_expect_success 'whitespace-only changes reported across renames' '
896 git reset --hard HEAD~1 &&
897 for i in 1 2 3 4 5 6 7 8 9; do echo "$i$i$i$i$i$i" || return 1; done >x &&
898 git add x &&
899 hash_x=$(git hash-object x) &&
900 before=$(git rev-parse --short "$hash_x") &&
901 git commit -m "base" &&
902 sed -e "5s/^/ /" x >z &&
903 git rm x &&
904 git add z &&
905 hash_z=$(git hash-object z) &&
906 after=$(git rev-parse --short "$hash_z") &&
907 git diff -w -M --cached >actual.raw &&
908 sed -e "/^similarity index /s/[0-9][0-9]*/NUM/" actual.raw >actual &&
909 cat <<-EOF >expect &&
910 diff --git a/x b/z
911 similarity index NUM%
912 rename from x
913 rename to z
914 index $before..$after 100644
915 EOF
916 test_cmp expect actual
917 '
918
919 cat >expected <<\EOF
920 diff --git a/empty b/void
921 similarity index 100%
922 rename from empty
923 rename to void
924 EOF
925
926 test_expect_success 'rename empty' '
927 git reset --hard &&
928 >empty &&
929 git add empty &&
930 git commit -m empty &&
931 git mv empty void &&
932 git diff -w --cached -M >current &&
933 test_cmp expected current
934 '
935
936 test_expect_success 'combined diff with autocrlf conversion' '
937
938 git reset --hard &&
939 test_commit "one side" x hello one-side &&
940 git checkout HEAD^ &&
941 echo >x goodbye &&
942 git commit -m "the other side" x &&
943 git config core.autocrlf true &&
944 test_must_fail git merge one-side >actual &&
945 test_i18ngrep "Automatic merge failed" actual &&
946
947 git diff >actual.raw &&
948 sed -e "1,/^@@@/d" actual.raw >actual &&
949 ! grep "^-" actual
950
951 '
952
953 # Start testing the colored format for whitespace checks
954
955 test_expect_success 'setup diff colors' '
956 git config color.diff.plain normal &&
957 git config color.diff.meta bold &&
958 git config color.diff.frag cyan &&
959 git config color.diff.func normal &&
960 git config color.diff.old red &&
961 git config color.diff.new green &&
962 git config color.diff.commit yellow &&
963 git config color.diff.whitespace blue &&
964
965 git config core.autocrlf false
966 '
967
968 test_expect_success 'diff that introduces a line with only tabs' '
969 git config core.whitespace blank-at-eol &&
970 git reset --hard &&
971 echo "test" >x &&
972 old_hash_x=$(git hash-object x) &&
973 before=$(git rev-parse --short "$old_hash_x") &&
974 git commit -m "initial" x &&
975 echo "{NTN}" | tr "NT" "\n\t" >>x &&
976 new_hash_x=$(git hash-object x) &&
977 after=$(git rev-parse --short "$new_hash_x") &&
978 git diff --color >current.raw &&
979 test_decode_color <current.raw >current &&
980
981 cat >expected <<-EOF &&
982 <BOLD>diff --git a/x b/x<RESET>
983 <BOLD>index $before..$after 100644<RESET>
984 <BOLD>--- a/x<RESET>
985 <BOLD>+++ b/x<RESET>
986 <CYAN>@@ -1 +1,4 @@<RESET>
987 test<RESET>
988 <GREEN>+<RESET><GREEN>{<RESET>
989 <GREEN>+<RESET><BLUE> <RESET>
990 <GREEN>+<RESET><GREEN>}<RESET>
991 EOF
992
993 test_cmp expected current
994 '
995
996 test_expect_success 'diff that introduces and removes ws breakages' '
997 git reset --hard &&
998 {
999 echo "0. blank-at-eol " &&
1000 echo "1. blank-at-eol "
1001 } >x &&
1002 old_hash_x=$(git hash-object x) &&
1003 before=$(git rev-parse --short "$old_hash_x") &&
1004 git commit -a --allow-empty -m preimage &&
1005 {
1006 echo "0. blank-at-eol " &&
1007 echo "1. still-blank-at-eol " &&
1008 echo "2. and a new line "
1009 } >x &&
1010 new_hash_x=$(git hash-object x) &&
1011 after=$(git rev-parse --short "$new_hash_x") &&
1012
1013 git diff --color >current.raw &&
1014 test_decode_color <current.raw >current &&
1015
1016 cat >expected <<-EOF &&
1017 <BOLD>diff --git a/x b/x<RESET>
1018 <BOLD>index $before..$after 100644<RESET>
1019 <BOLD>--- a/x<RESET>
1020 <BOLD>+++ b/x<RESET>
1021 <CYAN>@@ -1,2 +1,3 @@<RESET>
1022 0. blank-at-eol <RESET>
1023 <RED>-1. blank-at-eol <RESET>
1024 <GREEN>+<RESET><GREEN>1. still-blank-at-eol<RESET><BLUE> <RESET>
1025 <GREEN>+<RESET><GREEN>2. and a new line<RESET><BLUE> <RESET>
1026 EOF
1027
1028 test_cmp expected current
1029 '
1030
1031 test_expect_success 'ws-error-highlight test setup' '
1032
1033 git reset --hard &&
1034 {
1035 echo "0. blank-at-eol " &&
1036 echo "1. blank-at-eol "
1037 } >x &&
1038 old_hash_x=$(git hash-object x) &&
1039 before=$(git rev-parse --short "$old_hash_x") &&
1040 git commit -a --allow-empty -m preimage &&
1041 {
1042 echo "0. blank-at-eol " &&
1043 echo "1. still-blank-at-eol " &&
1044 echo "2. and a new line "
1045 } >x &&
1046 new_hash_x=$(git hash-object x) &&
1047 after=$(git rev-parse --short "$new_hash_x") &&
1048
1049 cat >expect.default-old <<-EOF &&
1050 <BOLD>diff --git a/x b/x<RESET>
1051 <BOLD>index $before..$after 100644<RESET>
1052 <BOLD>--- a/x<RESET>
1053 <BOLD>+++ b/x<RESET>
1054 <CYAN>@@ -1,2 +1,3 @@<RESET>
1055 0. blank-at-eol <RESET>
1056 <RED>-<RESET><RED>1. blank-at-eol<RESET><BLUE> <RESET>
1057 <GREEN>+<RESET><GREEN>1. still-blank-at-eol<RESET><BLUE> <RESET>
1058 <GREEN>+<RESET><GREEN>2. and a new line<RESET><BLUE> <RESET>
1059 EOF
1060
1061 cat >expect.all <<-EOF &&
1062 <BOLD>diff --git a/x b/x<RESET>
1063 <BOLD>index $before..$after 100644<RESET>
1064 <BOLD>--- a/x<RESET>
1065 <BOLD>+++ b/x<RESET>
1066 <CYAN>@@ -1,2 +1,3 @@<RESET>
1067 <RESET>0. blank-at-eol<RESET><BLUE> <RESET>
1068 <RED>-<RESET><RED>1. blank-at-eol<RESET><BLUE> <RESET>
1069 <GREEN>+<RESET><GREEN>1. still-blank-at-eol<RESET><BLUE> <RESET>
1070 <GREEN>+<RESET><GREEN>2. and a new line<RESET><BLUE> <RESET>
1071 EOF
1072
1073 cat >expect.none <<-EOF
1074 <BOLD>diff --git a/x b/x<RESET>
1075 <BOLD>index $before..$after 100644<RESET>
1076 <BOLD>--- a/x<RESET>
1077 <BOLD>+++ b/x<RESET>
1078 <CYAN>@@ -1,2 +1,3 @@<RESET>
1079 0. blank-at-eol <RESET>
1080 <RED>-1. blank-at-eol <RESET>
1081 <GREEN>+1. still-blank-at-eol <RESET>
1082 <GREEN>+2. and a new line <RESET>
1083 EOF
1084
1085 '
1086
1087 test_expect_success 'test --ws-error-highlight option' '
1088
1089 git diff --color --ws-error-highlight=default,old >current.raw &&
1090 test_decode_color <current.raw >current &&
1091 test_cmp expect.default-old current &&
1092
1093 git diff --color --ws-error-highlight=all >current.raw &&
1094 test_decode_color <current.raw >current &&
1095 test_cmp expect.all current &&
1096
1097 git diff --color --ws-error-highlight=none >current.raw &&
1098 test_decode_color <current.raw >current &&
1099 test_cmp expect.none current
1100
1101 '
1102
1103 test_expect_success 'test diff.wsErrorHighlight config' '
1104
1105 git -c diff.wsErrorHighlight=default,old diff --color >current.raw &&
1106 test_decode_color <current.raw >current &&
1107 test_cmp expect.default-old current &&
1108
1109 git -c diff.wsErrorHighlight=all diff --color >current.raw &&
1110 test_decode_color <current.raw >current &&
1111 test_cmp expect.all current &&
1112
1113 git -c diff.wsErrorHighlight=none diff --color >current.raw &&
1114 test_decode_color <current.raw >current &&
1115 test_cmp expect.none current
1116
1117 '
1118
1119 test_expect_success 'option overrides diff.wsErrorHighlight' '
1120
1121 git -c diff.wsErrorHighlight=none \
1122 diff --color --ws-error-highlight=default,old >current.raw &&
1123 test_decode_color <current.raw >current &&
1124 test_cmp expect.default-old current &&
1125
1126 git -c diff.wsErrorHighlight=default \
1127 diff --color --ws-error-highlight=all >current.raw &&
1128 test_decode_color <current.raw >current &&
1129 test_cmp expect.all current &&
1130
1131 git -c diff.wsErrorHighlight=all \
1132 diff --color --ws-error-highlight=none >current.raw &&
1133 test_decode_color <current.raw >current &&
1134 test_cmp expect.none current
1135
1136 '
1137
1138 test_expect_success 'detect moved code, complete file' '
1139 git reset --hard &&
1140 cat <<-\EOF >test.c &&
1141 #include<stdio.h>
1142 main()
1143 {
1144 printf("Hello World");
1145 }
1146 EOF
1147 git add test.c &&
1148 git commit -m "add main function" &&
1149 file=$(git rev-parse --short HEAD:test.c) &&
1150 git mv test.c main.c &&
1151 test_config color.diff.oldMoved "normal red" &&
1152 test_config color.diff.newMoved "normal green" &&
1153 git diff HEAD --color-moved=zebra --color --no-renames >actual.raw &&
1154 test_decode_color <actual.raw >actual &&
1155 cat >expected <<-EOF &&
1156 <BOLD>diff --git a/main.c b/main.c<RESET>
1157 <BOLD>new file mode 100644<RESET>
1158 <BOLD>index 0000000..$file<RESET>
1159 <BOLD>--- /dev/null<RESET>
1160 <BOLD>+++ b/main.c<RESET>
1161 <CYAN>@@ -0,0 +1,5 @@<RESET>
1162 <BGREEN>+<RESET><BGREEN>#include<stdio.h><RESET>
1163 <BGREEN>+<RESET><BGREEN>main()<RESET>
1164 <BGREEN>+<RESET><BGREEN>{<RESET>
1165 <BGREEN>+<RESET><BGREEN>printf("Hello World");<RESET>
1166 <BGREEN>+<RESET><BGREEN>}<RESET>
1167 <BOLD>diff --git a/test.c b/test.c<RESET>
1168 <BOLD>deleted file mode 100644<RESET>
1169 <BOLD>index $file..0000000<RESET>
1170 <BOLD>--- a/test.c<RESET>
1171 <BOLD>+++ /dev/null<RESET>
1172 <CYAN>@@ -1,5 +0,0 @@<RESET>
1173 <BRED>-#include<stdio.h><RESET>
1174 <BRED>-main()<RESET>
1175 <BRED>-{<RESET>
1176 <BRED>-printf("Hello World");<RESET>
1177 <BRED>-}<RESET>
1178 EOF
1179
1180 test_cmp expected actual
1181 '
1182
1183 test_expect_success 'detect malicious moved code, inside file' '
1184 test_config color.diff.oldMoved "normal red" &&
1185 test_config color.diff.newMoved "normal green" &&
1186 test_config color.diff.oldMovedAlternative "blue" &&
1187 test_config color.diff.newMovedAlternative "yellow" &&
1188 git reset --hard &&
1189 cat <<-\EOF >main.c &&
1190 #include<stdio.h>
1191 int stuff()
1192 {
1193 printf("Hello ");
1194 printf("World\n");
1195 }
1196
1197 int secure_foo(struct user *u)
1198 {
1199 if (!u->is_allowed_foo)
1200 return;
1201 foo(u);
1202 }
1203
1204 int main()
1205 {
1206 foo();
1207 }
1208 EOF
1209 cat <<-\EOF >test.c &&
1210 #include<stdio.h>
1211 int bar()
1212 {
1213 printf("Hello World, but different\n");
1214 }
1215
1216 int another_function()
1217 {
1218 bar();
1219 }
1220 EOF
1221 git add main.c test.c &&
1222 git commit -m "add main and test file" &&
1223 before_main=$(git rev-parse --short HEAD:main.c) &&
1224 before_test=$(git rev-parse --short HEAD:test.c) &&
1225 cat <<-\EOF >main.c &&
1226 #include<stdio.h>
1227 int stuff()
1228 {
1229 printf("Hello ");
1230 printf("World\n");
1231 }
1232
1233 int main()
1234 {
1235 foo();
1236 }
1237 EOF
1238 cat <<-\EOF >test.c &&
1239 #include<stdio.h>
1240 int bar()
1241 {
1242 printf("Hello World, but different\n");
1243 }
1244
1245 int secure_foo(struct user *u)
1246 {
1247 foo(u);
1248 if (!u->is_allowed_foo)
1249 return;
1250 }
1251
1252 int another_function()
1253 {
1254 bar();
1255 }
1256 EOF
1257 hash_main=$(git hash-object main.c) &&
1258 after_main=$(git rev-parse --short "$hash_main") &&
1259 hash_test=$(git hash-object test.c) &&
1260 after_test=$(git rev-parse --short "$hash_test") &&
1261 git diff HEAD --no-renames --color-moved=zebra --color >actual.raw &&
1262 test_decode_color <actual.raw >actual &&
1263 cat <<-EOF >expected &&
1264 <BOLD>diff --git a/main.c b/main.c<RESET>
1265 <BOLD>index $before_main..$after_main 100644<RESET>
1266 <BOLD>--- a/main.c<RESET>
1267 <BOLD>+++ b/main.c<RESET>
1268 <CYAN>@@ -5,13 +5,6 @@<RESET> <RESET>printf("Hello ");<RESET>
1269 printf("World\n");<RESET>
1270 }<RESET>
1271 <RESET>
1272 <BRED>-int secure_foo(struct user *u)<RESET>
1273 <BRED>-{<RESET>
1274 <BLUE>-if (!u->is_allowed_foo)<RESET>
1275 <BLUE>-return;<RESET>
1276 <RED>-foo(u);<RESET>
1277 <RED>-}<RESET>
1278 <RED>-<RESET>
1279 int main()<RESET>
1280 {<RESET>
1281 foo();<RESET>
1282 <BOLD>diff --git a/test.c b/test.c<RESET>
1283 <BOLD>index $before_test..$after_test 100644<RESET>
1284 <BOLD>--- a/test.c<RESET>
1285 <BOLD>+++ b/test.c<RESET>
1286 <CYAN>@@ -4,6 +4,13 @@<RESET> <RESET>int bar()<RESET>
1287 printf("Hello World, but different\n");<RESET>
1288 }<RESET>
1289 <RESET>
1290 <BGREEN>+<RESET><BGREEN>int secure_foo(struct user *u)<RESET>
1291 <BGREEN>+<RESET><BGREEN>{<RESET>
1292 <GREEN>+<RESET><GREEN>foo(u);<RESET>
1293 <BGREEN>+<RESET><BGREEN>if (!u->is_allowed_foo)<RESET>
1294 <BGREEN>+<RESET><BGREEN>return;<RESET>
1295 <GREEN>+<RESET><GREEN>}<RESET>
1296 <GREEN>+<RESET>
1297 int another_function()<RESET>
1298 {<RESET>
1299 bar();<RESET>
1300 EOF
1301
1302 test_cmp expected actual
1303 '
1304
1305 test_expect_success 'plain moved code, inside file' '
1306 test_config color.diff.oldMoved "normal red" &&
1307 test_config color.diff.newMoved "normal green" &&
1308 test_config color.diff.oldMovedAlternative "blue" &&
1309 test_config color.diff.newMovedAlternative "yellow" &&
1310 # needs previous test as setup
1311 git diff HEAD --no-renames --color-moved=plain --color >actual.raw &&
1312 test_decode_color <actual.raw >actual &&
1313 cat <<-EOF >expected &&
1314 <BOLD>diff --git a/main.c b/main.c<RESET>
1315 <BOLD>index $before_main..$after_main 100644<RESET>
1316 <BOLD>--- a/main.c<RESET>
1317 <BOLD>+++ b/main.c<RESET>
1318 <CYAN>@@ -5,13 +5,6 @@<RESET> <RESET>printf("Hello ");<RESET>
1319 printf("World\n");<RESET>
1320 }<RESET>
1321 <RESET>
1322 <BRED>-int secure_foo(struct user *u)<RESET>
1323 <BRED>-{<RESET>
1324 <BRED>-if (!u->is_allowed_foo)<RESET>
1325 <BRED>-return;<RESET>
1326 <BRED>-foo(u);<RESET>
1327 <BRED>-}<RESET>
1328 <BRED>-<RESET>
1329 int main()<RESET>
1330 {<RESET>
1331 foo();<RESET>
1332 <BOLD>diff --git a/test.c b/test.c<RESET>
1333 <BOLD>index $before_test..$after_test 100644<RESET>
1334 <BOLD>--- a/test.c<RESET>
1335 <BOLD>+++ b/test.c<RESET>
1336 <CYAN>@@ -4,6 +4,13 @@<RESET> <RESET>int bar()<RESET>
1337 printf("Hello World, but different\n");<RESET>
1338 }<RESET>
1339 <RESET>
1340 <BGREEN>+<RESET><BGREEN>int secure_foo(struct user *u)<RESET>
1341 <BGREEN>+<RESET><BGREEN>{<RESET>
1342 <BGREEN>+<RESET><BGREEN>foo(u);<RESET>
1343 <BGREEN>+<RESET><BGREEN>if (!u->is_allowed_foo)<RESET>
1344 <BGREEN>+<RESET><BGREEN>return;<RESET>
1345 <BGREEN>+<RESET><BGREEN>}<RESET>
1346 <BGREEN>+<RESET>
1347 int another_function()<RESET>
1348 {<RESET>
1349 bar();<RESET>
1350 EOF
1351
1352 test_cmp expected actual
1353 '
1354
1355 test_expect_success 'detect blocks of moved code' '
1356 git reset --hard &&
1357 cat <<-\EOF >lines.txt &&
1358 long line 1
1359 long line 2
1360 long line 3
1361 line 4
1362 line 5
1363 line 6
1364 line 7
1365 line 8
1366 line 9
1367 line 10
1368 line 11
1369 line 12
1370 line 13
1371 long line 14
1372 long line 15
1373 long line 16
1374 EOF
1375 git add lines.txt &&
1376 git commit -m "add poetry" &&
1377 cat <<-\EOF >lines.txt &&
1378 line 4
1379 line 5
1380 line 6
1381 line 7
1382 line 8
1383 line 9
1384 long line 1
1385 long line 2
1386 long line 3
1387 long line 14
1388 long line 15
1389 long line 16
1390 line 10
1391 line 11
1392 line 12
1393 line 13
1394 EOF
1395 test_config color.diff.oldMoved "magenta" &&
1396 test_config color.diff.newMoved "cyan" &&
1397 test_config color.diff.oldMovedAlternative "blue" &&
1398 test_config color.diff.newMovedAlternative "yellow" &&
1399 test_config color.diff.oldMovedDimmed "normal magenta" &&
1400 test_config color.diff.newMovedDimmed "normal cyan" &&
1401 test_config color.diff.oldMovedAlternativeDimmed "normal blue" &&
1402 test_config color.diff.newMovedAlternativeDimmed "normal yellow" &&
1403 git diff HEAD --no-renames --color-moved=blocks --color >actual.raw &&
1404 grep -v "index" actual.raw | test_decode_color >actual &&
1405 cat <<-\EOF >expected &&
1406 <BOLD>diff --git a/lines.txt b/lines.txt<RESET>
1407 <BOLD>--- a/lines.txt<RESET>
1408 <BOLD>+++ b/lines.txt<RESET>
1409 <CYAN>@@ -1,16 +1,16 @@<RESET>
1410 <MAGENTA>-long line 1<RESET>
1411 <MAGENTA>-long line 2<RESET>
1412 <MAGENTA>-long line 3<RESET>
1413 line 4<RESET>
1414 line 5<RESET>
1415 line 6<RESET>
1416 line 7<RESET>
1417 line 8<RESET>
1418 line 9<RESET>
1419 <CYAN>+<RESET><CYAN>long line 1<RESET>
1420 <CYAN>+<RESET><CYAN>long line 2<RESET>
1421 <CYAN>+<RESET><CYAN>long line 3<RESET>
1422 <CYAN>+<RESET><CYAN>long line 14<RESET>
1423 <CYAN>+<RESET><CYAN>long line 15<RESET>
1424 <CYAN>+<RESET><CYAN>long line 16<RESET>
1425 line 10<RESET>
1426 line 11<RESET>
1427 line 12<RESET>
1428 line 13<RESET>
1429 <MAGENTA>-long line 14<RESET>
1430 <MAGENTA>-long line 15<RESET>
1431 <MAGENTA>-long line 16<RESET>
1432 EOF
1433 test_cmp expected actual
1434
1435 '
1436
1437 test_expect_success 'detect permutations inside moved code -- dimmed-zebra' '
1438 # reuse setup from test before!
1439 test_config color.diff.oldMoved "magenta" &&
1440 test_config color.diff.newMoved "cyan" &&
1441 test_config color.diff.oldMovedAlternative "blue" &&
1442 test_config color.diff.newMovedAlternative "yellow" &&
1443 test_config color.diff.oldMovedDimmed "normal magenta" &&
1444 test_config color.diff.newMovedDimmed "normal cyan" &&
1445 test_config color.diff.oldMovedAlternativeDimmed "normal blue" &&
1446 test_config color.diff.newMovedAlternativeDimmed "normal yellow" &&
1447 git diff HEAD --no-renames --color-moved=dimmed-zebra --color >actual.raw &&
1448 grep -v "index" actual.raw | test_decode_color >actual &&
1449 cat <<-\EOF >expected &&
1450 <BOLD>diff --git a/lines.txt b/lines.txt<RESET>
1451 <BOLD>--- a/lines.txt<RESET>
1452 <BOLD>+++ b/lines.txt<RESET>
1453 <CYAN>@@ -1,16 +1,16 @@<RESET>
1454 <BMAGENTA>-long line 1<RESET>
1455 <BMAGENTA>-long line 2<RESET>
1456 <BMAGENTA>-long line 3<RESET>
1457 line 4<RESET>
1458 line 5<RESET>
1459 line 6<RESET>
1460 line 7<RESET>
1461 line 8<RESET>
1462 line 9<RESET>
1463 <BCYAN>+<RESET><BCYAN>long line 1<RESET>
1464 <BCYAN>+<RESET><BCYAN>long line 2<RESET>
1465 <CYAN>+<RESET><CYAN>long line 3<RESET>
1466 <YELLOW>+<RESET><YELLOW>long line 14<RESET>
1467 <BYELLOW>+<RESET><BYELLOW>long line 15<RESET>
1468 <BYELLOW>+<RESET><BYELLOW>long line 16<RESET>
1469 line 10<RESET>
1470 line 11<RESET>
1471 line 12<RESET>
1472 line 13<RESET>
1473 <BMAGENTA>-long line 14<RESET>
1474 <BMAGENTA>-long line 15<RESET>
1475 <BMAGENTA>-long line 16<RESET>
1476 EOF
1477 test_cmp expected actual
1478 '
1479
1480 test_expect_success 'zebra alternate color is only used when necessary' '
1481 cat >old.txt <<-\EOF &&
1482 line 1A should be marked as oldMoved newMovedAlternate
1483 line 1B should be marked as oldMoved newMovedAlternate
1484 unchanged
1485 line 2A should be marked as oldMoved newMovedAlternate
1486 line 2B should be marked as oldMoved newMovedAlternate
1487 line 3A should be marked as oldMovedAlternate newMoved
1488 line 3B should be marked as oldMovedAlternate newMoved
1489 unchanged
1490 line 4A should be marked as oldMoved newMovedAlternate
1491 line 4B should be marked as oldMoved newMovedAlternate
1492 line 5A should be marked as oldMovedAlternate newMoved
1493 line 5B should be marked as oldMovedAlternate newMoved
1494 line 6A should be marked as oldMoved newMoved
1495 line 6B should be marked as oldMoved newMoved
1496 EOF
1497 cat >new.txt <<-\EOF &&
1498 line 1A should be marked as oldMoved newMovedAlternate
1499 line 1B should be marked as oldMoved newMovedAlternate
1500 unchanged
1501 line 3A should be marked as oldMovedAlternate newMoved
1502 line 3B should be marked as oldMovedAlternate newMoved
1503 line 2A should be marked as oldMoved newMovedAlternate
1504 line 2B should be marked as oldMoved newMovedAlternate
1505 unchanged
1506 line 6A should be marked as oldMoved newMoved
1507 line 6B should be marked as oldMoved newMoved
1508 line 4A should be marked as oldMoved newMovedAlternate
1509 line 4B should be marked as oldMoved newMovedAlternate
1510 line 5A should be marked as oldMovedAlternate newMoved
1511 line 5B should be marked as oldMovedAlternate newMoved
1512 EOF
1513 test_expect_code 1 git diff --no-index --color --color-moved=zebra \
1514 --color-moved-ws=allow-indentation-change \
1515 old.txt new.txt >output &&
1516 grep -v index output | test_decode_color >actual &&
1517 cat >expected <<-\EOF &&
1518 <BOLD>diff --git a/old.txt b/new.txt<RESET>
1519 <BOLD>--- a/old.txt<RESET>
1520 <BOLD>+++ b/new.txt<RESET>
1521 <CYAN>@@ -1,14 +1,14 @@<RESET>
1522 <BOLD;MAGENTA>-line 1A should be marked as oldMoved newMovedAlternate<RESET>
1523 <BOLD;MAGENTA>-line 1B should be marked as oldMoved newMovedAlternate<RESET>
1524 <BOLD;CYAN>+<RESET><BOLD;CYAN> line 1A should be marked as oldMoved newMovedAlternate<RESET>
1525 <BOLD;CYAN>+<RESET><BOLD;CYAN> line 1B should be marked as oldMoved newMovedAlternate<RESET>
1526 unchanged<RESET>
1527 <BOLD;MAGENTA>-line 2A should be marked as oldMoved newMovedAlternate<RESET>
1528 <BOLD;MAGENTA>-line 2B should be marked as oldMoved newMovedAlternate<RESET>
1529 <BOLD;BLUE>-line 3A should be marked as oldMovedAlternate newMoved<RESET>
1530 <BOLD;BLUE>-line 3B should be marked as oldMovedAlternate newMoved<RESET>
1531 <BOLD;CYAN>+<RESET><BOLD;CYAN> line 3A should be marked as oldMovedAlternate newMoved<RESET>
1532 <BOLD;CYAN>+<RESET><BOLD;CYAN> line 3B should be marked as oldMovedAlternate newMoved<RESET>
1533 <BOLD;YELLOW>+<RESET><BOLD;YELLOW> line 2A should be marked as oldMoved newMovedAlternate<RESET>
1534 <BOLD;YELLOW>+<RESET><BOLD;YELLOW> line 2B should be marked as oldMoved newMovedAlternate<RESET>
1535 unchanged<RESET>
1536 <BOLD;MAGENTA>-line 4A should be marked as oldMoved newMovedAlternate<RESET>
1537 <BOLD;MAGENTA>-line 4B should be marked as oldMoved newMovedAlternate<RESET>
1538 <BOLD;BLUE>-line 5A should be marked as oldMovedAlternate newMoved<RESET>
1539 <BOLD;BLUE>-line 5B should be marked as oldMovedAlternate newMoved<RESET>
1540 <BOLD;MAGENTA>-line 6A should be marked as oldMoved newMoved<RESET>
1541 <BOLD;MAGENTA>-line 6B should be marked as oldMoved newMoved<RESET>
1542 <BOLD;CYAN>+<RESET><BOLD;CYAN> line 6A should be marked as oldMoved newMoved<RESET>
1543 <BOLD;CYAN>+<RESET><BOLD;CYAN> line 6B should be marked as oldMoved newMoved<RESET>
1544 <BOLD;YELLOW>+<RESET><BOLD;YELLOW> line 4A should be marked as oldMoved newMovedAlternate<RESET>
1545 <BOLD;YELLOW>+<RESET><BOLD;YELLOW> line 4B should be marked as oldMoved newMovedAlternate<RESET>
1546 <BOLD;CYAN>+<RESET><BOLD;CYAN> line 5A should be marked as oldMovedAlternate newMoved<RESET>
1547 <BOLD;CYAN>+<RESET><BOLD;CYAN> line 5B should be marked as oldMovedAlternate newMoved<RESET>
1548 EOF
1549 test_cmp expected actual
1550 '
1551
1552 test_expect_success 'short lines of opposite sign do not get marked as moved' '
1553 cat >old.txt <<-\EOF &&
1554 this line should be marked as moved
1555 unchanged
1556 unchanged
1557 unchanged
1558 unchanged
1559 too short
1560 this line should be marked as oldMoved newMoved
1561 this line should be marked as oldMovedAlternate newMoved
1562 unchanged 1
1563 unchanged 2
1564 unchanged 3
1565 unchanged 4
1566 this line should be marked as oldMoved newMoved/newMovedAlternate
1567 EOF
1568 cat >new.txt <<-\EOF &&
1569 too short
1570 unchanged
1571 unchanged
1572 this line should be marked as moved
1573 too short
1574 unchanged
1575 unchanged
1576 this line should be marked as oldMoved newMoved/newMovedAlternate
1577 unchanged 1
1578 unchanged 2
1579 this line should be marked as oldMovedAlternate newMoved
1580 this line should be marked as oldMoved newMoved/newMovedAlternate
1581 unchanged 3
1582 this line should be marked as oldMoved newMoved
1583 unchanged 4
1584 EOF
1585 test_expect_code 1 git diff --no-index --color --color-moved=zebra \
1586 old.txt new.txt >output && cat output &&
1587 grep -v index output | test_decode_color >actual &&
1588 cat >expect <<-\EOF &&
1589 <BOLD>diff --git a/old.txt b/new.txt<RESET>
1590 <BOLD>--- a/old.txt<RESET>
1591 <BOLD>+++ b/new.txt<RESET>
1592 <CYAN>@@ -1,13 +1,15 @@<RESET>
1593 <BOLD;MAGENTA>-this line should be marked as moved<RESET>
1594 <GREEN>+<RESET><GREEN>too short<RESET>
1595 unchanged<RESET>
1596 unchanged<RESET>
1597 <BOLD;CYAN>+<RESET><BOLD;CYAN>this line should be marked as moved<RESET>
1598 <GREEN>+<RESET><GREEN>too short<RESET>
1599 unchanged<RESET>
1600 unchanged<RESET>
1601 <RED>-too short<RESET>
1602 <BOLD;MAGENTA>-this line should be marked as oldMoved newMoved<RESET>
1603 <BOLD;BLUE>-this line should be marked as oldMovedAlternate newMoved<RESET>
1604 <BOLD;CYAN>+<RESET><BOLD;CYAN>this line should be marked as oldMoved newMoved/newMovedAlternate<RESET>
1605 unchanged 1<RESET>
1606 unchanged 2<RESET>
1607 <BOLD;CYAN>+<RESET><BOLD;CYAN>this line should be marked as oldMovedAlternate newMoved<RESET>
1608 <BOLD;YELLOW>+<RESET><BOLD;YELLOW>this line should be marked as oldMoved newMoved/newMovedAlternate<RESET>
1609 unchanged 3<RESET>
1610 <BOLD;CYAN>+<RESET><BOLD;CYAN>this line should be marked as oldMoved newMoved<RESET>
1611 unchanged 4<RESET>
1612 <BOLD;MAGENTA>-this line should be marked as oldMoved newMoved/newMovedAlternate<RESET>
1613 EOF
1614 test_cmp expect actual
1615 '
1616
1617 test_expect_success 'cmd option assumes configured colored-moved' '
1618 test_config color.diff.oldMoved "magenta" &&
1619 test_config color.diff.newMoved "cyan" &&
1620 test_config color.diff.oldMovedAlternative "blue" &&
1621 test_config color.diff.newMovedAlternative "yellow" &&
1622 test_config color.diff.oldMovedDimmed "normal magenta" &&
1623 test_config color.diff.newMovedDimmed "normal cyan" &&
1624 test_config color.diff.oldMovedAlternativeDimmed "normal blue" &&
1625 test_config color.diff.newMovedAlternativeDimmed "normal yellow" &&
1626 test_config diff.colorMoved zebra &&
1627 git diff HEAD --no-renames --color-moved --color >actual.raw &&
1628 grep -v "index" actual.raw | test_decode_color >actual &&
1629 cat <<-\EOF >expected &&
1630 <BOLD>diff --git a/lines.txt b/lines.txt<RESET>
1631 <BOLD>--- a/lines.txt<RESET>
1632 <BOLD>+++ b/lines.txt<RESET>
1633 <CYAN>@@ -1,16 +1,16 @@<RESET>
1634 <MAGENTA>-long line 1<RESET>
1635 <MAGENTA>-long line 2<RESET>
1636 <MAGENTA>-long line 3<RESET>
1637 line 4<RESET>
1638 line 5<RESET>
1639 line 6<RESET>
1640 line 7<RESET>
1641 line 8<RESET>
1642 line 9<RESET>
1643 <CYAN>+<RESET><CYAN>long line 1<RESET>
1644 <CYAN>+<RESET><CYAN>long line 2<RESET>
1645 <CYAN>+<RESET><CYAN>long line 3<RESET>
1646 <YELLOW>+<RESET><YELLOW>long line 14<RESET>
1647 <YELLOW>+<RESET><YELLOW>long line 15<RESET>
1648 <YELLOW>+<RESET><YELLOW>long line 16<RESET>
1649 line 10<RESET>
1650 line 11<RESET>
1651 line 12<RESET>
1652 line 13<RESET>
1653 <MAGENTA>-long line 14<RESET>
1654 <MAGENTA>-long line 15<RESET>
1655 <MAGENTA>-long line 16<RESET>
1656 EOF
1657 test_cmp expected actual
1658 '
1659
1660 test_expect_success 'no effect on diff from --color-moved with --word-diff' '
1661 cat <<-\EOF >text.txt &&
1662 Lorem Ipsum is simply dummy text of the printing and typesetting industry.
1663 EOF
1664 git add text.txt &&
1665 git commit -a -m "clean state" &&
1666 cat <<-\EOF >text.txt &&
1667 simply Lorem Ipsum dummy is text of the typesetting and printing industry.
1668 EOF
1669 git diff --color-moved --word-diff >actual &&
1670 git diff --word-diff >expect &&
1671 test_cmp expect actual
1672 '
1673
1674 test_expect_success !SANITIZE_LEAK 'no effect on show from --color-moved with --word-diff' '
1675 git show --color-moved --word-diff >actual &&
1676 git show --word-diff >expect &&
1677 test_cmp expect actual
1678 '
1679
1680 test_expect_success 'set up whitespace tests' '
1681 git reset --hard &&
1682 # Note that these lines have no leading or trailing whitespace.
1683 cat <<-\EOF >lines.txt &&
1684 line 1
1685 line 2
1686 line 3
1687 line 4
1688 line 5
1689 long line 6
1690 long line 7
1691 long line 8
1692 long line 9
1693 EOF
1694 git add lines.txt &&
1695 git commit -m "add poetry" &&
1696 git config color.diff.oldMoved "magenta" &&
1697 git config color.diff.newMoved "cyan"
1698 '
1699
1700 test_expect_success 'move detection ignoring whitespace ' '
1701 q_to_tab <<-\EOF >lines.txt &&
1702 Qlong line 6
1703 Qlong line 7
1704 Qlong line 8
1705 Qchanged long line 9
1706 line 1
1707 line 2
1708 line 3
1709 line 4
1710 line 5
1711 EOF
1712 git diff HEAD --no-renames --color-moved --color >actual.raw &&
1713 grep -v "index" actual.raw | test_decode_color >actual &&
1714 cat <<-\EOF >expected &&
1715 <BOLD>diff --git a/lines.txt b/lines.txt<RESET>
1716 <BOLD>--- a/lines.txt<RESET>
1717 <BOLD>+++ b/lines.txt<RESET>
1718 <CYAN>@@ -1,9 +1,9 @@<RESET>
1719 <GREEN>+<RESET> <GREEN>long line 6<RESET>
1720 <GREEN>+<RESET> <GREEN>long line 7<RESET>
1721 <GREEN>+<RESET> <GREEN>long line 8<RESET>
1722 <GREEN>+<RESET> <GREEN>changed long line 9<RESET>
1723 line 1<RESET>
1724 line 2<RESET>
1725 line 3<RESET>
1726 line 4<RESET>
1727 line 5<RESET>
1728 <RED>-long line 6<RESET>
1729 <RED>-long line 7<RESET>
1730 <RED>-long line 8<RESET>
1731 <RED>-long line 9<RESET>
1732 EOF
1733 test_cmp expected actual &&
1734
1735 git diff HEAD --no-renames --color-moved --color \
1736 --color-moved-ws=ignore-all-space >actual.raw &&
1737 grep -v "index" actual.raw | test_decode_color >actual &&
1738 cat <<-\EOF >expected &&
1739 <BOLD>diff --git a/lines.txt b/lines.txt<RESET>
1740 <BOLD>--- a/lines.txt<RESET>
1741 <BOLD>+++ b/lines.txt<RESET>
1742 <CYAN>@@ -1,9 +1,9 @@<RESET>
1743 <CYAN>+<RESET> <CYAN>long line 6<RESET>
1744 <CYAN>+<RESET> <CYAN>long line 7<RESET>
1745 <CYAN>+<RESET> <CYAN>long line 8<RESET>
1746 <GREEN>+<RESET> <GREEN>changed long line 9<RESET>
1747 line 1<RESET>
1748 line 2<RESET>
1749 line 3<RESET>
1750 line 4<RESET>
1751 line 5<RESET>
1752 <MAGENTA>-long line 6<RESET>
1753 <MAGENTA>-long line 7<RESET>
1754 <MAGENTA>-long line 8<RESET>
1755 <RED>-long line 9<RESET>
1756 EOF
1757 test_cmp expected actual
1758 '
1759
1760 test_expect_success 'move detection ignoring whitespace changes' '
1761 git reset --hard &&
1762 # Lines 6-8 have a space change, but 9 is new whitespace
1763 q_to_tab <<-\EOF >lines.txt &&
1764 longQline 6
1765 longQline 7
1766 longQline 8
1767 long liQne 9
1768 line 1
1769 line 2
1770 line 3
1771 line 4
1772 line 5
1773 EOF
1774
1775 git diff HEAD --no-renames --color-moved --color >actual.raw &&
1776 grep -v "index" actual.raw | test_decode_color >actual &&
1777 cat <<-\EOF >expected &&
1778 <BOLD>diff --git a/lines.txt b/lines.txt<RESET>
1779 <BOLD>--- a/lines.txt<RESET>
1780 <BOLD>+++ b/lines.txt<RESET>
1781 <CYAN>@@ -1,9 +1,9 @@<RESET>
1782 <GREEN>+<RESET><GREEN>long line 6<RESET>
1783 <GREEN>+<RESET><GREEN>long line 7<RESET>
1784 <GREEN>+<RESET><GREEN>long line 8<RESET>
1785 <GREEN>+<RESET><GREEN>long li ne 9<RESET>
1786 line 1<RESET>
1787 line 2<RESET>
1788 line 3<RESET>
1789 line 4<RESET>
1790 line 5<RESET>
1791 <RED>-long line 6<RESET>
1792 <RED>-long line 7<RESET>
1793 <RED>-long line 8<RESET>
1794 <RED>-long line 9<RESET>
1795 EOF
1796 test_cmp expected actual &&
1797
1798 git diff HEAD --no-renames --color-moved --color \
1799 --color-moved-ws=ignore-space-change >actual.raw &&
1800 grep -v "index" actual.raw | test_decode_color >actual &&
1801 cat <<-\EOF >expected &&
1802 <BOLD>diff --git a/lines.txt b/lines.txt<RESET>
1803 <BOLD>--- a/lines.txt<RESET>
1804 <BOLD>+++ b/lines.txt<RESET>
1805 <CYAN>@@ -1,9 +1,9 @@<RESET>
1806 <CYAN>+<RESET><CYAN>long line 6<RESET>
1807 <CYAN>+<RESET><CYAN>long line 7<RESET>
1808 <CYAN>+<RESET><CYAN>long line 8<RESET>
1809 <GREEN>+<RESET><GREEN>long li ne 9<RESET>
1810 line 1<RESET>
1811 line 2<RESET>
1812 line 3<RESET>
1813 line 4<RESET>
1814 line 5<RESET>
1815 <MAGENTA>-long line 6<RESET>
1816 <MAGENTA>-long line 7<RESET>
1817 <MAGENTA>-long line 8<RESET>
1818 <RED>-long line 9<RESET>
1819 EOF
1820 test_cmp expected actual
1821 '
1822
1823 test_expect_success 'move detection ignoring whitespace at eol' '
1824 git reset --hard &&
1825 # Lines 6-9 have new eol whitespace, but 9 also has it in the middle
1826 q_to_tab <<-\EOF >lines.txt &&
1827 long line 6Q
1828 long line 7Q
1829 long line 8Q
1830 longQline 9Q
1831 line 1
1832 line 2
1833 line 3
1834 line 4
1835 line 5
1836 EOF
1837
1838 # avoid cluttering the output with complaints about our eol whitespace
1839 test_config core.whitespace -blank-at-eol &&
1840
1841 git diff HEAD --no-renames --color-moved --color >actual.raw &&
1842 grep -v "index" actual.raw | test_decode_color >actual &&
1843 cat <<-\EOF >expected &&
1844 <BOLD>diff --git a/lines.txt b/lines.txt<RESET>
1845 <BOLD>--- a/lines.txt<RESET>
1846 <BOLD>+++ b/lines.txt<RESET>
1847 <CYAN>@@ -1,9 +1,9 @@<RESET>
1848 <GREEN>+<RESET><GREEN>long line 6 <RESET>
1849 <GREEN>+<RESET><GREEN>long line 7 <RESET>
1850 <GREEN>+<RESET><GREEN>long line 8 <RESET>
1851 <GREEN>+<RESET><GREEN>long line 9 <RESET>
1852 line 1<RESET>
1853 line 2<RESET>
1854 line 3<RESET>
1855 line 4<RESET>
1856 line 5<RESET>
1857 <RED>-long line 6<RESET>
1858 <RED>-long line 7<RESET>
1859 <RED>-long line 8<RESET>
1860 <RED>-long line 9<RESET>
1861 EOF
1862 test_cmp expected actual &&
1863
1864 git diff HEAD --no-renames --color-moved --color \
1865 --color-moved-ws=ignore-space-at-eol >actual.raw &&
1866 grep -v "index" actual.raw | test_decode_color >actual &&
1867 cat <<-\EOF >expected &&
1868 <BOLD>diff --git a/lines.txt b/lines.txt<RESET>
1869 <BOLD>--- a/lines.txt<RESET>
1870 <BOLD>+++ b/lines.txt<RESET>
1871 <CYAN>@@ -1,9 +1,9 @@<RESET>
1872 <CYAN>+<RESET><CYAN>long line 6 <RESET>
1873 <CYAN>+<RESET><CYAN>long line 7 <RESET>
1874 <CYAN>+<RESET><CYAN>long line 8 <RESET>
1875 <GREEN>+<RESET><GREEN>long line 9 <RESET>
1876 line 1<RESET>
1877 line 2<RESET>
1878 line 3<RESET>
1879 line 4<RESET>
1880 line 5<RESET>
1881 <MAGENTA>-long line 6<RESET>
1882 <MAGENTA>-long line 7<RESET>
1883 <MAGENTA>-long line 8<RESET>
1884 <RED>-long line 9<RESET>
1885 EOF
1886 test_cmp expected actual
1887 '
1888
1889 test_expect_success 'clean up whitespace-test colors' '
1890 git config --unset color.diff.oldMoved &&
1891 git config --unset color.diff.newMoved
1892 '
1893
1894 test_expect_success '--color-moved block at end of diff output respects MIN_ALNUM_COUNT' '
1895 git reset --hard &&
1896 >bar &&
1897 cat <<-\EOF >foo &&
1898 irrelevant_line
1899 line1
1900 EOF
1901 git add foo bar &&
1902 git commit -m x &&
1903
1904 cat <<-\EOF >bar &&
1905 line1
1906 EOF
1907 cat <<-\EOF >foo &&
1908 irrelevant_line
1909 EOF
1910
1911 git diff HEAD --color-moved=zebra --color --no-renames >actual.raw &&
1912 grep -v "index" actual.raw | test_decode_color >actual &&
1913 cat >expected <<-\EOF &&
1914 <BOLD>diff --git a/bar b/bar<RESET>
1915 <BOLD>--- a/bar<RESET>
1916 <BOLD>+++ b/bar<RESET>
1917 <CYAN>@@ -0,0 +1 @@<RESET>
1918 <GREEN>+<RESET><GREEN>line1<RESET>
1919 <BOLD>diff --git a/foo b/foo<RESET>
1920 <BOLD>--- a/foo<RESET>
1921 <BOLD>+++ b/foo<RESET>
1922 <CYAN>@@ -1,2 +1 @@<RESET>
1923 irrelevant_line<RESET>
1924 <RED>-line1<RESET>
1925 EOF
1926
1927 test_cmp expected actual
1928 '
1929
1930 test_expect_success '--color-moved respects MIN_ALNUM_COUNT' '
1931 git reset --hard &&
1932 cat <<-\EOF >foo &&
1933 nineteen chars 456789
1934 irrelevant_line
1935 twenty chars 234567890
1936 EOF
1937 >bar &&
1938 git add foo bar &&
1939 git commit -m x &&
1940
1941 cat <<-\EOF >foo &&
1942 irrelevant_line
1943 EOF
1944 cat <<-\EOF >bar &&
1945 twenty chars 234567890
1946 nineteen chars 456789
1947 EOF
1948
1949 git diff HEAD --color-moved=zebra --color --no-renames >actual.raw &&
1950 grep -v "index" actual.raw | test_decode_color >actual &&
1951 cat >expected <<-\EOF &&
1952 <BOLD>diff --git a/bar b/bar<RESET>
1953 <BOLD>--- a/bar<RESET>
1954 <BOLD>+++ b/bar<RESET>
1955 <CYAN>@@ -0,0 +1,2 @@<RESET>
1956 <BOLD;CYAN>+<RESET><BOLD;CYAN>twenty chars 234567890<RESET>
1957 <GREEN>+<RESET><GREEN>nineteen chars 456789<RESET>
1958 <BOLD>diff --git a/foo b/foo<RESET>
1959 <BOLD>--- a/foo<RESET>
1960 <BOLD>+++ b/foo<RESET>
1961 <CYAN>@@ -1,3 +1 @@<RESET>
1962 <RED>-nineteen chars 456789<RESET>
1963 irrelevant_line<RESET>
1964 <BOLD;MAGENTA>-twenty chars 234567890<RESET>
1965 EOF
1966
1967 test_cmp expected actual
1968 '
1969
1970 test_expect_success '--color-moved treats adjacent blocks as separate for MIN_ALNUM_COUNT' '
1971 git reset --hard &&
1972 cat <<-\EOF >foo &&
1973 7charsA
1974 irrelevant_line
1975 7charsB
1976 7charsC
1977 EOF
1978 >bar &&
1979 git add foo bar &&
1980 git commit -m x &&
1981
1982 cat <<-\EOF >foo &&
1983 irrelevant_line
1984 EOF
1985 cat <<-\EOF >bar &&
1986 7charsB
1987 7charsC
1988 7charsA
1989 EOF
1990
1991 git diff HEAD --color-moved=zebra --color --no-renames >actual.raw &&
1992 grep -v "index" actual.raw | test_decode_color >actual &&
1993 cat >expected <<-\EOF &&
1994 <BOLD>diff --git a/bar b/bar<RESET>
1995 <BOLD>--- a/bar<RESET>
1996 <BOLD>+++ b/bar<RESET>
1997 <CYAN>@@ -0,0 +1,3 @@<RESET>
1998 <GREEN>+<RESET><GREEN>7charsB<RESET>
1999 <GREEN>+<RESET><GREEN>7charsC<RESET>
2000 <GREEN>+<RESET><GREEN>7charsA<RESET>
2001 <BOLD>diff --git a/foo b/foo<RESET>
2002 <BOLD>--- a/foo<RESET>
2003 <BOLD>+++ b/foo<RESET>
2004 <CYAN>@@ -1,4 +1 @@<RESET>
2005 <RED>-7charsA<RESET>
2006 irrelevant_line<RESET>
2007 <RED>-7charsB<RESET>
2008 <RED>-7charsC<RESET>
2009 EOF
2010
2011 test_cmp expected actual
2012 '
2013
2014 test_expect_success '--color-moved rewinds for MIN_ALNUM_COUNT' '
2015 git reset --hard &&
2016 test_write_lines >file \
2017 A B C one two three four five six seven D E F G H I J &&
2018 git add file &&
2019 test_write_lines >file \
2020 one two A B C D E F G H I J two three four five six seven &&
2021 git diff --color-moved=zebra -- file &&
2022
2023 git diff --color-moved=zebra --color -- file >actual.raw &&
2024 grep -v "index" actual.raw | test_decode_color >actual &&
2025 cat >expected <<-\EOF &&
2026 <BOLD>diff --git a/file b/file<RESET>
2027 <BOLD>--- a/file<RESET>
2028 <BOLD>+++ b/file<RESET>
2029 <CYAN>@@ -1,13 +1,8 @@<RESET>
2030 <GREEN>+<RESET><GREEN>one<RESET>
2031 <GREEN>+<RESET><GREEN>two<RESET>
2032 A<RESET>
2033 B<RESET>
2034 C<RESET>
2035 <RED>-one<RESET>
2036 <BOLD;MAGENTA>-two<RESET>
2037 <BOLD;MAGENTA>-three<RESET>
2038 <BOLD;MAGENTA>-four<RESET>
2039 <BOLD;MAGENTA>-five<RESET>
2040 <BOLD;MAGENTA>-six<RESET>
2041 <BOLD;MAGENTA>-seven<RESET>
2042 D<RESET>
2043 E<RESET>
2044 F<RESET>
2045 <CYAN>@@ -15,3 +10,9 @@<RESET> <RESET>G<RESET>
2046 H<RESET>
2047 I<RESET>
2048 J<RESET>
2049 <BOLD;CYAN>+<RESET><BOLD;CYAN>two<RESET>
2050 <BOLD;CYAN>+<RESET><BOLD;CYAN>three<RESET>
2051 <BOLD;CYAN>+<RESET><BOLD;CYAN>four<RESET>
2052 <BOLD;CYAN>+<RESET><BOLD;CYAN>five<RESET>
2053 <BOLD;CYAN>+<RESET><BOLD;CYAN>six<RESET>
2054 <BOLD;CYAN>+<RESET><BOLD;CYAN>seven<RESET>
2055 EOF
2056
2057 test_cmp expected actual
2058 '
2059
2060 test_expect_success !SANITIZE_LEAK 'move detection with submodules' '
2061 test_create_repo bananas &&
2062 echo ripe >bananas/recipe &&
2063 git -C bananas add recipe &&
2064 test_commit fruit &&
2065 test_commit -C bananas recipe &&
2066 git submodule add ./bananas &&
2067 git add bananas &&
2068 git commit -a -m "bananas are like a heavy library?" &&
2069 echo foul >bananas/recipe &&
2070 echo ripe >fruit.t &&
2071
2072 git diff --submodule=diff --color-moved --color >actual &&
2073
2074 # no move detection as the moved line is across repository boundaries.
2075 test_decode_color <actual >decoded_actual &&
2076 ! grep BGREEN decoded_actual &&
2077 ! grep BRED decoded_actual &&
2078
2079 # nor did we mess with it another way
2080 git diff --submodule=diff --color >expect.raw &&
2081 test_decode_color <expect.raw >expect &&
2082 test_cmp expect decoded_actual &&
2083 rm -rf bananas &&
2084 git submodule deinit bananas
2085 '
2086
2087 test_expect_success 'only move detection ignores white spaces' '
2088 git reset --hard &&
2089 q_to_tab <<-\EOF >text.txt &&
2090 a long line to exceed per-line minimum
2091 another long line to exceed per-line minimum
2092 original file
2093 EOF
2094 git add text.txt &&
2095 git commit -m "add text" &&
2096 q_to_tab <<-\EOF >text.txt &&
2097 Qa long line to exceed per-line minimum
2098 Qanother long line to exceed per-line minimum
2099 new file
2100 EOF
2101
2102 # Make sure we get a different diff using -w
2103 git diff --color --color-moved -w >actual.raw &&
2104 grep -v "index" actual.raw | test_decode_color >actual &&
2105 q_to_tab <<-\EOF >expected &&
2106 <BOLD>diff --git a/text.txt b/text.txt<RESET>
2107 <BOLD>--- a/text.txt<RESET>
2108 <BOLD>+++ b/text.txt<RESET>
2109 <CYAN>@@ -1,3 +1,3 @@<RESET>
2110 Qa long line to exceed per-line minimum<RESET>
2111 Qanother long line to exceed per-line minimum<RESET>
2112 <RED>-original file<RESET>
2113 <GREEN>+<RESET><GREEN>new file<RESET>
2114 EOF
2115 test_cmp expected actual &&
2116
2117 # And now ignoring white space only in the move detection
2118 git diff --color --color-moved \
2119 --color-moved-ws=ignore-all-space,ignore-space-change,ignore-space-at-eol >actual.raw &&
2120 grep -v "index" actual.raw | test_decode_color >actual &&
2121 q_to_tab <<-\EOF >expected &&
2122 <BOLD>diff --git a/text.txt b/text.txt<RESET>
2123 <BOLD>--- a/text.txt<RESET>
2124 <BOLD>+++ b/text.txt<RESET>
2125 <CYAN>@@ -1,3 +1,3 @@<RESET>
2126 <BOLD;MAGENTA>-a long line to exceed per-line minimum<RESET>
2127 <BOLD;MAGENTA>-another long line to exceed per-line minimum<RESET>
2128 <RED>-original file<RESET>
2129 <BOLD;CYAN>+<RESET>Q<BOLD;CYAN>a long line to exceed per-line minimum<RESET>
2130 <BOLD;CYAN>+<RESET>Q<BOLD;CYAN>another long line to exceed per-line minimum<RESET>
2131 <GREEN>+<RESET><GREEN>new file<RESET>
2132 EOF
2133 test_cmp expected actual
2134 '
2135
2136 test_expect_success 'compare whitespace delta across moved blocks' '
2137
2138 git reset --hard &&
2139 q_to_tab <<-\EOF >text.txt &&
2140 QIndented
2141 QText across
2142 Qsome lines
2143 QBut! <- this stands out
2144 QAdjusting with
2145 QQdifferent starting
2146 Qwhite spaces
2147 QAnother outlier
2148 QQQIndented
2149 QQQText across
2150 QQQfive lines
2151 QQQthat has similar lines
2152 QQQto previous blocks, but with different indent
2153 QQQYetQAnotherQoutlierQ
2154 QLine with internal w h i t e s p a c e change
2155 EOF
2156
2157 git add text.txt &&
2158 git commit -m "add text.txt" &&
2159
2160 q_to_tab <<-\EOF >text.txt &&
2161 QQIndented
2162 QQText across
2163 QQsome lines
2164 QQQBut! <- this stands out
2165 Adjusting with
2166 Qdifferent starting
2167 white spaces
2168 AnotherQoutlier
2169 QQIndented
2170 QQText across
2171 QQfive lines
2172 QQthat has similar lines
2173 QQto previous blocks, but with different indent
2174 QQYetQAnotherQoutlier
2175 QLine with internal whitespace change
2176 EOF
2177
2178 git diff --color --color-moved --color-moved-ws=allow-indentation-change >actual.raw &&
2179 grep -v "index" actual.raw | test_decode_color >actual &&
2180
2181 q_to_tab <<-\EOF >expected &&
2182 <BOLD>diff --git a/text.txt b/text.txt<RESET>
2183 <BOLD>--- a/text.txt<RESET>
2184 <BOLD>+++ b/text.txt<RESET>
2185 <CYAN>@@ -1,15 +1,15 @@<RESET>
2186 <BOLD;MAGENTA>-QIndented<RESET>
2187 <BOLD;MAGENTA>-QText across<RESET>
2188 <BOLD;MAGENTA>-Qsome lines<RESET>
2189 <RED>-QBut! <- this stands out<RESET>
2190 <BOLD;MAGENTA>-QAdjusting with<RESET>
2191 <BOLD;MAGENTA>-QQdifferent starting<RESET>
2192 <BOLD;MAGENTA>-Qwhite spaces<RESET>
2193 <RED>-QAnother outlier<RESET>
2194 <BOLD;MAGENTA>-QQQIndented<RESET>
2195 <BOLD;MAGENTA>-QQQText across<RESET>
2196 <BOLD;MAGENTA>-QQQfive lines<RESET>
2197 <BOLD;MAGENTA>-QQQthat has similar lines<RESET>
2198 <BOLD;MAGENTA>-QQQto previous blocks, but with different indent<RESET>
2199 <RED>-QQQYetQAnotherQoutlierQ<RESET>
2200 <RED>-QLine with internal w h i t e s p a c e change<RESET>
2201 <BOLD;CYAN>+<RESET>QQ<BOLD;CYAN>Indented<RESET>
2202 <BOLD;CYAN>+<RESET>QQ<BOLD;CYAN>Text across<RESET>
2203 <BOLD;CYAN>+<RESET>QQ<BOLD;CYAN>some lines<RESET>
2204 <GREEN>+<RESET>QQQ<GREEN>But! <- this stands out<RESET>
2205 <BOLD;CYAN>+<RESET><BOLD;CYAN>Adjusting with<RESET>
2206 <BOLD;CYAN>+<RESET>Q<BOLD;CYAN>different starting<RESET>
2207 <BOLD;CYAN>+<RESET><BOLD;CYAN>white spaces<RESET>
2208 <GREEN>+<RESET><GREEN>AnotherQoutlier<RESET>
2209 <BOLD;CYAN>+<RESET>QQ<BOLD;CYAN>Indented<RESET>
2210 <BOLD;CYAN>+<RESET>QQ<BOLD;CYAN>Text across<RESET>
2211 <BOLD;CYAN>+<RESET>QQ<BOLD;CYAN>five lines<RESET>
2212 <BOLD;CYAN>+<RESET>QQ<BOLD;CYAN>that has similar lines<RESET>
2213 <BOLD;CYAN>+<RESET>QQ<BOLD;CYAN>to previous blocks, but with different indent<RESET>
2214 <GREEN>+<RESET>QQ<GREEN>YetQAnotherQoutlier<RESET>
2215 <GREEN>+<RESET>Q<GREEN>Line with internal whitespace change<RESET>
2216 EOF
2217
2218 test_cmp expected actual
2219 '
2220
2221 test_expect_success 'bogus settings in move detection erroring out' '
2222 test_must_fail git diff --color-moved=bogus 2>err &&
2223 test_i18ngrep "must be one of" err &&
2224 test_i18ngrep bogus err &&
2225
2226 test_must_fail git -c diff.colormoved=bogus diff 2>err &&
2227 test_i18ngrep "must be one of" err &&
2228 test_i18ngrep "from command-line config" err &&
2229
2230 test_must_fail git diff --color-moved-ws=bogus 2>err &&
2231 test_i18ngrep "possible values" err &&
2232 test_i18ngrep bogus err &&
2233
2234 test_must_fail git -c diff.colormovedws=bogus diff 2>err &&
2235 test_i18ngrep "possible values" err &&
2236 test_i18ngrep "from command-line config" err
2237 '
2238
2239 test_expect_success 'compare whitespace delta incompatible with other space options' '
2240 test_must_fail git diff \
2241 --color-moved-ws=allow-indentation-change,ignore-all-space \
2242 2>err &&
2243 test_i18ngrep allow-indentation-change err
2244 '
2245
2246 EMPTY=''
2247 test_expect_success 'compare mixed whitespace delta across moved blocks' '
2248
2249 git reset --hard &&
2250 tr "^|Q_" "\f\v\t " <<-EOF >text.txt &&
2251 ^__
2252 |____too short without
2253 ^
2254 ___being grouped across blank line
2255 ${EMPTY}
2256 context
2257 lines
2258 to
2259 anchor
2260 ____Indented text to
2261 _Q____be further indented by four spaces across
2262 ____Qseveral lines
2263 QQ____These two lines have had their
2264 ____indentation reduced by four spaces
2265 Qdifferent indentation change
2266 ____too short
2267 EOF
2268
2269 git add text.txt &&
2270 git commit -m "add text.txt" &&
2271
2272 tr "^|Q_" "\f\v\t " <<-EOF >text.txt &&
2273 context
2274 lines
2275 to
2276 anchor
2277 QIndented text to
2278 QQbe further indented by four spaces across
2279 Q____several lines
2280 ${EMPTY}
2281 QQtoo short without
2282 ${EMPTY}
2283 ^Q_______being grouped across blank line
2284 ${EMPTY}
2285 Q_QThese two lines have had their
2286 indentation reduced by four spaces
2287 QQdifferent indentation change
2288 __Qtoo short
2289 EOF
2290
2291 git -c color.diff.whitespace="normal red" \
2292 -c core.whitespace=space-before-tab \
2293 diff --color --color-moved --ws-error-highlight=all \
2294 --color-moved-ws=allow-indentation-change >actual.raw &&
2295 grep -v "index" actual.raw | tr "\f\v" "^|" | test_decode_color >actual &&
2296
2297 cat <<-\EOF >expected &&
2298 <BOLD>diff --git a/text.txt b/text.txt<RESET>
2299 <BOLD>--- a/text.txt<RESET>
2300 <BOLD>+++ b/text.txt<RESET>
2301 <CYAN>@@ -1,16 +1,16 @@<RESET>
2302 <BOLD;MAGENTA>-<RESET><BOLD;MAGENTA>^<RESET><BRED> <RESET>
2303 <BOLD;MAGENTA>-<RESET><BOLD;MAGENTA>| too short without<RESET>
2304 <BOLD;MAGENTA>-<RESET><BOLD;MAGENTA>^<RESET>
2305 <BOLD;MAGENTA>-<RESET><BOLD;MAGENTA> being grouped across blank line<RESET>
2306 <BOLD;MAGENTA>-<RESET>
2307 <RESET>context<RESET>
2308 <RESET>lines<RESET>
2309 <RESET>to<RESET>
2310 <RESET>anchor<RESET>
2311 <BOLD;MAGENTA>-<RESET><BOLD;MAGENTA> Indented text to<RESET>
2312 <BOLD;MAGENTA>-<RESET><BRED> <RESET> <BOLD;MAGENTA> be further indented by four spaces across<RESET>
2313 <BOLD;MAGENTA>-<RESET><BRED> <RESET> <BOLD;MAGENTA>several lines<RESET>
2314 <BOLD;BLUE>-<RESET> <BOLD;BLUE> These two lines have had their<RESET>
2315 <BOLD;BLUE>-<RESET><BOLD;BLUE> indentation reduced by four spaces<RESET>
2316 <BOLD;MAGENTA>-<RESET> <BOLD;MAGENTA>different indentation change<RESET>
2317 <RED>-<RESET><RED> too short<RESET>
2318 <BOLD;CYAN>+<RESET> <BOLD;CYAN>Indented text to<RESET>
2319 <BOLD;CYAN>+<RESET> <BOLD;CYAN>be further indented by four spaces across<RESET>
2320 <BOLD;CYAN>+<RESET> <BOLD;CYAN> several lines<RESET>
2321 <BOLD;YELLOW>+<RESET>
2322 <BOLD;YELLOW>+<RESET> <BOLD;YELLOW>too short without<RESET>
2323 <BOLD;YELLOW>+<RESET>
2324 <BOLD;YELLOW>+<RESET><BOLD;YELLOW>^ being grouped across blank line<RESET>
2325 <BOLD;YELLOW>+<RESET>
2326 <BOLD;CYAN>+<RESET> <BRED> <RESET> <BOLD;CYAN>These two lines have had their<RESET>
2327 <BOLD;CYAN>+<RESET><BOLD;CYAN>indentation reduced by four spaces<RESET>
2328 <BOLD;YELLOW>+<RESET> <BOLD;YELLOW>different indentation change<RESET>
2329 <GREEN>+<RESET><BRED> <RESET> <GREEN>too short<RESET>
2330 EOF
2331
2332 test_cmp expected actual
2333 '
2334
2335 test_expect_success 'combine --ignore-blank-lines with --function-context' '
2336 test_write_lines 1 "" 2 3 4 5 >a &&
2337 test_write_lines 1 2 3 4 >b &&
2338 test_must_fail git diff --no-index \
2339 --ignore-blank-lines --function-context a b >actual.raw &&
2340 sed -n "/@@/,\$p" <actual.raw >actual &&
2341 cat <<-\EOF >expect &&
2342 @@ -1,6 +1,4 @@
2343 1
2344 -
2345 2
2346 3
2347 4
2348 -5
2349 EOF
2350 test_cmp expect actual
2351 '
2352
2353 test_expect_success 'combine --ignore-blank-lines with --function-context 2' '
2354 test_write_lines a b c "" function 1 2 3 4 5 "" 6 7 8 9 >a &&
2355 test_write_lines "" a b c "" function 1 2 3 4 5 6 7 8 >b &&
2356 test_must_fail git diff --no-index \
2357 --ignore-blank-lines --function-context a b >actual.raw &&
2358 sed -n "/@@/,\$p" <actual.raw >actual &&
2359 cat <<-\EOF >expect &&
2360 @@ -5,11 +6,9 @@ c
2361 function
2362 1
2363 2
2364 3
2365 4
2366 5
2367 -
2368 6
2369 7
2370 8
2371 -9
2372 EOF
2373 test_cmp expect actual
2374 '
2375
2376 test_done