Skip to content

Commit 7e6c886

Browse files
authored
fix(coverage): printf spy no longer breaks coverage collection (#726)
1 parent dedb77b commit 7e6c886

3 files changed

Lines changed: 33 additions & 3 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
### Fixed
99
- A test that exited non-zero no longer poisons the exit code of subsequent tests in the same file (the per-test exit code was accumulated instead of reset)
1010
- Coverage report now counts backslash line-continuation lines as covered: a multi-line statement's hit is propagated forward across its continuation chain, so the lines after a trailing `\` are no longer reported as uncovered (#722)
11+
- Spying or mocking the `printf` builtin no longer breaks coverage collection: the coverage buffer is now flushed with `builtin printf`, so a test double can no longer shadow the write and silently drop all coverage data for that test (#724)
1112

1213
### Changed
1314
- Documentation and project URLs now point to the new primary domain `bashunit.com` (old `bashunit.typeddevs.com` continues to work as a redirect)

src/coverage.sh

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -330,11 +330,13 @@ function bashunit::coverage::flush_buffer() {
330330
test_hits_file="${_BASHUNIT_COVERAGE_TEST_HITS_FILE}.$$"
331331
fi
332332

333-
# Write buffered data in a single I/O operation
334-
printf '%s' "$_BASHUNIT_COVERAGE_BUFFER" >>"$data_file"
333+
# Write buffered data in a single I/O operation.
334+
# Use `builtin printf` so a user test spying/mocking the printf builtin
335+
# cannot shadow the coverage write and silently drop data (see issue #724).
336+
builtin printf '%s' "$_BASHUNIT_COVERAGE_BUFFER" >>"$data_file"
335337

336338
if [ -n "$_BASHUNIT_COVERAGE_HITS_BUFFER" ]; then
337-
printf '%s' "$_BASHUNIT_COVERAGE_HITS_BUFFER" >>"$test_hits_file"
339+
builtin printf '%s' "$_BASHUNIT_COVERAGE_HITS_BUFFER" >>"$test_hits_file"
338340
fi
339341

340342
# Reset buffer

tests/unit/coverage_core_test.sh

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,33 @@ function test_coverage_record_line_writes_to_file() {
268268
assert_contains "$test_file:20" "$content"
269269
}
270270

271+
function test_coverage_flush_buffer_writes_even_when_printf_is_spied() {
272+
BASHUNIT_COVERAGE="true"
273+
BASHUNIT_COVERAGE_PATHS="/"
274+
BASHUNIT_COVERAGE_EXCLUDE=""
275+
bashunit::coverage::init
276+
277+
local test_file="/some/path/script.sh"
278+
bashunit::coverage::record_line "$test_file" "10"
279+
bashunit::coverage::record_line "$test_file" "20"
280+
281+
# Spying printf must not shadow the coverage write (issue #724)
282+
bashunit::spy printf
283+
bashunit::coverage::flush_buffer
284+
bashunit::unmock printf
285+
286+
local data_file="$_BASHUNIT_COVERAGE_DATA_FILE"
287+
if bashunit::parallel::is_enabled; then
288+
data_file="${_BASHUNIT_COVERAGE_DATA_FILE}.$$"
289+
fi
290+
291+
local content
292+
content=$(cat "$data_file")
293+
294+
assert_contains "$test_file:10" "$content"
295+
assert_contains "$test_file:20" "$content"
296+
}
297+
271298
function test_coverage_cleanup_removes_temp_files() {
272299
BASHUNIT_COVERAGE="true"
273300
bashunit::coverage::init

0 commit comments

Comments
 (0)