-
Notifications
You must be signed in to change notification settings - Fork 379
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(gnovm): Test Coverage Support #2616
base: master
Are you sure you want to change the base?
Conversation
Codecov ReportAttention: Patch coverage is 📢 Thoughts on this report? Let us know! |
….go and op_eval.go
For simplicity for reviewing I'll change this PR as ready for review. |
Now all CI passes successfully. Previously, I had set it up to always generate and store coverage data whenever tests were run. But this caused timeouts in the strings and bytes packages due to increase overhead (#2935). So I modified it to collect data only when the coverage flag ( Currently, since it only perfoems basic operations, there are cases where lines that should be executed are not recognized during the execution. However, this case requires branch coverage and other static analysis features to be implemented. So, I plan to make these in a separate PR to prevent the current PR size from becoming too large. The planned tasks are as follows:
|
Hello @notJoon . It says "This branch has conflicts that must be resolved". Are there merge conflicts with master? |
The changes look reasonable to me, but we need a core dev to decide if they are needed. Do you need anything else from me for the "triage" review? |
I think checking just the basic things should be sufficient. I've added flags as per convention. |
@notJoon , can you resolve the conflicts with the master branch? |
@jefft0 resolved. thanks 👍 |
@notJoon, the failing CI checks are because of a misconfiguration of codecov. This has been fixed. Can you please push an empty commit? This will make the CI checks run again and hopefully pass. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the feature, but I think we need to change some things about the implementation 🙏
I'm primarily concerned that this sort of functionality and code doesn't belong in pkg/gnolang
, but warrants its own separate package. Please check the comments, and we can take it from there
cc @thehowl
gnovm/cmd/gno/test.go
Outdated
@@ -257,24 +301,33 @@ func gnoTestPkg( | |||
stdout = commands.WriteNopCloser(mockOut) | |||
} | |||
|
|||
coverageData := gno.NewCoverageData(cfg.rootDir) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick:
coverageData := gno.NewCoverageData(cfg.rootDir).Enable()
if !cfg.coverage {
coverageData.Disable()
}
gnovm/cmd/gno/test.go
Outdated
// testing with *_test.gno | ||
if len(unittestFiles) > 0 { | ||
// Determine gnoPkgPath by reading gno.mod | ||
var gnoPkgPath string | ||
modfile, err := gnomod.ParseAt(pkgPath) | ||
if err == nil { | ||
// TODO: use pkgPathFromRootDir? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leftover?
gnovm/cmd/gno/test.go
Outdated
@@ -392,6 +450,36 @@ func gnoTestPkg( | |||
} | |||
} | |||
|
|||
if cfg.coverage { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick:
if !coverageData.IsEnabled() {return errs}
// ...
gnovm/pkg/gnolang/op_exec.go
Outdated
@@ -433,6 +433,7 @@ EXEC_SWITCH: | |||
} | |||
switch cs := s.(type) { | |||
case *AssignStmt: | |||
m.recordCoverage(cs) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the overhead of something like this, for VM ops?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should have condition check also. I forgot
gnovm/pkg/gnolang/machine.go
Outdated
@@ -81,6 +82,9 @@ type Machine struct { | |||
// it is executed. It is reset to zero after the defer functions in the current | |||
// scope have finished executing. | |||
DeferPanicScope uint | |||
|
|||
// Test Coverage | |||
Coverage *CoverageData |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does the VM usually keep track of this sort of data? cc @mvertes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’ve added a this field to update executed lines directly on the Machine
, but it might be better to separate this functionality if possible.
Maybe I can fetch the executed lines separately using a getter, and then handle them within the coverage package. This would eliminate the dependency and overhead on the Machine
as well.
gnovm/pkg/gnolang/coverage.go
Outdated
strings.HasSuffix(pkgPath, "_filetest.gno") | ||
} | ||
|
||
type jsonCoverageMap map[string]JSONFileCoverage |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should move these types to the ToJSON
method, and not have them be package-level types
gnovm/pkg/gnolang/coverage.go
Outdated
return json.MarshalIndent(jsonCov, "", " ") | ||
} | ||
|
||
func (c *CoverageData) SaveJSON(fileName string) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't need to be a method on CoverageData
gnovm/pkg/gnolang/coverage.go
Outdated
return os.WriteFile(fileName, data, 0o644) | ||
} | ||
|
||
// TODO: temporary HTML output. need to match with go coverage tool |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leftover?
gnovm/pkg/gnolang/coverage.go
Outdated
} | ||
|
||
// TODO: temporary HTML output. need to match with go coverage tool | ||
func (c *CoverageData) SaveHTML(outputFileName string) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't need to be a method on CoverageData
gnovm/pkg/gnolang/coverage.go
Outdated
return t.Execute(file, data) | ||
} | ||
|
||
func (m *Machine) addFileToCodeCoverage(file string, totalLines int) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Machine
doesn't need this method, function can simply take in CoverageData
Merge RequirementsThe following requirements must be fulfilled before a pull request can be merged. These requirements are defined in this configuration file. Automated Checks🟢 Maintainers must be able to edit this pull request Details
Manual Checks
Details
|
Description
closes #1121
Support testing coverage functionality into previous testing framework. This feature tracks and reports which parts of the code were executed during test runs.
Key Changes
CoverageData
andFileCoverage
structsPopOp
inMachine.Run()
methodrecordCoverage
function for each statement to obtaining accurate coverage tracking resultAddHit
methodCLI Options
CLI Options
-cover
gno test <path> -cover
-view=<pattern>
gno test <path> -cover -view=demo/foo
-show-hits
gno test <path> -cover -view=demo/foo -show-hits
-html=<file>
gno test <path> -cover -html=coverage.html
All coverage-related flags must be preceded by the
-cover
flag to be active.Notes:
-view
option supports partial file path patterns and can match multiple files.-view
, the output is color-coded: green for executed lines, yellow for executable but not executed lines, and white for non-executable lines.-show-hits
option adds an orange hit count next to each executed line when used with-view
.The currently added CLI was added for testing during development. I plan to modify it later to provide the same functionality as go tool.