forked from jasonkarns/bats-mock
-
Notifications
You must be signed in to change notification settings - Fork 8
/
binstub
executable file
·158 lines (131 loc) · 4.53 KB
/
binstub
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#!/usr/bin/env bash
set -e
# Assume failure of stubbed command
status=1
program="${0##*/}"
# shellcheck disable=SC2018,SC2019 # anything not A-Z0-9 will be _
# the "\n" is necessary to avoid adding a trailing _ to the name
PROGRAM="$(echo "${program}" | tr a-z A-Z | tr -C "A-Z0-9\n" '_')"
if [[ "$PROGRAM" =~ ^[^A-Z_]+(.*)$ ]]; then
# remove leading non A-Z_ characters to make a valid variable name
PROGRAM="${BASH_REMATCH[1]}"
fi
_STUB_PLAN="${PROGRAM}_STUB_PLAN"
_STUB_RUN="${PROGRAM}_STUB_RUN"
_STUB_INDEX="${PROGRAM}_STUB_INDEX"
_STUB_RESULT="${PROGRAM}_STUB_RESULT"
_STUB_END="${PROGRAM}_STUB_END"
_STUB_DEBUG="${PROGRAM}_STUB_DEBUG"
debug() {
if [ -n "${!_STUB_DEBUG}" ] ; then
echo "bats-mock($program): $*" >&"${!_STUB_DEBUG}"
fi
}
[ -e "${!_STUB_PLAN}" ] || exit 1
[ -n "${!_STUB_RUN}" ] || eval "${_STUB_RUN}"="${BATS_MOCK_TMPDIR}/${program}-stub-run"
# Initialize or load the stub run information.
eval "${_STUB_INDEX}"=1
eval "${_STUB_RESULT}"=0
# shellcheck source=stub.bash
[ ! -e "${!_STUB_RUN}" ] || source "${!_STUB_RUN}"
if [ -z "${!_STUB_END}" ]; then
debug "got $program $*"
fi
# Loop over each line in the plan.
index=0
match_found=0
while IFS= read -r line; do
index=$((index + 1))
# debug "bats-mock: [idx $index, want ${!_STUB_INDEX}] $line"
if [ -z "${!_STUB_END}" ] && [ $index -eq "${!_STUB_INDEX}" ]; then
# We found the plan line we're interested in.
# Start off by assuming success.
match_found=1
arguments=("$@")
debug "arguments [${#arguments[@]}] = $(printf "'%q' " "${arguments[@]}")"
# Split the line into an array of arguments to match and a command to run.
# If the line does not contain ' : ' and does not start with a colon
# then the call is assumed to match any arguments and execute the command.
# Special case: Lines starting with double colon are also handled that way
# and get the double colons removed
command=" $line"
if [[ "$line" == ::* ]]; then
command="${line#::}"
elif [ "$command" != "${command/ : }" ]; then
patterns="${command%% : *}"
command="${command#* : }"
parsed_patterns=()
# Parse patterns into tokens using eval to respect quoted
# strings. This is less than ideal, but the pattern input
# is also already eval'd elsewhere. At least this handles
# things like newlines (which xargs doesn't)
origFlags="$-"
set -f
eval "parsed_patterns=(${patterns})"
set "-$origFlags"
debug "patterns [${#parsed_patterns[@]}] = $(printf "'%q' " "${parsed_patterns[@]}")"
# Match the expected argument patterns to actual
# arguments.
for (( i=0; i<${#parsed_patterns[@]}; i++ )); do
pattern="${parsed_patterns[$i]}"
argument="${arguments[$i]}"
if [ "$pattern" = '*' ]; then
continue
fi
case "$argument" in
# uncomment this line for partial pattern matching
# will break existing * matching and generate a shellcheck warning
# $pattern ) ;;
"$pattern" ) ;;
* ) debug "$(printf "match failed at idx %d, expected '%q', got '%q'" "$i" "$pattern" "$argument")"
match_found=2
break ;;
esac
done
# Check if there are unmatched arguments
if [[ ${#arguments[@]} -gt ${#parsed_patterns[@]} ]] ; then
idx="${#parsed_patterns[@]}"
argument="${arguments[$idx]}"
debug "$(printf "unexpected argument '%q' at idx %d" "$argument" "$idx")"
match_found=3
fi
fi
break
fi
done < "${!_STUB_PLAN}"
if [ -n "${!_STUB_END}" ]; then
debug "unstubbing"
if [ ! -f "${!_STUB_RUN}" ] && [ -n "${!_STUB_DEBUG}" ] ; then
echo "The stub for ${program} wasn't run"
exit 1
fi
# Clean up the run file.
"$BATS_MOCK_REAL_rm" -f "${!_STUB_RUN}"
# If the number of lines in the plan is larger than
# the requested index, we failed.
if [ $index -ge "${!_STUB_INDEX}" ]; then
eval "${_STUB_RESULT}"=1
fi
# Return the result.
exit "${!_STUB_RESULT}"
else
# If the arguments matched, evaluate the command
# in a subshell. Otherwise, log the failure.
if [ $match_found -eq 1 ] ; then
debug "running $command"
set +e
( eval "$command" )
status="$?"
debug "command result was $status"
set -e
else
debug "no plan row found"
eval "${_STUB_RESULT}"=1
fi
# Write out the run information.
{ echo "${_STUB_INDEX}=$((${!_STUB_INDEX} + 1))"
echo "${_STUB_RESULT}=${!_STUB_RESULT}"
} > "${!_STUB_RUN}"
debug "result ${!_STUB_RESULT}"
exit "$status"
fi