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