Fix the coverage tests

This fixes a bug where `make cover` was missing packages. The target now
covers all code except for code placed in the top level package (such as
main.go) and anything placed in the testutils directory.

This also fixes minor issues with the Dockerfile and the coverage_check
script

Note that this commit also strives to increase code coverage beyond the
80% margin

Change-Id: I9e1cbcf841cc869345a00f05e39774cb3da10065
This commit is contained in:
Ian Howell 2019-10-02 11:05:59 -05:00
parent 08cc716de5
commit dc9c78b210
12 changed files with 886 additions and 15 deletions

View File

@ -10,11 +10,7 @@ ENV GO111MODULE=on
RUN make get-modules RUN make get-modules
ARG MAKE_TARGET=build ARG MAKE_TARGET=build
RUN make ${MAKE_TARGET} && \ RUN make ${MAKE_TARGET}
if [[ "${MAKE_TARGET}" == 'lint' ]]; then \
mkdir -p /usr/src/airshipctl/bin; \
touch /usr/src/airshipctl/bin/airshipctl; \
fi
FROM ${RELEASE_IMAGE} as release FROM ${RELEASE_IMAGE} as release
COPY --from=builder /usr/src/airshipctl/bin/airshipctl /usr/local/bin/airshipctl COPY --from=builder /usr/src/airshipctl/bin/airshipctl /usr/local/bin/airshipctl

View File

@ -18,11 +18,15 @@ DOCKER_IMAGE_NAME ?= airshipctl
DOCKER_IMAGE_PREFIX ?= airshipit DOCKER_IMAGE_PREFIX ?= airshipit
DOCKER_IMAGE_TAG ?= dev DOCKER_IMAGE_TAG ?= dev
DOCKER_IMAGE ?= $(DOCKER_REGISTRY)/$(DOCKER_IMAGE_PREFIX)/$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG) DOCKER_IMAGE ?= $(DOCKER_REGISTRY)/$(DOCKER_IMAGE_PREFIX)/$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)
DOCKER_TARGET_STAGE ?= release
# go options # go options
PKG := ./... PKG := ./...
TESTS := . TESTS := .
TEST_FLAGS :=
COVER_FLAGS :=
COVER_PROFILE := cover.out COVER_PROFILE := cover.out
COVER_PKG := $(shell go list ./... | tail -n+2 | grep -v "opendev.org/airship/airshipctl/testutil" | paste -sd"," -)
.PHONY: get-modules .PHONY: get-modules
get-modules: get-modules:
@ -34,17 +38,17 @@ build: get-modules
.PHONY: test .PHONY: test
test: lint test: lint
test: TESTFLAGS += -race -v
test: unit-tests
test: cover test: cover
.PHONY: unit-tests .PHONY: unit-tests
unit-tests: build unit-tests: TESTFLAGS += -race -v
unit-tests:
@echo "Performing unit test step..." @echo "Performing unit test step..."
@GO111MODULE=on go test -run $(TESTS) $(PKG) $(TESTFLAGS) -covermode=atomic -coverprofile=$(COVER_PROFILE) @GO111MODULE=on go test -run $(TESTS) $(PKG) $(TESTFLAGS) $(COVER_FLAGS)
@echo "All unit tests passed" @echo "All unit tests passed"
.PHONY: cover .PHONY: cover
cover: COVER_FLAGS = -covermode=atomic -coverprofile=$(COVER_PROFILE) -coverpkg=$(COVER_PKG)
cover: unit-tests cover: unit-tests
@./tools/coverage_check $(COVER_PROFILE) @./tools/coverage_check $(COVER_PROFILE)
@ -56,7 +60,7 @@ lint:
.PHONY: docker-image .PHONY: docker-image
docker-image: docker-image:
@docker build . --build-arg MAKE_TARGET=$(DOCKER_MAKE_TARGET) --tag $(DOCKER_IMAGE) @docker build . --build-arg MAKE_TARGET=$(DOCKER_MAKE_TARGET) --tag $(DOCKER_IMAGE) --target $(DOCKER_TARGET_STAGE)
.PHONY: print-docker-image-tag .PHONY: print-docker-image-tag
print-docker-image-tag: print-docker-image-tag:
@ -64,10 +68,12 @@ print-docker-image-tag:
.PHONY: docker-image-unit-tests .PHONY: docker-image-unit-tests
docker-image-unit-tests: DOCKER_MAKE_TARGET = cover docker-image-unit-tests: DOCKER_MAKE_TARGET = cover
docker-image-unit-tests: DOCKER_TARGET_STAGE = builder
docker-image-unit-tests: docker-image docker-image-unit-tests: docker-image
.PHONY: docker-image-lint .PHONY: docker-image-lint
docker-image-lint: DOCKER_MAKE_TARGET = lint docker-image-lint: DOCKER_MAKE_TARGET = lint
docker-image-lint: DOCKER_TARGET_STAGE = builder
docker-image-lint: docker-image docker-image-lint: docker-image
.PHONY: clean .PHONY: clean
@ -81,7 +87,7 @@ docs:
.PHONY: update-golden .PHONY: update-golden
update-golden: delete-golden update-golden: delete-golden
update-golden: TESTFLAGS += -update -v update-golden: TESTFLAGS += -update
update-golden: PKG = opendev.org/airship/airshipctl/cmd/... update-golden: PKG = opendev.org/airship/airshipctl/cmd/...
update-golden: unit-tests update-golden: unit-tests

