@@ -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
943945function 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