diff --git a/src/Cake.Common.Tests/Unit/Tools/DotCover/Analyse/DotCoverAnalyserTests.cs b/src/Cake.Common.Tests/Unit/Tools/DotCover/Analyse/DotCoverAnalyserTests.cs index d3a39025ac..b2b5e3f010 100644 --- a/src/Cake.Common.Tests/Unit/Tools/DotCover/Analyse/DotCoverAnalyserTests.cs +++ b/src/Cake.Common.Tests/Unit/Tools/DotCover/Analyse/DotCoverAnalyserTests.cs @@ -241,6 +241,7 @@ public void Should_Append_LogFile() // Given var fixture = new DotCoverAnalyserFixture(); fixture.Settings.LogFile = "./logfile.log"; + fixture.Settings.UseLegacySyntax = true; // When var result = fixture.Run(); diff --git a/src/Cake.Common.Tests/Unit/Tools/DotCover/Cover/DotCoverCovererTests.cs b/src/Cake.Common.Tests/Unit/Tools/DotCover/Cover/DotCoverCovererTests.cs index f98ab9b6f9..3f042bea32 100644 --- a/src/Cake.Common.Tests/Unit/Tools/DotCover/Cover/DotCoverCovererTests.cs +++ b/src/Cake.Common.Tests/Unit/Tools/DotCover/Cover/DotCoverCovererTests.cs @@ -9,7 +9,10 @@ using Cake.Common.Tools.XUnit; using Cake.Core.IO; using Cake.Testing; +using NSubstitute; using Xunit; +using LogLevel = Cake.Core.Diagnostics.LogLevel; +using Verbosity = Cake.Core.Diagnostics.Verbosity; namespace Cake.Common.Tests.Unit.Tools.DotCover.Cover { @@ -87,6 +90,8 @@ public void Should_Throw_If_No_Tool_Was_Intercepted() AssertEx.IsCakeException(result, "No tool was started."); } + #region New Parameter Syntax + [Fact] public void Should_Capture_Tool_And_Arguments_From_Action() { @@ -145,61 +150,61 @@ public void Should_Append_TargetWorkingDir() } [Fact] - public void Should_Append_Scope() + public void Should_Not_Append_Scope() { // Given var fixture = new DotCoverCovererFixture(); fixture.Settings.WithScope("/Working/*.dll") - .WithScope("/Some/**/Other/*.dll"); + .WithScope("/Some/**/Other/*.dll"); // When var result = fixture.Run(); // Then + fixture.Context.Log.Received(1).Write(Verbosity.Minimal, LogLevel.Warning, "{0}", "Scope parameter is not supported in new DotCover format"); Assert.Equal("cover --target-executable \"/Working/tools/Test.exe\" " + "--target-arguments \"-argument\" " + - "--snapshot-output \"/Working/result.dcvr\" " + - "/Scope=\"/Working/*.dll;/Some/**/Other/*.dll\"", result.Args); + "--snapshot-output \"/Working/result.dcvr\"", result.Args); } [Fact] - public void Should_Append_Filters() + public void Should_Not_Append_Filters() { // Given var fixture = new DotCoverCovererFixture(); fixture.Settings.WithFilter("+:module=Test.*") - .WithFilter("-:myassembly"); + .WithFilter("-:myassembly"); // When var result = fixture.Run(); // Then + fixture.Context.Log.Received(1).Write(Verbosity.Minimal, LogLevel.Warning, "{0}", "Filters parameter is not supported in new DotCover format"); Assert.Equal("cover --target-executable \"/Working/tools/Test.exe\" " + "--target-arguments \"-argument\" " + - "--snapshot-output \"/Working/result.dcvr\" " + - "/Filters=\"+:module=Test.*;-:myassembly\"", result.Args); + "--snapshot-output \"/Working/result.dcvr\"", result.Args); } [Fact] - public void Should_Append_AttributeFilters() + public void Should_Not_Append_AttributeFilters() { // Given var fixture = new DotCoverCovererFixture(); fixture.Settings.WithAttributeFilter("filter1") - .WithAttributeFilter("filter2"); + .WithAttributeFilter("filter2"); // When var result = fixture.Run(); // Then + fixture.Context.Log.Received(1).Write(Verbosity.Minimal, LogLevel.Warning, "{0}", "AttributeFilters parameter is not supported in new DotCover format"); Assert.Equal("cover --target-executable \"/Working/tools/Test.exe\" " + "--target-arguments \"-argument\" " + - "--snapshot-output \"/Working/result.dcvr\" " + - "/AttributeFilters=\"filter1;filter2\"", result.Args); + "--snapshot-output \"/Working/result.dcvr\"", result.Args); } [Fact] - public void Should_Append_DisableDefaultFilters() + public void Should_Not_Append_DisableDefaultFilters() { // Given var fixture = new DotCoverCovererFixture(); @@ -209,28 +214,28 @@ public void Should_Append_DisableDefaultFilters() var result = fixture.Run(); // Then + fixture.Context.Log.Received(1).Write(Verbosity.Minimal, LogLevel.Warning, "{0}", "DisableDefaultFilters parameter is not supported in new DotCover format"); Assert.Equal("cover --target-executable \"/Working/tools/Test.exe\" " + "--target-arguments \"-argument\" " + - "--snapshot-output \"/Working/result.dcvr\" " + - "/DisableDefaultFilters", result.Args); + "--snapshot-output \"/Working/result.dcvr\"", result.Args); } [Fact] - public void Should_Append_ProcessFilters() + public void Should_Not_Append_ProcessFilters() { // Given var fixture = new DotCoverCovererFixture(); fixture.Settings.WithProcessFilter("+:test.exe") - .WithProcessFilter("-:sqlservr.exe"); + .WithProcessFilter("-:sqlservr.exe"); // When var result = fixture.Run(); // Then + fixture.Context.Log.Received(1).Write(Verbosity.Minimal, LogLevel.Warning, "{0}", "ProcessFilters parameter is not supported in new DotCover format"); Assert.Equal("cover --target-executable \"/Working/tools/Test.exe\" " + "--target-arguments \"-argument\" " + - "--snapshot-output \"/Working/result.dcvr\" " + - "/ProcessFilters=\"+:test.exe;-:sqlservr.exe\"", result.Args); + "--snapshot-output \"/Working/result.dcvr\"", result.Args); } [Fact] @@ -299,7 +304,7 @@ public void Should_Append_ExcludeAssemblies() // Given var fixture = new DotCoverCovererFixture(); fixture.Settings.WithExcludeAssembly("*.Tests") - .WithExcludeAssembly("Test.*"); + .WithExcludeAssembly("Test.*"); // When var result = fixture.Run(); @@ -317,7 +322,7 @@ public void Should_Append_ExcludeAttributes() // Given var fixture = new DotCoverCovererFixture(); fixture.Settings.WithExcludeAttribute("System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute") - .WithExcludeAttribute("Custom.*Attribute"); + .WithExcludeAttribute("Custom.*Attribute"); // When var result = fixture.Run(); @@ -335,7 +340,7 @@ public void Should_Append_ExcludeProcesses() // Given var fixture = new DotCoverCovererFixture(); fixture.Settings.WithExcludeProcess("test.exe") - .WithExcludeProcess("*.vshost.exe"); + .WithExcludeProcess("*.vshost.exe"); // When var result = fixture.Run(); @@ -504,8 +509,8 @@ public void Should_Not_Support_New_Features_In_Legacy_Mode() // Given var fixture = new DotCoverCovererFixture(); fixture.Settings.WithLegacySyntax() - .WithJsonReportOutput(new FilePath("/Working/report.json")) - .WithExcludeAssembly("*.Tests"); + .WithJsonReportOutput(new FilePath("/Working/report.json")) + .WithExcludeAssembly("*.Tests"); // When var result = fixture.Run(); @@ -524,7 +529,7 @@ public void Should_Support_New_Features_In_New_Mode() // Given var fixture = new DotCoverCovererFixture(); fixture.Settings.WithJsonReportOutput(new FilePath("/Working/report.json")) - .WithExcludeAssembly("*.Tests"); + .WithExcludeAssembly("*.Tests"); // When var result = fixture.Run(); @@ -534,6 +539,228 @@ public void Should_Support_New_Features_In_New_Mode() Assert.Contains("--exclude-assemblies \"*.Tests\"", result.Args); Assert.Contains("--snapshot-output", result.Args); } + + #endregion + + #region Legacy Parameter Syntax + + [Fact] + public void Should_Capture_Tool_And_Arguments_From_Action_LegacySyntax() + { + // Given + var fixture = new DotCoverCovererFixture(); + fixture.Settings.WithLegacySyntax(); + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("cover /TargetExecutable=\"/Working/tools/Test.exe\" " + + "/TargetArguments=\"-argument\" " + + "/Output=\"/Working/result.dcvr\"", result.Args); + } + + [Theory] + [InlineData("")] + [InlineData(null)] + public void Should_Not_Capture_Arguments_From_Action_If_Excluded_LegacySyntax(string arguments) + { + // Given + var fixture = new DotCoverCovererFixture(); + fixture.Action = context => + { + context.ProcessRunner.Start( + new FilePath("/Working/tools/Test.exe"), + new ProcessSettings() + { + Arguments = arguments + }); + }; + fixture.Settings.WithLegacySyntax(); + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("cover /TargetExecutable=\"/Working/tools/Test.exe\" " + + "/Output=\"/Working/result.dcvr\"", result.Args); + } + + [Fact] + public void Should_Append_TargetWorkingDir_LegacySyntax() + { + // Given + var fixture = new DotCoverCovererFixture(); + fixture.Settings.TargetWorkingDir = new DirectoryPath("/Working"); + fixture.Settings.WithLegacySyntax(); + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("cover /TargetExecutable=\"/Working/tools/Test.exe\" " + + "/TargetArguments=\"-argument\" " + + "/Output=\"/Working/result.dcvr\" " + + "/TargetWorkingDir=\"/Working\"", result.Args); + } + + [Fact] + public void Should_Append_Scope_LegacySyntax() + { + // Given + var fixture = new DotCoverCovererFixture(); + fixture.Settings.WithScope("/Working/*.dll") + .WithScope("/Some/**/Other/*.dll") + .WithLegacySyntax(); + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("cover /TargetExecutable=\"/Working/tools/Test.exe\" " + + "/TargetArguments=\"-argument\" " + + "/Output=\"/Working/result.dcvr\" " + + "/Scope=\"/Working/*.dll;/Some/**/Other/*.dll\"", result.Args); + } + + [Fact] + public void Should_Append_Filters_LegacySyntax() + { + // Given + var fixture = new DotCoverCovererFixture(); + fixture.Settings.WithFilter("+:module=Test.*") + .WithFilter("-:myassembly") + .WithLegacySyntax(); + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("cover /TargetExecutable=\"/Working/tools/Test.exe\" " + + "/TargetArguments=\"-argument\" " + + "/Output=\"/Working/result.dcvr\" " + + "/Filters=\"+:module=Test.*;-:myassembly\"", result.Args); + } + + [Fact] + public void Should_Append_AttributeFilters_LegacySyntax() + { + // Given + var fixture = new DotCoverCovererFixture(); + fixture.Settings.WithAttributeFilter("filter1") + .WithAttributeFilter("filter2") + .WithLegacySyntax(); + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("cover /TargetExecutable=\"/Working/tools/Test.exe\" " + + "/TargetArguments=\"-argument\" " + + "/Output=\"/Working/result.dcvr\" " + + "/AttributeFilters=\"filter1;filter2\"", result.Args); + } + + [Fact] + public void Should_Append_DisableDefaultFilters_LegacySyntax() + { + // Given + var fixture = new DotCoverCovererFixture(); + fixture.Settings.DisableDefaultFilters = true; + fixture.Settings.WithLegacySyntax(); + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("cover /TargetExecutable=\"/Working/tools/Test.exe\" " + + "/TargetArguments=\"-argument\" " + + "/Output=\"/Working/result.dcvr\" " + + "/DisableDefaultFilters", result.Args); + } + + [Fact] + public void Should_Append_ProcessFilters_LegacySyntax() + { + // Given + var fixture = new DotCoverCovererFixture(); + fixture.Settings.WithProcessFilter("+:test.exe") + .WithProcessFilter("-:sqlservr.exe") + .WithLegacySyntax(); + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("cover /TargetExecutable=\"/Working/tools/Test.exe\" " + + "/TargetArguments=\"-argument\" " + + "/Output=\"/Working/result.dcvr\" " + + "/ProcessFilters=\"+:test.exe;-:sqlservr.exe\"", result.Args); + } + + [Fact] + public void Should_Capture_XUnit_LegacySyntax() + { + // Given + var fixture = new DotCoverCovererFixture(); + fixture.FileSystem.CreateFile("/Working/tools/xunit.console.exe"); + fixture.Action = context => + { + context.XUnit2( + new FilePath[] { "./Test.dll" }, + new XUnit2Settings { ShadowCopy = false }); + }; + fixture.Settings.WithLegacySyntax(); + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("cover /TargetExecutable=\"/Working/tools/xunit.console.exe\" " + + "/TargetArguments=\"\\\"/Working/Test.dll\\\" -noshadow\" " + + "/Output=\"/Working/result.dcvr\"", result.Args); + } + + [Fact] + public void Should_Capture_NUnit_LegacySyntax() + { + // Given + var fixture = new DotCoverCovererFixture(); + fixture.FileSystem.CreateFile("/Working/tools/nunit-console.exe"); + fixture.Action = context => + { + context.NUnit( + new FilePath[] { "./Test.dll" }, + new NUnitSettings { ShadowCopy = false }); + }; + fixture.Settings.WithLegacySyntax(); + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("cover /TargetExecutable=\"/Working/tools/nunit-console.exe\" " + + "/TargetArguments=\"\\\"/Working/Test.dll\\\" -noshadow\" " + + "/Output=\"/Working/result.dcvr\"", result.Args); + } + + [Fact] + public void Should_Append_ConfigurationFile_LegacySyntax() + { + // Given + var fixture = new DotCoverCovererFixture(); + fixture.Settings.WithConfigFile(new FilePath("./config.xml")).WithLegacySyntax(); + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("cover \"/Working/config.xml\" /TargetExecutable=\"/Working/tools/Test.exe\" " + + "/TargetArguments=\"-argument\" " + + "/Output=\"/Working/result.dcvr\"", result.Args); + } + + #endregion } } } \ No newline at end of file diff --git a/src/Cake.Common.Tests/Unit/Tools/DotCover/Merge/DotCoverMergerTests.cs b/src/Cake.Common.Tests/Unit/Tools/DotCover/Merge/DotCoverMergerTests.cs index 238584413e..2f3f4d7040 100644 --- a/src/Cake.Common.Tests/Unit/Tools/DotCover/Merge/DotCoverMergerTests.cs +++ b/src/Cake.Common.Tests/Unit/Tools/DotCover/Merge/DotCoverMergerTests.cs @@ -7,7 +7,6 @@ using Cake.Common.Tools.DotCover; using Cake.Core.IO; using Xunit; - namespace Cake.Common.Tests.Unit.Tools.DotCover.Merge { public sealed class DotCoverMergerTests @@ -43,31 +42,83 @@ public void Should_Throw_If_Source_Files_Is_Empty() } [Fact] - public void Should_Throw_If_Output_File_Is_Null() + public void Should_Throw_If_Settings_Are_Null() { // Given var fixture = new DotCoverMergerFixture(); - fixture.OutputFile = null; + fixture.Settings = null; // When var result = Record.Exception(() => fixture.Run()); // Then - AssertEx.IsArgumentNullException(result, "outputFile"); + AssertEx.IsArgumentNullException(result, "settings"); } + #region New Parameter Syntax + [Fact] - public void Should_Throw_If_Settings_Are_Null() + public void Should_Ignore_Output_If_Not_Set() { // Given var fixture = new DotCoverMergerFixture(); - fixture.Settings = null; + fixture.SourceFiles = new List { new ("/Working/result1.dcvr"), new ("/Working/result2.dcvr") }; + fixture.OutputFile = null; + // When + var result = fixture.Run(); + + // Then + Assert.Equal("merge " + + "--snapshot-source \"/Working/result1.dcvr,/Working/result2.dcvr\"", result.Args); + } + + [Fact] + public void Should_Set_Correct_Arguments() + { + // Given + var fixture = new DotCoverMergerFixture(); + fixture.SourceFiles = new List { new ("/Working/result1.dcvr"), new ("/Working/result2.dcvr") }; + fixture.OutputFile = new FilePath("/Working/output.dcvr"); + // When + var result = fixture.Run(); + + // Then + Assert.Equal("merge " + + "--snapshot-source \"/Working/result1.dcvr,/Working/result2.dcvr\" " + + "--snapshot-output \"/Working/output.dcvr\"", result.Args); + } + + [Fact] + public void Should_Append_TemporaryDirectory() + { + // Given + var fixture = new DotCoverMergerFixture(); + fixture.Settings.TemporaryDirectory = new DirectoryPath("/Working/temp"); // When - var result = Record.Exception(() => fixture.Run()); + var result = fixture.Run(); // Then - AssertEx.IsArgumentNullException(result, "settings"); + Assert.Equal("merge " + + "--snapshot-source \"/Working/result1.dcvr,/Working/result2.dcvr\" " + + "--snapshot-output \"/Working/result.dcvr\" " + + "--temporary-directory \"/Working/temp\"", result.Args); + } + + [Fact] + public void Should_Not_Append_Null_TemporaryDirectory() + { + // Given + var fixture = new DotCoverMergerFixture(); + fixture.Settings.TemporaryDirectory = null; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("merge " + + "--snapshot-source \"/Working/result1.dcvr,/Working/result2.dcvr\" " + + "--snapshot-output \"/Working/result.dcvr\"", result.Args); } [Fact] @@ -81,27 +132,67 @@ public void Should_Append_LogFile() var result = fixture.Run(); // Then - Assert.Equal("Merge " + + Assert.Equal("merge " + + "--snapshot-source \"/Working/result1.dcvr,/Working/result2.dcvr\" " + + "--snapshot-output \"/Working/result.dcvr\" " + + "--log-file \"/Working/logfile.log\"", result.Args); + } + + #endregion + + #region Legacy Parameter Syntax + + [Fact] + public void Should_Append_LogFile_LegacySyntax() + { + // Given + var fixture = new DotCoverMergerFixture(); + fixture.Settings.LogFile = "./logfile.log"; + fixture.Settings.UseLegacySyntax = true; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("merge " + "/Source=\"/Working/result1.dcvr;/Working/result2.dcvr\" " + "/Output=\"/Working/result.dcvr\" " + "/LogFile=\"/Working/logfile.log\"", result.Args); } [Fact] - public void Should_Append_ConfigurationFile() + public void Should_Append_ConfigurationFile_LegacySyntax() { // Given var fixture = new DotCoverMergerFixture(); fixture.Settings.WithConfigFile(new FilePath("./config.xml")); + fixture.Settings.UseLegacySyntax = true; // When var result = fixture.Run(); // Then - Assert.Equal("Merge \"/Working/config.xml\" " + + Assert.Equal("merge \"/Working/config.xml\" " + "/Source=\"/Working/result1.dcvr;/Working/result2.dcvr\" " + "/Output=\"/Working/result.dcvr\"", result.Args); } + + [Fact] + public void Should_Throw_If_Output_File_Is_Null_LegacySyntax() + { + // Given + var fixture = new DotCoverMergerFixture(); + fixture.OutputFile = null; + fixture.Settings.UseLegacySyntax = true; + + // When + var result = Record.Exception(() => fixture.Run()); + + // Then + AssertEx.IsArgumentNullException(result, "outputFile"); + } + + #endregion } } } \ No newline at end of file diff --git a/src/Cake.Common.Tests/Unit/Tools/DotCover/Report/DotCoverReporterTests.cs b/src/Cake.Common.Tests/Unit/Tools/DotCover/Report/DotCoverReporterTests.cs index 468f0c17a5..9338b062b4 100644 --- a/src/Cake.Common.Tests/Unit/Tools/DotCover/Report/DotCoverReporterTests.cs +++ b/src/Cake.Common.Tests/Unit/Tools/DotCover/Report/DotCoverReporterTests.cs @@ -28,31 +28,169 @@ public void Should_Throw_If_Source_File_Is_Null() } [Fact] - public void Should_Throw_If_Output_File_Is_Null() + public void Should_Throw_If_Settings_Are_Null() { // Given var fixture = new DotCoverReporterFixture(); - fixture.OutputFile = null; + fixture.Settings = null; // When var result = Record.Exception(() => fixture.Run()); // Then - AssertEx.IsArgumentNullException(result, "outputFile"); + AssertEx.IsArgumentNullException(result, "settings"); } + #region New Parameter Syntax + [Fact] - public void Should_Throw_If_Settings_Are_Null() + public void Should_Ignore_Output_File_If_Null() { // Given var fixture = new DotCoverReporterFixture(); - fixture.Settings = null; + fixture.OutputFile = null; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("report " + + "--snapshot-source \"/Working/result.dcvr\"", result.Args); + } + + [Fact] + public void Should_Not_Ignore_Output_File_With_New_Syntax() + { + // Given + var fixture = new DotCoverReporterFixture(); + fixture.OutputFile = "myoutputfile.xml"; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("report " + + "--snapshot-source \"/Working/result.dcvr\" " + + "--xml-report-output \"/Working/myoutputfile.xml\"", result.Args); + } + + [Fact] + public void Should_Not_Ignore_Output_File_With_New_Syntax_Json() + { + // Given + var fixture = new DotCoverReporterFixture(); + fixture.OutputFile = "myoutputfile.json"; + fixture.Settings.ReportType = DotCoverReportType.JSON; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("report " + + "--snapshot-source \"/Working/result.dcvr\" " + + "--json-report-output \"/Working/myoutputfile.json\"", result.Args); + } + + + [Fact] + public void Should_Append_JsonReportOutput() + { + // Given + var fixture = new DotCoverReporterFixture(); + fixture.OutputFile = null; + fixture.Settings.JsonReportOutput = new FilePath("/Working/coverage.json"); + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("report " + + "--snapshot-source \"/Working/result.dcvr\" " + + "--json-report-output \"/Working/coverage.json\"", result.Args); + } + + [Theory] + [InlineData(DotCoverReportScope.None, "none")] + [InlineData(DotCoverReportScope.Assembly, "assembly")] + [InlineData(DotCoverReportScope.Type, "type")] + [InlineData(DotCoverReportScope.Method, "method")] + [InlineData(DotCoverReportScope.Statement, "statement")] + public void Should_Append_JsonReportScope(DotCoverReportScope reportScope, string reportScopeString) + { + // Given + var fixture = new DotCoverReporterFixture(); + fixture.OutputFile = null; + fixture.Settings.JsonReportOutput = new FilePath("/Working/coverage.json"); + fixture.Settings.JsonReportCoveringTestsScope = reportScope; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("report " + + "--snapshot-source \"/Working/result.dcvr\" " + + "--json-report-output \"/Working/coverage.json\" " + + "--json-report-covering-tests-scope \"" + reportScopeString + "\"", result.Args); + } + + [Fact] + public void Should_Append_XmlReportOutput() + { + // Given + var fixture = new DotCoverReporterFixture(); + fixture.OutputFile = null; + fixture.Settings.XmlReportOutput = new FilePath("/Working/coverage.json"); + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("report " + + "--snapshot-source \"/Working/result.dcvr\" " + + "--xml-report-output \"/Working/coverage.json\"", result.Args); + } + + [Theory] + [InlineData(DotCoverReportScope.None, "none")] + [InlineData(DotCoverReportScope.Assembly, "assembly")] + [InlineData(DotCoverReportScope.Type, "type")] + [InlineData(DotCoverReportScope.Method, "method")] + [InlineData(DotCoverReportScope.Statement, "statement")] + public void Should_Append_XmlReportScope(DotCoverReportScope reportScope, string reportScopeString) + { + // Given + var fixture = new DotCoverReporterFixture(); + fixture.OutputFile = null; + fixture.Settings.XmlReportOutput = new FilePath("/Working/coverage.json"); + fixture.Settings.XmlReportCoveringTestsScope = reportScope; + + // When + var result = fixture.Run(); + + // Then + Assert.Equal("report " + + "--snapshot-source \"/Working/result.dcvr\" " + + "--xml-report-output \"/Working/coverage.json\" " + + "--xml-report-covering-tests-scope \"" + reportScopeString + "\"", result.Args); + } + + #endregion + + #region Legacy Parameter Syntax + + [Fact] + public void Should_Throw_If_Output_File_Is_Null() + { + // Given + var fixture = new DotCoverReporterFixture(); + fixture.OutputFile = null; + fixture.Settings.UseLegacySyntax = true; // When var result = Record.Exception(() => fixture.Run()); // Then - AssertEx.IsArgumentNullException(result, "settings"); + AssertEx.IsArgumentNullException(result, "outputFile"); } [Theory] @@ -65,12 +203,13 @@ public void Should_Append_ReportType(DotCoverReportType reportType, string repor // Given var fixture = new DotCoverReporterFixture(); fixture.Settings.ReportType = reportType; + fixture.Settings.UseLegacySyntax = true; // When var result = fixture.Run(); // Then - Assert.Equal("Report " + + Assert.Equal("report " + "/Source=\"/Working/result.dcvr\" " + "/Output=\"/Working/result.xml\" " + "/ReportType=" + reportTypeString, result.Args); @@ -82,12 +221,13 @@ public void Should_Append_LogFile() // Given var fixture = new DotCoverReporterFixture(); fixture.Settings.LogFile = "./logfile.log"; + fixture.Settings.UseLegacySyntax = true; // When var result = fixture.Run(); // Then - Assert.Equal("Report " + + Assert.Equal("report " + "/Source=\"/Working/result.dcvr\" " + "/Output=\"/Working/result.xml\" " + "/LogFile=\"/Working/logfile.log\"", result.Args); @@ -99,15 +239,18 @@ public void Should_Append_ConfigurationFile() // Given var fixture = new DotCoverReporterFixture(); fixture.Settings.WithConfigFile(new FilePath("./config.xml")); + fixture.Settings.UseLegacySyntax = true; // When var result = fixture.Run(); // Then - Assert.Equal("Report \"/Working/config.xml\" " + + Assert.Equal("report \"/Working/config.xml\" " + "/Source=\"/Working/result.dcvr\" " + "/Output=\"/Working/result.xml\"", result.Args); } + + #endregion } } } \ No newline at end of file diff --git a/src/Cake.Common/Tools/DotCover/Cover/DotCoverCoverSettings.cs b/src/Cake.Common/Tools/DotCover/Cover/DotCoverCoverSettings.cs index eadc7ce291..66d8d884e6 100644 --- a/src/Cake.Common/Tools/DotCover/Cover/DotCoverCoverSettings.cs +++ b/src/Cake.Common/Tools/DotCover/Cover/DotCoverCoverSettings.cs @@ -52,13 +52,5 @@ public sealed class DotCoverCoverSettings : DotCoverCoverageSettings /// This represents the --no-ngen option. /// public bool NoNGen { get; set; } - - /// - /// Gets or sets a value indicating whether to use the legacy command syntax. - /// When true, uses old format like '/TargetExecutable="/path"'. - /// When false, uses new format like '--target-executable "/path"'. - /// Default is false (new format). - /// - public bool UseLegacySyntax { get; set; } } } \ No newline at end of file diff --git a/src/Cake.Common/Tools/DotCover/Cover/DotCoverCoverer.cs b/src/Cake.Common/Tools/DotCover/Cover/DotCoverCoverer.cs index c3d53ab657..354229f392 100644 --- a/src/Cake.Common/Tools/DotCover/Cover/DotCoverCoverer.cs +++ b/src/Cake.Common/Tools/DotCover/Cover/DotCoverCoverer.cs @@ -4,6 +4,7 @@ using System; using Cake.Core; +using Cake.Core.Diagnostics; using Cake.Core.IO; using Cake.Core.Tooling; @@ -124,6 +125,31 @@ private ProcessArgumentBuilder GetArguments( builder.Append("--no-ngen"); } + if (settings.Filters is { Count: > 0 }) + { + context.Log.Warning("Filters parameter is not supported in new DotCover format"); + } + + if (settings.Scope is { Count: > 0 }) + { + context.Log.Warning("Scope parameter is not supported in new DotCover format"); + } + + if (settings.AttributeFilters is { Count: > 0 }) + { + context.Log.Warning("AttributeFilters parameter is not supported in new DotCover format"); + } + + if (settings.ProcessFilters is { Count: > 0 }) + { + context.Log.Warning("ProcessFilters parameter is not supported in new DotCover format"); + } + + if (settings.DisableDefaultFilters is true) + { + context.Log.Warning("DisableDefaultFilters parameter is not supported in new DotCover format"); + } + // Get base arguments - new format GetCoverArguments(settings).CopyTo(builder); } @@ -165,41 +191,6 @@ private ProcessArgumentBuilder GetCoverCoverageArguments(DotCoverCoverageSetting builder.AppendSwitch("--exclude-processes", excludeProcesses.Quote()); } - // Legacy filtering options (maintain backward compatibility with old format) - // Scope - if (settings.Scope.Count > 0) - { - var scope = string.Join(';', settings.Scope); - builder.AppendSwitch("/Scope", "=", scope.Quote()); - } - - // Filters - if (settings.Filters.Count > 0) - { - var filters = string.Join(';', settings.Filters); - builder.AppendSwitch("/Filters", "=", filters.Quote()); - } - - // AttributeFilters - if (settings.AttributeFilters.Count > 0) - { - var attributeFilters = string.Join(';', settings.AttributeFilters); - builder.AppendSwitch("/AttributeFilters", "=", attributeFilters.Quote()); - } - - // ProcessFilters - if (settings.ProcessFilters.Count > 0) - { - var processFilters = string.Join(';', settings.ProcessFilters); - builder.AppendSwitch("/ProcessFilters", "=", processFilters.Quote()); - } - - // DisableDefaultFilters - if (settings.DisableDefaultFilters) - { - builder.Append("/DisableDefaultFilters"); - } - return builder; } diff --git a/src/Cake.Common/Tools/DotCover/DotCoverAliases.cs b/src/Cake.Common/Tools/DotCover/DotCoverAliases.cs index cc0cab137f..b959c04e6b 100644 --- a/src/Cake.Common/Tools/DotCover/DotCoverAliases.cs +++ b/src/Cake.Common/Tools/DotCover/DotCoverAliases.cs @@ -132,9 +132,9 @@ public static void DotCoverCover( /// /// /// DotCoverReport(new FilePath("./result.dcvr"), - /// new FilePath("./result.html"), + /// new FilePath("./result.xml"), /// new DotCoverReportSettings { - /// ReportType = DotCoverReportType.HTML + /// ReportType = DotCoverReportType.XML /// }); /// /// @@ -163,6 +163,45 @@ public static void DotCoverReport( reporter.Report(sourceFile, outputFile, settings); } + /// + /// Runs DotCover Report + /// for the specified action and settings. + /// + /// The context. + /// The DotCover coverage snapshot file name. + /// The settings. + /// + /// + /// DotCoverReport(new FilePath("./result.dcvr"), + /// new DotCoverReportSettings { + /// ReportType = DotCoverReportType.Xml + /// }); + /// + /// + [CakeMethodAlias] + [CakeAliasCategory("Report")] + [CakeNamespaceImport("Cake.Common.Tools.DotCover.Report")] + public static void DotCoverReport( + this ICakeContext context, + FilePath sourceFile, + DotCoverReportSettings settings) + { + ArgumentNullException.ThrowIfNull(context); + + if (settings == null) + { + settings = new DotCoverReportSettings(); + } + + // Create the DotCover reporter. + var reporter = new DotCoverReporter( + context.FileSystem, context.Environment, + context.ProcessRunner, context.Tools); + + // Run DotCover report. + reporter.Report(sourceFile, settings); + } + /// /// Runs DotCover Merge /// for the specified action and settings. @@ -234,5 +273,56 @@ public static void DotCoverMerge( // Run DotCover report. merger.Merge(sourceFiles, outputFile, settings); } + + /// + /// Runs DotCover Merge + /// for the specified action and settings. + /// + /// The context. + /// The list of DotCover coverage snapshot files. + /// + /// + /// DotCoverMerge(new[] { + /// new FilePath("./result1.dcvr"), + /// new FilePath("./result2.dcvr") + /// }); + /// + /// + [CakeMethodAlias] + [CakeAliasCategory("Merge")] + [CakeNamespaceImport("Cake.Common.Tools.DotCover.Merge")] + public static void DotCoverMerge( + this ICakeContext context, + IEnumerable sourceFiles) + { + DotCoverMerge(context, sourceFiles, new DotCoverMergeSettings()); + } + + /// + /// Runs DotCover Merge + /// for the specified action and settings. + /// + /// The context. + /// The list of DotCover coverage snapshot files. + /// The settings. + /// + /// + /// DotCoverMerge(new[] { + /// new FilePath("./result1.dcvr"), + /// new FilePath("./result2.dcvr") + /// }, + /// new DotCoverMergeSettings()); + /// + /// + public static void DotCoverMerge( + this ICakeContext context, + IEnumerable sourceFiles, + DotCoverMergeSettings settings) + { + var merger = new DotCoverMerger( + context.FileSystem, context.Environment, + context.ProcessRunner, context.Tools); + merger.Merge(sourceFiles, settings); + } } } \ No newline at end of file diff --git a/src/Cake.Common/Tools/DotCover/DotCoverSettings.cs b/src/Cake.Common/Tools/DotCover/DotCoverSettings.cs index c1e67be183..e5edf53d91 100644 --- a/src/Cake.Common/Tools/DotCover/DotCoverSettings.cs +++ b/src/Cake.Common/Tools/DotCover/DotCoverSettings.cs @@ -24,5 +24,13 @@ public abstract class DotCoverSettings : ToolSettings /// to specifying all parameters in-line or having them in a batch file. /// public FilePath ConfigFile { get; set; } + + /// + /// Gets or sets a value indicating whether to use the legacy command syntax. + /// When true, uses old format like '/TargetExecutable="/path"'. + /// When false, uses new format like '--target-executable "/path"'. + /// Default is false (new format). + /// + public bool UseLegacySyntax { get; set; } } } diff --git a/src/Cake.Common/Tools/DotCover/DotCoverTool.cs b/src/Cake.Common/Tools/DotCover/DotCoverTool.cs index 1293f35111..08ec603199 100644 --- a/src/Cake.Common/Tools/DotCover/DotCoverTool.cs +++ b/src/Cake.Common/Tools/DotCover/DotCoverTool.cs @@ -64,8 +64,16 @@ protected ProcessArgumentBuilder GetArguments(DotCoverSettings settings) // LogFile if (settings.LogFile != null) { - var logFilePath = settings.LogFile.MakeAbsolute(_environment); - builder.AppendSwitch("/LogFile", "=", logFilePath.FullPath.Quote()); + if (settings.UseLegacySyntax) + { + var logFilePath = settings.LogFile.MakeAbsolute(_environment); + builder.AppendSwitch("/LogFile", "=", logFilePath.FullPath.Quote()); + } + else + { + var logFilePath = settings.LogFile.MakeAbsolute(_environment); + builder.AppendSwitch("--log-file", logFilePath.FullPath.Quote()); + } } return builder; diff --git a/src/Cake.Common/Tools/DotCover/Merge/DotCoverMergeSettings.cs b/src/Cake.Common/Tools/DotCover/Merge/DotCoverMergeSettings.cs index 090de38cfa..ad95f89609 100644 --- a/src/Cake.Common/Tools/DotCover/Merge/DotCoverMergeSettings.cs +++ b/src/Cake.Common/Tools/DotCover/Merge/DotCoverMergeSettings.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using Cake.Core.IO; + namespace Cake.Common.Tools.DotCover.Merge { /// @@ -9,5 +11,10 @@ namespace Cake.Common.Tools.DotCover.Merge /// public sealed class DotCoverMergeSettings : DotCoverSettings { + /// + /// Gets or sets the directory for temporary files. + /// This represents the --temporary-directory option. + /// + public DirectoryPath TemporaryDirectory { get; set; } } } diff --git a/src/Cake.Common/Tools/DotCover/Merge/DotCoverMerger.cs b/src/Cake.Common/Tools/DotCover/Merge/DotCoverMerger.cs index 36f05ede9e..97c5654eaf 100644 --- a/src/Cake.Common/Tools/DotCover/Merge/DotCoverMerger.cs +++ b/src/Cake.Common/Tools/DotCover/Merge/DotCoverMerger.cs @@ -34,6 +34,17 @@ public DotCoverMerger( _environment = environment; } + /// + /// Runs DotCover Merge with the new parameter Syntax. + /// + /// The list of DotCover coverage snapshot files. + /// The settings. + /// The merged output file (optional). + public void Merge(IEnumerable sourceFiles, DotCoverMergeSettings settings, FilePath outputFile = null) + { + Merge(sourceFiles, outputFile, settings); + } + /// /// Runs DotCover Merge with the specified settings. /// @@ -49,8 +60,11 @@ public void Merge( { throw new ArgumentNullException("sourceFiles"); } - ArgumentNullException.ThrowIfNull(outputFile); ArgumentNullException.ThrowIfNull(settings); + if (settings.UseLegacySyntax) + { + ArgumentNullException.ThrowIfNull(outputFile); + } // Run the tool. Run(settings, GetArguments(sourceFiles, outputFile, settings)); @@ -63,11 +77,50 @@ private ProcessArgumentBuilder GetArguments( { var builder = new ProcessArgumentBuilder(); - builder.Append("Merge"); + // Command name - always lowercase 'merge' for both formats + builder.Append("merge"); // Set configuration file if exists. GetConfigurationFileArgument(settings).CopyTo(builder); + if (settings.UseLegacySyntax) + { + BuildLegacyArguments(sourceFiles, outputFile, builder); + } + else + { + BuildNewArguments(sourceFiles, outputFile, builder, settings); + } + + // Get Global settings + GetArguments(settings).CopyTo(builder); + + return builder; + } + + private void BuildNewArguments(IEnumerable sourceFiles, FilePath outputFile, ProcessArgumentBuilder builder, DotCoverMergeSettings settings) + { + // Set the Source files. + var source = string.Join(',', sourceFiles.Select(s => s.MakeAbsolute(_environment).FullPath)); + builder.AppendSwitch("--snapshot-source", source.Quote()); + + // Set the Output file. + if (outputFile != null) + { + outputFile = outputFile.MakeAbsolute(_environment); + builder.AppendSwitch("--snapshot-output", outputFile.FullPath.Quote()); + } + + // Set the Temporary directory. + if (settings.TemporaryDirectory != null) + { + settings.TemporaryDirectory = settings.TemporaryDirectory.MakeAbsolute(_environment); + builder.AppendSwitch("--temporary-directory", settings.TemporaryDirectory.FullPath.Quote()); + } + } + + private void BuildLegacyArguments(IEnumerable sourceFiles, FilePath outputFile, ProcessArgumentBuilder builder) + { // Set the Source files. var source = string.Join(';', sourceFiles.Select(s => s.MakeAbsolute(_environment).FullPath)); builder.AppendSwitch("/Source", "=", source.Quote()); @@ -75,11 +128,6 @@ private ProcessArgumentBuilder GetArguments( // Set the Output file. outputFile = outputFile.MakeAbsolute(_environment); builder.AppendSwitch("/Output", "=", outputFile.FullPath.Quote()); - - // Get Global settings - GetArguments(settings).CopyTo(builder); - - return builder; } } } diff --git a/src/Cake.Common/Tools/DotCover/Report/DotCoverReportSettings.cs b/src/Cake.Common/Tools/DotCover/Report/DotCoverReportSettings.cs index 0e04d50b72..23915dd7c8 100644 --- a/src/Cake.Common/Tools/DotCover/Report/DotCoverReportSettings.cs +++ b/src/Cake.Common/Tools/DotCover/Report/DotCoverReportSettings.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using Cake.Core.IO; + namespace Cake.Common.Tools.DotCover.Report { /// @@ -15,5 +17,29 @@ public sealed class DotCoverReportSettings : DotCoverSettings /// The Default value is . /// public DotCoverReportType ReportType { get; set; } + + /// + /// Gets or sets the path to save a formatted JSON report. + /// This represents the --json-report-output option. + /// + public FilePath JsonReportOutput { get; set; } + + /// + /// Gets or sets granularity for including covering tests in JSON reports: [none|assembly|type|method|statement] + /// This represents the --json-report-covering-tests-scope option. + /// + public DotCoverReportScope? JsonReportCoveringTestsScope { get; set; } + + /// + /// Gets or sets the path to save a formatted XML report. + /// This represents the --xml-report-output option. + /// + public FilePath XmlReportOutput { get; set; } + + /// + /// Gets or sets granularity for including covering tests in XML reports: [none|assembly|type|method|statement] + /// This represents the --xml-report-covering-tests-scope option. + /// + public DotCoverReportScope? XmlReportCoveringTestsScope { get; set; } } -} +} \ No newline at end of file diff --git a/src/Cake.Common/Tools/DotCover/Report/DotCoverReporter.cs b/src/Cake.Common/Tools/DotCover/Report/DotCoverReporter.cs index 870ed0a1a9..3485281f4a 100644 --- a/src/Cake.Common/Tools/DotCover/Report/DotCoverReporter.cs +++ b/src/Cake.Common/Tools/DotCover/Report/DotCoverReporter.cs @@ -33,7 +33,7 @@ public DotCoverReporter( } /// - /// Runs DotCover Cover with the specified settings. + /// Runs DotCover Report with the specified settings. /// /// The DotCover coverage snapshot file name. /// The DotCover output file. @@ -44,25 +44,108 @@ public void Report( DotCoverReportSettings settings) { ArgumentNullException.ThrowIfNull(sourceFile); - ArgumentNullException.ThrowIfNull(outputFile); ArgumentNullException.ThrowIfNull(settings); + if (settings.UseLegacySyntax) + { + ArgumentNullException.ThrowIfNull(outputFile); + } + + if (!settings.UseLegacySyntax && outputFile != null) + { + // map outputFile to new syntax parameters. Otherwise input is ignored + switch (settings.ReportType) + { + case DotCoverReportType.XML: + settings.XmlReportOutput = outputFile; + break; + case DotCoverReportType.JSON: + settings.JsonReportOutput = outputFile; + break; + default: + settings.XmlReportOutput = outputFile; + break; + } + } + // Run the tool. - Run(settings, GetArguments(sourceFile, outputFile, settings)); + Run(settings, GetArguments(sourceFile, settings, outputFile)); } - private ProcessArgumentBuilder GetArguments( + /// + /// Runs DotCover Report with the specified settings. + /// + /// The DotCover coverage snapshot file name. + /// The settings. + public void Report( FilePath sourceFile, - FilePath outputFile, DotCoverReportSettings settings) + { + ArgumentNullException.ThrowIfNull(sourceFile); + ArgumentNullException.ThrowIfNull(settings); + + // Run the tool. + Run(settings, GetArguments(sourceFile, settings)); + } + + private ProcessArgumentBuilder GetArguments( + FilePath sourceFile, + DotCoverReportSettings settings, FilePath outputFile = null) { var builder = new ProcessArgumentBuilder(); - builder.Append("Report"); + builder.Append("report"); // Set configuration file if exists. GetConfigurationFileArgument(settings).CopyTo(builder); + if (settings.UseLegacySyntax) + { + GenerateLegacyArguments(sourceFile, outputFile, settings, builder); + } + else + { + GenerateArguments(sourceFile, settings, builder); + } + + // Get Global settings + GetArguments(settings).CopyTo(builder); + + return builder; + } + + private void GenerateArguments(FilePath sourceFile, DotCoverReportSettings settings, ProcessArgumentBuilder builder) + { + // Set the Source file. + builder.AppendSwitch("--snapshot-source", sourceFile.MakeAbsolute(_environment).FullPath.Quote()); + + // Set Json report output + if (settings.JsonReportOutput != null) + { + builder.AppendSwitch("--json-report-output", settings.JsonReportOutput.MakeAbsolute(_environment).FullPath.Quote()); + } + + // Set test scope, ignore default value + if (settings.JsonReportCoveringTestsScope.HasValue) + { + builder.AppendSwitch("--json-report-covering-tests-scope", settings.JsonReportCoveringTestsScope.Value.ToString().ToLowerInvariant().Quote()); + } + + // Set Xml report output + if (settings.XmlReportOutput != null) + { + builder.AppendSwitch("--xml-report-output", settings.XmlReportOutput.MakeAbsolute(_environment).FullPath.Quote()); + } + + // Set test scope, ignore default value + if (settings.XmlReportCoveringTestsScope.HasValue) + { + builder.AppendSwitch("--xml-report-covering-tests-scope", settings.XmlReportCoveringTestsScope.Value.ToString().ToLowerInvariant().Quote()); + } + } + + private void GenerateLegacyArguments(FilePath sourceFile, FilePath outputFile, DotCoverReportSettings settings, ProcessArgumentBuilder builder) + { // Set the Source file. sourceFile = sourceFile.MakeAbsolute(_environment); builder.AppendSwitch("/Source", "=", sourceFile.FullPath.Quote()); @@ -76,11 +159,6 @@ private ProcessArgumentBuilder GetArguments( { builder.AppendSwitch("/ReportType", "=", settings.ReportType.ToString()); } - - // Get Global settings - GetArguments(settings).CopyTo(builder); - - return builder; } } }