Find Go coverage by module import path.

Why: `go test -coverprofile` names each file by its module import path.
crapper found it only by path suffix, which works when the module path
happens to end with the project-relative path. A module in a subdirectory
whose name differs from its directory (`svc/go.mod` declaring
`module example.com/api`) scored 0% for every function.

What: `go_import_name` builds the profile's name for a file from the
nearest go.mod's module line and the path inside the module. The bundle
remembers its root and looks a Go file up by that name first, then by the
old suffix match. `_nearest` becomes the shared `nearest_marker` so
coverage and the runners find go.mod the same way. mutator uses
`go_import_name` so the two tools cannot drift.

Proof: three new coverage specs (nested module with a different name,
quoted module path, fallback without a module line) failed first, now
pass; 147 pass, the 2 bb/uml environment failures are unchanged.
crapper on changed code: max CRAP 9.0 (percent_for, unchanged), new
functions <= 7.0. dryer: no candidates in changed files. mutator on the
changed lines: 13/13 killed.
This commit is contained in:
Robert C. Martin
2026-11-10 12:38:04 -06:00
parent 6fd92c4c9b
commit c757ec79a6
4 changed files with 86 additions and 13 deletions
+1 -1
View File
@@ -61,7 +61,7 @@ Clojure follows crap4clj: `if` / `when` and their variants, `and`, `or`, `loop`,
Java follows crap4java: `if`, loops, `catch`, `?:`, each `switch` label, and `&&` / `||`. Constructors and methods inside anonymous classes are omitted. Coverage is JaCoCo's `INSTRUCTION` counter.
Go follows crap4go: `if`, `for`, `range`, each `switch` and `select` clause, and `&&` / `||`. Coverage is `go test -coverprofile`.
Go follows crap4go: `if`, `for`, `range`, each `switch` and `select` clause, and `&&` / `||`. Coverage is `go test -coverprofile`, which names each file by its module import path (the `module` line of the nearest `go.mod` plus the path inside that module). crapper and mutator look a file up by that name first, then by the longest matching path suffix.
TypeScript, TSX, and JavaScript (`.js`, `.jsx`, `.mjs`, `.cjs`) use the same structural decisions as Java, including `&&` inside JSX, plus `??` and `?.`. Top-level functions, class methods, and top-level arrow functions are entries. An inline Express callback — `.get`, `.post`, `.put`, `.patch`, `.delete`, `.head`, `.options`, `.all`, `.use`, and `.route(path).get(...)` — is its own entry, named `GET /users`. A second callback on that same route is `GET /users#2`. Its decisions are not also charged to the enclosing function. Other nested callbacks stay inside the enclosing function. Coverage is LCOV. When the report has branch records (`BRDA`) inside a function, the score uses those branches; a function with no branches uses line hits. A `coverage` script is used as-is. A Vitest project runs `vitest --coverage` (installing `@vitest/coverage-v8` into `node_modules` when it is missing, without editing `package.json`). Other test scripts are wrapped in `c8`.