feat(gnovm): Instrumental Coverage
Description
This PR implements test coverage functionality for gno.The implementation uses AST-based code instrumentation to track line execution during tests.
alternate version of task #2616 Closed #3750
Implementation Overview
The coverage system consists of for main components:
- CoverageTracker
- CoverageInstrumenter AST-based transformer that inserts
testing.MarkLine()calls at execution points - Native Binding: Exposes Go functions to Gno through the testing package
- Report Generation: Creates JSON and text coverage reports with file-level stastics
Code Instrumentation Workflow
The system transforms source code by inserting traking calls before compilation:
For example:
Original Code
func Add(a, b int) int {
if a > 0 {
return a + b
}
return b
}
Instrumented Code
import "testing"
func Add(a, b int) int {
testing.MarkLine("path/to/file.gno", 1)
if a > 0 {
testing.MarkLine("path/to/file.gno", 2)
return a + b
}
testing.MarkLine("path/to/file.gno", 4)
return b
}
Usage
# Run tests with coverage
gno test -cover ./package
# Save coverage report to file
gno test -cover -coverprofile=coverage.json ./package
Coverage Report Format
The system generates reports in JSON format:
{
"files": {
"package/file.gno": {
"lines": {
"10": 5, // line 10 executed 5 times
"11": 0, // line 11 not executed
"12": 3 // line 12 executed 3 times
},
"total": 50,
"covered": 35,
"coverage": 70.0
}
}
}
Open Questions
During implementation, I discovered that coverage behaves differently for package (p/) and realms (r/):
- Realms: Coverage works correctly and shows accurate percentages
- Packages: Coverage shows 0% even when code is executed
This appears to be related to how packages handled, causing them to execute in a context where the testing package is not available for instrumentation.
Question for reviewers: Is this the expected behavior due to the architectural difference between packages and realms? Should packages be handled differently in the coverage system, or is there an alternative approach to instrument pure packages that don't have access to the testing context during execution?
It's a workaround, but I confirmed that coverage is measured for p packages as well when changing the module path to r in gnomod.toml file.
Example:
$ gno test examples/gno.land/p/demo/btree/btree_test.gno -cover
ok examples/gno.land/p/demo/btree 6.45s
Coverage Report:
Total Lines: 230
Covered Lines: 0
Overall Coverage: 0.00%
File: gno.land/p/demo/btree/btree.gno
Total Lines: 230
Covered Lines: 0
Coverage: 0.00%
After chage gnomod.toml file
ok examples/gno.land/p/demo/btree 6.69s
Coverage Report:
Total Lines: 230
Covered Lines: 161
Overall Coverage: 70.00%
File: gno.land/r/demo/btree/btree.gno
Total Lines: 230
Covered Lines: 161
Coverage: 70.00%
Future Enhancements
- Fix coverage for packages (
p/) - Add HTML report generation
🛠 PR Checks Summary
🔴 Pending initial approval by a review team member, or review from tech-staff
Manual Checks (for Reviewers):
- [ ] IGNORE the bot requirements for this PR (force green CI check)
Read More
🤖 This bot helps streamline PR reviews by verifying automated checks and providing guidance for contributors and reviewers.
✅ Automated Checks (for Contributors):
🟢 Maintainers must be able to edit this pull request (more info) 🔴 Pending initial approval by a review team member, or review from tech-staff
☑️ Contributor Actions:
- Fix any issues flagged by automated checks.
- Follow the Contributor Checklist to ensure your PR is ready for review.
- Add new tests, or document why they are unnecessary.
- Provide clear examples/screenshots, if necessary.
- Update documentation, if required.
- Ensure no breaking changes, or include
BREAKING CHANGEnotes. - Link related issues/PRs, where applicable.
☑️ Reviewer Actions:
- Complete manual checks for the PR, including the guidelines and additional checks if applicable.
📚 Resources:
Debug
Automated Checks
Maintainers must be able to edit this pull request (more info)
If
🟢 Condition met └── 🟢 And ├── 🟢 The base branch matches this pattern: ^master$ └── 🟢 The pull request was created from a fork (head branch repo: notJoon/gno-core)Then
🟢 Requirement satisfied └── 🟢 Maintainer can modify this pull requestPending initial approval by a review team member, or review from tech-staff
If
🟢 Condition met └── 🟢 And ├── 🟢 The base branch matches this pattern: ^master$ └── 🟢 Not (🔴 Pull request author is a member of the team: tech-staff)Then
🔴 Requirement not satisfied └── 🔴 If ├── 🔴 Condition │ └── 🔴 Or │ ├── 🔴 At least one of these user(s) reviewed the pull request: [jefft0 leohhhn n0izn0iz notJoon omarsy x1unix] (with state "APPROVED") │ ├── 🔴 At least 1 user(s) of the team tech-staff reviewed pull request │ └── 🔴 This pull request is a draft └── 🔴 Else └── 🔴 And ├── 🟢 This label is applied to pull request: review/triage-pending └── 🔴 On no pull requestManual Checks
**IGNORE** the bot requirements for this PR (force green CI check)
If
🟢 Condition met └── 🟢 On every pull requestCan be checked by
- Any user with comment edit permission
Codecov Report
:white_check_mark: All modified and coverable lines are covered by tests.
:loudspeaker: Thoughts on this report? Let us know!
~~I discovered when importing other realms within the realm package, a "unexpected node with ..." panic occurs. need to figure it out the cause.~~
partially fixed https://github.com/gnolang/gno/pull/4241/commits/3938af171e620f989ed1497d44da764ec475efea
@notJoon , do you want to merge master yet one more time to see if it fixes CI checks?
@jefft0 I need to update the internal implementations (handle the codecov failures too)