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