28
28
29
29
# Check whether required environment variables are set.
30
30
env_var_check () {
31
- local var
32
- for var in __SHELLMOCK_MOCKBIN __SHELLMOCK_FUNCSTORE __SHELLMOCK_OUTPUT; do
33
- if ! [[ -d ${! var-} ]]; then
34
- echo >&2 " Vairable ${var} not defined or no directory."
35
- exit 1
31
+ local var dir
32
+ local vars=(
33
+ __SHELLMOCK_ORGPATH
34
+ )
35
+ local dirs=(
36
+ __SHELLMOCK_MOCKBIN
37
+ __SHELLMOCK_FUNCSTORE
38
+ __SHELLMOCK_OUTPUT
39
+ )
40
+ for dir in " ${dirs[@]} " ; do
41
+ if ! [[ -d ${! dir-} ]]; then
42
+ echo >&2 " Variable ${dir} not defined or no directory."
43
+ _kill_parent
36
44
fi
37
45
done
46
+ for var in " ${vars[@]} " ; do
47
+ if [[ -z ${! var-} ]]; then
48
+ echo >&2 " Variable ${var} not defined."
49
+ _kill_parent
50
+ fi
51
+ done
52
+ }
53
+
54
+ # Remove shellmock's mockbin directory from PATH. We do so by using the env var
55
+ # set by the main shellmock code.
56
+ rm_mock_path () {
57
+ export PATH=" ${__SHELLMOCK_ORGPATH} "
58
+ }
59
+
60
+ # Make sure that we can find all the executables we need.
61
+ binary_deps_check () {
62
+ local has_err=0
63
+ local cmd
64
+ for cmd in base32 cat mkdir; do
65
+ if ! command -v " ${cmd} " & > /dev/null; then
66
+ echo >&2 " Required executable ${cmd} not found."
67
+ has_err=1
68
+ fi
69
+ done
70
+ if ! command -v flock & > /dev/null; then
71
+ echo >&2 " SHELLMOCK: Optional executable flock not found." \
72
+ " Please install for best performance."
73
+ fi
74
+ if [[ ${has_err} -ne 0 ]]; then
75
+ _kill_parent
76
+ return 1
77
+ fi
78
+ return 0
38
79
}
39
80
40
81
get_and_ensure_outdir () {
41
82
local cmd_b32=" $1 "
42
83
43
- local max_num_calls=${SHELLMOCK_MAX_CALLS_PER_MOCK:- 1000 }
84
+ local max_num_calls=${SHELLMOCK_MAX_CALLS_PER_MOCK:- 100 }
44
85
if ! [[ ${max_num_calls} =~ ^[0-9][0-9]* $ ]]; then
45
86
echo >&2 " SHELLMOCK_MAX_CALLS_PER_MOCK must be a number."
46
- _kill_parent " ${PPID} "
87
+ _kill_parent
47
88
return 1
48
89
fi
49
90
local tmp
50
91
tmp=$(( max_num_calls - 1 ))
51
92
local max_digits=${# tmp}
52
93
94
+ # shellmock: uses-command=flock
95
+ local _flock=flock
96
+ if
97
+ ! command -v flock & > /dev/null \
98
+ || [[ ${__SHELLMOCK_TESTING_WO_FLOCK-0} -eq 1 ]]
99
+ then
100
+ _flock=true
101
+ fi
102
+
53
103
# Ensure no two calls overwrite each other in a thread-safe way.
54
- local count
55
- count=$( printf " %0${max_digits} d" " 0" )
56
- local outdir=" ${__SHELLMOCK_OUTPUT} /${cmd_b32} /${count} "
104
+ local padded count=0
105
+ padded=$( printf " %0${max_digits} d" " ${count} " )
106
+ mkdir -p " ${__SHELLMOCK_OUTPUT} /${cmd_b32} "
107
+ local outdir=" ${__SHELLMOCK_OUTPUT} /${cmd_b32} /${padded} "
57
108
while ! (
58
109
# Increment the counter until we find one that has not been used before.
59
- flock -n 9 || exit 1
60
- [[ -d ${outdir} ]] && exit 1
61
- mkdir -p " ${outdir} "
110
+ " ${_flock} " -n 9 || exit 1
111
+ mkdir " ${outdir} " & > /dev/null
62
112
) 9> " ${__SHELLMOCK_OUTPUT} /lockfile_${cmd_b32} _${count} " ; do
63
- count=$( printf " %0${max_digits} d" " $(( count + 1 )) " )
64
- outdir=" ${__SHELLMOCK_OUTPUT} /${cmd_b32} /${count} "
113
+ count=$(( count + 1 ))
114
+ padded=$( printf " %0${max_digits} d" " ${count} " )
115
+ outdir=" ${__SHELLMOCK_OUTPUT} /${cmd_b32} /${padded} "
116
+
117
+ if [[ ${count} -ge ${max_num_calls} ]]; then
118
+ echo >&2 " The maximum number of calls per mock is ${max_num_calls} ." \
119
+ " Consider increasing SHELLMOCK_MAX_CALLS_PER_MOCK, which is currently" \
120
+ " set to '${max_num_calls} '."
121
+ _kill_parent
122
+ return 1
123
+ fi
65
124
done
66
125
67
- if [[ ${count} -ge ${max_num_calls} ]]; then
68
- echo >&2 " The maximum number of calls per mock is ${max_num_calls} ." \
69
- " Consider increasing SHELLMOCK_MAX_CALLS_PER_MOCK, which is currently" \
70
- " set to '${max_num_calls} '."
71
- _kill_parent " ${PPID} "
72
- return 1
73
- fi
74
-
75
126
echo " ${outdir} "
76
127
}
77
128
78
129
# When called, this script will write its own errors to a file so that they can
79
130
# be retrieved later when asserting expectations.
80
131
errecho () {
81
- echo >> " ${STDERR} " " $@ "
132
+ if [[ -n ${STDERR} ]]; then
133
+ echo >> " ${STDERR} " " $@ "
134
+ else
135
+ echo >&2 " $@ "
136
+ fi
82
137
}
83
138
84
139
output_args_and_stdin () {
@@ -103,6 +158,7 @@ _find_arg() {
103
158
shift
104
159
local args=(" $@ " )
105
160
161
+ local check
106
162
for check in " ${args[@]} " ; do
107
163
if [[ ${arg} == " ${check} " ]]; then
108
164
return 0
@@ -117,6 +173,7 @@ _find_regex_arg() {
117
173
shift
118
174
local args=(" $@ " )
119
175
176
+ local check
120
177
for check in " ${args[@]} " ; do
121
178
if [[ ${check} =~ ${regex} ]]; then
122
179
return 0
@@ -135,8 +192,8 @@ _match_spec() {
135
192
local spec
136
193
while read -r spec; do
137
194
local id val
138
- read -r -d ' : ' id <<< " ${spec}"
139
- val=" ${spec## " ${id} " : } "
195
+ id= " ${spec%%:* } "
196
+ val=" ${spec#* : } "
140
197
141
198
if [[ ${spec} =~ ^any: ]]; then
142
199
if ! _find_arg " ${val} " " $@ " ; then
@@ -183,7 +240,7 @@ _is_bats_process() {
183
240
}
184
241
185
242
_kill_parent () {
186
- local parent=" $1 "
243
+ local parent=" ${PPID} "
187
244
188
245
# Do not kill the parent process if it is a bats process. If we did, bats
189
246
# would no longer be able to track the test.
@@ -224,7 +281,7 @@ find_matching_argspec() {
224
281
) && wait $! || return 1
225
282
226
283
errecho " SHELLMOCK: unexpected call '${cmd} $* '"
227
- _kill_parent " ${PPID} "
284
+ _kill_parent
228
285
return 1
229
286
}
230
287
@@ -254,7 +311,7 @@ run_hook() {
254
311
# output. Anything output via errecho will end up in a file that is only
255
312
# looked at when asserting expectations.
256
313
echo >&2 " SHELLMOCK: error calling hook '${! hook_env_var} '"
257
- _kill_parent " ${PPID} "
314
+ _kill_parent
258
315
return 1
259
316
fi
260
317
fi
@@ -291,21 +348,25 @@ forward() {
291
348
shift
292
349
local args=(" $@ " )
293
350
294
- while read -r -d: path; do
295
- if
296
- [[ ${path} != " ${__SHELLMOCK_MOCKBIN} " ]] \
297
- && PATH=" ${path} " command -v " ${cmd} " & > /dev/null
298
- then
299
- local exe=" ${path} /${cmd} "
300
- echo >&2 " SHELLMOCK: forwarding call: ${exe} $* "
301
- exec " ${exe} " " ${args[@]} "
302
- fi
303
- done <<< " ${__SHELLMOCK_FUNCSTORE}:${PATH}"
351
+ local exe
352
+ local path=" ${__SHELLMOCK_FUNCSTORE} :${PATH} "
353
+ # Extend PATH by shellmock's funcstore because we may want to forward to a
354
+ # function instead of a binary.
355
+ if
356
+ ! exe=$( PATH=" ${path} " command -v " ${cmd} " )
357
+ then
358
+ echo >&2 " SHELLMOCK: failed to find executable to forward to: ${cmd} "
359
+ _kill_parent
360
+ fi
361
+ echo >&2 " SHELLMOCK: forwarding call: ${exe@ Q} ${*@ Q} "
362
+ exec " ${exe} " " ${args[@]} "
304
363
}
305
364
306
365
main () {
307
366
# Make sure that shell aliases never interfere with this mock.
308
367
unalias -a
368
+ rm_mock_path
369
+ binary_deps_check
309
370
env_var_check
310
371
# Determine our name. This assumes that the first value in argv is the name of
311
372
# the command. This is almost always so.
0 commit comments