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