View File

@ -0,0 +1,48 @@
package completion_test
import (
"errors"
"testing"
"opendev.org/airship/airshipctl/cmd/completion"
"opendev.org/airship/airshipctl/testutil"
)
func TestCompletion(t *testing.T) {
cmd := completion.NewCompletionCommand()
cmdTests := []*testutil.CmdTest{
{
Name: "completion-bash",
CmdLine: "bash",
Cmd: cmd,
},
{
Name: "completion-zsh",
CmdLine: "zsh",
Cmd: cmd,
},
{
Name: "completion-no-args",
CmdLine: "",
Cmd: cmd,
Error: errors.New("shell not specified"),
},
{
Name: "completion-too-many-args",
CmdLine: "bash zsh",
Cmd: cmd,
Error: errors.New("too many arguments, expected only the shell type"),
},
{
Name: "completion-unknown-shell",
CmdLine: "fish",
Cmd: cmd,
Error: errors.New("unsupported shell type \"fish\""),
},
}
for _, tt := range cmdTests {
testutil.RunTest(t, tt)
}
}

View File

@ -0,0 +1,303 @@
# bash completion for completion -*- shell-script -*-
__completion_debug()
{
if [[ -n ${BASH_COMP_DEBUG_FILE} ]]; then
echo "$*" >> "${BASH_COMP_DEBUG_FILE}"
fi
}
# Homebrew on Macs have version 1.3 of bash-completion which doesn't include
# _init_completion. This is a very minimal version of that function.
__completion_init_completion()
{
COMPREPLY=()
_get_comp_words_by_ref "$@" cur prev words cword
}
__completion_index_of_word()
{
local w word=$1
shift
index=0
for w in "$@"; do
[[ $w = "$word" ]] && return
index=$((index+1))
done
index=-1
}
__completion_contains_word()
{
local w word=$1; shift
for w in "$@"; do
[[ $w = "$word" ]] && return
done
return 1
}
__completion_handle_reply()
{
__completion_debug "${FUNCNAME[0]}"
case $cur in
-*)
if [[ $(type -t compopt) = "builtin" ]]; then
compopt -o nospace
fi
local allflags
if [ ${#must_have_one_flag[@]} -ne 0 ]; then
allflags=("${must_have_one_flag[@]}")
else
allflags=("${flags[*]} ${two_word_flags[*]}")
fi
COMPREPLY=( $(compgen -W "${allflags[*]}" -- "$cur") )
if [[ $(type -t compopt) = "builtin" ]]; then
[[ "${COMPREPLY[0]}" == *= ]] || compopt +o nospace
fi
# complete after --flag=abc
if [[ $cur == *=* ]]; then
if [[ $(type -t compopt) = "builtin" ]]; then
compopt +o nospace
fi
local index flag
flag="${cur%=*}"
__completion_index_of_word "${flag}" "${flags_with_completion[@]}"
COMPREPLY=()
if [[ ${index} -ge 0 ]]; then
PREFIX=""
cur="${cur#*=}"
${flags_completion[${index}]}
if [ -n "${ZSH_VERSION}" ]; then
# zsh completion needs --flag= prefix
eval "COMPREPLY=( \"\${COMPREPLY[@]/#/${flag}=}\" )"
fi
fi
fi
return 0;
;;
esac
# check if we are handling a flag with special work handling
local index
__completion_index_of_word "${prev}" "${flags_with_completion[@]}"
if [[ ${index} -ge 0 ]]; then
${flags_completion[${index}]}
return
fi
# we are parsing a flag and don't have a special handler, no completion
if [[ ${cur} != "${words[cword]}" ]]; then
return
fi
local completions
completions=("${commands[@]}")
if [[ ${#must_have_one_noun[@]} -ne 0 ]]; then
completions=("${must_have_one_noun[@]}")
fi
if [[ ${#must_have_one_flag[@]} -ne 0 ]]; then
completions+=("${must_have_one_flag[@]}")
fi
COMPREPLY=( $(compgen -W "${completions[*]}" -- "$cur") )
if [[ ${#COMPREPLY[@]} -eq 0 && ${#noun_aliases[@]} -gt 0 && ${#must_have_one_noun[@]} -ne 0 ]]; then
COMPREPLY=( $(compgen -W "${noun_aliases[*]}" -- "$cur") )
fi
if [[ ${#COMPREPLY[@]} -eq 0 ]]; then
declare -F __custom_func >/dev/null && __custom_func
fi
# available in bash-completion >= 2, not always present on macOS
if declare -F __ltrim_colon_completions >/dev/null; then
__ltrim_colon_completions "$cur"
fi
# If there is only 1 completion and it is a flag with an = it will be completed
# but we don't want a space after the =
if [[ "${#COMPREPLY[@]}" -eq "1" ]] && [[ $(type -t compopt) = "builtin" ]] && [[ "${COMPREPLY[0]}" == --*= ]]; then
compopt -o nospace
fi
}
# The arguments should be in the form "ext1|ext2|extn"
__completion_handle_filename_extension_flag()
{
local ext="$1"
_filedir "@(${ext})"
}
__completion_handle_subdirs_in_dir_flag()
{
local dir="$1"
pushd "${dir}" >/dev/null 2>&1 && _filedir -d && popd >/dev/null 2>&1
}
__completion_handle_flag()
{
__completion_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}"
# if a command required a flag, and we found it, unset must_have_one_flag()
local flagname=${words[c]}
local flagvalue
# if the word contained an =
if [[ ${words[c]} == *"="* ]]; then
flagvalue=${flagname#*=} # take in as flagvalue after the =
flagname=${flagname%=*} # strip everything after the =
flagname="${flagname}=" # but put the = back
fi
__completion_debug "${FUNCNAME[0]}: looking for ${flagname}"
if __completion_contains_word "${flagname}" "${must_have_one_flag[@]}"; then
must_have_one_flag=()
fi
# if you set a flag which only applies to this command, don't show subcommands
if __completion_contains_word "${flagname}" "${local_nonpersistent_flags[@]}"; then
commands=()
fi
# keep flag value with flagname as flaghash
# flaghash variable is an associative array which is only supported in bash > 3.
if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then
if [ -n "${flagvalue}" ] ; then
flaghash[${flagname}]=${flagvalue}
elif [ -n "${words[ $((c+1)) ]}" ] ; then
flaghash[${flagname}]=${words[ $((c+1)) ]}
else
flaghash[${flagname}]="true" # pad "true" for bool flag
fi
fi
# skip the argument to a two word flag
if __completion_contains_word "${words[c]}" "${two_word_flags[@]}"; then
c=$((c+1))
# if we are looking for a flags value, don't show commands
if [[ $c -eq $cword ]]; then
commands=()
fi
fi
c=$((c+1))
}
__completion_handle_noun()
{
__completion_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}"
if __completion_contains_word "${words[c]}" "${must_have_one_noun[@]}"; then
must_have_one_noun=()
elif __completion_contains_word "${words[c]}" "${noun_aliases[@]}"; then
must_have_one_noun=()
fi
nouns+=("${words[c]}")
c=$((c+1))
}
__completion_handle_command()
{
__completion_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}"
local next_command
if [[ -n ${last_command} ]]; then
next_command="_${last_command}_${words[c]//:/__}"
else
if [[ $c -eq 0 ]]; then
next_command="_completion_root_command"
else
next_command="_${words[c]//:/__}"
fi
fi
c=$((c+1))
__completion_debug "${FUNCNAME[0]}: looking for ${next_command}"
declare -F "$next_command" >/dev/null && $next_command
}
__completion_handle_word()
{
if [[ $c -ge $cword ]]; then
__completion_handle_reply
return
fi
__completion_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}"
if [[ "${words[c]}" == -* ]]; then
__completion_handle_flag
elif __completion_contains_word "${words[c]}" "${commands[@]}"; then
__completion_handle_command
elif [[ $c -eq 0 ]]; then
__completion_handle_command
elif __completion_contains_word "${words[c]}" "${command_aliases[@]}"; then
# aliashash variable is an associative array which is only supported in bash > 3.
if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then
words[c]=${aliashash[${words[c]}]}
__completion_handle_command
else
__completion_handle_noun
fi
else
__completion_handle_noun
fi
__completion_handle_word
}
_completion_root_command()
{
last_command="completion"
command_aliases=()
commands=()
flags=()
two_word_flags=()
local_nonpersistent_flags=()
flags_with_completion=()
flags_completion=()
flags+=("--help")
flags+=("-h")
local_nonpersistent_flags+=("--help")
must_have_one_flag=()
must_have_one_noun=()
must_have_one_noun+=("bash")
must_have_one_noun+=("zsh")
noun_aliases=()
}
__start_completion()
{
local cur prev words cword
declare -A flaghash 2>/dev/null || :
declare -A aliashash 2>/dev/null || :
if declare -F _init_completion >/dev/null 2>&1; then
_init_completion -s || return
else
__completion_init_completion -n "=" || return
fi
local c=0
local flags=()
local two_word_flags=()
local local_nonpersistent_flags=()
local flags_with_completion=()
local flags_completion=()
local commands=("completion")
local must_have_one_flag=()
local must_have_one_noun=()
local last_command
local nouns=()
__completion_handle_word
}
if [[ $(type -t compopt) = "builtin" ]]; then
complete -o default -F __start_completion completion
else
complete -o default -o nospace -F __start_completion completion
fi
# ex: ts=4 sw=4 et filetype=sh

View File

@ -0,0 +1,7 @@
Error: shell not specified
Usage:
completion SHELL [flags]
Flags:
-h, --help help for completion

View File

@ -0,0 +1,7 @@
Error: too many arguments, expected only the shell type
Usage:
completion SHELL [flags]
Flags:
-h, --help help for completion

View File

@ -0,0 +1,7 @@
Error: unsupported shell type "fish"
Usage:
completion SHELL [flags]
Flags:
-h, --help help for completion

View File

@ -0,0 +1,441 @@
#compdef airshipctl
__airshipctl_bash_source() {
alias shopt=':'
alias _expand=_bash_expand
alias _complete=_bash_comp
emulate -L sh
setopt kshglob noshglob braceexpand
source "$@"
}
__airshipctl_type() {
# -t is not supported by zsh
if [ "$1" == "-t" ]; then
shift
# fake Bash 4 to disable "complete -o nospace". Instead
# "compopt +-o nospace" is used in the code to toggle trailing
# spaces. We don't support that, but leave trailing spaces on
# all the time
if [ "$1" = "__airshipctl_compopt" ]; then
echo builtin
return 0
fi
fi
type "$@"
}
__airshipctl_compgen() {
local completions w
completions=( $(compgen "$@") ) || return $?
# filter by given word as prefix
while [[ "$1" = -* && "$1" != -- ]]; do
shift
shift
done
if [[ "$1" == -- ]]; then
shift
fi
for w in "${completions[@]}"; do
if [[ "${w}" = "$1"* ]]; then
echo "${w}"
fi
done
}
__airshipctl_compopt() {
true # don't do anything. Not supported by bashcompinit in zsh
}
__airshipctl_declare() {
if [ "$1" == "-F" ]; then
whence -w "$@"
else
builtin declare "$@"
fi
}
__airshipctl_ltrim_colon_completions()
{
if [[ "$1" == *:* && "$COMP_WORDBREAKS" == *:* ]]; then
# Remove colon-word prefix from COMPREPLY items
local colon_word=${1%${1##*:}}
local i=${#COMPREPLY[*]}
while [[ $((--i)) -ge 0 ]]; do
COMPREPLY[$i]=${COMPREPLY[$i]#"$colon_word"}
done
fi
}
__airshipctl_get_comp_words_by_ref() {
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[${COMP_CWORD}-1]}"
words=("${COMP_WORDS[@]}")
cword=("${COMP_CWORD[@]}")
}
__airshipctl_filedir() {
local RET OLD_IFS w qw
__debug "_filedir $@ cur=$cur"
if [[ "$1" = \~* ]]; then
# somehow does not work. Maybe, zsh does not call this at all
eval echo "$1"
return 0
fi
OLD_IFS="$IFS"
IFS=$'\n'
if [ "$1" = "-d" ]; then
shift
RET=( $(compgen -d) )
else
RET=( $(compgen -f) )
fi
IFS="$OLD_IFS"
IFS="," __debug "RET=${RET[@]} len=${#RET[@]}"
for w in ${RET[@]}; do
if [[ ! "${w}" = "${cur}"* ]]; then
continue
fi
if eval "[[ \"\${w}\" = *.$1 || -d \"\${w}\" ]]"; then
qw="$(__airshipctl_quote "${w}")"
if [ -d "${w}" ]; then
COMPREPLY+=("${qw}/")
else
COMPREPLY+=("${qw}")
fi
fi
done
}
__airshipctl_quote() {
if [[ $1 == \'* || $1 == \"* ]]; then
# Leave out first character
printf %q "${1:1}"
else
printf %q "$1"
fi
}
autoload -U +X bashcompinit && bashcompinit
# use word boundary patterns for BSD or GNU sed
LWORD='[[:<:]]'
RWORD='[[:>:]]'
if sed --help 2>&1 | grep -q GNU; then
LWORD='\<'
RWORD='\>'
fi
__airshipctl_convert_bash_to_zsh() {
sed \
-e 's/declare -F/whence -w/' \
-e 's/_get_comp_words_by_ref "\$@"/_get_comp_words_by_ref "\$*"/' \
-e 's/local \([a-zA-Z0-9_]*\)=/local \1; \1=/' \
-e 's/flags+=("\(--.*\)=")/flags+=("\1"); two_word_flags+=("\1")/' \
-e 's/must_have_one_flag+=("\(--.*\)=")/must_have_one_flag+=("\1")/' \
-e "s/${LWORD}_filedir${RWORD}/__airshipctl_filedir/g" \
-e "s/${LWORD}_get_comp_words_by_ref${RWORD}/__airshipctl_get_comp_words_by_ref/g" \
-e "s/${LWORD}__ltrim_colon_completions${RWORD}/__airshipctl_ltrim_colon_completions/g" \
-e "s/${LWORD}compgen${RWORD}/__airshipctl_compgen/g" \
-e "s/${LWORD}compopt${RWORD}/__airshipctl_compopt/g" \
-e "s/${LWORD}declare${RWORD}/__airshipctl_declare/g" \
-e "s/\\\$(type${RWORD}/\$(__airshipctl_type/g" \
-e 's/aliashash\["\(.\{1,\}\)"\]/aliashash[\1]/g' \
-e 's/FUNCNAME/funcstack/g' \
<<'BASH_COMPLETION_EOF'
# bash completion for completion -*- shell-script -*-
__completion_debug()
{
if [[ -n ${BASH_COMP_DEBUG_FILE} ]]; then
echo "$*" >> "${BASH_COMP_DEBUG_FILE}"
fi
}
# Homebrew on Macs have version 1.3 of bash-completion which doesn't include
# _init_completion. This is a very minimal version of that function.
__completion_init_completion()
{
COMPREPLY=()
_get_comp_words_by_ref "$@" cur prev words cword
}
__completion_index_of_word()
{
local w word=$1
shift
index=0
for w in "$@"; do
[[ $w = "$word" ]] && return
index=$((index+1))
done
index=-1
}
__completion_contains_word()
{
local w word=$1; shift
for w in "$@"; do
[[ $w = "$word" ]] && return
done
return 1
}
__completion_handle_reply()
{
__completion_debug "${FUNCNAME[0]}"
case $cur in
-*)
if [[ $(type -t compopt) = "builtin" ]]; then
compopt -o nospace
fi
local allflags
if [ ${#must_have_one_flag[@]} -ne 0 ]; then
allflags=("${must_have_one_flag[@]}")
else
allflags=("${flags[*]} ${two_word_flags[*]}")
fi
COMPREPLY=( $(compgen -W "${allflags[*]}" -- "$cur") )
if [[ $(type -t compopt) = "builtin" ]]; then
[[ "${COMPREPLY[0]}" == *= ]] || compopt +o nospace
fi
# complete after --flag=abc
if [[ $cur == *=* ]]; then
if [[ $(type -t compopt) = "builtin" ]]; then
compopt +o nospace
fi
local index flag
flag="${cur%=*}"
__completion_index_of_word "${flag}" "${flags_with_completion[@]}"
COMPREPLY=()
if [[ ${index} -ge 0 ]]; then
PREFIX=""
cur="${cur#*=}"
${flags_completion[${index}]}
if [ -n "${ZSH_VERSION}" ]; then
# zsh completion needs --flag= prefix
eval "COMPREPLY=( \"\${COMPREPLY[@]/#/${flag}=}\" )"
fi
fi
fi
return 0;
;;
esac
# check if we are handling a flag with special work handling
local index
__completion_index_of_word "${prev}" "${flags_with_completion[@]}"
if [[ ${index} -ge 0 ]]; then
${flags_completion[${index}]}
return
fi
# we are parsing a flag and don't have a special handler, no completion
if [[ ${cur} != "${words[cword]}" ]]; then
return
fi
local completions
completions=("${commands[@]}")
if [[ ${#must_have_one_noun[@]} -ne 0 ]]; then
completions=("${must_have_one_noun[@]}")
fi
if [[ ${#must_have_one_flag[@]} -ne 0 ]]; then
completions+=("${must_have_one_flag[@]}")
fi
COMPREPLY=( $(compgen -W "${completions[*]}" -- "$cur") )
if [[ ${#COMPREPLY[@]} -eq 0 && ${#noun_aliases[@]} -gt 0 && ${#must_have_one_noun[@]} -ne 0 ]]; then
COMPREPLY=( $(compgen -W "${noun_aliases[*]}" -- "$cur") )
fi
if [[ ${#COMPREPLY[@]} -eq 0 ]]; then
declare -F __custom_func >/dev/null && __custom_func
fi
# available in bash-completion >= 2, not always present on macOS
if declare -F __ltrim_colon_completions >/dev/null; then
__ltrim_colon_completions "$cur"
fi
# If there is only 1 completion and it is a flag with an = it will be completed
# but we don't want a space after the =
if [[ "${#COMPREPLY[@]}" -eq "1" ]] && [[ $(type -t compopt) = "builtin" ]] && [[ "${COMPREPLY[0]}" == --*= ]]; then
compopt -o nospace
fi
}
# The arguments should be in the form "ext1|ext2|extn"
__completion_handle_filename_extension_flag()
{
local ext="$1"
_filedir "@(${ext})"
}
__completion_handle_subdirs_in_dir_flag()
{
local dir="$1"
pushd "${dir}" >/dev/null 2>&1 && _filedir -d && popd >/dev/null 2>&1
}
__completion_handle_flag()
{
__completion_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}"
# if a command required a flag, and we found it, unset must_have_one_flag()
local flagname=${words[c]}
local flagvalue
# if the word contained an =
if [[ ${words[c]} == *"="* ]]; then
flagvalue=${flagname#*=} # take in as flagvalue after the =
flagname=${flagname%=*} # strip everything after the =
flagname="${flagname}=" # but put the = back
fi
__completion_debug "${FUNCNAME[0]}: looking for ${flagname}"
if __completion_contains_word "${flagname}" "${must_have_one_flag[@]}"; then
must_have_one_flag=()
fi
# if you set a flag which only applies to this command, don't show subcommands
if __completion_contains_word "${flagname}" "${local_nonpersistent_flags[@]}"; then
commands=()
fi
# keep flag value with flagname as flaghash
# flaghash variable is an associative array which is only supported in bash > 3.
if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then
if [ -n "${flagvalue}" ] ; then
flaghash[${flagname}]=${flagvalue}
elif [ -n "${words[ $((c+1)) ]}" ] ; then
flaghash[${flagname}]=${words[ $((c+1)) ]}
else
flaghash[${flagname}]="true" # pad "true" for bool flag
fi
fi
# skip the argument to a two word flag
if __completion_contains_word "${words[c]}" "${two_word_flags[@]}"; then
c=$((c+1))
# if we are looking for a flags value, don't show commands
if [[ $c -eq $cword ]]; then
commands=()
fi
fi
c=$((c+1))
}
__completion_handle_noun()
{
__completion_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}"
if __completion_contains_word "${words[c]}" "${must_have_one_noun[@]}"; then
must_have_one_noun=()
elif __completion_contains_word "${words[c]}" "${noun_aliases[@]}"; then
must_have_one_noun=()
fi
nouns+=("${words[c]}")
c=$((c+1))
}
__completion_handle_command()
{
__completion_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}"
local next_command
if [[ -n ${last_command} ]]; then
next_command="_${last_command}_${words[c]//:/__}"
else
if [[ $c -eq 0 ]]; then
next_command="_completion_root_command"
else
next_command="_${words[c]//:/__}"
fi
fi
c=$((c+1))
__completion_debug "${FUNCNAME[0]}: looking for ${next_command}"
declare -F "$next_command" >/dev/null && $next_command
}
__completion_handle_word()
{
if [[ $c -ge $cword ]]; then
__completion_handle_reply
return
fi
__completion_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}"
if [[ "${words[c]}" == -* ]]; then
__completion_handle_flag
elif __completion_contains_word "${words[c]}" "${commands[@]}"; then
__completion_handle_command
elif [[ $c -eq 0 ]]; then
__completion_handle_command
elif __completion_contains_word "${words[c]}" "${command_aliases[@]}"; then
# aliashash variable is an associative array which is only supported in bash > 3.
if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then
words[c]=${aliashash[${words[c]}]}
__completion_handle_command
else
__completion_handle_noun
fi
else
__completion_handle_noun
fi
__completion_handle_word
}
_completion_root_command()
{
last_command="completion"
command_aliases=()
commands=()
flags=()
two_word_flags=()
local_nonpersistent_flags=()
flags_with_completion=()
flags_completion=()
flags+=("--help")
flags+=("-h")
local_nonpersistent_flags+=("--help")
must_have_one_flag=()
must_have_one_noun=()
must_have_one_noun+=("bash")
must_have_one_noun+=("zsh")
noun_aliases=()
}
__start_completion()
{
local cur prev words cword
declare -A flaghash 2>/dev/null || :
declare -A aliashash 2>/dev/null || :
if declare -F _init_completion >/dev/null 2>&1; then
_init_completion -s || return
else
__completion_init_completion -n "=" || return
fi
local c=0
local flags=()
local two_word_flags=()
local local_nonpersistent_flags=()
local flags_with_completion=()
local flags_completion=()
local commands=("completion")
local must_have_one_flag=()
local must_have_one_noun=()
local last_command
local nouns=()
__completion_handle_word
}
if [[ $(type -t compopt) = "builtin" ]]; then
complete -o default -F __start_completion completion
else
complete -o default -o nospace -F __start_completion completion
fi
# ex: ts=4 sw=4 et filetype=sh
BASH_COMPLETION_EOF
}
__airshipctl_bash_source <(__airshipctl_convert_bash_to_zsh)

View File

@ -0,0 +1,22 @@
package util_test
import (
"testing"
"opendev.org/airship/airshipctl/pkg/util"
)
func TestReadYAMLFile(t *testing.T) {
var actual map[string]interface{}
if err := util.ReadYAMLFile("testdata/test.yaml", &actual); err != nil {
t.Fatalf("Error while reading YAML: %s", err.Error())
}
expectedString := "test"
actualString, ok := actual["testString"]
if !ok {
t.Fatalf("Missing \"testString\" attribute")
}
if actualString != expectedString {
t.Errorf("Expected %s, got %s", expectedString, actualString)
}
}

1
pkg/util/testdata/test.yaml vendored Normal file
View File

@ -0,0 +1 @@
testString: test

View File

@ -33,6 +33,9 @@ type CmdTest struct {
// The instatiated version of the root airshipctl command to test // The instatiated version of the root airshipctl command to test
Cmd *cobra.Command Cmd *cobra.Command
// The expected error
Error error
} }
// RunTest either asserts that a specific command's output matches the expected // RunTest either asserts that a specific command's output matches the expected
@ -47,9 +50,8 @@ func RunTest(t *testing.T, test *CmdTest) {
args := strings.Fields(test.CmdLine) args := strings.Fields(test.CmdLine)
cmd.SetArgs(args) cmd.SetArgs(args)
if err := cmd.Execute(); err != nil { err := cmd.Execute()
t.Fatalf("Unexpected error: %s", err.Error()) checkError(t, err, test.Error)
}
if *shouldUpdateGolden { if *shouldUpdateGolden {
updateGolden(t, test, actual.Bytes()) updateGolden(t, test, actual.Bytes())
@ -58,6 +60,20 @@ func RunTest(t *testing.T, test *CmdTest) {
} }
} }
// ReadFixtureBytes is a convenience function for opening a test fixture
func ReadFixtureBytes(t *testing.T, filename string) []byte {
fixtureData, err := ioutil.ReadFile(filename)
if err != nil {
t.Fatalf("Unexpected error while reading fixture at %s: %s", filename, err.Error())
}
return fixtureData
}
// ReadFixtureString is a convenience function for opening a test fixture
func ReadFixtureString(t *testing.T, filename string) string {
return string(ReadFixtureBytes(t, filename))
}
func updateGolden(t *testing.T, test *CmdTest, actual []byte) { func updateGolden(t *testing.T, test *CmdTest, actual []byte) {
goldenDir := filepath.Join(testdataDir, t.Name()+goldenDirSuffix) goldenDir := filepath.Join(testdataDir, t.Name()+goldenDirSuffix)
if err := os.MkdirAll(goldenDir, 0775); err != nil { if err := os.MkdirAll(goldenDir, 0775); err != nil {
@ -84,6 +100,23 @@ func assertEqualGolden(t *testing.T, test *CmdTest, actual []byte) {
} }
} }
func checkError(t *testing.T, actual, expected error) {
if expected == nil {
if actual == nil {
return
}
t.Fatalf("Unexpected error: %q", actual.Error())
}
if actual == nil {
t.Fatalf("Expected error %q, but got nil", expected.Error())
}
if actual.Error() != expected.Error() {
t.Fatalf("Expected error %q, but got %q", expected.Error(), actual.Error())
}
}
func normalize(in []byte) []byte { func normalize(in []byte) []byte {
return bytes.Replace(in, []byte("\r\n"), []byte("\n"), -1) return bytes.Replace(in, []byte("\r\n"), []byte("\n"), -1)
} }

View File

@ -1,5 +1,5 @@
#!/bin/bash #!/bin/bash
set -ex set -e
if [[ $# -ne 1 ]]; then if [[ $# -ne 1 ]]; then
printf "Usage: %s <coverfile>\n" "$0" printf "Usage: %s <coverfile>\n" "$0"