From 33affd66855d4d400bb894cf44cb0e158bbcf110 Mon Sep 17 00:00:00 2001 From: Bert Date: Sun, 30 Jul 2023 10:40:05 +0200 Subject: [PATCH 01/25] update documentation --- .gitignore | 4 +++- .../MSBuild/DeterministicBuild/HowTo.md | 18 +++++++++--------- .../XUnitTestProject1/XUnitTestProject1.csproj | 12 ++++++------ .../XUnitTestProject1/XUnitTestProject1.csproj | 12 ++++++------ .../XUnitTestProject2/XUnitTestProject2.csproj | 12 ++++++------ .../XUnitTestProject3/XUnitTestProject3.csproj | 12 ++++++------ .../VSTest/DeterministicBuild/HowTo.md | 14 +++++++------- README.md | 2 +- .../DeterministicBuild.cs | 8 ++++---- 9 files changed, 48 insertions(+), 46 deletions(-) diff --git a/.gitignore b/.gitignore index 177132965..19ba249cd 100644 --- a/.gitignore +++ b/.gitignore @@ -303,4 +303,6 @@ __pycache__/ .AssemblyAttributes DeterministicTest.props test/coverlet.integration.determisticbuild/*.txt -test/coverlet.integration.determisticbuild/runsettings \ No newline at end of file +test/coverlet.integration.determisticbuild/runsettings + +coverage.cobertura.xml diff --git a/Documentation/Examples/MSBuild/DeterministicBuild/HowTo.md b/Documentation/Examples/MSBuild/DeterministicBuild/HowTo.md index 44b9f2b1f..e3b3d3a65 100644 --- a/Documentation/Examples/MSBuild/DeterministicBuild/HowTo.md +++ b/Documentation/Examples/MSBuild/DeterministicBuild/HowTo.md @@ -37,17 +37,17 @@ Add msbuild package version generated to `"..\Documentation\Examples\MSBuild\Det - netcoreapp3.1 + net6.0 false - - - - - - + + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -65,7 +65,7 @@ Go to test project folder and run C:\git\coverlet\Documentation\Examples\MSBuild\DeterministicBuild (detbuilddocs -> origin) λ dotnet test /p:CollectCoverage=true /p:DeterministicSourcePaths=true Test run for C:\git\coverlet\Documentation\Examples\MSBuild\DeterministicBuild\XUnitTestProject1\bin\Debug\netcoreapp3.1\XUnitTestProject1.dll(.NETCoreApp,Version=v3.1) -Microsoft (R) Test Execution Command Line Tool Version 16.5.0 +Microsoft (R) Test Execution Command Line Tool Version 17.5.0 Copyright (c) Microsoft Corporation. All rights reserved. Starting test execution, please wait... @@ -98,4 +98,4 @@ You should see on output folder the coverlet source root mapping file generated. This is the confirmation that you're running coverage on deterministic build. ``` Documentation\Examples\MSBuild\DeterministicBuild\XUnitTestProject1\bin\Debug\netcoreapp3.1\CoverletSourceRootsMapping -``` \ No newline at end of file +``` diff --git a/Documentation/Examples/MSBuild/DeterministicBuild/XUnitTestProject1/XUnitTestProject1.csproj b/Documentation/Examples/MSBuild/DeterministicBuild/XUnitTestProject1/XUnitTestProject1.csproj index de3e88f32..259cc2340 100644 --- a/Documentation/Examples/MSBuild/DeterministicBuild/XUnitTestProject1/XUnitTestProject1.csproj +++ b/Documentation/Examples/MSBuild/DeterministicBuild/XUnitTestProject1/XUnitTestProject1.csproj @@ -1,15 +1,15 @@ - + - netcoreapp3.1 + net6.0 false - - - - + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Documentation/Examples/MSBuild/MergeWith/XUnitTestProject1/XUnitTestProject1.csproj b/Documentation/Examples/MSBuild/MergeWith/XUnitTestProject1/XUnitTestProject1.csproj index 76ecf3d44..e549327fa 100644 --- a/Documentation/Examples/MSBuild/MergeWith/XUnitTestProject1/XUnitTestProject1.csproj +++ b/Documentation/Examples/MSBuild/MergeWith/XUnitTestProject1/XUnitTestProject1.csproj @@ -1,18 +1,18 @@ - + - netcoreapp3.1 + net6.0 false - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - + + + diff --git a/Documentation/Examples/MSBuild/MergeWith/XUnitTestProject2/XUnitTestProject2.csproj b/Documentation/Examples/MSBuild/MergeWith/XUnitTestProject2/XUnitTestProject2.csproj index 6c938c759..be361474f 100644 --- a/Documentation/Examples/MSBuild/MergeWith/XUnitTestProject2/XUnitTestProject2.csproj +++ b/Documentation/Examples/MSBuild/MergeWith/XUnitTestProject2/XUnitTestProject2.csproj @@ -1,18 +1,18 @@ - + - netcoreapp3.1 + net6.0 false - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - + + + diff --git a/Documentation/Examples/MSBuild/MergeWith/XUnitTestProject3/XUnitTestProject3.csproj b/Documentation/Examples/MSBuild/MergeWith/XUnitTestProject3/XUnitTestProject3.csproj index d5267e6a2..c622ecd0a 100644 --- a/Documentation/Examples/MSBuild/MergeWith/XUnitTestProject3/XUnitTestProject3.csproj +++ b/Documentation/Examples/MSBuild/MergeWith/XUnitTestProject3/XUnitTestProject3.csproj @@ -1,18 +1,18 @@ - + - netcoreapp3.1 + net6.0 false - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - + + + diff --git a/Documentation/Examples/VSTest/DeterministicBuild/HowTo.md b/Documentation/Examples/VSTest/DeterministicBuild/HowTo.md index 96d94ef1b..f70361bd9 100644 --- a/Documentation/Examples/VSTest/DeterministicBuild/HowTo.md +++ b/Documentation/Examples/VSTest/DeterministicBuild/HowTo.md @@ -37,16 +37,16 @@ Add collectors package version generated to `"..\Documentation\Examples\VSTest\D - netcoreapp3.1 + net6.0 false - - - - - + + + + + @@ -79,4 +79,4 @@ You should see on output folder the coverlet source root mapping file generated. This is the confirmation that you're running coverage on deterministic build. ``` Documentation\Examples\VSTest\DeterministicBuild\XUnitTestProject1\bin\Debug\netcoreapp3.1\CoverletSourceRootsMapping_XUnitTestProject1 -``` \ No newline at end of file +``` diff --git a/README.md b/README.md index c60b9d37c..14a346410 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ See [documentation](Documentation/VSTestIntegration.md) for advanced usage. * _You need to be running .NET Core SDK v2.2.401 or newer_ * _You need to reference version 16.5.0 and above of Microsoft.NET.Test.Sdk_ ``` - + ``` ### MSBuild Integration (suffers of possible [known issue](https://github.com/coverlet-coverage/coverlet/blob/master/Documentation/KnownIssues.md#1-vstest-stops-process-execution-earlydotnet-test)) diff --git a/test/coverlet.integration.tests/DeterministicBuild.cs b/test/coverlet.integration.tests/DeterministicBuild.cs index 2607b5e8e..7affdd1d3 100644 --- a/test/coverlet.integration.tests/DeterministicBuild.cs +++ b/test/coverlet.integration.tests/DeterministicBuild.cs @@ -88,7 +88,7 @@ public void Msbuild() Assert.True(File.Exists(Path.Combine(_testProjectPath, "coverage.json"))); AssertCoverage(standardOutput); - // Process exits hang on clean seem that process doesn't close, maybe some mbuild node reuse? btw manually tested + // Process exits hang on clean seem that process doesn't close, maybe some msbuild node reuse? btw manually tested // DotnetCli("clean", out standardOutput, out standardError, _fixture.TestProjectPath); // Assert.False(File.Exists(sourceRootMappingFilePath)); RunCommand("git", "clean -fdx", out _, out _, _testProjectPath); @@ -112,7 +112,7 @@ public void Msbuild_SourceLink() Assert.Contains("raw.githubusercontent.com", File.ReadAllText(Path.Combine(_testProjectPath, "coverage.json"))); AssertCoverage(standardOutput, checkDeterministicReport: false); - // Process exits hang on clean seem that process doesn't close, maybe some mbuild node reuse? btw manually tested + // Process exits hang on clean seem that process doesn't close, maybe some msbuild node reuse? btw manually tested // DotnetCli("clean", out standardOutput, out standardError, _fixture.TestProjectPath); // Assert.False(File.Exists(sourceRootMappingFilePath)); RunCommand("git", "clean -fdx", out _, out _, _testProjectPath); @@ -140,7 +140,7 @@ public void Collectors() Assert.Contains("[coverlet]Initialize CoverletInProcDataCollector", File.ReadAllText(Directory.GetFiles(_testProjectPath, "log.host.*.txt").Single())); Assert.Contains("[coverlet]Mapping resolved", dataCollectorLogContent); - // Process exits hang on clean seem that process doesn't close, maybe some mbuild node reuse? btw manually tested + // Process exits hang on clean seem that process doesn't close, maybe some msbuild node reuse? btw manually tested // DotnetCli("clean", out standardOutput, out standardError, _fixture.TestProjectPath); // Assert.False(File.Exists(sourceRootMappingFilePath)); RunCommand("git", "clean -fdx", out _, out _, _testProjectPath); @@ -169,7 +169,7 @@ public void Collectors_SourceLink() Assert.Contains("[coverlet]Initialize CoverletInProcDataCollector", File.ReadAllText(Directory.GetFiles(_testProjectPath, "log.host.*.txt").Single())); Assert.Contains("[coverlet]Mapping resolved", dataCollectorLogContent); - // Process exits hang on clean seem that process doesn't close, maybe some mbuild node reuse? btw manually tested + // Process exits hang on clean seem that process doesn't close, maybe some msbuild node reuse? btw manually tested // DotnetCli("clean", out standardOutput, out standardError, _fixture.TestProjectPath); // Assert.False(File.Exists(sourceRootMappingFilePath)); RunCommand("git", "clean -fdx", out _, out _, _testProjectPath); From f6d0adf7882328809e1de37387b2f11e11119bb7 Mon Sep 17 00:00:00 2001 From: Bert Date: Thu, 3 Aug 2023 16:05:17 +0200 Subject: [PATCH 02/25] update nuget versions using CPM --- Directory.Build.props | 5 +- Directory.Build.targets | 28 --- Directory.Packages.props | 54 ++++++ coverlet.sln | 5 +- eng/azure-pipelines-nightly.yml | 10 +- eng/build.yml | 10 -- .../coverlet.collector.targets | 2 +- .../coverlet.collector.csproj | 6 +- src/coverlet.core/coverlet.core.csproj | 7 +- .../coverlet.msbuild.targets | 2 +- ...rlet.core.tests.samples.netstandard.csproj | 2 +- .../Helpers/InstrumentationHelperTests.cs | 4 +- .../Instrumentation/InstrumenterTests.cs | 22 ++- .../coverlet.core.tests.csproj | 6 +- ...verlet.integration.determisticbuild.csproj | 4 +- .../coverlet.integration.template.csproj | 5 +- test/coverlet.integration.tests/DotnetTool.cs | 160 +++++++++--------- .../coverlet.integration.tests.csproj | 11 +- ...et.tests.projectsample.netframework.csproj | 2 +- .../coverlet.tests.remoteexecutor.csproj | 2 +- .../coverlet.tests.xunit.extensions.csproj | 3 +- 21 files changed, 183 insertions(+), 167 deletions(-) create mode 100644 Directory.Packages.props rename src/coverlet.collector/build/{netstandard1.0 => netstandard2.0}/coverlet.collector.targets (98%) diff --git a/Directory.Build.props b/Directory.Build.props index 7a716a812..9373b11bf 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -14,6 +14,7 @@ true preview $(NoWarn);NU5105;CS1591 + true https://api.nuget.org/v3/index.json; @@ -24,8 +25,4 @@ true - - - - diff --git a/Directory.Build.targets b/Directory.Build.targets index aea1e02e7..a2859274b 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -1,32 +1,4 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Directory.Packages.props b/Directory.Packages.props new file mode 100644 index 000000000..e43c180b7 --- /dev/null +++ b/Directory.Packages.props @@ -0,0 +1,54 @@ + + + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/coverlet.sln b/coverlet.sln index 311b59387..6811c5e2a 100644 --- a/coverlet.sln +++ b/coverlet.sln @@ -34,6 +34,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution DeterministicBuild.targets = DeterministicBuild.targets Directory.Build.props = Directory.Build.props Directory.Build.targets = Directory.Build.targets + Directory.Packages.props = Directory.Packages.props global.json = global.json EndProjectSection EndProject @@ -65,9 +66,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "coverlet.tests.projectsampl EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "coverlet.tests.projectsample.wpf6", "test\coverlet.tests.projectsample.wpf6\coverlet.tests.projectsample.wpf6.csproj", "{988A5FF0-4326-4F5B-9F05-CB165543A555}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "coverlet.tests.projectsample.aspmvcrazor", "test\coverlet.tests.projectsample.aspmvcrazor\coverlet.tests.projectsample.aspmvcrazor.csproj", "{6ACF69B1-C01F-44A4-8F8E-2501884238D4}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "coverlet.tests.projectsample.aspmvcrazor", "test\coverlet.tests.projectsample.aspmvcrazor\coverlet.tests.projectsample.aspmvcrazor.csproj", "{6ACF69B1-C01F-44A4-8F8E-2501884238D4}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "coverlet.tests.projectsample.aspmvcrazor.tests", "test\coverlet.tests.projectsample.aspmvcrazor.tests\coverlet.tests.projectsample.aspmvcrazor.tests.csproj", "{F508CCDD-5BC8-4AB6-97B3-D37498813C41}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "coverlet.tests.projectsample.aspmvcrazor.tests", "test\coverlet.tests.projectsample.aspmvcrazor.tests\coverlet.tests.projectsample.aspmvcrazor.tests.csproj", "{F508CCDD-5BC8-4AB6-97B3-D37498813C41}" ProjectSection(ProjectDependencies) = postProject {31084026-D563-4B91-BE71-174C4270CCF4} = {31084026-D563-4B91-BE71-174C4270CCF4} {6ACF69B1-C01F-44A4-8F8E-2501884238D4} = {6ACF69B1-C01F-44A4-8F8E-2501884238D4} diff --git a/eng/azure-pipelines-nightly.yml b/eng/azure-pipelines-nightly.yml index 502f6065a..bb542fc5f 100644 --- a/eng/azure-pipelines-nightly.yml +++ b/eng/azure-pipelines-nightly.yml @@ -1,16 +1,16 @@ pool: - vmImage: 'windows-2019' + vmImage: 'windows-latest' steps: - task: UseDotNet@2 inputs: - version: 3.1.404 - displayName: Install .NET Core SDK 3.1.404 + version: 6.0.408 + displayName: Install .NET Core SDK 6.0.408 - task: UseDotNet@2 inputs: - version: 5.0.401 - displayName: Install .NET Core SDK 5.0.401 + version: 7.0.203 + displayName: Install .NET Core SDK 7.0.203 - task: UseDotNet@2 inputs: diff --git a/eng/build.yml b/eng/build.yml index e4db0b0a6..0932e5d02 100644 --- a/eng/build.yml +++ b/eng/build.yml @@ -1,14 +1,4 @@ steps: -- task: UseDotNet@2 - inputs: - version: 3.1.404 - displayName: Install .NET Core SDK 3.1.404 - -- task: UseDotNet@2 - inputs: - version: 5.0.401 - displayName: Install .NET Core SDK 5.0.401 - - task: UseDotNet@2 inputs: version: 6.0.408 diff --git a/src/coverlet.collector/build/netstandard1.0/coverlet.collector.targets b/src/coverlet.collector/build/netstandard2.0/coverlet.collector.targets similarity index 98% rename from src/coverlet.collector/build/netstandard1.0/coverlet.collector.targets rename to src/coverlet.collector/build/netstandard2.0/coverlet.collector.targets index 7bd7b28e7..8c189b6ab 100644 --- a/src/coverlet.collector/build/netstandard1.0/coverlet.collector.targets +++ b/src/coverlet.collector/build/netstandard2.0/coverlet.collector.targets @@ -26,7 +26,7 @@ WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and <_CoverletSdkNETCoreSdkVersion>$(NETCoreSdkVersion) <_CoverletSdkNETCoreSdkVersion Condition="$(_CoverletSdkNETCoreSdkVersion.Contains('-'))">$(_CoverletSdkNETCoreSdkVersion.Split('-')[0]) - <_CoverletSdkMinVersionWithDependencyTarget>3.1.300 + <_CoverletSdkMinVersionWithDependencyTarget>6.0.100 <_CoverletSourceRootTargetName>CoverletGetPathMap <_CoverletSourceRootTargetName Condition="'$([System.Version]::Parse($(_CoverletSdkNETCoreSdkVersion)).CompareTo($([System.Version]::Parse($(_CoverletSdkMinVersionWithDependencyTarget)))))' >= '0' ">InitializeSourceRootMappedPaths diff --git a/src/coverlet.collector/coverlet.collector.csproj b/src/coverlet.collector/coverlet.collector.csproj index bdae19ae6..0f64db543 100644 --- a/src/coverlet.collector/coverlet.collector.csproj +++ b/src/coverlet.collector/coverlet.collector.csproj @@ -79,9 +79,9 @@ - - - + + + diff --git a/src/coverlet.core/coverlet.core.csproj b/src/coverlet.core/coverlet.core.csproj index 34b6b5777..2a84b0b92 100644 --- a/src/coverlet.core/coverlet.core.csproj +++ b/src/coverlet.core/coverlet.core.csproj @@ -7,12 +7,13 @@ - - - + + + + diff --git a/src/coverlet.msbuild.tasks/coverlet.msbuild.targets b/src/coverlet.msbuild.tasks/coverlet.msbuild.targets index ed288de59..6a12b2fc3 100644 --- a/src/coverlet.msbuild.tasks/coverlet.msbuild.targets +++ b/src/coverlet.msbuild.tasks/coverlet.msbuild.targets @@ -6,7 +6,7 @@ <_CoverletSdkNETCoreSdkVersion>$(NETCoreSdkVersion) <_CoverletSdkNETCoreSdkVersion Condition="$(_CoverletSdkNETCoreSdkVersion.Contains('-'))">$(_CoverletSdkNETCoreSdkVersion.Split('-')[0]) - <_CoverletSdkMinVersionWithDependencyTarget>3.1.300 + <_CoverletSdkMinVersionWithDependencyTarget>6.0.100 <_CoverletSourceRootTargetName>CoverletGetPathMap <_CoverletSourceRootTargetName Condition="'$([System.Version]::Parse($(_CoverletSdkNETCoreSdkVersion)).CompareTo($([System.Version]::Parse($(_CoverletSdkMinVersionWithDependencyTarget)))))' >= '0' ">InitializeSourceRootMappedPaths diff --git a/test/coverlet.core.tests.samples.netstandard/coverlet.core.tests.samples.netstandard.csproj b/test/coverlet.core.tests.samples.netstandard/coverlet.core.tests.samples.netstandard.csproj index 783e0d0c3..9f753d759 100644 --- a/test/coverlet.core.tests.samples.netstandard/coverlet.core.tests.samples.netstandard.csproj +++ b/test/coverlet.core.tests.samples.netstandard/coverlet.core.tests.samples.netstandard.csproj @@ -6,7 +6,7 @@ - + diff --git a/test/coverlet.core.tests/Helpers/InstrumentationHelperTests.cs b/test/coverlet.core.tests/Helpers/InstrumentationHelperTests.cs index 71d88bfb8..3ea04b5b3 100644 --- a/test/coverlet.core.tests/Helpers/InstrumentationHelperTests.cs +++ b/test/coverlet.core.tests/Helpers/InstrumentationHelperTests.cs @@ -36,7 +36,7 @@ public void TestGetDependenciesWithTestAssembly() [Fact] public void EmbeddedPortablePDPHasLocalSource_NoDocumentsExist_ReturnsFalse() { - var fileSystem = new Mock {CallBase = true}; + var fileSystem = new Mock { CallBase = true }; fileSystem.Setup(x => x.Exists(It.IsAny())).Returns(false); var instrumentationHelper = @@ -70,7 +70,7 @@ public void EmbeddedPortablePDPHasLocalSource_FirstDocumentDoesNotExist_ReturnsE var instrumentationHelper = new InstrumentationHelper(new ProcessExitHandler(), new RetryHelper(), fileSystem.Object, new Mock().Object, new SourceRootTranslator(typeof(InstrumentationHelperTests).Assembly.Location, new Mock().Object, new FileSystem(), new AssemblyAdapter())); - Assert.Equal(result, instrumentationHelper.PortablePdbHasLocalSource(typeof(InstrumentationHelperTests).Assembly.Location, (AssemblySearchType) assemblySearchType)); + Assert.Equal(result, instrumentationHelper.PortablePdbHasLocalSource(typeof(InstrumentationHelperTests).Assembly.Location, (AssemblySearchType)assemblySearchType)); } [Fact] diff --git a/test/coverlet.core.tests/Instrumentation/InstrumenterTests.cs b/test/coverlet.core.tests/Instrumentation/InstrumenterTests.cs index ef5065f55..29605998b 100644 --- a/test/coverlet.core.tests/Instrumentation/InstrumenterTests.cs +++ b/test/coverlet.core.tests/Instrumentation/InstrumenterTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) Toni Solarin-Sodara +// Copyright (c) Toni Solarin-Sodara // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; @@ -7,20 +7,18 @@ using System.Linq; using System.Reflection; using System.Runtime.InteropServices; -using Coverlet.Core.Helpers; using Coverlet.Core.Abstractions; +using Coverlet.Core.Helpers; using Coverlet.Core.Samples.Tests; using Coverlet.Core.Symbols; -using Coverlet.Tests.Xunit.Extensions; +using Coverlet.Core.Tests; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Emit; +using Microsoft.VisualStudio.TestPlatform; using Mono.Cecil; using Moq; using Xunit; -using Microsoft.Extensions.DependencyModel; -using Microsoft.VisualStudio.TestPlatform; -using Coverlet.Core.Tests; namespace Coverlet.Core.Instrumentation.Tests { @@ -514,7 +512,7 @@ public void CanInstrumentFSharpAssemblyWithAnonymousRecord() var instrumenter = new Instrumenter(sample, "_coverlet_tests_projectsample_fsharp", new CoverageParameters(), loggerMock.Object, instrumentationHelper, new FileSystem(), new SourceRootTranslator(Assembly.GetExecutingAssembly().Location, loggerMock.Object, new FileSystem(), new AssemblyAdapter()), new CecilSymbolHelper()); - + Assert.True(instrumentationHelper.HasPdb(sample, out bool embedded)); Assert.False(embedded); Assert.True(instrumenter.CanInstrument()); @@ -528,7 +526,7 @@ public void CanInstrument_AssemblySearchTypeNone_ReturnsTrue() bool embeddedPdb; instrumentationHelper.Setup(x => x.HasPdb(It.IsAny(), out embeddedPdb)).Returns(true); - var instrumenter = new Instrumenter(It.IsAny(), It.IsAny(), new CoverageParameters{ExcludeAssembliesWithoutSources = "None"}, + var instrumenter = new Instrumenter(It.IsAny(), It.IsAny(), new CoverageParameters { ExcludeAssembliesWithoutSources = "None" }, loggerMock.Object, instrumentationHelper.Object, new Mock().Object, new Mock().Object, new CecilSymbolHelper()); Assert.True(instrumenter.CanInstrument()); @@ -551,10 +549,10 @@ string EmitAssemblyToInstrument(string outputFolder) namespace coverlet.tests.projectsample.excludedbyattribute{{ public class SampleClass {{ - public int SampleMethod() - {{ - return new System.Random().Next(); - }} + public int SampleMethod() + {{ + return new System.Random().Next(); + }} }} }} diff --git a/test/coverlet.core.tests/coverlet.core.tests.csproj b/test/coverlet.core.tests/coverlet.core.tests.csproj index a882b8e90..6e365070e 100644 --- a/test/coverlet.core.tests/coverlet.core.tests.csproj +++ b/test/coverlet.core.tests/coverlet.core.tests.csproj @@ -35,11 +35,11 @@ - + - + - + diff --git a/test/coverlet.integration.determisticbuild/coverlet.integration.determisticbuild.csproj b/test/coverlet.integration.determisticbuild/coverlet.integration.determisticbuild.csproj index b79d89433..8aca96c96 100644 --- a/test/coverlet.integration.determisticbuild/coverlet.integration.determisticbuild.csproj +++ b/test/coverlet.integration.determisticbuild/coverlet.integration.determisticbuild.csproj @@ -13,11 +13,11 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/test/coverlet.integration.template/coverlet.integration.template.csproj b/test/coverlet.integration.template/coverlet.integration.template.csproj index d1639d96f..32b03ab45 100644 --- a/test/coverlet.integration.template/coverlet.integration.template.csproj +++ b/test/coverlet.integration.template/coverlet.integration.template.csproj @@ -7,11 +7,12 @@ false Exe false + false - - + + diff --git a/test/coverlet.integration.tests/DotnetTool.cs b/test/coverlet.integration.tests/DotnetTool.cs index 8c87e33da..d2fd80fdf 100644 --- a/test/coverlet.integration.tests/DotnetTool.cs +++ b/test/coverlet.integration.tests/DotnetTool.cs @@ -1,97 +1,97 @@ // Copyright (c) Toni Solarin-Sodara // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using Coverlet.Tests.Xunit.Extensions; using System.IO; using System.Linq; +using Coverlet.Tests.Xunit.Extensions; using Xunit; namespace Coverlet.Integration.Tests { - public class DotnetGlobalTools : BaseTest + public class DotnetGlobalTools : BaseTest + { + private string InstallTool(string projectPath) { - private string InstallTool(string projectPath) - { - _ = DotnetCli($"tool install coverlet.console --version {GetPackageVersion("*console*.nupkg")} --tool-path \"{Path.Combine(projectPath, "coverletTool")}\"", out string standardOutput, out _, projectPath); - Assert.Contains("was successfully installed.", standardOutput); - return Path.Combine(projectPath, "coverletTool", "coverlet"); - } + _ = DotnetCli($"tool install coverlet.console --version {GetPackageVersion("*console*.nupkg")} --tool-path \"{Path.Combine(projectPath, "coverletTool")}\"", out string standardOutput, out _, projectPath); + Assert.Contains("was successfully installed.", standardOutput); + return Path.Combine(projectPath, "coverletTool", "coverlet"); + } - [Fact] - public void DotnetTool() - { - using ClonedTemplateProject clonedTemplateProject = CloneTemplateProject(); - UpdateNugeConfigtWithLocalPackageFolder(clonedTemplateProject.ProjectRootPath!); - string coverletToolCommandPath = InstallTool(clonedTemplateProject.ProjectRootPath!); - DotnetCli($"build {clonedTemplateProject.ProjectRootPath}", out string standardOutput, out string standardError); - string publishedTestFile = clonedTemplateProject.GetFiles("*" + ClonedTemplateProject.AssemblyName + ".dll").Single(f => !f.Contains("obj") && !f.Contains("ref")); - RunCommand(coverletToolCommandPath, $"\"{publishedTestFile}\" --target \"dotnet\" --targetargs \"test {Path.Combine(clonedTemplateProject.ProjectRootPath, ClonedTemplateProject.ProjectFileName)} --no-build\" --include-test-assembly --output \"{clonedTemplateProject.ProjectRootPath}\"{Path.DirectorySeparatorChar}", out standardOutput, out standardError); - Assert.Contains("Passed!", standardOutput); - AssertCoverage(clonedTemplateProject, standardOutput: standardOutput); - } + [Fact] + public void DotnetTool() + { + using ClonedTemplateProject clonedTemplateProject = CloneTemplateProject(); + UpdateNugeConfigtWithLocalPackageFolder(clonedTemplateProject.ProjectRootPath!); + string coverletToolCommandPath = InstallTool(clonedTemplateProject.ProjectRootPath!); + DotnetCli($"build {clonedTemplateProject.ProjectRootPath}", out string standardOutput, out string standardError); + string publishedTestFile = clonedTemplateProject.GetFiles("*" + ClonedTemplateProject.AssemblyName + ".dll").Single(f => !f.Contains("obj") && !f.Contains("ref")); + RunCommand(coverletToolCommandPath, $"\"{publishedTestFile}\" --target \"dotnet\" --targetargs \"test {Path.Combine(clonedTemplateProject.ProjectRootPath, ClonedTemplateProject.ProjectFileName)} --no-build\" --include-test-assembly --output \"{clonedTemplateProject.ProjectRootPath}\"{Path.DirectorySeparatorChar}", out standardOutput, out standardError); + Assert.Contains("Passed!", standardOutput); + AssertCoverage(clonedTemplateProject, standardOutput: standardOutput); + } - [Fact] - public void StandAlone() - { - using ClonedTemplateProject clonedTemplateProject = CloneTemplateProject(); - UpdateNugeConfigtWithLocalPackageFolder(clonedTemplateProject.ProjectRootPath!); - string coverletToolCommandPath = InstallTool(clonedTemplateProject.ProjectRootPath!); - DotnetCli($"build {clonedTemplateProject.ProjectRootPath}", out string standardOutput, out string standardError); - string publishedTestFile = clonedTemplateProject.GetFiles("*" + ClonedTemplateProject.AssemblyName + ".dll").Single(f => !f.Contains("obj") && !f.Contains("ref")); - RunCommand(coverletToolCommandPath, $"\"{Path.GetDirectoryName(publishedTestFile)}\" --target \"dotnet\" --targetargs \"{publishedTestFile}\" --output \"{clonedTemplateProject.ProjectRootPath}\"{Path.DirectorySeparatorChar}", out standardOutput, out standardError); - Assert.Contains("Hello World!", standardOutput); - AssertCoverage(clonedTemplateProject, standardOutput: standardOutput); - } + [Fact] + public void StandAlone() + { + using ClonedTemplateProject clonedTemplateProject = CloneTemplateProject(); + UpdateNugeConfigtWithLocalPackageFolder(clonedTemplateProject.ProjectRootPath!); + string coverletToolCommandPath = InstallTool(clonedTemplateProject.ProjectRootPath!); + DotnetCli($"build {clonedTemplateProject.ProjectRootPath}", out string standardOutput, out string standardError); + string publishedTestFile = clonedTemplateProject.GetFiles("*" + ClonedTemplateProject.AssemblyName + ".dll").Single(f => !f.Contains("obj") && !f.Contains("ref")); + RunCommand(coverletToolCommandPath, $"\"{Path.GetDirectoryName(publishedTestFile)}\" --target \"dotnet\" --targetargs \"{publishedTestFile}\" --output \"{clonedTemplateProject.ProjectRootPath}\"{Path.DirectorySeparatorChar}", out standardOutput, out standardError); + Assert.Contains("Hello World!", standardOutput); + AssertCoverage(clonedTemplateProject, standardOutput: standardOutput); + } - [ConditionalFact] - [SkipOnOS(OS.Linux)] - [SkipOnOS(OS.MacOS)] - public void StandAloneThreshold() - { - using ClonedTemplateProject clonedTemplateProject = CloneTemplateProject(); - UpdateNugeConfigtWithLocalPackageFolder(clonedTemplateProject.ProjectRootPath!); - string coverletToolCommandPath = InstallTool(clonedTemplateProject.ProjectRootPath!); - DotnetCli($"build {clonedTemplateProject.ProjectRootPath}", out string standardOutput, out string standardError); - string publishedTestFile = clonedTemplateProject.GetFiles("*" + ClonedTemplateProject.AssemblyName + ".dll").Single(f => !f.Contains("obj") && !f.Contains("ref")); - Assert.False( RunCommand(coverletToolCommandPath, $"\"{Path.GetDirectoryName(publishedTestFile)}\" --target \"dotnet\" --targetargs \"{publishedTestFile}\" --threshold 80 --output \"{clonedTemplateProject.ProjectRootPath}\"\\", out standardOutput, out standardError)); - Assert.Contains("Hello World!", standardOutput); - AssertCoverage(clonedTemplateProject, standardOutput: standardOutput); - Assert.Contains("The minimum line coverage is below the specified 80", standardOutput); - Assert.Contains("The minimum method coverage is below the specified 80", standardOutput); - } + [ConditionalFact] + [SkipOnOS(OS.Linux)] + [SkipOnOS(OS.MacOS)] + public void StandAloneThreshold() + { + using ClonedTemplateProject clonedTemplateProject = CloneTemplateProject(); + UpdateNugeConfigtWithLocalPackageFolder(clonedTemplateProject.ProjectRootPath!); + string coverletToolCommandPath = InstallTool(clonedTemplateProject.ProjectRootPath!); + DotnetCli($"build {clonedTemplateProject.ProjectRootPath}", out string standardOutput, out string standardError); + string publishedTestFile = clonedTemplateProject.GetFiles("*" + ClonedTemplateProject.AssemblyName + ".dll").Single(f => !f.Contains("obj") && !f.Contains("ref")); + Assert.False(RunCommand(coverletToolCommandPath, $"\"{Path.GetDirectoryName(publishedTestFile)}\" --target \"dotnet\" --targetargs \"{publishedTestFile}\" --threshold 80 --output \"{clonedTemplateProject.ProjectRootPath}\"\\", out standardOutput, out standardError)); + Assert.Contains("Hello World!", standardOutput); + AssertCoverage(clonedTemplateProject, standardOutput: standardOutput); + Assert.Contains("The minimum line coverage is below the specified 80", standardOutput); + Assert.Contains("The minimum method coverage is below the specified 80", standardOutput); + } - [ConditionalFact] - [SkipOnOS(OS.Linux)] - [SkipOnOS(OS.MacOS)] - public void StandAloneThresholdLine() - { - using ClonedTemplateProject clonedTemplateProject = CloneTemplateProject(); - UpdateNugeConfigtWithLocalPackageFolder(clonedTemplateProject.ProjectRootPath!); - string coverletToolCommandPath = InstallTool(clonedTemplateProject.ProjectRootPath!); - DotnetCli($"build {clonedTemplateProject.ProjectRootPath}", out string standardOutput, out string standardError); - string publishedTestFile = clonedTemplateProject.GetFiles("*" + ClonedTemplateProject.AssemblyName + ".dll").Single(f => !f.Contains("obj") && !f.Contains("ref")); - Assert.False(RunCommand(coverletToolCommandPath, $"\"{Path.GetDirectoryName(publishedTestFile)}\" --target \"dotnet\" --targetargs \"{publishedTestFile}\" --threshold 80 --threshold-type line --output \"{clonedTemplateProject.ProjectRootPath}\"\\", out standardOutput, out standardError)); - Assert.Contains("Hello World!", standardOutput); - AssertCoverage(clonedTemplateProject, standardOutput: standardOutput); - Assert.Contains("The minimum line coverage is below the specified 80", standardOutput); - Assert.DoesNotContain("The minimum method coverage is below the specified 80", standardOutput); - } + [ConditionalFact] + [SkipOnOS(OS.Linux)] + [SkipOnOS(OS.MacOS)] + public void StandAloneThresholdLine() + { + using ClonedTemplateProject clonedTemplateProject = CloneTemplateProject(); + UpdateNugeConfigtWithLocalPackageFolder(clonedTemplateProject.ProjectRootPath!); + string coverletToolCommandPath = InstallTool(clonedTemplateProject.ProjectRootPath!); + DotnetCli($"build {clonedTemplateProject.ProjectRootPath}", out string standardOutput, out string standardError); + string publishedTestFile = clonedTemplateProject.GetFiles("*" + ClonedTemplateProject.AssemblyName + ".dll").Single(f => !f.Contains("obj") && !f.Contains("ref")); + Assert.False(RunCommand(coverletToolCommandPath, $"\"{Path.GetDirectoryName(publishedTestFile)}\" --target \"dotnet\" --targetargs \"{publishedTestFile}\" --threshold 80 --threshold-type line --output \"{clonedTemplateProject.ProjectRootPath}\"\\", out standardOutput, out standardError)); + Assert.Contains("Hello World!", standardOutput); + AssertCoverage(clonedTemplateProject, standardOutput: standardOutput); + Assert.Contains("The minimum line coverage is below the specified 80", standardOutput); + Assert.DoesNotContain("The minimum method coverage is below the specified 80", standardOutput); + } - [ConditionalFact] - [SkipOnOS(OS.Linux)] - [SkipOnOS(OS.MacOS)] - public void StandAloneThresholdLineAndMethod () - { - using ClonedTemplateProject clonedTemplateProject = CloneTemplateProject(); - UpdateNugeConfigtWithLocalPackageFolder(clonedTemplateProject.ProjectRootPath!); - string coverletToolCommandPath = InstallTool(clonedTemplateProject.ProjectRootPath!); - DotnetCli($"build {clonedTemplateProject.ProjectRootPath}", out string standardOutput, out string standardError); - string publishedTestFile = clonedTemplateProject.GetFiles("*" + ClonedTemplateProject.AssemblyName + ".dll").Single(f => !f.Contains("obj") && !f.Contains("ref")); - Assert.False(RunCommand(coverletToolCommandPath, $"\"{Path.GetDirectoryName(publishedTestFile)}\" --target \"dotnet\" --targetargs \"{publishedTestFile}\" --threshold 80 --threshold-type line --threshold-type method --output \"{clonedTemplateProject.ProjectRootPath}\"\\", out standardOutput, out standardError)); - Assert.Contains("Hello World!", standardOutput); - AssertCoverage(clonedTemplateProject, standardOutput: standardOutput); - Assert.Contains("The minimum line coverage is below the specified 80", standardOutput); - Assert.Contains("The minimum method coverage is below the specified 80", standardOutput); - } + [ConditionalFact] + [SkipOnOS(OS.Linux)] + [SkipOnOS(OS.MacOS)] + public void StandAloneThresholdLineAndMethod() + { + using ClonedTemplateProject clonedTemplateProject = CloneTemplateProject(); + UpdateNugeConfigtWithLocalPackageFolder(clonedTemplateProject.ProjectRootPath!); + string coverletToolCommandPath = InstallTool(clonedTemplateProject.ProjectRootPath!); + DotnetCli($"build {clonedTemplateProject.ProjectRootPath}", out string standardOutput, out string standardError); + string publishedTestFile = clonedTemplateProject.GetFiles("*" + ClonedTemplateProject.AssemblyName + ".dll").Single(f => !f.Contains("obj") && !f.Contains("ref")); + Assert.False(RunCommand(coverletToolCommandPath, $"\"{Path.GetDirectoryName(publishedTestFile)}\" --target \"dotnet\" --targetargs \"{publishedTestFile}\" --threshold 80 --threshold-type line --threshold-type method --output \"{clonedTemplateProject.ProjectRootPath}\"\\", out standardOutput, out standardError)); + Assert.Contains("Hello World!", standardOutput); + AssertCoverage(clonedTemplateProject, standardOutput: standardOutput); + Assert.Contains("The minimum line coverage is below the specified 80", standardOutput); + Assert.Contains("The minimum method coverage is below the specified 80", standardOutput); } + } } diff --git a/test/coverlet.integration.tests/coverlet.integration.tests.csproj b/test/coverlet.integration.tests/coverlet.integration.tests.csproj index 2f0b3bacc..cda721792 100644 --- a/test/coverlet.integration.tests/coverlet.integration.tests.csproj +++ b/test/coverlet.integration.tests/coverlet.integration.tests.csproj @@ -4,14 +4,15 @@ net6.0 false enable + false - - - - - + + + + + diff --git a/test/coverlet.tests.projectsample.netframework/coverlet.tests.projectsample.netframework.csproj b/test/coverlet.tests.projectsample.netframework/coverlet.tests.projectsample.netframework.csproj index 822b965de..9a97434b9 100644 --- a/test/coverlet.tests.projectsample.netframework/coverlet.tests.projectsample.netframework.csproj +++ b/test/coverlet.tests.projectsample.netframework/coverlet.tests.projectsample.netframework.csproj @@ -7,7 +7,7 @@ - + all diff --git a/test/coverlet.tests.remoteexecutor/coverlet.tests.remoteexecutor.csproj b/test/coverlet.tests.remoteexecutor/coverlet.tests.remoteexecutor.csproj index 5167d6c7e..42c7c75d4 100644 --- a/test/coverlet.tests.remoteexecutor/coverlet.tests.remoteexecutor.csproj +++ b/test/coverlet.tests.remoteexecutor/coverlet.tests.remoteexecutor.csproj @@ -2,7 +2,7 @@ Exe - netcoreapp3.1 + net6.0 Coverlet.Tests.RemoteExecutor false false diff --git a/test/coverlet.tests.xunit.extensions/coverlet.tests.xunit.extensions.csproj b/test/coverlet.tests.xunit.extensions/coverlet.tests.xunit.extensions.csproj index 3003d7511..71b02548a 100644 --- a/test/coverlet.tests.xunit.extensions/coverlet.tests.xunit.extensions.csproj +++ b/test/coverlet.tests.xunit.extensions/coverlet.tests.xunit.extensions.csproj @@ -4,9 +4,10 @@ netstandard2.0 false false + false - + From e4e5bd053ca7fb48302284506ba6167782ccfb02 Mon Sep 17 00:00:00 2001 From: Bert Date: Sat, 5 Aug 2023 07:20:58 +0200 Subject: [PATCH 03/25] restart CI From 16f82a017c227e4a80e84471f50849348d23abc0 Mon Sep 17 00:00:00 2001 From: Bert Date: Sat, 5 Aug 2023 11:33:48 +0200 Subject: [PATCH 04/25] update SDK version (Collector.cs) --- .../MSBuild/DeterministicBuild/HowTo.md | 8 +- .../VSTest/DeterministicBuild/HowTo.md | 6 +- .../XUnitTestProject1.csproj | 8 +- .../XUnitTestProject1.csproj | 10 +- test/coverlet.integration.tests/Collectors.cs | 210 +++++++++--------- 5 files changed, 121 insertions(+), 121 deletions(-) diff --git a/Documentation/Examples/MSBuild/DeterministicBuild/HowTo.md b/Documentation/Examples/MSBuild/DeterministicBuild/HowTo.md index e3b3d3a65..d9e37a2ce 100644 --- a/Documentation/Examples/MSBuild/DeterministicBuild/HowTo.md +++ b/Documentation/Examples/MSBuild/DeterministicBuild/HowTo.md @@ -1,4 +1,4 @@ -To run test we need to generates packages to reference in on test project. +To run test we need to generates packages to reference in on test project. Run from repo root ``` C:\git\coverlet @@ -64,7 +64,7 @@ Go to test project folder and run ``` C:\git\coverlet\Documentation\Examples\MSBuild\DeterministicBuild (detbuilddocs -> origin) λ dotnet test /p:CollectCoverage=true /p:DeterministicSourcePaths=true -Test run for C:\git\coverlet\Documentation\Examples\MSBuild\DeterministicBuild\XUnitTestProject1\bin\Debug\netcoreapp3.1\XUnitTestProject1.dll(.NETCoreApp,Version=v3.1) +Test run for C:\git\coverlet\Documentation\Examples\MSBuild\DeterministicBuild\XUnitTestProject1\bin\Debug\net6.0\XUnitTestProject1.dll(.NETCoreApp,Version=v6.0) Microsoft (R) Test Execution Command Line Tool Version 17.5.0 Copyright (c) Microsoft Corporation. All rights reserved. @@ -94,8 +94,8 @@ Calculating coverage result... | Average | 100% | 100% | 100% | +---------+------+--------+--------+ ``` -You should see on output folder the coverlet source root mapping file generated. +You should see on output folder the coverlet source root mapping file generated. This is the confirmation that you're running coverage on deterministic build. ``` -Documentation\Examples\MSBuild\DeterministicBuild\XUnitTestProject1\bin\Debug\netcoreapp3.1\CoverletSourceRootsMapping +Documentation\Examples\MSBuild\DeterministicBuild\XUnitTestProject1\bin\Debug\net6.0\CoverletSourceRootsMapping ``` diff --git a/Documentation/Examples/VSTest/DeterministicBuild/HowTo.md b/Documentation/Examples/VSTest/DeterministicBuild/HowTo.md index f70361bd9..04760a229 100644 --- a/Documentation/Examples/VSTest/DeterministicBuild/HowTo.md +++ b/Documentation/Examples/VSTest/DeterministicBuild/HowTo.md @@ -60,8 +60,8 @@ Go to test project folder and run ``` C:\git\coverlet\Documentation\Examples\VSTest\DeterministicBuild (detbuilddocs -> origin) λ dotnet test --collect:"XPlat Code Coverage" /p:DeterministicSourcePaths=true -- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.DeterministicReport=true -Test run for C:\git\coverlet\Documentation\Examples\VSTest\DeterministicBuild\XUnitTestProject1\bin\Debug\netcoreapp3.1\XUnitTestProject1.dll(.NETCoreApp,Version=v3.1) -Microsoft (R) Test Execution Command Line Tool Version 16.5.0 +Test run for C:\git\coverlet\Documentation\Examples\VSTest\DeterministicBuild\XUnitTestProject1\bin\Debug\netcoreapp3.1\XUnitTestProject1.dll(.NETCoreApp,Version=v6.0) +Microsoft (R) Test Execution Command Line Tool Version 17.5.0 Copyright (c) Microsoft Corporation. All rights reserved. Starting test execution, please wait... @@ -78,5 +78,5 @@ Total tests: 1 You should see on output folder the coverlet source root mapping file generated. This is the confirmation that you're running coverage on deterministic build. ``` -Documentation\Examples\VSTest\DeterministicBuild\XUnitTestProject1\bin\Debug\netcoreapp3.1\CoverletSourceRootsMapping_XUnitTestProject1 +Documentation\Examples\VSTest\DeterministicBuild\XUnitTestProject1\bin\Debug\net6.0\CoverletSourceRootsMapping_XUnitTestProject1 ``` diff --git a/Documentation/Examples/VSTest/DeterministicBuild/XUnitTestProject1/XUnitTestProject1.csproj b/Documentation/Examples/VSTest/DeterministicBuild/XUnitTestProject1/XUnitTestProject1.csproj index ea3c58201..6144dfbd5 100644 --- a/Documentation/Examples/VSTest/DeterministicBuild/XUnitTestProject1/XUnitTestProject1.csproj +++ b/Documentation/Examples/VSTest/DeterministicBuild/XUnitTestProject1/XUnitTestProject1.csproj @@ -1,14 +1,14 @@  - netcoreapp3.1 + net6.0 false - - - + + + diff --git a/Documentation/Examples/VSTest/HelloWorld/XUnitTestProject1/XUnitTestProject1.csproj b/Documentation/Examples/VSTest/HelloWorld/XUnitTestProject1/XUnitTestProject1.csproj index 3000c34e8..33798c74c 100644 --- a/Documentation/Examples/VSTest/HelloWorld/XUnitTestProject1/XUnitTestProject1.csproj +++ b/Documentation/Examples/VSTest/HelloWorld/XUnitTestProject1/XUnitTestProject1.csproj @@ -1,15 +1,15 @@ - netcoreapp3.1 + net6.0 false - - - - + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/test/coverlet.integration.tests/Collectors.cs b/test/coverlet.integration.tests/Collectors.cs index 262f29d58..05d261c3b 100644 --- a/test/coverlet.integration.tests/Collectors.cs +++ b/test/coverlet.integration.tests/Collectors.cs @@ -8,120 +8,120 @@ namespace Coverlet.Integration.Tests { - public class TestSDK_16_2_0 : Collectors + public class TestSDK_17_5_0 : Collectors + { + public TestSDK_17_5_0() { - public TestSDK_16_2_0() - { - TestSDKVersion = "16.2.0"; - } - - private protected override void AssertCollectorsInjection(ClonedTemplateProject clonedTemplateProject) - { - // Check out/in process collectors injection - Assert.Contains("[coverlet]", File.ReadAllText(clonedTemplateProject.GetFiles("log.datacollector.*.txt").Single())); - - // There is a bug in this SDK version https://github.com/microsoft/vstest/pull/2221 - // in-proc coverlet.collector.dll collector with version != 1.0.0.0 won't be loaded - // Assert.Contains("[coverlet]", File.ReadAllText(clonedTemplateProject.GetFiles("log.host.*.txt").Single())); - } + TestSDKVersion = "17.5.0"; } - public class TestSDK_16_5_0 : Collectors + private protected override void AssertCollectorsInjection(ClonedTemplateProject clonedTemplateProject) { - public TestSDK_16_5_0() - { - TestSDKVersion = "16.5.0"; - } + // Check out/in process collectors injection + Assert.Contains("[coverlet]", File.ReadAllText(clonedTemplateProject.GetFiles("log.datacollector.*.txt").Single())); + + // There is a bug in this SDK version https://github.com/microsoft/vstest/pull/2221 + // in-proc coverlet.collector.dll collector with version != 1.0.0.0 won't be loaded + // Assert.Contains("[coverlet]", File.ReadAllText(clonedTemplateProject.GetFiles("log.host.*.txt").Single())); + } + } + + public class TestSDK_17_6_0 : Collectors + { + public TestSDK_17_6_0() + { + TestSDKVersion = "17.6.0"; + } + } + + public class TestSDK_Preview : Collectors + { + public TestSDK_Preview() + { + TestSDKVersion = "17.7.0-preview-23364-03"; + } + } + + public abstract class Collectors : BaseTest + { + private readonly string _buildConfiguration; + + public Collectors() + { + _buildConfiguration = GetAssemblyBuildConfiguration().ToString(); + } + + protected string? TestSDKVersion { get; set; } + + private ClonedTemplateProject PrepareTemplateProject() + { + if (TestSDKVersion is null) + { + throw new ArgumentNullException("Invalid TestSDKVersion"); + } + + ClonedTemplateProject clonedTemplateProject = CloneTemplateProject(testSDKVersion: TestSDKVersion); + UpdateNugeConfigtWithLocalPackageFolder(clonedTemplateProject.ProjectRootPath!); + AddCoverletCollectosRef(clonedTemplateProject.ProjectRootPath!); + return clonedTemplateProject; + } + + private protected virtual void AssertCollectorsInjection(ClonedTemplateProject clonedTemplateProject) + { + // Check out/in process collectors injection + Assert.Contains("[coverlet]Initializing CoverletCoverageDataCollector with configuration:", File.ReadAllText(clonedTemplateProject.GetFiles("log.datacollector.*.txt").Single())); + Assert.Contains("[coverlet]Initialize CoverletInProcDataCollector", File.ReadAllText(clonedTemplateProject.GetFiles("log.host.*.txt").Single())); + } + + [Fact] + public void TestVsTest_Test() + { + using ClonedTemplateProject clonedTemplateProject = PrepareTemplateProject(); + Assert.True(DotnetCli($"test -c {_buildConfiguration} \"{clonedTemplateProject.ProjectRootPath}\" --collect:\"XPlat Code Coverage\" --diag:{Path.Combine(clonedTemplateProject.ProjectRootPath, "log.txt")}", out string standardOutput, out string standardError, clonedTemplateProject.ProjectRootPath!), standardOutput); + // We don't have any result to check because tests and code to instrument are in same assembly so we need to pass + // IncludeTestAssembly=true we do it in other test + Assert.Contains("Passed!", standardOutput); + AssertCollectorsInjection(clonedTemplateProject); + } + + [Fact] + public void TestVsTest_Test_Settings() + { + using ClonedTemplateProject clonedTemplateProject = PrepareTemplateProject(); + string runSettingsPath = AddCollectorRunsettingsFile(clonedTemplateProject.ProjectRootPath!); + Assert.True(DotnetCli($"test -c {_buildConfiguration} \"{clonedTemplateProject.ProjectRootPath}\" --collect:\"XPlat Code Coverage\" --settings \"{runSettingsPath}\" --diag:{Path.Combine(clonedTemplateProject.ProjectRootPath, "log.txt")}", out string standardOutput, out string standardError), standardOutput); + Assert.Contains("Passed!", standardOutput); + AssertCoverage(clonedTemplateProject); + AssertCollectorsInjection(clonedTemplateProject); } - public class TestSDK_Preview : Collectors + [Fact] + public void TestVsTest_VsTest() { - public TestSDK_Preview() - { - TestSDKVersion = "16.5.0-preview-20200203-01"; - } + using ClonedTemplateProject clonedTemplateProject = PrepareTemplateProject(); + string runSettingsPath = AddCollectorRunsettingsFile(clonedTemplateProject.ProjectRootPath!); + Assert.True(DotnetCli($"publish -c {_buildConfiguration} {clonedTemplateProject.ProjectRootPath}", out string standardOutput, out string standardError), standardOutput); + string publishedTestFile = clonedTemplateProject.GetFiles("*" + ClonedTemplateProject.AssemblyName + ".dll").Single(f => f.Contains("publish")); + Assert.NotNull(publishedTestFile); + Assert.True(DotnetCli($"vstest \"{publishedTestFile}\" --collect:\"XPlat Code Coverage\" --diag:{Path.Combine(clonedTemplateProject.ProjectRootPath, "log.txt")}", out standardOutput, out standardError), standardOutput); + // We don't have any result to check because tests and code to instrument are in same assembly so we need to pass + // IncludeTestAssembly=true we do it in other test + Assert.Contains("Passed!", standardOutput); + AssertCollectorsInjection(clonedTemplateProject); } - public abstract class Collectors : BaseTest + [Fact] + public void TestVsTest_VsTest_Settings() { - private readonly string _buildConfiguration; - - public Collectors() - { - _buildConfiguration = GetAssemblyBuildConfiguration().ToString(); - } - - protected string? TestSDKVersion { get; set; } - - private ClonedTemplateProject PrepareTemplateProject() - { - if (TestSDKVersion is null) - { - throw new ArgumentNullException("Invalid TestSDKVersion"); - } - - ClonedTemplateProject clonedTemplateProject = CloneTemplateProject(testSDKVersion: TestSDKVersion); - UpdateNugeConfigtWithLocalPackageFolder(clonedTemplateProject.ProjectRootPath!); - AddCoverletCollectosRef(clonedTemplateProject.ProjectRootPath!); - return clonedTemplateProject; - } - - private protected virtual void AssertCollectorsInjection(ClonedTemplateProject clonedTemplateProject) - { - // Check out/in process collectors injection - Assert.Contains("[coverlet]Initializing CoverletCoverageDataCollector with configuration:", File.ReadAllText(clonedTemplateProject.GetFiles("log.datacollector.*.txt").Single())); - Assert.Contains("[coverlet]Initialize CoverletInProcDataCollector", File.ReadAllText(clonedTemplateProject.GetFiles("log.host.*.txt").Single())); - } - - [Fact] - public void TestVsTest_Test() - { - using ClonedTemplateProject clonedTemplateProject = PrepareTemplateProject(); - Assert.True(DotnetCli($"test -c {_buildConfiguration} \"{clonedTemplateProject.ProjectRootPath}\" --collect:\"XPlat Code Coverage\" --diag:{Path.Combine(clonedTemplateProject.ProjectRootPath, "log.txt")}", out string standardOutput, out string standardError, clonedTemplateProject.ProjectRootPath!), standardOutput); - // We don't have any result to check because tests and code to instrument are in same assembly so we need to pass - // IncludeTestAssembly=true we do it in other test - Assert.Contains("Passed!", standardOutput); - AssertCollectorsInjection(clonedTemplateProject); - } - - [Fact] - public void TestVsTest_Test_Settings() - { - using ClonedTemplateProject clonedTemplateProject = PrepareTemplateProject(); - string runSettingsPath = AddCollectorRunsettingsFile(clonedTemplateProject.ProjectRootPath!); - Assert.True(DotnetCli($"test -c {_buildConfiguration} \"{clonedTemplateProject.ProjectRootPath}\" --collect:\"XPlat Code Coverage\" --settings \"{runSettingsPath}\" --diag:{Path.Combine(clonedTemplateProject.ProjectRootPath, "log.txt")}", out string standardOutput, out string standardError), standardOutput); - Assert.Contains("Passed!", standardOutput); - AssertCoverage(clonedTemplateProject); - AssertCollectorsInjection(clonedTemplateProject); - } - - [Fact] - public void TestVsTest_VsTest() - { - using ClonedTemplateProject clonedTemplateProject = PrepareTemplateProject(); - string runSettingsPath = AddCollectorRunsettingsFile(clonedTemplateProject.ProjectRootPath!); - Assert.True(DotnetCli($"publish -c {_buildConfiguration} {clonedTemplateProject.ProjectRootPath}", out string standardOutput, out string standardError), standardOutput); - string publishedTestFile = clonedTemplateProject.GetFiles("*" + ClonedTemplateProject.AssemblyName + ".dll").Single(f => f.Contains("publish")); - Assert.NotNull(publishedTestFile); - Assert.True(DotnetCli($"vstest \"{publishedTestFile}\" --collect:\"XPlat Code Coverage\" --diag:{Path.Combine(clonedTemplateProject.ProjectRootPath, "log.txt")}", out standardOutput, out standardError), standardOutput); - // We don't have any result to check because tests and code to instrument are in same assembly so we need to pass - // IncludeTestAssembly=true we do it in other test - Assert.Contains("Passed!", standardOutput); - AssertCollectorsInjection(clonedTemplateProject); - } - - [Fact] - public void TestVsTest_VsTest_Settings() - { - using ClonedTemplateProject clonedTemplateProject = PrepareTemplateProject(); - string runSettingsPath = AddCollectorRunsettingsFile(clonedTemplateProject.ProjectRootPath!); - Assert.True(DotnetCli($"publish -c {_buildConfiguration} \"{clonedTemplateProject.ProjectRootPath}\"", out string standardOutput, out string standardError), standardOutput); - string publishedTestFile = clonedTemplateProject.GetFiles("*" + ClonedTemplateProject.AssemblyName + ".dll").Single(f => f.Contains("publish")); - Assert.NotNull(publishedTestFile); - Assert.True(DotnetCli($"vstest \"{publishedTestFile}\" --collect:\"XPlat Code Coverage\" --ResultsDirectory:\"{clonedTemplateProject.ProjectRootPath}\" /settings:\"{runSettingsPath}\" --diag:{Path.Combine(clonedTemplateProject.ProjectRootPath, "log.txt")}", out standardOutput, out standardError), standardOutput); - Assert.Contains("Passed!", standardOutput); - AssertCoverage(clonedTemplateProject); - AssertCollectorsInjection(clonedTemplateProject); - } + using ClonedTemplateProject clonedTemplateProject = PrepareTemplateProject(); + string runSettingsPath = AddCollectorRunsettingsFile(clonedTemplateProject.ProjectRootPath!); + Assert.True(DotnetCli($"publish -c {_buildConfiguration} \"{clonedTemplateProject.ProjectRootPath}\"", out string standardOutput, out string standardError), standardOutput); + string publishedTestFile = clonedTemplateProject.GetFiles("*" + ClonedTemplateProject.AssemblyName + ".dll").Single(f => f.Contains("publish")); + Assert.NotNull(publishedTestFile); + Assert.True(DotnetCli($"vstest \"{publishedTestFile}\" --collect:\"XPlat Code Coverage\" --ResultsDirectory:\"{clonedTemplateProject.ProjectRootPath}\" /settings:\"{runSettingsPath}\" --diag:{Path.Combine(clonedTemplateProject.ProjectRootPath, "log.txt")}", out standardOutput, out standardError), standardOutput); + Assert.Contains("Passed!", standardOutput); + AssertCoverage(clonedTemplateProject); + AssertCollectorsInjection(clonedTemplateProject); } + } } From 3ff04dea92a2d5e17471bfa58936539cccf0cc9d Mon Sep 17 00:00:00 2001 From: Bert Date: Sat, 5 Aug 2023 15:41:44 +0200 Subject: [PATCH 05/25] collect test result files --- eng/build.yml | 2 ++ eng/publish-coverlet-results.yml | 44 ++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 eng/publish-coverlet-results.yml diff --git a/eng/build.yml b/eng/build.yml index 0932e5d02..b6e2c2d83 100644 --- a/eng/build.yml +++ b/eng/build.yml @@ -24,3 +24,5 @@ steps: command: test arguments: -c $(BuildConfiguration) --no-build /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Include="[coverlet.collector]*%2c[coverlet.core]*%2c[coverlet.msbuild.tasks]*" /p:Exclude="[coverlet.core.tests.samples.netstandard]*%2c[coverlet.tests.xunit.extensions]*" testRunTitle: $(Agent.JobName) + +- template: publish-coverlet-results.yml diff --git a/eng/publish-coverlet-results.yml b/eng/publish-coverlet-results.yml new file mode 100644 index 000000000..0eb40bdc7 --- /dev/null +++ b/eng/publish-coverlet-results.yml @@ -0,0 +1,44 @@ +steps: +- task: Powershell@2 + displayName: Prepare coverage files to Upload + inputs: + targetType: inline + pwsh: true + script: | + New-Item -ItemType Directory "$(Build.SourcesDirectory)/artifacts/TestLogs/" + function Copy-FileKeepPath { + param ( + $filter,$FileToCopy,$des,$startIndex + ) + Get-ChildItem -Path $FileToCopy -Filter $filter -Recurse -File | ForEach-Object { + $fileName = $_.FullName + #Remove the first part to ignore from the path. + $newdes=Join-Path -Path $des -ChildPath $fileName.Substring($startIndex) + $folder=Split-Path -Path $newdes -Parent + $err=0 + + #check if folder exists" + $void=Get-Item $folder -ErrorVariable err -ErrorAction SilentlyContinue + if($err.Count -ne 0){ + #create when it doesn't + $void=New-Item -Path $folder -ItemType Directory -Force -Verbose + } + + $void=Copy-Item -Path $fileName -destination $newdes -Recurse -Container -Force -Verbose + } + } + $logfiles = "coverage.opencover.xml", "coverage.cobertura.xml", "coverage.json", "log.txt", "log.datacollector.*.txt", "log.host.*.txt" + foreach ($logfile in $logfiles ) { + Copy-FileKeepPath -FileToCopy "$(Build.SourcesDirectory)/test/coverlet.integration.tests/bin/*" -des "$(Build.SourcesDirectory)/artifacts/TestLogs/" -filter $logfile -startIndex "$(Build.SourcesDirectory)/test/coverlet.integration.tests/bin/".Length + } + + continueOnError: true + condition: always() + +- task: PublishPipelineArtifact@1 + displayName: Publish coverage logs + continueOnError: true + condition: always() + inputs: + path: artifacts/TestLogs + artifactName: TestLogs_$(Agent.Os)_$(BuildConfiguration) From a40ae62085a9cae54fe7dc0fda6565de6c89a76e Mon Sep 17 00:00:00 2001 From: Bert Date: Sat, 5 Aug 2023 16:40:37 +0200 Subject: [PATCH 06/25] enable coverage for build report --- eng/build.yml | 8 ++++- eng/publish-coverage-results.yml | 32 +++++++++++++++++++ ....yml => publish-coverlet-result-files.yml} | 0 3 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 eng/publish-coverage-results.yml rename eng/{publish-coverlet-results.yml => publish-coverlet-result-files.yml} (100%) diff --git a/eng/build.yml b/eng/build.yml index b6e2c2d83..0f36b2e92 100644 --- a/eng/build.yml +++ b/eng/build.yml @@ -25,4 +25,10 @@ steps: arguments: -c $(BuildConfiguration) --no-build /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Include="[coverlet.collector]*%2c[coverlet.core]*%2c[coverlet.msbuild.tasks]*" /p:Exclude="[coverlet.core.tests.samples.netstandard]*%2c[coverlet.tests.xunit.extensions]*" testRunTitle: $(Agent.JobName) -- template: publish-coverlet-results.yml +- template: publish-coverlet-result-files.yml + +- template: publish-coverage-results.yml + parameters: + reports: $(Build.SourcesDirectory)/**/coverage.opencover.xml + condition: and(succeeded(), eq(variables['_BuildConfig'], 'Debug')) + assemblyfilters: '-xunit*;+Coverlet.Core.*;+Coverlet.Collector.*' diff --git a/eng/publish-coverage-results.yml b/eng/publish-coverage-results.yml new file mode 100644 index 000000000..41f34a089 --- /dev/null +++ b/eng/publish-coverage-results.yml @@ -0,0 +1,32 @@ +# File: publish-coverage-results.yml +# uses reportgenerator task to create a code coverage report and aggregates available cobertura XML files. The results are publishes as a build artifact. + +parameters: + condition: 'succeeded()' + reports: '' + assemblyfilters: '-xunit*' + breakBuild: false + +steps: +- task: reportgenerator@5 + displayName: ReportGenerator + condition: ${{parameters.condition}} + inputs: + reports: ${{parameters.reports}} + targetdir: $(Build.SourcesDirectory)/artifacts/CoverageReport + reporttypes: Html;HtmlInline_AzurePipelines_Dark;Cobertura + verbosity: 'Verbose' + assemblyfilters: ${{parameters.assemblyfilters}} + +- publish: '$(Build.SourcesDirectory)/artifacts/CoverageReport' + displayName: 'Publish CoverageReport Artifact' + artifact: CoverageResults_$(Agent.Os)_$(BuildConfiguration) + condition: ${{parameters.condition}} + +- task: PublishCodeCoverageResults@1 + displayName: 'Publish code coverage' + condition: ${{parameters.condition}} + inputs: + codeCoverageTool: Cobertura + summaryFileLocation: '$(Build.SourcesDirectory)/artifacts/CoverageReport/Cobertura.xml' + failIfCoverageEmpty: ${{parameters.breakBuild}} diff --git a/eng/publish-coverlet-results.yml b/eng/publish-coverlet-result-files.yml similarity index 100% rename from eng/publish-coverlet-results.yml rename to eng/publish-coverlet-result-files.yml From 97c72b1b8ad682ebc13238135430a06733addea4 Mon Sep 17 00:00:00 2001 From: Bert Date: Sat, 5 Aug 2023 17:40:12 +0200 Subject: [PATCH 07/25] fix yaml --- eng/build.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/build.yml b/eng/build.yml index 0f36b2e92..dfb7a8144 100644 --- a/eng/build.yml +++ b/eng/build.yml @@ -29,6 +29,6 @@ steps: - template: publish-coverage-results.yml parameters: - reports: $(Build.SourcesDirectory)/**/coverage.opencover.xml - condition: and(succeeded(), eq(variables['_BuildConfig'], 'Debug')) - assemblyfilters: '-xunit*;+Coverlet.Core.*;+Coverlet.Collector.*' + reports: $(Build.SourcesDirectory)/**/coverage.opencover.xml + condition: and(succeeded(), eq(variables['_BuildConfig'], 'Debug')) + assemblyfilters: '-xunit*;+Coverlet.Core.*;+Coverlet.Collector.*' From 0515e4343174a68638ddbe1c9d57e7a9c9b46bcd Mon Sep 17 00:00:00 2001 From: Bert Date: Sat, 5 Aug 2023 17:52:08 +0200 Subject: [PATCH 08/25] disable template publish-coverage-results.yml --- eng/build.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/eng/build.yml b/eng/build.yml index dfb7a8144..2b37cb1cb 100644 --- a/eng/build.yml +++ b/eng/build.yml @@ -27,8 +27,8 @@ steps: - template: publish-coverlet-result-files.yml -- template: publish-coverage-results.yml - parameters: - reports: $(Build.SourcesDirectory)/**/coverage.opencover.xml - condition: and(succeeded(), eq(variables['_BuildConfig'], 'Debug')) - assemblyfilters: '-xunit*;+Coverlet.Core.*;+Coverlet.Collector.*' +#- template: publish-coverage-results.yml +# parameters: +# reports: $(Build.SourcesDirectory)/**/coverage.opencover.xml +# condition: and(succeeded(), eq(variables['_BuildConfig'], 'Debug')) +# assemblyfilters: '-xunit*;+Coverlet.Core.*;+Coverlet.Collector.*' From 7df9aa0ed337b23b1bcf2d2c5840f828d995a4a4 Mon Sep 17 00:00:00 2001 From: Bert Date: Mon, 7 Aug 2023 14:42:35 +0200 Subject: [PATCH 09/25] use Assert.Equal with static string --- .../Reporters/JsonReporterTests.cs | 67 ++++++++++++------- 1 file changed, 41 insertions(+), 26 deletions(-) diff --git a/test/coverlet.core.tests/Reporters/JsonReporterTests.cs b/test/coverlet.core.tests/Reporters/JsonReporterTests.cs index b6215befe..fb4dbd616 100644 --- a/test/coverlet.core.tests/Reporters/JsonReporterTests.cs +++ b/test/coverlet.core.tests/Reporters/JsonReporterTests.cs @@ -1,42 +1,57 @@ -// Copyright (c) Toni Solarin-Sodara +// Copyright (c) Toni Solarin-Sodara // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using System; using Coverlet.Core.Abstractions; using Moq; -using System; using Xunit; namespace Coverlet.Core.Reporters.Tests { - public class JsonReporterTests + public class JsonReporterTests + { + private static readonly string s_resultModule = @"{ + ""module"": { + ""doc.cs"": { + ""Coverlet.Core.Reporters.Tests.JsonReporterTests"": { + ""System.Void Coverlet.Core.Reporters.Tests.JsonReporterTests.TestReport()"": { + ""Lines"": { + ""1"": 1, + ""2"": 0 + }, + ""Branches"": [] + } + } + } + } +}"; + + [Fact] + public void TestReport() { - [Fact] - public void TestReport() - { - var result = new CoverageResult(); - result.Identifier = Guid.NewGuid().ToString(); + var result = new CoverageResult(); + result.Identifier = Guid.NewGuid().ToString(); - var lines = new Lines(); - lines.Add(1, 1); - lines.Add(2, 0); + var lines = new Lines(); + lines.Add(1, 1); + lines.Add(2, 0); - var methods = new Methods(); - string methodString = "System.Void Coverlet.Core.Reporters.Tests.JsonReporterTests.TestReport()"; - methods.Add(methodString, new Method()); - methods[methodString].Lines = lines; + var methods = new Methods(); + string methodString = "System.Void Coverlet.Core.Reporters.Tests.JsonReporterTests.TestReport()"; + methods.Add(methodString, new Method()); + methods[methodString].Lines = lines; - var classes = new Classes(); - classes.Add("Coverlet.Core.Reporters.Tests.JsonReporterTests", methods); + var classes = new Classes(); + classes.Add("Coverlet.Core.Reporters.Tests.JsonReporterTests", methods); - var documents = new Documents(); - documents.Add("doc.cs", classes); + var documents = new Documents(); + documents.Add("doc.cs", classes); - result.Modules = new Modules(); - result.Modules.Add("module", documents); + result.Modules = new Modules(); + result.Modules.Add("module", documents); - var reporter = new JsonReporter(); - Assert.NotEqual("{\n}", reporter.Report(result, new Mock().Object)); - Assert.NotEqual(string.Empty, reporter.Report(result, new Mock().Object)); - } + var reporter = new JsonReporter(); + Assert.Equal(s_resultModule, reporter.Report(result, new Mock().Object)); } -} \ No newline at end of file + } +} From 5415d3233f609c76f20b1b48b2700558261d0c3a Mon Sep 17 00:00:00 2001 From: Bert Date: Tue, 8 Aug 2023 10:38:38 +0200 Subject: [PATCH 10/25] fix markdown warnings and add properties PackageReadmeFile, PackageReleaseNotes --- Documentation/ConsumeNightlyBuild.md | 22 +- Documentation/DeterministicBuild.md | 9 +- Documentation/Examples.md | 1 + .../MSBuild/DeterministicBuild/HowTo.md | 14 +- .../Examples/MSBuild/MergeWith/HowTo.md | 9 +- .../VSTest/DeterministicBuild/HowTo.md | 17 +- .../Examples/VSTest/HelloWorld/HowTo.md | 6 +- Documentation/GlobalTool.md | 34 +-- Documentation/KnownIssues.md | 90 +++---- Documentation/MSBuildIntegration.md | 55 +++-- Documentation/ReleasePlan.md | 130 +++++------ Documentation/Roadmap.md | 28 ++- Documentation/Troubleshooting.md | 221 +++++++++--------- Documentation/VSTestIntegration.md | 69 +++--- .../coverlet.collector.csproj | 13 +- .../coverlet.msbuild.tasks.csproj | 14 +- 16 files changed, 392 insertions(+), 340 deletions(-) diff --git a/Documentation/ConsumeNightlyBuild.md b/Documentation/ConsumeNightlyBuild.md index 8f9309335..3901f70a5 100644 --- a/Documentation/ConsumeNightlyBuild.md +++ b/Documentation/ConsumeNightlyBuild.md @@ -8,9 +8,9 @@ To consume nightly builds, create a `NuGet.Config` in your root solution directo - + - + @@ -18,36 +18,44 @@ To consume nightly builds, create a `NuGet.Config` in your root solution directo ## Install packages -### Visual Studio: +### Visual Studio ![File](images/nightly.PNG)\ Example:\ ![File](images/nightlyExample.PNG) -### NuGet (Package Manager console): +### NuGet (Package Manager console) + ```powershell PM> Install-Package coverlet.msbuild -Version X.X.X-preview.X.XXX -Source https://pkgs.dev.azure.com/tonerdo/coverlet/_packaging/coverlet-nightly/nuget/v3/index.json ``` + Example: + ```powershell PM> Install-Package coverlet.msbuild -Version 3.0.4-preview.4.g5de0ad7d60 -Source https://pkgs.dev.azure.com/tonerdo/coverlet/_packaging/coverlet-nightly/nuget/v3/index.json ``` -### .NET CLI: +### .NET CLI + ```bash dotnet add package coverlet.msbuild --version X.X.X-preview.X.XXX --source https://pkgs.dev.azure.com/tonerdo/coverlet/_packaging/coverlet-nightly/nuget/v3/index.json ``` + Example: + ```bash dotnet add package coverlet.msbuild --version 3.0.4-preview.4.g5de0ad7d60 --source https://pkgs.dev.azure.com/tonerdo/coverlet/_packaging/coverlet-nightly/nuget/v3/index.json ``` -### MSBuild project file: +### MSBuild project file ```xml ``` + Example: + ```xml -``` \ No newline at end of file +``` diff --git a/Documentation/DeterministicBuild.md b/Documentation/DeterministicBuild.md index aa984e2dd..31fd2dae7 100644 --- a/Documentation/DeterministicBuild.md +++ b/Documentation/DeterministicBuild.md @@ -4,16 +4,17 @@ Support for deterministic builds is available **only** in the `msbuild` (`/p:Col From a coverage perspective, deterministic builds create some challenges because coverage tools usually need access to complete source file metadata (ie. local path) during instrumentation and report generation. These files are reported inside the `.pdb` files, where debugging information is stored. -In local (non-CI) builds, metadata emitted to pdbs are not "deterministic", which means that source files are reported with their full paths. For example, when we build the same project on different machines we'll have different paths emitted inside pdbs, hence, builds are "non deterministic". +In local (non-CI) builds, metadata emitted to pdbs are not "deterministic", which means that source files are reported with their full paths. For example, when we build the same project on different machines we'll have different paths emitted inside pdbs, hence, builds are "non deterministic". As explained above, to improve the level of security of generated artifacts (for instance, DLLs inside the NuGet package), we need to apply some signature (signing with certificate) and validate before usage to avoid possible security issues like tampering. Finally, thanks to deterministic CI builds (with the `ContinuousIntegrationBuild` property set to `true`) plus signature we can validate artifacts and be sure that the binary was built from specific sources (because there is no hard-coded variable metadata, like paths from different build machines). -# Deterministic report +## Deterministic report -Coverlet supports also deterministic reports(for now only for cobertura coverage format). +Coverlet supports also deterministic reports(for now only for cobertura coverage format). If you include `DeterministicReport` parameters for `msbuild` and `collectors` integrations resulting report will be like: + ```xml @@ -25,8 +26,8 @@ If you include `DeterministicReport` parameters for `msbuild` and `collectors` i ... ``` -As you can see we have empty `` element and the `filename` start with well known deterministic fragment `/_/...` +As you can see we have empty `` element and the `filename` start with well known deterministic fragment `/_/...` **Deterministic build is supported without any workaround since version 3.1.100 of .NET Core SDK** ## Workaround only for .NET Core SDK < 3.1.100 diff --git a/Documentation/Examples.md b/Documentation/Examples.md index 55f8169f0..2a6e5cc0b 100644 --- a/Documentation/Examples.md +++ b/Documentation/Examples.md @@ -1,4 +1,5 @@ # Examples + ## MSBuild Integration * Using `/p:MergeWith` feature `Documentation/Examples/MSBuild/MergeWith/MergeWith.sln` diff --git a/Documentation/Examples/MSBuild/DeterministicBuild/HowTo.md b/Documentation/Examples/MSBuild/DeterministicBuild/HowTo.md index d9e37a2ce..24bea3a46 100644 --- a/Documentation/Examples/MSBuild/DeterministicBuild/HowTo.md +++ b/Documentation/Examples/MSBuild/DeterministicBuild/HowTo.md @@ -1,6 +1,7 @@ To run test we need to generates packages to reference in on test project. Run from repo root -``` + +```shell C:\git\coverlet λ dotnet pack Microsoft (R) Build Engine version 16.5.0+d4cbfca49 for .NET Core @@ -32,7 +33,9 @@ Copyright (C) Microsoft Corporation. All rights reserved. Successfully created package 'C:\git\coverlet\bin\Debug\Packages\coverlet.msbuild.2.9.0-preview.6.ga0e22ec622.nupkg'. Successfully created package 'C:\git\coverlet\bin\Debug\Packages\coverlet.msbuild.2.9.0-preview.6.ga0e22ec622.snupkg'. ``` + Add msbuild package version generated to `"..\Documentation\Examples\MSBuild\DeterministicBuild\XUnitTestProject1\XUnitTestProject1.csproj"` + ```xml @@ -58,10 +61,11 @@ Add msbuild package version generated to `"..\Documentation\Examples\MSBuild\Det - ``` + Go to test project folder and run -``` + +```shell C:\git\coverlet\Documentation\Examples\MSBuild\DeterministicBuild (detbuilddocs -> origin) λ dotnet test /p:CollectCoverage=true /p:DeterministicSourcePaths=true Test run for C:\git\coverlet\Documentation\Examples\MSBuild\DeterministicBuild\XUnitTestProject1\bin\Debug\net6.0\XUnitTestProject1.dll(.NETCoreApp,Version=v6.0) @@ -94,8 +98,10 @@ Calculating coverage result... | Average | 100% | 100% | 100% | +---------+------+--------+--------+ ``` + You should see on output folder the coverlet source root mapping file generated. This is the confirmation that you're running coverage on deterministic build. -``` + +```text Documentation\Examples\MSBuild\DeterministicBuild\XUnitTestProject1\bin\Debug\net6.0\CoverletSourceRootsMapping ``` diff --git a/Documentation/Examples/MSBuild/MergeWith/HowTo.md b/Documentation/Examples/MSBuild/MergeWith/HowTo.md index c157b7b80..4135a1379 100644 --- a/Documentation/Examples/MSBuild/MergeWith/HowTo.md +++ b/Documentation/Examples/MSBuild/MergeWith/HowTo.md @@ -1,9 +1,9 @@ **Run from solution root sln** -To merge report togheter you need to run separate test and merge in one `json` format file. +To merge report together you need to run separate test and merge in one `json` format file. Last command will join and create final needed format file. -``` +```shell dotnet test XUnitTestProject1\XUnitTestProject1.csproj /p:CollectCoverage=true /p:CoverletOutput=../CoverageResults/ dotnet test XUnitTestProject2\XUnitTestProject2.csproj /p:CollectCoverage=true /p:CoverletOutput=../CoverageResults/ /p:MergeWith="../CoverageResults/coverage.json" dotnet test XUnitTestProject3\XUnitTestProject3.csproj /p:CollectCoverage=true /p:CoverletOutput=../CoverageResults/ /p:MergeWith="../CoverageResults/coverage.json" /p:CoverletOutputFormat="opencover" @@ -11,13 +11,14 @@ dotnet test XUnitTestProject3\XUnitTestProject3.csproj /p:CollectCoverage=true You can merge also running `dotnet test` and merge with single command from a solution file, but you need to ensure that tests will run sequentially(`-m:1`). This slow down testing but avoid invalid coverage result. -``` +```shell dotnet test /p:CollectCoverage=true /p:CoverletOutput=../CoverageResults/ /p:MergeWith="../CoverageResults/coverage.json" /p:CoverletOutputFormat=\"opencover,json\" -m:1 ``` + N.B. You need to specify `json` format plus another format(the final one), because Coverlet can only merge proprietary format. At the end you can delete temporary `coverage.json` file. You can also merge the coverage result and generate another valid format to export the content than opencover, like cobertura. -``` +```shell dotnet test /p:CollectCoverage=true /p:CoverletOutput=../CoverageResults/ /p:MergeWith="../CoverageResults/coverage.json" /p:CoverletOutputFormat=\"cobertura,json\" -m:1 ``` diff --git a/Documentation/Examples/VSTest/DeterministicBuild/HowTo.md b/Documentation/Examples/VSTest/DeterministicBuild/HowTo.md index 04760a229..586cd4043 100644 --- a/Documentation/Examples/VSTest/DeterministicBuild/HowTo.md +++ b/Documentation/Examples/VSTest/DeterministicBuild/HowTo.md @@ -1,6 +1,7 @@ -To run test we need to generates packages to reference in on test project. +To run test we need to generates packages to reference in on test project. Run from repo root -``` + +```shell C:\git\coverlet λ dotnet pack Microsoft (R) Build Engine version 16.5.0+d4cbfca49 for .NET Core @@ -32,7 +33,9 @@ Copyright (C) Microsoft Corporation. All rights reserved. Successfully created package 'C:\git\coverlet\bin\Debug\Packages\coverlet.msbuild.2.9.0-preview.6.ga0e22ec622.nupkg'. Successfully created package 'C:\git\coverlet\bin\Debug\Packages\coverlet.msbuild.2.9.0-preview.6.ga0e22ec622.snupkg'. ``` + Add collectors package version generated to `"..\Documentation\Examples\VSTest\DeterministicBuild\XUnitTestProject1\XUnitTestProject1.csproj"` + ```xml @@ -56,8 +59,10 @@ Add collectors package version generated to `"..\Documentation\Examples\VSTest\D ``` + Go to test project folder and run -``` + +```shell C:\git\coverlet\Documentation\Examples\VSTest\DeterministicBuild (detbuilddocs -> origin) λ dotnet test --collect:"XPlat Code Coverage" /p:DeterministicSourcePaths=true -- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.DeterministicReport=true Test run for C:\git\coverlet\Documentation\Examples\VSTest\DeterministicBuild\XUnitTestProject1\bin\Debug\netcoreapp3.1\XUnitTestProject1.dll(.NETCoreApp,Version=v6.0) @@ -75,8 +80,10 @@ Total tests: 1 Passed: 1 Total time: 1,3472 Seconds ``` -You should see on output folder the coverlet source root mapping file generated. + +You should see on output folder the coverlet source root mapping file generated. This is the confirmation that you're running coverage on deterministic build. -``` + +```text Documentation\Examples\VSTest\DeterministicBuild\XUnitTestProject1\bin\Debug\net6.0\CoverletSourceRootsMapping_XUnitTestProject1 ``` diff --git a/Documentation/Examples/VSTest/HelloWorld/HowTo.md b/Documentation/Examples/VSTest/HelloWorld/HowTo.md index 548105f9f..d965d05e1 100644 --- a/Documentation/Examples/VSTest/HelloWorld/HowTo.md +++ b/Documentation/Examples/VSTest/HelloWorld/HowTo.md @@ -1,11 +1,11 @@ **Run from XUnitTestProject1 folder** -``` +```shell dotnet test --collect:"XPlat Code Coverage" ``` With custom runsettings file -``` +```shell dotnet test --collect:"XPlat Code Coverage" --settings runsettings.xml -``` \ No newline at end of file +``` diff --git a/Documentation/GlobalTool.md b/Documentation/GlobalTool.md index cf50232c3..06b4e87db 100644 --- a/Documentation/GlobalTool.md +++ b/Documentation/GlobalTool.md @@ -42,9 +42,11 @@ Options: ``` NB. For a [multiple value] options you have to specify values multiple times i.e. -``` + +```shell --exclude-by-attribute 'Obsolete' --exclude-by-attribute 'GeneratedCode' --exclude-by-attribute 'CompilerGenerated' ``` + For `--merge-with` [check the sample](Examples.md). ## Code Coverage @@ -61,7 +63,7 @@ After the above command is run, a `coverage.json` file containing the results wi _Note: The `--no-build` flag is specified so that the `/path/to/test-assembly.dll` isn't rebuilt_ -## Code Coverage for integration tests and end-to-end tests. +## Code Coverage for integration tests and end-to-end tests Sometimes, there are tests that doesn't use regular unit test frameworks like xunit. You may find yourself in a situation where your tests are driven by a custom executable/script, which when run, could do anything from making API calls to driving Selenium. @@ -188,8 +190,9 @@ coverlet --target --targetargs --exclude-by-att ### Source Files You can also ignore specific source files from code coverage using the `--exclude-by-file` option - - Can be specified multiple times - - Use file path or directory path with globbing (e.g `dir1/*.cs`) + +* Can be specified multiple times +* Use file path or directory path with globbing (e.g `dir1/*.cs`) ```bash coverlet --target --targetargs --exclude-by-file "**/dir1/class1.cs" @@ -202,15 +205,17 @@ Coverlet gives the ability to have fine grained control over what gets excluded Syntax: `--exclude '[Assembly-Filter]Type-Filter'` Wildcards -- `*` => matches zero or more characters -- `?` => the prefixed character is optional + +* `*` => matches zero or more characters +* `?` => the prefixed character is optional Examples - - `--exclude "[*]*"` => Excludes all types in all assemblies (nothing is instrumented) - - `--exclude "[coverlet.*]Coverlet.Core.Coverage"` => Excludes the Coverage class in the `Coverlet.Core` namespace belonging to any assembly that matches `coverlet.*` (e.g `coverlet.core`) - - `--exclude "[*]Coverlet.Core.Instrumentation.*"` => Excludes all types belonging to `Coverlet.Core.Instrumentation` namespace in any assembly - - `--exclude "[coverlet.*.tests?]*"` => Excludes all types in any assembly starting with `coverlet.` and ending with `.test` or `.tests` (the `?` makes the `s` optional) - - `--exclude "[coverlet.*]*" --exclude "[*]Coverlet.Core*"` => Excludes assemblies matching `coverlet.*` and excludes all types belonging to the `Coverlet.Core` namespace in any assembly + +* `--exclude "[*]*"` => Excludes all types in all assemblies (nothing is instrumented) +* `--exclude "[coverlet.*]Coverlet.Core.Coverage"` => Excludes the Coverage class in the `Coverlet.Core` namespace belonging to any assembly that matches `coverlet.*` (e.g `coverlet.core`) +* `--exclude "[*]Coverlet.Core.Instrumentation.*"` => Excludes all types belonging to `Coverlet.Core.Instrumentation` namespace in any assembly +* `--exclude "[coverlet.*.tests?]*"` => Excludes all types in any assembly starting with `coverlet.` and ending with `.test` or `.tests` (the `?` makes the `s` optional) +* `--exclude "[coverlet.*]*" --exclude "[*]Coverlet.Core*"` => Excludes assemblies matching `coverlet.*` and excludes all types belonging to the `Coverlet.Core` namespace in any assembly ```bash coverlet --target --targetargs --exclude "[coverlet.*]Coverlet.Core.Coverage" @@ -219,9 +224,10 @@ coverlet --target --targetargs --exclude "[cove Coverlet goes a step in the other direction by also letting you explicitly set what can be included using the `--include` option. Examples - - `--include "[*]*"` => Includes all types in all assemblies (everything is instrumented) - - `--include "[coverlet.*]Coverlet.Core.Coverage"` => Includes the Coverage class in the `Coverlet.Core` namespace belonging to any assembly that matches `coverlet.*` (e.g `coverlet.core`) - - `--include "[coverlet.*.tests?]*"` => Includes all types in any assembly starting with `coverlet.` and ending with `.test` or `.tests` (the `?` makes the `s` optional) + +* `--include "[*]*"` => Includes all types in all assemblies (everything is instrumented) +* `--include "[coverlet.*]Coverlet.Core.Coverage"` => Includes the Coverage class in the `Coverlet.Core` namespace belonging to any assembly that matches `coverlet.*` (e.g `coverlet.core`) +* `--include "[coverlet.*.tests?]*"` => Includes all types in any assembly starting with `coverlet.` and ending with `.test` or `.tests` (the `?` makes the `s` optional) Both `--exclude` and `--include` options can be used together but `--exclude` takes precedence. You can specify the `--exclude` and `--include` options multiple times to allow for multiple filter expressions. diff --git a/Documentation/KnownIssues.md b/Documentation/KnownIssues.md index 0b5b842ec..07d17df34 100644 --- a/Documentation/KnownIssues.md +++ b/Documentation/KnownIssues.md @@ -2,7 +2,7 @@ ## VSTest stops process execution early -*Affected drivers*: msbuild (`dotnet test`) , dotnet tool(if you're using ` --targetargs "test ... --no-build"`) +*Affected drivers*: msbuild (`dotnet test`) , dotnet tool(if you're using `--targetargs "test ... --no-build"`) *Symptoms:* @@ -12,7 +12,7 @@ `warning : [coverlet] Hits file:'C:\Users\REDACTED\AppData\Local\Temp\testApp_ac32258b-fd4a-4bb4-824c-a79061e97c31' not found for module: 'testApp'` -* zero coverage result (often only on CI but not on local) +* zero coverage result (often only on CI but not on local) ```bash Calculating coverage result... @@ -37,7 +37,7 @@ +---------+------+--------+--------+ ``` -The issue is related to VSTest platform https://github.com/microsoft/vstest/issues/1900#issuecomment-457488472 +The issue is related to VSTest platform > However if testhost doesn't shut down within 100ms (as the execution is completed, we expect it to shutdown fast). vstest.console forcefully kills the process. @@ -46,7 +46,7 @@ This happen also if there are other "piece of code" during testing that slow dow *Solution:* -The only way to get around this issue is to use collectors integration https://github.com/coverlet-coverage/coverlet#vstest-integration-preferred-due-to-known-issue-supports-only-net-core-application. With the collector, we're injected in test host through a in-proc collector that communicates with the VSTest platform so we can signal when we end our work. +The only way to get around this issue is to use collectors integration . With the collector, we're injected in test host through a in-proc collector that communicates with the VSTest platform so we can signal when we end our work. ## Upgrade `coverlet.collector` to version > 1.0.0 @@ -54,7 +54,7 @@ The only way to get around this issue is to use collectors integration https://g *Symptoms:* The same as "known issue 1". -There is a bug inside the VSTest platform: https://github.com/microsoft/vstest/issues/2205. +There is a bug inside the VSTest platform: . If you upgrade the collector package with a version greater than 1.0.0, in-proc collector won't be loaded so you could incur "known issue number 1" and get zero coverage result @@ -62,36 +62,38 @@ If you upgrade the collector package with a version greater than 1.0.0, in-proc 1) Reference `Microsoft.NET.Test.Sdk` with version *greater than* 16.4.0 -```xml - - ... - - ... - -``` -2) You can pass custom *coverage.runsettings* file like this -```xml - - - - - - - cobertura - - - - - - - - - - -``` + ```xml + + ... + + ... + + ``` + +1) You can pass custom *coverage.runsettings* file like this + + ```xml + + + + + + + cobertura + + + + + + + + + + + ``` And pass it to command line @@ -103,11 +105,11 @@ dotnet test --settings coverage.runsettings *Affected drivers*: all drivers that support `/p:UseSourceLink=true` -*Symptoms:* some tool like SonarSource doesn't work well see https://github.com/coverlet-coverage/coverlet/issues/482 +*Symptoms:* some tool like SonarSource doesn't work well see `Nerdbank.GitVersioning` generates a version file on the fly but this file is not part of user solution and it's not commited to repo so the generated remote source file reference does not exit, i.e. -``` +```text ... ... @@ -125,7 +127,7 @@ dotnet test --settings coverage.runsettings *Symptoms:* during build/instrumentation you may get an exception like: -``` +```text [coverlet] Unable to instrument module: ..\UnitTests\bin\Debug\netcoreapp2.1\Core.Messaging.dll because : Failed to resolve assembly: 'Microsoft.Azure.ServiceBus, Version=3.4.0.0, Culture=neutral, PublicKeyToken=7e34167dcc6d6d8c' [..\UnitTests.csproj] ``` @@ -148,13 +150,13 @@ or by adding the property `` to the project file ``` -NB. This **DOESN'T ALWAYS WORK**, for example in case of the shared framework https://github.com/dotnet/cli/issues/12705#issuecomment-536686785 +NB. This **DOESN'T ALWAYS WORK**, for example in case of the shared framework We can do nothing at the moment as this is a build behaviour out of our control. -For .NET runtime version >= 3.0 the new default behavior is to copy all assets to the build output (CopyLocalLockFileAssemblies=true) https://github.com/dotnet/cli/issues/12705#issuecomment-535150372, unfortunately the issue could still arise. +For .NET runtime version >= 3.0 the new default behavior is to copy all assets to the build output (CopyLocalLockFileAssemblies=true) , unfortunately the issue could still arise. -In this case the only workaround at the moment is to *manually copy* missing dlls to the output folder: https://github.com/coverlet-coverage/coverlet/issues/560#issue-496440052 +In this case the only workaround at the moment is to *manually copy* missing dlls to the output folder: > The only reliable way to work around this problem is to drop the DLL in the unit tests project's bin\Release\netcoreapp2.2 directory. @@ -164,7 +166,7 @@ In this case the only workaround at the moment is to *manually copy* missing dll *Symptoms:* Running coverage on .NET Framework runtime(i.e. .NET 4.6.1) and get error like: -``` +```text Failed Tests.MinMax.Min_AsyncSelector_Int32_4 Error Message: System.TypeInitializationException : The type initializer for 'Tests.AsyncEnumerableTests' threw an exception. @@ -184,7 +186,7 @@ NB. Workaround doesn't work if test method itself explicitly creates an appdomai *Symptoms:* You are getting following result when running Coverlet within CI/CD pipeline: -``` +```text +--------+------+--------+--------+ | Module | Line | Branch | Method | +--------+------+--------+--------+ @@ -229,5 +231,5 @@ C:\Users\REDACTED\.nuget\packages\coverlet.msbuild\3.2.0\build\coverlet.msbuild. The XML code coverage report is too large for the coverlet to parse. *Potential Solutions:* -* Reduce noise from auto generated code, for example excluding your EntityFrameworkCore Migrations namespace or automatically generated typed Http Clients. See [Excluding From Coverage](./MSBuildIntegration.md#excluding-from-coverage) for more information on ignoring namespaces from code coverage. +* Reduce noise from auto generated code, for example excluding your EntityFrameworkCore Migrations namespace or automatically generated typed Http Clients. See [Excluding From Coverage](./MSBuildIntegration.md#excluding-from-coverage) for more information on ignoring namespaces from code coverage. diff --git a/Documentation/MSBuildIntegration.md b/Documentation/MSBuildIntegration.md index a937665be..a097462e9 100644 --- a/Documentation/MSBuildIntegration.md +++ b/Documentation/MSBuildIntegration.md @@ -4,7 +4,8 @@ In this mode, Coverlet doesn't require any additional setup other than including If a property takes multiple comma-separated values please note that [you will have to add escaped quotes around the string](https://github.com/Microsoft/msbuild/issues/2999#issuecomment-366078677) like this: `/p:Exclude=\"[coverlet.*]*,[*]Coverlet.Core*\"`, `/p:Include=\"[coverlet.*]*,[*]Coverlet.Core*\"`, or `/p:CoverletOutputFormat=\"json,opencover\"`. -To achieve same behavior above using **powershell** you need to use the verbatim argument marker `--%` like this: +To achieve same behavior above using **powershell** you need to use the verbatim argument marker `--%` like this: + ```powershell dotnet test /p:CollectCoverage=true --% /p:CoverletOutputFormat=\"opencover,lcov\" ``` @@ -103,7 +104,7 @@ The above command will automatically fail the build if the line, branch or metho dotnet test /p:CollectCoverage=true /p:Threshold=80 /p:ThresholdType=line ``` -You can specify multiple values for `ThresholdType` by separating them with commas. Valid values include `line`, `branch` and `method`. +You can specify multiple values for `ThresholdType` by separating them with commas. Valid values include `line`, `branch` and `method`. You can do the same for `Threshold` as well. ```bash @@ -137,8 +138,9 @@ dotnet test /p:CollectCoverage=true /p:ExcludeByAttribute="Obsolete,GeneratedCod ### Source Files You can also ignore specific source files from code coverage using the `ExcludeByFile` property - - Use single or multiple paths (separate by comma) - - Use file path or directory path with globbing (e.g `dir1/*.cs`) + +* Use single or multiple paths (separate by comma) +* Use file path or directory path with globbing (e.g `dir1/*.cs`) ```bash dotnet test /p:CollectCoverage=true /p:ExcludeByFile=\"**/dir1/class1.cs,**/dir2/*.cs,**/dir3/**/*.cs\" @@ -151,15 +153,17 @@ Coverlet gives the ability to have fine grained control over what gets excluded Syntax: `/p:Exclude=[Assembly-Filter]Type-Filter` Wildcards -- `*` => matches zero or more characters -- `?` => the prefixed character is optional + +* `*` => matches zero or more characters +* `?` => the prefixed character is optional Examples - - `/p:Exclude="[*]*"` => Excludes all types in all assemblies (nothing is instrumented) - - `/p:Exclude="[coverlet.*]Coverlet.Core.Coverage"` => Excludes the Coverage class in the `Coverlet.Core` namespace belonging to any assembly that matches `coverlet.*` (e.g `coverlet.core`) - - `/p:Exclude="[*]Coverlet.Core.Instrumentation.*"` => Excludes all types belonging to `Coverlet.Core.Instrumentation` namespace in any assembly - - `/p:Exclude="[coverlet.*.tests?]*"` => Excludes all types in any assembly starting with `coverlet.` and ending with `.test` or `.tests` (the `?` makes the `s` optional) - - `/p:Exclude=\"[coverlet.*]*,[*]Coverlet.Core*\"` => Excludes assemblies matching `coverlet.*` and excludes all types belonging to the `Coverlet.Core` namespace in any assembly + +* `/p:Exclude="[*]*"` => Excludes all types in all assemblies (nothing is instrumented) +* `/p:Exclude="[coverlet.*]Coverlet.Core.Coverage"` => Excludes the Coverage class in the `Coverlet.Core` namespace belonging to any assembly that matches `coverlet.*` (e.g `coverlet.core`) +* `/p:Exclude="[*]Coverlet.Core.Instrumentation.*"` => Excludes all types belonging to `Coverlet.Core.Instrumentation` namespace in any assembly +* `/p:Exclude="[coverlet.*.tests?]*"` => Excludes all types in any assembly starting with `coverlet.` and ending with `.test` or `.tests` (the `?` makes the `s` optional) +* `/p:Exclude=\"[coverlet.*]*,[*]Coverlet.Core*\"` => Excludes assemblies matching `coverlet.*` and excludes all types belonging to the `Coverlet.Core` namespace in any assembly ```bash dotnet test /p:CollectCoverage=true /p:Exclude="[coverlet.*]Coverlet.Core.Coverage" @@ -168,20 +172,21 @@ dotnet test /p:CollectCoverage=true /p:Exclude="[coverlet.*]Coverlet.Core.Covera Coverlet goes a step in the other direction by also letting you explicitly set what can be included using the `Include` property. Examples - - `/p:Include="[*]*"` => Includes all types in all assemblies (everything is instrumented) - - `/p:Include="[coverlet.*]Coverlet.Core.Coverage"` => Includes the Coverage class in the `Coverlet.Core` namespace belonging to any assembly that matches `coverlet.*` (e.g `coverlet.core`) - - `/p:Include="[coverlet.*.tests?]*"` => Includes all types in any assembly starting with `coverlet.` and ending with `.test` or `.tests` (the `?` makes the `s` optional) + +* `/p:Include="[*]*"` => Includes all types in all assemblies (everything is instrumented) +* `/p:Include="[coverlet.*]Coverlet.Core.Coverage"` => Includes the Coverage class in the `Coverlet.Core` namespace belonging to any assembly that matches `coverlet.*` (e.g `coverlet.core`) +* `/p:Include="[coverlet.*.tests?]*"` => Includes all types in any assembly starting with `coverlet.` and ending with `.test` or `.tests` (the `?` makes the `s` optional) Both `Exclude` and `Include` properties can be used together but `Exclude` takes precedence. You can specify multiple filter expressions by separting them with a comma (`,`). You can also include coverage of the test assembly itself by setting `/p:IncludeTestAssembly` to `true`. -### Skip auto-implemented properties +### Skip auto-implemented properties -Neither track nor record auto-implemented properties. +Neither track nor record auto-implemented properties. Syntax: `/p:SkipAutoProps=true` -### Instrument module wihtout local sources file. +### Instrument module wihtout local sources file Syntax: `/p:InstrumentModulesWithoutLocalSources=true` @@ -200,7 +205,7 @@ To exclude or include multiple assemblies when using Powershell scripts or creat Azure DevOps builds do not require double quotes to be unescaped: -``` +```shell dotnet test --configuration $(buildConfiguration) --no-build /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura /p:CoverletOutput=$(Build.SourcesDirectory)/TestResults/Coverage/ /p:Exclude="[MyAppName.DebugHost]*%2c[MyAppNamet.WebHost]*%2c[MyAppName.App]*" ``` @@ -223,16 +228,17 @@ Coverlet supports [SourceLink](https://github.com/dotnet/sourcelink) custom debu ## Deterministic build -Take a look at [documentation](DeterministicBuild.md) for further informations. -To generate deterministc report the parameter is: -``` +Take a look at [documentation](DeterministicBuild.md) for further information. +To generate deterministic report the parameter is: + +```shell /p:DeterministicReport=true ``` ## Exclude assemblies without sources from coverage The heuristic coverlet uses to determine if an assembly is a third-party dependency is based on the matching of the assembly`s source documents and the corresponding source files. -This parameter has three different values to control the automatic assembly exclusion. +This parameter has three different values to control the automatic assembly exclusion. | Parameter | Description | |-----------|-------------| @@ -241,6 +247,7 @@ This parameter has three different values to control the automatic assembly excl | None | No assembly is excluded. | Here is an example of how to specifiy the parameter: -``` + +```shell /p:ExcludeAssembliesWithoutSources="MissingAny" -``` \ No newline at end of file +``` diff --git a/Documentation/ReleasePlan.md b/Documentation/ReleasePlan.md index 84f09223b..a9b7943c8 100644 --- a/Documentation/ReleasePlan.md +++ b/Documentation/ReleasePlan.md @@ -2,9 +2,9 @@ ## Versioning strategy -Coverlet is versioned with Semantic Versioning [2.0.0](https://semver.org/#semantic-versioning-200) that states: +Coverlet is versioned with Semantic Versioning [6.0.0](https://semver.org/#semantic-versioning-200) that states: -``` +```text Given a version number MAJOR.MINOR.PATCH, increment the: MAJOR version when you make incompatible API changes, @@ -13,32 +13,31 @@ PATCH version when you make backwards-compatible bug fixes. Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format. ``` -We release 3 components as NuGet packages: +We release 3 components as NuGet packages: -**coverlet.msbuild.nupkg** -**coverlet.console.nupkg** -**coverlet.collector.nupkg** +**coverlet.msbuild.nupkg** +**coverlet.console.nupkg** +**coverlet.collector.nupkg** ### Current versions | Package | Version | |:----------------------|:--------| -|**coverlet.msbuild** | 6.0.0 | +|**coverlet.msbuild** | 6.0.0 | |**coverlet.console** | 6.0.0 | |**coverlet.collector** | 6.0.0 | - | Release Date | coverlet.msbuild | coverlet.console | coverlet.collector| commit hash | notes | | :-----------------|:-----------------|:------------------|:------------------|:-----------------------------------------|:-------------------------------| -| 05 May 2023 | 6.0.0 | 6.0.0 | 6.0.0 | 3ad4fa1d5cd7ffe206c0cb9dc805ee6ca5a7b550 | Version aligned with github one| -| 29 Oct 2022 | 3.2.0 | 3.2.0 | 3.2.0 | e2c9d84a84a9d2d240ac15feb70f9198c6f8e173 | | -| 06 Feb 2022 | 3.1.2 | 3.1.2 | 3.1.2 | e335b1a8025e49e2f2de6b40ef12ec9d3ed11ceb | Fix CoreLib coverage issues | -| 30 Jan 2022 | 3.1.1 | 3.1.1 | 3.1.1 | e4278c06faba63122a870df15a1a1b934f6bc81d | | -| 19 July 2021 | 3.1.0 | 3.1.0 | 3.1.0 | 5a0ecc1e92fd754e2439dc3e4c828ff7386aa1a7 | Support for determistic build | -| 21 February 2021 | 3.0.3 | 3.0.3 | 3.0.3 | adfabfd58de0aabe263e7d2080324e0b8541071e | Fix regressions | -| 24 January 2021 | 3.0.2 | 3.0.2 | 3.0.2 | ed918515492193fd154b60270d440c40fa30fee9 | Fix regressions | -| 16 January 2021 | 3.0.1 | 3.0.1 | 3.0.1 | 1b45fd89245369ae94407e7a77bdfee112042486 | Fix severe coverage regression | -| 09 January 2021 | 3.0.0 | 3.0.0 | 3.0.0 | 1e77f9d2183a320e8991bfc296460e793301931f | Align versions numbers | +| 05 May 2023 | 6.0.0 | 6.0.0 | 6.0.0 | 3ad4fa1d5cd7ffe206c0cb9dc805ee6ca5a7b550 | Version aligned with github one| +| 29 Oct 2022 | 3.2.0 | 3.2.0 | 3.2.0 | e2c9d84a84a9d2d240ac15feb70f9198c6f8e173 | | +| 06 Feb 2022 | 3.1.2 | 3.1.2 | 3.1.2 | e335b1a8025e49e2f2de6b40ef12ec9d3ed11ceb | Fix CoreLib coverage issues | +| 30 Jan 2022 | 3.1.1 | 3.1.1 | 3.1.1 | e4278c06faba63122a870df15a1a1b934f6bc81d | | +| 19 July 2021 | 3.1.0 | 3.1.0 | 3.1.0 | 5a0ecc1e92fd754e2439dc3e4c828ff7386aa1a7 | Support for determistic build | +| 21 February 2021 | 3.0.3 | 3.0.3 | 3.0.3 | adfabfd58de0aabe263e7d2080324e0b8541071e | Fix regressions | +| 24 January 2021 | 3.0.2 | 3.0.2 | 3.0.2 | ed918515492193fd154b60270d440c40fa30fee9 | Fix regressions | +| 16 January 2021 | 3.0.1 | 3.0.1 | 3.0.1 | 1b45fd89245369ae94407e7a77bdfee112042486 | Fix severe coverage regression | +| 09 January 2021 | 3.0.0 | 3.0.0 | 3.0.0 | 1e77f9d2183a320e8991bfc296460e793301931f | Align versions numbers | | 30 May 2020 | 2.9.0 | 1.7.2 | 1.3.0 | 83a38d45b3f9c231d705bfed849efbf41b3aaa86 | deterministic build support | | 04 April 2020 | 2.8.1 | 1.7.1 | 1.2.1 | 3f81828821d07d756e02a4105b2533cedf0b543c | | | 03 January 2019 | 2.8.0 | 1.7.0 | 1.2.0 | 72a688f1c47fa92059540d5fbb1c4b0b4bf0dc8c | | @@ -47,80 +46,81 @@ We release 3 components as NuGet packages: | 06 June 2019 | 2.6.2 | 1.5.2 | 1.0.0 | 3e7eac9df094c22335711a298d359890aed582e8 | first collector release | To get the list of commits between two version use git command + ```bash git log --oneline hashbefore currenthash ``` -# How to manually compare latest release with nightly build -Before creating a new release it makes sense to test the new release against a benchmark repository. This can help to determine bugs that haven't been found -by the unit/integration tests. Therefore, coverage of the latest release is compared with our nightly build. +## How to manually compare latest release with nightly build -In the following example the benchmark repository refit (https://github.com/reactiveui/refit) is used which already uses coverlet for coverage. +Before creating a new release it makes sense to test the new release against a benchmark repository. This can help to determine bugs that haven't been found +by the unit/integration tests. Therefore, coverage of the latest release is compared with our nightly build. -1. Clone the benchmark repository (https://github.com/reactiveui/refit) - -2. Check if latest coverlet version is used by the project, otherwise add coverlet to the project (https://github.com/coverlet-coverage/coverlet#installation). +In the following example the benchmark repository refit () is used which already uses coverlet for coverage. +1. Clone the benchmark repository () +2. Check if latest coverlet version is used by the project, otherwise add coverlet to the project (). 3. Create coverage report for latest coverlet version: -``` -dotnet test --collect:"XPlat Code Coverage" -``` + + ```shell + dotnet test --collect:"XPlat Code Coverage" + ``` 4. Update the test projects with the latest nightly build version of coverlet -(https://github.com/coverlet-coverage/coverlet/blob/master/Documentation/ConsumeNightlyBuild.md). +(). 5. Create coverage report for nightly build version by rerunning the tests: -``` -dotnet test --collect:"XPlat Code Coverage" -``` -6. Check for differences in the coverage reports. + ```shell + dotnet test --collect:"XPlat Code Coverage" + ``` +6. Check for differences in the coverage reports. -# How to manually release packages to nuget.org +## How to manually release packages to nuget.org This is the steps to release new packages to nuget.org 1. Update projects version in file `version.json` in root of repo (remove `-preview.{height}` and adjust version) -Do a PR and merge to master. + Do a PR and merge to master. 2. Clone repo, **remember to build packages from master and not from your fork or metadata links will point to your forked repo.** . Run `git log -5` from repo root to verify last commit. 3. From new cloned, aligned and versions updated repo root run pack command - ``` - dotnet pack -c release /p:TF_BUILD=true /p:PublicRelease=true - ... - coverlet.console -> D:\git\coverlet\src\coverlet.console\bin\Release\netcoreapp2.2\coverlet.console.dll - coverlet.console -> D:\git\coverlet\src\coverlet.console\bin\Release\netcoreapp2.2\publish\ - Successfully created package 'D:\git\coverlet\bin\Release\Packages\coverlet.msbuild.2.8.1.nupkg'. - Successfully created package 'D:\git\coverlet\bin\Release\Packages\coverlet.msbuild.2.8.1.snupkg'. - Successfully created package 'D:\git\coverlet\bin\Release\Packages\coverlet.console.1.7.1.nupkg'. - Successfully created package 'D:\git\coverlet\bin\Release\Packages\coverlet.console.1.7.1.snupkg'. - Successfully created package 'D:\git\coverlet\bin\Release\Packages\coverlet.collector.1.2.1.nupkg'. - Successfully created package 'D:\git\coverlet\bin\Release\Packages\coverlet.collector.1.2.1.snupkg'. - ``` - -4. Sign the packages using SignClient tool https://www.nuget.org/packages/SignClient - - ```powershell - ❯ SignClient "Sign" ` - >> --baseDirectory "REPO ROOT DIRECTORY\bin" ` - >> --input "**/*.nupkg" ` - >> --config "ROOT REPO DIRECTORY\eng\signclient.json" ` - >> --user "USER" ` - >> --secret "SECRET" ` - >> --name "Coverlet" ` - >> --description "Coverlet" ` - >> --descriptionUrl "https://github.com/coverlet-coverage/coverlet" - ``` + ```shell + dotnet pack -c release /p:TF_BUILD=true /p:PublicRelease=true + ... + coverlet.console -> D:\git\coverlet\src\coverlet.console\bin\Release\netcoreapp2.2\coverlet.console.dll + coverlet.console -> D:\git\coverlet\src\coverlet.console\bin\Release\netcoreapp2.2\publish\ + Successfully created package 'D:\git\coverlet\bin\Release\Packages\coverlet.msbuild.2.8.1.nupkg'. + Successfully created package 'D:\git\coverlet\bin\Release\Packages\coverlet.msbuild.2.8.1.snupkg'. + Successfully created package 'D:\git\coverlet\bin\Release\Packages\coverlet.console.1.7.1.nupkg'. + Successfully created package 'D:\git\coverlet\bin\Release\Packages\coverlet.console.1.7.1.snupkg'. + Successfully created package 'D:\git\coverlet\bin\Release\Packages\coverlet.collector.1.2.1.nupkg'. + Successfully created package 'D:\git\coverlet\bin\Release\Packages\coverlet.collector.1.2.1.snupkg'. + ``` + +4. Sign the packages using SignClient tool + + ```powershell + ❯ SignClient "Sign" ` + >> --baseDirectory "REPO ROOT DIRECTORY\bin" ` + >> --input "**/*.nupkg" ` + >> --config "ROOT REPO DIRECTORY\eng\signclient.json" ` + >> --user "USER" ` + >> --secret "SECRET" ` + >> --name "Coverlet" ` + >> --description "Coverlet" ` + >> --descriptionUrl "https://github.com/coverlet-coverage/coverlet" + ``` 5. Upload *.nupkg files to Nuget.org site. **Check all metadata(url links, deterministic build etc...) before "Submit"** 6. **On your fork**: - * Align to master - * Bump version by one (fix part) and re-add `-preview.{height}` - * Create release on repo https://github.com/coverlet-coverage/coverlet/releases - * Update the [Release Plan](https://github.com/coverlet-coverage/coverlet/blob/master/Documentation/ReleasePlan.md)(this document) and [ChangeLog](https://github.com/coverlet-coverage/coverlet/blob/master/Documentation/Changelog.md) - * Do PR and merge + * Align to master + * Bump version by one (fix part) and re-add `-preview.{height}` + * Create release on repo + * Update the [Release Plan](https://github.com/coverlet-coverage/coverlet/blob/master/Documentation/ReleasePlan.md)(this document) and [ChangeLog](https://github.com/coverlet-coverage/coverlet/blob/master/Documentation/Changelog.md) + * Do PR and merge diff --git a/Documentation/Roadmap.md b/Documentation/Roadmap.md index a7ef5117b..6415247af 100644 --- a/Documentation/Roadmap.md +++ b/Documentation/Roadmap.md @@ -1,30 +1,30 @@ # Roadmap -This document describes the roadmap for coverlet showing priorities. -Maintain coverlet means like any other project two things, answer/resolve soon as possible new issues that are blocking our users an second improve product with new features and enhancements in different areas. +This document describes the roadmap for coverlet showing priorities. +Maintain coverlet means like any other project two things, answer/resolve soon as possible new issues that are blocking our users an second improve product with new features and enhancements in different areas. All coverlet issues are labeled and categorized to better support this activites. -As soon as an issue is open is labeled with `untriaged` if not immediately solvable(we need to do some debugging/PoC to understand where is the issue). -After triage a final correct label is applied and will be taken into account depending on priority order. +As soon as an issue is open is labeled with `untriaged` if not immediately solvable(we need to do some debugging/PoC to understand where is the issue). +After triage a final correct label is applied and will be taken into account depending on priority order. We use `needs more info` if we're waiting for answers. Default priority order "should" be: 1) Bugs: we should fix bugs as soon as possible and for first bugs related to coverage because this is the goal of coverlet. -Coverage bugs: https://github.com/coverlet-coverage/coverlet/issues?q=is%3Aissue+is%3Aopen+label%3Abug+label%3Atenet-coverage -Other bugs: https://github.com/coverlet-coverage/coverlet/issues?q=is%3Aissue+is%3Aopen+label%3Abug + Coverage bugs: + Other bugs: 2) New features: analyze and add new features, we have three drivers so features could be related to one of these. -Feature requests: https://github.com/coverlet-coverage/coverlet/issues?q=is%3Aissue+is%3Aopen+label%3Afeature-request + Feature requests: 3) Performance: we never worked on performance aspect of coverlet, it makes sense for a "new project with some hope", but today coverlet is the facto the dotnet coverage tool, so we HAVE TO approach this aspect. -Performance issues: https://github.com/coverlet-coverage/coverlet/issues?q=is%3Aissue+is%3Aopen+label%3Atenet-performance +Performance issues: -Some new features have got a `Discussion` label if we don't have and agreement yet on semantics. -Discussions: https://github.com/coverlet-coverage/coverlet/issues?q=is%3Aissue+is%3Aopen+label%3Adiscussion +Some new features have got a `Discussion` label if we don't have and agreement yet on semantics. +Discussions: ## New features roadmap @@ -32,16 +32,14 @@ This is the list of features we should develop soon as possible: ### High priority -- Allow merge reports solution wide on all flavours https://github.com/coverlet-coverage/coverlet/issues/662 https://github.com/coverlet-coverage/coverlet/issues/357 +- Allow merge reports solution wide on all flavours -- Some perf improvements https://github.com/coverlet-coverage/coverlet/issues/836 +- Some perf improvements ### Low priority -- Rethink hits reports strategy https://github.com/coverlet-coverage/coverlet/issues/808 +- Rethink hits reports strategy ## Maintainers discussion channel [As maintainers we should try to find a way to keep in synch, we could use a chat where we can "take note" of progress and if possible answer to questions/doubt, I know this is OSS, but it's hard keep project at high level without "more ideas".] - - diff --git a/Documentation/Troubleshooting.md b/Documentation/Troubleshooting.md index f5df25ac8..9592b4af7 100644 --- a/Documentation/Troubleshooting.md +++ b/Documentation/Troubleshooting.md @@ -4,39 +4,40 @@ 1) Generate verbose log -``` -dotnet test test\coverlet.core.tests\coverlet.core.tests.csproj -c debug /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Include=[coverlet.*]* -verbosity:diagnostic -bl:msbuild.binlog -noconsolelogger -``` + ```shell + dotnet test test\coverlet.core.tests\coverlet.core.tests.csproj -c debug /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Include=[coverlet.*]* -verbosity:diagnostic -bl:msbuild.binlog -noconsolelogger + ``` -2) Download http://msbuildlog.com/ +2) Download 3) Open `msbuild.binlog` generated and search for '[coverlet]' logs - -![File](images/file.png) + + ![File](images/file.png) ## Collectors integration -``` +```shell dotnet test --collect:"XPlat Code Coverage" --settings runsettings --diag:log.txt ``` You'll get logs file in same folder similar to -``` +```text log.datacollector.19-09-12_14-55-17_64755_5.txt log.host.19-09-12_14-55-18_82700_6.txt log.txt ``` + Search inside with filter '[coverlet]' ## Coverlet Global Tool -``` +```shell coverlet "C:\git\coverlet\test\coverlet.core.tests\bin\Debug\netcoreapp2.0\coverlet.core.tests.dll" --target "dotnet" --targetargs "test C:\git\coverlet\test\coverlet.core.tests --no-build" --verbosity detailed ``` Sample output -``` +```text ... Instrumented module: 'C:\git\coverlet\test\coverlet.core.tests\bin\Debug\netcoreapp2.0\coverlet.core.dll' Instrumented module: 'C:\git\coverlet\test\coverlet.core.tests\bin\Debug\netcoreapp2.0\xunit.runner.reporters.netcoreapp10.dll' @@ -80,116 +81,120 @@ Hits file:'C:\Users\Marco\AppData\Local\Temp\coverlet.core_703263e9-21f0-4d1c-9c ## Use local build (no collectors) -Sometimes is useful test local updated source to fix issue. +Sometimes is useful test local updated source to fix issue. You can "load" your local build using simple switch: * build repo -``` -D:\git\coverlet (fixjsonserializerbug -> origin) -λ dotnet build -Microsoft (R) Build Engine version 16.1.76+g14b0a930a7 for .NET Core -Copyright (C) Microsoft Corporation. All rights reserved. - - Restore completed in 52.23 ms for D:\git\coverlet\test\coverlet.testsubject\coverlet.testsubject.csproj. - Restore completed in 58.97 ms for D:\git\coverlet\src\coverlet.console\coverlet.console.csproj. - Restore completed in 59 ms for D:\git\coverlet\src\coverlet.core\coverlet.core.csproj. - Restore completed in 59.17 ms for D:\git\coverlet\src\coverlet.msbuild.tasks\coverlet.msbuild.tasks.csproj. - Restore completed in 59.26 ms for D:\git\coverlet\src\coverlet.collector\coverlet.collector.csproj. - Restore completed in 60.1 ms for D:\git\coverlet\test\coverlet.collector.tests\coverlet.collector.tests.csproj. - Restore completed in 60.42 ms for D:\git\coverlet\test\coverlet.core.performancetest\coverlet.core.performancetest.csproj. - Restore completed in 60.47 ms for D:\git\coverlet\test\coverlet.core.tests\coverlet.core.tests.csproj. - Restore completed in 22.85 ms for D:\git\coverlet\test\coverlet.core.tests\coverlet.core.tests.csproj. - coverlet.testsubject -> D:\git\coverlet\test\coverlet.testsubject\bin\Debug\netcoreapp2.0\coverlet.testsubject.dll - coverlet.core -> D:\git\coverlet\src\coverlet.core\bin\Debug\netstandard2.0\coverlet.core.dll - coverlet.msbuild.tasks -> D:\git\coverlet\src\coverlet.msbuild.tasks\bin\Debug\netstandard2.0\coverlet.msbuild.tasks.dll - coverlet.collector -> D:\git\coverlet\src\coverlet.collector\bin\Debug\netcoreapp2.0\coverlet.collector.dll - coverlet.console -> D:\git\coverlet\src\coverlet.console\bin\Debug\netcoreapp2.2\coverlet.console.dll - coverlet.core.performancetest -> D:\git\coverlet\test\coverlet.core.performancetest\bin\Debug\netcoreapp2.0\coverlet.core.performancetest.dll - coverlet.core.tests -> D:\git\coverlet\test\coverlet.core.tests\bin\Debug\netcoreapp2.0\coverlet.core.tests.dll - coverlet.collector.tests -> D:\git\coverlet\test\coverlet.collector.tests\bin\Debug\netcoreapp2.2\coverlet.collector.tests.dll - -Build succeeded. - 0 Warning(s) - 0 Error(s) - -Time Elapsed 00:00:07.42 - -D:\git\coverlet (fixjsonserializerbug -> origin) -``` + ```text + D:\git\coverlet (fixjsonserializerbug -> origin) + λ dotnet build + Microsoft (R) Build Engine version 16.1.76+g14b0a930a7 for .NET Core + Copyright (C) Microsoft Corporation. All rights reserved. + + Restore completed in 52.23 ms for D:\git\coverlet\test\coverlet.testsubject\coverlet.testsubject.csproj. + Restore completed in 58.97 ms for D:\git\coverlet\src\coverlet.console\coverlet.console.csproj. + Restore completed in 59 ms for D:\git\coverlet\src\coverlet.core\coverlet.core.csproj. + Restore completed in 59.17 ms for D:\git\coverlet\src\coverlet.msbuild.tasks\coverlet.msbuild.tasks.csproj. + Restore completed in 59.26 ms for D:\git\coverlet\src\coverlet.collector\coverlet.collector.csproj. + Restore completed in 60.1 ms for D:\git\coverlet\test\coverlet.collector.tests\coverlet.collector.tests.csproj. + Restore completed in 60.42 ms for D:\git\coverlet\test\coverlet.core.performancetest\coverlet.core.performancetest.csproj. + Restore completed in 60.47 ms for D:\git\coverlet\test\coverlet.core.tests\coverlet.core.tests.csproj. + Restore completed in 22.85 ms for D:\git\coverlet\test\coverlet.core.tests\coverlet.core.tests.csproj. + coverlet.testsubject -> D:\git\coverlet\test\coverlet.testsubject\bin\Debug\netcoreapp2.0\coverlet.testsubject.dll + coverlet.core -> D:\git\coverlet\src\coverlet.core\bin\Debug\netstandard2.0\coverlet.core.dll + coverlet.msbuild.tasks -> D:\git\coverlet\src\coverlet.msbuild.tasks\bin\Debug\netstandard2.0\coverlet.msbuild.tasks.dll + coverlet.collector -> D:\git\coverlet\src\coverlet.collector\bin\Debug\netcoreapp2.0\coverlet.collector.dll + coverlet.console -> D:\git\coverlet\src\coverlet.console\bin\Debug\netcoreapp2.2\coverlet.console.dll + coverlet.core.performancetest -> D:\git\coverlet\test\coverlet.core.performancetest\bin\Debug\netcoreapp2.0\coverlet.core.performancetest.dll + coverlet.core.tests -> D:\git\coverlet\test\coverlet.core.tests\bin\Debug\netcoreapp2.0\coverlet.core.tests.dll + coverlet.collector.tests -> D:\git\coverlet\test\coverlet.collector.tests\bin\Debug\netcoreapp2.2\coverlet.collector.tests.dll + + Build succeeded. + 0 Warning(s) + 0 Error(s) + + Time Elapsed 00:00:07.42 + + D:\git\coverlet (fixjsonserializerbug -> origin) + ``` * Go to repro project and run -``` -D:\git\Cake.Codecov\Source\Cake.Codecov.Tests (develop -> origin) -λ dotnet test /p:CollectCoverage=true /p:Exclude="[xunit.*]*" /p:CoverletToolsPath=D:\git\coverlet\src\coverlet.msbuild.tasks\bin\Debug\netstandard2.0\ -Test run for D:\git\Cake.Codecov\Source\Cake.Codecov.Tests\bin\Debug\netcoreapp2.0\Cake.Codecov.Tests.dll(.NETCoreApp,Version=v2.0) -... -``` + ```text + D:\git\Cake.Codecov\Source\Cake.Codecov.Tests (develop -> origin) + λ dotnet test /p:CollectCoverage=true /p:Exclude="[xunit.*]*" /p:CoverletToolsPath=D:\git\coverlet\src\coverlet.msbuild.tasks\bin\Debug\netstandard2.0\ + Test run for D:\git\Cake.Codecov\Source\Cake.Codecov.Tests\bin\Debug\netcoreapp2.0\Cake.Codecov.Tests.dll(.NETCoreApp,Version=v2.0) + ... + ``` In this way you can add `Debug.Launch()` inside coverlet source and debug. -## Use local collectors build +## Use local collectors build To use/debug local collectors build we need to tell to our project to restore and use our local build nuget package. 1) Build local package -``` -C:\git\coverlet\src\coverlet.collector (master -> origin) -λ dotnet pack -Microsoft (R) Build Engine version 16.2.32702+c4012a063 for .NET Core -Copyright (C) Microsoft Corporation. All rights reserved. - - Restore completed in 50,28 ms for C:\git\coverlet\src\coverlet.collector\coverlet.collector.csproj. - Restore completed in 50,28 ms for C:\git\coverlet\src\coverlet.core\coverlet.core.csproj. - coverlet.core -> C:\git\coverlet\src\coverlet.core\bin\Debug\netstandard2.0\coverlet.core.dll - coverlet.collector -> C:\git\coverlet\src\coverlet.collector\bin\Debug\netcoreapp2.0\coverlet.collector.dll - Successfully created package 'C:\git\coverlet\bin\Debug\Packages\coverlet.collector.1.0.67.nupkg'. - Successfully created package 'C:\git\coverlet\bin\Debug\Packages\coverlet.collector.1.0.67.snupkg'. -``` + ```text + C:\git\coverlet\src\coverlet.collector (master -> origin) + λ dotnet pack + Microsoft (R) Build Engine version 16.2.32702+c4012a063 for .NET Core + Copyright (C) Microsoft Corporation. All rights reserved. + + Restore completed in 50,28 ms for C:\git\coverlet\src\coverlet.collector\coverlet.collector.csproj. + Restore completed in 50,28 ms for C:\git\coverlet\src\coverlet.core\coverlet.core.csproj. + coverlet.core -> C:\git\coverlet\src\coverlet.core\bin\Debug\netstandard2.0\coverlet.core.dll + coverlet.collector -> C:\git\coverlet\src\coverlet.collector\bin\Debug\netcoreapp2.0\coverlet.collector.dll + Successfully created package 'C:\git\coverlet\bin\Debug\Packages\coverlet.collector.1.0.67.nupkg'. + Successfully created package 'C:\git\coverlet\bin\Debug\Packages\coverlet.collector.1.0.67.snupkg'. + ``` + 2) Add new `NuGet.Config` file on your test project/solution -``` - - - - - - - - - - - -``` + + ```xml + + + + + + + + + + + + ``` + 3) Update nuget package in our test project -```xml - - - - netcoreapp2.2 - false - - - - - - - <-- My local package version - - - - - - - -``` + + ```xml + + + + netcoreapp2.2 + false + + + + + + + <-- My local package version + + + + + + + + ``` 4) Run test command -``` - dotnet test XUnitTestProject1\ --collect:"XPlat Code Coverage" -``` + ```shell + dotnet test XUnitTestProject1\ --collect:"XPlat Code Coverage" + ``` You can also attach/debug your code adding some line of code on collectors i.e. @@ -208,15 +213,15 @@ Fire attach System.Diagnostics.Debugger.Launch(); ``` -If you want debug in-process collector, you need to set VSTEST_HOST_DEBUG(https://github.com/microsoft/vstest/issues/2158) environment variable +If you want debug in-process collector, you need to set [VSTEST_HOST_DEBUG](https://github.com/microsoft/vstest/issues/2158) environment variable -``` +```shell set VSTEST_HOST_DEBUG=1 ``` Test host will wait for debugger -``` +```text Starting test execution, please wait... Logging Vstest Diagnostics in file: C:\git\coverletissue\collectorlog\XUnitTestProject1\log.txt Host debugging is enabled. Please attach debugger to testhost process to continue. @@ -231,7 +236,7 @@ Coverlet works thanks to ModuleTracker that is injected during instrumentation f We can collect logs from trackers through an enviroment variable -``` +```shell set COVERLET_ENABLETRACKERLOG=1 ``` @@ -241,7 +246,7 @@ When enabled, tracking event will be collected in a log file near to module loca You can live attach and debug msbuild tasks with `COVERLET_MSBUILD_INSTRUMENTATIONTASK_DEBUG` env variable -``` +```shell set COVERLET_MSBUILD_INSTRUMENTATIONTASK_DEBUG=1 ``` @@ -249,14 +254,14 @@ You can live attach and debug msbuild tasks with `COVERLET_MSBUILD_INSTRUMENTATI You can live attach and debug collectors with `COVERLET_DATACOLLECTOR_OUTOFPROC_DEBUG` and `COVERLET_DATACOLLECTOR_INPROC_DEBUG` env variable -``` +```shell set COVERLET_DATACOLLECTOR_OUTOFPROC_DEBUG=1 set COVERLET_DATACOLLECTOR_INPROC_DEBUG=1 ``` -You will be asked to attach a debugger through UI popup. +You will be asked to attach a debugger through UI popup. To enable exceptions log for in-process data collectors -``` +```shell set COVERLET_DATACOLLECTOR_INPROC_EXCEPTIONLOG_ENABLED=1 ``` diff --git a/Documentation/VSTestIntegration.md b/Documentation/VSTestIntegration.md index 4cc67383d..5cf2fa633 100644 --- a/Documentation/VSTestIntegration.md +++ b/Documentation/VSTestIntegration.md @@ -2,28 +2,25 @@ **Supported runtime versions**: -Before version `3.0.0` -- .NET Core >= 2.0 -- .NET Framework not fully supported(only out of process collector, could suffer of [known issue](KnownIssues.md#1-vstest-stops-process-execution-earlydotnet-test)) +Since version `6.0.0` -Since version `3.0.0` -- .NET Core >= 2.0 -- .NET Framework >= 4.6.1 +* .NET Core >= 6.0 +* .NET Framework >= 4.6.2 -As explained in quick start section, to use collectors you need to run *SDK v2.2.401* or newer and your project file must reference `coverlet.collector.dll` and a minimum version of `Microsoft.NET.Test.Sdk`. +As explained in quick start section, to use collectors you need to run *SDK v6.0.100* (LTS) or newer and your project file must reference `coverlet.collector` and a minimum version of `Microsoft.NET.Test.Sdk`. A sample project file looks like: ```xml - netcoreapp3.0;netcoreapp2.1;net46 + net6.0;net48 - - + + - + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -37,13 +34,13 @@ The reference to `coverlet.collector` package is included by default with xunit With correct reference in place you can run coverage through default dotnet test CLI verbs: -``` +```shell dotnet test --collect:"XPlat Code Coverage" ``` or -``` +```text dotnet publish ... ... -> C:\project\bin\Debug\netcoreapp3.0\testdll.dll @@ -56,7 +53,7 @@ As you can see in case of `vstest` verb you **must** publish project before. At the end of tests you'll find the coverage file data under default VSTest platform directory `TestResults` -``` +```text Attachments: C:\git\coverlet\Documentation\Examples\VSTest\HelloWorld\XUnitTestProject1\TestResults\bc5e983b-d7a8-4f17-8c0a-8a8831a4a891\coverage.cobertura.xml Test Run Successful. @@ -66,29 +63,31 @@ Total tests: 1 ``` You can change the position of files using standard `dotnet test` switch `[-r|--results-directory]` - -*NB: By design VSTest platform will create your file under a random named folder(guid string) so if you need stable path to load file to some gui report system(i.e. coveralls, codecov, reportgenerator etc..) that doesn't support glob patterns or hierarchical search, you'll need to manually move resulting file to a predictable folder* +>*NB: By design VSTest platform will create your file under a random named folder(guid string) so if you need stable path to load file to some gui report system(i.e. coveralls, codecov, reportgenerator etc..) that doesn't support glob patterns or hierarchical search, you'll need to manually move resulting file to a predictable folder* ## Coverlet options supported by VSTest integration At the moment VSTest integration doesn't support all features of msbuild and .NET tool, for instance show result on console, report merging and threshold validation. -We're working to fill the gaps. -*PS: if you don't have any other way to merge reports(for instance your report generator doesn't support multi coverage file) you can for the moment exploit a trick reported by one of our contributor Daniel Paz(@p4p3) https://github.com/tonerdo/coverlet/pull/225#issuecomment-573896446* +We're working to fill the gaps. +>*PS: if you don't have any other way to merge reports(for instance your report generator doesn't support multi coverage file) you can for the moment exploit a trick reported by one of our contributor Daniel Paz(@p4p3) * ### Default option (if you don't specify a runsettings file) Without specifying a runsettings file and calling coverlet by just the name of the collector, the result of the generated coverage output is by default in cobertura format. -``` + +```shell dotnet test --collect:"XPlat Code Coverage" ``` The output format of the coverage report can also be changed without a runsettings file by specifying it in a parameter. The supported formats are lcov, opencover, cobertura, teamcity, json (default coverlet proprietary format). -``` + +```shell dotnet test --collect:"XPlat Code Coverage;Format=json" ``` It is even possible to specify the coverage output in multiple formats. -``` + +```shell dotnet test --collect:"XPlat Code Coverage;Format=json,lcov,cobertura" ``` @@ -98,12 +97,12 @@ These are a list of options that are supported by coverlet. These can be specifi | Option | Summary | |:-------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------| -| Format | Coverage output format. These are either cobertura, json, lcov, opencover or teamcity as well as combinations of these formats. | -| Exclude | Exclude from code coverage analysing using filter expressions. | -| ExcludeByFile | Ignore specific source files from code coverage. | -| Include | Explicitly set what to include in code coverage analysis using filter expressions. | +| Format | Coverage output format. These are either cobertura, json, lcov, opencover or teamcity as well as combinations of these formats. | +| Exclude | Exclude from code coverage analysing using filter expressions. | +| ExcludeByFile | Ignore specific source files from code coverage. | +| Include | Explicitly set what to include in code coverage analysis using filter expressions. | | IncludeDirectory | Explicitly set which directories to include in code coverage analysis. | -| SingleHit | Specifies whether to limit code coverage hit reporting to a single hit for each location. | +| SingleHit | Specifies whether to limit code coverage hit reporting to a single hit for each location. | | UseSourceLink | Specifies whether to use SourceLink URIs in place of file system paths. | | IncludeTestAssembly | Include coverage of the test assembly. | | SkipAutoProps | Neither track nor record auto-implemented properties. | @@ -113,14 +112,14 @@ These are a list of options that are supported by coverlet. These can be specifi How to specify these options via runsettings? -``` +```xml - json,cobertura,lcov,teamcity,opencover + json,cobertura,lcov,teamcity,opencover [coverlet.*.tests?]*,[*]Coverlet.Core* [coverlet.*]*,[*]Coverlet.Core* Obsolete,GeneratedCodeAttribute,CompilerGeneratedAttribute @@ -138,13 +137,13 @@ How to specify these options via runsettings? ``` + Filtering details are present on [msbuild guide](MSBuildIntegration.md#excluding-from-coverage). This runsettings file can easily be provided using command line option as given : -1. `dotnet test --collect:"XPlat Code Coverage" --settings coverlet.runsettings` - -2. `dotnet vstest C:\project\bin\Debug\netcoreapp3.0\publish\testdll.dll --collect:"XPlat Code Coverage" --settings coverlet.runsettings` +* `dotnet test --collect:"XPlat Code Coverage" --settings coverlet.runsettings` +* `dotnet vstest C:\project\bin\Debug\netcoreapp3.0\publish\testdll.dll --collect:"XPlat Code Coverage" --settings coverlet.runsettings` Take a look at our [`HelloWorld`](Examples/VSTest/HelloWorld/HowTo.md) sample. @@ -154,20 +153,20 @@ You can avoid passing a `runsettings` file to `dotnet test` driver by using the For instance if you want to set the `Format` element as a runsettings option you can use this syntax: -``` +```shell dotnet test --collect:"XPlat Code Coverage" -- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.Format=json,cobertura,lcov,teamcity,opencover ``` -Take a look here for further information: https://github.com/microsoft/vstest-docs/blob/master/docs/RunSettingsArguments.md +Take a look here for further information: ## How it works -Coverlet integration is implemented with the help of [datacollectors](https://github.com/Microsoft/vstest-docs/blob/master/docs/extensions/datacollector.md). +Coverlet integration is implemented with the help of [datacollectors](https://github.com/Microsoft/vstest-docs/blob/master/docs/extensions/datacollector.md). When we specify `--collect:"XPlat Code Coverage"` VSTest platform tries to load coverlet collectors inside `coverlet.collector.dll` 1. Out-of-proc Datacollector: The outproc collector run in a separate process(datacollector.exe/datacollector.dll) than the process in which tests are being executed(testhost*.exe/testhost.dll). This datacollector is responsible for calling into Coverlet APIs for instrumenting dlls, collecting coverage results and sending the coverage output file back to test platform. -2. In-proc Datacollector: The in-proc collector is loaded in the testhost process executing the tests. This collector will be needed to remove the dependency on the process exit handler to flush the hit files and avoid to hit this [serious known issue](KnownIssues.md#1-vstest-stops-process-execution-earlydotnet-test) +1. In-proc Datacollector: The in-proc collector is loaded in the testhost process executing the tests. This collector will be needed to remove the dependency on the process exit handler to flush the hit files and avoid to hit this [serious known issue](KnownIssues.md#1-vstest-stops-process-execution-earlydotnet-test) ## Known Issues diff --git a/src/coverlet.collector/coverlet.collector.csproj b/src/coverlet.collector/coverlet.collector.csproj index 0f64db543..1459d5e69 100644 --- a/src/coverlet.collector/coverlet.collector.csproj +++ b/src/coverlet.collector/coverlet.collector.csproj @@ -5,10 +5,10 @@ true true false - true @@ -29,6 +29,8 @@ false Coverlet is a cross platform code coverage library for .NET, with support for line, branch and method coverage. coverage testing unit-test lcov opencover quality + VSTestIntegration.md + https://github.com/coverlet-coverage/coverlet/blob/master/Documentation/Changelog.md git @@ -39,6 +41,9 @@ + + true + diff --git a/src/coverlet.msbuild.tasks/coverlet.msbuild.tasks.csproj b/src/coverlet.msbuild.tasks/coverlet.msbuild.tasks.csproj index 0dbef0361..74fc19631 100644 --- a/src/coverlet.msbuild.tasks/coverlet.msbuild.tasks.csproj +++ b/src/coverlet.msbuild.tasks/coverlet.msbuild.tasks.csproj @@ -8,10 +8,10 @@ $(TargetsForTfmSpecificContentInPackage);PackBuildOutputs build false - true @@ -30,6 +30,8 @@ true Coverlet is a cross platform code coverage library for .NET, with support for line, branch and method coverage. coverage testing unit-test lcov opencover quality + MSBuildIntegration.md + https://github.com/coverlet-coverage/coverlet/blob/master/Documentation/Changelog.md git @@ -48,10 +50,14 @@ + + + true + From e1ab9e8f526793e958d210b9ef9b3a7300a2c8be Mon Sep 17 00:00:00 2001 From: Bert Date: Thu, 10 Aug 2023 08:13:21 +0200 Subject: [PATCH 11/25] change limitation formatting --- Documentation/VSTestIntegration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/VSTestIntegration.md b/Documentation/VSTestIntegration.md index 5cf2fa633..93018d5f0 100644 --- a/Documentation/VSTestIntegration.md +++ b/Documentation/VSTestIntegration.md @@ -67,7 +67,7 @@ You can change the position of files using standard `dotnet test` switch `[-r|-- ## Coverlet options supported by VSTest integration -At the moment VSTest integration doesn't support all features of msbuild and .NET tool, for instance show result on console, report merging and threshold validation. +:warning:At the moment VSTest integration **doesn't support all features** of msbuild and .NET tool, for instance show result on console, report merging and threshold validation. We're working to fill the gaps. >*PS: if you don't have any other way to merge reports(for instance your report generator doesn't support multi coverage file) you can for the moment exploit a trick reported by one of our contributor Daniel Paz(@p4p3) * From d729057f601d596325305134ac14669e12f9f148 Mon Sep 17 00:00:00 2001 From: Bert Date: Sat, 12 Aug 2023 11:14:28 +0200 Subject: [PATCH 12/25] update requirements --- README.md | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 14a346410..d9bcb1219 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,16 @@ # Coverlet -[![Build Status](https://dev.azure.com/tonerdo/coverlet/_apis/build/status/coverlet-coverage.coverlet?branchName=master)](https://dev.azure.com/tonerdo/coverlet/_build/latest?definitionId=5&branchName=master) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/coverlet-coverage/coverlet/blob/master/LICENSE) +[![Build Status](https://dev.azure.com/tonerdo/coverlet/_apis/build/status/coverlet-coverage.coverlet?branchName=master)](https://dev.azure.com/tonerdo/coverlet/_build/latest?definitionId=5&branchName=master) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/coverlet-coverage/coverlet/blob/master/LICENSE) | Driver | Current version | Downloads | |---|---|---| -| coverlet.collector | [![NuGet](https://img.shields.io/nuget/v/coverlet.collector.svg)](https://www.nuget.org/packages/coverlet.collector/) | [![NuGet](https://img.shields.io/nuget/dt/coverlet.collector.svg)](https://www.nuget.org/packages/coverlet.collector/) +| coverlet.collector | [![NuGet](https://img.shields.io/nuget/v/coverlet.collector.svg)](https://www.nuget.org/packages/coverlet.collector/) | [![NuGet](https://img.shields.io/nuget/dt/coverlet.collector.svg)](https://www.nuget.org/packages/coverlet.collector/) | coverlet.msbuild | [![NuGet](https://img.shields.io/nuget/v/coverlet.msbuild.svg)](https://www.nuget.org/packages/coverlet.msbuild/) | [![NuGet](https://img.shields.io/nuget/dt/coverlet.msbuild.svg)](https://www.nuget.org/packages/coverlet.msbuild/) | | coverlet.console | [![NuGet](https://img.shields.io/nuget/v/coverlet.console.svg)](https://www.nuget.org/packages/coverlet.console/) | [![NuGet](https://img.shields.io/nuget/dt/coverlet.console.svg)](https://www.nuget.org/packages/coverlet.console/) | Coverlet is a cross platform code coverage framework for .NET, with support for line, branch and method coverage. It works with .NET Framework on Windows and .NET Core on all supported platforms. -**Coverlet documentation reflect the current repository state of the features, not the released ones.** +**Coverlet documentation reflect the current repository state of the features, not the released ones.** **Check the [changelog](Documentation/Changelog.md) to understand if the documented feature you want to use has been officially released.** # Main contents @@ -28,14 +28,13 @@ Coverlet is a cross platform code coverage framework for .NET, with support for ## Quick Start -Coverlet can be used through three different *drivers* +Coverlet can be used through three different *drivers* * VSTest engine integration * MSBuild task integration * As a .NET Global tool (supports standalone integration tests) -Coverlet supports only SDK-style projects https://docs.microsoft.com/en-us/visualstudio/msbuild/how-to-use-project-sdk?view=vs-2019 - +Coverlet supports only SDK-style projects https://docs.microsoft.com/en-us/visualstudio/msbuild/how-to-use-project-sdk?view=vs-2019 ### VSTest Integration (preferred due to [known issue](https://github.com/coverlet-coverage/coverlet/blob/master/Documentation/KnownIssues.md#1-vstest-stops-process-execution-earlydotnet-test)) @@ -57,8 +56,8 @@ After the above command is run, a `coverage.cobertura.xml` file containing the r See [documentation](Documentation/VSTestIntegration.md) for advanced usage. #### Requirements -* _You need to be running .NET Core SDK v2.2.401 or newer_ -* _You need to reference version 16.5.0 and above of Microsoft.NET.Test.Sdk_ +* _You need to be running .NET 6.0 SDK v6.0.316 or newer_ +* _You need to reference version 17.5.0 and above of Microsoft.NET.Test.Sdk_ ``` ``` @@ -69,7 +68,7 @@ See [documentation](Documentation/VSTestIntegration.md) for advanced usage. ```bash dotnet add package coverlet.msbuild ``` -N.B. You **MUST** add package only to test projects +N.B. You **MUST** add package only to test projects ### Usage @@ -111,7 +110,7 @@ See [documentation](Documentation/GlobalTool.md) for advanced usage. #### Requirements .NET global tools rely on a .NET Core runtime installed on your machine https://docs.microsoft.com/en-us/dotnet/core/tools/global-tools#what-could-go-wrong -.NET Coverlet global tool requires _.NET Core 2.2 and above_ +.NET Coverlet global tool requires _.NET Core 2.2 and above_ ## How It Works @@ -131,14 +130,14 @@ Coverlet generates code coverage information by going through the following proc ## Deterministic build support -Coverlet supports coverage for deterministic builds. The solution at the moment is not optimal and need a workaround. +Coverlet supports coverage for deterministic builds. The solution at the moment is not optimal and need a workaround. Take a look at [documentation](Documentation/DeterministicBuild.md). ## Are you in trouble with some feature? Check on [examples](Documentation/Examples.md)! ## Known Issues -Unfortunately we have some known issues, check it [here](Documentation/KnownIssues.md) +Unfortunately we have some known issues, check it [here](Documentation/KnownIssues.md) ## Cake Add-In @@ -166,12 +165,12 @@ If you find a bug or have a feature request, please report them at this reposito ## Coverlet Team -Author and owner -* [Toni Solarin-Sodara](https://github.com/tonerdo) +Author and owner +* [Toni Solarin-Sodara](https://github.com/tonerdo) Co-maintainers -* [Peter Liljenberg](https://github.com/petli) +* [Peter Liljenberg](https://github.com/petli) * [David Müller](https://github.com/daveMueller) * [Marco Rossignoli](https://github.com/MarcoRossignoli) @@ -188,6 +187,6 @@ Part of the code is based on work done by OpenCover team https://github.com/Open ## License -This project is licensed under the MIT license. See the [LICENSE](LICENSE) file for more info. - +This project is licensed under the MIT license. See the [LICENSE](LICENSE) file for more info. + ## Supported by the [.NET Foundation](https://dotnetfoundation.org/) From a3432e422a3c9cc798b47b45c5c2ca4e29517329 Mon Sep 17 00:00:00 2001 From: Bert Date: Sun, 13 Aug 2023 08:37:06 +0200 Subject: [PATCH 13/25] update Tmds.ExecFunction version and enable test execution with .NET 7.0 SDK --- Directory.Packages.props | 2 +- test/coverlet.core.tests/Reporters/JsonReporterTests.cs | 2 +- .../coverlet.tests.projectsample.fsharp.fsproj | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index e43c180b7..d8227c702 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -44,7 +44,7 @@ We can check minimum supported package version here https://github.com/Microsoft/vstest/blob/master/src/Microsoft.TestPlatform.ObjectModel/Microsoft.TestPlatform.ObjectModel.csproj#L34 --> - + diff --git a/test/coverlet.core.tests/Reporters/JsonReporterTests.cs b/test/coverlet.core.tests/Reporters/JsonReporterTests.cs index fb4dbd616..b1d95d29f 100644 --- a/test/coverlet.core.tests/Reporters/JsonReporterTests.cs +++ b/test/coverlet.core.tests/Reporters/JsonReporterTests.cs @@ -51,7 +51,7 @@ public void TestReport() result.Modules.Add("module", documents); var reporter = new JsonReporter(); - Assert.Equal(s_resultModule, reporter.Report(result, new Mock().Object)); + Assert.Equal(s_resultModule, reporter.Report(result, new Mock().Object), ignoreLineEndingDifferences: true); } } } diff --git a/test/coverlet.tests.projectsample.fsharp/coverlet.tests.projectsample.fsharp.fsproj b/test/coverlet.tests.projectsample.fsharp/coverlet.tests.projectsample.fsharp.fsproj index cd7a95969..14224c9a0 100644 --- a/test/coverlet.tests.projectsample.fsharp/coverlet.tests.projectsample.fsharp.fsproj +++ b/test/coverlet.tests.projectsample.fsharp/coverlet.tests.projectsample.fsharp.fsproj @@ -5,6 +5,7 @@ true false false + false From 4ebed44c91b3d36464b59928c5dee022826904ea Mon Sep 17 00:00:00 2001 From: Bert Date: Sun, 13 Aug 2023 08:59:01 +0200 Subject: [PATCH 14/25] add comment --- Directory.Packages.props | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Directory.Packages.props b/Directory.Packages.props index d8227c702..d0e3d9429 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -44,6 +44,10 @@ We can check minimum supported package version here https://github.com/Microsoft/vstest/blob/master/src/Microsoft.TestPlatform.ObjectModel/Microsoft.TestPlatform.ObjectModel.csproj#L34 --> + From a73616bdc4b03a560be9a23b7aab0dfbbcdb28d5 Mon Sep 17 00:00:00 2001 From: Bert Date: Tue, 15 Aug 2023 10:48:01 +0200 Subject: [PATCH 15/25] remove rollForward from global.json (conflict with rollForwardOnNoCandidateFx) --- eng/azure-pipelines-nightly.yml | 18 ++++-------------- eng/build.yml | 8 ++++---- global.json | 3 +-- .../coverlet.core.tests.csproj | 2 +- 4 files changed, 10 insertions(+), 21 deletions(-) diff --git a/eng/azure-pipelines-nightly.yml b/eng/azure-pipelines-nightly.yml index bb542fc5f..60dc036fc 100644 --- a/eng/azure-pipelines-nightly.yml +++ b/eng/azure-pipelines-nightly.yml @@ -4,23 +4,13 @@ pool: steps: - task: UseDotNet@2 inputs: - version: 6.0.408 - displayName: Install .NET Core SDK 6.0.408 + version: 6.0.413 + displayName: Install .NET Core SDK 6.0.413 - task: UseDotNet@2 inputs: - version: 7.0.203 - displayName: Install .NET Core SDK 7.0.203 - -- task: UseDotNet@2 - inputs: - version: 6.0.408 - displayName: Install .NET Core SDK 6.0.408 - -- task: UseDotNet@2 - inputs: - version: 7.0.203 - displayName: Install .NET Core SDK 7.0.203 + version: 7.0.400 + displayName: Install .NET Core SDK 7.0.400 - task: NuGetAuthenticate@0 displayName: Authenticate with NuGet feeds diff --git a/eng/build.yml b/eng/build.yml index 2b37cb1cb..b2e3a8f34 100644 --- a/eng/build.yml +++ b/eng/build.yml @@ -1,13 +1,13 @@ steps: - task: UseDotNet@2 inputs: - version: 6.0.408 - displayName: Install .NET Core SDK 6.0.408 + version: 6.0.413 + displayName: Install .NET Core SDK 6.0.413 - task: UseDotNet@2 inputs: - version: 7.0.203 - displayName: Install .NET Core SDK 7.0.203 + version: 7.0.400 + displayName: Install .NET Core SDK 7.0.400 - script: dotnet restore displayName: Restore packages diff --git a/global.json b/global.json index ccc54128c..06ce1b485 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,5 @@ { "sdk": { - "version": "6.0.410", - "rollForward": "latestMajor" + "version": "7.0.400" } } diff --git a/test/coverlet.core.tests/coverlet.core.tests.csproj b/test/coverlet.core.tests/coverlet.core.tests.csproj index 6e365070e..09eb7759a 100644 --- a/test/coverlet.core.tests/coverlet.core.tests.csproj +++ b/test/coverlet.core.tests/coverlet.core.tests.csproj @@ -4,7 +4,7 @@ net6.0 false - $(NoWarn);CS8002 + $(NoWarn);CS8002;NU1008 NU1702 true From 50451a746233b03cd0d8327bf755dad8d1f84371 Mon Sep 17 00:00:00 2001 From: Bert Date: Tue, 15 Aug 2023 10:54:53 +0200 Subject: [PATCH 16/25] incorporate review comments --- Directory.Packages.props | 1 - .../Examples/MSBuild/DeterministicBuild/HowTo.md | 16 +++++++--------- .../XUnitTestProject1/XUnitTestProject1.csproj | 1 - .../Examples/VSTest/DeterministicBuild/HowTo.md | 15 +++++++-------- .../XUnitTestProject1/XUnitTestProject1.csproj | 1 + Documentation/ReleasePlan.md | 16 ++++++++-------- eng/publish-coverlet-result-files.yml | 13 ++++--------- 7 files changed, 27 insertions(+), 36 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index d0e3d9429..024c47c61 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -10,7 +10,6 @@ - diff --git a/Documentation/Examples/MSBuild/DeterministicBuild/HowTo.md b/Documentation/Examples/MSBuild/DeterministicBuild/HowTo.md index 24bea3a46..7afec0315 100644 --- a/Documentation/Examples/MSBuild/DeterministicBuild/HowTo.md +++ b/Documentation/Examples/MSBuild/DeterministicBuild/HowTo.md @@ -24,14 +24,13 @@ Copyright (C) Microsoft Corporation. All rights reserved. coverlet.core -> C:\git\coverlet\src\coverlet.core\bin\Debug\netstandard2.0\coverlet.core.dll coverlet.collector -> C:\git\coverlet\src\coverlet.collector\bin\Debug\netcoreapp2.0\coverlet.collector.dll coverlet.msbuild.tasks -> C:\git\coverlet\src\coverlet.msbuild.tasks\bin\Debug\netstandard2.0\coverlet.msbuild.tasks.dll - coverlet.console -> C:\git\coverlet\src\coverlet.console\bin\Debug\netcoreapp2.2\coverlet.console.dll - coverlet.console -> C:\git\coverlet\src\coverlet.console\bin\Debug\netcoreapp2.2\coverlet.console.dll - Successfully created package 'C:\git\coverlet\bin\Debug\Packages\coverlet.collector.1.3.0-preview.6.ga0e22ec622.nupkg'. - Successfully created package 'C:\git\coverlet\bin\Debug\Packages\coverlet.console.1.7.2-preview.6.ga0e22ec622.nupkg'. - Successfully created package 'C:\git\coverlet\bin\Debug\Packages\coverlet.console.1.7.2-preview.6.ga0e22ec622.snupkg'. - Successfully created package 'C:\git\coverlet\bin\Debug\Packages\coverlet.collector.1.3.0-preview.6.ga0e22ec622.snupkg'. - Successfully created package 'C:\git\coverlet\bin\Debug\Packages\coverlet.msbuild.2.9.0-preview.6.ga0e22ec622.nupkg'. - Successfully created package 'C:\git\coverlet\bin\Debug\Packages\coverlet.msbuild.2.9.0-preview.6.ga0e22ec622.snupkg'. + coverlet.console -> C:\git\coverlet\src\coverlet.console\bin\Debug\net6.0\coverlet.console.dll + Successfully created package 'C:\git\coverlet\bin\Debug\Packages\coverlet.collector.6.0.1-preview.6.g918cd179e0.nupkg'. + Successfully created package 'C:\git\coverlet\bin\Debug\Packages\coverlet.collector.6.0.1-preview.6.g918cd179e0.snupkg'. + Successfully created package 'C:\git\coverlet\bin\Debug\Packages\coverlet.msbuild.6.0.1-preview.6.g918cd179e0.nupkg'. + Successfully created package 'C:\git\coverlet\bin\Debug\Packages\coverlet.msbuild.6.0.1-preview.6.g918cd179e0.snupkg'. + Successfully created package 'C:\git\coverlet\bin\Debug\Packages\coverlet.console.6.0.1-preview.6.g918cd179e0.nupkg'. + Successfully created package 'C:\git\coverlet\bin\Debug\Packages\coverlet.console.6.0.1-preview.6.g918cd179e0.snupkg'. ``` Add msbuild package version generated to `"..\Documentation\Examples\MSBuild\DeterministicBuild\XUnitTestProject1\XUnitTestProject1.csproj"` @@ -48,7 +47,6 @@ Add msbuild package version generated to `"..\Documentation\Examples\MSBuild\Det - all diff --git a/Documentation/Examples/MSBuild/DeterministicBuild/XUnitTestProject1/XUnitTestProject1.csproj b/Documentation/Examples/MSBuild/DeterministicBuild/XUnitTestProject1/XUnitTestProject1.csproj index 259cc2340..f59a5b534 100644 --- a/Documentation/Examples/MSBuild/DeterministicBuild/XUnitTestProject1/XUnitTestProject1.csproj +++ b/Documentation/Examples/MSBuild/DeterministicBuild/XUnitTestProject1/XUnitTestProject1.csproj @@ -9,7 +9,6 @@ - all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Documentation/Examples/VSTest/DeterministicBuild/HowTo.md b/Documentation/Examples/VSTest/DeterministicBuild/HowTo.md index 586cd4043..0e18ffafc 100644 --- a/Documentation/Examples/VSTest/DeterministicBuild/HowTo.md +++ b/Documentation/Examples/VSTest/DeterministicBuild/HowTo.md @@ -24,14 +24,13 @@ Copyright (C) Microsoft Corporation. All rights reserved. coverlet.core -> C:\git\coverlet\src\coverlet.core\bin\Debug\netstandard2.0\coverlet.core.dll coverlet.collector -> C:\git\coverlet\src\coverlet.collector\bin\Debug\netcoreapp2.0\coverlet.collector.dll coverlet.msbuild.tasks -> C:\git\coverlet\src\coverlet.msbuild.tasks\bin\Debug\netstandard2.0\coverlet.msbuild.tasks.dll - coverlet.console -> C:\git\coverlet\src\coverlet.console\bin\Debug\netcoreapp2.2\coverlet.console.dll - coverlet.console -> C:\git\coverlet\src\coverlet.console\bin\Debug\netcoreapp2.2\coverlet.console.dll - Successfully created package 'C:\git\coverlet\bin\Debug\Packages\coverlet.collector.1.3.0-preview.6.ga0e22ec622.nupkg'. - Successfully created package 'C:\git\coverlet\bin\Debug\Packages\coverlet.console.1.7.2-preview.6.ga0e22ec622.nupkg'. - Successfully created package 'C:\git\coverlet\bin\Debug\Packages\coverlet.console.1.7.2-preview.6.ga0e22ec622.snupkg'. - Successfully created package 'C:\git\coverlet\bin\Debug\Packages\coverlet.collector.1.3.0-preview.6.ga0e22ec622.snupkg'. - Successfully created package 'C:\git\coverlet\bin\Debug\Packages\coverlet.msbuild.2.9.0-preview.6.ga0e22ec622.nupkg'. - Successfully created package 'C:\git\coverlet\bin\Debug\Packages\coverlet.msbuild.2.9.0-preview.6.ga0e22ec622.snupkg'. + coverlet.console -> C:\git\coverlet\src\coverlet.console\bin\Debug\net6.0\coverlet.console.dll + Successfully created package 'C:\git\coverlet\bin\Debug\Packages\coverlet.collector.6.0.1-preview.6.g918cd179e0.nupkg'. + Successfully created package 'C:\git\coverlet\bin\Debug\Packages\coverlet.collector.6.0.1-preview.6.g918cd179e0.snupkg'. + Successfully created package 'C:\git\coverlet\bin\Debug\Packages\coverlet.msbuild.6.0.1-preview.6.g918cd179e0.nupkg'. + Successfully created package 'C:\git\coverlet\bin\Debug\Packages\coverlet.msbuild.6.0.1-preview.6.g918cd179e0.snupkg'. + Successfully created package 'C:\git\coverlet\bin\Debug\Packages\coverlet.console.6.0.1-preview.6.g918cd179e0.nupkg'. + Successfully created package 'C:\git\coverlet\bin\Debug\Packages\coverlet.console.6.0.1-preview.6.g918cd179e0.snupkg'. ``` Add collectors package version generated to `"..\Documentation\Examples\VSTest\DeterministicBuild\XUnitTestProject1\XUnitTestProject1.csproj"` diff --git a/Documentation/Examples/VSTest/HelloWorld/XUnitTestProject1/XUnitTestProject1.csproj b/Documentation/Examples/VSTest/HelloWorld/XUnitTestProject1/XUnitTestProject1.csproj index 33798c74c..87be69a78 100644 --- a/Documentation/Examples/VSTest/HelloWorld/XUnitTestProject1/XUnitTestProject1.csproj +++ b/Documentation/Examples/VSTest/HelloWorld/XUnitTestProject1/XUnitTestProject1.csproj @@ -3,6 +3,7 @@ net6.0 false + false diff --git a/Documentation/ReleasePlan.md b/Documentation/ReleasePlan.md index a9b7943c8..1adceaa6e 100644 --- a/Documentation/ReleasePlan.md +++ b/Documentation/ReleasePlan.md @@ -92,14 +92,14 @@ This is the steps to release new packages to nuget.org ```shell dotnet pack -c release /p:TF_BUILD=true /p:PublicRelease=true ... - coverlet.console -> D:\git\coverlet\src\coverlet.console\bin\Release\netcoreapp2.2\coverlet.console.dll - coverlet.console -> D:\git\coverlet\src\coverlet.console\bin\Release\netcoreapp2.2\publish\ - Successfully created package 'D:\git\coverlet\bin\Release\Packages\coverlet.msbuild.2.8.1.nupkg'. - Successfully created package 'D:\git\coverlet\bin\Release\Packages\coverlet.msbuild.2.8.1.snupkg'. - Successfully created package 'D:\git\coverlet\bin\Release\Packages\coverlet.console.1.7.1.nupkg'. - Successfully created package 'D:\git\coverlet\bin\Release\Packages\coverlet.console.1.7.1.snupkg'. - Successfully created package 'D:\git\coverlet\bin\Release\Packages\coverlet.collector.1.2.1.nupkg'. - Successfully created package 'D:\git\coverlet\bin\Release\Packages\coverlet.collector.1.2.1.snupkg'. + coverlet.console -> D:\git\coverlet\src\coverlet.console\bin\Release\net6.0\coverlet.console.dll + coverlet.console -> D:\git\coverlet\src\coverlet.console\bin\Release\net6.0\publish\ + Successfully created package 'D:\git\coverlet\bin\Release\Packages\coverlet.collector.6.0.1-preview.6.g918cd179e0.nupkg'. + Successfully created package 'D:\git\coverlet\bin\Release\Packages\coverlet.collector.6.0.1-preview.6.g918cd179e0.snupkg'. + Successfully created package 'D:\git\coverlet\bin\Release\Packages\coverlet.msbuild.6.0.1-preview.6.g918cd179e0.nupkg'. + Successfully created package 'D:\git\coverlet\bin\Release\Packages\coverlet.msbuild.6.0.1-preview.6.g918cd179e0.snupkg'. + Successfully created package 'D:\git\coverlet\bin\Release\Packages\coverlet.console.6.0.1-preview.6.g918cd179e0.nupkg'. + Successfully created package 'D:\git\coverlet\bin\Release\Packages\coverlet.console.6.0.1-preview.6.g918cd179e0.snupkg'. ``` 4. Sign the packages using SignClient tool diff --git a/eng/publish-coverlet-result-files.yml b/eng/publish-coverlet-result-files.yml index 0eb40bdc7..cca9a00c1 100644 --- a/eng/publish-coverlet-result-files.yml +++ b/eng/publish-coverlet-result-files.yml @@ -8,22 +8,17 @@ steps: New-Item -ItemType Directory "$(Build.SourcesDirectory)/artifacts/TestLogs/" function Copy-FileKeepPath { param ( - $filter,$FileToCopy,$des,$startIndex + $Filter,$FileToCopy,$Destination,$StartIndex ) - Get-ChildItem -Path $FileToCopy -Filter $filter -Recurse -File | ForEach-Object { + Get-ChildItem -Path $FileToCopy -Filter $Filter -Recurse -File | ForEach-Object { $fileName = $_.FullName - #Remove the first part to ignore from the path. - $newdes=Join-Path -Path $des -ChildPath $fileName.Substring($startIndex) - $folder=Split-Path -Path $newdes -Parent + $newDestination=Join-Path -Path $Destination -ChildPath $fileName.Substring($StartIndex) + $folder=Split-Path -Path $newDestination -Parent $err=0 - - #check if folder exists" $void=Get-Item $folder -ErrorVariable err -ErrorAction SilentlyContinue if($err.Count -ne 0){ - #create when it doesn't $void=New-Item -Path $folder -ItemType Directory -Force -Verbose } - $void=Copy-Item -Path $fileName -destination $newdes -Recurse -Container -Force -Verbose } } From c901ebfe1ae5951cc3a9c8741247555f4772f3b0 Mon Sep 17 00:00:00 2001 From: Bert Date: Tue, 15 Aug 2023 11:30:51 +0200 Subject: [PATCH 17/25] incorporate review comments --- .../XUnitTestProject1/XUnitTestProject1.csproj | 1 + eng/publish-coverlet-result-files.yml | 10 +++------- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/Documentation/Examples/VSTest/DeterministicBuild/XUnitTestProject1/XUnitTestProject1.csproj b/Documentation/Examples/VSTest/DeterministicBuild/XUnitTestProject1/XUnitTestProject1.csproj index 6144dfbd5..642b38552 100644 --- a/Documentation/Examples/VSTest/DeterministicBuild/XUnitTestProject1/XUnitTestProject1.csproj +++ b/Documentation/Examples/VSTest/DeterministicBuild/XUnitTestProject1/XUnitTestProject1.csproj @@ -3,6 +3,7 @@ net6.0 false + false diff --git a/eng/publish-coverlet-result-files.yml b/eng/publish-coverlet-result-files.yml index cca9a00c1..5f781e96b 100644 --- a/eng/publish-coverlet-result-files.yml +++ b/eng/publish-coverlet-result-files.yml @@ -14,17 +14,13 @@ steps: $fileName = $_.FullName $newDestination=Join-Path -Path $Destination -ChildPath $fileName.Substring($StartIndex) $folder=Split-Path -Path $newDestination -Parent - $err=0 - $void=Get-Item $folder -ErrorVariable err -ErrorAction SilentlyContinue - if($err.Count -ne 0){ - $void=New-Item -Path $folder -ItemType Directory -Force -Verbose - } - $void=Copy-Item -Path $fileName -destination $newdes -Recurse -Container -Force -Verbose + if (!(Test-Path -Path $folder)) {New-Item $folder -Type Directory -Force -Verbose} + Copy-Item -Path $fileName -Destination $newDestination -Recurse -Force -Verbose } } $logfiles = "coverage.opencover.xml", "coverage.cobertura.xml", "coverage.json", "log.txt", "log.datacollector.*.txt", "log.host.*.txt" foreach ($logfile in $logfiles ) { - Copy-FileKeepPath -FileToCopy "$(Build.SourcesDirectory)/test/coverlet.integration.tests/bin/*" -des "$(Build.SourcesDirectory)/artifacts/TestLogs/" -filter $logfile -startIndex "$(Build.SourcesDirectory)/test/coverlet.integration.tests/bin/".Length + Copy-FileKeepPath -FileToCopy "$(Build.SourcesDirectory)/test/*" -des "$(Build.SourcesDirectory)/artifacts/TestLogs/" -filter $logfile -startIndex "$(Build.SourcesDirectory)/test/coverlet.integration.tests/bin/".Length } continueOnError: true From 9c4fad5944f85867c15d89a63bfc8a8477edd215 Mon Sep 17 00:00:00 2001 From: Bert Date: Tue, 15 Aug 2023 11:48:42 +0200 Subject: [PATCH 18/25] run test only on windows plattform (net48 library) --- test/coverlet.core.tests/coverlet.core.tests.csproj | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/coverlet.core.tests/coverlet.core.tests.csproj b/test/coverlet.core.tests/coverlet.core.tests.csproj index 09eb7759a..9b6a3b4be 100644 --- a/test/coverlet.core.tests/coverlet.core.tests.csproj +++ b/test/coverlet.core.tests/coverlet.core.tests.csproj @@ -30,7 +30,10 @@ - + + + + From 40fffda0e7f14e4af99cf2856844f047ee278159 Mon Sep 17 00:00:00 2001 From: Bert Date: Tue, 15 Aug 2023 12:02:45 +0200 Subject: [PATCH 19/25] remove coverlet.tests.projectsample.vbmynamespace.vbproj from solution file --- coverlet.sln | 7 ------- 1 file changed, 7 deletions(-) diff --git a/coverlet.sln b/coverlet.sln index 6811c5e2a..c3392e38d 100644 --- a/coverlet.sln +++ b/coverlet.sln @@ -54,8 +54,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{9A8B19D4 test\Directory.Build.targets = test\Directory.Build.targets EndProjectSection EndProject -Project("{778DAE3C-4631-46EA-AA77-85C1314464D9}") = "coverlet.tests.projectsample.vbmynamespace", "test\coverlet.tests.projectsample.vbmynamespace\coverlet.tests.projectsample.vbmynamespace.vbproj", "{C9B7DC34-3E04-4F20-AED4-73791AF8020D}" -EndProject Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "coverlet.tests.projectsample.fsharp", "test\coverlet.tests.projectsample.fsharp\coverlet.tests.projectsample.fsharp.fsproj", "{1CBF6966-2A67-4D2C-8598-D174B83072F4}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "coverlet.tests.projectsample.netframework", "test\coverlet.tests.projectsample.netframework\coverlet.tests.projectsample.netframework.csproj", "{E69D68C9-78ED-4076-A14B-D07295A4B2A5}" @@ -136,10 +134,6 @@ Global {F8199E19-FA9A-4559-9101-CAD7028121B4}.Debug|Any CPU.Build.0 = Debug|Any CPU {F8199E19-FA9A-4559-9101-CAD7028121B4}.Release|Any CPU.ActiveCfg = Release|Any CPU {F8199E19-FA9A-4559-9101-CAD7028121B4}.Release|Any CPU.Build.0 = Release|Any CPU - {C9B7DC34-3E04-4F20-AED4-73791AF8020D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C9B7DC34-3E04-4F20-AED4-73791AF8020D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C9B7DC34-3E04-4F20-AED4-73791AF8020D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C9B7DC34-3E04-4F20-AED4-73791AF8020D}.Release|Any CPU.Build.0 = Release|Any CPU {1CBF6966-2A67-4D2C-8598-D174B83072F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1CBF6966-2A67-4D2C-8598-D174B83072F4}.Debug|Any CPU.Build.0 = Debug|Any CPU {1CBF6966-2A67-4D2C-8598-D174B83072F4}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -188,7 +182,6 @@ Global {5FF404AD-7C0B-465A-A1E9-558CDC642B0C} = {2FEBDE1B-83E3-445B-B9F8-5644B0E0E134} {F8199E19-FA9A-4559-9101-CAD7028121B4} = {2FEBDE1B-83E3-445B-B9F8-5644B0E0E134} {9A8B19D4-4A24-4217-AEFE-159B68F029A1} = {2FEBDE1B-83E3-445B-B9F8-5644B0E0E134} - {C9B7DC34-3E04-4F20-AED4-73791AF8020D} = {2FEBDE1B-83E3-445B-B9F8-5644B0E0E134} {1CBF6966-2A67-4D2C-8598-D174B83072F4} = {2FEBDE1B-83E3-445B-B9F8-5644B0E0E134} {E69D68C9-78ED-4076-A14B-D07295A4B2A5} = {2FEBDE1B-83E3-445B-B9F8-5644B0E0E134} {1C3CA3F8-DF8C-433F-8A56-69102D2BBDF6} = {2FEBDE1B-83E3-445B-B9F8-5644B0E0E134} From 007a9a1370aca47a2c8c51cedaa98f6ede731278 Mon Sep 17 00:00:00 2001 From: Bert Date: Tue, 15 Aug 2023 12:24:45 +0200 Subject: [PATCH 20/25] run Instrumenter_MethodsWithoutReferenceToSource_AreSkipped only for windows --- .../Instrumentation/InstrumenterTests.cs | 1151 +++++++++-------- 1 file changed, 577 insertions(+), 574 deletions(-) diff --git a/test/coverlet.core.tests/Instrumentation/InstrumenterTests.cs b/test/coverlet.core.tests/Instrumentation/InstrumenterTests.cs index 29605998b..572c1590f 100644 --- a/test/coverlet.core.tests/Instrumentation/InstrumenterTests.cs +++ b/test/coverlet.core.tests/Instrumentation/InstrumenterTests.cs @@ -12,6 +12,7 @@ using Coverlet.Core.Samples.Tests; using Coverlet.Core.Symbols; using Coverlet.Core.Tests; +using Coverlet.Tests.Xunit.Extensions; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Emit; @@ -22,346 +23,346 @@ namespace Coverlet.Core.Instrumentation.Tests { - public class InstrumenterTests : IDisposable - { - private readonly Mock _mockLogger = new(); - private Action _disposeAction; + public class InstrumenterTests : IDisposable + { + private readonly Mock _mockLogger = new(); + private Action _disposeAction; - public void Dispose() - { - _disposeAction?.Invoke(); - } + public void Dispose() + { + _disposeAction?.Invoke(); + } - [Fact] - public void TestCoreLibInstrumentation() - { - DirectoryInfo directory = Directory.CreateDirectory(Path.Combine(Directory.GetCurrentDirectory(), nameof(TestCoreLibInstrumentation))); - string[] files = new[] - { + [Fact] + public void TestCoreLibInstrumentation() + { + DirectoryInfo directory = Directory.CreateDirectory(Path.Combine(Directory.GetCurrentDirectory(), nameof(TestCoreLibInstrumentation))); + string[] files = new[] + { "System.Private.CoreLib.dll", "System.Private.CoreLib.pdb" }; - foreach (string file in files) - { - File.Copy(Path.Combine(Directory.GetCurrentDirectory(), "TestAssets", file), Path.Combine(directory.FullName, file), overwrite: true); - } + foreach (string file in files) + { + File.Copy(Path.Combine(Directory.GetCurrentDirectory(), "TestAssets", file), Path.Combine(directory.FullName, file), overwrite: true); + } - var partialMockFileSystem = new Mock(); - partialMockFileSystem.CallBase = true; - partialMockFileSystem.Setup(fs => fs.OpenRead(It.IsAny())).Returns((string path) => - { - if (Path.GetFileName(path.Replace(@"\", @"/")) == files[1]) - { - return File.OpenRead(Path.Combine(Path.Combine(Directory.GetCurrentDirectory(), "TestAssets"), files[1])); - } - else - { - return File.OpenRead(path); - } - }); - partialMockFileSystem.Setup(fs => fs.Exists(It.IsAny())).Returns((string path) => - { - if (Path.GetFileName(path.Replace(@"\", @"/")) == files[1]) - { - return File.Exists(Path.Combine(Path.Combine(Directory.GetCurrentDirectory(), "TestAssets"), files[1])); - } - else - { - if (path.Contains(@":\git\runtime")) - { - return true; - } - else - { - return File.Exists(path); - } - } - }); - var sourceRootTranslator = new SourceRootTranslator(_mockLogger.Object, new FileSystem()); - var parameters = new CoverageParameters(); - var instrumentationHelper = - new InstrumentationHelper(new ProcessExitHandler(), new RetryHelper(), partialMockFileSystem.Object, _mockLogger.Object, sourceRootTranslator); - var instrumenter = new Instrumenter(Path.Combine(directory.FullName, files[0]), "_coverlet_instrumented", parameters, _mockLogger.Object, instrumentationHelper, partialMockFileSystem.Object, sourceRootTranslator, new CecilSymbolHelper()); - - Assert.True(instrumenter.CanInstrument()); - InstrumenterResult result = instrumenter.Instrument(); - Assert.NotNull(result); - Assert.Equal(1052, result.Documents.Count); - foreach ((string docName, Document _) in result.Documents) - { - Assert.False(docName.EndsWith(@"System.Private.CoreLib\src\System\Threading\Interlocked.cs")); - } - directory.Delete(true); + var partialMockFileSystem = new Mock(); + partialMockFileSystem.CallBase = true; + partialMockFileSystem.Setup(fs => fs.OpenRead(It.IsAny())).Returns((string path) => + { + if (Path.GetFileName(path.Replace(@"\", @"/")) == files[1]) + { + return File.OpenRead(Path.Combine(Path.Combine(Directory.GetCurrentDirectory(), "TestAssets"), files[1])); } - - [Theory] - [InlineData(true)] - [InlineData(false)] - public void TestInstrument(bool singleHit) + else { - InstrumenterTest instrumenterTest = CreateInstrumentor(singleHit: singleHit); - - InstrumenterResult result = instrumenterTest.Instrumenter.Instrument(); - - Assert.Equal(Path.GetFileNameWithoutExtension(instrumenterTest.Module), result.Module); - Assert.Equal(instrumenterTest.Module, result.ModulePath); - - instrumenterTest.Directory.Delete(true); + return File.OpenRead(path); } - - [Theory] - [InlineData(true)] - [InlineData(false)] - public void TestInstrumentCoreLib(bool singleHit) + }); + partialMockFileSystem.Setup(fs => fs.Exists(It.IsAny())).Returns((string path) => + { + if (Path.GetFileName(path.Replace(@"\", @"/")) == files[1]) { - InstrumenterTest instrumenterTest = CreateInstrumentor(fakeCoreLibModule: true, singleHit: singleHit); - - InstrumenterResult result = instrumenterTest.Instrumenter.Instrument(); - - Assert.Equal(Path.GetFileNameWithoutExtension(instrumenterTest.Module), result.Module); - Assert.Equal(instrumenterTest.Module, result.ModulePath); - - instrumenterTest.Directory.Delete(true); + return File.Exists(Path.Combine(Path.Combine(Directory.GetCurrentDirectory(), "TestAssets"), files[1])); } - - [Theory] - [InlineData(typeof(ClassExcludedByCodeAnalysisCodeCoverageAttr))] - [InlineData(typeof(ClassExcludedByCoverletCodeCoverageAttr))] - public void TestInstrument_ClassesWithExcludeAttributeAreExcluded(Type excludedType) + else { - InstrumenterTest instrumenterTest = CreateInstrumentor(); - InstrumenterResult result = instrumenterTest.Instrumenter.Instrument(); + if (path.Contains(@":\git\runtime")) + { + return true; + } + else + { + return File.Exists(path); + } + } + }); + var sourceRootTranslator = new SourceRootTranslator(_mockLogger.Object, new FileSystem()); + var parameters = new CoverageParameters(); + var instrumentationHelper = + new InstrumentationHelper(new ProcessExitHandler(), new RetryHelper(), partialMockFileSystem.Object, _mockLogger.Object, sourceRootTranslator); + var instrumenter = new Instrumenter(Path.Combine(directory.FullName, files[0]), "_coverlet_instrumented", parameters, _mockLogger.Object, instrumentationHelper, partialMockFileSystem.Object, sourceRootTranslator, new CecilSymbolHelper()); + + Assert.True(instrumenter.CanInstrument()); + InstrumenterResult result = instrumenter.Instrument(); + Assert.NotNull(result); + Assert.Equal(1052, result.Documents.Count); + foreach ((string docName, Document _) in result.Documents) + { + Assert.False(docName.EndsWith(@"System.Private.CoreLib\src\System\Threading\Interlocked.cs")); + } + directory.Delete(true); + } - Document doc = result.Documents.Values.FirstOrDefault(d => Path.GetFileName(d.Path) == "Samples.cs"); - Assert.NotNull(doc); + [Theory] + [InlineData(true)] + [InlineData(false)] + public void TestInstrument(bool singleHit) + { + InstrumenterTest instrumenterTest = CreateInstrumentor(singleHit: singleHit); - bool found = doc.Lines.Values.Any(l => l.Class == excludedType.FullName); - Assert.False(found, "Class decorated with with exclude attribute should be excluded"); + InstrumenterResult result = instrumenterTest.Instrumenter.Instrument(); - instrumenterTest.Directory.Delete(true); - } + Assert.Equal(Path.GetFileNameWithoutExtension(instrumenterTest.Module), result.Module); + Assert.Equal(instrumenterTest.Module, result.ModulePath); - [Theory] - [InlineData(typeof(ClassExcludedByAttrWithoutAttributeNameSuffix), nameof(TestSDKAutoGeneratedCode))] - public void TestInstrument_ClassesWithExcludeAttributeWithoutAttributeNameSuffixAreExcluded(Type excludedType, string excludedAttribute) - { - InstrumenterTest instrumenterTest = CreateInstrumentor(attributesToIgnore: new string[] { excludedAttribute }); - InstrumenterResult result = instrumenterTest.Instrumenter.Instrument(); + instrumenterTest.Directory.Delete(true); + } - Document doc = result.Documents.Values.FirstOrDefault(d => Path.GetFileName(d.Path) == "Samples.cs"); - Assert.NotNull(doc); + [Theory] + [InlineData(true)] + [InlineData(false)] + public void TestInstrumentCoreLib(bool singleHit) + { + InstrumenterTest instrumenterTest = CreateInstrumentor(fakeCoreLibModule: true, singleHit: singleHit); - bool found = doc.Lines.Values.Any(l => l.Class == excludedType.FullName); - Assert.False(found, "Class decorated with with exclude attribute should be excluded"); + InstrumenterResult result = instrumenterTest.Instrumenter.Instrument(); - instrumenterTest.Directory.Delete(true); - } + Assert.Equal(Path.GetFileNameWithoutExtension(instrumenterTest.Module), result.Module); + Assert.Equal(instrumenterTest.Module, result.ModulePath); - [Theory] - [InlineData(nameof(ObsoleteAttribute))] - [InlineData("Obsolete")] - [InlineData(nameof(TestSDKAutoGeneratedCode))] - public void TestInstrument_ClassesWithCustomExcludeAttributeAreExcluded(string excludedAttribute) - { - InstrumenterTest instrumenterTest = CreateInstrumentor(attributesToIgnore: new string[] { excludedAttribute }); - InstrumenterResult result = instrumenterTest.Instrumenter.Instrument(); + instrumenterTest.Directory.Delete(true); + } - Document doc = result.Documents.Values.FirstOrDefault(d => Path.GetFileName(d.Path) == "Samples.cs"); - Assert.NotNull(doc); -#pragma warning disable CS0612 // Type or member is obsolete - bool found = doc.Lines.Values.Any(l => l.Class.Equals(nameof(ClassExcludedByObsoleteAttr))); -#pragma warning restore CS0612 // Type or member is obsolete - Assert.False(found, "Class decorated with with exclude attribute should be excluded"); + [Theory] + [InlineData(typeof(ClassExcludedByCodeAnalysisCodeCoverageAttr))] + [InlineData(typeof(ClassExcludedByCoverletCodeCoverageAttr))] + public void TestInstrument_ClassesWithExcludeAttributeAreExcluded(Type excludedType) + { + InstrumenterTest instrumenterTest = CreateInstrumentor(); + InstrumenterResult result = instrumenterTest.Instrumenter.Instrument(); - instrumenterTest.Directory.Delete(true); - } + Document doc = result.Documents.Values.FirstOrDefault(d => Path.GetFileName(d.Path) == "Samples.cs"); + Assert.NotNull(doc); - [Theory] - [InlineData(nameof(ObsoleteAttribute), "ClassWithMethodExcludedByObsoleteAttr")] - [InlineData("Obsolete", "ClassWithMethodExcludedByObsoleteAttr")] - [InlineData(nameof(TestSDKAutoGeneratedCode), "ClassExcludedByAttrWithoutAttributeNameSuffix")] - public void TestInstrument_ClassesWithMethodWithCustomExcludeAttributeAreExcluded(string excludedAttribute, string testClassName) - { - InstrumenterTest instrumenterTest = CreateInstrumentor(attributesToIgnore: new string[] { excludedAttribute }); - InstrumenterResult result = instrumenterTest.Instrumenter.Instrument(); + bool found = doc.Lines.Values.Any(l => l.Class == excludedType.FullName); + Assert.False(found, "Class decorated with with exclude attribute should be excluded"); - Document doc = result.Documents.Values.FirstOrDefault(d => Path.GetFileName(d.Path) == "Samples.cs"); - Assert.NotNull(doc); - bool found = doc.Lines.Values.Any(l => l.Method.Equals($"System.String Coverlet.Core.Samples.Tests.{testClassName}::Method(System.String)")); - Assert.False(found, "Method decorated with with exclude attribute should be excluded"); + instrumenterTest.Directory.Delete(true); + } - instrumenterTest.Directory.Delete(true); - } + [Theory] + [InlineData(typeof(ClassExcludedByAttrWithoutAttributeNameSuffix), nameof(TestSDKAutoGeneratedCode))] + public void TestInstrument_ClassesWithExcludeAttributeWithoutAttributeNameSuffixAreExcluded(Type excludedType, string excludedAttribute) + { + InstrumenterTest instrumenterTest = CreateInstrumentor(attributesToIgnore: new string[] { excludedAttribute }); + InstrumenterResult result = instrumenterTest.Instrumenter.Instrument(); - [Theory] - [InlineData(nameof(ObsoleteAttribute), "ClassWithMethodExcludedByObsoleteAttr")] - [InlineData("Obsolete", "ClassWithMethodExcludedByObsoleteAttr")] - [InlineData(nameof(TestSDKAutoGeneratedCode), "ClassExcludedByAttrWithoutAttributeNameSuffix")] - public void TestInstrument_ClassesWithPropertyWithCustomExcludeAttributeAreExcluded(string excludedAttribute, string testClassName) - { - InstrumenterTest instrumenterTest = CreateInstrumentor(attributesToIgnore: new string[] { excludedAttribute }); - InstrumenterResult result = instrumenterTest.Instrumenter.Instrument(); + Document doc = result.Documents.Values.FirstOrDefault(d => Path.GetFileName(d.Path) == "Samples.cs"); + Assert.NotNull(doc); - Document doc = result.Documents.Values.FirstOrDefault(d => Path.GetFileName(d.Path) == "Samples.cs"); - Assert.NotNull(doc); - bool getFound = doc.Lines.Values.Any(l => l.Method.Equals($"System.String Coverlet.Core.Samples.Tests.{testClassName}::get_Property()")); - Assert.False(getFound, "Property getter decorated with with exclude attribute should be excluded"); + bool found = doc.Lines.Values.Any(l => l.Class == excludedType.FullName); + Assert.False(found, "Class decorated with with exclude attribute should be excluded"); - bool setFound = doc.Lines.Values.Any(l => l.Method.Equals($"System.String Coverlet.Core.Samples.Tests.{testClassName}::set_Property()")); - Assert.False(setFound, "Property setter decorated with with exclude attribute should be excluded"); + instrumenterTest.Directory.Delete(true); + } - instrumenterTest.Directory.Delete(true); - } + [Theory] + [InlineData(nameof(ObsoleteAttribute))] + [InlineData("Obsolete")] + [InlineData(nameof(TestSDKAutoGeneratedCode))] + public void TestInstrument_ClassesWithCustomExcludeAttributeAreExcluded(string excludedAttribute) + { + InstrumenterTest instrumenterTest = CreateInstrumentor(attributesToIgnore: new string[] { excludedAttribute }); + InstrumenterResult result = instrumenterTest.Instrumenter.Instrument(); - private InstrumenterTest CreateInstrumentor(bool fakeCoreLibModule = false, string[] attributesToIgnore = null, string[] excludedFiles = null, bool singleHit = false) - { - string module = GetType().Assembly.Location; - string pdb = Path.Combine(Path.GetDirectoryName(module), Path.GetFileNameWithoutExtension(module) + ".pdb"); - string identifier = Guid.NewGuid().ToString(); + Document doc = result.Documents.Values.FirstOrDefault(d => Path.GetFileName(d.Path) == "Samples.cs"); + Assert.NotNull(doc); +#pragma warning disable CS0612 // Type or member is obsolete + bool found = doc.Lines.Values.Any(l => l.Class.Equals(nameof(ClassExcludedByObsoleteAttr))); +#pragma warning restore CS0612 // Type or member is obsolete + Assert.False(found, "Class decorated with with exclude attribute should be excluded"); - DirectoryInfo directory = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), identifier)); + instrumenterTest.Directory.Delete(true); + } - string destModule, destPdb; - if (fakeCoreLibModule) - { - destModule = "System.Private.CoreLib.dll"; - destPdb = "System.Private.CoreLib.pdb"; - } - else - { - destModule = Path.GetFileName(module); - destPdb = Path.GetFileName(pdb); - } + [Theory] + [InlineData(nameof(ObsoleteAttribute), "ClassWithMethodExcludedByObsoleteAttr")] + [InlineData("Obsolete", "ClassWithMethodExcludedByObsoleteAttr")] + [InlineData(nameof(TestSDKAutoGeneratedCode), "ClassExcludedByAttrWithoutAttributeNameSuffix")] + public void TestInstrument_ClassesWithMethodWithCustomExcludeAttributeAreExcluded(string excludedAttribute, string testClassName) + { + InstrumenterTest instrumenterTest = CreateInstrumentor(attributesToIgnore: new string[] { excludedAttribute }); + InstrumenterResult result = instrumenterTest.Instrumenter.Instrument(); - File.Copy(module, Path.Combine(directory.FullName, destModule), true); - File.Copy(pdb, Path.Combine(directory.FullName, destPdb), true); + Document doc = result.Documents.Values.FirstOrDefault(d => Path.GetFileName(d.Path) == "Samples.cs"); + Assert.NotNull(doc); + bool found = doc.Lines.Values.Any(l => l.Method.Equals($"System.String Coverlet.Core.Samples.Tests.{testClassName}::Method(System.String)")); + Assert.False(found, "Method decorated with with exclude attribute should be excluded"); - var instrumentationHelper = - new InstrumentationHelper(new ProcessExitHandler(), new RetryHelper(), new FileSystem(), new Mock().Object, new SourceRootTranslator(new Mock().Object, new FileSystem())); + instrumenterTest.Directory.Delete(true); + } - module = Path.Combine(directory.FullName, destModule); - CoverageParameters parameters = new() - { - ExcludeAttributes = attributesToIgnore, - DoesNotReturnAttributes = new string[] { "DoesNotReturnAttribute" } - }; - var instrumenter = new Instrumenter(module, identifier, parameters, _mockLogger.Object, instrumentationHelper, new FileSystem(), new SourceRootTranslator(_mockLogger.Object, new FileSystem()), new CecilSymbolHelper()); - return new InstrumenterTest - { - Instrumenter = instrumenter, - Module = module, - Identifier = identifier, - Directory = directory - }; - } + [Theory] + [InlineData(nameof(ObsoleteAttribute), "ClassWithMethodExcludedByObsoleteAttr")] + [InlineData("Obsolete", "ClassWithMethodExcludedByObsoleteAttr")] + [InlineData(nameof(TestSDKAutoGeneratedCode), "ClassExcludedByAttrWithoutAttributeNameSuffix")] + public void TestInstrument_ClassesWithPropertyWithCustomExcludeAttributeAreExcluded(string excludedAttribute, string testClassName) + { + InstrumenterTest instrumenterTest = CreateInstrumentor(attributesToIgnore: new string[] { excludedAttribute }); + InstrumenterResult result = instrumenterTest.Instrumenter.Instrument(); - class InstrumenterTest - { - public Instrumenter Instrumenter { get; set; } + Document doc = result.Documents.Values.FirstOrDefault(d => Path.GetFileName(d.Path) == "Samples.cs"); + Assert.NotNull(doc); + bool getFound = doc.Lines.Values.Any(l => l.Method.Equals($"System.String Coverlet.Core.Samples.Tests.{testClassName}::get_Property()")); + Assert.False(getFound, "Property getter decorated with with exclude attribute should be excluded"); - public string Module { get; set; } + bool setFound = doc.Lines.Values.Any(l => l.Method.Equals($"System.String Coverlet.Core.Samples.Tests.{testClassName}::set_Property()")); + Assert.False(setFound, "Property setter decorated with with exclude attribute should be excluded"); - public string Identifier { get; set; } + instrumenterTest.Directory.Delete(true); + } - public DirectoryInfo Directory { get; set; } - } + private InstrumenterTest CreateInstrumentor(bool fakeCoreLibModule = false, string[] attributesToIgnore = null, string[] excludedFiles = null, bool singleHit = false) + { + string module = GetType().Assembly.Location; + string pdb = Path.Combine(Path.GetDirectoryName(module), Path.GetFileNameWithoutExtension(module) + ".pdb"); + string identifier = Guid.NewGuid().ToString(); + + DirectoryInfo directory = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), identifier)); + + string destModule, destPdb; + if (fakeCoreLibModule) + { + destModule = "System.Private.CoreLib.dll"; + destPdb = "System.Private.CoreLib.pdb"; + } + else + { + destModule = Path.GetFileName(module); + destPdb = Path.GetFileName(pdb); + } + + File.Copy(module, Path.Combine(directory.FullName, destModule), true); + File.Copy(pdb, Path.Combine(directory.FullName, destPdb), true); + + var instrumentationHelper = + new InstrumentationHelper(new ProcessExitHandler(), new RetryHelper(), new FileSystem(), new Mock().Object, new SourceRootTranslator(new Mock().Object, new FileSystem())); + + module = Path.Combine(directory.FullName, destModule); + CoverageParameters parameters = new() + { + ExcludeAttributes = attributesToIgnore, + DoesNotReturnAttributes = new string[] { "DoesNotReturnAttribute" } + }; + var instrumenter = new Instrumenter(module, identifier, parameters, _mockLogger.Object, instrumentationHelper, new FileSystem(), new SourceRootTranslator(_mockLogger.Object, new FileSystem()), new CecilSymbolHelper()); + return new InstrumenterTest + { + Instrumenter = instrumenter, + Module = module, + Identifier = identifier, + Directory = directory + }; + } - [Fact] - public void TestInstrument_NetStandardAwareAssemblyResolver_FromRuntime() - { - var netstandardResolver = new NetstandardAwareAssemblyResolver(null, _mockLogger.Object); + class InstrumenterTest + { + public Instrumenter Instrumenter { get; set; } - // We ask for "official" netstandard.dll implementation with know MS public key cc7b13ffcd2ddd51 same in all runtime - AssemblyDefinition resolved = netstandardResolver.Resolve(AssemblyNameReference.Parse("netstandard, Version=0.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51")); - Assert.NotNull(resolved); + public string Module { get; set; } - // We check that netstandard.dll was resolved from runtime folder, where System.Object is - Assert.Equal(Path.Combine(Path.GetDirectoryName(typeof(object).Assembly.Location), "netstandard.dll"), resolved.MainModule.FileName); - } + public string Identifier { get; set; } - [Fact] - public void TestInstrument_NetStandardAwareAssemblyResolver_FromFolder() - { - // Someone could create a custom dll named netstandard.dll we need to be sure that not - // conflicts with "official" resolution - - // We create dummy netstandard.dll - var compilation = CSharpCompilation.Create( - "netstandard", - new[] { CSharpSyntaxTree.ParseText("") }, - new[] { MetadataReference.CreateFromFile(typeof(object).Assembly.Location) }, - new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); - - Assembly newAssemlby; - using (var dllStream = new MemoryStream()) - { - EmitResult emitResult = compilation.Emit(dllStream); - Assert.True(emitResult.Success); - newAssemlby = Assembly.Load(dllStream.ToArray()); - // remove if exists - File.Delete("netstandard.dll"); - File.WriteAllBytes("netstandard.dll", dllStream.ToArray()); - } + public DirectoryInfo Directory { get; set; } + } - var netstandardResolver = new NetstandardAwareAssemblyResolver(newAssemlby.Location, _mockLogger.Object); - AssemblyDefinition resolved = netstandardResolver.Resolve(AssemblyNameReference.Parse(newAssemlby.FullName)); + [Fact] + public void TestInstrument_NetStandardAwareAssemblyResolver_FromRuntime() + { + var netstandardResolver = new NetstandardAwareAssemblyResolver(null, _mockLogger.Object); - // We check if final netstandard.dll resolved is local folder one and not "official" netstandard.dll - Assert.Equal(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "netstandard.dll"), Path.GetFullPath(resolved.MainModule.FileName)); - } + // We ask for "official" netstandard.dll implementation with know MS public key cc7b13ffcd2ddd51 same in all runtime + AssemblyDefinition resolved = netstandardResolver.Resolve(AssemblyNameReference.Parse("netstandard, Version=0.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51")); + Assert.NotNull(resolved); - public static IEnumerable TestInstrument_ExcludedFilesHelper_Data() - { - yield return new object[] { new string[]{ @"one.txt" }, new ValueTuple[] + // We check that netstandard.dll was resolved from runtime folder, where System.Object is + Assert.Equal(Path.Combine(Path.GetDirectoryName(typeof(object).Assembly.Location), "netstandard.dll"), resolved.MainModule.FileName); + } + + [Fact] + public void TestInstrument_NetStandardAwareAssemblyResolver_FromFolder() + { + // Someone could create a custom dll named netstandard.dll we need to be sure that not + // conflicts with "official" resolution + + // We create dummy netstandard.dll + var compilation = CSharpCompilation.Create( + "netstandard", + new[] { CSharpSyntaxTree.ParseText("") }, + new[] { MetadataReference.CreateFromFile(typeof(object).Assembly.Location) }, + new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); + + Assembly newAssemlby; + using (var dllStream = new MemoryStream()) + { + EmitResult emitResult = compilation.Emit(dllStream); + Assert.True(emitResult.Success); + newAssemlby = Assembly.Load(dllStream.ToArray()); + // remove if exists + File.Delete("netstandard.dll"); + File.WriteAllBytes("netstandard.dll", dllStream.ToArray()); + } + + var netstandardResolver = new NetstandardAwareAssemblyResolver(newAssemlby.Location, _mockLogger.Object); + AssemblyDefinition resolved = netstandardResolver.Resolve(AssemblyNameReference.Parse(newAssemlby.FullName)); + + // We check if final netstandard.dll resolved is local folder one and not "official" netstandard.dll + Assert.Equal(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "netstandard.dll"), Path.GetFullPath(resolved.MainModule.FileName)); + } + + public static IEnumerable TestInstrument_ExcludedFilesHelper_Data() + { + yield return new object[] { new string[]{ @"one.txt" }, new ValueTuple[] { (@"one.txt", true, false), (@"c:\dir\one.txt", false, true), (@"dir/one.txt", false, false) }}; - yield return new object[] { new string[]{ @"*one.txt" }, new ValueTuple[] + yield return new object[] { new string[]{ @"*one.txt" }, new ValueTuple[] { (@"one.txt", true , false), (@"c:\dir\one.txt", false, true), (@"dir/one.txt", false, false) }}; - yield return new object[] { new string[]{ @"*.txt" }, new ValueTuple[] + yield return new object[] { new string[]{ @"*.txt" }, new ValueTuple[] { (@"one.txt", true, false), (@"c:\dir\one.txt", false, true), (@"dir/one.txt", false, false) }}; - yield return new object[] { new string[]{ @"*.*" }, new ValueTuple[] + yield return new object[] { new string[]{ @"*.*" }, new ValueTuple[] { (@"one.txt", true, false), (@"c:\dir\one.txt", false, true), (@"dir/one.txt", false, false) }}; - yield return new object[] { new string[]{ @"one.*" }, new ValueTuple[] + yield return new object[] { new string[]{ @"one.*" }, new ValueTuple[] { (@"one.txt", true, false), (@"c:\dir\one.txt", false, true), (@"dir/one.txt", false, false) }}; - yield return new object[] { new string[]{ @"dir/*.txt" }, new ValueTuple[] + yield return new object[] { new string[]{ @"dir/*.txt" }, new ValueTuple[] { (@"one.txt", false, false), (@"c:\dir\one.txt", true, true), (@"dir/one.txt", true, false) }}; - yield return new object[] { new string[]{ @"dir\*.txt" }, new ValueTuple[] + yield return new object[] { new string[]{ @"dir\*.txt" }, new ValueTuple[] { (@"one.txt", false, false), (@"c:\dir\one.txt", true, true), (@"dir/one.txt", true, false) }}; - yield return new object[] { new string[]{ @"**/*" }, new ValueTuple[] + yield return new object[] { new string[]{ @"**/*" }, new ValueTuple[] { (@"one.txt", true, false), (@"c:\dir\one.txt", true, true), (@"dir/one.txt", true, false) }}; - yield return new object[] { new string[]{ @"dir/**/*" }, new ValueTuple[] + yield return new object[] { new string[]{ @"dir/**/*" }, new ValueTuple[] { (@"one.txt", false, false), (@"c:\dir\one.txt", true, true), @@ -369,182 +370,182 @@ public static IEnumerable TestInstrument_ExcludedFilesHelper_Data() (@"c:\dir\dir2\one.txt", true, true), (@"dir/dir2/one.txt", true, false) }}; - yield return new object[] { new string[]{ @"one.txt", @"dir\*two.txt" }, new ValueTuple[] + yield return new object[] { new string[]{ @"one.txt", @"dir\*two.txt" }, new ValueTuple[] { (@"one.txt", true, false), (@"c:\dir\imtwo.txt", true, true), (@"dir/one.txt", false, false) }}; - // This is a special case test different drive same path - // We strip out drive from path to check for globbing - // BTW I don't know if makes sense add a filter with full path maybe we should forbid - yield return new object[] { new string[]{ @"c:\dir\one.txt" }, new ValueTuple[] + // This is a special case test different drive same path + // We strip out drive from path to check for globbing + // BTW I don't know if makes sense add a filter with full path maybe we should forbid + yield return new object[] { new string[]{ @"c:\dir\one.txt" }, new ValueTuple[] { (@"c:\dir\one.txt", true, true), (@"d:\dir\one.txt", true, true) // maybe should be false? }}; - yield return new object[] { new string[]{ null }, new ValueTuple[] + yield return new object[] { new string[]{ null }, new ValueTuple[] { (null, false, false), }}; - } + } - [Theory] - [MemberData(nameof(TestInstrument_ExcludedFilesHelper_Data))] - public void TestInstrument_ExcludedFilesHelper(string[] excludeFilterHelper, ValueTuple[] result) + [Theory] + [MemberData(nameof(TestInstrument_ExcludedFilesHelper_Data))] + public void TestInstrument_ExcludedFilesHelper(string[] excludeFilterHelper, ValueTuple[] result) + { + var exludeFilterHelper = new ExcludedFilesHelper(excludeFilterHelper, new Mock().Object); + foreach (ValueTuple checkFile in result) + { + if (checkFile.Item3) // run test only on windows platform { - var exludeFilterHelper = new ExcludedFilesHelper(excludeFilterHelper, new Mock().Object); - foreach (ValueTuple checkFile in result) - { - if (checkFile.Item3) // run test only on windows platform - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - Assert.Equal(checkFile.Item2, exludeFilterHelper.Exclude(checkFile.Item1)); - } - } - else - { - Assert.Equal(checkFile.Item2, exludeFilterHelper.Exclude(checkFile.Item1)); - } - } + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + Assert.Equal(checkFile.Item2, exludeFilterHelper.Exclude(checkFile.Item1)); + } } - - [Fact] - public void SkipEmbeddedPpdbWithoutLocalSource() + else { - string xunitDll = Directory.GetFiles(Directory.GetCurrentDirectory(), "xunit.core.dll").First(); - var loggerMock = new Mock(); - - var instrumentationHelper = - new InstrumentationHelper(new ProcessExitHandler(), new RetryHelper(), new FileSystem(), loggerMock.Object, - new SourceRootTranslator(xunitDll, new Mock().Object, new FileSystem(), new AssemblyAdapter())); - - var instrumenter = new Instrumenter(xunitDll, "_xunit_instrumented", new CoverageParameters(), loggerMock.Object, instrumentationHelper, new FileSystem(), new SourceRootTranslator(xunitDll, loggerMock.Object, new FileSystem(), new AssemblyAdapter()), new CecilSymbolHelper()); - Assert.True(instrumentationHelper.HasPdb(xunitDll, out bool embedded)); - Assert.True(embedded); - Assert.False(instrumenter.CanInstrument()); - loggerMock.Verify(l => l.LogVerbose(It.IsAny())); - - // Default case - string sample = Directory.GetFiles(Directory.GetCurrentDirectory(), "coverlet.tests.projectsample.empty.dll").First(); - instrumentationHelper = - new InstrumentationHelper(new ProcessExitHandler(), new RetryHelper(), new FileSystem(), new Mock().Object, - new SourceRootTranslator(Assembly.GetExecutingAssembly().Location, new Mock().Object, new FileSystem(), new AssemblyAdapter())); - - instrumenter = new Instrumenter(sample, "_coverlet_tests_projectsample_empty", new CoverageParameters(), loggerMock.Object, instrumentationHelper, new FileSystem(), new SourceRootTranslator(Assembly.GetExecutingAssembly().Location, loggerMock.Object, new FileSystem(), new AssemblyAdapter()), new CecilSymbolHelper()); - - Assert.True(instrumentationHelper.HasPdb(sample, out embedded)); - Assert.False(embedded); - Assert.True(instrumenter.CanInstrument()); - loggerMock.VerifyNoOtherCalls(); + Assert.Equal(checkFile.Item2, exludeFilterHelper.Exclude(checkFile.Item1)); } + } + } - [Fact] - public void SkipPpdbWithoutLocalSource() - { - string dllFileName = "75d9f96508d74def860a568f426ea4a4.dll"; - string pdbFileName = "75d9f96508d74def860a568f426ea4a4.pdb"; + [Fact] + public void SkipEmbeddedPpdbWithoutLocalSource() + { + string xunitDll = Directory.GetFiles(Directory.GetCurrentDirectory(), "xunit.core.dll").First(); + var loggerMock = new Mock(); + + var instrumentationHelper = + new InstrumentationHelper(new ProcessExitHandler(), new RetryHelper(), new FileSystem(), loggerMock.Object, + new SourceRootTranslator(xunitDll, new Mock().Object, new FileSystem(), new AssemblyAdapter())); + + var instrumenter = new Instrumenter(xunitDll, "_xunit_instrumented", new CoverageParameters(), loggerMock.Object, instrumentationHelper, new FileSystem(), new SourceRootTranslator(xunitDll, loggerMock.Object, new FileSystem(), new AssemblyAdapter()), new CecilSymbolHelper()); + Assert.True(instrumentationHelper.HasPdb(xunitDll, out bool embedded)); + Assert.True(embedded); + Assert.False(instrumenter.CanInstrument()); + loggerMock.Verify(l => l.LogVerbose(It.IsAny())); + + // Default case + string sample = Directory.GetFiles(Directory.GetCurrentDirectory(), "coverlet.tests.projectsample.empty.dll").First(); + instrumentationHelper = + new InstrumentationHelper(new ProcessExitHandler(), new RetryHelper(), new FileSystem(), new Mock().Object, + new SourceRootTranslator(Assembly.GetExecutingAssembly().Location, new Mock().Object, new FileSystem(), new AssemblyAdapter())); + + instrumenter = new Instrumenter(sample, "_coverlet_tests_projectsample_empty", new CoverageParameters(), loggerMock.Object, instrumentationHelper, new FileSystem(), new SourceRootTranslator(Assembly.GetExecutingAssembly().Location, loggerMock.Object, new FileSystem(), new AssemblyAdapter()), new CecilSymbolHelper()); + + Assert.True(instrumentationHelper.HasPdb(sample, out embedded)); + Assert.False(embedded); + Assert.True(instrumenter.CanInstrument()); + loggerMock.VerifyNoOtherCalls(); + } - var partialMockFileSystem = new Mock(); - partialMockFileSystem.CallBase = true; - partialMockFileSystem.Setup(fs => fs.OpenRead(It.IsAny())).Returns((string path) => - { - if (Path.GetFileName(path.Replace(@"\", @"/")) == pdbFileName) - { - return File.OpenRead(Path.Combine(Path.Combine(Directory.GetCurrentDirectory(), "TestAssets"), pdbFileName)); - } - else - { - return File.OpenRead(path); - } - }); - partialMockFileSystem.Setup(fs => fs.Exists(It.IsAny())).Returns((string path) => - { - if (Path.GetFileName(path.Replace(@"\", @"/")) == pdbFileName) - { - return File.Exists(Path.Combine(Path.Combine(Directory.GetCurrentDirectory(), "TestAssets"), pdbFileName)); - } - else - { - return File.Exists(path); - } - }); - - var instrumentationHelper = - new InstrumentationHelper(new ProcessExitHandler(), new RetryHelper(), partialMockFileSystem.Object, _mockLogger.Object, new SourceRootTranslator(_mockLogger.Object, new FileSystem())); - string sample = Directory.GetFiles(Path.Combine(Directory.GetCurrentDirectory(), "TestAssets"), dllFileName).First(); - var loggerMock = new Mock(); - var instrumenter = new Instrumenter(sample, "_75d9f96508d74def860a568f426ea4a4_instrumented", new CoverageParameters(), loggerMock.Object, instrumentationHelper, partialMockFileSystem.Object, new SourceRootTranslator(loggerMock.Object, new FileSystem()), new CecilSymbolHelper()); - - Assert.True(instrumentationHelper.HasPdb(sample, out bool embedded)); - Assert.False(embedded); - Assert.False(instrumenter.CanInstrument()); - _mockLogger.Verify(l => l.LogVerbose(It.IsAny())); + [Fact] + public void SkipPpdbWithoutLocalSource() + { + string dllFileName = "75d9f96508d74def860a568f426ea4a4.dll"; + string pdbFileName = "75d9f96508d74def860a568f426ea4a4.pdb"; + + var partialMockFileSystem = new Mock(); + partialMockFileSystem.CallBase = true; + partialMockFileSystem.Setup(fs => fs.OpenRead(It.IsAny())).Returns((string path) => + { + if (Path.GetFileName(path.Replace(@"\", @"/")) == pdbFileName) + { + return File.OpenRead(Path.Combine(Path.Combine(Directory.GetCurrentDirectory(), "TestAssets"), pdbFileName)); } - - [Fact] - public void TestInstrument_MissingModule() + else + { + return File.OpenRead(path); + } + }); + partialMockFileSystem.Setup(fs => fs.Exists(It.IsAny())).Returns((string path) => + { + if (Path.GetFileName(path.Replace(@"\", @"/")) == pdbFileName) + { + return File.Exists(Path.Combine(Path.Combine(Directory.GetCurrentDirectory(), "TestAssets"), pdbFileName)); + } + else { - var loggerMock = new Mock(); + return File.Exists(path); + } + }); + + var instrumentationHelper = + new InstrumentationHelper(new ProcessExitHandler(), new RetryHelper(), partialMockFileSystem.Object, _mockLogger.Object, new SourceRootTranslator(_mockLogger.Object, new FileSystem())); + string sample = Directory.GetFiles(Path.Combine(Directory.GetCurrentDirectory(), "TestAssets"), dllFileName).First(); + var loggerMock = new Mock(); + var instrumenter = new Instrumenter(sample, "_75d9f96508d74def860a568f426ea4a4_instrumented", new CoverageParameters(), loggerMock.Object, instrumentationHelper, partialMockFileSystem.Object, new SourceRootTranslator(loggerMock.Object, new FileSystem()), new CecilSymbolHelper()); + + Assert.True(instrumentationHelper.HasPdb(sample, out bool embedded)); + Assert.False(embedded); + Assert.False(instrumenter.CanInstrument()); + _mockLogger.Verify(l => l.LogVerbose(It.IsAny())); + } - var instrumentationHelper = - new InstrumentationHelper(new ProcessExitHandler(), new RetryHelper(), new FileSystem(), new Mock().Object, - new SourceRootTranslator(new Mock().Object, new FileSystem())); + [Fact] + public void TestInstrument_MissingModule() + { + var loggerMock = new Mock(); - var instrumenter = new Instrumenter("test", "_test_instrumented", new CoverageParameters(), loggerMock.Object, instrumentationHelper, new FileSystem(), new SourceRootTranslator(loggerMock.Object, new FileSystem()), new CecilSymbolHelper()); + var instrumentationHelper = + new InstrumentationHelper(new ProcessExitHandler(), new RetryHelper(), new FileSystem(), new Mock().Object, + new SourceRootTranslator(new Mock().Object, new FileSystem())); - Assert.False(instrumenter.CanInstrument()); - loggerMock.Verify(l => l.LogWarning(It.IsAny())); - } + var instrumenter = new Instrumenter("test", "_test_instrumented", new CoverageParameters(), loggerMock.Object, instrumentationHelper, new FileSystem(), new SourceRootTranslator(loggerMock.Object, new FileSystem()), new CecilSymbolHelper()); - [Fact] - public void CanInstrumentFSharpAssemblyWithAnonymousRecord() - { - var loggerMock = new Mock(); + Assert.False(instrumenter.CanInstrument()); + loggerMock.Verify(l => l.LogWarning(It.IsAny())); + } - string sample = Directory.GetFiles(Directory.GetCurrentDirectory(), "coverlet.tests.projectsample.fsharp.dll").First(); - var instrumentationHelper = - new InstrumentationHelper(new ProcessExitHandler(), new RetryHelper(), new FileSystem(), new Mock().Object, - new SourceRootTranslator(Assembly.GetExecutingAssembly().Location, new Mock().Object, new FileSystem(), new AssemblyAdapter())); + [Fact] + public void CanInstrumentFSharpAssemblyWithAnonymousRecord() + { + var loggerMock = new Mock(); - var instrumenter = new Instrumenter(sample, "_coverlet_tests_projectsample_fsharp", new CoverageParameters(), loggerMock.Object, instrumentationHelper, - new FileSystem(), new SourceRootTranslator(Assembly.GetExecutingAssembly().Location, loggerMock.Object, new FileSystem(), new AssemblyAdapter()), new CecilSymbolHelper()); + string sample = Directory.GetFiles(Directory.GetCurrentDirectory(), "coverlet.tests.projectsample.fsharp.dll").First(); + var instrumentationHelper = + new InstrumentationHelper(new ProcessExitHandler(), new RetryHelper(), new FileSystem(), new Mock().Object, + new SourceRootTranslator(Assembly.GetExecutingAssembly().Location, new Mock().Object, new FileSystem(), new AssemblyAdapter())); - Assert.True(instrumentationHelper.HasPdb(sample, out bool embedded)); - Assert.False(embedded); - Assert.True(instrumenter.CanInstrument()); - } + var instrumenter = new Instrumenter(sample, "_coverlet_tests_projectsample_fsharp", new CoverageParameters(), loggerMock.Object, instrumentationHelper, + new FileSystem(), new SourceRootTranslator(Assembly.GetExecutingAssembly().Location, loggerMock.Object, new FileSystem(), new AssemblyAdapter()), new CecilSymbolHelper()); - [Fact] - public void CanInstrument_AssemblySearchTypeNone_ReturnsTrue() - { - var loggerMock = new Mock(); - var instrumentationHelper = new Mock(); - bool embeddedPdb; - instrumentationHelper.Setup(x => x.HasPdb(It.IsAny(), out embeddedPdb)).Returns(true); + Assert.True(instrumentationHelper.HasPdb(sample, out bool embedded)); + Assert.False(embedded); + Assert.True(instrumenter.CanInstrument()); + } - var instrumenter = new Instrumenter(It.IsAny(), It.IsAny(), new CoverageParameters { ExcludeAssembliesWithoutSources = "None" }, - loggerMock.Object, instrumentationHelper.Object, new Mock().Object, new Mock().Object, new CecilSymbolHelper()); + [Fact] + public void CanInstrument_AssemblySearchTypeNone_ReturnsTrue() + { + var loggerMock = new Mock(); + var instrumentationHelper = new Mock(); + bool embeddedPdb; + instrumentationHelper.Setup(x => x.HasPdb(It.IsAny(), out embeddedPdb)).Returns(true); - Assert.True(instrumenter.CanInstrument()); - } + var instrumenter = new Instrumenter(It.IsAny(), It.IsAny(), new CoverageParameters { ExcludeAssembliesWithoutSources = "None" }, + loggerMock.Object, instrumentationHelper.Object, new Mock().Object, new Mock().Object, new CecilSymbolHelper()); - [Theory] - [InlineData("NotAMatch", new string[] { }, false)] - [InlineData("ExcludeFromCoverageAttribute", new string[] { }, true)] - [InlineData("ExcludeFromCodeCoverageAttribute", new string[] { }, true)] - [InlineData("CustomExclude", new string[] { "CustomExclude" }, true)] - [InlineData("CustomExcludeAttribute", new string[] { "CustomExclude" }, true)] - [InlineData("CustomExcludeAttribute", new string[] { "CustomExcludeAttribute" }, true)] - public void TestInstrument_AssemblyMarkedAsExcludeFromCodeCoverage(string attributeName, string[] excludedAttributes, bool expectedExcludes) - { - string EmitAssemblyToInstrument(string outputFolder) - { - SyntaxTree attributeClassSyntaxTree = CSharpSyntaxTree.ParseText("[System.AttributeUsage(System.AttributeTargets.Assembly)]public class " + attributeName + ":System.Attribute{}"); - SyntaxTree instrumentableClassSyntaxTree = CSharpSyntaxTree.ParseText($@" + Assert.True(instrumenter.CanInstrument()); + } + + [Theory] + [InlineData("NotAMatch", new string[] { }, false)] + [InlineData("ExcludeFromCoverageAttribute", new string[] { }, true)] + [InlineData("ExcludeFromCodeCoverageAttribute", new string[] { }, true)] + [InlineData("CustomExclude", new string[] { "CustomExclude" }, true)] + [InlineData("CustomExcludeAttribute", new string[] { "CustomExclude" }, true)] + [InlineData("CustomExcludeAttribute", new string[] { "CustomExcludeAttribute" }, true)] + public void TestInstrument_AssemblyMarkedAsExcludeFromCodeCoverage(string attributeName, string[] excludedAttributes, bool expectedExcludes) + { + string EmitAssemblyToInstrument(string outputFolder) + { + SyntaxTree attributeClassSyntaxTree = CSharpSyntaxTree.ParseText("[System.AttributeUsage(System.AttributeTargets.Assembly)]public class " + attributeName + ":System.Attribute{}"); + SyntaxTree instrumentableClassSyntaxTree = CSharpSyntaxTree.ParseText($@" [assembly:{attributeName}] namespace coverlet.tests.projectsample.excludedbyattribute{{ public class SampleClass @@ -557,164 +558,164 @@ public int SampleMethod() }} "); - CSharpCompilation compilation = CSharpCompilation.Create(attributeName, new List + CSharpCompilation compilation = CSharpCompilation.Create(attributeName, new List { attributeClassSyntaxTree,instrumentableClassSyntaxTree }).AddReferences( - MetadataReference.CreateFromFile(typeof(Attribute).Assembly.Location)). - WithOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, false)); + MetadataReference.CreateFromFile(typeof(Attribute).Assembly.Location)). + WithOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, false)); - string dllPath = Path.Combine(outputFolder, $"{attributeName}.dll"); - string pdbPath = Path.Combine(outputFolder, $"{attributeName}.pdb"); + string dllPath = Path.Combine(outputFolder, $"{attributeName}.dll"); + string pdbPath = Path.Combine(outputFolder, $"{attributeName}.pdb"); - using (FileStream outputStream = File.Create(dllPath)) - using (FileStream pdbStream = File.Create(pdbPath)) - { - bool isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); - var emitOptions = new EmitOptions(pdbFilePath: pdbPath); - EmitResult emitResult = compilation.Emit(outputStream, pdbStream, options: isWindows ? emitOptions : emitOptions.WithDebugInformationFormat(DebugInformationFormat.PortablePdb)); - if (!emitResult.Success) - { - string message = "Failure to dynamically create dll"; - foreach (Diagnostic diagnostic in emitResult.Diagnostics) - { - message += Environment.NewLine; - message += diagnostic.GetMessage(); - } - throw new Xunit.Sdk.XunitException(message); - } - } - return dllPath; - } - - string tempDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); - Directory.CreateDirectory(tempDirectory); - _disposeAction = () => Directory.Delete(tempDirectory, true); - - var partialMockFileSystem = new Mock(); - partialMockFileSystem.CallBase = true; - partialMockFileSystem.Setup(fs => fs.NewFileStream(It.IsAny(), It.IsAny(), It.IsAny())).Returns((string path, FileMode mode, FileAccess access) => + using (FileStream outputStream = File.Create(dllPath)) + using (FileStream pdbStream = File.Create(pdbPath)) + { + bool isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + var emitOptions = new EmitOptions(pdbFilePath: pdbPath); + EmitResult emitResult = compilation.Emit(outputStream, pdbStream, options: isWindows ? emitOptions : emitOptions.WithDebugInformationFormat(DebugInformationFormat.PortablePdb)); + if (!emitResult.Success) + { + string message = "Failure to dynamically create dll"; + foreach (Diagnostic diagnostic in emitResult.Diagnostics) { - return new FileStream(path, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite); - }); - var loggerMock = new Mock(); - - string excludedbyattributeDll = EmitAssemblyToInstrument(tempDirectory); - - var instrumentationHelper = - new InstrumentationHelper(new ProcessExitHandler(), new RetryHelper(), new FileSystem(), new Mock().Object, - new SourceRootTranslator(new Mock().Object, new FileSystem())); - CoverageParameters parametes = new(); - parametes.ExcludeAttributes = excludedAttributes; - var instrumenter = new Instrumenter(excludedbyattributeDll, "_xunit_excludedbyattribute", parametes, loggerMock.Object, instrumentationHelper, partialMockFileSystem.Object, new SourceRootTranslator(loggerMock.Object, new FileSystem()), new CecilSymbolHelper()); - - InstrumenterResult result = instrumenter.Instrument(); - Assert.Empty(result.Documents); - if (expectedExcludes) { loggerMock.Verify(l => l.LogVerbose(It.IsAny())); } + message += Environment.NewLine; + message += diagnostic.GetMessage(); + } + throw new Xunit.Sdk.XunitException(message); + } } + return dllPath; + } + + string tempDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); + Directory.CreateDirectory(tempDirectory); + _disposeAction = () => Directory.Delete(tempDirectory, true); + + var partialMockFileSystem = new Mock(); + partialMockFileSystem.CallBase = true; + partialMockFileSystem.Setup(fs => fs.NewFileStream(It.IsAny(), It.IsAny(), It.IsAny())).Returns((string path, FileMode mode, FileAccess access) => + { + return new FileStream(path, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite); + }); + var loggerMock = new Mock(); + + string excludedbyattributeDll = EmitAssemblyToInstrument(tempDirectory); + + var instrumentationHelper = + new InstrumentationHelper(new ProcessExitHandler(), new RetryHelper(), new FileSystem(), new Mock().Object, + new SourceRootTranslator(new Mock().Object, new FileSystem())); + CoverageParameters parametes = new(); + parametes.ExcludeAttributes = excludedAttributes; + var instrumenter = new Instrumenter(excludedbyattributeDll, "_xunit_excludedbyattribute", parametes, loggerMock.Object, instrumentationHelper, partialMockFileSystem.Object, new SourceRootTranslator(loggerMock.Object, new FileSystem()), new CecilSymbolHelper()); + + InstrumenterResult result = instrumenter.Instrument(); + Assert.Empty(result.Documents); + if (expectedExcludes) { loggerMock.Verify(l => l.LogVerbose(It.IsAny())); } + } - [Fact] - public void TestInstrument_NetstandardAwareAssemblyResolver_PreserveCompilationContext() - { - var netstandardResolver = new NetstandardAwareAssemblyResolver(Assembly.GetExecutingAssembly().Location, _mockLogger.Object); - AssemblyDefinition asm = netstandardResolver.TryWithCustomResolverOnDotNetCore(new AssemblyNameReference("Microsoft.Extensions.Logging.Abstractions", new Version("2.2.0"))); - Assert.NotNull(asm); - } + [Fact] + public void TestInstrument_NetstandardAwareAssemblyResolver_PreserveCompilationContext() + { + var netstandardResolver = new NetstandardAwareAssemblyResolver(Assembly.GetExecutingAssembly().Location, _mockLogger.Object); + AssemblyDefinition asm = netstandardResolver.TryWithCustomResolverOnDotNetCore(new AssemblyNameReference("Microsoft.Extensions.Logging.Abstractions", new Version("2.2.0"))); + Assert.NotNull(asm); + } - [Fact] - public void TestInstrument_LambdaInsideMethodWithExcludeAttributeAreExcluded() - { - InstrumenterTest instrumenterTest = CreateInstrumentor(); - InstrumenterResult result = instrumenterTest.Instrumenter.Instrument(); - - Document doc = result.Documents.Values.FirstOrDefault(d => Path.GetFileName(d.Path) == "Instrumentation.ExcludeFromCoverage.cs"); - Assert.NotNull(doc); - - Assert.Contains(doc.Lines.Values, l => l.Method == "System.Int32 Coverlet.Core.Samples.Tests.MethodsWithExcludeFromCodeCoverageAttr::TestLambda(System.String,System.Int32)"); - Assert.DoesNotContain(doc.Lines.Values, l => l.Method == "System.Int32 Coverlet.Core.Samples.Tests.MethodsWithExcludeFromCodeCoverageAttr::TestLambda(System.String)"); - Assert.DoesNotContain(doc.Lines.Values, l => l.Class.StartsWith("Coverlet.Core.Samples.Tests.MethodsWithExcludeFromCodeCoverageAttr/") && - instrumenterTest.Instrumenter.IsSynthesizedNameOf(l.Method, "TestLambda", 0)); - Assert.DoesNotContain(doc.Lines.Values, l => l.Method == "System.Int32 Coverlet.Core.Samples.Tests.MethodsWithExcludeFromCodeCoverageAttr2::TestLambda(System.String,System.Int32)"); - Assert.DoesNotContain(doc.Lines.Values, l => l.Class.StartsWith("Coverlet.Core.Samples.Tests.MethodsWithExcludeFromCodeCoverageAttr2/") && - instrumenterTest.Instrumenter.IsSynthesizedNameOf(l.Method, "TestLambda", 1)); - Assert.Contains(doc.Lines.Values, l => l.Method == "System.Int32 Coverlet.Core.Samples.Tests.MethodsWithExcludeFromCodeCoverageAttr2::TestLambda(System.String)"); - - instrumenterTest.Directory.Delete(true); - } + [Fact] + public void TestInstrument_LambdaInsideMethodWithExcludeAttributeAreExcluded() + { + InstrumenterTest instrumenterTest = CreateInstrumentor(); + InstrumenterResult result = instrumenterTest.Instrumenter.Instrument(); + + Document doc = result.Documents.Values.FirstOrDefault(d => Path.GetFileName(d.Path) == "Instrumentation.ExcludeFromCoverage.cs"); + Assert.NotNull(doc); + + Assert.Contains(doc.Lines.Values, l => l.Method == "System.Int32 Coverlet.Core.Samples.Tests.MethodsWithExcludeFromCodeCoverageAttr::TestLambda(System.String,System.Int32)"); + Assert.DoesNotContain(doc.Lines.Values, l => l.Method == "System.Int32 Coverlet.Core.Samples.Tests.MethodsWithExcludeFromCodeCoverageAttr::TestLambda(System.String)"); + Assert.DoesNotContain(doc.Lines.Values, l => l.Class.StartsWith("Coverlet.Core.Samples.Tests.MethodsWithExcludeFromCodeCoverageAttr/") && + instrumenterTest.Instrumenter.IsSynthesizedNameOf(l.Method, "TestLambda", 0)); + Assert.DoesNotContain(doc.Lines.Values, l => l.Method == "System.Int32 Coverlet.Core.Samples.Tests.MethodsWithExcludeFromCodeCoverageAttr2::TestLambda(System.String,System.Int32)"); + Assert.DoesNotContain(doc.Lines.Values, l => l.Class.StartsWith("Coverlet.Core.Samples.Tests.MethodsWithExcludeFromCodeCoverageAttr2/") && + instrumenterTest.Instrumenter.IsSynthesizedNameOf(l.Method, "TestLambda", 1)); + Assert.Contains(doc.Lines.Values, l => l.Method == "System.Int32 Coverlet.Core.Samples.Tests.MethodsWithExcludeFromCodeCoverageAttr2::TestLambda(System.String)"); + + instrumenterTest.Directory.Delete(true); + } - [Fact] - public void TestInstrument_LocalFunctionInsideMethodWithExcludeAttributeAreExcluded() - { - InstrumenterTest instrumenterTest = CreateInstrumentor(); - InstrumenterResult result = instrumenterTest.Instrumenter.Instrument(); - - Document doc = result.Documents.Values.FirstOrDefault(d => Path.GetFileName(d.Path) == "Instrumentation.ExcludeFromCoverage.cs"); - Assert.NotNull(doc); - - Assert.Contains(doc.Lines.Values, l => l.Method == "System.Int32 Coverlet.Core.Samples.Tests.MethodsWithExcludeFromCodeCoverageAttr::TestLocalFunction(System.String,System.Int32)"); - Assert.DoesNotContain(doc.Lines.Values, l => l.Method == "System.Int32 Coverlet.Core.Samples.Tests.MethodsWithExcludeFromCodeCoverageAttr::TestLocalFunction(System.String)"); - Assert.DoesNotContain(doc.Lines.Values, l => l.Class == "Coverlet.Core.Samples.Tests.MethodsWithExcludeFromCodeCoverageAttr" && - instrumenterTest.Instrumenter.IsSynthesizedNameOf(l.Method, "TestLocalFunction", 6)); - Assert.Contains(doc.Lines.Values, l => l.Class == "Coverlet.Core.Samples.Tests.MethodsWithExcludeFromCodeCoverageAttr" && - instrumenterTest.Instrumenter.IsSynthesizedNameOf(l.Method, "TestLocalFunction", 7)); - Assert.DoesNotContain(doc.Lines.Values, l => l.Method == "System.Int32 Coverlet.Core.Samples.Tests.MethodsWithExcludeFromCodeCoverageAttr2::TestLocalFunction(System.String,System.Int32)"); - Assert.DoesNotContain(doc.Lines.Values, l => l.Class == "Coverlet.Core.Samples.Tests.MethodsWithExcludeFromCodeCoverageAttr2" && - instrumenterTest.Instrumenter.IsSynthesizedNameOf(l.Method, "TestLocalFunction", 7)); - Assert.Contains(doc.Lines.Values, l => l.Method == "System.Int32 Coverlet.Core.Samples.Tests.MethodsWithExcludeFromCodeCoverageAttr2::TestLocalFunction(System.String)"); - Assert.Contains(doc.Lines.Values, l => l.Class == "Coverlet.Core.Samples.Tests.MethodsWithExcludeFromCodeCoverageAttr2" && - instrumenterTest.Instrumenter.IsSynthesizedNameOf(l.Method, "TestLocalFunction", 6)); - - instrumenterTest.Directory.Delete(true); - } + [Fact] + public void TestInstrument_LocalFunctionInsideMethodWithExcludeAttributeAreExcluded() + { + InstrumenterTest instrumenterTest = CreateInstrumentor(); + InstrumenterResult result = instrumenterTest.Instrumenter.Instrument(); + + Document doc = result.Documents.Values.FirstOrDefault(d => Path.GetFileName(d.Path) == "Instrumentation.ExcludeFromCoverage.cs"); + Assert.NotNull(doc); + + Assert.Contains(doc.Lines.Values, l => l.Method == "System.Int32 Coverlet.Core.Samples.Tests.MethodsWithExcludeFromCodeCoverageAttr::TestLocalFunction(System.String,System.Int32)"); + Assert.DoesNotContain(doc.Lines.Values, l => l.Method == "System.Int32 Coverlet.Core.Samples.Tests.MethodsWithExcludeFromCodeCoverageAttr::TestLocalFunction(System.String)"); + Assert.DoesNotContain(doc.Lines.Values, l => l.Class == "Coverlet.Core.Samples.Tests.MethodsWithExcludeFromCodeCoverageAttr" && + instrumenterTest.Instrumenter.IsSynthesizedNameOf(l.Method, "TestLocalFunction", 6)); + Assert.Contains(doc.Lines.Values, l => l.Class == "Coverlet.Core.Samples.Tests.MethodsWithExcludeFromCodeCoverageAttr" && + instrumenterTest.Instrumenter.IsSynthesizedNameOf(l.Method, "TestLocalFunction", 7)); + Assert.DoesNotContain(doc.Lines.Values, l => l.Method == "System.Int32 Coverlet.Core.Samples.Tests.MethodsWithExcludeFromCodeCoverageAttr2::TestLocalFunction(System.String,System.Int32)"); + Assert.DoesNotContain(doc.Lines.Values, l => l.Class == "Coverlet.Core.Samples.Tests.MethodsWithExcludeFromCodeCoverageAttr2" && + instrumenterTest.Instrumenter.IsSynthesizedNameOf(l.Method, "TestLocalFunction", 7)); + Assert.Contains(doc.Lines.Values, l => l.Method == "System.Int32 Coverlet.Core.Samples.Tests.MethodsWithExcludeFromCodeCoverageAttr2::TestLocalFunction(System.String)"); + Assert.Contains(doc.Lines.Values, l => l.Class == "Coverlet.Core.Samples.Tests.MethodsWithExcludeFromCodeCoverageAttr2" && + instrumenterTest.Instrumenter.IsSynthesizedNameOf(l.Method, "TestLocalFunction", 6)); + + instrumenterTest.Directory.Delete(true); + } - [Fact] - public void TestInstrument_YieldInsideMethodWithExcludeAttributeAreExcluded() - { - InstrumenterTest instrumenterTest = CreateInstrumentor(); - InstrumenterResult result = instrumenterTest.Instrumenter.Instrument(); - - Document doc = result.Documents.Values.FirstOrDefault(d => Path.GetFileName(d.Path) == "Instrumentation.ExcludeFromCoverage.cs"); - Assert.NotNull(doc); - - Assert.DoesNotContain(doc.Lines.Values, l => l.Class.StartsWith("Coverlet.Core.Samples.Tests.MethodsWithExcludeFromCodeCoverageAttr/") && - instrumenterTest.Instrumenter.IsSynthesizedNameOf(l.Method, "TestYield", 2)); - Assert.Contains(doc.Lines.Values, l => l.Class.StartsWith("Coverlet.Core.Samples.Tests.MethodsWithExcludeFromCodeCoverageAttr/") && - instrumenterTest.Instrumenter.IsSynthesizedNameOf(l.Method, "TestYield", 3)); - Assert.Contains(doc.Lines.Values, l => l.Class.StartsWith("Coverlet.Core.Samples.Tests.MethodsWithExcludeFromCodeCoverageAttr2/") && - instrumenterTest.Instrumenter.IsSynthesizedNameOf(l.Method, "TestYield", 2)); - Assert.DoesNotContain(doc.Lines.Values, l => l.Class.StartsWith("Coverlet.Core.Samples.Tests.MethodsWithExcludeFromCodeCoverageAttr2/") && - instrumenterTest.Instrumenter.IsSynthesizedNameOf(l.Method, "TestYield", 3)); - - instrumenterTest.Directory.Delete(true); - } + [Fact] + public void TestInstrument_YieldInsideMethodWithExcludeAttributeAreExcluded() + { + InstrumenterTest instrumenterTest = CreateInstrumentor(); + InstrumenterResult result = instrumenterTest.Instrumenter.Instrument(); + + Document doc = result.Documents.Values.FirstOrDefault(d => Path.GetFileName(d.Path) == "Instrumentation.ExcludeFromCoverage.cs"); + Assert.NotNull(doc); + + Assert.DoesNotContain(doc.Lines.Values, l => l.Class.StartsWith("Coverlet.Core.Samples.Tests.MethodsWithExcludeFromCodeCoverageAttr/") && + instrumenterTest.Instrumenter.IsSynthesizedNameOf(l.Method, "TestYield", 2)); + Assert.Contains(doc.Lines.Values, l => l.Class.StartsWith("Coverlet.Core.Samples.Tests.MethodsWithExcludeFromCodeCoverageAttr/") && + instrumenterTest.Instrumenter.IsSynthesizedNameOf(l.Method, "TestYield", 3)); + Assert.Contains(doc.Lines.Values, l => l.Class.StartsWith("Coverlet.Core.Samples.Tests.MethodsWithExcludeFromCodeCoverageAttr2/") && + instrumenterTest.Instrumenter.IsSynthesizedNameOf(l.Method, "TestYield", 2)); + Assert.DoesNotContain(doc.Lines.Values, l => l.Class.StartsWith("Coverlet.Core.Samples.Tests.MethodsWithExcludeFromCodeCoverageAttr2/") && + instrumenterTest.Instrumenter.IsSynthesizedNameOf(l.Method, "TestYield", 3)); + + instrumenterTest.Directory.Delete(true); + } - [Fact] - public void TestInstrument_AsyncAwaitInsideMethodWithExcludeAttributeAreExcluded() - { - InstrumenterTest instrumenterTest = CreateInstrumentor(); - InstrumenterResult result = instrumenterTest.Instrumenter.Instrument(); - - Document doc = result.Documents.Values.FirstOrDefault(d => Path.GetFileName(d.Path) == "Instrumentation.ExcludeFromCoverage.cs"); - Assert.NotNull(doc); - - Assert.DoesNotContain(doc.Lines.Values, l => l.Class.StartsWith("Coverlet.Core.Samples.Tests.MethodsWithExcludeFromCodeCoverageAttr/") && - instrumenterTest.Instrumenter.IsSynthesizedNameOf(l.Method, "TestAsyncAwait", 4)); - Assert.Contains(doc.Lines.Values, l => l.Class.StartsWith("Coverlet.Core.Samples.Tests.MethodsWithExcludeFromCodeCoverageAttr/") && - instrumenterTest.Instrumenter.IsSynthesizedNameOf(l.Method, "TestAsyncAwait", 5)); - Assert.Contains(doc.Lines.Values, l => l.Class.StartsWith("Coverlet.Core.Samples.Tests.MethodsWithExcludeFromCodeCoverageAttr2/") && - instrumenterTest.Instrumenter.IsSynthesizedNameOf(l.Method, "TestAsyncAwait", 4)); - Assert.DoesNotContain(doc.Lines.Values, l => l.Class.StartsWith("Coverlet.Core.Samples.Tests.MethodsWithExcludeFromCodeCoverageAttr2/") && - instrumenterTest.Instrumenter.IsSynthesizedNameOf(l.Method, "TestAsyncAwait", 5)); - - instrumenterTest.Directory.Delete(true); - } + [Fact] + public void TestInstrument_AsyncAwaitInsideMethodWithExcludeAttributeAreExcluded() + { + InstrumenterTest instrumenterTest = CreateInstrumentor(); + InstrumenterResult result = instrumenterTest.Instrumenter.Instrument(); + + Document doc = result.Documents.Values.FirstOrDefault(d => Path.GetFileName(d.Path) == "Instrumentation.ExcludeFromCoverage.cs"); + Assert.NotNull(doc); + + Assert.DoesNotContain(doc.Lines.Values, l => l.Class.StartsWith("Coverlet.Core.Samples.Tests.MethodsWithExcludeFromCodeCoverageAttr/") && + instrumenterTest.Instrumenter.IsSynthesizedNameOf(l.Method, "TestAsyncAwait", 4)); + Assert.Contains(doc.Lines.Values, l => l.Class.StartsWith("Coverlet.Core.Samples.Tests.MethodsWithExcludeFromCodeCoverageAttr/") && + instrumenterTest.Instrumenter.IsSynthesizedNameOf(l.Method, "TestAsyncAwait", 5)); + Assert.Contains(doc.Lines.Values, l => l.Class.StartsWith("Coverlet.Core.Samples.Tests.MethodsWithExcludeFromCodeCoverageAttr2/") && + instrumenterTest.Instrumenter.IsSynthesizedNameOf(l.Method, "TestAsyncAwait", 4)); + Assert.DoesNotContain(doc.Lines.Values, l => l.Class.StartsWith("Coverlet.Core.Samples.Tests.MethodsWithExcludeFromCodeCoverageAttr2/") && + instrumenterTest.Instrumenter.IsSynthesizedNameOf(l.Method, "TestAsyncAwait", 5)); + + instrumenterTest.Directory.Delete(true); + } - [Fact] - public void TestReachabilityHelper() - { - int[] allInstrumentableLines = - new[] - { + [Fact] + public void TestReachabilityHelper() + { + int[] allInstrumentableLines = + new[] + { // Throws 7, 8, // NoBranches @@ -739,10 +740,10 @@ public void TestReachabilityHelper() 147, 149, 150, 151, 152, 153, 154, 155, 156, 159, 161, 163, 166, 167, 168, // FiltersAndFinallies 171, 173, 174, 175, 176, 177, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 192, 193, 194, 195, 196, 197 - }; - int[] notReachableLines = - new[] - { + }; + int[] notReachableLines = + new[] + { // NoBranches 15, 16, // If @@ -761,51 +762,53 @@ public void TestReachabilityHelper() 163, 164, // FiltersAndFinallies 176, 177, 183, 184, 189, 190, 195, 196, 197 - }; + }; - int[] expectedToBeInstrumented = allInstrumentableLines.Except(notReachableLines).ToArray(); + int[] expectedToBeInstrumented = allInstrumentableLines.Except(notReachableLines).ToArray(); - InstrumenterTest instrumenterTest = CreateInstrumentor(); - InstrumenterResult result = instrumenterTest.Instrumenter.Instrument(); + InstrumenterTest instrumenterTest = CreateInstrumentor(); + InstrumenterResult result = instrumenterTest.Instrumenter.Instrument(); - Document doc = result.Documents.Values.FirstOrDefault(d => Path.GetFileName(d.Path) == "Instrumentation.DoesNotReturn.cs"); + Document doc = result.Documents.Values.FirstOrDefault(d => Path.GetFileName(d.Path) == "Instrumentation.DoesNotReturn.cs"); - // check for instrumented lines - doc.AssertNonInstrumentedLines(BuildConfiguration.Debug, notReachableLines); - doc.AssertInstrumentLines(BuildConfiguration.Debug, expectedToBeInstrumented); + // check for instrumented lines + doc.AssertNonInstrumentedLines(BuildConfiguration.Debug, notReachableLines); + doc.AssertInstrumentLines(BuildConfiguration.Debug, expectedToBeInstrumented); - instrumenterTest.Directory.Delete(true); - } + instrumenterTest.Directory.Delete(true); + } - [Fact] - public void Instrumenter_MethodsWithoutReferenceToSource_AreSkipped() - { - var loggerMock = new Mock(); + [ConditionalFact] + [SkipOnOS(OS.Linux, "not supported")] + [SkipOnOS(OS.MacOS, "not supported")] + public void Instrumenter_MethodsWithoutReferenceToSource_AreSkipped() + { + var loggerMock = new Mock(); - string module = Directory.GetFiles(Directory.GetCurrentDirectory(), "coverlet.tests.projectsample.vbmynamespace.dll").First(); - string pdb = Path.Combine(Path.GetDirectoryName(module), Path.GetFileNameWithoutExtension(module) + ".pdb"); + string module = Directory.GetFiles(Directory.GetCurrentDirectory(), "coverlet.tests.projectsample.vbmynamespace.dll").First(); + string pdb = Path.Combine(Path.GetDirectoryName(module), Path.GetFileNameWithoutExtension(module) + ".pdb"); - DirectoryInfo directory = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString())); + DirectoryInfo directory = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString())); - File.Copy(module, Path.Combine(directory.FullName, Path.GetFileName(module)), true); - File.Copy(pdb, Path.Combine(directory.FullName, Path.GetFileName(pdb)), true); + File.Copy(module, Path.Combine(directory.FullName, Path.GetFileName(module)), true); + File.Copy(pdb, Path.Combine(directory.FullName, Path.GetFileName(pdb)), true); - var instrumentationHelper = - new InstrumentationHelper(new ProcessExitHandler(), new RetryHelper(), new FileSystem(), new Mock().Object, - new SourceRootTranslator(module, new Mock().Object, new FileSystem(), new AssemblyAdapter())); + var instrumentationHelper = + new InstrumentationHelper(new ProcessExitHandler(), new RetryHelper(), new FileSystem(), new Mock().Object, + new SourceRootTranslator(module, new Mock().Object, new FileSystem(), new AssemblyAdapter())); - CoverageParameters parameters = new(); + CoverageParameters parameters = new(); - var instrumenter = new Instrumenter(Path.Combine(directory.FullName, Path.GetFileName(module)), "_coverlet_tests_projectsample_vbmynamespace", parameters, - loggerMock.Object, instrumentationHelper, new FileSystem(), new SourceRootTranslator(Path.Combine(directory.FullName, Path.GetFileName(module)), loggerMock.Object, new FileSystem(), new AssemblyAdapter()), new CecilSymbolHelper()); + var instrumenter = new Instrumenter(Path.Combine(directory.FullName, Path.GetFileName(module)), "_coverlet_tests_projectsample_vbmynamespace", parameters, + loggerMock.Object, instrumentationHelper, new FileSystem(), new SourceRootTranslator(Path.Combine(directory.FullName, Path.GetFileName(module)), loggerMock.Object, new FileSystem(), new AssemblyAdapter()), new CecilSymbolHelper()); - instrumentationHelper.BackupOriginalModule(Path.Combine(directory.FullName, Path.GetFileName(module)), "_coverlet_tests_projectsample_vbmynamespace"); + instrumentationHelper.BackupOriginalModule(Path.Combine(directory.FullName, Path.GetFileName(module)), "_coverlet_tests_projectsample_vbmynamespace"); - InstrumenterResult result = instrumenter.Instrument(); + InstrumenterResult result = instrumenter.Instrument(); - Assert.False(result.Documents.ContainsKey(string.Empty)); + Assert.False(result.Documents.ContainsKey(string.Empty)); - directory.Delete(true); - } + directory.Delete(true); } + } } From fafa17486db6b7f784836a6f83f23332bc12da26 Mon Sep 17 00:00:00 2001 From: Bert Date: Wed, 16 Aug 2023 09:44:27 +0200 Subject: [PATCH 21/25] remove PackageReference VersionOverride for test dependencies --- Directory.Packages.props | 3 +++ .../coverlet.core.tests.csproj | 18 ++++++------------ 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 024c47c61..3826d83dd 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -15,6 +15,7 @@ + @@ -33,8 +34,10 @@ + + true - + + + + - + + - @@ -36,15 +39,6 @@ - - - - - - - - - PreserveNewest From 646b06de1851ddcd84688e01ecb46f2760f4e5f2 Mon Sep 17 00:00:00 2001 From: Bert Date: Sat, 19 Aug 2023 08:56:56 +0200 Subject: [PATCH 22/25] remove condition for coverlet.tests.projectsample.vbmynamespace.vbproj --- test/coverlet.core.tests/coverlet.core.tests.csproj | 7 ++----- .../coverlet.tests.projectsample.netframework.csproj | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/test/coverlet.core.tests/coverlet.core.tests.csproj b/test/coverlet.core.tests/coverlet.core.tests.csproj index fa82381c2..294ad8cfb 100644 --- a/test/coverlet.core.tests/coverlet.core.tests.csproj +++ b/test/coverlet.core.tests/coverlet.core.tests.csproj @@ -28,15 +28,12 @@ + - - - - - + diff --git a/test/coverlet.tests.projectsample.netframework/coverlet.tests.projectsample.netframework.csproj b/test/coverlet.tests.projectsample.netframework/coverlet.tests.projectsample.netframework.csproj index 9a97434b9..d34a33ca5 100644 --- a/test/coverlet.tests.projectsample.netframework/coverlet.tests.projectsample.netframework.csproj +++ b/test/coverlet.tests.projectsample.netframework/coverlet.tests.projectsample.netframework.csproj @@ -7,7 +7,7 @@ - + all From 960ad931b340827a3e11b9110998586cfde11935 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20M=C3=BCller?= Date: Sat, 19 Aug 2023 22:16:13 +0200 Subject: [PATCH 23/25] reverted os skip --- test/coverlet.core.tests/Instrumentation/InstrumenterTests.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/coverlet.core.tests/Instrumentation/InstrumenterTests.cs b/test/coverlet.core.tests/Instrumentation/InstrumenterTests.cs index 572c1590f..b64f2e4a5 100644 --- a/test/coverlet.core.tests/Instrumentation/InstrumenterTests.cs +++ b/test/coverlet.core.tests/Instrumentation/InstrumenterTests.cs @@ -779,8 +779,6 @@ public void TestReachabilityHelper() } [ConditionalFact] - [SkipOnOS(OS.Linux, "not supported")] - [SkipOnOS(OS.MacOS, "not supported")] public void Instrumenter_MethodsWithoutReferenceToSource_AreSkipped() { var loggerMock = new Mock(); From 950347d8b32aee10b670c9ca63e7a54f426b6451 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20M=C3=BCller?= Date: Sat, 19 Aug 2023 22:18:09 +0200 Subject: [PATCH 24/25] nit --- test/coverlet.core.tests/Instrumentation/InstrumenterTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/coverlet.core.tests/Instrumentation/InstrumenterTests.cs b/test/coverlet.core.tests/Instrumentation/InstrumenterTests.cs index b64f2e4a5..72f5d696e 100644 --- a/test/coverlet.core.tests/Instrumentation/InstrumenterTests.cs +++ b/test/coverlet.core.tests/Instrumentation/InstrumenterTests.cs @@ -778,7 +778,7 @@ public void TestReachabilityHelper() instrumenterTest.Directory.Delete(true); } - [ConditionalFact] + [Fact] public void Instrumenter_MethodsWithoutReferenceToSource_AreSkipped() { var loggerMock = new Mock(); From 187ac2b275c9ba86ba9f6765001669a89a7312df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20M=C3=BCller?= Date: Sat, 19 Aug 2023 22:23:40 +0200 Subject: [PATCH 25/25] fix --- test/coverlet.core.tests/Instrumentation/InstrumenterTests.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/test/coverlet.core.tests/Instrumentation/InstrumenterTests.cs b/test/coverlet.core.tests/Instrumentation/InstrumenterTests.cs index 72f5d696e..2060da38d 100644 --- a/test/coverlet.core.tests/Instrumentation/InstrumenterTests.cs +++ b/test/coverlet.core.tests/Instrumentation/InstrumenterTests.cs @@ -12,7 +12,6 @@ using Coverlet.Core.Samples.Tests; using Coverlet.Core.Symbols; using Coverlet.Core.Tests; -using Coverlet.Tests.Xunit.Extensions; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Emit;