Skip to content

Commit 9f739d0

Browse files
committed
fix(test-doubles): use builtin echo/printf in spy to prevent recursion when spying on echo or printf
Spying on 'echo' or 'printf' caused bashunit to hang indefinitely because the generated spy function called back into itself through bashunit's internal use of these builtins. Changes: - Use 'builtin echo' and 'builtin printf' inside the eval'd spy function body in bashunit::spy to prevent recursive calls when spying on echo or printf - Use 'builtin echo' in bashunit::mock's no-arg form for the same reason - Use 'builtin echo' in bashunit::helper::normalize_variable_name so that spy assertions remain functional even when echo is spied upon - Add functional tests (with fixtures) verifying that spying on echo and printf completes without hanging Fixes #607
1 parent 2a2e24f commit 9f739d0

6 files changed

Lines changed: 36 additions & 6 deletions

File tree

src/helpers.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ function bashunit::helper::normalize_variable_name() {
261261
normalized_string="_$normalized_string"
262262
fi
263263

264-
echo "$normalized_string"
264+
builtin echo "$normalized_string"
265265
}
266266

267267
function bashunit::helper::get_provider_data() {

src/test_doubles.sh

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ function bashunit::mock() {
3434
if [[ $# -gt 0 ]]; then
3535
eval "function $command() { $* \"\$@\"; }"
3636
else
37-
eval "function $command() { echo \"$($CAT)\" ; }"
37+
eval "function $command() { builtin echo \"$($CAT)\" ; }"
3838
fi
3939

4040
export -f "${command?}"
@@ -61,14 +61,14 @@ function bashunit::spy() {
6161
local serialized=\"\"
6262
local arg
6363
for arg in \"\$@\"; do
64-
serialized=\"\$serialized\$(printf '%q' \"\$arg\")$'\\x1f'\"
64+
serialized=\"\$serialized\$(builtin printf '%q' \"\$arg\")$'\\x1f'\"
6565
done
6666
serialized=\${serialized%$'\\x1f'}
67-
printf '%s\x1e%s\\n' \"\$raw\" \"\$serialized\" >> '$params_file'
67+
builtin printf '%s\x1e%s\\n' \"\$raw\" \"\$serialized\" >> '$params_file'
6868
local _c
69-
_c=\$(cat '$times_file' 2>/dev/null || echo 0)
69+
_c=\$(cat '$times_file' 2>/dev/null || builtin echo 0)
7070
_c=\$((_c+1))
71-
echo \"\$_c\" > '$times_file'
71+
builtin echo \"\$_c\" > '$times_file'
7272
}"
7373

7474
export -f "${command?}"

tests/functional/doubles_test.sh

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,3 +89,21 @@ function test_spy_commands_called_once_when_executing_a_sourced_function() {
8989
assert_have_been_called_times 1 awk
9090
assert_have_been_called_times 1 head
9191
}
92+
93+
function test_spy_on_echo_does_not_hang() {
94+
source ./tests/functional/fixtures/echo_function.sh
95+
bashunit::spy echo
96+
97+
write_message "hello world"
98+
99+
assert_have_been_called echo
100+
}
101+
102+
function test_spy_on_printf_does_not_hang() {
103+
source ./tests/functional/fixtures/printf_function.sh
104+
bashunit::spy printf
105+
106+
format_message "hello world"
107+
108+
assert_have_been_called printf
109+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#!/usr/bin/env bash
2+
3+
function write_message() {
4+
echo "message: $*"
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#!/usr/bin/env bash
2+
3+
function format_message() {
4+
printf "formatted: %s\n" "$*"
5+
}

tests/unit/test_doubles_test.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,3 +214,5 @@ function test_unsuccessful_spy_nth_called_with_invalid_index() {
214214
"expected call" "at index 5 but" "only called 1 times")" \
215215
"$(assert_have_been_called_nth_with 5 ps "first")"
216216
}
217+
218+

0 commit comments

Comments
 (0)