7af93ba928ece85265509537b521764827194955
   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        if test -n "$quiet_opt"; then
 220                test_stderr ""
 221        else
 222                test_stderr "no pathspec given."
 223        fi
 224'
 225
 226test_expect_success '-q with multiple args' '
 227        expect "" &&
 228        test_check_ignore "-q one two" 128 &&
 229        stderr_contains "fatal: --quiet is only valid with a single pathname"
 230'
 231
 232test_expect_success '--quiet with multiple args' '
 233        expect "" &&
 234        test_check_ignore "--quiet one two" 128 &&
 235        stderr_contains "fatal: --quiet is only valid with a single pathname"
 236'
 237
 238for verbose_opt in '-v' '--verbose'
 239do
 240        for quiet_opt in '-q' '--quiet'
 241        do
 242                test_expect_success "$quiet_opt $verbose_opt" "
 243                        expect '' &&
 244                        test_check_ignore '$quiet_opt $verbose_opt foo' 128 &&
 245                        stderr_contains 'fatal: cannot have both --quiet and --verbose'
 246                "
 247        done
 248done
 249
 250test_expect_success '--quiet with multiple args' '
 251        expect "" &&
 252        test_check_ignore "--quiet one two" 128 &&
 253        stderr_contains "fatal: --quiet is only valid with a single pathname"
 254'
 255
 256test_expect_success_multi 'erroneous use of --' '' '
 257        test_check_ignore "--" 128 &&
 258        stderr_contains "fatal: no path specified"
 259'
 260
 261test_expect_success_multi '--stdin with superfluous arg' '' '
 262        test_check_ignore "--stdin foo" 128 &&
 263        stderr_contains "fatal: cannot specify pathnames with --stdin"
 264'
 265
 266test_expect_success_multi '--stdin -z with superfluous arg' '' '
 267        test_check_ignore "--stdin -z foo" 128 &&
 268        stderr_contains "fatal: cannot specify pathnames with --stdin"
 269'
 270
 271test_expect_success_multi '-z without --stdin' '' '
 272        test_check_ignore "-z" 128 &&
 273        stderr_contains "fatal: -z only makes sense with --stdin"
 274'
 275
 276test_expect_success_multi '-z without --stdin and superfluous arg' '' '
 277        test_check_ignore "-z foo" 128 &&
 278        stderr_contains "fatal: -z only makes sense with --stdin"
 279'
 280
 281test_expect_success_multi 'needs work tree' '' '
 282        (
 283                cd .git &&
 284                test_check_ignore "foo" 128
 285        ) &&
 286        stderr_contains "fatal: This operation must be run in a work tree"
 287'
 288
 289############################################################################
 290#
 291# test standard ignores
 292
 293# First make sure that the presence of a file in the working tree
 294# does not impact results, but that the presence of a file in the
 295# index does.
 296
 297for subdir in '' 'a/'
 298do
 299        if test -z "$subdir"
 300        then
 301                where="at top-level"
 302        else
 303                where="in subdir $subdir"
 304        fi
 305
 306        test_expect_success_multi "non-existent file $where not ignored" \
 307                "::     ${subdir}non-existent" \
 308                "test_check_ignore '${subdir}non-existent' 1"
 309
 310        test_expect_success_multi "non-existent file $where ignored" \
 311                ".gitignore:1:one       ${subdir}one" \
 312                "test_check_ignore '${subdir}one'"
 313
 314        test_expect_success_multi "existing untracked file $where not ignored" \
 315                "::     ${subdir}not-ignored" \
 316                "test_check_ignore '${subdir}not-ignored' 1"
 317
 318        test_expect_success_multi "existing tracked file $where not ignored" \
 319                "::     ${subdir}ignored-but-in-index" \
 320                "test_check_ignore '${subdir}ignored-but-in-index' 1"
 321
 322        test_expect_success_multi "existing untracked file $where ignored" \
 323                ".gitignore:2:ignored-* ${subdir}ignored-and-untracked" \
 324                "test_check_ignore '${subdir}ignored-and-untracked'"
 325
 326        test_expect_success_multi "mix of file types $where" \
 327"::     ${subdir}non-existent
 328.gitignore:1:one        ${subdir}one
 329::      ${subdir}not-ignored
 330::      ${subdir}ignored-but-in-index
 331.gitignore:2:ignored-*  ${subdir}ignored-and-untracked" \
 332                "test_check_ignore '
 333                        ${subdir}non-existent
 334                        ${subdir}one
 335                        ${subdir}not-ignored
 336                        ${subdir}ignored-but-in-index
 337                        ${subdir}ignored-and-untracked'
 338                "
 339done
 340
 341# Having established the above, from now on we mostly test against
 342# files which do not exist in the working tree or index.
 343
 344test_expect_success 'sub-directory local ignore' '
 345        expect "a/3-three" &&
 346        test_check_ignore "a/3-three a/three-not-this-one"
 347'
 348
 349test_expect_success 'sub-directory local ignore with --verbose'  '
 350        expect "a/.gitignore:2:*three   a/3-three" &&
 351        test_check_ignore "--verbose a/3-three a/three-not-this-one"
 352'
 353
 354test_expect_success 'local ignore inside a sub-directory' '
 355        expect "3-three" &&
 356        (
 357                cd a &&
 358                test_check_ignore "3-three three-not-this-one"
 359        )
 360'
 361test_expect_success 'local ignore inside a sub-directory with --verbose' '
 362        expect "a/.gitignore:2:*three   3-three" &&
 363        (
 364                cd a &&
 365                test_check_ignore "--verbose 3-three three-not-this-one"
 366        )
 367'
 368
 369test_expect_success_multi 'nested include' \
 370        'a/b/.gitignore:8:!on*  a/b/one' '
 371        test_check_ignore "a/b/one"
 372'
 373
 374############################################################################
 375#
 376# test ignored sub-directories
 377
 378test_expect_success_multi 'ignored sub-directory' \
 379        'a/b/.gitignore:5:ignored-dir/  a/b/ignored-dir' '
 380        test_check_ignore "a/b/ignored-dir"
 381'
 382
 383test_expect_success 'multiple files inside ignored sub-directory' '
 384        expect_from_stdin <<-\EOF &&
 385                a/b/ignored-dir/foo
 386                a/b/ignored-dir/twoooo
 387                a/b/ignored-dir/seven
 388        EOF
 389        test_check_ignore "a/b/ignored-dir/foo a/b/ignored-dir/twoooo a/b/ignored-dir/seven"
 390'
 391
 392test_expect_success 'multiple files inside ignored sub-directory with -v' '
 393        expect_from_stdin <<-\EOF &&
 394                a/b/.gitignore:5:ignored-dir/   a/b/ignored-dir/foo
 395                a/b/.gitignore:5:ignored-dir/   a/b/ignored-dir/twoooo
 396                a/b/.gitignore:5:ignored-dir/   a/b/ignored-dir/seven
 397        EOF
 398        test_check_ignore "-v a/b/ignored-dir/foo a/b/ignored-dir/twoooo a/b/ignored-dir/seven"
 399'
 400
 401test_expect_success 'cd to ignored sub-directory' '
 402        expect_from_stdin <<-\EOF &&
 403                foo
 404                twoooo
 405                ../one
 406                seven
 407                ../../one
 408        EOF
 409        (
 410                cd a/b/ignored-dir &&
 411                test_check_ignore "foo twoooo ../one seven ../../one"
 412        )
 413'
 414
 415test_expect_success 'cd to ignored sub-directory with -v' '
 416        expect_from_stdin <<-\EOF &&
 417                a/b/.gitignore:5:ignored-dir/   foo
 418                a/b/.gitignore:5:ignored-dir/   twoooo
 419                a/b/.gitignore:8:!on*   ../one
 420                a/b/.gitignore:5:ignored-dir/   seven
 421                .gitignore:1:one        ../../one
 422        EOF
 423        (
 424                cd a/b/ignored-dir &&
 425                test_check_ignore "-v foo twoooo ../one seven ../../one"
 426        )
 427'
 428
 429############################################################################
 430#
 431# test handling of symlinks
 432
 433test_expect_success_multi SYMLINKS 'symlink' '::        a/symlink' '
 434        test_check_ignore "a/symlink" 1
 435'
 436
 437test_expect_success_multi SYMLINKS 'beyond a symlink' '' '
 438        test_check_ignore "a/symlink/foo" 128 &&
 439        test_stderr "fatal: '\''a/symlink/foo'\'' is beyond a symbolic link"
 440'
 441
 442test_expect_success_multi SYMLINKS 'beyond a symlink from subdirectory' '' '
 443        (
 444                cd a &&
 445                test_check_ignore "symlink/foo" 128
 446        ) &&
 447        test_stderr "fatal: '\''symlink/foo'\'' is beyond a symbolic link"
 448'
 449
 450############################################################################
 451#
 452# test handling of submodules
 453
 454test_expect_success_multi 'submodule' '' '
 455        test_check_ignore "a/submodule/one" 128 &&
 456        test_stderr "fatal: Path '\''a/submodule/one'\'' is in submodule '\''a/submodule'\''"
 457'
 458
 459test_expect_success_multi 'submodule from subdirectory' '' '
 460        (
 461                cd a &&
 462                test_check_ignore "submodule/one" 128
 463        ) &&
 464        test_stderr "fatal: Path '\''a/submodule/one'\'' is in submodule '\''a/submodule'\''"
 465'
 466
 467############################################################################
 468#
 469# test handling of global ignore files
 470
 471test_expect_success 'global ignore not yet enabled' '
 472        expect_from_stdin <<-\EOF &&
 473                .git/info/exclude:7:per-repo    per-repo
 474                a/.gitignore:2:*three   a/globalthree
 475                .git/info/exclude:7:per-repo    a/per-repo
 476        EOF
 477        test_check_ignore "-v globalone per-repo a/globalthree a/per-repo not-ignored a/globaltwo"
 478'
 479
 480test_expect_success 'global ignore' '
 481        enable_global_excludes &&
 482        expect_from_stdin <<-\EOF &&
 483                globalone
 484                per-repo
 485                globalthree
 486                a/globalthree
 487                a/per-repo
 488                globaltwo
 489        EOF
 490        test_check_ignore "globalone per-repo globalthree a/globalthree a/per-repo not-ignored globaltwo"
 491'
 492
 493test_expect_success 'global ignore with -v' '
 494        enable_global_excludes &&
 495        expect_from_stdin <<-EOF &&
 496                $global_excludes:1:globalone    globalone
 497                .git/info/exclude:7:per-repo    per-repo
 498                $global_excludes:3:globalthree  globalthree
 499                a/.gitignore:2:*three   a/globalthree
 500                .git/info/exclude:7:per-repo    a/per-repo
 501                $global_excludes:2:!globaltwo   globaltwo
 502        EOF
 503        test_check_ignore "-v globalone per-repo globalthree a/globalthree a/per-repo not-ignored globaltwo"
 504'
 505
 506############################################################################
 507#
 508# test --stdin
 509
 510cat <<-\EOF >stdin
 511        one
 512        not-ignored
 513        a/one
 514        a/not-ignored
 515        a/b/on
 516        a/b/one
 517        a/b/one one
 518        "a/b/one two"
 519        "a/b/one\"three"
 520        a/b/not-ignored
 521        a/b/two
 522        a/b/twooo
 523        globaltwo
 524        a/globaltwo
 525        a/b/globaltwo
 526        b/globaltwo
 527EOF
 528cat <<-\EOF >expected-default
 529        one
 530        a/one
 531        a/b/on
 532        a/b/one
 533        a/b/one one
 534        a/b/one two
 535        "a/b/one\"three"
 536        a/b/two
 537        a/b/twooo
 538        globaltwo
 539        a/globaltwo
 540        a/b/globaltwo
 541        b/globaltwo
 542EOF
 543cat <<-EOF >expected-verbose
 544        .gitignore:1:one        one
 545        .gitignore:1:one        a/one
 546        a/b/.gitignore:8:!on*   a/b/on
 547        a/b/.gitignore:8:!on*   a/b/one
 548        a/b/.gitignore:8:!on*   a/b/one one
 549        a/b/.gitignore:8:!on*   a/b/one two
 550        a/b/.gitignore:8:!on*   "a/b/one\"three"
 551        a/b/.gitignore:9:!two   a/b/two
 552        a/.gitignore:1:two*     a/b/twooo
 553        $global_excludes:2:!globaltwo   globaltwo
 554        $global_excludes:2:!globaltwo   a/globaltwo
 555        $global_excludes:2:!globaltwo   a/b/globaltwo
 556        $global_excludes:2:!globaltwo   b/globaltwo
 557EOF
 558
 559sed -e 's/^"//' -e 's/\\//' -e 's/"$//' stdin | \
 560        tr "\n" "\0" >stdin0
 561sed -e 's/^"//' -e 's/\\//' -e 's/"$//' expected-default | \
 562        tr "\n" "\0" >expected-default0
 563sed -e 's/      "/      /' -e 's/\\//' -e 's/"$//' expected-verbose | \
 564        tr ":\t\n" "\0" >expected-verbose0
 565
 566test_expect_success '--stdin' '
 567        expect_from_stdin <expected-default &&
 568        test_check_ignore "--stdin" <stdin
 569'
 570
 571test_expect_success '--stdin -q' '
 572        expect "" &&
 573        test_check_ignore "-q --stdin" <stdin
 574'
 575
 576test_expect_success '--stdin -v' '
 577        expect_from_stdin <expected-verbose &&
 578        test_check_ignore "-v --stdin" <stdin
 579'
 580
 581for opts in '--stdin -z' '-z --stdin'
 582do
 583        test_expect_success "$opts" "
 584                expect_from_stdin <expected-default0 &&
 585                test_check_ignore '$opts' <stdin0
 586        "
 587
 588        test_expect_success "$opts -q" "
 589                expect "" &&
 590                test_check_ignore '-q $opts' <stdin0
 591        "
 592
 593        test_expect_success "$opts -v" "
 594                expect_from_stdin <expected-verbose0 &&
 595                test_check_ignore '-v $opts' <stdin0
 596        "
 597done
 598
 599cat <<-\EOF >stdin
 600        ../one
 601        ../not-ignored
 602        one
 603        not-ignored
 604        b/on
 605        b/one
 606        b/one one
 607        "b/one two"
 608        "b/one\"three"
 609        b/two
 610        b/not-ignored
 611        b/twooo
 612        ../globaltwo
 613        globaltwo
 614        b/globaltwo
 615        ../b/globaltwo
 616        c/not-ignored
 617EOF
 618# N.B. we deliberately end STDIN with a non-matching pattern in order
 619# to test that the exit code indicates that one or more of the
 620# provided paths is ignored - in other words, that it represents an
 621# aggregation of all the results, not just the final result.
 622
 623cat <<-EOF >expected-all
 624        .gitignore:1:one        ../one
 625        ::      ../not-ignored
 626        .gitignore:1:one        one
 627        ::      not-ignored
 628        a/b/.gitignore:8:!on*   b/on
 629        a/b/.gitignore:8:!on*   b/one
 630        a/b/.gitignore:8:!on*   b/one one
 631        a/b/.gitignore:8:!on*   b/one two
 632        a/b/.gitignore:8:!on*   "b/one\"three"
 633        a/b/.gitignore:9:!two   b/two
 634        ::      b/not-ignored
 635        a/.gitignore:1:two*     b/twooo
 636        $global_excludes:2:!globaltwo   ../globaltwo
 637        $global_excludes:2:!globaltwo   globaltwo
 638        $global_excludes:2:!globaltwo   b/globaltwo
 639        $global_excludes:2:!globaltwo   ../b/globaltwo
 640        ::      c/not-ignored
 641EOF
 642grep -v '^::    ' expected-all >expected-verbose
 643sed -e 's/.*    //' expected-verbose >expected-default
 644
 645sed -e 's/^"//' -e 's/\\//' -e 's/"$//' stdin | \
 646        tr "\n" "\0" >stdin0
 647sed -e 's/^"//' -e 's/\\//' -e 's/"$//' expected-default | \
 648        tr "\n" "\0" >expected-default0
 649sed -e 's/      "/      /' -e 's/\\//' -e 's/"$//' expected-verbose | \
 650        tr ":\t\n" "\0" >expected-verbose0
 651
 652test_expect_success '--stdin from subdirectory' '
 653        expect_from_stdin <expected-default &&
 654        (
 655                cd a &&
 656                test_check_ignore "--stdin" <../stdin
 657        )
 658'
 659
 660test_expect_success '--stdin from subdirectory with -v' '
 661        expect_from_stdin <expected-verbose &&
 662        (
 663                cd a &&
 664                test_check_ignore "--stdin -v" <../stdin
 665        )
 666'
 667
 668test_expect_success '--stdin from subdirectory with -v -n' '
 669        expect_from_stdin <expected-all &&
 670        (
 671                cd a &&
 672                test_check_ignore "--stdin -v -n" <../stdin
 673        )
 674'
 675
 676for opts in '--stdin -z' '-z --stdin'
 677do
 678        test_expect_success "$opts from subdirectory" '
 679                expect_from_stdin <expected-default0 &&
 680                (
 681                        cd a &&
 682                        test_check_ignore "'"$opts"'" <../stdin0
 683                )
 684        '
 685
 686        test_expect_success "$opts from subdirectory with -v" '
 687                expect_from_stdin <expected-verbose0 &&
 688                (
 689                        cd a &&
 690                        test_check_ignore "'"$opts"' -v" <../stdin0
 691                )
 692        '
 693done
 694
 695
 696test_done