Skip to content
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: Execution branch coverage report #4755

Merged
merged 17 commits into from
Nov 9, 2023

Conversation

robin-aws
Copy link
Member

@robin-aws robin-aws commented Nov 8, 2023

Description

Implements an execution coverage report in the same format as the existing verification coverage and expected generated test coverage reports. Mainly this just meant using the existing low-level instrumentation provided by the old CLI /coverage option to write coverage data to a temporary file during execution, and then parsing this data and populating a CoverageReport object. I've only implemented this for C# for now, since the execution coverage SHOULD generally be identical across languages (the instrumentation is emitted from the common SinglePassCompiler) but it wouldn't take much work to hook it up for the other backends.

Also adds this to the DafnyStandardLibraries project, and augments the existing coverage report generation to handle .doo files and Uris somewhat better.

Also renames the existing verification option --coverage-report to --verification-coverage-report, since this option is almost always in scope (since most commands run verification), and for dafny test and dafny run "coverage report" more naturally means execution coverage instead. The former hasn't been released yet so this won't break anyone. :)

Resolves #4671

How has this been tested?

comp/CoverageReport.dfy, similar to the existing logger/CoverageReport.dfy

By submitting this pull request, I confirm that my contribution is made under the terms of the MIT license.

@robin-aws robin-aws changed the title feat: Execution coverage report feat: Execution branch coverage report Nov 8, 2023
@robin-aws robin-aws requested a review from atomb November 9, 2023 00:07
@robin-aws robin-aws marked this pull request as ready for review November 9, 2023 00:07
@robin-aws
Copy link
Member Author

I've fixed the refman failure locally but don't want to push and trigger another CI run until I've also addressed any PR feedback

atomb
atomb previously approved these changes Nov 9, 2023
Copy link
Member

@atomb atomb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was remarkably simple! It changed a somewhat large number of lines, but all in very simple ways.

protected void EmitCoverageReportInstrumentation(Program program, ConcreteSyntaxTree wr) {
wr.WriteLine(@"
namespace DafnyProfiling {
public class CodeCoverage {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we put this in the runtime?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not without breaking the existing /coverage option, since the idea is that you could provide your own implementation of DafnyProfilng.CodeCoverage as per the BranchCoverage.dfy test.

foreach (var ((token, _), tally) in legend.Zip(tallies)) {
var label = tally == 0 ? CoverageLabel.NotCovered : CoverageLabel.FullyCovered;
// For now we only identify branches at the line granularity,
// which matches what `dafny generate-tests ... --coverage-report` does as well.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is nice because then merging actual and expected coverage would work well. The merge-coverage-reports command could perhaps use a --diff flag that would produce a report indicating where two coverage reports differed.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My thoughts exactly, and although I do suspect that the actual and expected coverage don't 100% agree on coverable things yet, I don't think it will take much to align them in the future.

ArgumentHelpName = "directory"
};
public static readonly Option<bool> NoTimeStampForCoverageReport = new("--no-timestamp-for-coverage-report",
"Write coverage report directly to the specified folder instead of creating a timestamped subdirectory.") {
IsHidden = true
};
public static readonly Option<string> ExecutionCoverageReport = new("--coverage-report",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could call this --execution-coverage-report, since that term shows up in the variable name and the description text. :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did consider that, but then it would feel weird to not further qualify dafny generate-tests --coverage-report as well, perhaps as --expected-execution-coverage-report. Given the generate-tests one is already released I'm more inclined to leave both with the simpler name.

@@ -32,6 +32,20 @@ method {:test} TestMyMap() {
expect greeting == "Hello\nDafny\n";
}

method {:test} TestGetGreetingSuccess() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The coverage reporting is already bearing dividends. :)

@@ -1 +1 @@
The new `--coverage-report` flag to `dafny verify` creates an HTML report highlighting which portions of the program were and were not necessary for verification. The format is the same as for `dafny generate-tests --coverage-report` and files from the two commands can be merged.
The new `--verification-coverage-report` flag to `dafny verify` creates an HTML report highlighting which portions of the program were and were not necessary for verification. The format is the same as for `dafny generate-tests --coverage-report` and files from the two commands can be merged.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for being thorough about where you change the name of this flag!

@robin-aws robin-aws merged commit 4d7bdf5 into dafny-lang:master Nov 9, 2023
20 checks passed
robin-aws added a commit that referenced this pull request Nov 10, 2023
### Description
#4755 broke the nightly build because I neglected to escape a string
literal properly. Works just fine as long as your directory separator is
`/`, but then Windows had to go and be all different. :)

### How has this been tested?
Existing tests with `run-deep-tests`.

<small>By submitting this pull request, I confirm that my contribution
is made under the terms of the [MIT
license](https://github.com/dafny-lang/dafny/blob/master/LICENSE.txt).</small>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Feature request: runtime branch coverage
2 participants