5ae5ecb0fbc085f4723be236e1b74d42811d82ae
   1#!/bin/sh
   2
   3test_description='blob conversion via gitattributes'
   4
   5. ./test-lib.sh
   6
   7TEST_ROOT="$(pwd)"
   8
   9cat <<EOF >"$TEST_ROOT/rot13.sh"
  10#!$SHELL_PATH
  11tr \
  12  'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' \
  13  'nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM'
  14EOF
  15chmod +x "$TEST_ROOT/rot13.sh"
  16
  17generate_random_characters () {
  18        LEN=$1
  19        NAME=$2
  20        test-genrandom some-seed $LEN |
  21                perl -pe "s/./chr((ord($&) % 26) + ord('a'))/sge" >"$TEST_ROOT/$NAME"
  22}
  23
  24file_size () {
  25        perl -e 'print -s $ARGV[0]' "$1"
  26}
  27
  28filter_git () {
  29        rm -f rot13-filter.log &&
  30        git "$@"
  31}
  32
  33# Compare two files and ensure that `clean` and `smudge` respectively are
  34# called at least once if specified in the `expect` file. The actual
  35# invocation count is not relevant because their number can vary.
  36# c.f. http://public-inbox.org/git/xmqqshv18i8i.fsf@gitster.mtv.corp.google.com/
  37test_cmp_count () {
  38        expect=$1
  39        actual=$2
  40        for FILE in "$expect" "$actual"
  41        do
  42                sort "$FILE" | uniq -c |
  43                sed -e "s/^ *[0-9][0-9]*[       ]*IN: /x IN: /" >"$FILE.tmp" &&
  44                mv "$FILE.tmp" "$FILE" || return
  45        done &&
  46        test_cmp "$expect" "$actual"
  47}
  48
  49# Compare two files but exclude all `clean` invocations because Git can
  50# call `clean` zero or more times.
  51# c.f. http://public-inbox.org/git/xmqqshv18i8i.fsf@gitster.mtv.corp.google.com/
  52test_cmp_exclude_clean () {
  53        expect=$1
  54        actual=$2
  55        for FILE in "$expect" "$actual"
  56        do
  57                grep -v "IN: clean" "$FILE" >"$FILE.tmp" &&
  58                mv "$FILE.tmp" "$FILE"
  59        done &&
  60        test_cmp "$expect" "$actual"
  61}
  62
  63# Check that the contents of two files are equal and that their rot13 version
  64# is equal to the committed content.
  65test_cmp_committed_rot13 () {
  66        test_cmp "$1" "$2" &&
  67        "$TEST_ROOT/rot13.sh" <"$1" >expected &&
  68        git cat-file blob :"$2" >actual &&
  69        test_cmp expected actual
  70}
  71
  72test_expect_success setup '
  73        git config filter.rot13.smudge ./rot13.sh &&
  74        git config filter.rot13.clean ./rot13.sh &&
  75
  76        {
  77            echo "*.t filter=rot13"
  78            echo "*.i ident"
  79        } >.gitattributes &&
  80
  81        {
  82            echo a b c d e f g h i j k l m
  83            echo n o p q r s t u v w x y z
  84            echo '\''$Id$'\''
  85        } >test &&
  86        cat test >test.t &&
  87        cat test >test.o &&
  88        cat test >test.i &&
  89        git add test test.t test.i &&
  90        rm -f test test.t test.i &&
  91        git checkout -- test test.t test.i &&
  92
  93        echo "content-test2" >test2.o &&
  94        echo "content-test3 - filename with special characters" >"test3 '\''sq'\'',\$x=.o"
  95'
  96
  97script='s/^\$Id: \([0-9a-f]*\) \$/\1/p'
  98
  99test_expect_success check '
 100
 101        test_cmp test.o test &&
 102        test_cmp test.o test.t &&
 103
 104        # ident should be stripped in the repository
 105        git diff --raw --exit-code :test :test.i &&
 106        id=$(git rev-parse --verify :test) &&
 107        embedded=$(sed -ne "$script" test.i) &&
 108        test "z$id" = "z$embedded" &&
 109
 110        git cat-file blob :test.t >test.r &&
 111
 112        ./rot13.sh <test.o >test.t &&
 113        test_cmp test.r test.t
 114'
 115
 116# If an expanded ident ever gets into the repository, we want to make sure that
 117# it is collapsed before being expanded again on checkout
 118test_expect_success expanded_in_repo '
 119        {
 120                echo "File with expanded keywords"
 121                echo "\$Id\$"
 122                echo "\$Id:\$"
 123                echo "\$Id: 0000000000000000000000000000000000000000 \$"
 124                echo "\$Id: NoSpaceAtEnd\$"
 125                echo "\$Id:NoSpaceAtFront \$"
 126                echo "\$Id:NoSpaceAtEitherEnd\$"
 127                echo "\$Id: NoTerminatingSymbol"
 128                echo "\$Id: Foreign Commit With Spaces \$"
 129        } >expanded-keywords.0 &&
 130
 131        {
 132                cat expanded-keywords.0 &&
 133                printf "\$Id: NoTerminatingSymbolAtEOF"
 134        } >expanded-keywords &&
 135        cat expanded-keywords >expanded-keywords-crlf &&
 136        git add expanded-keywords expanded-keywords-crlf &&
 137        git commit -m "File with keywords expanded" &&
 138        id=$(git rev-parse --verify :expanded-keywords) &&
 139
 140        {
 141                echo "File with expanded keywords"
 142                echo "\$Id: $id \$"
 143                echo "\$Id: $id \$"
 144                echo "\$Id: $id \$"
 145                echo "\$Id: $id \$"
 146                echo "\$Id: $id \$"
 147                echo "\$Id: $id \$"
 148                echo "\$Id: NoTerminatingSymbol"
 149                echo "\$Id: Foreign Commit With Spaces \$"
 150        } >expected-output.0 &&
 151        {
 152                cat expected-output.0 &&
 153                printf "\$Id: NoTerminatingSymbolAtEOF"
 154        } >expected-output &&
 155        {
 156                append_cr <expected-output.0 &&
 157                printf "\$Id: NoTerminatingSymbolAtEOF"
 158        } >expected-output-crlf &&
 159        {
 160                echo "expanded-keywords ident"
 161                echo "expanded-keywords-crlf ident text eol=crlf"
 162        } >>.gitattributes &&
 163
 164        rm -f expanded-keywords expanded-keywords-crlf &&
 165
 166        git checkout -- expanded-keywords &&
 167        test_cmp expanded-keywords expected-output &&
 168
 169        git checkout -- expanded-keywords-crlf &&
 170        test_cmp expanded-keywords-crlf expected-output-crlf
 171'
 172
 173# The use of %f in a filter definition is expanded to the path to
 174# the filename being smudged or cleaned.  It must be shell escaped.
 175# First, set up some interesting file names and pet them in
 176# .gitattributes.
 177test_expect_success 'filter shell-escaped filenames' '
 178        cat >argc.sh <<-EOF &&
 179        #!$SHELL_PATH
 180        cat >/dev/null
 181        echo argc: \$# "\$@"
 182        EOF
 183        normal=name-no-magic &&
 184        special="name  with '\''sq'\'' and \$x" &&
 185        echo some test text >"$normal" &&
 186        echo some test text >"$special" &&
 187        git add "$normal" "$special" &&
 188        git commit -q -m "add files" &&
 189        echo "name* filter=argc" >.gitattributes &&
 190
 191        # delete the files and check them out again, using a smudge filter
 192        # that will count the args and echo the command-line back to us
 193        test_config filter.argc.smudge "sh ./argc.sh %f" &&
 194        rm "$normal" "$special" &&
 195        git checkout -- "$normal" "$special" &&
 196
 197        # make sure argc.sh counted the right number of args
 198        echo "argc: 1 $normal" >expect &&
 199        test_cmp expect "$normal" &&
 200        echo "argc: 1 $special" >expect &&
 201        test_cmp expect "$special" &&
 202
 203        # do the same thing, but with more args in the filter expression
 204        test_config filter.argc.smudge "sh ./argc.sh %f --my-extra-arg" &&
 205        rm "$normal" "$special" &&
 206        git checkout -- "$normal" "$special" &&
 207
 208        # make sure argc.sh counted the right number of args
 209        echo "argc: 2 $normal --my-extra-arg" >expect &&
 210        test_cmp expect "$normal" &&
 211        echo "argc: 2 $special --my-extra-arg" >expect &&
 212        test_cmp expect "$special" &&
 213        :
 214'
 215
 216test_expect_success 'required filter should filter data' '
 217        test_config filter.required.smudge ./rot13.sh &&
 218        test_config filter.required.clean ./rot13.sh &&
 219        test_config filter.required.required true &&
 220
 221        echo "*.r filter=required" >.gitattributes &&
 222
 223        cat test.o >test.r &&
 224        git add test.r &&
 225
 226        rm -f test.r &&
 227        git checkout -- test.r &&
 228        test_cmp test.o test.r &&
 229
 230        ./rot13.sh <test.o >expected &&
 231        git cat-file blob :test.r >actual &&
 232        test_cmp expected actual
 233'
 234
 235test_expect_success 'required filter smudge failure' '
 236        test_config filter.failsmudge.smudge false &&
 237        test_config filter.failsmudge.clean cat &&
 238        test_config filter.failsmudge.required true &&
 239
 240        echo "*.fs filter=failsmudge" >.gitattributes &&
 241
 242        echo test >test.fs &&
 243        git add test.fs &&
 244        rm -f test.fs &&
 245        test_must_fail git checkout -- test.fs
 246'
 247
 248test_expect_success 'required filter clean failure' '
 249        test_config filter.failclean.smudge cat &&
 250        test_config filter.failclean.clean false &&
 251        test_config filter.failclean.required true &&
 252
 253        echo "*.fc filter=failclean" >.gitattributes &&
 254
 255        echo test >test.fc &&
 256        test_must_fail git add test.fc
 257'
 258
 259test_expect_success 'filtering large input to small output should use little memory' '
 260        test_config filter.devnull.clean "cat >/dev/null" &&
 261        test_config filter.devnull.required true &&
 262        for i in $(test_seq 1 30); do printf "%1048576d" 1; done >30MB &&
 263        echo "30MB filter=devnull" >.gitattributes &&
 264        GIT_MMAP_LIMIT=1m GIT_ALLOC_LIMIT=1m git add 30MB
 265'
 266
 267test_expect_success 'filter that does not read is fine' '
 268        test-genrandom foo $((128 * 1024 + 1)) >big &&
 269        echo "big filter=epipe" >.gitattributes &&
 270        test_config filter.epipe.clean "echo xyzzy" &&
 271        git add big &&
 272        git cat-file blob :big >actual &&
 273        echo xyzzy >expect &&
 274        test_cmp expect actual
 275'
 276
 277test_expect_success EXPENSIVE 'filter large file' '
 278        test_config filter.largefile.smudge cat &&
 279        test_config filter.largefile.clean cat &&
 280        for i in $(test_seq 1 2048); do printf "%1048576d" 1; done >2GB &&
 281        echo "2GB filter=largefile" >.gitattributes &&
 282        git add 2GB 2>err &&
 283        test_must_be_empty err &&
 284        rm -f 2GB &&
 285        git checkout -- 2GB 2>err &&
 286        test_must_be_empty err
 287'
 288
 289test_expect_success "filter: clean empty file" '
 290        test_config filter.in-repo-header.clean  "echo cleaned && cat" &&
 291        test_config filter.in-repo-header.smudge "sed 1d" &&
 292
 293        echo "empty-in-worktree    filter=in-repo-header" >>.gitattributes &&
 294        >empty-in-worktree &&
 295
 296        echo cleaned >expected &&
 297        git add empty-in-worktree &&
 298        git show :empty-in-worktree >actual &&
 299        test_cmp expected actual
 300'
 301
 302test_expect_success "filter: smudge empty file" '
 303        test_config filter.empty-in-repo.clean "cat >/dev/null" &&
 304        test_config filter.empty-in-repo.smudge "echo smudged && cat" &&
 305
 306        echo "empty-in-repo filter=empty-in-repo" >>.gitattributes &&
 307        echo dead data walking >empty-in-repo &&
 308        git add empty-in-repo &&
 309
 310        echo smudged >expected &&
 311        git checkout-index --prefix=filtered- empty-in-repo &&
 312        test_cmp expected filtered-empty-in-repo
 313'
 314
 315test_expect_success 'disable filter with empty override' '
 316        test_config_global filter.disable.smudge false &&
 317        test_config_global filter.disable.clean false &&
 318        test_config filter.disable.smudge false &&
 319        test_config filter.disable.clean false &&
 320
 321        echo "*.disable filter=disable" >.gitattributes &&
 322
 323        echo test >test.disable &&
 324        git -c filter.disable.clean= add test.disable 2>err &&
 325        test_must_be_empty err &&
 326        rm -f test.disable &&
 327        git -c filter.disable.smudge= checkout -- test.disable 2>err &&
 328        test_must_be_empty err
 329'
 330
 331test_expect_success 'diff does not reuse worktree files that need cleaning' '
 332        test_config filter.counter.clean "echo . >>count; sed s/^/clean:/" &&
 333        echo "file filter=counter" >.gitattributes &&
 334        test_commit one file &&
 335        test_commit two file &&
 336
 337        >count &&
 338        git diff-tree -p HEAD &&
 339        test_line_count = 0 count
 340'
 341
 342test_expect_success PERL 'required process filter should filter data' '
 343        test_config_global filter.protocol.process "$TEST_DIRECTORY/t0021/rot13-filter.pl clean smudge" &&
 344        test_config_global filter.protocol.required true &&
 345        rm -rf repo &&
 346        mkdir repo &&
 347        (
 348                cd repo &&
 349                git init &&
 350
 351                echo "git-stderr.log" >.gitignore &&
 352                echo "*.r filter=protocol" >.gitattributes &&
 353                git add . &&
 354                git commit . -m "test commit 1" &&
 355                git branch empty-branch &&
 356
 357                cp "$TEST_ROOT/test.o" test.r &&
 358                cp "$TEST_ROOT/test2.o" test2.r &&
 359                mkdir testsubdir &&
 360                cp "$TEST_ROOT/test3 '\''sq'\'',\$x=.o" "testsubdir/test3 '\''sq'\'',\$x=.r" &&
 361                >test4-empty.r &&
 362
 363                S=$(file_size test.r) &&
 364                S2=$(file_size test2.r) &&
 365                S3=$(file_size "testsubdir/test3 '\''sq'\'',\$x=.r") &&
 366
 367                filter_git add . &&
 368                cat >expected.log <<-EOF &&
 369                        START
 370                        init handshake complete
 371                        IN: clean test.r $S [OK] -- OUT: $S . [OK]
 372                        IN: clean test2.r $S2 [OK] -- OUT: $S2 . [OK]
 373                        IN: clean test4-empty.r 0 [OK] -- OUT: 0  [OK]
 374                        IN: clean testsubdir/test3 '\''sq'\'',\$x=.r $S3 [OK] -- OUT: $S3 . [OK]
 375                        STOP
 376                EOF
 377                test_cmp_count expected.log rot13-filter.log &&
 378
 379                filter_git commit . -m "test commit 2" &&
 380                cat >expected.log <<-EOF &&
 381                        START
 382                        init handshake complete
 383                        IN: clean test.r $S [OK] -- OUT: $S . [OK]
 384                        IN: clean test2.r $S2 [OK] -- OUT: $S2 . [OK]
 385                        IN: clean test4-empty.r 0 [OK] -- OUT: 0  [OK]
 386                        IN: clean testsubdir/test3 '\''sq'\'',\$x=.r $S3 [OK] -- OUT: $S3 . [OK]
 387                        IN: clean test.r $S [OK] -- OUT: $S . [OK]
 388                        IN: clean test2.r $S2 [OK] -- OUT: $S2 . [OK]
 389                        IN: clean test4-empty.r 0 [OK] -- OUT: 0  [OK]
 390                        IN: clean testsubdir/test3 '\''sq'\'',\$x=.r $S3 [OK] -- OUT: $S3 . [OK]
 391                        STOP
 392                EOF
 393                test_cmp_count expected.log rot13-filter.log &&
 394
 395                rm -f test2.r "testsubdir/test3 '\''sq'\'',\$x=.r" &&
 396
 397                filter_git checkout --quiet --no-progress . &&
 398                cat >expected.log <<-EOF &&
 399                        START
 400                        init handshake complete
 401                        IN: smudge test2.r $S2 [OK] -- OUT: $S2 . [OK]
 402                        IN: smudge testsubdir/test3 '\''sq'\'',\$x=.r $S3 [OK] -- OUT: $S3 . [OK]
 403                        STOP
 404                EOF
 405                test_cmp_exclude_clean expected.log rot13-filter.log &&
 406
 407                filter_git checkout --quiet --no-progress empty-branch &&
 408                cat >expected.log <<-EOF &&
 409                        START
 410                        init handshake complete
 411                        IN: clean test.r $S [OK] -- OUT: $S . [OK]
 412                        STOP
 413                EOF
 414                test_cmp_exclude_clean expected.log rot13-filter.log &&
 415
 416                filter_git checkout --quiet --no-progress master &&
 417                cat >expected.log <<-EOF &&
 418                        START
 419                        init handshake complete
 420                        IN: smudge test.r $S [OK] -- OUT: $S . [OK]
 421                        IN: smudge test2.r $S2 [OK] -- OUT: $S2 . [OK]
 422                        IN: smudge test4-empty.r 0 [OK] -- OUT: 0  [OK]
 423                        IN: smudge testsubdir/test3 '\''sq'\'',\$x=.r $S3 [OK] -- OUT: $S3 . [OK]
 424                        STOP
 425                EOF
 426                test_cmp_exclude_clean expected.log rot13-filter.log &&
 427
 428                test_cmp_committed_rot13 "$TEST_ROOT/test.o" test.r &&
 429                test_cmp_committed_rot13 "$TEST_ROOT/test2.o" test2.r &&
 430                test_cmp_committed_rot13 "$TEST_ROOT/test3 '\''sq'\'',\$x=.o" "testsubdir/test3 '\''sq'\'',\$x=.r"
 431        )
 432'
 433
 434test_expect_success PERL 'required process filter takes precedence' '
 435        test_config_global filter.protocol.clean false &&
 436        test_config_global filter.protocol.process "$TEST_DIRECTORY/t0021/rot13-filter.pl clean" &&
 437        test_config_global filter.protocol.required true &&
 438        rm -rf repo &&
 439        mkdir repo &&
 440        (
 441                cd repo &&
 442                git init &&
 443
 444                echo "*.r filter=protocol" >.gitattributes &&
 445                cp "$TEST_ROOT/test.o" test.r &&
 446                S=$(file_size test.r) &&
 447
 448                # Check that the process filter is invoked here
 449                filter_git add . &&
 450                cat >expected.log <<-EOF &&
 451                        START
 452                        init handshake complete
 453                        IN: clean test.r $S [OK] -- OUT: $S . [OK]
 454                        STOP
 455                EOF
 456                test_cmp_count expected.log rot13-filter.log
 457        )
 458'
 459
 460test_expect_success PERL 'required process filter should be used only for "clean" operation only' '
 461        test_config_global filter.protocol.process "$TEST_DIRECTORY/t0021/rot13-filter.pl clean" &&
 462        rm -rf repo &&
 463        mkdir repo &&
 464        (
 465                cd repo &&
 466                git init &&
 467
 468                echo "*.r filter=protocol" >.gitattributes &&
 469                cp "$TEST_ROOT/test.o" test.r &&
 470                S=$(file_size test.r) &&
 471
 472                filter_git add . &&
 473                cat >expected.log <<-EOF &&
 474                        START
 475                        init handshake complete
 476                        IN: clean test.r $S [OK] -- OUT: $S . [OK]
 477                        STOP
 478                EOF
 479                test_cmp_count expected.log rot13-filter.log &&
 480
 481                rm test.r &&
 482
 483                filter_git checkout --quiet --no-progress . &&
 484                # If the filter would be used for "smudge", too, we would see
 485                # "IN: smudge test.r 57 [OK] -- OUT: 57 . [OK]" here
 486                cat >expected.log <<-EOF &&
 487                        START
 488                        init handshake complete
 489                        STOP
 490                EOF
 491                test_cmp_exclude_clean expected.log rot13-filter.log
 492        )
 493'
 494
 495test_expect_success PERL 'required process filter should process multiple packets' '
 496        test_config_global filter.protocol.process "$TEST_DIRECTORY/t0021/rot13-filter.pl clean smudge" &&
 497        test_config_global filter.protocol.required true &&
 498
 499        rm -rf repo &&
 500        mkdir repo &&
 501        (
 502                cd repo &&
 503                git init &&
 504
 505                # Generate data requiring 1, 2, 3 packets
 506                S=65516 && # PKTLINE_DATA_MAXLEN -> Maximal size of a packet
 507                generate_random_characters $(($S    )) 1pkt_1__.file &&
 508                generate_random_characters $(($S  +1)) 2pkt_1+1.file &&
 509                generate_random_characters $(($S*2-1)) 2pkt_2-1.file &&
 510                generate_random_characters $(($S*2  )) 2pkt_2__.file &&
 511                generate_random_characters $(($S*2+1)) 3pkt_2+1.file &&
 512
 513                for FILE in "$TEST_ROOT"/*.file
 514                do
 515                        cp "$FILE" . &&
 516                        "$TEST_ROOT/rot13.sh" <"$FILE" >"$FILE.rot13"
 517                done &&
 518
 519                echo "*.file filter=protocol" >.gitattributes &&
 520                filter_git add *.file .gitattributes &&
 521                cat >expected.log <<-EOF &&
 522                        START
 523                        init handshake complete
 524                        IN: clean 1pkt_1__.file $(($S    )) [OK] -- OUT: $(($S    )) . [OK]
 525                        IN: clean 2pkt_1+1.file $(($S  +1)) [OK] -- OUT: $(($S  +1)) .. [OK]
 526                        IN: clean 2pkt_2-1.file $(($S*2-1)) [OK] -- OUT: $(($S*2-1)) .. [OK]
 527                        IN: clean 2pkt_2__.file $(($S*2  )) [OK] -- OUT: $(($S*2  )) .. [OK]
 528                        IN: clean 3pkt_2+1.file $(($S*2+1)) [OK] -- OUT: $(($S*2+1)) ... [OK]
 529                        STOP
 530                EOF
 531                test_cmp_count expected.log rot13-filter.log &&
 532
 533                rm -f *.file &&
 534
 535                filter_git checkout --quiet --no-progress -- *.file &&
 536                cat >expected.log <<-EOF &&
 537                        START
 538                        init handshake complete
 539                        IN: smudge 1pkt_1__.file $(($S    )) [OK] -- OUT: $(($S    )) . [OK]
 540                        IN: smudge 2pkt_1+1.file $(($S  +1)) [OK] -- OUT: $(($S  +1)) .. [OK]
 541                        IN: smudge 2pkt_2-1.file $(($S*2-1)) [OK] -- OUT: $(($S*2-1)) .. [OK]
 542                        IN: smudge 2pkt_2__.file $(($S*2  )) [OK] -- OUT: $(($S*2  )) .. [OK]
 543                        IN: smudge 3pkt_2+1.file $(($S*2+1)) [OK] -- OUT: $(($S*2+1)) ... [OK]
 544                        STOP
 545                EOF
 546                test_cmp_exclude_clean expected.log rot13-filter.log &&
 547
 548                for FILE in *.file
 549                do
 550                        test_cmp_committed_rot13 "$TEST_ROOT/$FILE" $FILE
 551                done
 552        )
 553'
 554
 555test_expect_success PERL 'required process filter with clean error should fail' '
 556        test_config_global filter.protocol.process "$TEST_DIRECTORY/t0021/rot13-filter.pl clean smudge" &&
 557        test_config_global filter.protocol.required true &&
 558        rm -rf repo &&
 559        mkdir repo &&
 560        (
 561                cd repo &&
 562                git init &&
 563
 564                echo "*.r filter=protocol" >.gitattributes &&
 565
 566                cp "$TEST_ROOT/test.o" test.r &&
 567                echo "this is going to fail" >clean-write-fail.r &&
 568                echo "content-test3-subdir" >test3.r &&
 569
 570                test_must_fail git add .
 571        )
 572'
 573
 574test_expect_success PERL 'process filter should restart after unexpected write failure' '
 575        test_config_global filter.protocol.process "$TEST_DIRECTORY/t0021/rot13-filter.pl clean smudge" &&
 576        rm -rf repo &&
 577        mkdir repo &&
 578        (
 579                cd repo &&
 580                git init &&
 581
 582                echo "*.r filter=protocol" >.gitattributes &&
 583
 584                cp "$TEST_ROOT/test.o" test.r &&
 585                cp "$TEST_ROOT/test2.o" test2.r &&
 586                echo "this is going to fail" >smudge-write-fail.o &&
 587                cp smudge-write-fail.o smudge-write-fail.r &&
 588
 589                S=$(file_size test.r) &&
 590                S2=$(file_size test2.r) &&
 591                SF=$(file_size smudge-write-fail.r) &&
 592
 593                git add . &&
 594                rm -f *.r &&
 595
 596                rm -f rot13-filter.log &&
 597                git checkout --quiet --no-progress . 2>git-stderr.log &&
 598
 599                grep "smudge write error at" git-stderr.log &&
 600                grep "error: external filter" git-stderr.log &&
 601
 602                cat >expected.log <<-EOF &&
 603                        START
 604                        init handshake complete
 605                        IN: smudge smudge-write-fail.r $SF [OK] -- OUT: $SF [WRITE FAIL]
 606                        START
 607                        init handshake complete
 608                        IN: smudge test.r $S [OK] -- OUT: $S . [OK]
 609                        IN: smudge test2.r $S2 [OK] -- OUT: $S2 . [OK]
 610                        STOP
 611                EOF
 612                test_cmp_exclude_clean expected.log rot13-filter.log &&
 613
 614                test_cmp_committed_rot13 "$TEST_ROOT/test.o" test.r &&
 615                test_cmp_committed_rot13 "$TEST_ROOT/test2.o" test2.r &&
 616
 617                # Smudge failed
 618                ! test_cmp smudge-write-fail.o smudge-write-fail.r &&
 619                "$TEST_ROOT/rot13.sh" <smudge-write-fail.o >expected &&
 620                git cat-file blob :smudge-write-fail.r >actual &&
 621                test_cmp expected actual
 622        )
 623'
 624
 625test_expect_success PERL 'process filter should not be restarted if it signals an error' '
 626        test_config_global filter.protocol.process "$TEST_DIRECTORY/t0021/rot13-filter.pl clean smudge" &&
 627        rm -rf repo &&
 628        mkdir repo &&
 629        (
 630                cd repo &&
 631                git init &&
 632
 633                echo "*.r filter=protocol" >.gitattributes &&
 634
 635                cp "$TEST_ROOT/test.o" test.r &&
 636                cp "$TEST_ROOT/test2.o" test2.r &&
 637                echo "this will cause an error" >error.o &&
 638                cp error.o error.r &&
 639
 640                S=$(file_size test.r) &&
 641                S2=$(file_size test2.r) &&
 642                SE=$(file_size error.r) &&
 643
 644                git add . &&
 645                rm -f *.r &&
 646
 647                filter_git checkout --quiet --no-progress . &&
 648                cat >expected.log <<-EOF &&
 649                        START
 650                        init handshake complete
 651                        IN: smudge error.r $SE [OK] -- OUT: 0 [ERROR]
 652                        IN: smudge test.r $S [OK] -- OUT: $S . [OK]
 653                        IN: smudge test2.r $S2 [OK] -- OUT: $S2 . [OK]
 654                        STOP
 655                EOF
 656                test_cmp_exclude_clean expected.log rot13-filter.log &&
 657
 658                test_cmp_committed_rot13 "$TEST_ROOT/test.o" test.r &&
 659                test_cmp_committed_rot13 "$TEST_ROOT/test2.o" test2.r &&
 660                test_cmp error.o error.r
 661        )
 662'
 663
 664test_expect_success PERL 'process filter abort stops processing of all further files' '
 665        test_config_global filter.protocol.process "$TEST_DIRECTORY/t0021/rot13-filter.pl clean smudge" &&
 666        rm -rf repo &&
 667        mkdir repo &&
 668        (
 669                cd repo &&
 670                git init &&
 671
 672                echo "*.r filter=protocol" >.gitattributes &&
 673
 674                cp "$TEST_ROOT/test.o" test.r &&
 675                cp "$TEST_ROOT/test2.o" test2.r &&
 676                echo "error this blob and all future blobs" >abort.o &&
 677                cp abort.o abort.r &&
 678
 679                SA=$(file_size abort.r) &&
 680
 681                git add . &&
 682                rm -f *.r &&
 683
 684                # Note: This test assumes that Git filters files in alphabetical
 685                # order ("abort.r" before "test.r").
 686                filter_git checkout --quiet --no-progress . &&
 687                cat >expected.log <<-EOF &&
 688                        START
 689                        init handshake complete
 690                        IN: smudge abort.r $SA [OK] -- OUT: 0 [ABORT]
 691                        STOP
 692                EOF
 693                test_cmp_exclude_clean expected.log rot13-filter.log &&
 694
 695                test_cmp "$TEST_ROOT/test.o" test.r &&
 696                test_cmp "$TEST_ROOT/test2.o" test2.r &&
 697                test_cmp abort.o abort.r
 698        )
 699'
 700
 701test_expect_success PERL 'invalid process filter must fail (and not hang!)' '
 702        test_config_global filter.protocol.process cat &&
 703        test_config_global filter.protocol.required true &&
 704        rm -rf repo &&
 705        mkdir repo &&
 706        (
 707                cd repo &&
 708                git init &&
 709
 710                echo "*.r filter=protocol" >.gitattributes &&
 711
 712                cp "$TEST_ROOT/test.o" test.r &&
 713                test_must_fail git add . 2>git-stderr.log &&
 714                grep "does not support filter protocol version" git-stderr.log
 715        )
 716'
 717
 718test_done