#!/bin/sh test_description='core.whitespace rules and git apply' . ./test-lib.sh prepare_test_file () { # A line that has character X is touched iff RULE is in effect: # X RULE # ! trailing-space # @ space-before-tab # # indent-with-non-tab (default tab width 8) # = indent-with-non-tab,tabwidth=16 # % tab-in-indent sed -e "s/_/ /g" -e "s/>/ /" <<-\EOF An_SP in an ordinary line>and a HT. >A HT (%). _>A SP and a HT (@%). _>_A SP, a HT and a SP (@%). _______Seven SP. ________Eight SP (#). _______>Seven SP and a HT (@%). ________>Eight SP and a HT (@#%). _______>_Seven SP, a HT and a SP (@%). ________>_Eight SP, a HT and a SP (@#%). _______________Fifteen SP (#). _______________>Fifteen SP and a HT (@#%). ________________Sixteen SP (#=). ________________>Sixteen SP and a HT (@#%=). _____a__Five SP, a non WS, two SP. A line with a (!) trailing SP_ A line with a (!) trailing HT> EOF } apply_patch () { >target && sed -e "s|\([ab]\)/file|\1/target|" <patch | git apply "$@" } test_fix () { # fix should not barf apply_patch --whitespace=fix || return 1 # find touched lines $DIFF file target | sed -n -e "s/^> //p" >fixed # the changed lines are all expected to change fixed_cnt=$(wc -l <fixed) case "$1" in '') expect_cnt=$fixed_cnt ;; ?*) expect_cnt=$(grep "[$1]" <fixed | wc -l) ;; esac test $fixed_cnt -eq $expect_cnt || return 1 # and we are not missing anything case "$1" in '') expect_cnt=0 ;; ?*) expect_cnt=$(grep "[$1]" <file | wc -l) ;; esac test $fixed_cnt -eq $expect_cnt || return 1 # Get the patch actually applied git diff-files -p target >fixed-patch test -s fixed-patch && return 0 # Make sure it is complaint-free >target git apply --whitespace=error-all <fixed-patch } test_expect_success setup ' >file && git add file && prepare_test_file >file && git diff-files -p >patch && >target && git add target ' test_expect_success 'whitespace=nowarn, default rule' ' apply_patch --whitespace=nowarn && test_cmp file target ' test_expect_success 'whitespace=warn, default rule' ' apply_patch --whitespace=warn && test_cmp file target ' test_expect_success 'whitespace=error-all, default rule' ' test_must_fail apply_patch --whitespace=error-all && test_must_be_empty target ' test_expect_success 'whitespace=error-all, no rule' ' git config core.whitespace -trailing,-space-before,-indent && apply_patch --whitespace=error-all && test_cmp file target ' test_expect_success 'whitespace=error-all, no rule (attribute)' ' git config --unset core.whitespace && echo "target -whitespace" >.gitattributes && apply_patch --whitespace=error-all && test_cmp file target ' test_expect_success 'spaces inserted by tab-in-indent' ' git config core.whitespace -trailing,-space,-indent,tab && rm -f .gitattributes && test_fix % && sed -e "s/_/ /g" -e "s/>/ /" <<-\EOF >expect && An_SP in an ordinary line>and a HT. ________A HT (%). ________A SP and a HT (@%). _________A SP, a HT and a SP (@%). _______Seven SP. ________Eight SP (#). ________Seven SP and a HT (@%). ________________Eight SP and a HT (@#%). _________Seven SP, a HT and a SP (@%). _________________Eight SP, a HT and a SP (@#%). _______________Fifteen SP (#). ________________Fifteen SP and a HT (@#%). ________________Sixteen SP (#=). ________________________Sixteen SP and a HT (@#%=). _____a__Five SP, a non WS, two SP. A line with a (!) trailing SP_ A line with a (!) trailing HT> EOF test_cmp expect target ' for t in - '' do case "$t" in '') tt='!' ;; *) tt= ;; esac for s in - '' do case "$s" in '') ts='@' ;; *) ts= ;; esac for i in - '' do case "$i" in '') ti='#' ti16='=';; *) ti= ti16= ;; esac for h in - '' do [ -z "$h$i" ] && continue case "$h" in '') th='%' ;; *) th= ;; esac rule=${t}trailing,${s}space,${i}indent,${h}tab rm -f .gitattributes test_expect_success "rule=$rule" ' git config core.whitespace "$rule" && test_fix "$tt$ts$ti$th" ' test_expect_success "rule=$rule,tabwidth=16" ' git config core.whitespace "$rule,tabwidth=16" && test_fix "$tt$ts$ti16$th" ' test_expect_success "rule=$rule (attributes)" ' git config --unset core.whitespace && echo "target whitespace=$rule" >.gitattributes && test_fix "$tt$ts$ti$th" ' test_expect_success "rule=$rule,tabwidth=16 (attributes)" ' echo "target whitespace=$rule,tabwidth=16" >.gitattributes && test_fix "$tt$ts$ti16$th" ' done done done done create_patch () { sed -e "s/_/ /" <<-\EOF diff --git a/target b/target index e69de29..8bd6648 100644 --- a/target +++ b/target @@ -0,0 +1,3 @@ +An empty line follows + +A line with trailing whitespace and no newline_ \ No newline at end of file EOF } test_expect_success 'trailing whitespace & no newline at the end of file' ' >target && create_patch >patch-file && git apply --whitespace=fix patch-file && grep "newline$" target && grep "^$" target ' test_expect_success 'blank at EOF with --whitespace=fix (1)' ' test_might_fail git config --unset core.whitespace && rm -f .gitattributes && { echo a; echo b; echo c; } >one && git add one && { echo a; echo b; echo c; } >expect && { cat expect; echo; } >one && git diff -- one >patch && git checkout one && git apply --whitespace=fix patch && test_cmp expect one ' test_expect_success 'blank at EOF with --whitespace=fix (2)' ' { echo a; echo b; echo c; } >one && git add one && { echo a; echo c; } >expect && { cat expect; echo; echo; } >one && git diff -- one >patch && git checkout one && git apply --whitespace=fix patch && test_cmp expect one ' test_expect_success 'blank at EOF with --whitespace=fix (3)' ' { echo a; echo b; echo; } >one && git add one && { echo a; echo c; echo; } >expect && { cat expect; echo; echo; } >one && git diff -- one >patch && git checkout one && git apply --whitespace=fix patch && test_cmp expect one ' test_expect_success 'blank at end of hunk, not at EOF with --whitespace=fix' ' { echo a; echo b; echo; echo; echo; echo; echo; echo d; } >one && git add one && { echo a; echo c; echo; echo; echo; echo; echo; echo; echo d; } >expect && cp expect one && git diff -- one >patch && git checkout one && git apply --whitespace=fix patch && test_cmp expect one ' test_expect_success 'blank at EOF with --whitespace=warn' ' { echo a; echo b; echo c; } >one && git add one && echo >>one && cat one >expect && git diff -- one >patch && git checkout one && git apply --whitespace=warn patch 2>error && test_cmp expect one && grep "new blank line at EOF" error ' test_expect_success 'blank at EOF with --whitespace=error' ' { echo a; echo b; echo c; } >one && git add one && cat one >expect && echo >>one && git diff -- one >patch && git checkout one && test_must_fail git apply --whitespace=error patch 2>error && test_cmp expect one && grep "new blank line at EOF" error ' test_expect_success 'blank but not empty at EOF' ' { echo a; echo b; echo c; } >one && git add one && echo " " >>one && cat one >expect && git diff -- one >patch && git checkout one && git apply --whitespace=warn patch 2>error && test_cmp expect one && grep "new blank line at EOF" error ' test_expect_success 'applying beyond EOF requires one non-blank context line' ' { echo; echo; echo; echo; } >one && git add one && { echo b; } >>one && git diff -- one >patch && git checkout one && { echo a; echo; } >one && cp one expect && test_must_fail git apply --whitespace=fix patch && test_cmp expect one && test_must_fail git apply --ignore-space-change --whitespace=fix patch && test_cmp expect one ' test_expect_success 'tons of blanks at EOF should not apply' ' for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16; do echo; echo; echo; echo; done >one && git add one && echo a >>one && git diff -- one >patch && >one && test_must_fail git apply --whitespace=fix patch && test_must_fail git apply --ignore-space-change --whitespace=fix patch ' test_expect_success 'missing blank line at end with --whitespace=fix' ' echo a >one && echo >>one && git add one && echo b >>one && cp one expect && git diff -- one >patch && echo a >one && cp one saved-one && test_must_fail git apply patch && git apply --whitespace=fix patch && test_cmp expect one && mv saved-one one && git apply --ignore-space-change --whitespace=fix patch && test_cmp expect one ' test_expect_success 'two missing blank lines at end with --whitespace=fix' ' { echo a; echo; echo b; echo c; } >one && cp one no-blank-lines && { echo; echo; } >>one && git add one && echo d >>one && cp one expect && echo >>one && git diff -- one >patch && cp no-blank-lines one && test_must_fail git apply patch && git apply --whitespace=fix patch && test_cmp expect one && mv no-blank-lines one && test_must_fail git apply patch && git apply --ignore-space-change --whitespace=fix patch && test_cmp expect one ' test_expect_success 'missing blank line at end, insert before end, --whitespace=fix' ' { echo a; echo; } >one && git add one && { echo b; echo a; echo; } >one && cp one expect && git diff -- one >patch && echo a >one && test_must_fail git apply patch && git apply --whitespace=fix patch && test_cmp expect one ' test_expect_success 'shrink file with tons of missing blanks at end of file' ' { echo a; echo b; echo c; } >one && cp one no-blank-lines && for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16; do echo; echo; echo; echo; done >>one && git add one && echo a >one && cp one expect && git diff -- one >patch && cp no-blank-lines one && test_must_fail git apply patch && git apply --whitespace=fix patch && test_cmp expect one && mv no-blank-lines one && git apply --ignore-space-change --whitespace=fix patch && test_cmp expect one ' test_expect_success 'missing blanks at EOF must only match blank lines' ' { echo a; echo b; } >one && git add one && { echo c; echo d; } >>one && git diff -- one >patch && echo a >one && test_must_fail git apply patch && test_must_fail git apply --whitespace=fix patch && test_must_fail git apply --ignore-space-change --whitespace=fix patch ' sed -e's/Z//' >one <<EOF a b c Z EOF test_expect_success 'missing blank line should match context line with spaces' ' git add one && echo d >>one && git diff -- one >patch && { echo a; echo b; echo c; } >one && cp one expect && { echo; echo d; } >>expect && git add one && git apply --whitespace=fix patch && test_cmp expect one ' sed -e's/Z//' >one <<EOF a b c Z EOF test_expect_success 'same, but with the --ignore-space-option' ' git add one && echo d >>one && cp one expect && git diff -- one >patch && { echo a; echo b; echo c; } >one && git add one && git checkout-index -f one && git apply --ignore-space-change --whitespace=fix patch && test_cmp expect one ' test_expect_success 'same, but with CR-LF line endings && cr-at-eol set' ' git config core.whitespace cr-at-eol && printf "a\r\n" >one && printf "b\r\n" >>one && printf "c\r\n" >>one && cp one save-one && printf " \r\n" >>one && git add one && printf "d\r\n" >>one && cp one expect && git diff -- one >patch && mv save-one one && git apply --ignore-space-change --whitespace=fix patch && test_cmp expect one ' test_expect_success 'CR-LF line endings && add line && text=auto' ' git config --unset core.whitespace && printf "a\r\n" >one && cp one save-one && git add one && printf "b\r\n" >>one && cp one expect && git diff -- one >patch && mv save-one one && echo "one text=auto" >.gitattributes && git apply patch && test_cmp expect one ' test_expect_success 'CR-LF line endings && change line && text=auto' ' printf "a\r\n" >one && cp one save-one && git add one && printf "b\r\n" >one && cp one expect && git diff -- one >patch && mv save-one one && echo "one text=auto" >.gitattributes && git apply patch && test_cmp expect one ' test_expect_success 'LF in repo, CRLF in worktree && change line && text=auto' ' printf "a\n" >one && git add one && printf "b\r\n" >one && git diff -- one >patch && printf "a\r\n" >one && echo "one text=auto" >.gitattributes && git -c core.eol=CRLF apply patch && printf "b\r\n" >expect && test_cmp expect one ' test_expect_success 'whitespace=fix to expand' ' qz_to_tab_space >preimage <<-\EOF && QQa QQb QQc ZZZZZZZZZZZZZZZZd QQe QQf QQg EOF qz_to_tab_space >patch <<-\EOF && diff --git a/preimage b/preimage --- a/preimage +++ b/preimage @@ -1,7 +1,6 @@ QQa QQb QQc -QQd QQe QQf QQg EOF git -c core.whitespace=tab-in-indent apply --whitespace=fix patch ' test_expect_success 'whitespace check skipped for excluded paths' ' git config core.whitespace blank-at-eol && >used && >unused && git add used unused && echo "used" >used && echo "unused " >unused && git diff-files -p used unused >patch && git apply --include=used --stat --whitespace=error <patch ' test_done