feat(coverage): branch coverage MVP via static branch-point detection#661
Merged
Chemaclass merged 7 commits intofeat/coverage-improvementsfrom May 4, 2026
Merged
Conversation
Records the decision to use static branch-point detection plus line-hit inference for the branch-coverage MVP, scoping included constructs (if/elif/else, case) and listing deferred items (implicit-else, short-circuit branches, loop-entry decisions).
Adds bashunit::coverage::extract_branches, a single-pass parser that discovers if/elif/else chains and case patterns and emits one record per decision with the line ranges of each arm. Pairs it with bashunit::coverage::compute_branch_hits, which walks the existing line-hit data and marks each arm taken iff at least one executable line inside its range was hit. Both functions are Bash 3.0+ compatible (parallel indexed arrays in place of associative arrays). See adrs/adr-007-branch-coverage-mvp.md for the design and known limitations.
Verifies that the LCOV report emits branch records produced by compute_branch_hits: one BRDA per arm for if/else and case, the BRF total, the BRH count of taken arms, and that BRF/BRH are still emitted (as zeros) for files with no branch points.
Adds the BRDA/BRF/BRH entry to the changelog and a "Branch Coverage Scope" section to docs/coverage.md spelling out the limitations (no-executable-line arms, implicit-else omission, compound conditional folding, untracked short-circuit and loop-entry decisions).
Eliminates duplication in extract_branches by extracting two helpers: - _append_arm: shared arm-close logic, returns via global to avoid per-line subshell cost. - _is_case_pattern_line: case-pattern opener detection. Folds the elif/else clauses (identical except for keyword) into one branch. Replaces the IFS+set-- arm split in compute_branch_hits with a parameter-expansion loop, and pulls the per-arm taken check into _arm_taken. LCOV BRDA parsing now uses IFS='|' read for clarity. Verified on /bin/bash 3.2.57 (macOS default): 814 unit tests pass, parallel mode included. No new Bash 4+ constructs introduced.
b018d86 to
21adf54
Compare
Promotes branch coverage to a top-level section with: a what-counts table, the two opt-in env vars (SHOW_FUNCTIONS, SHOW_UNCOVERED), a worked example showing the full LCOV output for a partially-tested if/elif/else chain, genhtml integration command, and a Codecov gate recipe. Adds FN/FNDA/FNF/FNH and BRDA/BRF/BRH rows to the LCOV field reference table.
Extracts six small handlers (_branch_push_if, _branch_close_if_arm, _branch_emit_if, _branch_push_case, _branch_close_case_arm, _branch_emit_case, _branch_open_case_pattern) that operate on the state arrays kept as locals in extract_branches via Bash's dynamic scoping. The main loop becomes a straightforward dispatch over the first token of each line. Bash 3.0+ compatibility preserved (no namerefs, no associative arrays); verified on /bin/bash 3.2.57 with the full unit suite in both sequential and parallel modes.
CosmeValera
approved these changes
May 4, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds branch coverage to the LCOV report so reviewers see whether
else/elifarms and individualcasepatterns were exercised. Stacked on top of #660 (function records + uncovered hotspots) and will rebase tomainonce #660 merges.bashunit::coverage::extract_branches— single-pass parser that findsif/elif/elsechains andcasepatterns, emitting one record per decision with the line ranges of each arm. Same shape as the existingextract_functionswalker.bashunit::coverage::compute_branch_hits— reuses the existing line-hit data file. An arm is taken iff at least one executable line inside its range was hit. Output:<decision_line>|<block>|<branch_index>|<taken>.BRDA:<line>,<block>,<branch>,<taken>,BRF:<count>andBRH:<count>per file, consumed unchanged bygenhtml, Codecov and Coveralls.Why static + line-hit inference, not runtime tracing
DEBUG-trap decision tracing via
BASH_COMMANDwas rejected because:BASH_COMMANDsemantics diverge across Bash 3.x and 5.x for((...)),[[...]]and pipelines.Static parsing of branch points plus line-hit lookup keeps zero runtime overhead and a deterministic, testable contract.
Known limitations (documented)
else(anif/elifchain without an explicitelse) reports only the explicit arms.if A && B) are reported as a single binary decision, not per sub-expression.&&/||short-circuit branches outsideifand loop-entry decisions (while/until) are not tracked.Each is listed in
docs/coverage.mdandadrs/adr-007-branch-coverage-mvp.mdwith a path to a follow-up if/when prioritized.Test plan
./bashunit tests/unit/coverage_branches_test.sh— 8 tests for extractor + hit computation./bashunit tests/unit/coverage_reporting_test.sh— 3 new BRDA tests (if/else, case, no-branches), 32 total./bashunit --parallel tests/unit/— 814 passed, no regressionsmake sa(ShellCheck),make lint(EditorConfig)Commits
docs(adr): branch coverage MVP designfeat(coverage): branch extractor and hit computationtest(coverage): cover BRDA/BRF/BRH emission in LCOV reportdocs(coverage): document branch coverage MVP