030a16e778ffb3bdb361f0d6a1c7fa0f4d074d88
   1#!/bin/sh
   2#
   3# Copyright (c) 2012 Felipe Contreras
   4#
   5
   6test_description='test bash completion'
   7
   8. ./lib-bash.sh
   9
  10complete ()
  11{
  12        # do nothing
  13        return 0
  14}
  15
  16# Be careful when updating this list:
  17#
  18# (1) The build tree may have build artifact from different branch, or
  19#     the user's $PATH may have a random executable that may begin
  20#     with "git-check" that are not part of the subcommands this build
  21#     will ship, e.g.  "check-ignore".  The tests for completion for
  22#     subcommand names tests how "check" is expanded; we limit the
  23#     possible candidates to "checkout" and "check-attr" to make sure
  24#     "check-attr", which is known by the filter function as a
  25#     subcommand to be thrown out, while excluding other random files
  26#     that happen to begin with "check" to avoid letting them get in
  27#     the way.
  28#
  29# (2) A test makes sure that common subcommands are included in the
  30#     completion for "git <TAB>", and a plumbing is excluded.  "add",
  31#     "filter-branch" and "ls-files" are listed for this.
  32
  33GIT_TESTING_COMMAND_COMPLETION='add checkout check-attr filter-branch ls-files'
  34
  35. "$GIT_BUILD_DIR/contrib/completion/git-completion.bash"
  36
  37# We don't need this function to actually join words or do anything special.
  38# Also, it's cleaner to avoid touching bash's internal completion variables.
  39# So let's override it with a minimal version for testing purposes.
  40_get_comp_words_by_ref ()
  41{
  42        while [ $# -gt 0 ]; do
  43                case "$1" in
  44                cur)
  45                        cur=${_words[_cword]}
  46                        ;;
  47                prev)
  48                        prev=${_words[_cword-1]}
  49                        ;;
  50                words)
  51                        words=("${_words[@]}")
  52                        ;;
  53                cword)
  54                        cword=$_cword
  55                        ;;
  56                esac
  57                shift
  58        done
  59}
  60
  61print_comp ()
  62{
  63        local IFS=$'\n'
  64        echo "${COMPREPLY[*]}" > out
  65}
  66
  67run_completion ()
  68{
  69        local -a COMPREPLY _words
  70        local _cword
  71        _words=( $1 )
  72        test "${1: -1}" = ' ' && _words[${#_words[@]}+1]=''
  73        (( _cword = ${#_words[@]} - 1 ))
  74        __git_wrap__git_main && print_comp
  75}
  76
  77# Test high-level completion
  78# Arguments are:
  79# 1: typed text so far (cur)
  80# 2: expected completion
  81test_completion ()
  82{
  83        if test $# -gt 1
  84        then
  85                printf '%s\n' "$2" >expected
  86        else
  87                sed -e 's/Z$//' >expected
  88        fi &&
  89        run_completion "$1" &&
  90        test_cmp expected out
  91}
  92
  93# Test __gitcomp.
  94# The first argument is the typed text so far (cur); the rest are
  95# passed to __gitcomp.  Expected output comes is read from the
  96# standard input, like test_completion().
  97test_gitcomp ()
  98{
  99        local -a COMPREPLY &&
 100        sed -e 's/Z$//' >expected &&
 101        local cur="$1" &&
 102        shift &&
 103        __gitcomp "$@" &&
 104        print_comp &&
 105        test_cmp expected out
 106}
 107
 108# Test __gitcomp_nl
 109# Arguments are:
 110# 1: current word (cur)
 111# -: the rest are passed to __gitcomp_nl
 112test_gitcomp_nl ()
 113{
 114        local -a COMPREPLY &&
 115        sed -e 's/Z$//' >expected &&
 116        local cur="$1" &&
 117        shift &&
 118        __gitcomp_nl "$@" &&
 119        print_comp &&
 120        test_cmp expected out
 121}
 122
 123invalid_variable_name='${foo.bar}'
 124
 125actual="$TRASH_DIRECTORY/actual"
 126
 127if test_have_prereq MINGW
 128then
 129        ROOT="$(pwd -W)"
 130else
 131        ROOT="$(pwd)"
 132fi
 133
 134test_expect_success 'setup for __gitdir tests' '
 135        mkdir -p subdir/subsubdir &&
 136        git init otherrepo
 137'
 138
 139test_expect_success '__gitdir - from command line (through $__git_dir)' '
 140        echo "$ROOT/otherrepo/.git" >expected &&
 141        (
 142                __git_dir="$ROOT/otherrepo/.git" &&
 143                __gitdir >"$actual"
 144        ) &&
 145        test_cmp expected "$actual"
 146'
 147
 148test_expect_success '__gitdir - repo as argument' '
 149        echo "otherrepo/.git" >expected &&
 150        __gitdir "otherrepo" >"$actual" &&
 151        test_cmp expected "$actual"
 152'
 153
 154test_expect_success '__gitdir - remote as argument' '
 155        echo "remote" >expected &&
 156        __gitdir "remote" >"$actual" &&
 157        test_cmp expected "$actual"
 158'
 159
 160test_expect_success '__gitdir - .git directory in cwd' '
 161        echo ".git" >expected &&
 162        __gitdir >"$actual" &&
 163        test_cmp expected "$actual"
 164'
 165
 166test_expect_success '__gitdir - .git directory in parent' '
 167        echo "$ROOT/.git" >expected &&
 168        (
 169                cd subdir/subsubdir &&
 170                __gitdir >"$actual"
 171        ) &&
 172        test_cmp expected "$actual"
 173'
 174
 175test_expect_success '__gitdir - cwd is a .git directory' '
 176        echo "." >expected &&
 177        (
 178                cd .git &&
 179                __gitdir >"$actual"
 180        ) &&
 181        test_cmp expected "$actual"
 182'
 183
 184test_expect_success '__gitdir - parent is a .git directory' '
 185        echo "$ROOT/.git" >expected &&
 186        (
 187                cd .git/refs/heads &&
 188                __gitdir >"$actual"
 189        ) &&
 190        test_cmp expected "$actual"
 191'
 192
 193test_expect_success '__gitdir - $GIT_DIR set while .git directory in cwd' '
 194        echo "$ROOT/otherrepo/.git" >expected &&
 195        (
 196                GIT_DIR="$ROOT/otherrepo/.git" &&
 197                export GIT_DIR &&
 198                __gitdir >"$actual"
 199        ) &&
 200        test_cmp expected "$actual"
 201'
 202
 203test_expect_success '__gitdir - $GIT_DIR set while .git directory in parent' '
 204        echo "$ROOT/otherrepo/.git" >expected &&
 205        (
 206                GIT_DIR="$ROOT/otherrepo/.git" &&
 207                export GIT_DIR &&
 208                cd subdir &&
 209                __gitdir >"$actual"
 210        ) &&
 211        test_cmp expected "$actual"
 212'
 213
 214test_expect_success '__gitdir - non-existing $GIT_DIR' '
 215        (
 216                GIT_DIR="$ROOT/non-existing" &&
 217                export GIT_DIR &&
 218                test_must_fail __gitdir
 219        )
 220'
 221
 222test_expect_success '__gitdir - gitfile in cwd' '
 223        echo "$ROOT/otherrepo/.git" >expected &&
 224        echo "gitdir: $ROOT/otherrepo/.git" >subdir/.git &&
 225        test_when_finished "rm -f subdir/.git" &&
 226        (
 227                cd subdir &&
 228                __gitdir >"$actual"
 229        ) &&
 230        test_cmp expected "$actual"
 231'
 232
 233test_expect_success '__gitdir - gitfile in parent' '
 234        echo "$ROOT/otherrepo/.git" >expected &&
 235        echo "gitdir: $ROOT/otherrepo/.git" >subdir/.git &&
 236        test_when_finished "rm -f subdir/.git" &&
 237        (
 238                cd subdir/subsubdir &&
 239                __gitdir >"$actual"
 240        ) &&
 241        test_cmp expected "$actual"
 242'
 243
 244test_expect_success SYMLINKS '__gitdir - resulting path avoids symlinks' '
 245        echo "$ROOT/otherrepo/.git" >expected &&
 246        mkdir otherrepo/dir &&
 247        test_when_finished "rm -rf otherrepo/dir" &&
 248        ln -s otherrepo/dir link &&
 249        test_when_finished "rm -f link" &&
 250        (
 251                cd link &&
 252                __gitdir >"$actual"
 253        ) &&
 254        test_cmp expected "$actual"
 255'
 256
 257test_expect_success '__gitdir - not a git repository' '
 258        nongit test_must_fail __gitdir
 259'
 260
 261test_expect_success '__gitcomp - trailing space - options' '
 262        test_gitcomp "--re" "--dry-run --reuse-message= --reedit-message=
 263                --reset-author" <<-EOF
 264        --reuse-message=Z
 265        --reedit-message=Z
 266        --reset-author Z
 267        EOF
 268'
 269
 270test_expect_success '__gitcomp - trailing space - config keys' '
 271        test_gitcomp "br" "branch. branch.autosetupmerge
 272                branch.autosetuprebase browser." <<-\EOF
 273        branch.Z
 274        branch.autosetupmerge Z
 275        branch.autosetuprebase Z
 276        browser.Z
 277        EOF
 278'
 279
 280test_expect_success '__gitcomp - option parameter' '
 281        test_gitcomp "--strategy=re" "octopus ours recursive resolve subtree" \
 282                "" "re" <<-\EOF
 283        recursive Z
 284        resolve Z
 285        EOF
 286'
 287
 288test_expect_success '__gitcomp - prefix' '
 289        test_gitcomp "branch.me" "remote merge mergeoptions rebase" \
 290                "branch.maint." "me" <<-\EOF
 291        branch.maint.merge Z
 292        branch.maint.mergeoptions Z
 293        EOF
 294'
 295
 296test_expect_success '__gitcomp - suffix' '
 297        test_gitcomp "branch.me" "master maint next pu" "branch." \
 298                "ma" "." <<-\EOF
 299        branch.master.Z
 300        branch.maint.Z
 301        EOF
 302'
 303
 304test_expect_success '__gitcomp - doesnt fail because of invalid variable name' '
 305        __gitcomp "$invalid_variable_name"
 306'
 307
 308read -r -d "" refs <<-\EOF
 309maint
 310master
 311next
 312pu
 313EOF
 314
 315test_expect_success '__gitcomp_nl - trailing space' '
 316        test_gitcomp_nl "m" "$refs" <<-EOF
 317        maint Z
 318        master Z
 319        EOF
 320'
 321
 322test_expect_success '__gitcomp_nl - prefix' '
 323        test_gitcomp_nl "--fixup=m" "$refs" "--fixup=" "m" <<-EOF
 324        --fixup=maint Z
 325        --fixup=master Z
 326        EOF
 327'
 328
 329test_expect_success '__gitcomp_nl - suffix' '
 330        test_gitcomp_nl "branch.ma" "$refs" "branch." "ma" "." <<-\EOF
 331        branch.maint.Z
 332        branch.master.Z
 333        EOF
 334'
 335
 336test_expect_success '__gitcomp_nl - no suffix' '
 337        test_gitcomp_nl "ma" "$refs" "" "ma" "" <<-\EOF
 338        maintZ
 339        masterZ
 340        EOF
 341'
 342
 343test_expect_success '__gitcomp_nl - doesnt fail because of invalid variable name' '
 344        __gitcomp_nl "$invalid_variable_name"
 345'
 346
 347test_expect_success '__git_remotes - list remotes from $GIT_DIR/remotes and from config file' '
 348        cat >expect <<-EOF &&
 349        remote_from_file_1
 350        remote_from_file_2
 351        remote_in_config_1
 352        remote_in_config_2
 353        EOF
 354        test_when_finished "rm -rf .git/remotes" &&
 355        mkdir -p .git/remotes &&
 356        >.git/remotes/remote_from_file_1 &&
 357        >.git/remotes/remote_from_file_2 &&
 358        test_when_finished "git remote remove remote_in_config_1" &&
 359        git remote add remote_in_config_1 git://remote_1 &&
 360        test_when_finished "git remote remove remote_in_config_2" &&
 361        git remote add remote_in_config_2 git://remote_2 &&
 362        __git_remotes >actual &&
 363        test_cmp expect actual
 364'
 365
 366test_expect_success '__git_get_config_variables' '
 367        cat >expect <<-EOF &&
 368        name-1
 369        name-2
 370        EOF
 371        test_config interesting.name-1 good &&
 372        test_config interesting.name-2 good &&
 373        test_config subsection.interesting.name-3 bad &&
 374        __git_get_config_variables interesting >actual &&
 375        test_cmp expect actual
 376'
 377
 378test_expect_success '__git_pretty_aliases' '
 379        cat >expect <<-EOF &&
 380        author
 381        hash
 382        EOF
 383        test_config pretty.author "%an %ae" &&
 384        test_config pretty.hash %H &&
 385        __git_pretty_aliases >actual &&
 386        test_cmp expect actual
 387'
 388
 389test_expect_success '__git_aliases' '
 390        cat >expect <<-EOF &&
 391        ci
 392        co
 393        EOF
 394        test_config alias.ci commit &&
 395        test_config alias.co checkout &&
 396        __git_aliases >actual &&
 397        test_cmp expect actual
 398'
 399
 400test_expect_success 'basic' '
 401        run_completion "git " &&
 402        # built-in
 403        grep -q "^add \$" out &&
 404        # script
 405        grep -q "^filter-branch \$" out &&
 406        # plumbing
 407        ! grep -q "^ls-files \$" out &&
 408
 409        run_completion "git f" &&
 410        ! grep -q -v "^f" out
 411'
 412
 413test_expect_success 'double dash "git" itself' '
 414        test_completion "git --" <<-\EOF
 415        --paginate Z
 416        --no-pager Z
 417        --git-dir=
 418        --bare Z
 419        --version Z
 420        --exec-path Z
 421        --exec-path=
 422        --html-path Z
 423        --man-path Z
 424        --info-path Z
 425        --work-tree=
 426        --namespace=
 427        --no-replace-objects Z
 428        --help Z
 429        EOF
 430'
 431
 432test_expect_success 'double dash "git checkout"' '
 433        test_completion "git checkout --" <<-\EOF
 434        --quiet Z
 435        --ours Z
 436        --theirs Z
 437        --track Z
 438        --no-track Z
 439        --merge Z
 440        --conflict=
 441        --orphan Z
 442        --patch Z
 443        EOF
 444'
 445
 446test_expect_success 'general options' '
 447        test_completion "git --ver" "--version " &&
 448        test_completion "git --hel" "--help " &&
 449        test_completion "git --exe" <<-\EOF &&
 450        --exec-path Z
 451        --exec-path=
 452        EOF
 453        test_completion "git --htm" "--html-path " &&
 454        test_completion "git --pag" "--paginate " &&
 455        test_completion "git --no-p" "--no-pager " &&
 456        test_completion "git --git" "--git-dir=" &&
 457        test_completion "git --wor" "--work-tree=" &&
 458        test_completion "git --nam" "--namespace=" &&
 459        test_completion "git --bar" "--bare " &&
 460        test_completion "git --inf" "--info-path " &&
 461        test_completion "git --no-r" "--no-replace-objects "
 462'
 463
 464test_expect_success 'general options plus command' '
 465        test_completion "git --version check" "checkout " &&
 466        test_completion "git --paginate check" "checkout " &&
 467        test_completion "git --git-dir=foo check" "checkout " &&
 468        test_completion "git --bare check" "checkout " &&
 469        test_completion "git --exec-path=foo check" "checkout " &&
 470        test_completion "git --html-path check" "checkout " &&
 471        test_completion "git --no-pager check" "checkout " &&
 472        test_completion "git --work-tree=foo check" "checkout " &&
 473        test_completion "git --namespace=foo check" "checkout " &&
 474        test_completion "git --paginate check" "checkout " &&
 475        test_completion "git --info-path check" "checkout " &&
 476        test_completion "git --no-replace-objects check" "checkout "
 477'
 478
 479test_expect_success 'git --help completion' '
 480        test_completion "git --help ad" "add " &&
 481        test_completion "git --help core" "core-tutorial "
 482'
 483
 484test_expect_success 'setup for ref completion' '
 485        echo content >file1 &&
 486        echo more >file2 &&
 487        git add file1 file2 &&
 488        git commit -m one &&
 489        git branch mybranch &&
 490        git tag mytag
 491'
 492
 493test_expect_success 'checkout completes ref names' '
 494        test_completion "git checkout m" <<-\EOF
 495        master Z
 496        mybranch Z
 497        mytag Z
 498        EOF
 499'
 500
 501test_expect_success 'show completes all refs' '
 502        test_completion "git show m" <<-\EOF
 503        master Z
 504        mybranch Z
 505        mytag Z
 506        EOF
 507'
 508
 509test_expect_success '<ref>: completes paths' '
 510        test_completion "git show mytag:f" <<-\EOF
 511        file1 Z
 512        file2 Z
 513        EOF
 514'
 515
 516test_expect_success 'complete tree filename with spaces' '
 517        echo content >"name with spaces" &&
 518        git add "name with spaces" &&
 519        git commit -m spaces &&
 520        test_completion "git show HEAD:nam" <<-\EOF
 521        name with spaces Z
 522        EOF
 523'
 524
 525test_expect_success 'complete tree filename with metacharacters' '
 526        echo content >"name with \${meta}" &&
 527        git add "name with \${meta}" &&
 528        git commit -m meta &&
 529        test_completion "git show HEAD:nam" <<-\EOF
 530        name with ${meta} Z
 531        name with spaces Z
 532        EOF
 533'
 534
 535test_expect_success 'send-email' '
 536        test_completion "git send-email --cov" "--cover-letter " &&
 537        test_completion "git send-email ma" "master "
 538'
 539
 540test_expect_success 'complete files' '
 541        git init tmp && cd tmp &&
 542        test_when_finished "cd .. && rm -rf tmp" &&
 543
 544        echo "expected" > .gitignore &&
 545        echo "out" >> .gitignore &&
 546
 547        git add .gitignore &&
 548        test_completion "git commit " ".gitignore" &&
 549
 550        git commit -m ignore &&
 551
 552        touch new &&
 553        test_completion "git add " "new" &&
 554
 555        git add new &&
 556        git commit -a -m new &&
 557        test_completion "git add " "" &&
 558
 559        git mv new modified &&
 560        echo modify > modified &&
 561        test_completion "git add " "modified" &&
 562
 563        touch untracked &&
 564
 565        : TODO .gitignore should not be here &&
 566        test_completion "git rm " <<-\EOF &&
 567        .gitignore
 568        modified
 569        EOF
 570
 571        test_completion "git clean " "untracked" &&
 572
 573        : TODO .gitignore should not be here &&
 574        test_completion "git mv " <<-\EOF &&
 575        .gitignore
 576        modified
 577        EOF
 578
 579        mkdir dir &&
 580        touch dir/file-in-dir &&
 581        git add dir/file-in-dir &&
 582        git commit -m dir &&
 583
 584        mkdir untracked-dir &&
 585
 586        : TODO .gitignore should not be here &&
 587        test_completion "git mv modified " <<-\EOF &&
 588        .gitignore
 589        dir
 590        modified
 591        untracked
 592        untracked-dir
 593        EOF
 594
 595        test_completion "git commit " "modified" &&
 596
 597        : TODO .gitignore should not be here &&
 598        test_completion "git ls-files " <<-\EOF &&
 599        .gitignore
 600        dir
 601        modified
 602        EOF
 603
 604        touch momified &&
 605        test_completion "git add mom" "momified"
 606'
 607
 608test_expect_success "completion uses <cmd> completion for alias: !sh -c 'git <cmd> ...'" '
 609        test_config alias.co "!sh -c '"'"'git checkout ...'"'"'" &&
 610        test_completion "git co m" <<-\EOF
 611        master Z
 612        mybranch Z
 613        mytag Z
 614        EOF
 615'
 616
 617test_expect_success 'completion uses <cmd> completion for alias: !f () { VAR=val git <cmd> ... }' '
 618        test_config alias.co "!f () { VAR=val git checkout ... ; } f" &&
 619        test_completion "git co m" <<-\EOF
 620        master Z
 621        mybranch Z
 622        mytag Z
 623        EOF
 624'
 625
 626test_expect_success 'completion used <cmd> completion for alias: !f() { : git <cmd> ; ... }' '
 627        test_config alias.co "!f() { : git checkout ; if ... } f" &&
 628        test_completion "git co m" <<-\EOF
 629        master Z
 630        mybranch Z
 631        mytag Z
 632        EOF
 633'
 634
 635test_expect_failure 'complete with tilde expansion' '
 636        git init tmp && cd tmp &&
 637        test_when_finished "cd .. && rm -rf tmp" &&
 638
 639        touch ~/tmp/file &&
 640
 641        test_completion "git add ~/tmp/" "~/tmp/file"
 642'
 643
 644test_done