Skip to content

Commit cfdee38

Browse files
committed
refactor(coverage): drop subshell capture in branch hit walk
Converts _arm_taken from echo-via-subshell to a global-out (_BASHUNIT_ARM_TAKEN_OUT) so compute_branch_hits no longer pays a subshell per arm. Pulls the consecutive-line range compression in the uncovered-lines text report into _compress_ranges so the loop body stays focused on filtering and the formatting concern lives in one named helper. Bash 3.0+ verified on /bin/bash 3.2.57: 40 reporting+branch tests pass, 809 unit tests pass under --parallel, make sa and make lint stay green.
1 parent c0593b1 commit cfdee38

1 file changed

Lines changed: 51 additions & 46 deletions

File tree

src/coverage.sh

Lines changed: 51 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -936,23 +936,23 @@ function bashunit::coverage::extract_branches() {
936936
done
937937
}
938938

939-
# Returns 1 (true/taken) iff any executable line in [arm_start..arm_end]
940-
# has a recorded hit. Caller must have populated the hits_by_line and
941-
# src_lines arrays in scope (Bash 3.0 cannot pass arrays in).
942-
# Result is echoed as "0" or "1" so the caller can capture it.
939+
# Sets _BASHUNIT_ARM_TAKEN_OUT to 1 iff any executable line in
940+
# [arm_start..arm_end] has a recorded hit, else 0. Caller must have
941+
# populated the hits_by_line and src_lines arrays in scope; Bash 3.0
942+
# cannot pass arrays into a function. Result is returned via the
943+
# global to avoid a per-arm subshell.
944+
_BASHUNIT_ARM_TAKEN_OUT=0
943945
function bashunit::coverage::_arm_taken() {
944-
local arm_start="$1" arm_end="$2"
945-
local ln content h
946+
local arm_start="$1" arm_end="$2" ln
946947
for ((ln = arm_start; ln <= arm_end; ln++)); do
947-
content="${src_lines[$((ln - 1))]:-}"
948-
bashunit::coverage::is_executable_line "$content" "$ln" || continue
949-
h=${hits_by_line[$ln]:-0}
950-
if [ "$h" -gt 0 ]; then
951-
echo 1
948+
bashunit::coverage::is_executable_line \
949+
"${src_lines[$((ln - 1))]:-}" "$ln" || continue
950+
if [ "${hits_by_line[$ln]:-0}" -gt 0 ]; then
951+
_BASHUNIT_ARM_TAKEN_OUT=1
952952
return
953953
fi
954954
done
955-
echo 0
955+
_BASHUNIT_ARM_TAKEN_OUT=0
956956
}
957957

958958
# Compute branch hit data for a file.
@@ -979,16 +979,16 @@ function bashunit::coverage::compute_branch_hits() {
979979

980980
local block=0 decision_line _kind arms branch_entry
981981
local -a arm_specs=()
982-
local arm arm_index taken
982+
local arm arm_index
983983
while IFS= read -r branch_entry; do
984984
[ -z "$branch_entry" ] && continue
985985
IFS='|' read -r decision_line _kind arms <<<"$branch_entry"
986986

987987
arm_index=0
988988
IFS=',' read -ra arm_specs <<<"$arms"
989989
for arm in "${arm_specs[@]}"; do
990-
taken=$(bashunit::coverage::_arm_taken "${arm%%:*}" "${arm##*:}")
991-
echo "${decision_line}|${block}|${arm_index}|${taken}"
990+
bashunit::coverage::_arm_taken "${arm%%:*}" "${arm##*:}"
991+
echo "${decision_line}|${block}|${arm_index}|${_BASHUNIT_ARM_TAKEN_OUT}"
992992
arm_index=$((arm_index + 1))
993993
done
994994

@@ -1140,6 +1140,38 @@ function bashunit::coverage::report_text() {
11401140
fi
11411141
}
11421142

1143+
# Compress a sorted list of integers into a comma-separated range
1144+
# string (e.g. "3 4 5 7 9 10" -> "3-5,7,9-10"). Result on
1145+
# _BASHUNIT_RANGES_OUT to avoid a subshell on each call.
1146+
_BASHUNIT_RANGES_OUT=""
1147+
function bashunit::coverage::_compress_ranges() {
1148+
local out="" start="" end="" n
1149+
for n in "$@"; do
1150+
if [ -z "$start" ]; then
1151+
start="$n"
1152+
end="$n"
1153+
elif [ "$n" -eq $((end + 1)) ]; then
1154+
end="$n"
1155+
else
1156+
if [ "$start" = "$end" ]; then
1157+
out="${out}${start},"
1158+
else
1159+
out="${out}${start}-${end},"
1160+
fi
1161+
start="$n"
1162+
end="$n"
1163+
fi
1164+
done
1165+
if [ -n "$start" ]; then
1166+
if [ "$start" = "$end" ]; then
1167+
out="${out}${start}"
1168+
else
1169+
out="${out}${start}-${end}"
1170+
fi
1171+
fi
1172+
_BASHUNIT_RANGES_OUT="${out%,}"
1173+
}
1174+
11431175
# List executable lines that were never hit, grouped by file.
11441176
# Gated on BASHUNIT_COVERAGE_SHOW_UNCOVERED=true. Output is suppressed
11451177
# when no uncovered lines exist so a fully-covered run stays quiet.
@@ -1178,37 +1210,10 @@ function bashunit::coverage::report_text_uncovered() {
11781210
fi
11791211

11801212
local display_file="${file#"$(pwd)"/}"
1181-
local color reset="$_BASHUNIT_COLOR_DEFAULT"
1182-
color="$_BASHUNIT_COLOR_FAILED"
1183-
1184-
# Compress consecutive line numbers into ranges (3-5 instead of 3,4,5)
1185-
local out="" prev_start="" prev_end="" ln
1186-
for ln in "${uncovered_lines[@]}"; do
1187-
if [ -z "$prev_start" ]; then
1188-
prev_start="$ln"
1189-
prev_end="$ln"
1190-
continue
1191-
fi
1192-
if [ "$ln" -eq $((prev_end + 1)) ]; then
1193-
prev_end="$ln"
1194-
else
1195-
if [ "$prev_start" = "$prev_end" ]; then
1196-
out="${out}${prev_start},"
1197-
else
1198-
out="${out}${prev_start}-${prev_end},"
1199-
fi
1200-
prev_start="$ln"
1201-
prev_end="$ln"
1202-
fi
1203-
done
1204-
if [ -n "$prev_start" ]; then
1205-
if [ "$prev_start" = "$prev_end" ]; then
1206-
out="${out}${prev_start}"
1207-
else
1208-
out="${out}${prev_start}-${prev_end}"
1209-
fi
1210-
fi
1211-
out="${out%,}"
1213+
local color="$_BASHUNIT_COLOR_FAILED" reset="$_BASHUNIT_COLOR_DEFAULT"
1214+
local out
1215+
bashunit::coverage::_compress_ranges "${uncovered_lines[@]}"
1216+
out="$_BASHUNIT_RANGES_OUT"
12121217

12131218
printf "%s%s:%s%s\n" "$color" "$display_file" "$out" "$reset"
12141219
done < <(bashunit::coverage::get_tracked_files)

0 commit comments

Comments
 (0)