test: 11 packages ship with no test file, and the suite sits at 65.6% statement coverage #523

Open
opened 2026-09-16 00:13:53 +00:00 by hexajon · 0 comments
Owner

The gap

Go's own coverage tooling answers "what do we not test". Two commands, no extra dependency:

# per-package and total statement coverage
go test -coverprofile=cover.out -covermode=atomic ./...
go tool cover -func=cover.out          # per-function; last line is the total

# packages that carry no test file at all
go list -f '{{if and (not .TestGoFiles) (not .XTestGoFiles)}}{{.ImportPath}}{{end}}' ./...

Measured on aed5df08 (full suite green, covermode=atomic):

  • Total: 65.6% of statements.
  • 1683 of 4205 functions are at 0.0%.
  • 11 of 80 packages have no test file at all.

scripts/gate.sh never builds a coverage profile, so none of this is visible in the gate or in CI. The number can drift in either direction and nothing says so.

Packages with zero tests

package lines
internal/cmd/misc 243
internal/cmd/adr 183
internal/cmd/gpgkey 176
internal/cmd/search 156
internal/cmd/orchestrate 155
internal/cmd/packages 155
internal/testutil 139
internal/cmd/open 84
internal/cmd/activitypub 60
internal/service/adr/madr 29
internal/cmd/serverinfo 28

internal/testutil is test scaffolding, so it needs no tests of its own. The other ten are production code reachable from the CLI.

Weakest covered packages

25.4%  internal/cmd/user
25.9%  internal/service/issue
30.0%  internal/cmd/org
31.8%  internal/cmd/prune
33.3%  internal/cmd/actions
41.2%  internal/cmd/branchapi
42.7%  internal/cmd/admin
44.2%  internal/cmdutil
44.7%  internal/cmd/wiki
46.2%  internal/gitea
47.0%  internal/mcp

internal/service/issue is the one that worries me most. It is core business logic, not a thin CLI shell, and the whole issue surface sits at 0.0%: List, Create, Update, Close, Open, Comment, ListComments, EditComment, DeleteComment, ListDeps, AddDep, RemoveDep, the reaction calls, the attachment calls, Lock/Unlock, the subscription calls, and issue/develop.go:50 Develop. The package has a Client interface built for exactly this kind of fake-backed test, so the cost per test is low.

internal/cmd/* coverage is partly structural: a cobra wiring file has few branchable statements. Flag parsing, argument validation, and the dual-mode JSON/text output path are still worth pinning, and those are where renames break.

Acceptance criteria

  1. Every production package has at least one test file. internal/testutil is the one allowed exception, recorded as such.
  2. internal/service/issue and internal/service's issue files reach at least 70% statements, with the fake Client driving the API calls.
  3. internal/cmd/adr, internal/cmd/search, internal/cmd/packages, internal/cmd/orchestrate, internal/cmd/gpgkey, internal/cmd/misc, internal/cmd/open, internal/cmd/activitypub, internal/cmd/serverinfo, and internal/service/adr/madr each get tests over flag parsing, argument validation, and output shape.
  4. scripts/gate.sh reports the total coverage number so a drop is visible. Whether it also fails below a floor is open, see below.
  5. go test ./... stays green and the gate stays clean.

Open question

Should the gate fail below a coverage floor, or only print the number? A hard floor stops silent erosion but turns a legitimate refactor into a red gate. I am not deciding this inside the issue. Reporting the number (criterion 4) is safe either way and does not depend on the answer.

## The gap Go's own coverage tooling answers "what do we not test". Two commands, no extra dependency: ```bash # per-package and total statement coverage go test -coverprofile=cover.out -covermode=atomic ./... go tool cover -func=cover.out # per-function; last line is the total # packages that carry no test file at all go list -f '{{if and (not .TestGoFiles) (not .XTestGoFiles)}}{{.ImportPath}}{{end}}' ./... ``` Measured on `aed5df08` (full suite green, `covermode=atomic`): - Total: **65.6% of statements**. - **1683 of 4205 functions are at 0.0%.** - **11 of 80 packages have no test file at all.** `scripts/gate.sh` never builds a coverage profile, so none of this is visible in the gate or in CI. The number can drift in either direction and nothing says so. ## Packages with zero tests | package | lines | | --- | --- | | `internal/cmd/misc` | 243 | | `internal/cmd/adr` | 183 | | `internal/cmd/gpgkey` | 176 | | `internal/cmd/search` | 156 | | `internal/cmd/orchestrate` | 155 | | `internal/cmd/packages` | 155 | | `internal/testutil` | 139 | | `internal/cmd/open` | 84 | | `internal/cmd/activitypub` | 60 | | `internal/service/adr/madr` | 29 | | `internal/cmd/serverinfo` | 28 | `internal/testutil` is test scaffolding, so it needs no tests of its own. The other ten are production code reachable from the CLI. ## Weakest covered packages ``` 25.4% internal/cmd/user 25.9% internal/service/issue 30.0% internal/cmd/org 31.8% internal/cmd/prune 33.3% internal/cmd/actions 41.2% internal/cmd/branchapi 42.7% internal/cmd/admin 44.2% internal/cmdutil 44.7% internal/cmd/wiki 46.2% internal/gitea 47.0% internal/mcp ``` `internal/service/issue` is the one that worries me most. It is core business logic, not a thin CLI shell, and the whole issue surface sits at 0.0%: `List`, `Create`, `Update`, `Close`, `Open`, `Comment`, `ListComments`, `EditComment`, `DeleteComment`, `ListDeps`, `AddDep`, `RemoveDep`, the reaction calls, the attachment calls, `Lock`/`Unlock`, the subscription calls, and `issue/develop.go:50 Develop`. The package has a `Client` interface built for exactly this kind of fake-backed test, so the cost per test is low. `internal/cmd/*` coverage is partly structural: a `cobra` wiring file has few branchable statements. Flag parsing, argument validation, and the dual-mode JSON/text output path are still worth pinning, and those are where renames break. ## Acceptance criteria 1. Every production package has at least one test file. `internal/testutil` is the one allowed exception, recorded as such. 2. `internal/service/issue` and `internal/service`'s issue files reach at least 70% statements, with the fake `Client` driving the API calls. 3. `internal/cmd/adr`, `internal/cmd/search`, `internal/cmd/packages`, `internal/cmd/orchestrate`, `internal/cmd/gpgkey`, `internal/cmd/misc`, `internal/cmd/open`, `internal/cmd/activitypub`, `internal/cmd/serverinfo`, and `internal/service/adr/madr` each get tests over flag parsing, argument validation, and output shape. 4. `scripts/gate.sh` reports the total coverage number so a drop is visible. Whether it also fails below a floor is open, see below. 5. `go test ./...` stays green and the gate stays clean. ## Open question Should the gate fail below a coverage floor, or only print the number? A hard floor stops silent erosion but turns a legitimate refactor into a red gate. I am not deciding this inside the issue. Reporting the number (criterion 4) is safe either way and does not depend on the answer.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
sixfold-space/madtea#523
No description provided.