1#!/usr/local/bin/bash
2# Licensed to the Apache Software Foundation (ASF) under one
3# or more contributor license agreements.  See the NOTICE file
4# distributed with this work for additional information
5# regarding copyright ownership.  The ASF licenses this file
6# to you under the Apache License, Version 2.0 (the
7# "License"); you may not use this file except in compliance
8# with the License.  You may obtain a copy of the License at
9#
10#   http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing,
13# software distributed under the License is distributed on an
14# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15# KIND, either express or implied.  See the License for the
16# specific language governing permissions and limitations
17# under the License.
18
19# Checks that the "_svn" function defined in the specified "bash_completion"
20# script produces appropriate lists of completions for various incomplete svn
21# command lines.
22
23THIS_DIR=`dirname "$0"`
24SCRIPT="$1"
25if [ -z "$SCRIPT" ]; then
26  SCRIPT="$THIS_DIR/bash_completion"
27fi
28
29if [ ! -r "$SCRIPT" ] || [ "$2" ]; then
30  echo "Usage: bash_completion_test [BASH_COMPLETION_PATHNAME]"
31  echo "Tests the specified \"bash_completion\" script,"
32  echo "defaulting to the one in the same directory as this test,"
33  echo "including checking it against the \"svn\" program found in the current PATH."
34  exit 1
35fi
36
37set -e  # Exit on error
38shopt -s extglob
39export LC_ALL=C
40
41# Execute the script which is to be tested.
42. "$SCRIPT"
43
44# From the given incomplete command, print a space-separated list of
45# possible completions of the last argument (or of an empty first argument
46# if no subcommand is given).
47#
48# Usage: get_completions SVN-CMD [SVN-SUBCOMMAND [SVN-OPTION...]]
49# where SVN-CMD is "svn", "svnadmin", etc.; such that when a leading
50# underscore is added, it must name one of the completion functions in
51# "bash_completion".
52get_completions() {
53  SVN_CMD="$1"
54  COMP_WORDS=("$@")
55  if [ $# == 1 ]; then
56    COMP_CWORD=1
57  else
58    COMP_CWORD=$(($#-1))
59  fi
60  # Call the appropriate completion function (e.g. "_svn") with no arguments.
61  "_$SVN_CMD"
62  echo -n "${COMPREPLY[*]}"
63}
64
65# Print a failure message, record the failure, and return "false".
66# Usage: fail MESSAGE
67fail() {
68  PREFIX="FAIL: "
69  for LINE in "$@"; do
70    echo "$PREFIX$LINE"
71    PREFIX="      "
72  done
73  TESTS_FAILED=1
74  false
75}
76
77# Check that EXPECTED-WORD is among the completions of the last word in
78# SVN-ARGS.  SVN-ARGS is a single argument to this function, split
79# into multiple arguments when passed to "get_completions()".
80# Usage: includes SVN-CMD SVN-ARGS EXPECTED-WORD
81includes() {
82  SVN_CMD="$1"
83  SVN_ARGS="$2"
84  EXPECTED_WORD="$3"
85  COMPLETIONS=`get_completions "$SVN_CMD" $SVN_ARGS`
86  if [[ "$EXPECTED_WORD" != @(${COMPLETIONS// /|}) ]]; then
87    fail "completions of \"$SVN_CMD $SVN_ARGS\" should include \"$EXPECTED_WORD\"" \
88      "(completions: $COMPLETIONS)"
89  fi
90}
91
92excludes() {
93  SVN_CMD="$1"
94  SVN_ARGS="$2"
95  EXPECTED_WORD="$3"
96  COMPLETIONS=`get_completions "$SVN_CMD" $SVN_ARGS`
97  if [[ "$EXPECTED_WORD" == @(${COMPLETIONS// /|}) ]]; then
98    fail "completions of \"$SVN_CMD $SVN_ARGS\" should exclude \"$EXPECTED_WORD\"" \
99      "(completions: $COMPLETIONS)"
100  fi
101}
102
103# Print the valid subcommands for an "svn"-like program, one per line, sorted.
104# Exclude any synonym that is just a truncation of its full name.
105# Usage: get_svn_subcommands SVN-CMD
106# where SVN-CMD is "svn" or another program that outputs similar help.
107get_svn_subcommands() {
108  SVN_CMD="$1"
109  "$SVN_CMD" help |
110    # Find the relevant lines.
111    sed -n -e '1,/^Available subcommands:$/d;/^$/q;p' |
112    # Remove brackets and commas
113    tr -d ' )' | tr '(,' ' ' |
114    # Remove simple abbreviations
115    ( while read SYNONYMS; do
116        for CMD in $SYNONYMS; do
117          if [ "$CMD" != "?" ]; then
118            for SYNONYM in $SYNONYMS; do
119              case $SYNONYM in
120              $CMD) ;;
121              $CMD*) CMD= ; break ;;
122              esac
123            done
124            if [ $CMD ]; then
125              echo $CMD
126            fi
127          fi
128        done
129      done
130    ) |
131    sort
132}
133
134# Print the valid option switches for "svn SUBCMD", one per line, sorted.
135# Usage: get_svn_options SVN-CMD SUBCMD
136# where SVN-CMD is "svn" or another program that outputs similar help.
137get_svn_options() {
138  SVN_CMD="$1"
139  SUBCMD="$2"
140  { "$SVN_CMD" help "$SUBCMD" |
141      # Remove deprecated options
142      grep -v deprecated |
143      # Find the relevant lines; remove "arg" and description.
144      sed -n -e '1,/^\(Valid\|Global\) options:$/d;/^  -/!d' \
145             -e 's/\( ARG\)* * : .*//;p' |
146      # Remove brackets; put each word on its own line.
147      tr -d '] ' | tr '[' '\n'
148    # The following options are always accepted but not listed in the help
149    if [ "$SUBCMD" != "help" ] ; then
150      echo "-h"
151      echo "--help"
152    fi
153  } | sort
154
155}
156
157
158# The tests.
159set +e  # Do not exit on error
160TESTS_FAILED=
161
162echo "Checking general completion"
163includes svn "he" "help"
164includes svn "" "help"
165includes svn "" "--version"
166
167for SVN_CMD in svn svnadmin svndumpfilter svnlook svnrdump svnsync; do
168  echo "Checking list of subcommands: $SVN_CMD"
169  HELP_SUBCMDS=`get_svn_subcommands "$SVN_CMD" | tr "\n" " "`
170  COMPLETION_SUBCMDS=`get_completions "$SVN_CMD" | tr " " "\n" | grep -v "^-" | sort | tr "\n" " "`
171  if [ "$HELP_SUBCMDS" != "$COMPLETION_SUBCMDS" ]; then
172    fail "non-option completions for \"$SVN_CMD\" != subcommands accepted" \
173         "    (non-o. cmpl.: $COMPLETION_SUBCMDS)" \
174         "    (help says:    $HELP_SUBCMDS)"
175  fi
176
177  echo "Checking list of options for each subcommand"
178  for SUBCMD in $HELP_SUBCMDS; do
179    HELP_OPTIONS=`get_svn_options $SVN_CMD $SUBCMD | tr "\n" " "`
180    COMPLETION_OPTIONS=`get_completions $SVN_CMD $SUBCMD - | tr " " "\n" | sort | tr "\n" " "`
181    if [ "$HELP_OPTIONS" != "$COMPLETION_OPTIONS" ]; then
182      fail "completions for \"$SVN_CMD $SUBCMD -\" != options accepted" \
183           "    (completions: $COMPLETION_OPTIONS)" \
184           "    (help says:   $HELP_OPTIONS)"
185    fi
186  done
187done
188
189echo "Checking rejection of synonyms"
190excludes svn "diff -x -u -" "-x"
191excludes svn "diff -x -u --e" "--extensions"
192excludes svn "diff --extensions -u -" "--extensions"
193excludes svn "diff --extensions -u -" "-x"
194excludes svn "diff --extensions=-u -" "-x"
195
196if [ $TESTS_FAILED ]; then
197  echo "FAILURE: at least one bash_completion test failed."
198else
199  echo "All bash_completion tests passed."
200fi
201