Skip to content
This repository has been archived by the owner on Nov 15, 2021. It is now read-only.

Uncovered branches in C# async methods #352

Closed
sharwell opened this issue Oct 8, 2015 · 6 comments
Closed

Uncovered branches in C# async methods #352

sharwell opened this issue Oct 8, 2015 · 6 comments

Comments

@sharwell
Copy link

sharwell commented Oct 8, 2015

We're having a bit of trouble with the handling of async methods in the StyleCopAnalyzers project. These methods are compiled to a state machine, and await expressions within the method result in a branch which is difficult to impossible to cover both cases. Specifically, if the evaluated awaitable is already done, execution of the state machine continues on the current thread. Otherwise, it registers a continuation and returns.

This behavior can be observed in the results for our SA1000UnitTests.cs file.

It would be nice if an option were available to treat coverage of either branch direction as fully covered in this specific case. Based on the results of DotNetAnalyzers/StyleCopAnalyzers#1546 (our failed workaround attempt), I estimate that this issue is responsible for nearly 10% gap in our overall code coverage reporting.

@sawilde
Copy link
Member

sawilde commented Oct 8, 2015

Hmm it may be possible - we've recently started ignoring branches in other auto-generated code (e.g. yield) so if we can find a nice way to identify them before we instrument them we can have a go at ignoring them. Are you able to create a repeat sceanrio that I can add to my test suite that is not so coupled to your code just so know I am looking at the right issue, it'll just save time when someone gets round to looking at the issue.

@sharwell
Copy link
Author

sharwell commented Oct 8, 2015

@sawilde I haven't run this code through OpenCover, but I expect it to reproduce the described behavior. Together, TestCompletedTask and TestIncompleteTask should result in full coverage of ExampleMethodAsync. If either of them is run by itself, however, OpenCover will only show partial coverage.

public void TestCompletedTask()
{
    ExampleMethodAsync(Task.FromResult(0)).GetAwaiter().GetResult();
}

public void TestIncompleteTask()
{
    ExampleMethodAsync(Task.Delay(TimeSpan.FromMilliseconds(10))).GetAwaiter().GetResult();
}

public async Task ExampleMethodAsync(Task antecedent)
{
    await antecedent;
}

@sawilde
Copy link
Member

sawilde commented Oct 9, 2015

Thanks that makes things much clearer

@ddur ddur self-assigned this Dec 26, 2015
@ddur
Copy link
Contributor

ddur commented Dec 26, 2015

Since after await keyword must be only a method with limited return values, no user defined branches exist in that sequence point. This can be recognized by "await " string and branches removed.
Feature will support only c#

@ddur
Copy link
Contributor

ddur commented Dec 27, 2015

No need to fix, compiler generated branches for await are already excluded by recent changes.
If not all, most of compiler generated branches are excluded by comparing source offsets with method IL offsets.

@sharwell
OpenCover.Reports.zip
OpenCover.4.6.166.Reports.zip

@ddur
Copy link
Contributor

ddur commented Dec 27, 2015

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants