diff --git a/Directory.Packages.props b/Directory.Packages.props index eba94e254..995b8e1fc 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -54,18 +54,18 @@ - + - + - + - + diff --git a/Documentation/GlobalTool.md b/Documentation/GlobalTool.md index e91f67c9d..6b9161b4f 100644 --- a/Documentation/GlobalTool.md +++ b/Documentation/GlobalTool.md @@ -275,5 +275,4 @@ Coverlet outputs specific exit codes to better support build automation systems 2 - Coverage percentage is below threshold. 3 - Test fails and also coverage percentage is below threshold. 101 - General exception occurred during coverlet process. -102 - Missing options or invalid arguments for coverlet process. ``` diff --git a/global.json b/global.json index 6dfc6666e..0417b6523 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "8.0.407" + "version": "8.0.408" } } diff --git a/src/coverlet.collector/coverlet.collector.csproj b/src/coverlet.collector/coverlet.collector.csproj index 7630bb845..fa18b7b3c 100644 --- a/src/coverlet.collector/coverlet.collector.csproj +++ b/src/coverlet.collector/coverlet.collector.csproj @@ -27,7 +27,6 @@ tonerdo MIT https://github.com/coverlet-coverage/coverlet - https://raw.githubusercontent.com/tonerdo/coverlet/master/_assets/coverlet-icon.svg?sanitize=true coverlet-icon.png false Coverlet is a cross platform code coverage library for .NET, with support for line, branch and method coverage. diff --git a/src/coverlet.console/ExitCodes.cs b/src/coverlet.console/ExitCodes.cs index 93a7d395f..616bf8b10 100644 --- a/src/coverlet.console/ExitCodes.cs +++ b/src/coverlet.console/ExitCodes.cs @@ -28,10 +28,5 @@ internal enum CommandExitCodes /// Indicates exception occurred during Coverlet process. /// Exception = 101, - - /// - /// Indicates missing options or empty arguments for Coverlet process. - /// - CommandParsingException = 102 } diff --git a/src/coverlet.console/Program.cs b/src/coverlet.console/Program.cs index ec763612d..f591095b0 100644 --- a/src/coverlet.console/Program.cs +++ b/src/coverlet.console/Program.cs @@ -25,6 +25,7 @@ namespace Coverlet.Console { public static class Program { + static int s_exitCode; static int Main(string[] args) { var moduleOrAppDirectory = new Argument("path", "Path to the test assembly or application directory."); @@ -175,7 +176,7 @@ string sourceMappingFile // Adjust log level based on user input. logger.Level = verbosity; - int exitCode = (int)CommandExitCodes.Success; + s_exitCode = (int)CommandExitCodes.Success; try { @@ -357,44 +358,44 @@ string sourceMappingFile logger.LogInformation(coverageTable.ToStringAlternative()); if (process.ExitCode > 0) { - exitCode += (int)CommandExitCodes.TestFailed; + s_exitCode = (int)CommandExitCodes.TestFailed; } ThresholdTypeFlags thresholdTypeFlags = result.GetThresholdTypesBelowThreshold(thresholdTypeFlagValues, thresholdStat); if (thresholdTypeFlags != ThresholdTypeFlags.None) { - exitCode += (int)CommandExitCodes.CoverageBelowThreshold; - var exceptionMessageBuilder = new StringBuilder(); + s_exitCode = (int)CommandExitCodes.CoverageBelowThreshold; + var errorMessageBuilder = new StringBuilder(); if ((thresholdTypeFlags & ThresholdTypeFlags.Line) != ThresholdTypeFlags.None) { - exceptionMessageBuilder.AppendLine($"The {thresholdStat.ToString().ToLower()} line coverage is below the specified {thresholdTypeFlagValues[ThresholdTypeFlags.Line]}"); + errorMessageBuilder.AppendLine($"The {thresholdStat.ToString().ToLower()} line coverage is below the specified {thresholdTypeFlagValues[ThresholdTypeFlags.Line]}"); } if ((thresholdTypeFlags & ThresholdTypeFlags.Branch) != ThresholdTypeFlags.None) { - exceptionMessageBuilder.AppendLine($"The {thresholdStat.ToString().ToLower()} branch coverage is below the specified {thresholdTypeFlagValues[ThresholdTypeFlags.Branch]}"); + errorMessageBuilder.AppendLine($"The {thresholdStat.ToString().ToLower()} branch coverage is below the specified {thresholdTypeFlagValues[ThresholdTypeFlags.Branch]}"); } if ((thresholdTypeFlags & ThresholdTypeFlags.Method) != ThresholdTypeFlags.None) { - exceptionMessageBuilder.AppendLine($"The {thresholdStat.ToString().ToLower()} method coverage is below the specified {thresholdTypeFlagValues[ThresholdTypeFlags.Method]}"); + errorMessageBuilder.AppendLine($"The {thresholdStat.ToString().ToLower()} method coverage is below the specified {thresholdTypeFlagValues[ThresholdTypeFlags.Method]}"); } - throw new InvalidOperationException(exceptionMessageBuilder.ToString()); + logger.LogError(errorMessageBuilder.ToString()); } - return Task.FromResult(exitCode); + return Task.FromResult(s_exitCode); } catch (Win32Exception we) when (we.Source == "System.Diagnostics.Process") { logger.LogError($"Start process '{target}' failed with '{we.Message}'"); - return Task.FromResult(exitCode > 0 ? exitCode : (int)CommandExitCodes.Exception); + return Task.FromResult(s_exitCode > 0 ? s_exitCode : (int)CommandExitCodes.Exception); } catch (Exception ex) { logger.LogError(ex.Message); - return Task.FromResult(exitCode > 0 ? exitCode : (int)CommandExitCodes.Exception); + return Task.FromResult(s_exitCode > 0 ? s_exitCode : (int)CommandExitCodes.Exception); } } diff --git a/src/coverlet.console/coverlet.console.csproj b/src/coverlet.console/coverlet.console.csproj index 2a7181b18..c2798a2a1 100644 --- a/src/coverlet.console/coverlet.console.csproj +++ b/src/coverlet.console/coverlet.console.csproj @@ -16,7 +16,6 @@ coverage;testing;unit-test;lcov;opencover;quality GlobalTool.md https://github.com/coverlet-coverage/coverlet/blob/master/Documentation/Changelog.md - https://raw.githubusercontent.com/tonerdo/coverlet/master/_assets/coverlet-icon.svg?sanitize=true coverlet-icon.png https://github.com/coverlet-coverage/coverlet MIT diff --git a/src/coverlet.msbuild.tasks/coverlet.msbuild.tasks.csproj b/src/coverlet.msbuild.tasks/coverlet.msbuild.tasks.csproj index c04e823b0..08e532b4f 100644 --- a/src/coverlet.msbuild.tasks/coverlet.msbuild.tasks.csproj +++ b/src/coverlet.msbuild.tasks/coverlet.msbuild.tasks.csproj @@ -28,7 +28,6 @@ tonerdo MIT https://github.com/coverlet-coverage/coverlet - https://raw.githubusercontent.com/tonerdo/coverlet/master/_assets/coverlet-icon.svg?sanitize=true coverlet-icon.png false true diff --git a/test/coverlet.integration.template/DeepThought.cs b/test/coverlet.integration.template/DeepThought.cs index e2a3f4b9c..998a001a2 100644 --- a/test/coverlet.integration.template/DeepThought.cs +++ b/test/coverlet.integration.template/DeepThought.cs @@ -1,10 +1,21 @@ -namespace Coverlet.Integration.Template +namespace Coverlet.Integration.Template { - public class DeepThought + public class DeepThought + { + public int AnswerToTheUltimateQuestionOfLifeTheUniverseAndEverything() { - public int AnswerToTheUltimateQuestionOfLifeTheUniverseAndEverything() - { - return 42; - } + return 42; } + + // This method is not covered by any test + // It is here to demonstrate how Coverlet will report on untested code + // required for Coverlet.Integration.Tests.DotnetGlobalTools.StandAloneThreshold + // required for Coverlet.Integration.Tests.DotnetGlobalTools.DotnetToolThreshold + public void TheUntestedMethod() + { +#pragma warning disable CS0219 // Variable is assigned but its value is never used + string s = "this will never be covered by any test"; +#pragma warning restore CS0219 // Variable is assigned but its value is never used + } + } } diff --git a/test/coverlet.integration.tests/DotnetTool.cs b/test/coverlet.integration.tests/DotnetTool.cs index 91e989f02..cadec6207 100644 --- a/test/coverlet.integration.tests/DotnetTool.cs +++ b/test/coverlet.integration.tests/DotnetTool.cs @@ -35,13 +35,14 @@ public void DotnetTool() string outputPath = $"{clonedTemplateProject.ProjectRootPath}{Path.DirectorySeparatorChar}coverage.json"; DotnetCli($"build -f {_buildTargetFramework} {clonedTemplateProject.ProjectRootPath}", out string buildOutput, out string buildError); string publishedTestFile = clonedTemplateProject.GetFiles("*" + ClonedTemplateProject.AssemblyName + ".dll").Single(f => !f.Contains("obj") && !f.Contains("ref")); - RunCommand(coverletToolCommandPath, $"\"{publishedTestFile}\" --target \"dotnet\" --targetargs \"test {Path.Combine(clonedTemplateProject.ProjectRootPath, ClonedTemplateProject.ProjectFileName)} --no-build\" --include-test-assembly --output \"{outputPath}\"", out string standardOutput, out string standardError); + int cmdExitCode = RunCommand(coverletToolCommandPath, $"\"{publishedTestFile}\" --target \"dotnet\" --targetargs \"test {Path.Combine(clonedTemplateProject.ProjectRootPath, ClonedTemplateProject.ProjectFileName)} --no-build\" --include-test-assembly --output \"{outputPath}\"", out string standardOutput, out string standardError); if (!string.IsNullOrEmpty(standardError)) { _output.WriteLine(standardError); } Assert.Contains("Passed!", standardOutput); AssertCoverage(clonedTemplateProject, standardOutput: standardOutput); + Assert.Equal((int)CommandExitCodes.Success, cmdExitCode); } [Fact] @@ -53,14 +54,14 @@ public void StandAlone() string outputPath = $"{clonedTemplateProject.ProjectRootPath}{Path.DirectorySeparatorChar}coverage.json"; DotnetCli($"build -f {_buildTargetFramework} {clonedTemplateProject.ProjectRootPath}", out string buildOutput, out string buildError); string publishedTestFile = clonedTemplateProject.GetFiles("*" + ClonedTemplateProject.AssemblyName + ".dll").Single(f => !f.Contains("obj") && !f.Contains("ref")); - RunCommand(coverletToolCommandPath, $"\"{Path.GetDirectoryName(publishedTestFile)}\" --target \"dotnet\" --targetargs \"{publishedTestFile}\" --output \"{outputPath}\"", out string standardOutput, out string standardError); + int cmdExitCode = RunCommand(coverletToolCommandPath, $"\"{Path.GetDirectoryName(publishedTestFile)}\" --target \"dotnet\" --targetargs \"{publishedTestFile}\" --output \"{outputPath}\"", out string standardOutput, out string standardError); if (!string.IsNullOrEmpty(standardError)) { _output.WriteLine(standardError); } - //Assert.Contains("Hello World!", standardOutput); Assert.True(File.Exists(outputPath)); AssertCoverage(clonedTemplateProject, standardOutput: standardOutput); + Assert.Equal((int)CommandExitCodes.Success, cmdExitCode); } [Fact] @@ -82,13 +83,11 @@ public void StandAloneThreshold() // make standard output available in trx file _output.WriteLine(standardOutput); } - //Assert.Contains("Hello World!", standardOutput); Assert.True(File.Exists(outputPath)); AssertCoverage(clonedTemplateProject, standardOutput: standardOutput); - //Assert.Equal((int)CommandExitCodes.CoverageBelowThreshold, cmdExitCode); - // this messages are now in stderr available but standardError stream is empty in test environment - //Assert.Contains("The minimum line coverage is below the specified 80", standardError); - //Assert.Contains("The minimum method coverage is below the specified 80", standardOutput); + Assert.Equal((int)CommandExitCodes.CoverageBelowThreshold, cmdExitCode); + Assert.Contains("The minimum line coverage is below the specified 80", standardOutput); + Assert.Contains("The minimum method coverage is below the specified 80", standardOutput); } [Fact] @@ -110,12 +109,11 @@ public void StandAloneThresholdLine() // make standard output available in trx file _output.WriteLine(standardOutput); } - // Assert.Contains("Hello World!", standardOutput); Assert.True(File.Exists(outputPath)); AssertCoverage(clonedTemplateProject, standardOutput: standardOutput); - //Assert.Equal((int)CommandExitCodes.CoverageBelowThreshold, cmdExitCode); - //Assert.Contains("The minimum line coverage is below the specified 80", standardError); - //Assert.DoesNotContain("The minimum method coverage is below the specified 80", standardOutput); + Assert.Equal((int)CommandExitCodes.CoverageBelowThreshold, cmdExitCode); + Assert.Contains("The minimum line coverage is below the specified 80", standardOutput); + Assert.DoesNotContain("The minimum method coverage is below the specified 80", standardOutput); } [Fact] @@ -137,12 +135,11 @@ public void StandAloneThresholdLineAndMethod() // make standard output available in trx file _output.WriteLine(standardOutput); } - // Assert.Contains("Hello World!", standardOutput); Assert.True(File.Exists(outputPath)); AssertCoverage(clonedTemplateProject, standardOutput: standardOutput); - //Assert.Equal((int)CommandExitCodes.CoverageBelowThreshold, cmdExitCode); - //Assert.Contains("The minimum line coverage is below the specified 80", standardError); - //Assert.Contains("The minimum method coverage is below the specified 80", standardOutput); + Assert.Equal((int)CommandExitCodes.CoverageBelowThreshold, cmdExitCode); + Assert.Contains("The minimum line coverage is below the specified 80", standardOutput); + Assert.Contains("The minimum method coverage is below the specified 80", standardOutput); } } } diff --git a/test/coverlet.integration.tests/Msbuild.cs b/test/coverlet.integration.tests/Msbuild.cs index abb784d10..7e4c8656f 100644 --- a/test/coverlet.integration.tests/Msbuild.cs +++ b/test/coverlet.integration.tests/Msbuild.cs @@ -45,7 +45,7 @@ public void TestMsbuild() } Assert.Equal(0, result); Assert.Contains("Passed!", standardOutput, StringComparison.Ordinal); - Assert.Contains("| coverletsamplelib.integration.template | 100% | 100% | 100% |", standardOutput, StringComparison.Ordinal); + Assert.Contains("| coverletsamplelib.integration.template | 50% | 100% | 50% |", standardOutput, StringComparison.Ordinal); string coverageFileName = $"coverage.json"; Assert.True(File.Exists(Path.Combine(clonedTemplateProject.ProjectRootPath, coverageFileName))); AssertCoverage(clonedTemplateProject, coverageFileName); @@ -66,7 +66,7 @@ public void TestMsbuild_NoCoverletOutput() } Assert.Equal(0, result); Assert.Contains("Passed!", standardOutput, StringComparison.Ordinal); - Assert.Contains("| coverletsamplelib.integration.template | 100% | 100% | 100% |", standardOutput, StringComparison.Ordinal); + Assert.Contains("| coverletsamplelib.integration.template | 50% | 100% | 50% |", standardOutput, StringComparison.Ordinal); string coverageFileName = $"coverage.json"; Assert.True(File.Exists(Path.Combine(clonedTemplateProject.ProjectRootPath, coverageFileName))); AssertCoverage(clonedTemplateProject, coverageFileName); @@ -87,7 +87,7 @@ public void TestMsbuild_CoverletOutput_Folder_FileNameWithoutExtension() } Assert.Equal(0, result); Assert.Contains("Passed!", standardOutput, StringComparison.Ordinal); - Assert.Contains("| coverletsamplelib.integration.template | 100% | 100% | 100% |", standardOutput, StringComparison.Ordinal); + Assert.Contains("| coverletsamplelib.integration.template | 50% | 100% | 50% |", standardOutput, StringComparison.Ordinal); string coverageFileName = $"file.json"; Assert.True(File.Exists(Path.Combine(clonedTemplateProject.ProjectRootPath, coverageFileName))); AssertCoverage(clonedTemplateProject, coverageFileName); @@ -99,7 +99,7 @@ public void TestMsbuild_CoverletOutput_Folder_FileNameExtension() using ClonedTemplateProject clonedTemplateProject = PrepareTemplateProject(); Assert.Equal(0, DotnetCli($"test -c {_buildConfiguration} -f {_buildTargetFramework} \"{clonedTemplateProject.ProjectRootPath}\" /p:CollectCoverage=true /p:Include=\"[{ClonedTemplateProject.AssemblyName}]*DeepThought\" /p:IncludeTestAssembly=true /p:CoverletOutput=\"{clonedTemplateProject.ProjectRootPath}\"\\file.ext", out string standardOutput, out string standardError)); Assert.Contains("Passed!", standardOutput, StringComparison.Ordinal); - Assert.Contains("| coverletsamplelib.integration.template | 100% | 100% | 100% |", standardOutput, StringComparison.Ordinal); + Assert.Contains("| coverletsamplelib.integration.template | 50% | 100% | 50% |", standardOutput, StringComparison.Ordinal); string coverageFileName = $"file.ext"; Assert.True(File.Exists(Path.Combine(clonedTemplateProject.ProjectRootPath, coverageFileName))); AssertCoverage(clonedTemplateProject, coverageFileName); @@ -123,7 +123,7 @@ public void TestMsbuild_CoverletOutput_Folder_FileNameExtension_SpecifyFramework _output.WriteLine(standardOutput); } Assert.Contains("Passed!", standardOutput, StringComparison.Ordinal); - Assert.Contains("| coverletsamplelib.integration.template | 100% | 100% | 100% |", standardOutput, StringComparison.Ordinal); + Assert.Contains("| coverletsamplelib.integration.template | 50% | 100% | 50% |", standardOutput, StringComparison.Ordinal); Assert.True(File.Exists(Path.Combine(clonedTemplateProject.ProjectRootPath, "file.ext"))); AssertCoverage(clonedTemplateProject, "file.ext"); } @@ -142,7 +142,7 @@ public void TestMsbuild_CoverletOutput_Folder_FileNameWithDoubleExtension() _output.WriteLine(standardOutput); } Assert.Contains("Passed!", standardOutput, StringComparison.Ordinal); - Assert.Contains("| coverletsamplelib.integration.template | 100% | 100% | 100% |", standardOutput, StringComparison.Ordinal); + Assert.Contains("| coverletsamplelib.integration.template | 50% | 100% | 50% |", standardOutput, StringComparison.Ordinal); string coverageFileName = $"file.ext1.ext2"; Assert.True(File.Exists(Path.Combine(clonedTemplateProject.ProjectRootPath, coverageFileName))); AssertCoverage(clonedTemplateProject, coverageFileName); @@ -164,7 +164,7 @@ public void Test_MultipleTargetFrameworkReport_NoCoverletOutput() _output.WriteLine(standardOutput); } Assert.Contains("Passed!", standardOutput, StringComparison.Ordinal); - Assert.Contains("| coverletsamplelib.integration.template | 100% | 100% | 100% |", standardOutput, StringComparison.Ordinal); + Assert.Contains("| coverletsamplelib.integration.template | 50% | 100% | 50% |", standardOutput, StringComparison.Ordinal); foreach (string targetFramework in targetFrameworks) { @@ -191,7 +191,7 @@ public void Test_MultipleTargetFrameworkReport_CoverletOutput_Folder() } Assert.Equal(0, result); Assert.Contains("Passed!", standardOutput, StringComparison.Ordinal); - Assert.Contains("| coverletsamplelib.integration.template | 100% | 100% | 100% |", standardOutput, StringComparison.Ordinal); + Assert.Contains("| coverletsamplelib.integration.template | 50% | 100% | 50% |", standardOutput, StringComparison.Ordinal); foreach (string targetFramework in targetFrameworks) { @@ -218,7 +218,7 @@ public void Test_MultipleTargetFrameworkReport_CoverletOutput_Folder_FileNameWit _output.WriteLine(standardOutput); } Assert.Contains("Passed!", standardOutput, StringComparison.Ordinal); - Assert.Contains("| coverletsamplelib.integration.template | 100% | 100% | 100% |", standardOutput, StringComparison.Ordinal); + Assert.Contains("| coverletsamplelib.integration.template | 50% | 100% | 50% |", standardOutput, StringComparison.Ordinal); foreach (string targetFramework in targetFrameworks) { @@ -248,7 +248,7 @@ public void Test_MultipleTargetFrameworkReport_CoverletOutput_Folder_FileNameWit _output.WriteLine(standardOutput); } Assert.Contains("Passed!", standardOutput, StringComparison.Ordinal); - Assert.Contains("| coverletsamplelib.integration.template | 100% | 100% | 100% |", standardOutput, StringComparison.Ordinal); + Assert.Contains("| coverletsamplelib.integration.template | 50% | 100% | 50% |", standardOutput, StringComparison.Ordinal); foreach (string targetFramework in targetFrameworks) { @@ -281,7 +281,7 @@ public void Test_MultipleTargetFrameworkReport_CoverletOutput_Folder_FileNameWit _output.WriteLine(standardOutput); } Assert.Contains("Passed!", standardOutput, StringComparison.Ordinal); - Assert.Contains("| coverletsamplelib.integration.template | 100% | 100% | 100% |", standardOutput, StringComparison.Ordinal); + Assert.Contains("| coverletsamplelib.integration.template | 50% | 100% | 50% |", standardOutput, StringComparison.Ordinal); foreach (string targetFramework in targetFrameworks) { @@ -307,7 +307,7 @@ public void Test_MultipleTargetFrameworkReport_CoverletOutput_Folder_FileNameWit _output.WriteLine(standardOutput); } Assert.Contains("Passed!", standardOutput, StringComparison.Ordinal); - Assert.Contains("| coverletsamplelib.integration.template | 100% | 100% | 100% |", standardOutput, StringComparison.Ordinal); + Assert.Contains("| coverletsamplelib.integration.template | 50% | 100% | 50% |", standardOutput, StringComparison.Ordinal); foreach (string targetFramework in targetFrameworks) { diff --git a/test/coverlet.integration.tests/coverlet.integration.tests.csproj b/test/coverlet.integration.tests/coverlet.integration.tests.csproj index 4c8cc9c50..fbb887bc2 100644 --- a/test/coverlet.integration.tests/coverlet.integration.tests.csproj +++ b/test/coverlet.integration.tests/coverlet.integration.tests.csproj @@ -29,6 +29,7 @@ +