Skip to content

Commit 52368d3

Browse files
authored
fix(test-doubles): use builtin echo/printf in spy to prevent recursion (#607) (#614)
Co-authored-by: SauronBot <sauronbot@users.noreply.github.com>
1 parent 8a946e2 commit 52368d3

7 files changed

Lines changed: 43 additions & 10 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
## Unreleased
44

5+
### Fixed
6+
- Fix spying on `echo` or `printf` causing bashunit to hang due to infinite recursion (#607)
7+
58
## [0.34.1](https://github.com/TypedDevs/bashunit/compare/0.34.0...0.34.1) - 2026-03-20
69

710
### Added

src/helpers.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -273,11 +273,11 @@ function bashunit::helper::normalize_variable_name() {
273273
normalized_string="${input_string//[^a-zA-Z0-9_]/_}"
274274

275275
local _re='^[a-zA-Z_]'
276-
if [ "$(echo "$normalized_string" | "$GREP" -cE "$_re" || true)" -eq 0 ]; then
276+
if [ "$(builtin echo "$normalized_string" | "$GREP" -cE "$_re" || true)" -eq 0 ]; then
277277
normalized_string="_$normalized_string"
278278
fi
279279

280-
echo "$normalized_string"
280+
builtin echo "$normalized_string"
281281
}
282282

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

src/test_doubles.sh

Lines changed: 8 additions & 8 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?}"
@@ -83,7 +83,7 @@ function assert_have_been_called() {
8383
local file_var="${variable}_times_file"
8484
local times=0
8585
if [ -f "${!file_var-}" ]; then
86-
times=$(cat "${!file_var}" 2>/dev/null || echo 0)
86+
times=$(cat "${!file_var}" 2>/dev/null || builtin echo 0)
8787
fi
8888
local label="${2:-$(bashunit::helper::normalize_test_function_name "${FUNCNAME[1]}")}"
8989

@@ -141,7 +141,7 @@ function assert_have_been_called_times() {
141141
local file_var="${variable}_times_file"
142142
local times=0
143143
if [ -f "${!file_var-}" ]; then
144-
times=$(cat "${!file_var}" 2>/dev/null || echo 0)
144+
times=$(cat "${!file_var}" 2>/dev/null || builtin echo 0)
145145
fi
146146
local label="${3:-$(bashunit::helper::normalize_test_function_name "${FUNCNAME[1]}")}"
147147
if [ "$times" -ne "$expected_count" ]; then
@@ -170,7 +170,7 @@ function assert_have_been_called_nth_with() {
170170

171171
local times=0
172172
if [ -f "${!times_file_var-}" ]; then
173-
times=$(cat "${!times_file_var}" 2>/dev/null || echo 0)
173+
times=$(cat "${!times_file_var}" 2>/dev/null || builtin echo 0)
174174
fi
175175

176176
if [ "$nth" -gt "$times" ]; then

tests/functional/doubles_test.sh

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,3 +106,21 @@ function test_mock_mktemp_does_not_break_spy_creation() {
106106
assert_have_been_called_times 1 rm
107107
assert_have_been_called_with rm "-f" "/tmp/mocked_temp_file"
108108
}
109+
110+
function test_spy_on_echo_does_not_hang() {
111+
source ./tests/functional/fixtures/echo_function.sh
112+
bashunit::spy echo
113+
114+
write_message "hello world"
115+
116+
assert_have_been_called echo
117+
}
118+
119+
function test_spy_on_printf_does_not_hang() {
120+
source ./tests/functional/fixtures/printf_function.sh
121+
bashunit::spy printf
122+
123+
format_message "hello world"
124+
125+
assert_have_been_called printf
126+
}
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)