commit-graph: when incompatible with graphs, indicate why
[git] / t / t4124-apply-ws-rule.sh
1 #!/bin/sh
2
3 test_description='core.whitespace rules and git apply'
4
5 . ./test-lib.sh
6
7 prepare_test_file () {
8
9         # A line that has character X is touched iff RULE is in effect:
10         #       X  RULE
11         #       !  trailing-space
12         #       @  space-before-tab
13         #       #  indent-with-non-tab (default tab width 8)
14         #       =  indent-with-non-tab,tabwidth=16
15         #       %  tab-in-indent
16         sed -e "s/_/ /g" -e "s/>/       /" <<-\EOF
17                 An_SP in an ordinary line>and a HT.
18                 >A HT (%).
19                 _>A SP and a HT (@%).
20                 _>_A SP, a HT and a SP (@%).
21                 _______Seven SP.
22                 ________Eight SP (#).
23                 _______>Seven SP and a HT (@%).
24                 ________>Eight SP and a HT (@#%).
25                 _______>_Seven SP, a HT and a SP (@%).
26                 ________>_Eight SP, a HT and a SP (@#%).
27                 _______________Fifteen SP (#).
28                 _______________>Fifteen SP and a HT (@#%).
29                 ________________Sixteen SP (#=).
30                 ________________>Sixteen SP and a HT (@#%=).
31                 _____a__Five SP, a non WS, two SP.
32                 A line with a (!) trailing SP_
33                 A line with a (!) trailing HT>
34         EOF
35 }
36
37 apply_patch () {
38         cmd_prefix= &&
39         if test "x$1" = 'x!'
40         then
41                 cmd_prefix=test_must_fail &&
42                 shift
43         fi &&
44         >target &&
45         sed -e "s|\([ab]\)/file|\1/target|" <patch |
46         $cmd_prefix git apply "$@"
47 }
48
49 test_fix () {
50         # fix should not barf
51         apply_patch --whitespace=fix || return 1
52
53         # find touched lines
54         $DIFF file target | sed -n -e "s/^> //p" >fixed
55         # busybox's diff(1) doesn't output normal format
56         if ! test -s fixed
57         then
58                 $DIFF -u file target |
59                 grep -v '^+++ target' |
60                 sed -ne "/^+/s/+//p" >fixed
61         fi
62
63         # the changed lines are all expected to change
64         fixed_cnt=$(wc -l <fixed)
65         case "$1" in
66         '') expect_cnt=$fixed_cnt ;;
67         ?*) expect_cnt=$(grep "[$1]" <fixed | wc -l) ;;
68         esac
69         test $fixed_cnt -eq $expect_cnt || return 1
70
71         # and we are not missing anything
72         case "$1" in
73         '') expect_cnt=0 ;;
74         ?*) expect_cnt=$(grep "[$1]" <file | wc -l) ;;
75         esac
76         test $fixed_cnt -eq $expect_cnt || return 1
77
78         # Get the patch actually applied
79         git diff-files -p target >fixed-patch
80         test -s fixed-patch && return 0
81
82         # Make sure it is complaint-free
83         >target
84         git apply --whitespace=error-all <fixed-patch
85
86 }
87
88 test_expect_success setup '
89
90         >file &&
91         git add file &&
92         prepare_test_file >file &&
93         git diff-files -p >patch &&
94         >target &&
95         git add target
96
97 '
98
99 test_expect_success 'whitespace=nowarn, default rule' '
100
101         apply_patch --whitespace=nowarn &&
102         test_cmp file target
103
104 '
105
106 test_expect_success 'whitespace=warn, default rule' '
107
108         apply_patch --whitespace=warn &&
109         test_cmp file target
110
111 '
112
113 test_expect_success 'whitespace=error-all, default rule' '
114
115         apply_patch ! --whitespace=error-all &&
116         test_must_be_empty target
117
118 '
119
120 test_expect_success 'whitespace=error-all, no rule' '
121
122         git config core.whitespace -trailing,-space-before,-indent &&
123         apply_patch --whitespace=error-all &&
124         test_cmp file target
125
126 '
127
128 test_expect_success 'whitespace=error-all, no rule (attribute)' '
129
130         git config --unset core.whitespace &&
131         echo "target -whitespace" >.gitattributes &&
132         apply_patch --whitespace=error-all &&
133         test_cmp file target
134
135 '
136
137 test_expect_success 'spaces inserted by tab-in-indent' '
138
139         git config core.whitespace -trailing,-space,-indent,tab &&
140         rm -f .gitattributes &&
141         test_fix % &&
142         sed -e "s/_/ /g" -e "s/>/       /" <<-\EOF >expect &&
143                 An_SP in an ordinary line>and a HT.
144                 ________A HT (%).
145                 ________A SP and a HT (@%).
146                 _________A SP, a HT and a SP (@%).
147                 _______Seven SP.
148                 ________Eight SP (#).
149                 ________Seven SP and a HT (@%).
150                 ________________Eight SP and a HT (@#%).
151                 _________Seven SP, a HT and a SP (@%).
152                 _________________Eight SP, a HT and a SP (@#%).
153                 _______________Fifteen SP (#).
154                 ________________Fifteen SP and a HT (@#%).
155                 ________________Sixteen SP (#=).
156                 ________________________Sixteen SP and a HT (@#%=).
157                 _____a__Five SP, a non WS, two SP.
158                 A line with a (!) trailing SP_
159                 A line with a (!) trailing HT>
160         EOF
161         test_cmp expect target
162
163 '
164
165 for t in - ''
166 do
167         case "$t" in '') tt='!' ;; *) tt= ;; esac
168         for s in - ''
169         do
170                 case "$s" in '') ts='@' ;; *) ts= ;; esac
171                 for i in - ''
172                 do
173                         case "$i" in '') ti='#' ti16='=';; *) ti= ti16= ;; esac
174                         for h in - ''
175                         do
176                                 [ -z "$h$i" ] && continue
177                                 case "$h" in '') th='%' ;; *) th= ;; esac
178                                 rule=${t}trailing,${s}space,${i}indent,${h}tab
179
180                                 rm -f .gitattributes
181                                 test_expect_success "rule=$rule" '
182                                         git config core.whitespace "$rule" &&
183                                         test_fix "$tt$ts$ti$th"
184                                 '
185
186                                 test_expect_success "rule=$rule,tabwidth=16" '
187                                         git config core.whitespace "$rule,tabwidth=16" &&
188                                         test_fix "$tt$ts$ti16$th"
189                                 '
190
191                                 test_expect_success "rule=$rule (attributes)" '
192                                         git config --unset core.whitespace &&
193                                         echo "target whitespace=$rule" >.gitattributes &&
194                                         test_fix "$tt$ts$ti$th"
195                                 '
196
197                                 test_expect_success "rule=$rule,tabwidth=16 (attributes)" '
198                                         echo "target whitespace=$rule,tabwidth=16" >.gitattributes &&
199                                         test_fix "$tt$ts$ti16$th"
200                                 '
201
202                         done
203                 done
204         done
205 done
206
207 create_patch () {
208         sed -e "s/_/ /" <<-\EOF
209                 diff --git a/target b/target
210                 index e69de29..8bd6648 100644
211                 --- a/target
212                 +++ b/target
213                 @@ -0,0 +1,3 @@
214                 +An empty line follows
215                 +
216                 +A line with trailing whitespace and no newline_
217                 \ No newline at end of file
218         EOF
219 }
220
221 test_expect_success 'trailing whitespace & no newline at the end of file' '
222         >target &&
223         create_patch >patch-file &&
224         git apply --whitespace=fix patch-file &&
225         grep "newline$" target &&
226         grep "^$" target
227 '
228
229 test_expect_success 'blank at EOF with --whitespace=fix (1)' '
230         test_might_fail git config --unset core.whitespace &&
231         rm -f .gitattributes &&
232
233         { echo a; echo b; echo c; } >one &&
234         git add one &&
235         { echo a; echo b; echo c; } >expect &&
236         { cat expect; echo; } >one &&
237         git diff -- one >patch &&
238
239         git checkout one &&
240         git apply --whitespace=fix patch &&
241         test_cmp expect one
242 '
243
244 test_expect_success 'blank at EOF with --whitespace=fix (2)' '
245         { echo a; echo b; echo c; } >one &&
246         git add one &&
247         { echo a; echo c; } >expect &&
248         { cat expect; echo; echo; } >one &&
249         git diff -- one >patch &&
250
251         git checkout one &&
252         git apply --whitespace=fix patch &&
253         test_cmp expect one
254 '
255
256 test_expect_success 'blank at EOF with --whitespace=fix (3)' '
257         { echo a; echo b; echo; } >one &&
258         git add one &&
259         { echo a; echo c; echo; } >expect &&
260         { cat expect; echo; echo; } >one &&
261         git diff -- one >patch &&
262
263         git checkout one &&
264         git apply --whitespace=fix patch &&
265         test_cmp expect one
266 '
267
268 test_expect_success 'blank at end of hunk, not at EOF with --whitespace=fix' '
269         { echo a; echo b; echo; echo; echo; echo; echo; echo d; } >one &&
270         git add one &&
271         { echo a; echo c; echo; echo; echo; echo; echo; echo; echo d; } >expect &&
272         cp expect one &&
273         git diff -- one >patch &&
274
275         git checkout one &&
276         git apply --whitespace=fix patch &&
277         test_cmp expect one
278 '
279
280 test_expect_success 'blank at EOF with --whitespace=warn' '
281         { echo a; echo b; echo c; } >one &&
282         git add one &&
283         echo >>one &&
284         cat one >expect &&
285         git diff -- one >patch &&
286
287         git checkout one &&
288         git apply --whitespace=warn patch 2>error &&
289         test_cmp expect one &&
290         grep "new blank line at EOF" error
291 '
292
293 test_expect_success 'blank at EOF with --whitespace=error' '
294         { echo a; echo b; echo c; } >one &&
295         git add one &&
296         cat one >expect &&
297         echo >>one &&
298         git diff -- one >patch &&
299
300         git checkout one &&
301         test_must_fail git apply --whitespace=error patch 2>error &&
302         test_cmp expect one &&
303         grep "new blank line at EOF" error
304 '
305
306 test_expect_success 'blank but not empty at EOF' '
307         { echo a; echo b; echo c; } >one &&
308         git add one &&
309         echo "   " >>one &&
310         cat one >expect &&
311         git diff -- one >patch &&
312
313         git checkout one &&
314         git apply --whitespace=warn patch 2>error &&
315         test_cmp expect one &&
316         grep "new blank line at EOF" error
317 '
318
319 test_expect_success 'applying beyond EOF requires one non-blank context line' '
320         { echo; echo; echo; echo; } >one &&
321         git add one &&
322         { echo b; } >>one &&
323         git diff -- one >patch &&
324
325         git checkout one &&
326         { echo a; echo; } >one &&
327         cp one expect &&
328         test_must_fail git apply --whitespace=fix patch &&
329         test_cmp expect one &&
330         test_must_fail git apply --ignore-space-change --whitespace=fix patch &&
331         test_cmp expect one
332 '
333
334 test_expect_success 'tons of blanks at EOF should not apply' '
335         for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16; do
336                 echo; echo; echo; echo;
337         done >one &&
338         git add one &&
339         echo a >>one &&
340         git diff -- one >patch &&
341
342         >one &&
343         test_must_fail git apply --whitespace=fix patch &&
344         test_must_fail git apply --ignore-space-change --whitespace=fix patch
345 '
346
347 test_expect_success 'missing blank line at end with --whitespace=fix' '
348         echo a >one &&
349         echo >>one &&
350         git add one &&
351         echo b >>one &&
352         cp one expect &&
353         git diff -- one >patch &&
354         echo a >one &&
355         cp one saved-one &&
356         test_must_fail git apply patch &&
357         git apply --whitespace=fix patch &&
358         test_cmp expect one &&
359         mv saved-one one &&
360         git apply --ignore-space-change --whitespace=fix patch &&
361         test_cmp expect one
362 '
363
364 test_expect_success 'two missing blank lines at end with --whitespace=fix' '
365         { echo a; echo; echo b; echo c; } >one &&
366         cp one no-blank-lines &&
367         { echo; echo; } >>one &&
368         git add one &&
369         echo d >>one &&
370         cp one expect &&
371         echo >>one &&
372         git diff -- one >patch &&
373         cp no-blank-lines one &&
374         test_must_fail git apply patch &&
375         git apply --whitespace=fix patch &&
376         test_cmp expect one &&
377         mv no-blank-lines one &&
378         test_must_fail git apply patch &&
379         git apply --ignore-space-change --whitespace=fix patch &&
380         test_cmp expect one
381 '
382
383 test_expect_success 'missing blank line at end, insert before end, --whitespace=fix' '
384         { echo a; echo; } >one &&
385         git add one &&
386         { echo b; echo a; echo; } >one &&
387         cp one expect &&
388         git diff -- one >patch &&
389         echo a >one &&
390         test_must_fail git apply patch &&
391         git apply --whitespace=fix patch &&
392         test_cmp expect one
393 '
394
395 test_expect_success 'shrink file with tons of missing blanks at end of file' '
396         { echo a; echo b; echo c; } >one &&
397         cp one no-blank-lines &&
398         for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16; do
399                 echo; echo; echo; echo;
400         done >>one &&
401         git add one &&
402         echo a >one &&
403         cp one expect &&
404         git diff -- one >patch &&
405         cp no-blank-lines one &&
406         test_must_fail git apply patch &&
407         git apply --whitespace=fix patch &&
408         test_cmp expect one &&
409         mv no-blank-lines one &&
410         git apply --ignore-space-change --whitespace=fix patch &&
411         test_cmp expect one
412 '
413
414 test_expect_success 'missing blanks at EOF must only match blank lines' '
415         { echo a; echo b; } >one &&
416         git add one &&
417         { echo c; echo d; } >>one &&
418         git diff -- one >patch &&
419
420         echo a >one &&
421         test_must_fail git apply patch &&
422         test_must_fail git apply --whitespace=fix patch &&
423         test_must_fail git apply --ignore-space-change --whitespace=fix patch
424 '
425
426 sed -e's/Z//' >one <<EOF
427 a
428 b
429 c
430                       Z
431 EOF
432
433 test_expect_success 'missing blank line should match context line with spaces' '
434         git add one &&
435         echo d >>one &&
436         git diff -- one >patch &&
437         { echo a; echo b; echo c; } >one &&
438         cp one expect &&
439         { echo; echo d; } >>expect &&
440         git add one &&
441
442         git apply --whitespace=fix patch &&
443         test_cmp expect one
444 '
445
446 sed -e's/Z//' >one <<EOF
447 a
448 b
449 c
450                       Z
451 EOF
452
453 test_expect_success 'same, but with the --ignore-space-option' '
454         git add one &&
455         echo d >>one &&
456         cp one expect &&
457         git diff -- one >patch &&
458         { echo a; echo b; echo c; } >one &&
459         git add one &&
460
461         git checkout-index -f one &&
462         git apply --ignore-space-change --whitespace=fix patch &&
463         test_cmp expect one
464 '
465
466 test_expect_success 'same, but with CR-LF line endings && cr-at-eol set' '
467         git config core.whitespace cr-at-eol &&
468         printf "a\r\n" >one &&
469         printf "b\r\n" >>one &&
470         printf "c\r\n" >>one &&
471         cp one save-one &&
472         printf "                 \r\n" >>one &&
473         git add one &&
474         printf "d\r\n" >>one &&
475         cp one expect &&
476         git diff -- one >patch &&
477         mv save-one one &&
478
479         git apply --ignore-space-change --whitespace=fix patch &&
480         test_cmp expect one
481 '
482
483 test_expect_success 'CR-LF line endings && add line && text=auto' '
484         git config --unset core.whitespace &&
485         printf "a\r\n" >one &&
486         cp one save-one &&
487         git add one &&
488         printf "b\r\n" >>one &&
489         cp one expect &&
490         git diff -- one >patch &&
491         mv save-one one &&
492         echo "one text=auto" >.gitattributes &&
493         git apply patch &&
494         test_cmp expect one
495 '
496
497 test_expect_success 'CR-LF line endings && change line && text=auto' '
498         printf "a\r\n" >one &&
499         cp one save-one &&
500         git add one &&
501         printf "b\r\n" >one &&
502         cp one expect &&
503         git diff -- one >patch &&
504         mv save-one one &&
505         echo "one text=auto" >.gitattributes &&
506         git apply patch &&
507         test_cmp expect one
508 '
509
510 test_expect_success 'LF in repo, CRLF in worktree && change line && text=auto' '
511         printf "a\n" >one &&
512         git add one &&
513         printf "b\r\n" >one &&
514         git diff -- one >patch &&
515         printf "a\r\n" >one &&
516         echo "one text=auto" >.gitattributes &&
517         git -c core.eol=CRLF apply patch &&
518         printf "b\r\n" >expect &&
519         test_cmp expect one
520 '
521
522 test_expect_success 'whitespace=fix to expand' '
523         qz_to_tab_space >preimage <<-\EOF &&
524         QQa
525         QQb
526         QQc
527         ZZZZZZZZZZZZZZZZd
528         QQe
529         QQf
530         QQg
531         EOF
532         qz_to_tab_space >patch <<-\EOF &&
533         diff --git a/preimage b/preimage
534         --- a/preimage
535         +++ b/preimage
536         @@ -1,7 +1,6 @@
537          QQa
538          QQb
539          QQc
540         -QQd
541          QQe
542          QQf
543          QQg
544         EOF
545         git -c core.whitespace=tab-in-indent apply --whitespace=fix patch
546 '
547
548 test_expect_success 'whitespace check skipped for excluded paths' '
549         git config core.whitespace blank-at-eol &&
550         >used &&
551         >unused &&
552         git add used unused &&
553         echo "used" >used &&
554         echo "unused " >unused &&
555         git diff-files -p used unused >patch &&
556         git apply --include=used --stat --whitespace=error <patch
557 '
558
559 test_done