What version of rules_go are you using?
v0.62.0
What version of gazelle are you using?
n/a
What version of Bazel are you using?
9.1.0
Does this issue reproduce with the latest releases of all the above?
Yes.
What operating system and processor architecture are you using?
macOS/arm64, though nothing here is platform-specific.
What did you do?
Ran coverage over a go_library that no test links:
go_library(
name = "untested",
srcs = ["untested.go"],
importpath = "example.com/untested",
)
$ bazel coverage //src:all --combined_report=lcov
What did you expect to see?
The package reported at 0%. go test -cover ./... has done this natively since
Go 1.22 (golang/go#18909): a package with functions but no test files emits
zero-count blocks and prints coverage: 0.0% of statements.
What did you see instead?
SF:src/untested.go
FNF:0
FNH:0
LF:0
LH:0
end_of_record
rules_go doesn't pass any baseline coverage files, so Bazel falls back to
BaselineCoverageAction, which writes only the path and end_of_record. The
zeros are just LcovPrinter serializing counters nobody computed.
The catch is that LF:0 is also the correct output for a file that genuinely
has nothing to cover — constants only, or excluded by build constraints.
Consumers can't tell the two apart, so 0/0 ends up scored as 100%, and a package
with no tests at all scores better than one with partial tests. In our repo that
hid 21 files (~700 lines).
This is bazelbuild/bazel#5716, but that's no longer blocking: Bazel 9 added
baseline_coverage_files to coverage_common.instrumented_files_info
(bazelbuild/bazel#26133), which is the seam @fmeum suggested there:
For Go, a separate tool could do this.
Implemented in #4669: it runs cmd/cover over the target's srcs to get the real
line set, guarded on bazel_features so Bazel 7/8 keep today's behaviour.
What version of rules_go are you using?
v0.62.0
What version of gazelle are you using?
n/a
What version of Bazel are you using?
9.1.0
Does this issue reproduce with the latest releases of all the above?
Yes.
What operating system and processor architecture are you using?
macOS/arm64, though nothing here is platform-specific.
What did you do?
Ran coverage over a
go_librarythat no test links:$ bazel coverage //src:all --combined_report=lcovWhat did you expect to see?
The package reported at 0%.
go test -cover ./...has done this natively sinceGo 1.22 (golang/go#18909): a package with functions but no test files emits
zero-count blocks and prints
coverage: 0.0% of statements.What did you see instead?
rules_go doesn't pass any baseline coverage files, so Bazel falls back to
BaselineCoverageAction, which writes only the path andend_of_record. Thezeros are just
LcovPrinterserializing counters nobody computed.The catch is that
LF:0is also the correct output for a file that genuinelyhas nothing to cover — constants only, or excluded by build constraints.
Consumers can't tell the two apart, so 0/0 ends up scored as 100%, and a package
with no tests at all scores better than one with partial tests. In our repo that
hid 21 files (~700 lines).
This is bazelbuild/bazel#5716, but that's no longer blocking: Bazel 9 added
baseline_coverage_filestocoverage_common.instrumented_files_info(bazelbuild/bazel#26133), which is the seam @fmeum suggested there:
Implemented in #4669: it runs
cmd/coverover the target's srcs to get the realline set, guarded on
bazel_featuresso Bazel 7/8 keep today's behaviour.