t / t4124-apply-ws-rule.shon commit revision: new rev^-n shorthand for rev^n..rev (8779351)
   1#!/bin/sh
   2
   3test_description='core.whitespace rules and git apply'
   4
   5. ./test-lib.sh
   6
   7prepare_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
  37apply_patch () {
  38        >target &&
  39        sed -e "s|\([ab]\)/file|\1/target|" <patch |
  40        git apply "$@"
  41}
  42
  43test_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
  75test_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
  86test_expect_success 'whitespace=nowarn, default rule' '
  87
  88        apply_patch --whitespace=nowarn &&
  89        test_cmp file target
  90
  91'
  92
  93test_expect_success 'whitespace=warn, default rule' '
  94
  95        apply_patch --whitespace=warn &&
  96        test_cmp file target
  97
  98'
  99
 100test_expect_success 'whitespace=error-all, default rule' '
 101
 102        test_must_fail apply_patch --whitespace=error-all &&
 103        ! test -s target
 104
 105'
 106
 107test_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
 115test_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
 124test_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
 152for t in - ''
 153do
 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
 192done
 193
 194create_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
 208test_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
 216test_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
 231test_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
 243test_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
 255test_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
 267test_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
 280test_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
 293test_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
 306test_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
 321test_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
 334test_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
 351test_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
 370test_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
 382test_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
 401test_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
 413sed -e's/Z//' >one <<EOF
 414a
 415b
 416c
 417                      Z
 418EOF
 419
 420test_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
 433sed -e's/Z//' >one <<EOF
 434a
 435b
 436c
 437                      Z
 438EOF
 439
 440test_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
 453test_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
 470test_expect_success 'same, but with CR-LF line endings && cr-at-eol unset' '
 471        git config --unset core.whitespace &&
 472        printf "a\r\n" >one &&
 473        printf "b\r\n" >>one &&
 474        printf "c\r\n" >>one &&
 475        cp one save-one &&
 476        printf "                 \r\n" >>one &&
 477        git add one &&
 478        cp one expect &&
 479        printf "d\r\n" >>one &&
 480        git diff -- one >patch &&
 481        mv save-one one &&
 482        echo d >>expect &&
 483
 484        git apply --ignore-space-change --whitespace=fix patch &&
 485        test_cmp one expect
 486'
 487
 488test_expect_success 'whitespace=fix to expand' '
 489        qz_to_tab_space >preimage <<-\EOF &&
 490        QQa
 491        QQb
 492        QQc
 493        ZZZZZZZZZZZZZZZZd
 494        QQe
 495        QQf
 496        QQg
 497        EOF
 498        qz_to_tab_space >patch <<-\EOF &&
 499        diff --git a/preimage b/preimage
 500        --- a/preimage
 501        +++ b/preimage
 502        @@ -1,7 +1,6 @@
 503         QQa
 504         QQb
 505         QQc
 506        -QQd
 507         QQe
 508         QQf
 509         QQg
 510        EOF
 511        git -c core.whitespace=tab-in-indent apply --whitespace=fix patch
 512'
 513
 514test_expect_success 'whitespace check skipped for excluded paths' '
 515        git config core.whitespace blank-at-eol &&
 516        >used &&
 517        >unused &&
 518        git add used unused &&
 519        echo "used" >used &&
 520        echo "unused " >unused &&
 521        git diff-files -p used unused >patch &&
 522        git apply --include=used --stat --whitespace=error <patch
 523'
 524
 525test_done