diff --git a/Documentation/Changelog.md b/Documentation/Changelog.md index 56d1536..d8d3fe3 100644 --- a/Documentation/Changelog.md +++ b/Documentation/Changelog.md @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Fixed +-Fix branch coverage issue for il switch [#1177](https://github.com/coverlet-coverage/coverlet/issues/1177) +-Fix branch coverage with using statement and several awaits[#1176](https://github.com/coverlet-coverage/coverlet/issues/1176) + ## Release date 2021-07-19 ### Packages coverlet.msbuild 3.1.0 diff --git a/src/coverlet.core/Symbols/CecilSymbolHelper.cs b/src/coverlet.core/Symbols/CecilSymbolHelper.cs index 2590972..542a17a 100644 --- a/src/coverlet.core/Symbols/CecilSymbolHelper.cs +++ b/src/coverlet.core/Symbols/CecilSymbolHelper.cs @@ -124,8 +124,8 @@ namespace Coverlet.Core.Symbols If method is a generated MoveNext we'll skip first branches (could be a switch or a series of branches) that check state machine value to jump to correct state (for instance after a true async call) Check if it's a Cond_Branch on state machine current value int num = <>1__state; - We are on branch OpCode so we need to go back by max 2 operation to reach ldloc.0 the load of "num" - Max 2 because we handle following patterns + We are on branch OpCode so we need to go back by max 3 operation to reach ldloc.0 the load of "num" + Max 3 because we handle following patterns Swich @@ -168,7 +168,7 @@ namespace Coverlet.Core.Symbols */ Instruction current = instruction.Previous; - for (int instructionBefore = 2; instructionBefore > 0 && current.Previous != null; current = current.Previous, instructionBefore--) + for (int instructionBefore = 3; instructionBefore > 0 && current.Previous != null; current = current.Previous, instructionBefore--) { if ( (current.OpCode == OpCodes.Ldloc && current.Operand is VariableDefinition vo && vo.Index == 0) || @@ -1446,4 +1446,4 @@ namespace Coverlet.Core.Symbols } } } -} \ No newline at end of file +} diff --git a/test/coverlet.core.tests/Coverage/CoverageTests.AsyncAwait.cs b/test/coverlet.core.tests/Coverage/CoverageTests.AsyncAwait.cs index 56b08fc..bd5e99a 100644 --- a/test/coverlet.core.tests/Coverage/CoverageTests.AsyncAwait.cs +++ b/test/coverlet.core.tests/Coverage/CoverageTests.AsyncAwait.cs @@ -1,4 +1,5 @@ using System.IO; +using System.Linq; using System.Threading.Tasks; using Coverlet.Core.Samples.Tests; @@ -125,5 +126,33 @@ namespace Coverlet.Core.Tests File.Delete(path); } } + + [Fact] + public void AsyncAwait_Issue_1177() + { + string path = Path.GetTempFileName(); + try + { + FunctionExecutor.Run(async (string[] pathSerialize) => + { + CoveragePrepareResult coveragePrepareResult = await TestInstrumentationHelper.Run(instance => + { + ((Task)instance.Test()).ConfigureAwait(false).GetAwaiter().GetResult(); + return Task.CompletedTask; + }, + persistPrepareResultToFile: pathSerialize[0]); + + return 0; + }, new string[] { path }); + + var document = TestInstrumentationHelper.GetCoverageResult(path).Document("Instrumentation.AsyncAwait.cs"); + document.AssertLinesCovered(BuildConfiguration.Debug, (133, 1), (134, 1), (135, 1), (136, 1), (137, 1)); + Assert.DoesNotContain(document.Branches, x => x.Key.Line == 134); + } + finally + { + File.Delete(path); + } + } } } \ No newline at end of file diff --git a/test/coverlet.core.tests/Samples/Instrumentation.AsyncAwait.cs b/test/coverlet.core.tests/Samples/Instrumentation.AsyncAwait.cs index 3270a77..c6c00d8 100644 --- a/test/coverlet.core.tests/Samples/Instrumentation.AsyncAwait.cs +++ b/test/coverlet.core.tests/Samples/Instrumentation.AsyncAwait.cs @@ -125,4 +125,16 @@ namespace Coverlet.Core.Samples.Tests Task Process(string cat); } } + + public class Issue_1177 + { + async public Task Test() + { + await Task.CompletedTask; + using var _ = new System.IO.MemoryStream(); + await Task.CompletedTask; + await Task.CompletedTask; + await Task.CompletedTask; + } + } }