t / t0008-ignores.shon commit Merge branch 'rr/complete-difftool-fixup' (bdff0e3)
   1#!/bin/sh
   2
   3test_description=check-ignore
   4
   5. ./test-lib.sh
   6
   7init_vars () {
   8        global_excludes="$(pwd)/global-excludes"
   9}
  10
  11enable_global_excludes () {
  12        init_vars &&
  13        git config core.excludesfile "$global_excludes"
  14}
  15
  16expect_in () {
  17        dest="$HOME/expected-$1" text="$2"
  18        if test -z "$text"
  19        then
  20                >"$dest" # avoid newline
  21        else
  22                echo "$text" >"$dest"
  23        fi
  24}
  25
  26expect () {
  27        expect_in stdout "$1"
  28}
  29
  30expect_from_stdin () {
  31        cat >"$HOME/expected-stdout"
  32}
  33
  34test_stderr () {
  35        expected="$1"
  36        expect_in stderr "$1" &&
  37        test_cmp "$HOME/expected-stderr" "$HOME/stderr"
  38}
  39
  40stderr_contains () {
  41        regexp="$1"
  42        if grep "$regexp" "$HOME/stderr"
  43        then
  44                return 0
  45        else
  46                echo "didn't find /$regexp/ in $HOME/stderr"
  47                cat "$HOME/stderr"
  48                return 1
  49        fi
  50}
  51
  52stderr_empty_on_success () {
  53        expect_code="$1"
  54        if test $expect_code = 0
  55        then
  56                test_stderr ""
  57        else
  58                # If we expect failure then stderr might or might not be empty
  59                # due to --quiet - the caller can check its contents
  60                return 0
  61        fi
  62}
  63
  64test_check_ignore () {
  65        args="$1" expect_code="${2:-0}" global_args="$3"
  66
  67        init_vars &&
  68        rm -f "$HOME/stdout" "$HOME/stderr" "$HOME/cmd" &&
  69        echo git $global_args check-ignore $quiet_opt $verbose_opt $non_matching_opt $args \
  70                >"$HOME/cmd" &&
  71        echo "$expect_code" >"$HOME/expected-exit-code" &&
  72        test_expect_code "$expect_code" \
  73                git $global_args check-ignore $quiet_opt $verbose_opt $non_matching_opt $args \
  74                >"$HOME/stdout" 2>"$HOME/stderr" &&
  75        test_cmp "$HOME/expected-stdout" "$HOME/stdout" &&
  76        stderr_empty_on_success "$expect_code"
  77}
  78
  79# Runs the same code with 4 different levels of output verbosity:
  80#
  81#   1. with -q / --quiet
  82#   2. with default verbosity
  83#   3. with -v / --verbose
  84#   4. with -v / --verbose, *and* -n / --non-matching
  85#
  86# expecting success each time.  Takes advantage of the fact that
  87# check-ignore --verbose output is the same as normal output except
  88# for the extra first column.
  89#
  90# Arguments:
  91#   - (optional) prereqs for this test, e.g. 'SYMLINKS'
  92#   - test name
  93#   - output to expect from the fourth verbosity mode (the output
  94#     from the other verbosity modes is automatically inferred
  95#     from this value)
  96#   - code to run (should invoke test_check_ignore)
  97test_expect_success_multi () {
  98        prereq=
  99        if test $# -eq 4
 100        then
 101                prereq=$1
 102                shift
 103        fi
 104        testname="$1" expect_all="$2" code="$3"
 105
 106        expect_verbose=$( echo "$expect_all" | grep -v '^::     ' )
 107        expect=$( echo "$expect_verbose" | sed -e 's/.* //' )
 108
 109        test_expect_success $prereq "$testname" '
 110                expect "$expect" &&
 111                eval "$code"
 112        '
 113
 114        # --quiet is only valid when a single pattern is passed
 115        if test $( echo "$expect_all" | wc -l ) = 1
 116        then
 117                for quiet_opt in '-q' '--quiet'
 118                do
 119                        test_expect_success $prereq "$testname${quiet_opt:+ with $quiet_opt}" "
 120                        expect '' &&
 121                        $code
 122                "
 123                done
 124                quiet_opt=
 125        fi
 126
 127        for verbose_opt in '-v' '--verbose'
 128        do
 129                for non_matching_opt in '' ' -n' ' --non-matching'
 130                do
 131                        if test -n "$non_matching_opt"
 132                        then
 133                                my_expect="$expect_all"
 134                        else
 135                                my_expect="$expect_verbose"
 136                        fi
 137
 138                        test_code="
 139                                expect '$my_expect' &&
 140                                $code
 141                        "
 142                        opts="$verbose_opt$non_matching_opt"
 143                        test_expect_success $prereq "$testname${opts:+ with $opts}" "$test_code"
 144                done
 145        done
 146        verbose_opt=
 147        non_matching_opt=
 148}
 149
 150test_expect_success 'setup' '
 151        init_vars &&
 152        mkdir -p a/b/ignored-dir a/submodule b &&
 153        if test_have_prereq SYMLINKS
 154        then
 155                ln -s b a/symlink
 156        fi &&
 157        (
 158                cd a/submodule &&
 159                git init &&
 160                echo a >a &&
 161                git add a &&
 162                git commit -m"commit in submodule"
 163        ) &&
 164        git add a/submodule &&
 165        cat <<-\EOF >.gitignore &&
 166                one
 167                ignored-*
 168                top-level-dir/
 169        EOF
 170        for dir in . a
 171        do
 172                : >$dir/not-ignored &&
 173                : >$dir/ignored-and-untracked &&
 174                : >$dir/ignored-but-in-index
 175        done &&
 176        git add -f ignored-but-in-index a/ignored-but-in-index &&
 177        cat <<-\EOF >a/.gitignore &&
 178                two*
 179                *three
 180        EOF
 181        cat <<-\EOF >a/b/.gitignore &&
 182                four
 183                five
 184                # this comment should affect the line numbers
 185                six
 186                ignored-dir/
 187                # and so should this blank line:
 188
 189                !on*
 190                !two
 191        EOF
 192        echo "seven" >a/b/ignored-dir/.gitignore &&
 193        test -n "$HOME" &&
 194        cat <<-\EOF >"$global_excludes" &&
 195                globalone
 196                !globaltwo
 197                globalthree
 198        EOF
 199        cat <<-\EOF >>.git/info/exclude
 200                per-repo
 201        EOF
 202'
 203
 204############################################################################
 205#
 206# test invalid inputs
 207
 208test_expect_success_multi '. corner-case' '::   .' '
 209        test_check_ignore . 1
 210'
 211
 212test_expect_success_multi 'empty command line' '' '
 213        test_check_ignore "" 128 &&
 214        stderr_contains "fatal: no path specified"
 215'
 216
 217test_expect_success_multi '--stdin with empty STDIN' '' '
 218        test_check_ignore "--stdin" 1 </dev/null &&
 219        test_stderr ""
 220'
 221
 222test_expect_success '-q with multiple args' '
 223        expect "" &&
 224        test_check_ignore "-q one two" 128 &&
 225        stderr_contains "fatal: --quiet is only valid with a single pathname"
 226'
 227
 228test_expect_success '--quiet with multiple args' '
 229        expect "" &&
 230        test_check_ignore "--quiet one two" 128 &&
 231        stderr_contains "fatal: --quiet is only valid with a single pathname"
 232'
 233
 234for verbose_opt in '-v' '--verbose'
 235do
 236        for quiet_opt in '-q' '--quiet'
 237        do
 238                test_expect_success "$quiet_opt $verbose_opt" "
 239                        expect '' &&
 240                        test_check_ignore '$quiet_opt $verbose_opt foo' 128 &&
 241                        stderr_contains 'fatal: cannot have both --quiet and --verbose'
 242                "
 243        done
 244done
 245
 246test_expect_success '--quiet with multiple args' '
 247        expect "" &&
 248        test_check_ignore "--quiet one two" 128 &&
 249        stderr_contains "fatal: --quiet is only valid with a single pathname"
 250'
 251
 252test_expect_success_multi 'erroneous use of --' '' '
 253        test_check_ignore "--" 128 &&
 254        stderr_contains "fatal: no path specified"
 255'
 256
 257test_expect_success_multi '--stdin with superfluous arg' '' '
 258        test_check_ignore "--stdin foo" 128 &&
 259        stderr_contains "fatal: cannot specify pathnames with --stdin"
 260'
 261
 262test_expect_success_multi '--stdin -z with superfluous arg' '' '
 263        test_check_ignore "--stdin -z foo" 128 &&
 264        stderr_contains "fatal: cannot specify pathnames with --stdin"
 265'
 266
 267test_expect_success_multi '-z without --stdin' '' '
 268        test_check_ignore "-z" 128 &&
 269        stderr_contains "fatal: -z only makes sense with --stdin"
 270'
 271
 272test_expect_success_multi '-z without --stdin and superfluous arg' '' '
 273        test_check_ignore "-z foo" 128 &&
 274        stderr_contains "fatal: -z only makes sense with --stdin"
 275'
 276
 277test_expect_success_multi 'needs work tree' '' '
 278        (
 279                cd .git &&
 280                test_check_ignore "foo" 128
 281        ) &&
 282        stderr_contains "fatal: This operation must be run in a work tree"
 283'
 284
 285############################################################################
 286#
 287# test standard ignores
 288
 289# First make sure that the presence of a file in the working tree
 290# does not impact results, but that the presence of a file in the
 291# index does.
 292
 293for subdir in '' 'a/'
 294do
 295        if test -z "$subdir"
 296        then
 297                where="at top-level"
 298        else
 299                where="in subdir $subdir"
 300        fi
 301
 302        test_expect_success_multi "non-existent file $where not ignored" \
 303                "::     ${subdir}non-existent" \
 304                "test_check_ignore '${subdir}non-existent' 1"
 305
 306        test_expect_success_multi "non-existent file $where ignored" \
 307                ".gitignore:1:one       ${subdir}one" \
 308                "test_check_ignore '${subdir}one'"
 309
 310        test_expect_success_multi "existing untracked file $where not ignored" \
 311                "::     ${subdir}not-ignored" \
 312                "test_check_ignore '${subdir}not-ignored' 1"
 313
 314        test_expect_success_multi "existing tracked file $where not ignored" \
 315                "::     ${subdir}ignored-but-in-index" \
 316                "test_check_ignore '${subdir}ignored-but-in-index' 1"
 317
 318        test_expect_success_multi "existing untracked file $where ignored" \
 319                ".gitignore:2:ignored-* ${subdir}ignored-and-untracked" \
 320                "test_check_ignore '${subdir}ignored-and-untracked'"
 321
 322        test_expect_success_multi "mix of file types $where" \
 323"::     ${subdir}non-existent
 324.gitignore:1:one        ${subdir}one
 325::      ${subdir}not-ignored
 326::      ${subdir}ignored-but-in-index
 327.gitignore:2:ignored-*  ${subdir}ignored-and-untracked" \
 328                "test_check_ignore '
 329                        ${subdir}non-existent
 330                        ${subdir}one
 331                        ${subdir}not-ignored
 332                        ${subdir}ignored-but-in-index
 333                        ${subdir}ignored-and-untracked'
 334                "
 335done
 336
 337# Having established the above, from now on we mostly test against
 338# files which do not exist in the working tree or index.
 339
 340test_expect_success 'sub-directory local ignore' '
 341        expect "a/3-three" &&
 342        test_check_ignore "a/3-three a/three-not-this-one"
 343'
 344
 345test_expect_success 'sub-directory local ignore with --verbose'  '
 346        expect "a/.gitignore:2:*three   a/3-three" &&
 347        test_check_ignore "--verbose a/3-three a/three-not-this-one"
 348'
 349
 350test_expect_success 'local ignore inside a sub-directory' '
 351        expect "3-three" &&
 352        (
 353                cd a &&
 354                test_check_ignore "3-three three-not-this-one"
 355        )
 356'
 357test_expect_success 'local ignore inside a sub-directory with --verbose' '
 358        expect "a/.gitignore:2:*three   3-three" &&
 359        (
 360                cd a &&
 361                test_check_ignore "--verbose 3-three three-not-this-one"
 362        )
 363'
 364
 365test_expect_success_multi 'nested include' \
 366        'a/b/.gitignore:8:!on*  a/b/one' '
 367        test_check_ignore "a/b/one"
 368'
 369
 370############################################################################
 371#
 372# test ignored sub-directories
 373
 374test_expect_success_multi 'ignored sub-directory' \
 375        'a/b/.gitignore:5:ignored-dir/  a/b/ignored-dir' '
 376        test_check_ignore "a/b/ignored-dir"
 377'
 378
 379test_expect_success 'multiple files inside ignored sub-directory' '
 380        expect_from_stdin <<-\EOF &&
 381                a/b/ignored-dir/foo
 382                a/b/ignored-dir/twoooo
 383                a/b/ignored-dir/seven
 384        EOF
 385        test_check_ignore "a/b/ignored-dir/foo a/b/ignored-dir/twoooo a/b/ignored-dir/seven"
 386'
 387
 388test_expect_success 'multiple files inside ignored sub-directory with -v' '
 389        expect_from_stdin <<-\EOF &&
 390                a/b/.gitignore:5:ignored-dir/   a/b/ignored-dir/foo
 391                a/b/.gitignore:5:ignored-dir/   a/b/ignored-dir/twoooo
 392                a/b/.gitignore:5:ignored-dir/   a/b/ignored-dir/seven
 393        EOF
 394        test_check_ignore "-v a/b/ignored-dir/foo a/b/ignored-dir/twoooo a/b/ignored-dir/seven"
 395'
 396
 397test_expect_success 'cd to ignored sub-directory' '
 398        expect_from_stdin <<-\EOF &&
 399                foo
 400                twoooo
 401                ../one
 402                seven
 403                ../../one
 404        EOF
 405        (
 406                cd a/b/ignored-dir &&
 407                test_check_ignore "foo twoooo ../one seven ../../one"
 408        )
 409'
 410
 411test_expect_success 'cd to ignored sub-directory with -v' '
 412        expect_from_stdin <<-\EOF &&
 413                a/b/.gitignore:5:ignored-dir/   foo
 414                a/b/.gitignore:5:ignored-dir/   twoooo
 415                a/b/.gitignore:8:!on*   ../one
 416                a/b/.gitignore:5:ignored-dir/   seven
 417                .gitignore:1:one        ../../one
 418        EOF
 419        (
 420                cd a/b/ignored-dir &&
 421                test_check_ignore "-v foo twoooo ../one seven ../../one"
 422        )
 423'
 424
 425############################################################################
 426#
 427# test handling of symlinks
 428
 429test_expect_success_multi SYMLINKS 'symlink' '::        a/symlink' '
 430        test_check_ignore "a/symlink" 1
 431'
 432
 433test_expect_success_multi SYMLINKS 'beyond a symlink' '' '
 434        test_check_ignore "a/symlink/foo" 128 &&
 435        test_stderr "fatal: '\''a/symlink/foo'\'' is beyond a symbolic link"
 436'
 437
 438test_expect_success_multi SYMLINKS 'beyond a symlink from subdirectory' '' '
 439        (
 440                cd a &&
 441                test_check_ignore "symlink/foo" 128
 442        ) &&
 443        test_stderr "fatal: '\''symlink/foo'\'' is beyond a symbolic link"
 444'
 445
 446############################################################################
 447#
 448# test handling of submodules
 449
 450test_expect_success_multi 'submodule' '' '
 451        test_check_ignore "a/submodule/one" 128 &&
 452        test_stderr "fatal: Path '\''a/submodule/one'\'' is in submodule '\''a/submodule'\''"
 453'
 454
 455test_expect_success_multi 'submodule from subdirectory' '' '
 456        (
 457                cd a &&
 458                test_check_ignore "submodule/one" 128
 459        ) &&
 460        test_stderr "fatal: Path '\''a/submodule/one'\'' is in submodule '\''a/submodule'\''"
 461'
 462
 463############################################################################
 464#
 465# test handling of global ignore files
 466
 467test_expect_success 'global ignore not yet enabled' '
 468        expect_from_stdin <<-\EOF &&
 469                .git/info/exclude:7:per-repo    per-repo
 470                a/.gitignore:2:*three   a/globalthree
 471                .git/info/exclude:7:per-repo    a/per-repo
 472        EOF
 473        test_check_ignore "-v globalone per-repo a/globalthree a/per-repo not-ignored a/globaltwo"
 474'
 475
 476test_expect_success 'global ignore' '
 477        enable_global_excludes &&
 478        expect_from_stdin <<-\EOF &&
 479                globalone
 480                per-repo
 481                globalthree
 482                a/globalthree
 483                a/per-repo
 484                globaltwo
 485        EOF
 486        test_check_ignore "globalone per-repo globalthree a/globalthree a/per-repo not-ignored globaltwo"
 487'
 488
 489test_expect_success 'global ignore with -v' '
 490        enable_global_excludes &&
 491        expect_from_stdin <<-EOF &&
 492                $global_excludes:1:globalone    globalone
 493                .git/info/exclude:7:per-repo    per-repo
 494                $global_excludes:3:globalthree  globalthree
 495                a/.gitignore:2:*three   a/globalthree
 496                .git/info/exclude:7:per-repo    a/per-repo
 497                $global_excludes:2:!globaltwo   globaltwo
 498        EOF
 499        test_check_ignore "-v globalone per-repo globalthree a/globalthree a/per-repo not-ignored globaltwo"
 500'
 501
 502############################################################################
 503#
 504# test --stdin
 505
 506cat <<-\EOF >stdin
 507        one
 508        not-ignored
 509        a/one
 510        a/not-ignored
 511        a/b/on
 512        a/b/one
 513        a/b/one one
 514        "a/b/one two"
 515        "a/b/one\"three"
 516        a/b/not-ignored
 517        a/b/two
 518        a/b/twooo
 519        globaltwo
 520        a/globaltwo
 521        a/b/globaltwo
 522        b/globaltwo
 523EOF
 524cat <<-\EOF >expected-default
 525        one
 526        a/one
 527        a/b/on
 528        a/b/one
 529        a/b/one one
 530        a/b/one two
 531        "a/b/one\"three"
 532        a/b/two
 533        a/b/twooo
 534        globaltwo
 535        a/globaltwo
 536        a/b/globaltwo
 537        b/globaltwo
 538EOF
 539cat <<-EOF >expected-verbose
 540        .gitignore:1:one        one
 541        .gitignore:1:one        a/one
 542        a/b/.gitignore:8:!on*   a/b/on
 543        a/b/.gitignore:8:!on*   a/b/one
 544        a/b/.gitignore:8:!on*   a/b/one one
 545        a/b/.gitignore:8:!on*   a/b/one two
 546        a/b/.gitignore:8:!on*   "a/b/one\"three"
 547        a/b/.gitignore:9:!two   a/b/two
 548        a/.gitignore:1:two*     a/b/twooo
 549        $global_excludes:2:!globaltwo   globaltwo
 550        $global_excludes:2:!globaltwo   a/globaltwo
 551        $global_excludes:2:!globaltwo   a/b/globaltwo
 552        $global_excludes:2:!globaltwo   b/globaltwo
 553EOF
 554
 555sed -e 's/^"//' -e 's/\\//' -e 's/"$//' stdin | \
 556        tr "\n" "\0" >stdin0
 557sed -e 's/^"//' -e 's/\\//' -e 's/"$//' expected-default | \
 558        tr "\n" "\0" >expected-default0
 559sed -e 's/      "/      /' -e 's/\\//' -e 's/"$//' expected-verbose | \
 560        tr ":\t\n" "\0" >expected-verbose0
 561
 562test_expect_success '--stdin' '
 563        expect_from_stdin <expected-default &&
 564        test_check_ignore "--stdin" <stdin
 565'
 566
 567test_expect_success '--stdin -q' '
 568        expect "" &&
 569        test_check_ignore "-q --stdin" <stdin
 570'
 571
 572test_expect_success '--stdin -v' '
 573        expect_from_stdin <expected-verbose &&
 574        test_check_ignore "-v --stdin" <stdin
 575'
 576
 577for opts in '--stdin -z' '-z --stdin'
 578do
 579        test_expect_success "$opts" "
 580                expect_from_stdin <expected-default0 &&
 581                test_check_ignore '$opts' <stdin0
 582        "
 583
 584        test_expect_success "$opts -q" "
 585                expect "" &&
 586                test_check_ignore '-q $opts' <stdin0
 587        "
 588
 589        test_expect_success "$opts -v" "
 590                expect_from_stdin <expected-verbose0 &&
 591                test_check_ignore '-v $opts' <stdin0
 592        "
 593done
 594
 595cat <<-\EOF >stdin
 596        ../one
 597        ../not-ignored
 598        one
 599        not-ignored
 600        b/on
 601        b/one
 602        b/one one
 603        "b/one two"
 604        "b/one\"three"
 605        b/two
 606        b/not-ignored
 607        b/twooo
 608        ../globaltwo
 609        globaltwo
 610        b/globaltwo
 611        ../b/globaltwo
 612        c/not-ignored
 613EOF
 614# N.B. we deliberately end STDIN with a non-matching pattern in order
 615# to test that the exit code indicates that one or more of the
 616# provided paths is ignored - in other words, that it represents an
 617# aggregation of all the results, not just the final result.
 618
 619cat <<-EOF >expected-all
 620        .gitignore:1:one        ../one
 621        ::      ../not-ignored
 622        .gitignore:1:one        one
 623        ::      not-ignored
 624        a/b/.gitignore:8:!on*   b/on
 625        a/b/.gitignore:8:!on*   b/one
 626        a/b/.gitignore:8:!on*   b/one one
 627        a/b/.gitignore:8:!on*   b/one two
 628        a/b/.gitignore:8:!on*   "b/one\"three"
 629        a/b/.gitignore:9:!two   b/two
 630        ::      b/not-ignored
 631        a/.gitignore:1:two*     b/twooo
 632        $global_excludes:2:!globaltwo   ../globaltwo
 633        $global_excludes:2:!globaltwo   globaltwo
 634        $global_excludes:2:!globaltwo   b/globaltwo
 635        $global_excludes:2:!globaltwo   ../b/globaltwo
 636        ::      c/not-ignored
 637EOF
 638grep -v '^::    ' expected-all >expected-verbose
 639sed -e 's/.*    //' expected-verbose >expected-default
 640
 641sed -e 's/^"//' -e 's/\\//' -e 's/"$//' stdin | \
 642        tr "\n" "\0" >stdin0
 643sed -e 's/^"//' -e 's/\\//' -e 's/"$//' expected-default | \
 644        tr "\n" "\0" >expected-default0
 645sed -e 's/      "/      /' -e 's/\\//' -e 's/"$//' expected-verbose | \
 646        tr ":\t\n" "\0" >expected-verbose0
 647
 648test_expect_success '--stdin from subdirectory' '
 649        expect_from_stdin <expected-default &&
 650        (
 651                cd a &&
 652                test_check_ignore "--stdin" <../stdin
 653        )
 654'
 655
 656test_expect_success '--stdin from subdirectory with -v' '
 657        expect_from_stdin <expected-verbose &&
 658        (
 659                cd a &&
 660                test_check_ignore "--stdin -v" <../stdin
 661        )
 662'
 663
 664test_expect_success '--stdin from subdirectory with -v -n' '
 665        expect_from_stdin <expected-all &&
 666        (
 667                cd a &&
 668                test_check_ignore "--stdin -v -n" <../stdin
 669        )
 670'
 671
 672for opts in '--stdin -z' '-z --stdin'
 673do
 674        test_expect_success "$opts from subdirectory" '
 675                expect_from_stdin <expected-default0 &&
 676                (
 677                        cd a &&
 678                        test_check_ignore "'"$opts"'" <../stdin0
 679                )
 680        '
 681
 682        test_expect_success "$opts from subdirectory with -v" '
 683                expect_from_stdin <expected-verbose0 &&
 684                (
 685                        cd a &&
 686                        test_check_ignore "'"$opts"' -v" <../stdin0
 687                )
 688        '
 689done
 690
 691test_expect_success PIPE 'streaming support for --stdin' '
 692        mkfifo in out &&
 693        (git check-ignore -n -v --stdin <in >out &) &&
 694
 695        # We cannot just "echo >in" because check-ignore would get EOF
 696        # after echo exited; instead we open the descriptor in our
 697        # shell, and then echo to the fd. We make sure to close it at
 698        # the end, so that the subprocess does get EOF and dies
 699        # properly.
 700        exec 9>in &&
 701        test_when_finished "exec 9>&-" &&
 702        echo >&9 one &&
 703        read response <out &&
 704        echo "$response" | grep "^\.gitignore:1:one     one" &&
 705        echo >&9 two &&
 706        read response <out &&
 707        echo "$response" | grep "^::    two"
 708'
 709
 710test_done