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