├── .gitattributes ├── test ├── .gitignore ├── coverlet.core.tests │ ├── .gitignore │ ├── coverlet.core.tests.snk │ ├── TestAssets │ │ ├── System.Private.CoreLib.dll │ │ ├── System.Private.CoreLib.pdb │ │ ├── CoverletSourceRootsMappingTest │ │ ├── 75d9f96508d74def860a568f426ea4a4.dll │ │ └── 75d9f96508d74def860a568f426ea4a4.pdb │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── Samples │ │ ├── .editorconfig │ │ ├── Instrumentation.ExcludeFromCoverage.Issue1302.cs │ │ ├── Instrumentation.ExcludeFromCoverage.NestedStateMachines.cs │ │ ├── Instrumentation.AsyncIterator.cs │ │ ├── Instrumentation.AutoProps.cs │ │ ├── Instrumentation.SelectionStatements.cs │ │ ├── Instrumentation.AwaitUsing.cs │ │ ├── Instrumentation.AsyncForeach.cs │ │ ├── Instrumentation.Yield.cs │ │ ├── Instrumentation.ExcludeFromCoverage.Issue670.cs │ │ ├── Instrumentation.ExcludeFilter.cs │ │ └── Instrumentation.AsyncAwaitValueTask.cs │ ├── Helpers │ │ ├── FileSystemTests.cs │ │ └── RetryHelperTests.cs │ ├── Reporters │ │ ├── ReporterFactoryTests.cs │ │ ├── JsonReporterTests.cs │ │ ├── LcovReporterTests.cs │ │ └── Reporters.cs │ └── Coverage │ │ ├── CoverageTests.AsyncIterator.cs │ │ ├── CoverageTests.AwaitUsing.cs │ │ ├── CoverageTests.IntegerOverflow.cs │ │ └── CoverageTests.AsyncAwaitValueTask.cs ├── coverlet.tests.remoteexecutor │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── coverlet.tests.remoteexecutor.snk │ ├── coverlet.tests.remoteexecutor.csproj │ └── Program.cs ├── coverlet.collector.tests │ ├── coverlet.collector.tests.snk │ ├── Properties │ │ └── AssemblyInfo.cs │ └── coverlet.collector.tests.csproj ├── coverlet.integration.tests │ ├── coverlet.integration.tests.snk │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── coverlet.integration.tests.csproj │ ├── DotnetTool.cs │ └── AssertHelper.cs ├── coverlet.core.tests.samples.netstandard │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── coverlet.core.tests.samples.netstandard.snk │ ├── .editorconfig │ ├── coverlet.core.tests.samples.netstandard.csproj │ └── Instrumentation.AsyncAwait.cs ├── coverlet.tests.projectsample.fsharp │ ├── Library.fs │ └── coverlet.tests.projectsample.fsharp.fsproj ├── coverlet.tests.xunit.extensions │ ├── coverlet.tests.xunit.extensions.snk │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── ITestCondition.cs │ ├── coverlet.tests.xunit.extensions.csproj │ ├── SkipOnOS.cs │ ├── Extensions.cs │ └── ConditionalFact.cs ├── coverlet.tests.projectsample.empty │ ├── Class1.cs │ ├── coverlet.tests.projectsample.empty.csproj │ └── .editorconfig ├── coverlet.integration.template │ ├── nuget.config │ ├── DeepThought.cs │ ├── .editorconfig │ ├── TemplateTest.cs │ ├── Program.cs │ └── coverlet.integration.template.csproj ├── Directory.Build.props ├── coverlet.testsubject │ ├── coverlet.testsubject.csproj │ └── .editorconfig ├── coverlet.integration.determisticbuild │ ├── DeepThought.cs │ ├── .editorconfig │ ├── TemplateTest.cs │ └── coverlet.integration.determisticbuild.csproj ├── coverlet.core.performancetest │ ├── .editorconfig │ ├── coverlet.core.performancetest.csproj │ └── PerformanceTest.cs ├── coverlet.tests.projectsample.netframework │ ├── .editorconfig │ ├── AsyncAwaitStateMachineNetFramework.cs │ └── coverlet.tests.projectsample.netframework.csproj ├── coverlet.tests.projectsample.excludedbyattribute │ ├── coverlet.tests.projectsample.excludedbyattribute.csproj │ ├── .editorconfig │ └── SampleClass.cs └── Directory.Build.targets ├── _assets ├── coverlet.png ├── coverlet@2x.png ├── coverlet@3x.png ├── coverlet@4x.png ├── coverlet-icon.png ├── coverlet@0.5x.png ├── coverlet@1.5x.png ├── coverlet@0.75x.png └── coverlet-icon.svg ├── src ├── coverlet.console │ ├── runtimeconfig.template.json │ ├── coverlet.console.snk │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── ConsoleTables │ │ └── .editorconfig │ ├── ExitCodes.cs │ ├── Logging │ │ ├── LogLevel.cs │ │ └── ConsoleLogger.cs │ └── coverlet.console.csproj ├── coverlet.core │ ├── coverlet.core.snk │ ├── Abstractions │ │ ├── IConsole.cs │ │ ├── IProcessExitHandler.cs │ │ ├── IRetryHelper.cs │ │ ├── ILogger.cs │ │ ├── ISourceRootTranslator.cs │ │ ├── IReporter.cs │ │ ├── ICecilSymbolHelper.cs │ │ ├── IFileSystem.cs │ │ └── IInstrumentationHelper.cs │ ├── Enums │ │ ├── ThresholdStatistic.cs │ │ └── ThresholdTypeFlags.cs │ ├── Attributes │ │ ├── DoesNotReturnAttribute.cs │ │ └── ExcludeFromCoverage.cs │ ├── Helpers │ │ ├── Console.cs │ │ ├── ProcessExitHandler.cs │ │ ├── FileSystem.cs │ │ └── RetryHelper.cs │ ├── Extensions │ │ └── HelperExtensions.cs │ ├── Reporters │ │ ├── JsonReporter.cs │ │ ├── ReporterFactory.cs │ │ ├── LcovReporter.cs │ │ └── TeamCityReporter.cs │ ├── coverlet.core.csproj │ ├── CoverageDetails.cs │ ├── Exceptions.cs │ ├── Symbols │ │ └── BranchPoint.cs │ ├── CoveragePrepareResult.cs │ └── Properties │ │ └── AssemblyInfo.cs ├── coverlet.collector │ ├── coverlet.collector.snk │ ├── Utilities │ │ ├── CoverletDataCollectorException.cs │ │ ├── FileHelper.cs │ │ ├── DirectoryHelper.cs │ │ ├── TestPlatformLogger.cs │ │ ├── Interfaces │ │ │ ├── ICountDown.cs │ │ │ ├── IFileHelper.cs │ │ │ ├── IDirectoryHelper.cs │ │ │ └── ICoverageWrapper.cs │ │ ├── CountDownEvent.cs │ │ ├── CoverletConstants.cs │ │ └── TestPlatformEqtTrace.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── DataCollection │ │ ├── CoverletLogger.cs │ │ └── CoverageWrapper.cs │ └── build │ │ └── netstandard1.0 │ │ └── coverlet.collector.targets └── coverlet.msbuild.tasks │ ├── coverlet.msbuild.tasks.snk │ ├── BaseTask.cs │ ├── Properties │ └── AssemblyInfo.cs │ ├── MSBuildLogger.cs │ ├── coverlet.msbuild.props │ ├── ReportWriter.cs │ └── coverlet.msbuild.tasks.csproj ├── Documentation ├── images │ ├── file.png │ ├── nightly.PNG │ └── nightlyExample.PNG ├── Examples │ ├── VSTest │ │ ├── DeterministicBuild │ │ │ ├── Directory.Build.targets │ │ │ ├── ClassLibrary1 │ │ │ │ ├── ClassLibrary1.csproj │ │ │ │ └── Class1.cs │ │ │ ├── XUnitTestProject1 │ │ │ │ ├── UnitTest1.cs │ │ │ │ └── XUnitTestProject1.csproj │ │ │ ├── Directory.Build.props │ │ │ ├── DeterministicBuild.targets │ │ │ └── DeterministicBuild.sln │ │ └── HelloWorld │ │ │ ├── ClassLibrary1 │ │ │ ├── ClassLibrary1.csproj │ │ │ └── Class1.cs │ │ │ ├── HowTo.md │ │ │ ├── XUnitTestProject1 │ │ │ ├── UnitTest1.cs │ │ │ ├── runsettings.xml │ │ │ └── XUnitTestProject1.csproj │ │ │ └── HelloWorld.sln │ └── MSBuild │ │ ├── DeterministicBuild │ │ ├── Directory.Build.targets │ │ ├── ClassLibrary1 │ │ │ ├── ClassLibrary1.csproj │ │ │ └── Class1.cs │ │ ├── XUnitTestProject1 │ │ │ ├── UnitTest1.cs │ │ │ └── XUnitTestProject1.csproj │ │ ├── Directory.Build.props │ │ ├── DeterministicBuild.targets │ │ └── DeterministicBuild.sln │ │ └── MergeWith │ │ ├── ClassLibrary1 │ │ ├── ClassLibrary1.csproj │ │ └── Class1.cs │ │ ├── ClassLibrary2 │ │ ├── ClassLibrary2.csproj │ │ └── Class2.cs │ │ ├── ClassLibrary3 │ │ ├── ClassLibrary3.csproj │ │ └── Class3.cs │ │ ├── XUnitTestProject1 │ │ ├── UnitTest1.cs │ │ └── XUnitTestProject1.csproj │ │ ├── XUnitTestProject2 │ │ ├── UnitTest2.cs │ │ └── XUnitTestProject2.csproj │ │ ├── XUnitTestProject3 │ │ ├── UnitTest3.cs │ │ └── XUnitTestProject3.csproj │ │ └── HowTo.md ├── Examples.md ├── DriversFeatures.md ├── ConsumeNightlyBuild.md └── Roadmap.md ├── global.json ├── CODE_OF_CONDUCT.md ├── version.json ├── eng ├── signclient.json ├── build.yml ├── azure-pipelines-nightly.yml └── azure-pipelines.yml ├── DeterministicBuild.targets ├── LICENSE ├── Directory.Build.props ├── THIRD-PARTY-NOTICES.txt ├── Directory.Build.targets └── CONTRIBUTING.md /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /test/.gitignore: -------------------------------------------------------------------------------- 1 | coverage.json 2 | coverage.opencover.xml 3 | -------------------------------------------------------------------------------- /test/coverlet.core.tests/.gitignore: -------------------------------------------------------------------------------- 1 | coverage.* 2 | !75d9f96508d74def860a568f426ea4a4.* -------------------------------------------------------------------------------- /_assets/coverlet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdsol/coverlet/master/_assets/coverlet.png -------------------------------------------------------------------------------- /_assets/coverlet@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdsol/coverlet/master/_assets/coverlet@2x.png -------------------------------------------------------------------------------- /_assets/coverlet@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdsol/coverlet/master/_assets/coverlet@3x.png -------------------------------------------------------------------------------- /_assets/coverlet@4x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdsol/coverlet/master/_assets/coverlet@4x.png -------------------------------------------------------------------------------- /src/coverlet.console/runtimeconfig.template.json: -------------------------------------------------------------------------------- 1 | { 2 | "rollForwardOnNoCandidateFx": 2 3 | } 4 | -------------------------------------------------------------------------------- /_assets/coverlet-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdsol/coverlet/master/_assets/coverlet-icon.png -------------------------------------------------------------------------------- /_assets/coverlet@0.5x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdsol/coverlet/master/_assets/coverlet@0.5x.png -------------------------------------------------------------------------------- /_assets/coverlet@1.5x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdsol/coverlet/master/_assets/coverlet@1.5x.png -------------------------------------------------------------------------------- /_assets/coverlet@0.75x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdsol/coverlet/master/_assets/coverlet@0.75x.png -------------------------------------------------------------------------------- /Documentation/images/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdsol/coverlet/master/Documentation/images/file.png -------------------------------------------------------------------------------- /global.json: -------------------------------------------------------------------------------- 1 | { 2 | "sdk": { 3 | "version": "5.0.401", 4 | "rollForward": "latestMajor" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Documentation/images/nightly.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdsol/coverlet/master/Documentation/images/nightly.PNG -------------------------------------------------------------------------------- /src/coverlet.core/coverlet.core.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdsol/coverlet/master/src/coverlet.core/coverlet.core.snk -------------------------------------------------------------------------------- /Documentation/images/nightlyExample.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdsol/coverlet/master/Documentation/images/nightlyExample.PNG -------------------------------------------------------------------------------- /src/coverlet.console/coverlet.console.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdsol/coverlet/master/src/coverlet.console/coverlet.console.snk -------------------------------------------------------------------------------- /src/coverlet.collector/coverlet.collector.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdsol/coverlet/master/src/coverlet.collector/coverlet.collector.snk -------------------------------------------------------------------------------- /test/coverlet.core.tests/coverlet.core.tests.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdsol/coverlet/master/test/coverlet.core.tests/coverlet.core.tests.snk -------------------------------------------------------------------------------- /src/coverlet.msbuild.tasks/coverlet.msbuild.tasks.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdsol/coverlet/master/src/coverlet.msbuild.tasks/coverlet.msbuild.tasks.snk -------------------------------------------------------------------------------- /test/coverlet.tests.remoteexecutor/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | [assembly: AssemblyKeyFile("coverlet.tests.remoteexecutor.snk")] -------------------------------------------------------------------------------- /test/coverlet.collector.tests/coverlet.collector.tests.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdsol/coverlet/master/test/coverlet.collector.tests/coverlet.collector.tests.snk -------------------------------------------------------------------------------- /test/coverlet.core.tests/TestAssets/System.Private.CoreLib.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdsol/coverlet/master/test/coverlet.core.tests/TestAssets/System.Private.CoreLib.dll -------------------------------------------------------------------------------- /test/coverlet.core.tests/TestAssets/System.Private.CoreLib.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdsol/coverlet/master/test/coverlet.core.tests/TestAssets/System.Private.CoreLib.pdb -------------------------------------------------------------------------------- /test/coverlet.integration.tests/coverlet.integration.tests.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdsol/coverlet/master/test/coverlet.integration.tests/coverlet.integration.tests.snk -------------------------------------------------------------------------------- /test/coverlet.core.tests.samples.netstandard/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | [assembly: AssemblyKeyFile("coverlet.core.tests.samples.netstandard.snk")] -------------------------------------------------------------------------------- /test/coverlet.core.tests/TestAssets/CoverletSourceRootsMappingTest: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdsol/coverlet/master/test/coverlet.core.tests/TestAssets/CoverletSourceRootsMappingTest -------------------------------------------------------------------------------- /test/coverlet.tests.projectsample.fsharp/Library.fs: -------------------------------------------------------------------------------- 1 | namespace coverlet.tests.projectsample.fsharp 2 | 3 | module TestModule = 4 | type Type1 = Option1 | Option2 of {| x: string |} 5 | -------------------------------------------------------------------------------- /test/coverlet.tests.remoteexecutor/coverlet.tests.remoteexecutor.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdsol/coverlet/master/test/coverlet.tests.remoteexecutor/coverlet.tests.remoteexecutor.snk -------------------------------------------------------------------------------- /test/coverlet.core.tests/TestAssets/75d9f96508d74def860a568f426ea4a4.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdsol/coverlet/master/test/coverlet.core.tests/TestAssets/75d9f96508d74def860a568f426ea4a4.dll -------------------------------------------------------------------------------- /test/coverlet.core.tests/TestAssets/75d9f96508d74def860a568f426ea4a4.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdsol/coverlet/master/test/coverlet.core.tests/TestAssets/75d9f96508d74def860a568f426ea4a4.pdb -------------------------------------------------------------------------------- /test/coverlet.tests.xunit.extensions/coverlet.tests.xunit.extensions.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdsol/coverlet/master/test/coverlet.tests.xunit.extensions/coverlet.tests.xunit.extensions.snk -------------------------------------------------------------------------------- /Documentation/Examples/VSTest/DeterministicBuild/Directory.Build.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /test/coverlet.core.tests.samples.netstandard/coverlet.core.tests.samples.netstandard.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdsol/coverlet/master/test/coverlet.core.tests.samples.netstandard/coverlet.core.tests.samples.netstandard.snk -------------------------------------------------------------------------------- /Documentation/Examples/MSBuild/DeterministicBuild/Directory.Build.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Documentation/Examples/MSBuild/MergeWith/ClassLibrary1/ClassLibrary1.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Documentation/Examples/MSBuild/MergeWith/ClassLibrary2/ClassLibrary2.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Documentation/Examples/MSBuild/MergeWith/ClassLibrary3/ClassLibrary3.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Documentation/Examples/VSTest/HelloWorld/ClassLibrary1/ClassLibrary1.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Documentation/Examples/MSBuild/DeterministicBuild/ClassLibrary1/ClassLibrary1.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Documentation/Examples/VSTest/DeterministicBuild/ClassLibrary1/ClassLibrary1.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /test/coverlet.tests.projectsample.empty/Class1.cs: -------------------------------------------------------------------------------- 1 | namespace Coverlet.Tests.ProjectSample.Empty 2 | { 3 | public class Class1 4 | { 5 | public int Method() 6 | { 7 | return 42; 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/coverlet.integration.template/nuget.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Documentation/Examples/MSBuild/MergeWith/ClassLibrary1/Class1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ClassLibrary1 4 | { 5 | public class Class1 6 | { 7 | public int Method() 8 | { 9 | return 42; 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Documentation/Examples/MSBuild/MergeWith/ClassLibrary2/Class2.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ClassLibrary2 4 | { 5 | public class Class2 6 | { 7 | public int Method() 8 | { 9 | return 42; 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Documentation/Examples/MSBuild/MergeWith/ClassLibrary3/Class3.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ClassLibrary3 4 | { 5 | public class Class3 6 | { 7 | public int Method() 8 | { 9 | return 42; 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Documentation/Examples/VSTest/HelloWorld/ClassLibrary1/Class1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ClassLibrary1 4 | { 5 | public class Class1 6 | { 7 | public int Method() 8 | { 9 | return 42; 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/coverlet.console/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | [assembly: System.Reflection.AssemblyKeyFileAttribute("coverlet.console.snk")] -------------------------------------------------------------------------------- /Documentation/Examples/VSTest/DeterministicBuild/ClassLibrary1/Class1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ClassLibrary1 4 | { 5 | public class Class1 6 | { 7 | public int Method() 8 | { 9 | return 42; 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Documentation/Examples/MSBuild/DeterministicBuild/ClassLibrary1/Class1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ClassLibrary1 4 | { 5 | public class Class1 6 | { 7 | public int Method() 8 | { 9 | return 42; 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/coverlet.core.tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System.Reflection; 5 | 6 | [assembly: AssemblyKeyFile("coverlet.core.tests.snk")] -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | 3 | This project has adopted the code of conduct defined by the Contributor Covenant 4 | to clarify expected behavior in our community. 5 | 6 | For more information, see the [.NET Foundation Code of Conduct](https://dotnetfoundation.org/code-of-conduct). -------------------------------------------------------------------------------- /Documentation/Examples/VSTest/HelloWorld/HowTo.md: -------------------------------------------------------------------------------- 1 | **Run from XUnitTestProject1 folder** 2 | 3 | ``` 4 | dotnet test --collect:"XPlat Code Coverage" 5 | ``` 6 | 7 | With custom runsettings file 8 | 9 | ``` 10 | dotnet test --collect:"XPlat Code Coverage" --settings runsettings.xml 11 | ``` -------------------------------------------------------------------------------- /test/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | true 6 | 7 | -------------------------------------------------------------------------------- /test/coverlet.collector.tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System.Reflection; 5 | 6 | [assembly: AssemblyKeyFile("coverlet.collector.tests.snk")] 7 | -------------------------------------------------------------------------------- /test/coverlet.integration.template/DeepThought.cs: -------------------------------------------------------------------------------- 1 | namespace Coverlet.Integration.Template 2 | { 3 | public class DeepThought 4 | { 5 | public int AnswerToTheUltimateQuestionOfLifeTheUniverseAndEverything() 6 | { 7 | return 42; 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/coverlet.testsubject/coverlet.testsubject.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net5.0 5 | false 6 | false 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /test/coverlet.integration.tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System.Reflection; 5 | 6 | [assembly: AssemblyKeyFile("coverlet.integration.tests.snk")] 7 | -------------------------------------------------------------------------------- /test/coverlet.tests.xunit.extensions/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System.Reflection; 5 | 6 | [assembly: AssemblyKeyFile("coverlet.tests.xunit.extensions.snk")] 7 | -------------------------------------------------------------------------------- /test/coverlet.integration.determisticbuild/DeepThought.cs: -------------------------------------------------------------------------------- 1 | namespace Coverlet.Integration.DeterministicBuild 2 | { 3 | public class DeepThought 4 | { 5 | public int AnswerToTheUltimateQuestionOfLifeTheUniverseAndEverything() 6 | { 7 | return 42; 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/coverlet.testsubject/.editorconfig: -------------------------------------------------------------------------------- 1 | # top-most EditorConfig file 2 | # We don't want to import other EditorConfig files and we want 3 | # to ensure no rules are enabled for these asset source files. 4 | root = true 5 | 6 | [*.cs] 7 | # Default severity for all analyzer diagnostics 8 | dotnet_analyzer_diagnostic.severity = none 9 | -------------------------------------------------------------------------------- /test/coverlet.tests.projectsample.empty/coverlet.tests.projectsample.empty.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | false 6 | false 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/coverlet.console/ConsoleTables/.editorconfig: -------------------------------------------------------------------------------- 1 | # top-most EditorConfig file 2 | # We don't want to import other EditorConfig files and we want 3 | # to ensure no rules are enabled for these asset source files. 4 | root = true 5 | 6 | [*.cs] 7 | # Default severity for all analyzer diagnostics 8 | dotnet_analyzer_diagnostic.severity = none 9 | -------------------------------------------------------------------------------- /test/coverlet.core.performancetest/.editorconfig: -------------------------------------------------------------------------------- 1 | # top-most EditorConfig file 2 | # We don't want to import other EditorConfig files and we want 3 | # to ensure no rules are enabled for these asset source files. 4 | root = true 5 | 6 | [*.cs] 7 | # Default severity for all analyzer diagnostics 8 | dotnet_analyzer_diagnostic.severity = none 9 | -------------------------------------------------------------------------------- /test/coverlet.core.tests/Samples/.editorconfig: -------------------------------------------------------------------------------- 1 | # top-most EditorConfig file 2 | # We don't want to import other EditorConfig files and we want 3 | # to ensure no rules are enabled for these asset source files. 4 | root = true 5 | 6 | [*.cs] 7 | # Default severity for all analyzer diagnostics 8 | dotnet_analyzer_diagnostic.severity = none 9 | -------------------------------------------------------------------------------- /test/coverlet.integration.template/.editorconfig: -------------------------------------------------------------------------------- 1 | # top-most EditorConfig file 2 | # We don't want to import other EditorConfig files and we want 3 | # to ensure no rules are enabled for these asset source files. 4 | root = true 5 | 6 | [*.cs] 7 | # Default severity for all analyzer diagnostics 8 | dotnet_analyzer_diagnostic.severity = none 9 | -------------------------------------------------------------------------------- /version.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/AArnott/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", 3 | "version": "3.1.3-preview.{height}", 4 | "publicReleaseRefSpec": [ 5 | "^refs/heads/master$" 6 | ], 7 | "nugetPackageVersion":{ 8 | "semVer": 2 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Documentation/Examples/MSBuild/MergeWith/XUnitTestProject1/UnitTest1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Xunit; 3 | 4 | namespace XUnitTestProject1 5 | { 6 | public class UnitTest1 7 | { 8 | [Fact] 9 | public void Test1() 10 | { 11 | new ClassLibrary1.Class1().Method(); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Documentation/Examples/MSBuild/MergeWith/XUnitTestProject2/UnitTest2.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Xunit; 3 | 4 | namespace XUnitTestProject2 5 | { 6 | public class UnitTest2 7 | { 8 | [Fact] 9 | public void Test2() 10 | { 11 | new ClassLibrary2.Class2().Method(); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Documentation/Examples/MSBuild/MergeWith/XUnitTestProject3/UnitTest3.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Xunit; 3 | 4 | namespace XUnitTestProject3 5 | { 6 | public class UnitTest3 7 | { 8 | [Fact] 9 | public void Test3() 10 | { 11 | new ClassLibrary3.Class3().Method(); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Documentation/Examples/VSTest/HelloWorld/XUnitTestProject1/UnitTest1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Xunit; 3 | 4 | namespace XUnitTestProject1 5 | { 6 | public class UnitTest1 7 | { 8 | [Fact] 9 | public void Test1() 10 | { 11 | new ClassLibrary1.Class1().Method(); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/coverlet.tests.projectsample.empty/.editorconfig: -------------------------------------------------------------------------------- 1 | # top-most EditorConfig file 2 | # We don't want to import other EditorConfig files and we want 3 | # to ensure no rules are enabled for these asset source files. 4 | root = true 5 | 6 | [*.cs] 7 | # Default severity for all analyzer diagnostics 8 | dotnet_analyzer_diagnostic.severity = none 9 | -------------------------------------------------------------------------------- /test/coverlet.core.tests.samples.netstandard/.editorconfig: -------------------------------------------------------------------------------- 1 | # top-most EditorConfig file 2 | # We don't want to import other EditorConfig files and we want 3 | # to ensure no rules are enabled for these asset source files. 4 | root = true 5 | 6 | [*.cs] 7 | # Default severity for all analyzer diagnostics 8 | dotnet_analyzer_diagnostic.severity = none 9 | -------------------------------------------------------------------------------- /test/coverlet.integration.determisticbuild/.editorconfig: -------------------------------------------------------------------------------- 1 | # top-most EditorConfig file 2 | # We don't want to import other EditorConfig files and we want 3 | # to ensure no rules are enabled for these asset source files. 4 | root = true 5 | 6 | [*.cs] 7 | # Default severity for all analyzer diagnostics 8 | dotnet_analyzer_diagnostic.severity = none 9 | -------------------------------------------------------------------------------- /test/coverlet.tests.projectsample.netframework/.editorconfig: -------------------------------------------------------------------------------- 1 | # top-most EditorConfig file 2 | # We don't want to import other EditorConfig files and we want 3 | # to ensure no rules are enabled for these asset source files. 4 | root = true 5 | 6 | [*.cs] 7 | # Default severity for all analyzer diagnostics 8 | dotnet_analyzer_diagnostic.severity = none 9 | -------------------------------------------------------------------------------- /Documentation/Examples/MSBuild/DeterministicBuild/XUnitTestProject1/UnitTest1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Xunit; 3 | 4 | namespace XUnitTestProject1 5 | { 6 | public class UnitTest1 7 | { 8 | [Fact] 9 | public void Test1() 10 | { 11 | new ClassLibrary1.Class1().Method(); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Documentation/Examples/VSTest/DeterministicBuild/XUnitTestProject1/UnitTest1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Xunit; 3 | 4 | namespace XUnitTestProject1 5 | { 6 | public class UnitTest1 7 | { 8 | [Fact] 9 | public void Test1() 10 | { 11 | new ClassLibrary1.Class1().Method(); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/coverlet.core/Abstractions/IConsole.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Coverlet.Core.Abstractions 5 | { 6 | internal interface IConsole 7 | { 8 | public void WriteLine(string value); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/coverlet.tests.projectsample.excludedbyattribute/coverlet.tests.projectsample.excludedbyattribute.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net5.0 5 | false 6 | false 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /test/coverlet.tests.projectsample.excludedbyattribute/.editorconfig: -------------------------------------------------------------------------------- 1 | # top-most EditorConfig file 2 | # We don't want to import other EditorConfig files and we want 3 | # to ensure no rules are enabled for these asset source files. 4 | root = true 5 | 6 | [*.cs] 7 | # Default severity for all analyzer diagnostics 8 | dotnet_analyzer_diagnostic.severity = none 9 | -------------------------------------------------------------------------------- /src/coverlet.core/Enums/ThresholdStatistic.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Coverlet.Core.Enums 5 | { 6 | internal enum ThresholdStatistic 7 | { 8 | Minimum, 9 | Average, 10 | Total 11 | } 12 | } -------------------------------------------------------------------------------- /test/coverlet.tests.projectsample.netframework/AsyncAwaitStateMachineNetFramework.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace coverlet.tests.projectsample.netframework 4 | { 5 | public class AsyncAwaitStateMachineNetFramework 6 | { 7 | public async Task AsyncAwait() 8 | { 9 | await Task.CompletedTask; 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/coverlet.core/Abstractions/IProcessExitHandler.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System; 5 | 6 | namespace Coverlet.Core.Abstractions 7 | { 8 | internal interface IProcessExitHandler 9 | { 10 | void Add(EventHandler handler); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/coverlet.tests.xunit.extensions/ITestCondition.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Coverlet.Tests.Xunit.Extensions 5 | { 6 | public interface ITestCondition 7 | { 8 | bool IsMet { get; } 9 | string SkipReason { get; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test/coverlet.tests.xunit.extensions/coverlet.tests.xunit.extensions.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | false 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /test/coverlet.integration.template/TemplateTest.cs: -------------------------------------------------------------------------------- 1 | using Xunit; 2 | 3 | namespace Coverlet.Integration.Template 4 | { 5 | public class TemplateTest 6 | { 7 | [Fact] 8 | public void Answer() 9 | { 10 | DeepThought dt = new DeepThought(); 11 | Assert.Equal(42, dt.AnswerToTheUltimateQuestionOfLifeTheUniverseAndEverything()); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/coverlet.tests.projectsample.excludedbyattribute/SampleClass.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics.CodeAnalysis; 3 | 4 | [assembly: ExcludeFromCodeCoverage] 5 | 6 | namespace coverlet.tests.projectsample.excludedbyattribute 7 | { 8 | public class SampleClass 9 | { 10 | public int SampleMethod() 11 | { 12 | return new Random().Next(); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/coverlet.core/Enums/ThresholdTypeFlags.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System; 5 | 6 | namespace Coverlet.Core.Enums 7 | { 8 | [Flags] 9 | internal enum ThresholdTypeFlags 10 | { 11 | None = 0, 12 | Line = 2, 13 | Branch = 4, 14 | Method = 8 15 | } 16 | } -------------------------------------------------------------------------------- /test/coverlet.integration.determisticbuild/TemplateTest.cs: -------------------------------------------------------------------------------- 1 | using Xunit; 2 | 3 | namespace Coverlet.Integration.DeterministicBuild 4 | { 5 | public class TemplateTest 6 | { 7 | [Fact] 8 | public void Answer() 9 | { 10 | DeepThought dt = new DeepThought(); 11 | Assert.Equal(42, dt.AnswerToTheUltimateQuestionOfLifeTheUniverseAndEverything()); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/coverlet.msbuild.tasks/BaseTask.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System; 5 | using Microsoft.Build.Utilities; 6 | 7 | namespace Coverlet.MSbuild.Tasks 8 | { 9 | public abstract class BaseTask : Task 10 | { 11 | protected static IServiceProvider ServiceProvider { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/coverlet.integration.template/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | using Coverlet.Integration.Template; 4 | 5 | namespace HelloWorld 6 | { 7 | class Program 8 | { 9 | static void Main(string[] args) 10 | { 11 | DeepThought dt = new DeepThought(); 12 | dt.AnswerToTheUltimateQuestionOfLifeTheUniverseAndEverything(); 13 | Console.WriteLine("Hello World!"); 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /Documentation/Examples/VSTest/HelloWorld/XUnitTestProject1/runsettings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | lcov,cobertura 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /eng/signclient.json: -------------------------------------------------------------------------------- 1 | { 2 | "SignClient": { 3 | "AzureAd": { 4 | "AADInstance": "https://login.microsoftonline.com/", 5 | "ClientId": "c248d68a-ba6f-4aa9-8a68-71fe872063f8", 6 | "TenantId": "16076fdc-fcc1-4a15-b1ca-32c9a255900e" 7 | }, 8 | "Service": { 9 | "Url": "https://codesign.dotnetfoundation.org/", 10 | "ResourceId": "https://SignService/3c30251f-36f3-490b-a955-520addb85001" 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /test/coverlet.core.tests.samples.netstandard/coverlet.core.tests.samples.netstandard.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netstandard2.0 4 | false 5 | false 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/coverlet.core/Attributes/DoesNotReturnAttribute.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System; 5 | 6 | namespace Coverlet.Core.Attributes 7 | { 8 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Class)] 9 | internal class DoesNotReturnAttribute : Attribute { } 10 | } 11 | -------------------------------------------------------------------------------- /src/coverlet.core/Attributes/ExcludeFromCoverage.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System; 5 | 6 | namespace Coverlet.Core.Attributes 7 | { 8 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Class)] 9 | internal sealed class ExcludeFromCoverageAttribute : Attribute { } 10 | } -------------------------------------------------------------------------------- /test/coverlet.tests.projectsample.fsharp/coverlet.tests.projectsample.fsharp.fsproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net5.0 5 | true 6 | false 7 | false 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/coverlet.core/Helpers/Console.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System; 5 | using Coverlet.Core.Abstractions; 6 | 7 | namespace Coverlet.Core.Helpers 8 | { 9 | public class SystemConsole : IConsole 10 | { 11 | public void WriteLine(string value) 12 | { 13 | Console.WriteLine(value); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Documentation/Examples/MSBuild/DeterministicBuild/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | https://api.nuget.org/v3/index.json; 6 | ..\..\..\..\..\bin\$(Configuration)\Packages 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Documentation/Examples/VSTest/DeterministicBuild/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | https://api.nuget.org/v3/index.json; 6 | ..\..\..\..\..\bin\$(Configuration)\Packages 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Documentation/Examples.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | ## MSBuild Integration 3 | 4 | * Using `/p:MergeWith` feature `Documentation/Examples/MSBuild/MergeWith/MergeWith.sln` 5 | * Deterministic build feature `Documentation/Examples/MSBuild/DeterministicBuild/DeterministicBuild.sln` 6 | 7 | ## VSTest Integration 8 | 9 | * HelloWorld sample `Documentation/Examples/VSTest/HelloWorld/HelloWorld.sln` 10 | * Deterministic build feature `Documentation/Examples/VSTest/DeterministicBuild/DeterministicBuild.sln` 11 | -------------------------------------------------------------------------------- /src/coverlet.core/Abstractions/IRetryHelper.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System; 5 | 6 | namespace Coverlet.Core.Abstractions 7 | { 8 | internal interface IRetryHelper 9 | { 10 | void Retry(Action action, Func backoffStrategy, int maxAttemptCount = 3); 11 | T Do(Func action, Func backoffStrategy, int maxAttemptCount = 3); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/coverlet.core/Helpers/ProcessExitHandler.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System; 5 | using Coverlet.Core.Abstractions; 6 | 7 | namespace Coverlet.Core.Helpers 8 | { 9 | internal class ProcessExitHandler : IProcessExitHandler 10 | { 11 | public void Add(EventHandler handler) 12 | { 13 | AppDomain.CurrentDomain.ProcessExit += handler; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /test/coverlet.tests.projectsample.netframework/coverlet.tests.projectsample.netframework.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net472 5 | false 6 | false 7 | 8 | 9 | 10 | 11 | all 12 | 13 | 14 | -------------------------------------------------------------------------------- /test/coverlet.core.tests/Samples/Instrumentation.ExcludeFromCoverage.Issue1302.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Coverlet.Core.Samples.Tests 4 | { 5 | public class Issue1302 6 | { 7 | public void Run() 8 | { 9 | [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] 10 | static Func LocalFunction() 11 | { 12 | return myString => myString.Length == 10; 13 | } 14 | 15 | LocalFunction(); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/coverlet.core/Abstractions/ILogger.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System; 5 | 6 | namespace Coverlet.Core.Abstractions 7 | { 8 | internal interface ILogger 9 | { 10 | void LogVerbose(string message); 11 | void LogInformation(string message, bool important = false); 12 | void LogWarning(string message); 13 | void LogError(string message); 14 | void LogError(Exception exception); 15 | } 16 | } -------------------------------------------------------------------------------- /src/coverlet.core/Abstractions/ISourceRootTranslator.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System.Collections.Generic; 5 | using Coverlet.Core.Helpers; 6 | 7 | namespace Coverlet.Core.Abstractions 8 | { 9 | internal interface ISourceRootTranslator 10 | { 11 | string ResolveFilePath(string originalFileName); 12 | string ResolveDeterministicPath(string originalFileName); 13 | IReadOnlyList ResolvePathRoot(string pathRoot); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/coverlet.core/Abstractions/IReporter.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Coverlet.Core.Abstractions 5 | { 6 | internal interface IReporter 7 | { 8 | ReporterOutputType OutputType { get; } 9 | string Format { get; } 10 | string Extension { get; } 11 | string Report(CoverageResult result, ISourceRootTranslator sourceRootTranslator); 12 | } 13 | 14 | internal enum ReporterOutputType 15 | { 16 | File, 17 | Console, 18 | } 19 | } -------------------------------------------------------------------------------- /src/coverlet.collector/Utilities/CoverletDataCollectorException.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System; 5 | 6 | namespace Coverlet.Collector.Utilities 7 | { 8 | internal class CoverletDataCollectorException : Exception 9 | { 10 | public CoverletDataCollectorException(string message) : base(message) 11 | { 12 | } 13 | 14 | public CoverletDataCollectorException(string message, Exception innerException) : base(message, innerException) 15 | { 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/coverlet.core/Extensions/HelperExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System; 5 | using Coverlet.Core.Attributes; 6 | 7 | namespace Coverlet.Core.Extensions 8 | { 9 | internal static class HelperExtensions 10 | { 11 | [ExcludeFromCoverage] 12 | public static TRet Maybe(this T value, Func action, TRet defValue = default) 13 | where T : class 14 | { 15 | return (value != null) ? action(value) : defValue; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /test/coverlet.integration.template/coverlet.integration.template.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net5.0 5 | false 6 | coverletsamplelib.integration.template 7 | false 8 | Exe 9 | false 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /test/coverlet.core.tests/Samples/Instrumentation.ExcludeFromCoverage.NestedStateMachines.cs: -------------------------------------------------------------------------------- 1 | // Remember to use full name because adding new using directives change line numbers 2 | 3 | namespace Coverlet.Core.Samples.Tests 4 | { 5 | public class MethodsWithExcludeFromCodeCoverageAttr_NestedStateMachines 6 | { 7 | [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] 8 | public async System.Threading.Tasks.Task NestedStateMachines() 9 | { 10 | await System.Threading.Tasks.Task.Run(async () => await System.Threading.Tasks.Task.Delay(50)); 11 | } 12 | 13 | public int Test() 14 | { 15 | return 0; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/coverlet.msbuild.tasks/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System.Reflection; 5 | using System.Runtime.CompilerServices; 6 | 7 | [assembly: AssemblyKeyFile("coverlet.msbuild.tasks.snk")] 8 | [assembly: InternalsVisibleTo("coverlet.core.tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100757cf9291d78a82e5bb58a827a3c46c2f959318327ad30d1b52e918321ffbd847fb21565b8576d2a3a24562a93e86c77a298b564a0f1b98f63d7a1441a3a8bcc206da3ed09d5dacc76e122a109a9d3ac608e21a054d667a2bae98510a1f0f653c0e6f58f42b4b3934f6012f5ec4a09b3dfd3e14d437ede1424bdb722aead64ad")] -------------------------------------------------------------------------------- /test/coverlet.core.performancetest/coverlet.core.performancetest.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | net5.0 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/coverlet.collector/Utilities/FileHelper.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System.IO; 5 | using Coverlet.Collector.Utilities.Interfaces; 6 | 7 | namespace Coverlet.Collector.Utilities 8 | { 9 | /// 10 | internal class FileHelper : IFileHelper 11 | { 12 | /// 13 | public bool Exists(string path) 14 | { 15 | return File.Exists(path); 16 | } 17 | 18 | /// 19 | public void WriteAllText(string path, string contents) 20 | { 21 | File.WriteAllText(path, contents); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/coverlet.core/Reporters/JsonReporter.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using Coverlet.Core.Abstractions; 5 | using Newtonsoft.Json; 6 | 7 | namespace Coverlet.Core.Reporters 8 | { 9 | internal class JsonReporter : IReporter 10 | { 11 | public ReporterOutputType OutputType => ReporterOutputType.File; 12 | 13 | public string Format => "json"; 14 | 15 | public string Extension => "json"; 16 | 17 | public string Report(CoverageResult result, ISourceRootTranslator _) 18 | { 19 | return JsonConvert.SerializeObject(result.Modules, Formatting.Indented); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/coverlet.core/Abstractions/ICecilSymbolHelper.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System.Collections.Generic; 5 | using Coverlet.Core.Symbols; 6 | using Mono.Cecil; 7 | using Mono.Cecil.Cil; 8 | 9 | namespace Coverlet.Core.Abstractions 10 | { 11 | internal interface ICecilSymbolHelper 12 | { 13 | IReadOnlyList GetBranchPoints(MethodDefinition methodDefinition); 14 | bool SkipNotCoverableInstruction(MethodDefinition methodDefinition, Instruction instruction); 15 | bool SkipInlineAssignedAutoProperty(bool skipAutoProps, MethodDefinition methodDefinition, Instruction instruction); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /test/coverlet.core.tests/Helpers/FileSystemTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using Xunit; 5 | 6 | namespace Coverlet.Core.Helpers.Tests 7 | { 8 | public class FileSystemTests 9 | { 10 | [Theory] 11 | [InlineData(null, null)] 12 | [InlineData("", "")] 13 | [InlineData("filename.cs", "filename.cs")] 14 | [InlineData("filename{T}.cs", "filename{{T}}.cs")] 15 | public void TestEscapeFileName(string fileName, string expected) 16 | { 17 | string actual = FileSystem.EscapeFileName(fileName); 18 | 19 | Assert.Equal(expected, actual); 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /test/coverlet.core.tests.samples.netstandard/Instrumentation.AsyncAwait.cs: -------------------------------------------------------------------------------- 1 | // Remember to use full name because adding new using directives change line numbers 2 | 3 | namespace Coverlet.Core.Tests 4 | { 5 | public class Issue_669_2 6 | { 7 | private readonly System.Net.Http.HttpClient _httpClient = new System.Net.Http.HttpClient(); 8 | 9 | async public System.Threading.Tasks.ValueTask SendRequest() 10 | { 11 | using (var requestMessage = new System.Net.Http.HttpRequestMessage(System.Net.Http.HttpMethod.Get, "https://www.google.it")) 12 | { 13 | return await _httpClient.SendAsync(requestMessage).ConfigureAwait(false); 14 | } 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Documentation/Examples/VSTest/DeterministicBuild/XUnitTestProject1/XUnitTestProject1.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | false 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/coverlet.core/coverlet.core.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | netstandard2.0 6 | 5.7.2 7 | false 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/coverlet.core/Abstractions/IFileSystem.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System.IO; 5 | 6 | namespace Coverlet.Core.Abstractions 7 | { 8 | internal interface IFileSystem 9 | { 10 | bool Exists(string path); 11 | 12 | void WriteAllText(string path, string contents); 13 | 14 | string ReadAllText(string path); 15 | 16 | Stream OpenRead(string path); 17 | 18 | void Copy(string sourceFileName, string destFileName, bool overwrite); 19 | 20 | void Delete(string path); 21 | 22 | Stream NewFileStream(string path, FileMode mode); 23 | 24 | Stream NewFileStream(string path, FileMode mode, FileAccess access); 25 | 26 | string[] ReadAllLines(string path); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /test/coverlet.tests.remoteexecutor/coverlet.tests.remoteexecutor.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp3.1 6 | Coverlet.Tests.RemoteExecutor 7 | false 8 | false 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Documentation/Examples/MSBuild/MergeWith/XUnitTestProject1/XUnitTestProject1.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | false 6 | 7 | 8 | 9 | 10 | all 11 | runtime; build; native; contentfiles; analyzers; buildtransitive 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Documentation/Examples/MSBuild/MergeWith/XUnitTestProject2/XUnitTestProject2.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | false 6 | 7 | 8 | 9 | 10 | all 11 | runtime; build; native; contentfiles; analyzers; buildtransitive 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Documentation/Examples/MSBuild/MergeWith/XUnitTestProject3/XUnitTestProject3.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | false 6 | 7 | 8 | 9 | 10 | all 11 | runtime; build; native; contentfiles; analyzers; buildtransitive 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Documentation/Examples/VSTest/HelloWorld/XUnitTestProject1/XUnitTestProject1.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | false 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | all 14 | runtime; build; native; contentfiles; analyzers; buildtransitive 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /eng/build.yml: -------------------------------------------------------------------------------- 1 | steps: 2 | - task: UseDotNet@2 3 | inputs: 4 | version: 3.1.404 5 | displayName: Install .NET Core SDK 3.1.404 6 | 7 | - task: UseDotNet@2 8 | inputs: 9 | version: 5.0.401 10 | displayName: Install .NET Core SDK 5.0.401 11 | 12 | - script: dotnet restore 13 | displayName: Restore packages 14 | 15 | - script: dotnet build -c $(BuildConfiguration) --no-restore 16 | displayName: Build 17 | 18 | - script: dotnet pack -c $(BuildConfiguration) --no-restore 19 | displayName: Pack 20 | 21 | - task: DotNetCoreCLI@2 22 | displayName: Run tests 23 | inputs: 24 | command: test 25 | 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]*" 26 | testRunTitle: $(Agent.JobName) 27 | -------------------------------------------------------------------------------- /src/coverlet.collector/Utilities/DirectoryHelper.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System.IO; 5 | using Coverlet.Collector.Utilities.Interfaces; 6 | 7 | namespace Coverlet.Collector.Utilities 8 | { 9 | /// 10 | internal class DirectoryHelper : IDirectoryHelper 11 | { 12 | /// 13 | public bool Exists(string path) 14 | { 15 | return Directory.Exists(path); 16 | } 17 | 18 | /// 19 | public void CreateDirectory(string path) 20 | { 21 | Directory.CreateDirectory(path); 22 | } 23 | 24 | /// 25 | public void Delete(string path, bool recursive) 26 | { 27 | Directory.Delete(path, recursive); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /test/coverlet.integration.tests/coverlet.integration.tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net5.0 5 | false 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /test/coverlet.core.tests/Samples/Instrumentation.AsyncIterator.cs: -------------------------------------------------------------------------------- 1 | // Remember to use full name because adding new using directives change line numbers 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | 9 | namespace Coverlet.Core.Samples.Tests 10 | { 11 | public class AsyncIterator 12 | { 13 | async public Task Issue1104_Repro() 14 | { 15 | int sum = 0; 16 | 17 | await foreach (int result in CreateSequenceAsync()) 18 | { 19 | sum += result; 20 | } 21 | 22 | return sum; 23 | } 24 | 25 | async private IAsyncEnumerable CreateSequenceAsync() 26 | { 27 | for (int i = 0; i < 100; ++i) 28 | { 29 | await Task.CompletedTask; 30 | yield return i; 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/coverlet.core/CoverageDetails.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System; 5 | 6 | namespace Coverlet.Core 7 | { 8 | internal class CoverageDetails 9 | { 10 | private double _averageModulePercent; 11 | 12 | public Modules Modules { get; internal set; } 13 | public double Covered { get; internal set; } 14 | public int Total { get; internal set; } 15 | public double Percent 16 | { 17 | get 18 | { 19 | if (Modules?.Count == 0) return 0; 20 | return Total == 0 ? 100D : Math.Floor((Covered / Total) * 10000) / 100; 21 | } 22 | } 23 | 24 | public double AverageModulePercent 25 | { 26 | get { return Math.Floor(_averageModulePercent * 100) / 100; } 27 | internal set { _averageModulePercent = value; } 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /eng/azure-pipelines-nightly.yml: -------------------------------------------------------------------------------- 1 | pool: 2 | vmImage: 'windows-2019' 3 | 4 | steps: 5 | - task: UseDotNet@2 6 | inputs: 7 | version: 3.1.404 8 | displayName: Install .NET Core SDK 3.1.404 9 | 10 | - task: UseDotNet@2 11 | inputs: 12 | version: 5.0.401 13 | displayName: Install .NET Core SDK 5.0.401 14 | 15 | - task: NuGetAuthenticate@0 16 | displayName: Authenticate with NuGet feeds 17 | 18 | - script: dotnet pack -c Release /p:PublicRelease=false 19 | displayName: Create NuGet packages 20 | 21 | - task: NuGetCommand@2 22 | inputs: 23 | command: push 24 | packagesToPush: $(Build.SourcesDirectory)/bin/Release/Packages/*.nupkg 25 | nuGetFeedType: internal 26 | publishVstsFeed: coverlet/coverlet-nightly 27 | displayName: Publish NuGet packages 28 | 29 | - task: NuGetCommand@2 30 | inputs: 31 | command: push 32 | packagesToPush: $(Build.SourcesDirectory)/bin/Release/Packages/*.snupkg 33 | nuGetFeedType: internal 34 | publishVstsFeed: coverlet/coverlet-nightly 35 | displayName: Publish NuGet symbol packages 36 | -------------------------------------------------------------------------------- /test/coverlet.core.tests/Reporters/ReporterFactoryTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using Xunit; 5 | 6 | namespace Coverlet.Core.Reporters.Tests 7 | { 8 | public class ReporterFactoryTests 9 | { 10 | [Fact] 11 | public void TestCreateReporter() 12 | { 13 | Assert.Equal(typeof(JsonReporter), new ReporterFactory("json").CreateReporter().GetType()); 14 | Assert.Equal(typeof(LcovReporter), new ReporterFactory("lcov").CreateReporter().GetType()); 15 | Assert.Equal(typeof(OpenCoverReporter), new ReporterFactory("opencover").CreateReporter().GetType()); 16 | Assert.Equal(typeof(CoberturaReporter), new ReporterFactory("cobertura").CreateReporter().GetType()); 17 | Assert.Equal(typeof(TeamCityReporter), new ReporterFactory("teamcity").CreateReporter().GetType()); 18 | Assert.Null(new ReporterFactory("").CreateReporter()); 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /Documentation/Examples/MSBuild/DeterministicBuild/XUnitTestProject1/XUnitTestProject1.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | false 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | all 15 | runtime; build; native; contentfiles; analyzers; buildtransitive 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /test/coverlet.collector.tests/coverlet.collector.tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | net5.0 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | all 15 | runtime; build; native; contentfiles; analyzers 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /DeterministicBuild.targets: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | $([System.IO.Path]::Combine('$(IntermediateOutputPath)','$(TargetFrameworkMoniker).AssemblyAttributes$(DefaultLanguageSourceExtension)')) 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 19 | 20 | <_LocalTopLevelSourceRoot Include="@(SourceRoot)" Condition="'%(SourceRoot.NestedRoot)' == ''"/> 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /test/coverlet.core.performancetest/PerformanceTest.cs: -------------------------------------------------------------------------------- 1 | using coverlet.testsubject; 2 | using System.Threading.Tasks; 3 | using System.Collections.Generic; 4 | using Xunit; 5 | 6 | namespace Coverlet.Core.PerformanceTest 7 | { 8 | /// 9 | /// Test the performance of coverlet by running a unit test that calls a reasonably big and complex test class. 10 | /// Enable the test, compile, then run the test in the command line: 11 | /// 12 | /// dotnet test /p:CollectCoverage=true test/Coverlet.Core.PerformanceTest/ 13 | /// 14 | /// 15 | public class PerformanceTest 16 | { 17 | [Theory] 18 | [InlineData(20_000)] 19 | public void TestPerformance(int iterations) 20 | { 21 | var big = new BigClass(); 22 | 23 | var tasks = new List(); 24 | 25 | for (var i = 0; i < iterations; i++) 26 | { 27 | var j = i; 28 | tasks.Add(Task.Run(() => big.Do(j))); 29 | } 30 | 31 | Task.WaitAll(tasks.ToArray()); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /_assets/coverlet-icon.svg: -------------------------------------------------------------------------------- 1 | coverlet -------------------------------------------------------------------------------- /src/coverlet.core/Reporters/ReporterFactory.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System; 5 | using System.Linq; 6 | using Coverlet.Core.Abstractions; 7 | 8 | namespace Coverlet.Core.Reporters 9 | { 10 | internal class ReporterFactory 11 | { 12 | private readonly string _format; 13 | private readonly IReporter[] _reporters; 14 | 15 | public ReporterFactory(string format) 16 | { 17 | _format = format; 18 | _reporters = new IReporter[] { 19 | new JsonReporter(), new LcovReporter(), 20 | new OpenCoverReporter(), new CoberturaReporter(), 21 | new TeamCityReporter() 22 | }; 23 | } 24 | 25 | public bool IsValidFormat() 26 | { 27 | return CreateReporter() != null; 28 | } 29 | 30 | public IReporter CreateReporter() 31 | => _reporters.FirstOrDefault(r => string.Equals(r.Format, _format, StringComparison.OrdinalIgnoreCase)); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /test/coverlet.core.tests/Samples/Instrumentation.AutoProps.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Coverlet.Core.Samples.Tests 4 | { 5 | public class AutoProps 6 | { 7 | private int _myVal = 0; 8 | public AutoProps() 9 | { 10 | _myVal = new Random().Next(); 11 | } 12 | public int AutoPropsNonInit { get; set; } 13 | public int AutoPropsInit { get; set; } = 10; 14 | } 15 | 16 | public record RecordWithPropertyInit 17 | { 18 | private int _myRecordVal = 0; 19 | public RecordWithPropertyInit() 20 | { 21 | _myRecordVal = new Random().Next(); 22 | } 23 | public string RecordAutoPropsNonInit { get; set; } 24 | public string RecordAutoPropsInit { get; set; } = string.Empty; 25 | } 26 | 27 | public class ClassWithAutoRecordProperties 28 | { 29 | record AutoRecordWithProperties(string Prop1, string Prop2); 30 | 31 | public ClassWithAutoRecordProperties() 32 | { 33 | var record = new AutoRecordWithProperties(string.Empty, string.Empty); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Documentation/Examples/MSBuild/DeterministicBuild/DeterministicBuild.targets: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | $([System.IO.Path]::Combine('$(IntermediateOutputPath)','$(TargetFrameworkMoniker).AssemblyAttributes$(DefaultLanguageSourceExtension)')) 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 19 | 20 | <_LocalTopLevelSourceRoot Include="@(SourceRoot)" Condition="'%(SourceRoot.NestedRoot)' == ''"/> 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /Documentation/Examples/VSTest/DeterministicBuild/DeterministicBuild.targets: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | $([System.IO.Path]::Combine('$(IntermediateOutputPath)','$(TargetFrameworkMoniker).AssemblyAttributes$(DefaultLanguageSourceExtension)')) 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 19 | 20 | <_LocalTopLevelSourceRoot Include="@(SourceRoot)" Condition="'%(SourceRoot.NestedRoot)' == ''"/> 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 Toni Solarin-Sodara 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /src/coverlet.collector/Utilities/TestPlatformLogger.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollection; 5 | 6 | namespace Coverlet.Collector.Utilities 7 | { 8 | /// 9 | /// Test platform logger 10 | /// 11 | internal class TestPlatformLogger 12 | { 13 | private readonly DataCollectionLogger _logger; 14 | private readonly DataCollectionContext _dataCollectionContext; 15 | 16 | public TestPlatformLogger(DataCollectionLogger logger, DataCollectionContext dataCollectionContext) 17 | { 18 | _logger = logger; 19 | _dataCollectionContext = dataCollectionContext; 20 | } 21 | 22 | /// 23 | /// Log warning 24 | /// 25 | /// Warning message 26 | public void LogWarning(string warning) 27 | { 28 | _logger.LogWarning(_dataCollectionContext, $"[coverlet]{warning}"); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /test/Directory.Build.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | false 10 | 11 | 12 | 13 | 17 | $(RepoRoot)src\coverlet.msbuild.tasks\bin\$(Configuration)\netstandard2.0\ 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/coverlet.collector/Utilities/Interfaces/ICountDown.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System; 5 | 6 | namespace Coverlet.Collector.Utilities.Interfaces 7 | { 8 | 9 | /// 10 | /// Factory for ICountDownEvent 11 | /// 12 | internal interface ICountDownEventFactory 13 | { 14 | /// 15 | /// Create ICountDownEvent instance 16 | /// 17 | /// count of CountDownEvent 18 | /// max wait 19 | /// 20 | ICountDownEvent Create(int count, TimeSpan waitTimeout); 21 | } 22 | 23 | /// 24 | /// Wrapper interface for CountDownEvent 25 | /// 26 | internal interface ICountDownEvent 27 | { 28 | /// 29 | /// Signal event 30 | /// 31 | void Signal(); 32 | 33 | /// 34 | /// Wait for event 35 | /// 36 | void Wait(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/coverlet.console/ExitCodes.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System; 5 | 6 | /// 7 | /// Exit Codes returned from Coverlet console process. 8 | /// 9 | [Flags] 10 | internal enum CommandExitCodes 11 | { 12 | /// 13 | /// Indicates successful run of dotnet test without any test failure and coverage percentage above threshold if provided. 14 | /// 15 | Success = 0, 16 | 17 | /// 18 | /// Indicates test failure by dotnet test. 19 | /// 20 | TestFailed = 1, 21 | 22 | /// 23 | /// Indicates coverage percentage is below given threshold for one or more threshold type. 24 | /// 25 | CoverageBelowThreshold = 2, 26 | 27 | /// 28 | /// Indicates exception occurred during Coverlet process. 29 | /// 30 | Exception = 101, 31 | 32 | /// 33 | /// Indicates missing options or empty arguments for Coverlet process. 34 | /// 35 | CommandParsingException = 102 36 | } 37 | 38 | -------------------------------------------------------------------------------- /src/coverlet.console/Logging/LogLevel.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Coverlet.Console.Logging 5 | { 6 | /// 7 | /// Defines logging severity levels. 8 | /// 9 | enum LogLevel 10 | { 11 | /// 12 | /// Logs that track the general flow of the application. These logs should have long-term value. 13 | /// 14 | Detailed = 0, 15 | 16 | /// 17 | /// Logs that highlight an abnormal or unexpected event in the application flow, but do not otherwise cause the 18 | /// application execution to stop. 19 | /// 20 | Normal = 1, 21 | 22 | /// 23 | /// Logs that highlight when the current flow of execution is stopped due to a failure. These should indicate a 24 | /// failure in the current activity, not an application-wide failure. 25 | /// 26 | Minimal = 2, 27 | 28 | /// 29 | /// Not used for writing log messages. Specifies that a logging category should not write any messages except warning and errors. 30 | /// 31 | Quiet = 3 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/coverlet.msbuild.tasks/MSBuildLogger.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System; 5 | using Microsoft.Build.Framework; 6 | using Microsoft.Build.Utilities; 7 | using ILogger = Coverlet.Core.Abstractions.ILogger; 8 | 9 | namespace Coverlet.MSbuild.Tasks 10 | { 11 | class MSBuildLogger : ILogger 12 | { 13 | private const string LogPrefix = "[coverlet] "; 14 | 15 | private readonly TaskLoggingHelper _log; 16 | 17 | public MSBuildLogger(TaskLoggingHelper log) => _log = log; 18 | 19 | public void LogVerbose(string message) => _log.LogMessage(MessageImportance.Low, $"{LogPrefix}{message}"); 20 | 21 | // We use `MessageImportance.High` because with `MessageImportance.Normal` doesn't show anything 22 | public void LogInformation(string message, bool important = false) => _log.LogMessage(MessageImportance.High, $"{LogPrefix}{message}"); 23 | 24 | public void LogWarning(string message) => _log.LogWarning($"{LogPrefix}{message}"); 25 | 26 | public void LogError(string message) => _log.LogError($"{LogPrefix}{message}"); 27 | 28 | public void LogError(Exception exception) => _log.LogErrorFromException(exception, true); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/coverlet.core/Abstractions/IInstrumentationHelper.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Coverlet.Core.Abstractions 5 | { 6 | internal interface IInstrumentationHelper 7 | { 8 | void BackupOriginalModule(string module, string identifier); 9 | void DeleteHitsFile(string path); 10 | string[] GetCoverableModules(string module, string[] directories, bool includeTestAssembly); 11 | bool HasPdb(string module, out bool embedded); 12 | bool IsModuleExcluded(string module, string[] excludeFilters); 13 | bool IsModuleIncluded(string module, string[] includeFilters); 14 | bool IsValidFilterExpression(string filter); 15 | bool IsTypeExcluded(string module, string type, string[] excludeFilters); 16 | bool IsTypeIncluded(string module, string type, string[] includeFilters); 17 | void RestoreOriginalModule(string module, string identifier); 18 | bool EmbeddedPortablePdbHasLocalSource(string module, out string firstNotFoundDocument); 19 | bool PortablePdbHasLocalSource(string module, out string firstNotFoundDocument); 20 | bool IsLocalMethod(string method); 21 | void SetLogger(ILogger logger); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test/coverlet.core.tests/Samples/Instrumentation.SelectionStatements.cs: -------------------------------------------------------------------------------- 1 | // Remember to use full name because adding new using directives change line numbers 2 | 3 | namespace Coverlet.Core.Samples.Tests 4 | { 5 | public class SelectionStatements 6 | { 7 | public int If(bool condition) 8 | { 9 | if (condition) 10 | { 11 | return 1; 12 | } 13 | else 14 | { 15 | return 0; 16 | } 17 | } 18 | 19 | public int Switch(int caseSwitch) 20 | { 21 | switch (caseSwitch) 22 | { 23 | case 1: 24 | return 1; 25 | case 2: 26 | return 2; 27 | default: 28 | return 0; 29 | } 30 | } 31 | 32 | public string SwitchCsharp8(object value) => 33 | value 34 | switch 35 | { 36 | int i => i.ToString(System.Globalization.CultureInfo.InvariantCulture), 37 | uint ui => ui.ToString(System.Globalization.CultureInfo.InvariantCulture), 38 | short s => s.ToString(System.Globalization.CultureInfo.InvariantCulture), 39 | _ => throw new System.NotSupportedException() 40 | }; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /test/coverlet.tests.xunit.extensions/SkipOnOS.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System; 5 | using System.Runtime.InteropServices; 6 | 7 | namespace Coverlet.Tests.Xunit.Extensions 8 | { 9 | public enum OS 10 | { 11 | Linux, 12 | MacOS, 13 | Windows 14 | } 15 | 16 | [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Assembly, AllowMultiple = true)] 17 | public class SkipOnOSAttribute : Attribute, ITestCondition 18 | { 19 | private readonly OS _os; 20 | private readonly string _reason; 21 | 22 | public SkipOnOSAttribute(OS os, string reason = "") => (_os, _reason) = (os, reason); 23 | 24 | public bool IsMet => _os switch 25 | { 26 | OS.Linux => !RuntimeInformation.IsOSPlatform(OSPlatform.Linux), 27 | OS.MacOS => !RuntimeInformation.IsOSPlatform(OSPlatform.OSX), 28 | OS.Windows => !RuntimeInformation.IsOSPlatform(OSPlatform.Windows), 29 | _ => throw new NotSupportedException($"Not supported OS {_os}") 30 | }; 31 | 32 | public string SkipReason => $"OS not supported{(string.IsNullOrEmpty(_reason) ? "" : $", {_reason}")}"; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /test/coverlet.core.tests/Samples/Instrumentation.AwaitUsing.cs: -------------------------------------------------------------------------------- 1 | // Remember to use full name because adding new using directives change line numbers 2 | 3 | using System; 4 | using System.IO; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Coverlet.Core.Samples.Tests 9 | { 10 | public class AwaitUsing 11 | { 12 | async public ValueTask HasAwaitUsing() 13 | { 14 | await using (var ms = new MemoryStream(Encoding.ASCII.GetBytes("Boo"))) 15 | { 16 | } 17 | } 18 | 19 | 20 | async public Task Issue914_Repro() 21 | { 22 | await Issue914_Repro_Example1(); 23 | await Issue914_Repro_Example2(); 24 | } 25 | 26 | 27 | async private Task Issue914_Repro_Example1() 28 | { 29 | await using var transaction = new MyTransaction(); 30 | } 31 | 32 | 33 | async private Task Issue914_Repro_Example2() 34 | { 35 | var transaction = new MyTransaction(); 36 | await transaction.DisposeAsync(); 37 | } 38 | 39 | 40 | private class MyTransaction : IAsyncDisposable 41 | { 42 | public async ValueTask DisposeAsync() 43 | { 44 | await default(ValueTask); 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /test/coverlet.integration.determisticbuild/coverlet.integration.determisticbuild.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | net5.0 7 | false 8 | coverletsample.integration.determisticbuild 9 | 10 | https://api.nuget.org/v3/index.json; 11 | $(RepoRoot)bin\$(Configuration)\Packages 12 | 13 | 14 | 15 | 16 | 17 | all 18 | runtime; build; native; contentfiles; analyzers; buildtransitive 19 | 20 | 21 | all 22 | runtime; build; native; contentfiles; analyzers; buildtransitive 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/coverlet.core/Exceptions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System; 5 | 6 | namespace Coverlet.Core.Exceptions 7 | { 8 | [Serializable] 9 | internal class CoverletException : Exception 10 | { 11 | public CoverletException() { } 12 | public CoverletException(string message) : base(message) { } 13 | public CoverletException(string message, System.Exception inner) : base(message, inner) { } 14 | protected CoverletException( 15 | System.Runtime.Serialization.SerializationInfo info, 16 | System.Runtime.Serialization.StreamingContext context) : base(info, context) { } 17 | } 18 | 19 | [Serializable] 20 | internal class CecilAssemblyResolutionException : CoverletException 21 | { 22 | public CecilAssemblyResolutionException() { } 23 | public CecilAssemblyResolutionException(string message) : base(message) { } 24 | public CecilAssemblyResolutionException(string message, System.Exception inner) : base(message, inner) { } 25 | protected CecilAssemblyResolutionException( 26 | System.Runtime.Serialization.SerializationInfo info, 27 | System.Runtime.Serialization.StreamingContext context) : base(info, context) { } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/coverlet.collector/Utilities/CountDownEvent.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System; 5 | using System.Threading; 6 | using Coverlet.Collector.Utilities.Interfaces; 7 | 8 | namespace Coverlet.Collector.Utilities 9 | { 10 | internal class CollectorCountdownEventFactory : ICountDownEventFactory 11 | { 12 | public ICountDownEvent Create(int count, TimeSpan waitTimeout) 13 | { 14 | return new CollectorCountdownEvent(count, waitTimeout); 15 | } 16 | } 17 | 18 | internal class CollectorCountdownEvent : ICountDownEvent 19 | { 20 | private readonly CountdownEvent _countDownEvent; 21 | private readonly TimeSpan _waitTimeout; 22 | 23 | public CollectorCountdownEvent(int count, TimeSpan waitTimeout) 24 | { 25 | _countDownEvent = new CountdownEvent(count); 26 | _waitTimeout = waitTimeout; 27 | } 28 | 29 | public void Signal() 30 | { 31 | _countDownEvent.Signal(); 32 | } 33 | 34 | public void Wait() 35 | { 36 | if (!_countDownEvent.Wait(_waitTimeout)) 37 | { 38 | throw new TimeoutException($"CollectorCountdownEvent timeout after {_waitTimeout}"); 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/coverlet.collector/Utilities/Interfaces/IFileHelper.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Coverlet.Collector.Utilities.Interfaces 5 | { 6 | internal interface IFileHelper 7 | { 8 | /// 9 | /// Determines whether the specified file exists. 10 | /// 11 | /// The file to check. 12 | /// true if the caller has the required permissions and path contains the name of an existing file; otherwise, false. 13 | /// This method also returns false if path is null, an invalid path, or a zero-length string. 14 | /// If the caller does not have sufficient permissions to read the specified file, 15 | /// no exception is thrown and the method returns false regardless of the existence of path. 16 | bool Exists(string path); 17 | 18 | /// 19 | /// Creates a new file, writes the specified string to the file, and then closes the file. 20 | /// If the target file already exists, it is overwritten. 21 | /// 22 | /// The file to write to. 23 | /// The string to write to the file. 24 | void WriteAllText(string path, string contents); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/coverlet.tests.xunit.extensions/Extensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System.Linq; 5 | using Xunit.Abstractions; 6 | using Xunit.Sdk; 7 | 8 | namespace Coverlet.Tests.Xunit.Extensions 9 | { 10 | internal static class TestMethodExtensions 11 | { 12 | public static string EvaluateSkipConditions(this ITestMethod testMethod) 13 | { 14 | ITypeInfo testClass = testMethod.TestClass.Class; 15 | IAssemblyInfo assembly = testMethod.TestClass.TestCollection.TestAssembly.Assembly; 16 | System.Collections.Generic.IEnumerable conditionAttributes = testMethod.Method 17 | .GetCustomAttributes(typeof(ITestCondition)) 18 | .Concat(testClass.GetCustomAttributes(typeof(ITestCondition))) 19 | .Concat(assembly.GetCustomAttributes(typeof(ITestCondition))) 20 | .OfType() 21 | .Select(attributeInfo => attributeInfo.Attribute); 22 | 23 | foreach (ITestCondition condition in conditionAttributes) 24 | { 25 | if (!condition.IsMet) 26 | { 27 | return condition.SkipReason; 28 | } 29 | } 30 | 31 | return null; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $(MSBuildThisFileDirectory) 5 | Debug 6 | $(MSBuildThisFileDirectory)bin\$(Configuration)\Packages\ 7 | true 8 | true 9 | true 10 | snupkg 11 | true 12 | true 13 | preview 14 | true 15 | preview 16 | $(NoWarn);NU5105 17 | 18 | https://api.nuget.org/v3/index.json; 19 | 20 | 21 | 22 | 23 | true 24 | true 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/coverlet.collector/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System.Reflection; 5 | using System.Runtime.CompilerServices; 6 | 7 | [assembly: AssemblyKeyFile("coverlet.collector.snk")] 8 | [assembly: InternalsVisibleTo("coverlet.core.tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100757cf9291d78a82e5bb58a827a3c46c2f959318327ad30d1b52e918321ffbd847fb21565b8576d2a3a24562a93e86c77a298b564a0f1b98f63d7a1441a3a8bcc206da3ed09d5dacc76e122a109a9d3ac608e21a054d667a2bae98510a1f0f653c0e6f58f42b4b3934f6012f5ec4a09b3dfd3e14d437ede1424bdb722aead64ad")] 9 | [assembly: InternalsVisibleTo("coverlet.collector.tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100ed0ed6af9693182615b8dcadc83c918b8d36312f86cefc69539d67d4189cd1b89420e7c3871802ffef7f5ca7816c68ad856c77bf7c230cc07824d96aa5d1237eebd30e246b9a14e22695fb26b40c800f74ea96619092cbd3a5d430d6c003fc7a82e8ccd1e315b935105d9232fe9e99e8d7ff54bba6f191959338d4a3169df9b3")] 10 | // Needed to mock internal type https://github.com/Moq/moq4/wiki/Quickstart#advanced-features 11 | [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] -------------------------------------------------------------------------------- /THIRD-PARTY-NOTICES.txt: -------------------------------------------------------------------------------- 1 | coverlet uses third-party libraries or other resources that may be 2 | distributed under licenses different than the coverlet software. 3 | 4 | In the event that we accidentally failed to list a required notice, please 5 | bring it to our attention by posting an issue. 6 | 7 | The attached notices are provided for information only. 8 | 9 | 10 | License notice for ConsoleTables 11 | -------------------------------- 12 | 13 | The MIT License (MIT) 14 | 15 | Copyright (c) 2012 Khalid Abuhakmeh 16 | 17 | Permission is hereby granted, free of charge, to any person obtaining a copy 18 | of this software and associated documentation files (the "Software"), to deal 19 | in the Software without restriction, including without limitation the rights 20 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 21 | copies of the Software, and to permit persons to whom the Software is 22 | furnished to do so, subject to the following conditions: 23 | 24 | The above copyright notice and this permission notice shall be included in all 25 | copies or substantial portions of the Software. 26 | 27 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 28 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 29 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 30 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 31 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 32 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 33 | SOFTWARE. 34 | -------------------------------------------------------------------------------- /test/coverlet.core.tests/Reporters/JsonReporterTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using Coverlet.Core.Abstractions; 5 | using Moq; 6 | using System; 7 | using Xunit; 8 | 9 | namespace Coverlet.Core.Reporters.Tests 10 | { 11 | public class JsonReporterTests 12 | { 13 | [Fact] 14 | public void TestReport() 15 | { 16 | var result = new CoverageResult(); 17 | result.Identifier = Guid.NewGuid().ToString(); 18 | 19 | var lines = new Lines(); 20 | lines.Add(1, 1); 21 | lines.Add(2, 0); 22 | 23 | var methods = new Methods(); 24 | string methodString = "System.Void Coverlet.Core.Reporters.Tests.JsonReporterTests.TestReport()"; 25 | methods.Add(methodString, new Method()); 26 | methods[methodString].Lines = lines; 27 | 28 | var classes = new Classes(); 29 | classes.Add("Coverlet.Core.Reporters.Tests.JsonReporterTests", methods); 30 | 31 | var documents = new Documents(); 32 | documents.Add("doc.cs", classes); 33 | 34 | result.Modules = new Modules(); 35 | result.Modules.Add("module", documents); 36 | 37 | var reporter = new JsonReporter(); 38 | Assert.NotEqual("{\n}", reporter.Report(result, new Mock().Object)); 39 | Assert.NotEqual(string.Empty, reporter.Report(result, new Mock().Object)); 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /src/coverlet.console/coverlet.console.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net5.0 6 | coverlet 7 | true 8 | coverlet.console 9 | 10 | 11 | 12 | 13 | $(AssemblyTitle) 14 | tonerdo 15 | Coverlet is a cross platform code coverage tool for .NET, with support for line, branch and method coverage. 16 | coverage;testing;unit-test;lcov;opencover;quality 17 | https://raw.githubusercontent.com/tonerdo/coverlet/master/_assets/coverlet-icon.svg?sanitize=true 18 | coverlet-icon.png 19 | https://github.com/coverlet-coverage/coverlet 20 | MIT 21 | git 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /Documentation/DriversFeatures.md: -------------------------------------------------------------------------------- 1 | # Driver feature differences 2 | 3 | All Coverlet drivers share the same coverage engine. Since version 3.0.0, we've consolidated versioning across drivers, so for every new release, all drivers will have the same version number. 4 | 5 | We think that keeping the versions in sync better expresses the set of features every release will have. This does not mean that all drivers will support every functionality/feature or have the same behaviours, since they are limited by the context they're running in. 6 | 7 | In the table below we keep track of main differences: 8 | 9 | | Feature | MSBuild | .NET Tool | DataCollectors | 10 | |:-----------------------------------|:--------------|--------------|------------------| 11 | | .NET Core support(>= 2.0) | Yes | Yes | Yes | 12 | | .NET Framework support(>= 4.6.1) | Yes | Yes | Yes(since 3.0.0) | 13 | | Show result on console | Yes | Yes | No | 14 | | Deterministic reports output folder| Yes | Yes | No | 15 | | Merge reports | Yes | Yes | No | 16 | | Coverage threshold validation | Yes | Yes | No | 17 | | Deterministic build support | Yes | No | Yes | 18 | 19 | When possible, we advice you to use the collectors integration (VSTest engine integration), since it is fully integrated inside the test pipeline and does not suffer from the [known issues](KnownIssues.md) of the other drivers. 20 | -------------------------------------------------------------------------------- /src/coverlet.core/Symbols/BranchPoint.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System; 5 | using System.Diagnostics; 6 | 7 | namespace Coverlet.Core.Symbols 8 | { 9 | /// 10 | /// a branch point 11 | /// 12 | [DebuggerDisplay("StartLine = {StartLine}")] 13 | internal class BranchPoint 14 | { 15 | /// 16 | /// Line of the branching instruction 17 | /// 18 | public int StartLine { get; set; } 19 | 20 | /// 21 | /// A path that can be taken 22 | /// 23 | public int Path { get; set; } 24 | 25 | /// 26 | /// An order of the point within the method 27 | /// 28 | public UInt32 Ordinal { get; set; } 29 | 30 | /// 31 | /// List of OffsetPoints between Offset and EndOffset (exclusive) 32 | /// 33 | public System.Collections.Generic.List OffsetPoints { get; set; } 34 | 35 | /// 36 | /// The IL offset of the point 37 | /// 38 | public int Offset { get; set; } 39 | 40 | /// 41 | /// Last Offset == EndOffset. 42 | /// Can be same as Offset 43 | /// 44 | public int EndOffset { get; set; } 45 | 46 | /// 47 | /// The url to the document if an entry was not mapped to an id 48 | /// 49 | public string Document { get; set; } 50 | } 51 | } -------------------------------------------------------------------------------- /src/coverlet.msbuild.tasks/coverlet.msbuild.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | false 4 | 5 | 6 | 7 | 8 | 9 | false 10 | false 11 | 12 | false 13 | false 14 | json 15 | $([MSBuild]::EnsureTrailingSlash('$(MSBuildProjectDirectory)')) 16 | 0 17 | line,branch,method 18 | minimum 19 | 20 | 21 | $(MSBuildThisFileDirectory) 22 | 23 | 24 | -------------------------------------------------------------------------------- /Documentation/Examples/MSBuild/MergeWith/HowTo.md: -------------------------------------------------------------------------------- 1 | **Run from solution root sln** 2 | 3 | To merge report togheter you need to run separate test and merge in one `json` format file. 4 | Last command will join and create final needed format file. 5 | 6 | ``` 7 | dotnet test XUnitTestProject1\XUnitTestProject1.csproj /p:CollectCoverage=true /p:CoverletOutput=../CoverageResults/ 8 | dotnet test XUnitTestProject2\XUnitTestProject2.csproj /p:CollectCoverage=true /p:CoverletOutput=../CoverageResults/ /p:MergeWith="../CoverageResults/coverage.json" 9 | dotnet test XUnitTestProject3\XUnitTestProject3.csproj /p:CollectCoverage=true /p:CoverletOutput=../CoverageResults/ /p:MergeWith="../CoverageResults/coverage.json" /p:CoverletOutputFormat="opencover" 10 | ``` 11 | 12 | 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. 13 | 14 | ``` 15 | dotnet test /p:CollectCoverage=true /p:CoverletOutput=../CoverageResults/ /p:MergeWith="../CoverageResults/coverage.json" /p:CoverletOutputFormat=\"opencover,json\" -m:1 16 | ``` 17 | 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. 18 | 19 | You can also merge the coverage result and generate another valid format to export the content than opencover, like cobertura. 20 | 21 | ``` 22 | dotnet test /p:CollectCoverage=true /p:CoverletOutput=../CoverageResults/ /p:MergeWith="../CoverageResults/coverage.json" /p:CoverletOutputFormat=\"cobertura,json\" -m:1 23 | ``` 24 | -------------------------------------------------------------------------------- /test/coverlet.core.tests/Samples/Instrumentation.AsyncForeach.cs: -------------------------------------------------------------------------------- 1 | // Remember to use full name because adding new using directives change line numbers 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | 9 | namespace Coverlet.Core.Samples.Tests 10 | { 11 | public class AsyncForeach 12 | { 13 | async public ValueTask SumWithATwist(IAsyncEnumerable ints) 14 | { 15 | int sum = 0; 16 | 17 | await foreach (int i in ints) 18 | { 19 | if (i > 0) 20 | { 21 | sum += i; 22 | } 23 | else 24 | { 25 | sum = 0; 26 | } 27 | } 28 | 29 | return sum; 30 | } 31 | 32 | 33 | async public ValueTask Sum(IAsyncEnumerable ints) 34 | { 35 | int sum = 0; 36 | 37 | await foreach (int i in ints) 38 | { 39 | sum += i; 40 | } 41 | 42 | return sum; 43 | } 44 | 45 | 46 | async public ValueTask SumEmpty() 47 | { 48 | int sum = 0; 49 | 50 | await foreach (int i in AsyncEnumerable.Empty()) 51 | { 52 | sum += i; 53 | } 54 | 55 | return sum; 56 | } 57 | 58 | public async ValueTask GenericAsyncForeach(IAsyncEnumerable ints) 59 | { 60 | await foreach (int obj in ints) 61 | { 62 | await Task.Delay(1); 63 | } 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/coverlet.collector/Utilities/Interfaces/IDirectoryHelper.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Coverlet.Collector.Utilities.Interfaces 5 | { 6 | interface IDirectoryHelper 7 | { 8 | /// 9 | /// Determines whether the specified directory exists. 10 | /// 11 | /// The directory to check. 12 | /// true if the caller has the required permissions and path contains the name of an existing directory; otherwise, false. 13 | /// This method also returns false if path is null, an invalid path, or a zero-length string. 14 | /// If the caller does not have sufficient permissions to read the specified file, 15 | /// no exception is thrown and the method returns false regardless of the existence of path. 16 | bool Exists(string path); 17 | 18 | /// 19 | /// Creates all directories and subdirectories in the specified path unless they already exist. 20 | /// 21 | /// The directory to create. 22 | void CreateDirectory(string directory); 23 | 24 | /// 25 | /// Deletes the specified directory and, if indicated, any subdirectories and files in the directory. 26 | /// 27 | /// The name of the directory to remove. 28 | /// true to remove directories, subdirectories, and files in path; otherwise, false. 29 | void Delete(string path, bool recursive); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /test/coverlet.core.tests/Samples/Instrumentation.Yield.cs: -------------------------------------------------------------------------------- 1 | // Remember to use full name because adding new using directives change line numbers 2 | 3 | namespace Coverlet.Core.Samples.Tests 4 | { 5 | public class Yield 6 | { 7 | public System.Collections.Generic.IEnumerable One() 8 | { 9 | yield return 1; 10 | } 11 | 12 | public System.Collections.Generic.IEnumerable Two() 13 | { 14 | yield return 1; 15 | yield return 2; 16 | } 17 | 18 | public System.Collections.Generic.IEnumerable OneWithSwitch(int n) 19 | { 20 | int result; 21 | switch (n) 22 | { 23 | case 0: 24 | result = 10; 25 | break; 26 | case 1: 27 | result = 11; 28 | break; 29 | case 2: 30 | result = 12; 31 | break; 32 | default: 33 | result = -1; 34 | break; 35 | } 36 | 37 | yield return result; 38 | } 39 | 40 | public System.Collections.Generic.IEnumerable Three() 41 | { 42 | yield return 1; 43 | yield return 2; 44 | yield return 3; 45 | } 46 | 47 | public System.Collections.Generic.IEnumerable Enumerable(System.Collections.Generic.IList ls) 48 | { 49 | foreach ( 50 | var item 51 | in 52 | ls 53 | ) 54 | { 55 | yield return item; 56 | } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /eng/azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | trigger: 2 | branches: 3 | include: ["master", "*_validate"] 4 | paths: 5 | exclude: [".github", "doc", "*.md"] 6 | 7 | jobs: 8 | - job: Windows 9 | displayName: Windows 10 | continueOnError: 'true' 11 | strategy: 12 | matrix: 13 | Debug: 14 | buildConfiguration: "Debug" 15 | Release: 16 | buildConfiguration: "Release" 17 | pool: 18 | vmImage: 'windows-latest' 19 | steps: 20 | - template: build.yml 21 | - task: CopyFiles@2 22 | displayName: Collect packages 23 | inputs: 24 | SourceFolder: bin\$(BuildConfiguration)\Packages 25 | Contents: | 26 | *.nupkg 27 | *.snupkg 28 | TargetFolder: $(Build.ArtifactStagingDirectory)\Packages 29 | condition: eq(variables['BuildConfiguration'], 'Release') 30 | - task: PublishBuildArtifacts@1 31 | displayName: Publish packages as build artifacts 32 | inputs: 33 | PathtoPublish: $(Build.ArtifactStagingDirectory)\Packages 34 | ArtifactName: Packages 35 | publishLocation: Container 36 | condition: eq(variables['BuildConfiguration'], 'Release') 37 | 38 | - job: macOS 39 | displayName: macOS 40 | continueOnError: 'true' 41 | strategy: 42 | matrix: 43 | Debug: 44 | buildConfiguration: "Debug" 45 | Release: 46 | buildConfiguration: "Release" 47 | pool: 48 | vmImage: 'macOS-latest' 49 | steps: 50 | - template: build.yml 51 | 52 | - job: Linux 53 | displayName: Linux 54 | continueOnError: 'true' 55 | strategy: 56 | matrix: 57 | Debug: 58 | buildConfiguration: "Debug" 59 | Release: 60 | buildConfiguration: "Release" 61 | pool: 62 | vmImage: 'ubuntu-latest' 63 | steps: 64 | - template: build.yml 65 | -------------------------------------------------------------------------------- /src/coverlet.console/Logging/ConsoleLogger.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System; 5 | using Coverlet.Core.Abstractions; 6 | using static System.Console; 7 | 8 | namespace Coverlet.Console.Logging 9 | { 10 | class ConsoleLogger : ILogger 11 | { 12 | private static readonly object s_sync = new(); 13 | 14 | public LogLevel Level { get; set; } = LogLevel.Normal; 15 | 16 | public void LogError(string message) => Log(LogLevel.Quiet, message, ConsoleColor.Red); 17 | 18 | public void LogError(Exception exception) => LogError(exception.ToString()); 19 | 20 | public void LogInformation(string message, bool important = false) => Log(important ? LogLevel.Minimal : LogLevel.Normal, message, ForegroundColor); 21 | 22 | public void LogVerbose(string message) => Log(LogLevel.Detailed, message, ForegroundColor); 23 | 24 | public void LogWarning(string message) => Log(LogLevel.Quiet, message, ConsoleColor.Yellow); 25 | 26 | private void Log(LogLevel level, string message, ConsoleColor color) 27 | { 28 | if (level < Level) return; 29 | 30 | lock (s_sync) 31 | { 32 | ConsoleColor currentForegroundColor; 33 | if (color != (currentForegroundColor = ForegroundColor)) 34 | { 35 | ForegroundColor = color; 36 | WriteLine(message); 37 | ForegroundColor = currentForegroundColor; 38 | } 39 | else 40 | { 41 | WriteLine(message); 42 | } 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/coverlet.core/CoveragePrepareResult.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System.IO; 5 | using System.Runtime.Serialization; 6 | using Coverlet.Core.Instrumentation; 7 | 8 | namespace Coverlet.Core 9 | { 10 | // Followed safe serializer guide, will emit xml format 11 | // https://docs.microsoft.com/en-us/visualstudio/code-quality/ca2300-do-not-use-insecure-deserializer-binaryformatter?view=vs-2019 12 | // https://docs.microsoft.com/en-us/visualstudio/code-quality/ca2301-do-not-call-binaryformatter-deserialize-without-first-setting-binaryformatter-binder?view=vs-2019 13 | [DataContract] 14 | internal class CoveragePrepareResult 15 | { 16 | [DataMember] 17 | public string Identifier { get; set; } 18 | [DataMember] 19 | public string ModuleOrDirectory { get; set; } 20 | [DataMember] 21 | public string MergeWith { get; set; } 22 | [DataMember] 23 | public bool UseSourceLink { get; set; } 24 | [DataMember] 25 | public InstrumenterResult[] Results { get; set; } 26 | [DataMember] 27 | public CoverageParameters Parameters { get; set; } 28 | 29 | public static CoveragePrepareResult Deserialize(Stream serializedInstrumentState) 30 | { 31 | return (CoveragePrepareResult)new DataContractSerializer(typeof(CoveragePrepareResult)).ReadObject(serializedInstrumentState); 32 | } 33 | 34 | public static Stream Serialize(CoveragePrepareResult instrumentState) 35 | { 36 | var ms = new MemoryStream(); 37 | new DataContractSerializer(typeof(CoveragePrepareResult)).WriteObject(ms, instrumentState); 38 | ms.Position = 0; 39 | return ms; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/coverlet.collector/Utilities/CoverletConstants.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Coverlet.Collector.Utilities 5 | { 6 | internal static class CoverletConstants 7 | { 8 | public const string FriendlyName = "XPlat code coverage"; 9 | public const string DefaultUri = @"datacollector://Microsoft/CoverletCodeCoverage/1.0"; 10 | public const string DataCollectorName = "CoverletCoverageDataCollector"; 11 | public const string DefaultReportFormat = "cobertura"; 12 | public const string DefaultFileName = "coverage"; 13 | public const string IncludeFiltersElementName = "Include"; 14 | public const string IncludeDirectoriesElementName = "IncludeDirectory"; 15 | public const string ExcludeFiltersElementName = "Exclude"; 16 | public const string ExcludeSourceFilesElementName = "ExcludeByFile"; 17 | public const string ExcludeAttributesElementName = "ExcludeByAttribute"; 18 | public const string MergeWithElementName = "MergeWith"; 19 | public const string UseSourceLinkElementName = "UseSourceLink"; 20 | public const string SingleHitElementName = "SingleHit"; 21 | public const string IncludeTestAssemblyElementName = "IncludeTestAssembly"; 22 | public const string TestSourcesPropertyName = "TestSources"; 23 | public const string ReportFormatElementName = "Format"; 24 | public const string DefaultExcludeFilter = "[coverlet.*]*"; 25 | public const string InProcDataCollectorName = "CoverletInProcDataCollector"; 26 | public const string SkipAutoProps = "SkipAutoProps"; 27 | public const string DoesNotReturnAttributesElementName = "DoesNotReturnAttribute"; 28 | public const string DeterministicReport = "DeterministicReport"; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Documentation/ConsumeNightlyBuild.md: -------------------------------------------------------------------------------- 1 | # Consume nightly build 2 | 3 | To consume nightly builds, create a `NuGet.Config` in your root solution directory and add the following content: 4 | 5 | ```xml 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | ``` 18 | 19 | ## Install packages 20 | 21 | ### Visual Studio: 22 | 23 | ![File](images/nightly.PNG)\ 24 | Example:\ 25 | ![File](images/nightlyExample.PNG) 26 | 27 | ### NuGet (Package Manager console): 28 | ```powershell 29 | 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 30 | ``` 31 | Example: 32 | ```powershell 33 | 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 34 | ``` 35 | 36 | ### .NET CLI: 37 | ```bash 38 | 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 39 | ``` 40 | Example: 41 | ```bash 42 | 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 43 | ``` 44 | 45 | ### MSBuild project file: 46 | 47 | ```xml 48 | 49 | ``` 50 | Example: 51 | ```xml 52 | 53 | ``` -------------------------------------------------------------------------------- /src/coverlet.collector/Utilities/TestPlatformEqtTrace.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using Microsoft.VisualStudio.TestPlatform.ObjectModel; 5 | 6 | namespace Coverlet.Collector.Utilities 7 | { 8 | /// 9 | /// Test platform eqttrace 10 | /// 11 | internal class TestPlatformEqtTrace 12 | { 13 | public bool IsInfoEnabled => EqtTrace.IsInfoEnabled; 14 | public bool IsVerboseEnabled => EqtTrace.IsVerboseEnabled; 15 | 16 | /// 17 | /// Verbose logger 18 | /// 19 | /// Format 20 | /// Args 21 | public void Verbose(string format, params object[] args) 22 | { 23 | EqtTrace.Verbose($"[coverlet]{format}", args); 24 | } 25 | 26 | /// 27 | /// Warning logger 28 | /// 29 | /// Format 30 | /// Args 31 | public void Warning(string format, params object[] args) 32 | { 33 | EqtTrace.Warning($"[coverlet]{format}", args); 34 | } 35 | 36 | /// 37 | /// Info logger 38 | /// 39 | /// Format 40 | /// Args 41 | public void Info(string format, params object[] args) 42 | { 43 | EqtTrace.Info($"[coverlet]{format}", args); 44 | } 45 | 46 | /// 47 | /// Error logger 48 | /// 49 | /// Format 50 | /// Args 51 | public void Error(string format, params object[] args) 52 | { 53 | EqtTrace.Error($"[coverlet]{format}", args); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /test/coverlet.core.tests/Reporters/LcovReporterTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using Coverlet.Core.Abstractions; 5 | using Moq; 6 | using System; 7 | using Xunit; 8 | 9 | namespace Coverlet.Core.Reporters.Tests 10 | { 11 | public class LcovReporterTests 12 | { 13 | [Fact] 14 | public void TestReport() 15 | { 16 | var result = new CoverageResult(); 17 | result.Parameters = new CoverageParameters(); 18 | result.Identifier = Guid.NewGuid().ToString(); 19 | 20 | var lines = new Lines(); 21 | lines.Add(1, 1); 22 | lines.Add(2, 0); 23 | 24 | var branches = new Branches(); 25 | branches.Add(new BranchInfo { Line = 1, Hits = 1, Offset = 23, EndOffset = 24, Path = 0, Ordinal = 1 }); 26 | branches.Add(new BranchInfo { Line = 1, Hits = 0, Offset = 23, EndOffset = 27, Path = 1, Ordinal = 2 }); 27 | 28 | var methods = new Methods(); 29 | string methodString = "System.Void Coverlet.Core.Reporters.Tests.LcovReporterTests.TestReport()"; 30 | methods.Add(methodString, new Method()); 31 | methods[methodString].Lines = lines; 32 | methods[methodString].Branches = branches; 33 | 34 | var classes = new Classes(); 35 | classes.Add("Coverlet.Core.Reporters.Tests.LcovReporterTests", methods); 36 | 37 | var documents = new Documents(); 38 | documents.Add("doc.cs", classes); 39 | result.Modules = new Modules(); 40 | result.Modules.Add("module", documents); 41 | 42 | var reporter = new LcovReporter(); 43 | string report = reporter.Report(result, new Mock().Object); 44 | 45 | Assert.NotEmpty(report); 46 | Assert.Equal("SF:doc.cs", report.Split(Environment.NewLine)[0]); 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /src/coverlet.collector/Utilities/Interfaces/ICoverageWrapper.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using Coverlet.Collector.DataCollection; 5 | using Coverlet.Core; 6 | using Coverlet.Core.Abstractions; 7 | 8 | namespace Coverlet.Collector.Utilities.Interfaces 9 | { 10 | /// 11 | /// Wrapper interface for Coverage class in coverlet.core 12 | /// Since the class is not testable, this interface is used to abstract methods for mocking in unit tests. 13 | /// 14 | internal interface ICoverageWrapper 15 | { 16 | /// 17 | /// Creates a coverage object from given coverlet settings 18 | /// 19 | /// Coverlet settings 20 | /// Coverlet logger 21 | /// Coverlet instrumentationHelper 22 | /// Coverlet fileSystem 23 | /// Coverlet sourceRootTranslator 24 | /// 25 | /// Coverage object 26 | Coverage CreateCoverage(CoverletSettings settings, ILogger logger, IInstrumentationHelper instrumentationHelper, IFileSystem fileSystem, ISourceRootTranslator sourceRootTranslator, ICecilSymbolHelper cecilSymbolHelper); 27 | 28 | /// 29 | /// Gets the coverage result from provided coverage object 30 | /// 31 | /// Coverage 32 | /// The coverage result 33 | CoverageResult GetCoverageResult(Coverage coverage); 34 | 35 | /// 36 | /// Prepares modules for getting coverage. 37 | /// Wrapper over coverage.PrepareModules 38 | /// 39 | /// 40 | void PrepareModules(Coverage coverage); 41 | 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /test/coverlet.tests.xunit.extensions/ConditionalFact.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System; 5 | using Xunit; 6 | using Xunit.Abstractions; 7 | using Xunit.Sdk; 8 | 9 | namespace Coverlet.Tests.Xunit.Extensions 10 | { 11 | [AttributeUsage(AttributeTargets.Method)] 12 | [XunitTestCaseDiscoverer("Coverlet.Tests.Xunit.Extensions." + nameof(ConditionalFactDiscoverer), "coverlet.tests.xunit.extensions")] 13 | public class ConditionalFact : FactAttribute { } 14 | 15 | internal class ConditionalFactDiscoverer : FactDiscoverer 16 | { 17 | public ConditionalFactDiscoverer(IMessageSink diagnosticMessageSink) : base(diagnosticMessageSink) { } 18 | 19 | protected override IXunitTestCase CreateTestCase(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo factAttribute) 20 | { 21 | return new SkippableTestCase(testMethod.EvaluateSkipConditions(), DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), discoveryOptions.MethodDisplayOptionsOrDefault(), testMethod); 22 | } 23 | } 24 | 25 | internal class SkippableTestCase : XunitTestCase 26 | { 27 | private readonly string _skipReason; 28 | 29 | [Obsolete("Called by the de-serializer; should only be called by deriving classes for de-serialization purposes")] 30 | public SkippableTestCase() { } 31 | 32 | public SkippableTestCase(string skipReason, IMessageSink diagnosticMessageSink, TestMethodDisplay defaultMethodDisplay, TestMethodDisplayOptions defaultMethodDisplayOptions, ITestMethod testMethod, object[] testMethodArguments = null) 33 | : base(diagnosticMessageSink, defaultMethodDisplay, defaultMethodDisplayOptions, testMethod, testMethodArguments) 34 | { 35 | _skipReason = skipReason; 36 | } 37 | protected override string GetSkipReason(IAttributeInfo factAttribute) 38 | { 39 | return _skipReason ?? base.GetSkipReason(factAttribute); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/coverlet.core/Helpers/FileSystem.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System.IO; 5 | using Coverlet.Core.Abstractions; 6 | 7 | namespace Coverlet.Core.Helpers 8 | { 9 | internal class FileSystem : IFileSystem 10 | { 11 | // We need to partial mock this method on tests 12 | public virtual bool Exists(string path) 13 | { 14 | return File.Exists(path); 15 | } 16 | 17 | public void WriteAllText(string path, string contents) 18 | { 19 | File.WriteAllText(path, contents); 20 | } 21 | 22 | public string ReadAllText(string path) 23 | { 24 | return File.ReadAllText(path); 25 | } 26 | 27 | // We need to partial mock this method on tests 28 | public virtual Stream OpenRead(string path) 29 | { 30 | return File.OpenRead(path); 31 | } 32 | 33 | public void Copy(string sourceFileName, string destFileName, bool overwrite) 34 | { 35 | File.Copy(sourceFileName, destFileName, overwrite); 36 | } 37 | 38 | public void Delete(string path) 39 | { 40 | File.Delete(path); 41 | } 42 | 43 | // We need to partial mock this method on tests 44 | public virtual Stream NewFileStream(string path, FileMode mode) 45 | { 46 | return new FileStream(path, mode); 47 | } 48 | 49 | // We need to partial mock this method on tests 50 | public virtual Stream NewFileStream(string path, FileMode mode, FileAccess access) 51 | { 52 | return new FileStream(path, mode, access); 53 | } 54 | 55 | public string[] ReadAllLines(string path) 56 | { 57 | return File.ReadAllLines(path); 58 | } 59 | 60 | // Escape format characters in file names 61 | internal static string EscapeFileName(string fileName) 62 | { 63 | return fileName?.Replace("{", "{{").Replace("}", "}}"); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /test/coverlet.core.tests/Samples/Instrumentation.ExcludeFromCoverage.Issue670.cs: -------------------------------------------------------------------------------- 1 | // Remember to use full name because adding new using directives change line numbers 2 | 3 | namespace Coverlet.Core.Samples.Tests 4 | { 5 | public class MethodsWithExcludeFromCodeCoverageAttr_Issue670 6 | { 7 | public void Test(string input) 8 | { 9 | MethodsWithExcludeFromCodeCoverageAttr_Issue670_Startup obj = new MethodsWithExcludeFromCodeCoverageAttr_Issue670_Startup(); 10 | obj.ObjectExtension(input); 11 | } 12 | } 13 | 14 | [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] 15 | public class MethodsWithExcludeFromCodeCoverageAttr_Issue670_Startup 16 | { 17 | public void UseExceptionHandler(System.Action action) 18 | { 19 | action(this); 20 | } 21 | 22 | public async void Run(System.Func func) 23 | { 24 | await func(new MethodsWithExcludeFromCodeCoverageAttr_Issue670_Context()); 25 | } 26 | } 27 | 28 | [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] 29 | public class MethodsWithExcludeFromCodeCoverageAttr_Issue670_Context 30 | { 31 | public System.Threading.Tasks.Task SimulateAsyncWork(int val) 32 | { 33 | return System.Threading.Tasks.Task.Delay(System.Math.Min(val, 50)); 34 | } 35 | } 36 | 37 | public static class MethodsWithExcludeFromCodeCoverageAttr_Issue670_Ext 38 | { 39 | [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] 40 | public static void ObjectExtension(this Coverlet.Core.Samples.Tests.MethodsWithExcludeFromCodeCoverageAttr_Issue670_Startup obj, string input) 41 | { 42 | obj.UseExceptionHandler(o => 43 | { 44 | o.Run(async context => 45 | { 46 | if (context != null) 47 | { 48 | await context.SimulateAsyncWork(input.Length); 49 | } 50 | }); 51 | }); 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /src/coverlet.collector/DataCollection/CoverletLogger.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System; 5 | using Coverlet.Collector.Utilities; 6 | using Coverlet.Core.Abstractions; 7 | 8 | namespace Coverlet.Collector.DataCollection 9 | { 10 | /// 11 | /// Coverlet logger 12 | /// 13 | internal class CoverletLogger : ILogger 14 | { 15 | private readonly TestPlatformEqtTrace _eqtTrace; 16 | private readonly TestPlatformLogger _logger; 17 | 18 | public CoverletLogger(TestPlatformEqtTrace eqtTrace, TestPlatformLogger logger) 19 | { 20 | _eqtTrace = eqtTrace; 21 | _logger = logger; 22 | } 23 | 24 | /// 25 | /// Logs error 26 | /// 27 | /// Error message 28 | public void LogError(string message) 29 | { 30 | _logger.LogWarning(message); 31 | } 32 | 33 | /// 34 | /// Logs error 35 | /// 36 | /// Exception to log 37 | public void LogError(Exception exception) 38 | { 39 | _logger.LogWarning(exception.ToString()); 40 | } 41 | 42 | /// 43 | /// Logs information 44 | /// 45 | /// Information message 46 | /// importance 47 | public void LogInformation(string message, bool important = false) 48 | { 49 | _eqtTrace.Info(message); 50 | } 51 | 52 | /// 53 | /// Logs verbose 54 | /// 55 | /// Verbose message 56 | public void LogVerbose(string message) 57 | { 58 | _eqtTrace.Verbose(message); 59 | } 60 | 61 | /// 62 | /// Logs warning 63 | /// 64 | /// Warning message 65 | public void LogWarning(string message) 66 | { 67 | _eqtTrace.Warning(message); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Directory.Build.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /test/coverlet.core.tests/Coverage/CoverageTests.AsyncIterator.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System.IO; 5 | using System.Threading.Tasks; 6 | using Coverlet.Core.Samples.Tests; 7 | using Xunit; 8 | 9 | namespace Coverlet.Core.Tests 10 | { 11 | public partial class CoverageTests 12 | { 13 | [Fact] 14 | public void AsyncIterator() 15 | { 16 | string path = Path.GetTempFileName(); 17 | try 18 | { 19 | FunctionExecutor.Run(async (string[] pathSerialize) => 20 | { 21 | CoveragePrepareResult coveragePrepareResult = await TestInstrumentationHelper.Run(instance => 22 | { 23 | int res = ((Task)instance.Issue1104_Repro()).GetAwaiter().GetResult(); 24 | 25 | return Task.CompletedTask; 26 | }, persistPrepareResultToFile: pathSerialize[0]); 27 | return 0; 28 | }, new string[] { path }); 29 | 30 | TestInstrumentationHelper.GetCoverageResult(path) 31 | .Document("Instrumentation.AsyncIterator.cs") 32 | .AssertLinesCovered(BuildConfiguration.Debug, 33 | // Issue1104_Repro() 34 | (14, 1), (15, 1), (17, 203), (18, 100), (19, 100), (20, 100), (22, 1), (23, 1), 35 | // CreateSequenceAsync() 36 | (26, 1), (27, 202), (28, 100), (29, 100), (30, 100), (31, 100), (32, 1) 37 | ) 38 | .AssertBranchesCovered(BuildConfiguration.Debug, 39 | // Issue1104_Repro(), 40 | (17, 0, 1), (17, 1, 100), 41 | // CreateSequenceAsync() 42 | (27, 0, 1), (27, 1, 100) 43 | ) 44 | .ExpectedTotalNumberOfBranches(BuildConfiguration.Debug, 2); 45 | } 46 | finally 47 | { 48 | File.Delete(path); 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /test/coverlet.core.tests/Coverage/CoverageTests.AwaitUsing.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System.IO; 5 | using System.Threading.Tasks; 6 | using Coverlet.Core.Samples.Tests; 7 | using Xunit; 8 | 9 | namespace Coverlet.Core.Tests 10 | { 11 | public partial class CoverageTests 12 | { 13 | [Fact] 14 | public void AwaitUsing() 15 | { 16 | string path = Path.GetTempFileName(); 17 | try 18 | { 19 | FunctionExecutor.Run(async (string[] pathSerialize) => 20 | { 21 | CoveragePrepareResult coveragePrepareResult = await TestInstrumentationHelper.Run(instance => 22 | { 23 | ((ValueTask)instance.HasAwaitUsing()).GetAwaiter().GetResult(); 24 | ((Task)instance.Issue914_Repro()).GetAwaiter().GetResult(); 25 | 26 | return Task.CompletedTask; 27 | }, persistPrepareResultToFile: pathSerialize[0]); 28 | return 0; 29 | }, new string[] { path }); 30 | 31 | TestInstrumentationHelper.GetCoverageResult(path) 32 | .Document("Instrumentation.AwaitUsing.cs") 33 | .AssertLinesCovered(BuildConfiguration.Debug, 34 | // HasAwaitUsing() 35 | (13, 1), (14, 1), (15, 1), (16, 1), (17, 1), 36 | // Issue914_Repro() 37 | (21, 1), (22, 1), (23, 1), (24, 1), 38 | // Issue914_Repro_Example1() 39 | (28, 1), (29, 1), (30, 1), 40 | // Issue914_Repro_Example2() 41 | (34, 1), (35, 1), (36, 1), (37, 1), 42 | // MyTransaction.DisposeAsync() 43 | (43, 2), (44, 2), (45, 2) 44 | ) 45 | .ExpectedTotalNumberOfBranches(BuildConfiguration.Debug, 0); 46 | } 47 | finally 48 | { 49 | File.Delete(path); 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions are highly welcome, however, except for very small changes, kindly file an issue and let's have a discussion before you open a pull request. 4 | 5 | ## Requirements 6 | 7 | .NET SDK 2.2 https://dotnet.microsoft.com/download/dotnet-core/2.2 8 | .NET SDK 3.1 https://dotnet.microsoft.com/download/dotnet-core/3.1 9 | 10 | ## Building the Project 11 | 12 | Clone this repo: 13 | 14 | git clone https://github.com/coverlet-coverage/coverlet.git 15 | cd coverlet 16 | 17 | Building, testing, and packing use all the standard dotnet commands: 18 | 19 | dotnet restore 20 | dotnet build --no-restore 21 | dotnet pack 22 | dotnet test --no-build /p:CollectCoverage=true /p:Include=\"[coverlet.collector]*,[coverlet.core]*,[coverlet.msbuild.tasks]*\" /p:Exclude=\"[coverlet.core.tests.samples.netstandard]*,[coverlet.tests.xunit.extensions]*\" 23 | 24 | NB. You need to `pack` before testing because we have some integration testing that consume packages 25 | 26 | ## Performance testing 27 | 28 | There is a simple performance test for the hit counting instrumentation in the test project `coverlet.core.performancetest`. Build the project with the msbuild step above and then run: 29 | 30 | dotnet test /p:CollectCoverage=true test/coverlet.core.performancetest/ 31 | 32 | The duration of the test can be tweaked by changing the number of iterations in the `[InlineData]` in the `PerformanceTest` class. 33 | 34 | For more realistic testing it is recommended to try out any changes to the hit counting code paths on large, realistic projects. If you don't have any handy https://github.com/dotnet/corefx is an excellent candidate. [This page](https://github.com/dotnet/corefx/blob/master/Documentation/building/code-coverage.md) describes how to run code coverage tests for both the full solution and for individual projects with coverlet from nuget. Suitable projects (listed in order of escalating test durations): 35 | 36 | * System.Collections.Concurrent.Tests 37 | * System.Collections.Tests 38 | * System.Reflection.Metadata.Tests 39 | * System.Xml.Linq.Events.Tests 40 | * System.Runtime.Serialization.Formatters.Tests 41 | 42 | Change to the directory of the library and run the msbuild code coverage command: 43 | 44 | dotnet test /p:Coverage=true 45 | 46 | To run with a development version of coverlet call `dotnet run` instead of the installed coverlet version, e.g.: 47 | 48 | dotnet test /p:Coverage=true /p:CoverageExecutablePath="dotnet run -p C:\...\coverlet\src\coverlet.console\coverlet.console.csproj" 49 | -------------------------------------------------------------------------------- /test/coverlet.core.tests/Helpers/RetryHelperTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System; 5 | using Xunit; 6 | 7 | namespace Coverlet.Core.Helpers.Tests 8 | { 9 | public class RetryHelperTests 10 | { 11 | [Fact] 12 | public void TestRetryWithFixedRetryBackoff() 13 | { 14 | Func retryStrategy = () => 15 | { 16 | return TimeSpan.FromMilliseconds(1); 17 | }; 18 | 19 | var target = new RetryTarget(); 20 | try 21 | { 22 | new RetryHelper().Retry(() => target.TargetActionThrows(), retryStrategy, 7); 23 | } 24 | catch 25 | { 26 | Assert.Equal(7, target.Calls); 27 | } 28 | } 29 | 30 | [Fact] 31 | public void TestRetryWithExponentialRetryBackoff() 32 | { 33 | int currentSleep = 6; 34 | Func retryStrategy = () => 35 | { 36 | var sleep = TimeSpan.FromMilliseconds(currentSleep); 37 | currentSleep *= 2; 38 | return sleep; 39 | }; 40 | 41 | var target = new RetryTarget(); 42 | try 43 | { 44 | new RetryHelper().Retry(() => target.TargetActionThrows(), retryStrategy, 3); 45 | } 46 | catch 47 | { 48 | Assert.Equal(3, target.Calls); 49 | Assert.Equal(24, currentSleep); 50 | } 51 | } 52 | 53 | [Fact] 54 | public void TestRetryFinishesIfSuccessful() 55 | { 56 | Func retryStrategy = () => 57 | { 58 | return TimeSpan.FromMilliseconds(1); 59 | }; 60 | 61 | var target = new RetryTarget(); 62 | new RetryHelper().Retry(() => target.TargetActionThrows5Times(), retryStrategy, 20); 63 | Assert.Equal(6, target.Calls); 64 | } 65 | 66 | } 67 | 68 | public class RetryTarget 69 | { 70 | public int Calls { get; set; } 71 | public void TargetActionThrows() 72 | { 73 | Calls++; 74 | throw new Exception("Simulating Failure"); 75 | } 76 | public void TargetActionThrows5Times() 77 | { 78 | Calls++; 79 | if (Calls < 6) throw new Exception("Simulating Failure"); 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /test/coverlet.core.tests/Coverage/CoverageTests.IntegerOverflow.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System.IO; 5 | using Coverlet.Core.Abstractions; 6 | using Coverlet.Core.Instrumentation; 7 | using Moq; 8 | using Xunit; 9 | 10 | namespace Coverlet.Core.Tests 11 | { 12 | public partial class CoverageTests 13 | { 14 | [Fact] 15 | public void CoverageResult_NegativeLineCoverage_TranslatedToMaxValueOfInt32() 16 | { 17 | var instrumenterResult = new InstrumenterResult 18 | { 19 | HitsFilePath = "HitsFilePath", 20 | SourceLink = "SourceLink", 21 | ModulePath = "ModulePath" 22 | }; 23 | 24 | instrumenterResult.HitCandidates.Add(new HitCandidate(false, 0, 1, 1)); 25 | 26 | var document = new Document 27 | { 28 | Index = 0, 29 | Path = "Path0" 30 | }; 31 | 32 | document.Lines.Add(1, new Line 33 | { 34 | Class = "Class0", 35 | Hits = 0, 36 | Method = "Method0", 37 | Number = 1 38 | }); 39 | 40 | instrumenterResult.Documents.Add("document", document); 41 | 42 | var coveragePrepareResult = new CoveragePrepareResult 43 | { 44 | UseSourceLink = true, 45 | Results = new[] {instrumenterResult}, 46 | Parameters = new CoverageParameters() 47 | }; 48 | 49 | Stream memoryStream = new MemoryStream(); 50 | var binaryWriter = new BinaryWriter(memoryStream); 51 | binaryWriter.Write(1); 52 | binaryWriter.Write(-1); 53 | memoryStream.Position = 0; 54 | 55 | var fileSystemMock = new Mock(); 56 | fileSystemMock.Setup(x => x.Exists(It.IsAny())).Returns(true); 57 | fileSystemMock.Setup(x => x.NewFileStream(It.IsAny(), FileMode.Open, FileAccess.Read)) 58 | .Returns(memoryStream); 59 | 60 | var coverage = new Coverage(coveragePrepareResult, new Mock().Object, new Mock().Object, 61 | fileSystemMock.Object, new Mock().Object); 62 | 63 | CoverageResult coverageResult = coverage.GetCoverageResult(); 64 | coverageResult.Document("document").AssertLinesCovered(BuildConfiguration.Debug, (1, int.MaxValue)); 65 | 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/coverlet.core/Helpers/RetryHelper.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Threading; 7 | using Coverlet.Core.Abstractions; 8 | 9 | namespace Coverlet.Core.Helpers 10 | { 11 | // A slightly amended version of the code found here: https://stackoverflow.com/a/1563234/186184 12 | // This code allows for varying backoff strategies through the use of Func. 13 | internal class RetryHelper : IRetryHelper 14 | { 15 | /// 16 | /// Retry a void method. 17 | /// 18 | /// The action to perform 19 | /// A function returning a Timespan defining the backoff strategy to use. 20 | /// The maximum number of retries before bailing out. Defaults to 3. 21 | public void Retry( 22 | Action action, 23 | Func backoffStrategy, 24 | int maxAttemptCount = 3) 25 | { 26 | Do(() => 27 | { 28 | action(); 29 | return null; 30 | }, backoffStrategy, maxAttemptCount); 31 | } 32 | 33 | /// 34 | /// Retry a method returning type T. 35 | /// 36 | /// The type of the object to return 37 | /// The action to perform 38 | /// A function returning a Timespan defining the backoff strategy to use. 39 | /// The maximum number of retries before bailing out. Defaults to 3. 40 | public T Do( 41 | Func action, 42 | Func backoffStrategy, 43 | int maxAttemptCount = 3) 44 | { 45 | var exceptions = new List(); 46 | 47 | for (int attempted = 0; attempted < maxAttemptCount; attempted++) 48 | { 49 | try 50 | { 51 | if (attempted > 0) 52 | { 53 | Thread.Sleep(backoffStrategy()); 54 | } 55 | return action(); 56 | } 57 | catch (Exception ex) 58 | { 59 | exceptions.Add(ex); 60 | } 61 | } 62 | throw new AggregateException(exceptions); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /test/coverlet.core.tests/Samples/Instrumentation.ExcludeFilter.cs: -------------------------------------------------------------------------------- 1 | // Remember to use full name because adding new using directives change line numbers 2 | 3 | using System; 4 | using System.Threading.Tasks; 5 | 6 | namespace Coverlet.Core.Samples.Tests 7 | { 8 | public class ExcludeFilterNestedAutogeneratedTypes 9 | { 10 | public void Run() 11 | { 12 | NestedToFilterOut nested = new NestedToFilterOut(); 13 | nested.SomeMethodLambda(); 14 | nested.SomeMethodAsync().ConfigureAwait(false).GetAwaiter().GetResult(); 15 | } 16 | 17 | public class NestedToFilterOut 18 | { 19 | public void SomeMethodLambda() => AppDomain.CurrentDomain.ProcessExit += (s, e) => { }; 20 | public Task SomeMethodAsync() => Task.FromResult(new Random().Next()); 21 | } 22 | } 23 | 24 | public static class Issue_689 25 | { 26 | static Issue_689() 27 | { 28 | State = 0; 29 | EventSource_Issue_689.Handle += (s, e) => Handler(1); 30 | Uncoverlet.AddHandler(); 31 | } 32 | 33 | internal static class Uncoverlet 34 | { 35 | internal static void AddHandler() => EventSource_Issue_689.Handle += (s, e) => Handler(2); 36 | } 37 | 38 | public static void Handler(int i) 39 | { 40 | State = i; 41 | } 42 | 43 | public static int State { get; set; } 44 | } 45 | 46 | public static class EventSource_Issue_689 47 | { 48 | public static event EventHandler Handle; 49 | public static void RaiseEvent() 50 | { 51 | Handle?.Invoke(new object(), new object()); 52 | } 53 | } 54 | 55 | public class ExcludeFilterOuterTypes 56 | { 57 | public int Run() 58 | { 59 | return new ExcludeFilterOuterTypes2().Run(); 60 | } 61 | } 62 | 63 | public class ExcludeFilterOuterTypes2 64 | { 65 | public int Run() 66 | { 67 | return 42; 68 | } 69 | } 70 | 71 | public class ExcludeFilterClass1 72 | { 73 | public int Run() => 10 + new ExcludeFilterClass2().Run(); 74 | 75 | public class ExcludeFilterClass2 76 | { 77 | public int Run() => 10 + new ExcludeFilterClass3().Run(); 78 | 79 | public class ExcludeFilterClass3 80 | { 81 | public int Run() => 10 + new ExcludeFilterClass4().Run(); 82 | 83 | public class ExcludeFilterClass4 84 | { 85 | public int Run() => 12; 86 | } 87 | } 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Documentation/Roadmap.md: -------------------------------------------------------------------------------- 1 | # Roadmap 2 | 3 | This document describes the roadmap for coverlet showing priorities. 4 | 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. 5 | All coverlet issues are labeled and categorized to better support this activites. 6 | 7 | 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). 8 | After triage a final correct label is applied and will be taken into account depending on priority order. 9 | We use `needs more info` if we're waiting for answers. 10 | 11 | Default priority order "should" be: 12 | 13 | 1) Bugs: we should fix bugs as soon as possible and for first bugs related to coverage because this is the goal of coverlet. 14 | 15 | Coverage bugs: https://github.com/coverlet-coverage/coverlet/issues?q=is%3Aissue+is%3Aopen+label%3Abug+label%3Atenet-coverage 16 | Other bugs: https://github.com/coverlet-coverage/coverlet/issues?q=is%3Aissue+is%3Aopen+label%3Abug 17 | 18 | 2) New features: analyze and add new features, we have three drivers so features could be related to one of these. 19 | 20 | Feature requests: https://github.com/coverlet-coverage/coverlet/issues?q=is%3Aissue+is%3Aopen+label%3Afeature-request 21 | 22 | 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. 23 | 24 | Performance issues: https://github.com/coverlet-coverage/coverlet/issues?q=is%3Aissue+is%3Aopen+label%3Atenet-performance 25 | 26 | Some new features have got a `Discussion` label if we don't have and agreement yet on semantics. 27 | Discussions: https://github.com/coverlet-coverage/coverlet/issues?q=is%3Aissue+is%3Aopen+label%3Adiscussion 28 | 29 | ## New features roadmap 30 | 31 | This is the list of features we should develop soon as possible: 32 | 33 | ### High priority 34 | 35 | - Allow merge reports solution wide on all flavours https://github.com/coverlet-coverage/coverlet/issues/662 https://github.com/coverlet-coverage/coverlet/issues/357 36 | 37 | - Some perf improvements https://github.com/coverlet-coverage/coverlet/issues/836 38 | 39 | ### Low priority 40 | 41 | - Rethink hits reports strategy https://github.com/coverlet-coverage/coverlet/issues/808 42 | 43 | ## Maintainers discussion channel 44 | 45 | [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".] 46 | 47 | 48 | -------------------------------------------------------------------------------- /src/coverlet.msbuild.tasks/ReportWriter.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System.IO; 5 | using Coverlet.Core; 6 | using Coverlet.Core.Abstractions; 7 | 8 | namespace Coverlet.MSbuild.Tasks 9 | { 10 | internal class ReportWriter 11 | { 12 | private readonly string _coverletMultiTargetFrameworksCurrentTFM; 13 | private readonly string _directory; 14 | private readonly string _output; 15 | private readonly IReporter _reporter; 16 | private readonly IFileSystem _fileSystem; 17 | private readonly IConsole _console; 18 | private readonly ISourceRootTranslator _sourceRootTranslator; 19 | private readonly CoverageResult _result; 20 | 21 | public ReportWriter(string coverletMultiTargetFrameworksCurrentTFM, string directory, string output, 22 | IReporter reporter, IFileSystem fileSystem, IConsole console, CoverageResult result, ISourceRootTranslator sourceRootTranslator) 23 | => (_coverletMultiTargetFrameworksCurrentTFM, _directory, _output, _reporter, _fileSystem, _console, _result, _sourceRootTranslator) = 24 | (coverletMultiTargetFrameworksCurrentTFM, directory, output, reporter, fileSystem, console, result, sourceRootTranslator); 25 | 26 | public string WriteReport() 27 | { 28 | string filename = Path.GetFileName(_output); 29 | 30 | string separatorPoint = string.IsNullOrEmpty(_coverletMultiTargetFrameworksCurrentTFM) ? "" : "."; 31 | 32 | if (filename == string.Empty) 33 | { 34 | // empty filename for instance only directory is passed to CoverletOutput c:\reportpath 35 | // c:\reportpath\coverage.reportedextension 36 | filename = $"coverage.{_coverletMultiTargetFrameworksCurrentTFM}{separatorPoint}{_reporter.Extension}"; 37 | } 38 | else if (Path.HasExtension(filename)) 39 | { 40 | // filename with extension for instance c:\reportpath\file.ext 41 | // we keep user specified name 42 | filename = $"{Path.GetFileNameWithoutExtension(filename)}{separatorPoint}{_coverletMultiTargetFrameworksCurrentTFM}{Path.GetExtension(filename)}"; 43 | } 44 | else 45 | { 46 | // filename without extension for instance c:\reportpath\file 47 | // c:\reportpath\file.reportedextension 48 | filename = $"{filename}{separatorPoint}{_coverletMultiTargetFrameworksCurrentTFM}.{_reporter.Extension}"; 49 | } 50 | 51 | string report = Path.Combine(_directory, filename); 52 | _console.WriteLine($" Generating report '{report}'"); 53 | _fileSystem.WriteAllText(report, _reporter.Report(_result, _sourceRootTranslator)); 54 | return report; 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/coverlet.collector/DataCollection/CoverageWrapper.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using Coverlet.Collector.Utilities.Interfaces; 5 | using Coverlet.Core; 6 | using Coverlet.Core.Abstractions; 7 | 8 | namespace Coverlet.Collector.DataCollection 9 | { 10 | /// 11 | /// Implementation for wrapping over Coverage class in coverlet.core 12 | /// 13 | internal class CoverageWrapper : ICoverageWrapper 14 | { 15 | /// 16 | /// Creates a coverage object from given coverlet settings 17 | /// 18 | /// Coverlet settings 19 | /// Coverlet logger 20 | /// Coverage object 21 | public Coverage CreateCoverage(CoverletSettings settings, ILogger coverletLogger, IInstrumentationHelper instrumentationHelper, IFileSystem fileSystem, ISourceRootTranslator sourceRootTranslator, ICecilSymbolHelper cecilSymbolHelper) 22 | { 23 | CoverageParameters parameters = new() 24 | { 25 | IncludeFilters = settings.IncludeFilters, 26 | IncludeDirectories = settings.IncludeDirectories, 27 | ExcludeFilters = settings.ExcludeFilters, 28 | ExcludedSourceFiles = settings.ExcludeSourceFiles, 29 | ExcludeAttributes = settings.ExcludeAttributes, 30 | IncludeTestAssembly = settings.IncludeTestAssembly, 31 | SingleHit = settings.SingleHit, 32 | MergeWith = settings.MergeWith, 33 | UseSourceLink = settings.UseSourceLink, 34 | SkipAutoProps = settings.SkipAutoProps, 35 | DoesNotReturnAttributes = settings.DoesNotReturnAttributes, 36 | DeterministicReport = settings.DeterministicReport 37 | }; 38 | 39 | return new Coverage( 40 | settings.TestModule, 41 | parameters, 42 | coverletLogger, 43 | instrumentationHelper, 44 | fileSystem, 45 | sourceRootTranslator, 46 | cecilSymbolHelper); 47 | } 48 | 49 | /// 50 | /// Gets the coverage result from provided coverage object 51 | /// 52 | /// Coverage 53 | /// The coverage result 54 | public CoverageResult GetCoverageResult(Coverage coverage) 55 | { 56 | return coverage.GetCoverageResult(); 57 | } 58 | 59 | /// 60 | /// Prepares modules for getting coverage. 61 | /// Wrapper over coverage.PrepareModules 62 | /// 63 | /// 64 | public void PrepareModules(Coverage coverage) 65 | { 66 | coverage.PrepareModules(); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/coverlet.core/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System.Reflection; 5 | using System.Runtime.CompilerServices; 6 | 7 | [assembly: AssemblyKeyFile("coverlet.core.snk")] 8 | 9 | [assembly: InternalsVisibleTo("coverlet.msbuild.tasks, PublicKey=0024000004800000940000000602000000240000525341310004000001000100e5f154a600df71cbdc8a8e69af077379c00889b9a597fbcac536c114911641809ef03b34a33dbe7befe8ea76535889175098bda0710bce04e321689e4458fc7515ca4a074b8618ad61489ec4d71171352e73ed04baeb1d8b8e4855342ef217968da2eebdfc53e119cdd93500a973974a3aed57c400f9bb187f784b0a0924099b")] 10 | [assembly: InternalsVisibleTo("coverlet.console, PublicKey=00240000048000009400000006020000002400005253413100040000010001002515029761c695320036d518d74cc27defddd346afbfb4f16152ae3f4f0e779ae2fe048671a4ac3af595625db8e59fa3b5eeac22c06eacaebb54137ee8973449b68c5da8bbef903c2ac2d0b54143faf82f1b813fd24facfd5b6c7041ae5955ec63ba17cc57037b98eecbe44c7d2833c3aeabcc4e23109763f580067a74adacae")] 11 | [assembly: InternalsVisibleTo("coverlet.collector, PublicKey=00240000048000009400000006020000002400005253413100040000010001003d23b9ef372215da7c81af920b919db5799fd021a1ca10b2e9e0ddac71237a29f8f6361a805a747457e561a7d616417f1870cda099486df25d580a4e11a0738293342881566254d7840e42f42fb9bfd8e8dca354df7dc68db14b2d0cd79bb2bf7afdbd62bd948d81b534cba7a326cf6ee840a1aee5dba0a1c660b30813ca99e5")] 12 | 13 | [assembly: InternalsVisibleTo("coverlet.core.tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100757cf9291d78a82e5bb58a827a3c46c2f959318327ad30d1b52e918321ffbd847fb21565b8576d2a3a24562a93e86c77a298b564a0f1b98f63d7a1441a3a8bcc206da3ed09d5dacc76e122a109a9d3ac608e21a054d667a2bae98510a1f0f653c0e6f58f42b4b3934f6012f5ec4a09b3dfd3e14d437ede1424bdb722aead64ad")] 14 | [assembly: InternalsVisibleTo("coverlet.collector.tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100ed0ed6af9693182615b8dcadc83c918b8d36312f86cefc69539d67d4189cd1b89420e7c3871802ffef7f5ca7816c68ad856c77bf7c230cc07824d96aa5d1237eebd30e246b9a14e22695fb26b40c800f74ea96619092cbd3a5d430d6c003fc7a82e8ccd1e315b935105d9232fe9e99e8d7ff54bba6f191959338d4a3169df9b3")] 15 | [assembly: InternalsVisibleTo("coverlet.integration.tests, PublicKey=002400000480000094000000060200000024000052534131000400000100010001d24efbe9cbc2dc49b7a3d2ae34ca37cfb69b4f450acd768a22ce5cd021c8a38ae7dc68b2809a1ac606ad531b578f192a5690b2986990cbda4dd84ec65a3a4c1c36f6d7bb18f08592b93091535eaee2f0c8e48763ed7f190db2008e1f9e0facd5c0df5aaab74febd3430e09a428a72e5e6b88357f92d78e47512d46ebdc3cbb")] 16 | // Needed to mock internal type https://github.com/Moq/moq4/wiki/Quickstart#advanced-features 17 | [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] -------------------------------------------------------------------------------- /test/coverlet.core.tests/Reporters/Reporters.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System.IO; 5 | using Coverlet.Core.Abstractions; 6 | using Coverlet.MSbuild.Tasks; 7 | using Moq; 8 | using Xunit; 9 | 10 | namespace Coverlet.Core.Reporters.Tests 11 | { 12 | public class Reporters 13 | { 14 | // we use lcov with extension .info and cobertura with extension .cobertura.xml 15 | // to have all possible extension format 16 | // empty coverletOutput is not possible thank's to props default 17 | [Theory] 18 | // single tfm 19 | [InlineData("", "/folder/reportFolder/", "lcov", "/folder/reportFolder/coverage.info")] 20 | [InlineData(null, "/folder/reportFolder/", "cobertura", "/folder/reportFolder/coverage.cobertura.xml")] 21 | [InlineData(null, "/folder/reportFolder/file.ext", "cobertura", "/folder/reportFolder/file.ext")] 22 | [InlineData(null, "/folder/reportFolder/file.ext1.ext2", "cobertura", "/folder/reportFolder/file.ext1.ext2")] 23 | [InlineData(null, "/folder/reportFolder/file", "cobertura", "/folder/reportFolder/file.cobertura.xml")] 24 | [InlineData(null, "file", "cobertura", "file.cobertura.xml")] 25 | // multiple tfm 26 | [InlineData("netcoreapp2.2", "/folder/reportFolder/", "lcov", "/folder/reportFolder/coverage.netcoreapp2.2.info")] 27 | [InlineData("netcoreapp2.2", "/folder/reportFolder/", "cobertura", "/folder/reportFolder/coverage.netcoreapp2.2.cobertura.xml")] 28 | [InlineData("net472", "/folder/reportFolder/file.ext", "cobertura", "/folder/reportFolder/file.net472.ext")] 29 | [InlineData("net472", "/folder/reportFolder/file.ext1.ext2", "cobertura", "/folder/reportFolder/file.ext1.net472.ext2")] 30 | [InlineData("netcoreapp2.2", "/folder/reportFolder/file", "cobertura", "/folder/reportFolder/file.netcoreapp2.2.cobertura.xml")] 31 | [InlineData("netcoreapp2.2", "file", "cobertura", "file.netcoreapp2.2.cobertura.xml")] 32 | public void Msbuild_ReportWriter(string coverletMultiTargetFrameworksCurrentTFM, string coverletOutput, string reportFormat, string expectedFileName) 33 | { 34 | var fileSystem = new Mock(); 35 | var console = new Mock(); 36 | 37 | var reportWriter = new ReportWriter( 38 | coverletMultiTargetFrameworksCurrentTFM, 39 | // mimic code inside CoverageResultTask.cs 40 | Path.GetDirectoryName(coverletOutput), 41 | coverletOutput, 42 | new ReporterFactory(reportFormat).CreateReporter(), 43 | fileSystem.Object, 44 | console.Object, 45 | new CoverageResult() { Modules = new Modules(), Parameters = new CoverageParameters() }, null); 46 | 47 | string path = reportWriter.WriteReport(); 48 | // Path.Combine depends on OS so we can change only win side to avoid duplication 49 | Assert.Equal(path.Replace('/', Path.DirectorySeparatorChar), expectedFileName.Replace('/', Path.DirectorySeparatorChar)); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /test/coverlet.integration.tests/DotnetTool.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using Coverlet.Tests.Xunit.Extensions; 5 | using System.IO; 6 | using System.Linq; 7 | using Xunit; 8 | 9 | namespace Coverlet.Integration.Tests 10 | { 11 | public class DotnetGlobalTools : BaseTest 12 | { 13 | private string InstallTool(string projectPath) 14 | { 15 | _ = DotnetCli($"tool install coverlet.console --version {GetPackageVersion("*console*.nupkg")} --tool-path \"{Path.Combine(projectPath, "coverletTool")}\"", out string standardOutput, out _, projectPath); 16 | Assert.Contains("was successfully installed.", standardOutput); 17 | return Path.Combine(projectPath, "coverletTool", "coverlet "); 18 | } 19 | 20 | [ConditionalFact] 21 | [SkipOnOS(OS.Linux)] 22 | [SkipOnOS(OS.MacOS)] 23 | public void DotnetTool() 24 | { 25 | using ClonedTemplateProject clonedTemplateProject = CloneTemplateProject(); 26 | UpdateNugeConfigtWithLocalPackageFolder(clonedTemplateProject.ProjectRootPath!); 27 | string coverletToolCommandPath = InstallTool(clonedTemplateProject.ProjectRootPath!); 28 | DotnetCli($"build {clonedTemplateProject.ProjectRootPath}", out string standardOutput, out string standardError); 29 | string publishedTestFile = clonedTemplateProject.GetFiles("*" + ClonedTemplateProject.AssemblyName + ".dll").Single(f => !f.Contains("obj") && !f.Contains("ref")); 30 | RunCommand(coverletToolCommandPath, $"\"{publishedTestFile}\" --target \"dotnet\" --targetargs \"test {Path.Combine(clonedTemplateProject.ProjectRootPath, ClonedTemplateProject.ProjectFileName)} --no-build\" --include-test-assembly --output \"{clonedTemplateProject.ProjectRootPath}\"\\", out standardOutput, out standardError); 31 | Assert.Contains("Passed!", standardOutput); 32 | AssertCoverage(clonedTemplateProject, standardOutput: standardOutput); 33 | } 34 | 35 | [ConditionalFact] 36 | [SkipOnOS(OS.Linux)] 37 | [SkipOnOS(OS.MacOS)] 38 | public void StandAlone() 39 | { 40 | using ClonedTemplateProject clonedTemplateProject = CloneTemplateProject(); 41 | UpdateNugeConfigtWithLocalPackageFolder(clonedTemplateProject.ProjectRootPath!); 42 | string coverletToolCommandPath = InstallTool(clonedTemplateProject.ProjectRootPath!); 43 | DotnetCli($"build {clonedTemplateProject.ProjectRootPath}", out string standardOutput, out string standardError); 44 | string publishedTestFile = clonedTemplateProject.GetFiles("*" + ClonedTemplateProject.AssemblyName + ".dll").Single(f => !f.Contains("obj") && !f.Contains("ref")); 45 | RunCommand(coverletToolCommandPath, $"\"{Path.GetDirectoryName(publishedTestFile)}\" --target \"dotnet\" --targetargs \"{publishedTestFile}\" --output \"{clonedTemplateProject.ProjectRootPath}\"\\", out standardOutput, out standardError); 46 | Assert.Contains("Hello World!", standardOutput); 47 | AssertCoverage(clonedTemplateProject, standardOutput: standardOutput); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/coverlet.core/Reporters/LcovReporter.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using Coverlet.Core.Abstractions; 8 | 9 | namespace Coverlet.Core.Reporters 10 | { 11 | internal class LcovReporter : IReporter 12 | { 13 | public ReporterOutputType OutputType => ReporterOutputType.File; 14 | 15 | public string Format => "lcov"; 16 | 17 | public string Extension => "info"; 18 | 19 | public string Report(CoverageResult result, ISourceRootTranslator sourceRootTranslator) 20 | { 21 | if (result.Parameters.DeterministicReport) 22 | { 23 | throw new NotSupportedException("Deterministic report not supported by lcov reporter"); 24 | } 25 | 26 | var summary = new CoverageSummary(); 27 | var lcov = new List(); 28 | 29 | foreach (KeyValuePair module in result.Modules) 30 | { 31 | foreach (KeyValuePair doc in module.Value) 32 | { 33 | CoverageDetails docLineCoverage = summary.CalculateLineCoverage(doc.Value); 34 | CoverageDetails docBranchCoverage = summary.CalculateBranchCoverage(doc.Value); 35 | CoverageDetails docMethodCoverage = summary.CalculateMethodCoverage(doc.Value); 36 | 37 | lcov.Add("SF:" + doc.Key); 38 | foreach (KeyValuePair @class in doc.Value) 39 | { 40 | foreach (KeyValuePair method in @class.Value) 41 | { 42 | // Skip all methods with no lines 43 | if (method.Value.Lines.Count == 0) 44 | continue; 45 | 46 | lcov.Add($"FN:{method.Value.Lines.First().Key - 1},{method.Key}"); 47 | lcov.Add($"FNDA:{method.Value.Lines.First().Value},{method.Key}"); 48 | 49 | foreach (KeyValuePair line in method.Value.Lines) 50 | lcov.Add($"DA:{line.Key},{line.Value}"); 51 | 52 | foreach (BranchInfo branch in method.Value.Branches) 53 | { 54 | lcov.Add($"BRDA:{branch.Line},{branch.Offset},{branch.Path},{branch.Hits}"); 55 | } 56 | } 57 | } 58 | 59 | lcov.Add($"LF:{docLineCoverage.Total}"); 60 | lcov.Add($"LH:{docLineCoverage.Covered}"); 61 | 62 | lcov.Add($"BRF:{docBranchCoverage.Total}"); 63 | lcov.Add($"BRH:{docBranchCoverage.Covered}"); 64 | 65 | lcov.Add($"FNF:{docMethodCoverage.Total}"); 66 | lcov.Add($"FNH:{docMethodCoverage.Covered}"); 67 | 68 | lcov.Add("end_of_record"); 69 | } 70 | } 71 | 72 | return string.Join(Environment.NewLine, lcov); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/coverlet.core/Reporters/TeamCityReporter.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System; 5 | using System.Globalization; 6 | using System.Text; 7 | using Coverlet.Core.Abstractions; 8 | 9 | namespace Coverlet.Core.Reporters 10 | { 11 | internal class TeamCityReporter : IReporter 12 | { 13 | public ReporterOutputType OutputType => ReporterOutputType.Console; 14 | 15 | public string Format => "teamcity"; 16 | 17 | public string Extension => null; 18 | 19 | public string Report(CoverageResult result, ISourceRootTranslator sourceRootTranslator) 20 | { 21 | if (result.Parameters.DeterministicReport) 22 | { 23 | throw new NotSupportedException("Deterministic report not supported by teamcity reporter"); 24 | } 25 | 26 | // Calculate coverage 27 | var summary = new CoverageSummary(); 28 | CoverageDetails overallLineCoverage = summary.CalculateLineCoverage(result.Modules); 29 | CoverageDetails overallBranchCoverage = summary.CalculateBranchCoverage(result.Modules); 30 | CoverageDetails overallMethodCoverage = summary.CalculateMethodCoverage(result.Modules); 31 | 32 | // Report coverage 33 | var stringBuilder = new StringBuilder(); 34 | OutputLineCoverage(overallLineCoverage, stringBuilder); 35 | OutputBranchCoverage(overallBranchCoverage, stringBuilder); 36 | OutputMethodCoverage(overallMethodCoverage, stringBuilder); 37 | 38 | // Return a placeholder 39 | return stringBuilder.ToString(); 40 | } 41 | 42 | private static void OutputLineCoverage(CoverageDetails coverageDetails, StringBuilder builder) 43 | { 44 | // The number of covered lines 45 | OutputTeamCityServiceMessage("CodeCoverageAbsLCovered", coverageDetails.Covered, builder); 46 | 47 | // Line-level code coverage 48 | OutputTeamCityServiceMessage("CodeCoverageAbsLTotal", coverageDetails.Total, builder); 49 | } 50 | 51 | private static void OutputBranchCoverage(CoverageDetails coverageDetails, StringBuilder builder) 52 | { 53 | // The number of covered branches 54 | OutputTeamCityServiceMessage("CodeCoverageAbsBCovered", coverageDetails.Covered, builder); 55 | 56 | // Branch-level code coverage 57 | OutputTeamCityServiceMessage("CodeCoverageAbsBTotal", coverageDetails.Total, builder); 58 | } 59 | 60 | private static void OutputMethodCoverage(CoverageDetails coverageDetails, StringBuilder builder) 61 | { 62 | // The number of covered methods 63 | OutputTeamCityServiceMessage("CodeCoverageAbsMCovered", coverageDetails.Covered, builder); 64 | 65 | // Method-level code coverage 66 | OutputTeamCityServiceMessage("CodeCoverageAbsMTotal", coverageDetails.Total, builder); 67 | } 68 | 69 | private static void OutputTeamCityServiceMessage(string key, double value, StringBuilder builder) 70 | { 71 | builder.AppendLine($"##teamcity[buildStatisticValue key='{key}' value='{value.ToString("0.##", new CultureInfo("en-US"))}']"); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Documentation/Examples/VSTest/HelloWorld/HelloWorld.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29521.150 5 | MinimumVisualStudioVersion = 15.0.26124.0 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "XUnitTestProject1", "XUnitTestProject1\XUnitTestProject1.csproj", "{26290689-7824-4A08-89B0-6C2F44085D7C}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ClassLibrary1", "ClassLibrary1\ClassLibrary1.csproj", "{E3BAA878-1CFC-4F94-B962-BAD20CEBFFAB}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{6078A839-FBD0-4135-A552-7A7A0D80A587}" 11 | ProjectSection(SolutionItems) = preProject 12 | HowTo.md = HowTo.md 13 | EndProjectSection 14 | EndProject 15 | Global 16 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 17 | Debug|Any CPU = Debug|Any CPU 18 | Debug|x64 = Debug|x64 19 | Debug|x86 = Debug|x86 20 | Release|Any CPU = Release|Any CPU 21 | Release|x64 = Release|x64 22 | Release|x86 = Release|x86 23 | EndGlobalSection 24 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 25 | {26290689-7824-4A08-89B0-6C2F44085D7C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 26 | {26290689-7824-4A08-89B0-6C2F44085D7C}.Debug|Any CPU.Build.0 = Debug|Any CPU 27 | {26290689-7824-4A08-89B0-6C2F44085D7C}.Debug|x64.ActiveCfg = Debug|Any CPU 28 | {26290689-7824-4A08-89B0-6C2F44085D7C}.Debug|x64.Build.0 = Debug|Any CPU 29 | {26290689-7824-4A08-89B0-6C2F44085D7C}.Debug|x86.ActiveCfg = Debug|Any CPU 30 | {26290689-7824-4A08-89B0-6C2F44085D7C}.Debug|x86.Build.0 = Debug|Any CPU 31 | {26290689-7824-4A08-89B0-6C2F44085D7C}.Release|Any CPU.ActiveCfg = Release|Any CPU 32 | {26290689-7824-4A08-89B0-6C2F44085D7C}.Release|Any CPU.Build.0 = Release|Any CPU 33 | {26290689-7824-4A08-89B0-6C2F44085D7C}.Release|x64.ActiveCfg = Release|Any CPU 34 | {26290689-7824-4A08-89B0-6C2F44085D7C}.Release|x64.Build.0 = Release|Any CPU 35 | {26290689-7824-4A08-89B0-6C2F44085D7C}.Release|x86.ActiveCfg = Release|Any CPU 36 | {26290689-7824-4A08-89B0-6C2F44085D7C}.Release|x86.Build.0 = Release|Any CPU 37 | {E3BAA878-1CFC-4F94-B962-BAD20CEBFFAB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 38 | {E3BAA878-1CFC-4F94-B962-BAD20CEBFFAB}.Debug|Any CPU.Build.0 = Debug|Any CPU 39 | {E3BAA878-1CFC-4F94-B962-BAD20CEBFFAB}.Debug|x64.ActiveCfg = Debug|Any CPU 40 | {E3BAA878-1CFC-4F94-B962-BAD20CEBFFAB}.Debug|x64.Build.0 = Debug|Any CPU 41 | {E3BAA878-1CFC-4F94-B962-BAD20CEBFFAB}.Debug|x86.ActiveCfg = Debug|Any CPU 42 | {E3BAA878-1CFC-4F94-B962-BAD20CEBFFAB}.Debug|x86.Build.0 = Debug|Any CPU 43 | {E3BAA878-1CFC-4F94-B962-BAD20CEBFFAB}.Release|Any CPU.ActiveCfg = Release|Any CPU 44 | {E3BAA878-1CFC-4F94-B962-BAD20CEBFFAB}.Release|Any CPU.Build.0 = Release|Any CPU 45 | {E3BAA878-1CFC-4F94-B962-BAD20CEBFFAB}.Release|x64.ActiveCfg = Release|Any CPU 46 | {E3BAA878-1CFC-4F94-B962-BAD20CEBFFAB}.Release|x64.Build.0 = Release|Any CPU 47 | {E3BAA878-1CFC-4F94-B962-BAD20CEBFFAB}.Release|x86.ActiveCfg = Release|Any CPU 48 | {E3BAA878-1CFC-4F94-B962-BAD20CEBFFAB}.Release|x86.Build.0 = Release|Any CPU 49 | EndGlobalSection 50 | GlobalSection(SolutionProperties) = preSolution 51 | HideSolutionNode = FALSE 52 | EndGlobalSection 53 | GlobalSection(ExtensibilityGlobals) = postSolution 54 | SolutionGuid = {070BB83A-CEA3-44DF-B61C-CA6225F66E29} 55 | EndGlobalSection 56 | EndGlobal 57 | -------------------------------------------------------------------------------- /src/coverlet.collector/build/netstandard1.0/coverlet.collector.targets: -------------------------------------------------------------------------------- 1 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | $(VSTestTestAdapterPath);$(MSBuildThisFileDirectory) 23 | 24 | 25 | 26 | 27 | <_CoverletSdkNETCoreSdkVersion>$(NETCoreSdkVersion) 28 | <_CoverletSdkNETCoreSdkVersion Condition="$(_CoverletSdkNETCoreSdkVersion.Contains('-'))">$(_CoverletSdkNETCoreSdkVersion.Split('-')[0]) 29 | <_CoverletSdkMinVersionWithDependencyTarget>3.1.300 30 | <_CoverletSourceRootTargetName>CoverletGetPathMap 31 | <_CoverletSourceRootTargetName Condition="'$([System.Version]::Parse($(_CoverletSdkNETCoreSdkVersion)).CompareTo($([System.Version]::Parse($(_CoverletSdkMinVersionWithDependencyTarget)))))' >= '0' ">InitializeSourceRootMappedPaths 32 | 33 | 34 | 35 | 39 | 41 | 42 | 43 | <_byProject Include="@(_LocalTopLevelSourceRoot->'%(MSBuildSourceProjectFile)')" OriginalPath="%(Identity)" /> 44 | <_mapping Include="@(_byProject->'%(Identity)|%(OriginalPath)=%(MappedPath)')" /> 45 | 46 | 47 | <_sourceRootMappingFilePath>$([MSBuild]::EnsureTrailingSlash('$(OutputPath)'))CoverletSourceRootsMapping 48 | 49 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /test/coverlet.tests.remoteexecutor/Program.cs: -------------------------------------------------------------------------------- 1 | // This code is an adapted porting of CoreFx RemoteExecutor 2 | // https://github.com/dotnet/arcade/tree/master/src/Microsoft.DotNet.RemoteExecutor/src 3 | 4 | using System; 5 | using System.IO; 6 | using System.Reflection; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Runtime.ExceptionServices; 10 | using System.Runtime.Loader; 11 | 12 | namespace Coverlet.Tests.RemoteExecutor 13 | { 14 | /// 15 | /// Provides an entry point in a new process that will load a specified method and invoke it. 16 | /// 17 | internal static class Program 18 | { 19 | private static int Main(string[] args) 20 | { 21 | string assemlbyFilePath = args[0]; 22 | string typeName = args[1]; 23 | string methodName = args[2]; 24 | string exceptionFile = args[3]; 25 | 26 | string[] additionalArgs = args.Length > 4 ? 27 | args.Subarray(4, args.Length - 4) : 28 | Array.Empty(); 29 | 30 | Assembly a = null; 31 | Type t = null; 32 | MethodInfo mi = null; 33 | object instance = null; 34 | int exitCode = 0; 35 | try 36 | { 37 | // Create the test class if necessary 38 | a = AssemblyLoadContext.Default.LoadFromAssemblyPath(assemlbyFilePath); 39 | t = a.GetType(typeName); 40 | mi = t.GetTypeInfo().GetDeclaredMethod(methodName); 41 | if (!mi.IsStatic) 42 | { 43 | instance = Activator.CreateInstance(t); 44 | } 45 | 46 | // Invoke the test 47 | object result = mi.Invoke(instance, additionalArgs); 48 | 49 | if (result is Task task) 50 | { 51 | exitCode = task.GetAwaiter().GetResult(); 52 | } 53 | else if (result is int exit) 54 | { 55 | exitCode = exit; 56 | } 57 | } 58 | catch (Exception exc) 59 | { 60 | if (exc is TargetInvocationException && exc.InnerException != null) 61 | exc = exc.InnerException; 62 | 63 | var output = new StringBuilder(); 64 | output.AppendLine(); 65 | output.AppendLine("Child exception:"); 66 | output.AppendLine(" " + exc); 67 | output.AppendLine(); 68 | output.AppendLine("Child process:"); 69 | output.AppendLine(string.Format(" {0} {1} {2}", a, t, mi)); 70 | output.AppendLine(); 71 | 72 | if (additionalArgs.Length > 0) 73 | { 74 | output.AppendLine("Child arguments:"); 75 | output.AppendLine(" " + string.Join(", ", additionalArgs)); 76 | } 77 | 78 | File.WriteAllText(exceptionFile, output.ToString()); 79 | 80 | ExceptionDispatchInfo.Capture(exc).Throw(); 81 | } 82 | finally 83 | { 84 | (instance as IDisposable)?.Dispose(); 85 | } 86 | 87 | return exitCode; 88 | } 89 | 90 | private static T[] Subarray(this T[] arr, int offset, int count) 91 | { 92 | var newArr = new T[count]; 93 | Array.Copy(arr, offset, newArr, 0, count); 94 | return newArr; 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /Documentation/Examples/VSTest/DeterministicBuild/DeterministicBuild.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30014.187 5 | MinimumVisualStudioVersion = 15.0.26124.0 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "XUnitTestProject1", "XUnitTestProject1\XUnitTestProject1.csproj", "{BFF46C49-E8A2-4BA9-9A8D-C56C933E3973}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ClassLibrary1", "ClassLibrary1\ClassLibrary1.csproj", "{47C1D631-2ACB-47CF-BE3A-F8FA42715D7B}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8AE3B75E-33BA-4E07-AD78-2DBCC3392262}" 11 | ProjectSection(SolutionItems) = preProject 12 | DeterministicBuild.targets = DeterministicBuild.targets 13 | Directory.Build.props = Directory.Build.props 14 | Directory.Build.targets = Directory.Build.targets 15 | HowTo.md = HowTo.md 16 | EndProjectSection 17 | EndProject 18 | Global 19 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 20 | Debug|Any CPU = Debug|Any CPU 21 | Debug|x64 = Debug|x64 22 | Debug|x86 = Debug|x86 23 | Release|Any CPU = Release|Any CPU 24 | Release|x64 = Release|x64 25 | Release|x86 = Release|x86 26 | EndGlobalSection 27 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 28 | {BFF46C49-E8A2-4BA9-9A8D-C56C933E3973}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {BFF46C49-E8A2-4BA9-9A8D-C56C933E3973}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {BFF46C49-E8A2-4BA9-9A8D-C56C933E3973}.Debug|x64.ActiveCfg = Debug|Any CPU 31 | {BFF46C49-E8A2-4BA9-9A8D-C56C933E3973}.Debug|x64.Build.0 = Debug|Any CPU 32 | {BFF46C49-E8A2-4BA9-9A8D-C56C933E3973}.Debug|x86.ActiveCfg = Debug|Any CPU 33 | {BFF46C49-E8A2-4BA9-9A8D-C56C933E3973}.Debug|x86.Build.0 = Debug|Any CPU 34 | {BFF46C49-E8A2-4BA9-9A8D-C56C933E3973}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {BFF46C49-E8A2-4BA9-9A8D-C56C933E3973}.Release|Any CPU.Build.0 = Release|Any CPU 36 | {BFF46C49-E8A2-4BA9-9A8D-C56C933E3973}.Release|x64.ActiveCfg = Release|Any CPU 37 | {BFF46C49-E8A2-4BA9-9A8D-C56C933E3973}.Release|x64.Build.0 = Release|Any CPU 38 | {BFF46C49-E8A2-4BA9-9A8D-C56C933E3973}.Release|x86.ActiveCfg = Release|Any CPU 39 | {BFF46C49-E8A2-4BA9-9A8D-C56C933E3973}.Release|x86.Build.0 = Release|Any CPU 40 | {47C1D631-2ACB-47CF-BE3A-F8FA42715D7B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 41 | {47C1D631-2ACB-47CF-BE3A-F8FA42715D7B}.Debug|Any CPU.Build.0 = Debug|Any CPU 42 | {47C1D631-2ACB-47CF-BE3A-F8FA42715D7B}.Debug|x64.ActiveCfg = Debug|Any CPU 43 | {47C1D631-2ACB-47CF-BE3A-F8FA42715D7B}.Debug|x64.Build.0 = Debug|Any CPU 44 | {47C1D631-2ACB-47CF-BE3A-F8FA42715D7B}.Debug|x86.ActiveCfg = Debug|Any CPU 45 | {47C1D631-2ACB-47CF-BE3A-F8FA42715D7B}.Debug|x86.Build.0 = Debug|Any CPU 46 | {47C1D631-2ACB-47CF-BE3A-F8FA42715D7B}.Release|Any CPU.ActiveCfg = Release|Any CPU 47 | {47C1D631-2ACB-47CF-BE3A-F8FA42715D7B}.Release|Any CPU.Build.0 = Release|Any CPU 48 | {47C1D631-2ACB-47CF-BE3A-F8FA42715D7B}.Release|x64.ActiveCfg = Release|Any CPU 49 | {47C1D631-2ACB-47CF-BE3A-F8FA42715D7B}.Release|x64.Build.0 = Release|Any CPU 50 | {47C1D631-2ACB-47CF-BE3A-F8FA42715D7B}.Release|x86.ActiveCfg = Release|Any CPU 51 | {47C1D631-2ACB-47CF-BE3A-F8FA42715D7B}.Release|x86.Build.0 = Release|Any CPU 52 | EndGlobalSection 53 | GlobalSection(SolutionProperties) = preSolution 54 | HideSolutionNode = FALSE 55 | EndGlobalSection 56 | GlobalSection(ExtensibilityGlobals) = postSolution 57 | SolutionGuid = {89E650B4-E15F-46F0-B8F4-CE372B2092AB} 58 | EndGlobalSection 59 | EndGlobal 60 | -------------------------------------------------------------------------------- /Documentation/Examples/MSBuild/DeterministicBuild/DeterministicBuild.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30014.187 5 | MinimumVisualStudioVersion = 15.0.26124.0 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "XUnitTestProject1", "XUnitTestProject1\XUnitTestProject1.csproj", "{BFF46C49-E8A2-4BA9-9A8D-C56C933E3973}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ClassLibrary1", "ClassLibrary1\ClassLibrary1.csproj", "{47C1D631-2ACB-47CF-BE3A-F8FA42715D7B}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8AE3B75E-33BA-4E07-AD78-2DBCC3392262}" 11 | ProjectSection(SolutionItems) = preProject 12 | DeterministicBuild.targets = DeterministicBuild.targets 13 | Directory.Build.props = Directory.Build.props 14 | Directory.Build.targets = Directory.Build.targets 15 | HowTo.md = HowTo.md 16 | EndProjectSection 17 | EndProject 18 | Global 19 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 20 | Debug|Any CPU = Debug|Any CPU 21 | Debug|x64 = Debug|x64 22 | Debug|x86 = Debug|x86 23 | Release|Any CPU = Release|Any CPU 24 | Release|x64 = Release|x64 25 | Release|x86 = Release|x86 26 | EndGlobalSection 27 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 28 | {BFF46C49-E8A2-4BA9-9A8D-C56C933E3973}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {BFF46C49-E8A2-4BA9-9A8D-C56C933E3973}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {BFF46C49-E8A2-4BA9-9A8D-C56C933E3973}.Debug|x64.ActiveCfg = Debug|Any CPU 31 | {BFF46C49-E8A2-4BA9-9A8D-C56C933E3973}.Debug|x64.Build.0 = Debug|Any CPU 32 | {BFF46C49-E8A2-4BA9-9A8D-C56C933E3973}.Debug|x86.ActiveCfg = Debug|Any CPU 33 | {BFF46C49-E8A2-4BA9-9A8D-C56C933E3973}.Debug|x86.Build.0 = Debug|Any CPU 34 | {BFF46C49-E8A2-4BA9-9A8D-C56C933E3973}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {BFF46C49-E8A2-4BA9-9A8D-C56C933E3973}.Release|Any CPU.Build.0 = Release|Any CPU 36 | {BFF46C49-E8A2-4BA9-9A8D-C56C933E3973}.Release|x64.ActiveCfg = Release|Any CPU 37 | {BFF46C49-E8A2-4BA9-9A8D-C56C933E3973}.Release|x64.Build.0 = Release|Any CPU 38 | {BFF46C49-E8A2-4BA9-9A8D-C56C933E3973}.Release|x86.ActiveCfg = Release|Any CPU 39 | {BFF46C49-E8A2-4BA9-9A8D-C56C933E3973}.Release|x86.Build.0 = Release|Any CPU 40 | {47C1D631-2ACB-47CF-BE3A-F8FA42715D7B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 41 | {47C1D631-2ACB-47CF-BE3A-F8FA42715D7B}.Debug|Any CPU.Build.0 = Debug|Any CPU 42 | {47C1D631-2ACB-47CF-BE3A-F8FA42715D7B}.Debug|x64.ActiveCfg = Debug|Any CPU 43 | {47C1D631-2ACB-47CF-BE3A-F8FA42715D7B}.Debug|x64.Build.0 = Debug|Any CPU 44 | {47C1D631-2ACB-47CF-BE3A-F8FA42715D7B}.Debug|x86.ActiveCfg = Debug|Any CPU 45 | {47C1D631-2ACB-47CF-BE3A-F8FA42715D7B}.Debug|x86.Build.0 = Debug|Any CPU 46 | {47C1D631-2ACB-47CF-BE3A-F8FA42715D7B}.Release|Any CPU.ActiveCfg = Release|Any CPU 47 | {47C1D631-2ACB-47CF-BE3A-F8FA42715D7B}.Release|Any CPU.Build.0 = Release|Any CPU 48 | {47C1D631-2ACB-47CF-BE3A-F8FA42715D7B}.Release|x64.ActiveCfg = Release|Any CPU 49 | {47C1D631-2ACB-47CF-BE3A-F8FA42715D7B}.Release|x64.Build.0 = Release|Any CPU 50 | {47C1D631-2ACB-47CF-BE3A-F8FA42715D7B}.Release|x86.ActiveCfg = Release|Any CPU 51 | {47C1D631-2ACB-47CF-BE3A-F8FA42715D7B}.Release|x86.Build.0 = Release|Any CPU 52 | EndGlobalSection 53 | GlobalSection(SolutionProperties) = preSolution 54 | HideSolutionNode = FALSE 55 | EndGlobalSection 56 | GlobalSection(ExtensibilityGlobals) = postSolution 57 | SolutionGuid = {89E650B4-E15F-46F0-B8F4-CE372B2092AB} 58 | EndGlobalSection 59 | EndGlobal 60 | -------------------------------------------------------------------------------- /test/coverlet.core.tests/Samples/Instrumentation.AsyncAwaitValueTask.cs: -------------------------------------------------------------------------------- 1 | // Remember to use full name because adding new using directives change line numbers 2 | 3 | using System; 4 | using System.IO; 5 | using System.Threading.Tasks; 6 | 7 | namespace Coverlet.Core.Samples.Tests 8 | { 9 | public class AsyncAwaitValueTask 10 | { 11 | async public ValueTask AsyncExecution(bool skipLast) 12 | { 13 | var bytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }; 14 | 15 | var stream = new MemoryStream(bytes); 16 | stream.Position = 0; 17 | 18 | int res = 0; 19 | res += await Async(stream); 20 | 21 | res += await Async(stream); 22 | 23 | if (!skipLast) 24 | { 25 | res += await Async(stream); 26 | } 27 | 28 | return res; 29 | } 30 | 31 | async public ValueTask Async(System.IO.MemoryStream stream) 32 | { 33 | var buffer = new byte[4]; 34 | await stream.ReadAsync(buffer.AsMemory()); // This overload of ReadAsync() returns a ValueTask 35 | return buffer[0] + buffer[1] + buffer[2] + buffer[3]; 36 | } 37 | 38 | async public ValueTask AsyncExecution(int val) 39 | { 40 | var bytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; 41 | 42 | var stream = new MemoryStream(bytes); 43 | stream.Position = 0; 44 | 45 | int res = 0; 46 | switch (val) 47 | { 48 | case 1: 49 | { 50 | res += await Async(stream); 51 | break; 52 | } 53 | case 2: 54 | { 55 | res += await Async(stream) + await Async(stream); 56 | break; 57 | } 58 | case 3: 59 | { 60 | res += await Async(stream) + await Async(stream) + 61 | await Async(stream); 62 | break; 63 | } 64 | case 4: 65 | { 66 | res += await Async(stream) + await Async(stream) + 67 | await Async(stream) + await Async(stream); 68 | break; 69 | } 70 | default: 71 | break; 72 | } 73 | return res; 74 | } 75 | 76 | async public ValueTask SyncExecution() 77 | { 78 | await Sync(); 79 | } 80 | 81 | public ValueTask Sync() 82 | { 83 | return default(ValueTask); 84 | } 85 | 86 | async public ValueTask ConfigureAwait() 87 | { 88 | var bytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }; 89 | 90 | var stream = new MemoryStream(bytes); 91 | stream.Position = 0; 92 | 93 | await Async(stream).ConfigureAwait(false); 94 | return 42; 95 | } 96 | 97 | async public Task WrappingValueTaskAsTask() 98 | { 99 | var bytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }; 100 | 101 | var stream = new MemoryStream(bytes); 102 | stream.Position = 0; 103 | 104 | var task = Async(stream).AsTask(); 105 | 106 | return await task; 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /test/coverlet.integration.tests/AssertHelper.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System; 5 | using System.Collections.Generic; 6 | using System.IO; 7 | using System.Linq; 8 | using Coverlet.Core; 9 | using Xunit.Sdk; 10 | 11 | namespace Coverlet.Integration.Tests 12 | { 13 | internal static class AssertHelper 14 | { 15 | public static Classes Document(this Modules modules, string docName) 16 | { 17 | if (docName is null) 18 | { 19 | throw new ArgumentNullException(nameof(docName)); 20 | } 21 | 22 | foreach (KeyValuePair module in modules) 23 | { 24 | foreach (KeyValuePair document in module.Value) 25 | { 26 | if (Path.GetFileName(document.Key) == docName) 27 | { 28 | return document.Value; 29 | } 30 | } 31 | } 32 | 33 | throw new XunitException($"Document not found '{docName}'"); 34 | } 35 | 36 | public static Methods Class(this Classes classes, string className) 37 | { 38 | if (className is null) 39 | { 40 | throw new ArgumentNullException(nameof(className)); 41 | } 42 | 43 | foreach (KeyValuePair @class in classes) 44 | { 45 | if (@class.Key == className) 46 | { 47 | return @class.Value; 48 | } 49 | } 50 | 51 | throw new XunitException($"Document not found '{className}'"); 52 | } 53 | 54 | public static Method Method(this Methods methods, string methodName) 55 | { 56 | if (methodName is null) 57 | { 58 | throw new ArgumentNullException(nameof(methodName)); 59 | } 60 | 61 | foreach (KeyValuePair method in methods) 62 | { 63 | if (method.Key.Contains(methodName)) 64 | { 65 | return method.Value; 66 | } 67 | } 68 | 69 | throw new XunitException($"Document not found '{methodName}'"); 70 | } 71 | 72 | public static void AssertLinesCovered(this Method method, params (int line, int hits)[] lines) 73 | { 74 | if (lines is null) 75 | { 76 | throw new ArgumentNullException(nameof(lines)); 77 | } 78 | 79 | var linesToCover = new List(lines.Select(l => l.line)); 80 | 81 | foreach (KeyValuePair line in method.Lines) 82 | { 83 | foreach ((int lineToCheck, int expectedHits) in lines) 84 | { 85 | if (line.Key == lineToCheck) 86 | { 87 | linesToCover.Remove(line.Key); 88 | if (line.Value != expectedHits) 89 | { 90 | throw new XunitException($"Unexpected hits expected line: {lineToCheck} hits: {expectedHits} actual hits: {line.Value}"); 91 | } 92 | } 93 | } 94 | } 95 | 96 | if (linesToCover.Count != 0) 97 | { 98 | throw new XunitException($"Not all requested line found, {linesToCover.Select(l => l.ToString()).Aggregate((a, b) => $"{a}, {b}")}"); 99 | } 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/coverlet.msbuild.tasks/coverlet.msbuild.tasks.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | netstandard2.0 6 | coverlet.msbuild.tasks 7 | true 8 | $(TargetsForTfmSpecificContentInPackage);PackBuildOutputs 9 | build 10 | false 11 | 17 | true 18 | 19 | 20 | 21 | 22 | coverlet.msbuild 23 | coverlet.msbuild 24 | tonerdo 25 | MIT 26 | https://github.com/coverlet-coverage/coverlet 27 | https://raw.githubusercontent.com/tonerdo/coverlet/master/_assets/coverlet-icon.svg?sanitize=true 28 | coverlet-icon.png 29 | false 30 | true 31 | Coverlet is a cross platform code coverage library for .NET, with support for line, branch and method coverage. 32 | coverage testing unit-test lcov opencover quality 33 | git 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /test/coverlet.core.tests/Coverage/CoverageTests.AsyncAwaitValueTask.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Toni Solarin-Sodara 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System.IO; 5 | using System.Threading.Tasks; 6 | using Coverlet.Core.Samples.Tests; 7 | using Xunit; 8 | 9 | namespace Coverlet.Core.Tests 10 | { 11 | public partial class CoverageTests 12 | { 13 | [Fact] 14 | public void AsyncAwaitWithValueTask() 15 | { 16 | string path = Path.GetTempFileName(); 17 | try 18 | { 19 | FunctionExecutor.Run(async (string[] pathSerialize) => 20 | { 21 | CoveragePrepareResult coveragePrepareResult = await TestInstrumentationHelper.Run(async instance => 22 | { 23 | instance.SyncExecution(); 24 | 25 | int res = await ((ValueTask)instance.AsyncExecution(true)).ConfigureAwait(false); 26 | res = await ((ValueTask)instance.AsyncExecution(1)).ConfigureAwait(false); 27 | res = await ((ValueTask)instance.AsyncExecution(2)).ConfigureAwait(false); 28 | res = await ((ValueTask)instance.AsyncExecution(3)).ConfigureAwait(false); 29 | res = await ((ValueTask)instance.ConfigureAwait()).ConfigureAwait(false); 30 | res = ((Task)instance.WrappingValueTaskAsTask()).ConfigureAwait(false).GetAwaiter().GetResult(); 31 | }, persistPrepareResultToFile: pathSerialize[0]); 32 | return 0; 33 | }, new string[] { path }); 34 | 35 | TestInstrumentationHelper.GetCoverageResult(path) 36 | .Document("Instrumentation.AsyncAwaitValueTask.cs") 37 | .AssertLinesCovered(BuildConfiguration.Debug, 38 | // AsyncExecution(bool) 39 | (12, 1), (13, 1), (15, 1), (16, 1), (18, 1), (19, 1), (21, 1), (23, 1), (24, 0), (25, 0), (26, 0), (28, 1), (29, 1), 40 | // Async 41 | (32, 10), (33, 10), (34, 10), (35, 10), (36, 10), 42 | // AsyncExecution(int) 43 | (39, 3), (40, 3), (42, 3), (43, 3), (45, 3), (46, 3), 44 | (49, 1), (50, 1), (51, 1), (54, 1), (55, 1), (56, 1), (59, 1), (60, 1), (62, 1), 45 | (65, 0), (66, 0), (67, 0), (68, 0), (71, 0), 46 | // SyncExecution 47 | (77, 1), (78, 1), (79, 1), 48 | // Sync 49 | (82, 1), (83, 1), (84, 1), 50 | // ConfigureAwait 51 | (87, 1), (88, 1), (90, 1), (91, 1), (93, 1), (94, 1), (95, 1), 52 | // WrappingValueTaskAsTask 53 | (98, 1), (99, 1), (101, 1), (102, 1), (104, 1), (106, 1), (107, 1) 54 | ) 55 | .AssertBranchesCovered(BuildConfiguration.Debug, 56 | // AsyncExecution(bool) if statement 57 | (23, 0, 0), (23, 1, 1), 58 | // AsyncExecution(int) switch statement 59 | (46, 0, 3), (46, 1, 1), (46, 2, 1), (46, 3, 1), (46, 4, 0) 60 | ) 61 | .ExpectedTotalNumberOfBranches(BuildConfiguration.Debug, 2); 62 | } 63 | finally 64 | { 65 | File.Delete(path); 66 | } 67 | } 68 | } 69 | } 70 | --------------------------------------------------------------------------------