From 657fb0007f39f07cc0401e0c5d03e25df6234aa4 Mon Sep 17 00:00:00 2001 From: Alexander M Pickering Date: Tue, 21 Jul 2026 20:19:46 -0500 Subject: Inital commit. --- scripts/lib/coverage-report.awk | 84 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 scripts/lib/coverage-report.awk (limited to 'scripts/lib/coverage-report.awk') diff --git a/scripts/lib/coverage-report.awk b/scripts/lib/coverage-report.awk new file mode 100644 index 0000000..982eb45 --- /dev/null +++ b/scripts/lib/coverage-report.awk @@ -0,0 +1,84 @@ +# scripts/lib/coverage-report.awk +# Produce line-coverage reports for shell sources from an executed-line set. +# +# Inputs: +# -v COVERED= TSV of "\t" executed lines (sorted -u). +# -v HTMLDIR= directory to write per-file .html reports into. +# ARGV the source files to report on (absolute paths). +# +# Output (stdout): one CSV row per source file: +# file,total_executable,covered,percent +# +# "Executable" lines are determined heuristically: non-blank, non-comment +# lines that are not pure structural tokens (then/do/done/else/fi/esac/{/}). +# Heredoc/multiline string bodies are approximated and may read as missed; +# see docs/coverage.md for the documented limitations. + +function trim(s) { sub(/^[ \t]+/, "", s); sub(/[ \t]+$/, "", s); return s } + +function is_exec(line, t) { + t = trim(line) + if (t == "") return 0 + if (t ~ /^#/) return 0 + if (t ~ /^(then|do|done|else|fi|esac)([ \t].*)?$/) return 0 + if (t ~ /^[{}]([ \t;].*)?$/) return 0 + if (t ~ /^[()]([ \t].*)?$/) return 0 + if (t ~ /^;;/) return 0 + return 1 +} + +function esc(s) { + gsub(/&/, "\\&", s) + gsub(//, "\\>", s) + return s +} + +function basename(p) { sub(/.*\//, "", p); sub(/.*\\/, "", p); return p } + +BEGIN { + FS = "\t" + # Load the executed-line set. + while ((getline ln < COVERED) > 0) { + nf = split(ln, a, "\t") + if (nf >= 2) covered[a[1] SUBSEP a[2]] = 1 + } + close(COVERED) +} + +# New source file: open its HTML report and reset counters. +FNR == 1 { + if (cur != "") finish_file() + cur = FILENAME + curbase = basename(FILENAME) + total = 0; hit = 0 + html = HTMLDIR "/" curbase ".html" + print "" > html + print "coverage: " esc(curbase) "" > html + print "" > html + print "

coverage: " esc(curbase) "

" > html +} + +{ + cls = "na" + if (is_exec($0)) { + total++ + if ((curbase SUBSEP FNR) in covered) { hit++; cls = "hit" } else { cls = "miss" } + } + print "" > html +} + +function finish_file( pct) { + print "
" FNR "" esc($0) "
" > html + close(html) + pct = (total > 0 ? (hit * 100.0 / total) : 0) + printf "%s,%d,%d,%.1f\n", curbase, total, hit, pct +} + +END { if (cur != "") finish_file() } -- cgit v1.2.3-70-g09d2