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