Skip to content

Branch coverage Issue - async await #1177

Closed
@g0dm0d3

Description

Hi again)
Code:

namespace CoverletAsync
{
    public class MyService
    {
        public async Task<byte[]> GetBytes(Func<Task<bool>> process, Func<Task<MemoryStream>> getStream, Func<ISession> getSession, Func<Stream, ISession, Task<byte[]>> doWithStream)
        {
            if (!await process())
            {
                return Array.Empty<byte>();
            }

            using var session = getSession();
            await using var stream = await getStream();
            return await doWithStream(stream, session);
        }

        public interface ISession : IDisposable
        {
        }
    }
}

Test:

namespace CoverletAsync.Tests
{
    public class Tests
    {
        [Test]
        public async Task SomeMethodEmpty()
        {
            await using var memoryStream = new MemoryStream();
            var actual = await new MyService().GetBytes(() => Task.FromResult(false), () => Task.FromResult(memoryStream), () => new TestSession(), (stream, session) => Task.FromResult(new byte[] { 0x01, 0x02 }));

            CollectionAssert.IsEmpty(actual);
        }

        [Test]
        public async Task SomeMethodNonEmpty()
        {
            await using var memoryStream = new MemoryStream();
            var actual = await new MyService().GetBytes(() => Task.FromResult(true), () => Task.FromResult(memoryStream), () => new TestSession(), (stream, session) => Task.FromResult(new byte[] { 0x01, 0x02 }));

            Assert.That(actual, Is.EqualTo(new byte[] { 0x01, 0x02 }));
        }

        private class TestSession : MyService.ISession
        {
            public void Dispose()
            {
            }
        }
    }
}

Expected:
Full branch coverage

Actual:
Partially covered (1 visits, 2 of 4 branches are covered)

Output:
image

Report:

<?xml version="1.0" encoding="utf-8"?>
<coverage line-rate="1" branch-rate="0.75" version="1.9" timestamp="1623166089" lines-covered="8" lines-valid="8" branches-covered="6" branches-valid="8">
  <sources>
    <source>F:\</source>
  </sources>
  <packages>
    <package name="CoverletAsync" line-rate="1" branch-rate="0.75" complexity="8">
      <classes>
        <class name="CoverletAsync.MyService/&lt;GetBytes&gt;d__0" filename="Work\experiments\CoverletAsync\CoverletAsync\MyService.cs" line-rate="1" branch-rate="0.75" complexity="8">
          <methods>
            <method name="MoveNext" signature="()" line-rate="1" branch-rate="0.75" complexity="8">
              <lines>
                <line number="10" hits="2" branch="True" condition-coverage="100% (2/2)">
                  <conditions>
                    <condition number="16" type="jump" coverage="100%" />
                  </conditions>
                </line>
                <line number="11" hits="2" branch="True" condition-coverage="100% (2/2)">
                  <conditions>
                    <condition number="146" type="jump" coverage="100%" />
                  </conditions>
                </line>
                <line number="12" hits="1" branch="False" />
                <line number="13" hits="1" branch="False" />
                <line number="16" hits="1" branch="True" condition-coverage="50% (2/4)">
                  <conditions>
                    <condition number="181" type="switch" coverage="50%" />
                  </conditions>
                </line>
                <line number="17" hits="1" branch="False" />
                <line number="18" hits="1" branch="False" />
                <line number="19" hits="2" branch="False" />
              </lines>
            </method>
          </methods>
          <lines>
            <line number="10" hits="2" branch="True" condition-coverage="100% (2/2)">
              <conditions>
                <condition number="16" type="jump" coverage="100%" />
              </conditions>
            </line>
            <line number="11" hits="2" branch="True" condition-coverage="100% (2/2)">
              <conditions>
                <condition number="146" type="jump" coverage="100%" />
              </conditions>
            </line>
            <line number="12" hits="1" branch="False" />
            <line number="13" hits="1" branch="False" />
            <line number="16" hits="1" branch="True" condition-coverage="50% (2/4)">
              <conditions>
                <condition number="181" type="switch" coverage="50%" />
              </conditions>
            </line>
            <line number="17" hits="1" branch="False" />
            <line number="18" hits="1" branch="False" />
            <line number="19" hits="2" branch="False" />
          </lines>
        </class>
      </classes>
    </package>
  </packages>
</coverage>

Run: dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura

Reproduced in .NET Core 3.1, Coverlet 3.0.3 / Coverlet 3.0.4-preview.31.g4902c245c8

Metadata

Assignees

Labels

bugSomething isn't workingtenet-coverageIssue related to possible incorrect coverage

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions