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 bb74ba5f17..f98ab9b6f9 100644
--- a/src/Cake.Common.Tests/Unit/Tools/DotCover/Cover/DotCoverCovererTests.cs
+++ b/src/Cake.Common.Tests/Unit/Tools/DotCover/Cover/DotCoverCovererTests.cs
@@ -4,6 +4,7 @@
using Cake.Common.Tests.Fixtures.Tools.DotCover.Cover;
using Cake.Common.Tools.DotCover;
+using Cake.Common.Tools.DotCover.Cover;
using Cake.Common.Tools.NUnit;
using Cake.Common.Tools.XUnit;
using Cake.Core.IO;
@@ -96,9 +97,9 @@ public void Should_Capture_Tool_And_Arguments_From_Action()
var result = fixture.Run();
// Then
- Assert.Equal("Cover /TargetExecutable=\"/Working/tools/Test.exe\" " +
- "/TargetArguments=\"-argument\" " +
- "/Output=\"/Working/result.dcvr\"", result.Args);
+ Assert.Equal("cover --target-executable \"/Working/tools/Test.exe\" " +
+ "--target-arguments \"-argument\" " +
+ "--snapshot-output \"/Working/result.dcvr\"", result.Args);
}
[Theory]
@@ -122,8 +123,8 @@ public void Should_Not_Capture_Arguments_From_Action_If_Excluded(string argument
var result = fixture.Run();
// Then
- Assert.Equal("Cover /TargetExecutable=\"/Working/tools/Test.exe\" " +
- "/Output=\"/Working/result.dcvr\"", result.Args);
+ Assert.Equal("cover --target-executable \"/Working/tools/Test.exe\" " +
+ "--snapshot-output \"/Working/result.dcvr\"", result.Args);
}
[Fact]
@@ -137,10 +138,10 @@ public void Should_Append_TargetWorkingDir()
var result = fixture.Run();
// Then
- Assert.Equal("Cover /TargetExecutable=\"/Working/tools/Test.exe\" " +
- "/TargetArguments=\"-argument\" " +
- "/Output=\"/Working/result.dcvr\" " +
- "/TargetWorkingDir=\"/Working\"", result.Args);
+ Assert.Equal("cover --target-executable \"/Working/tools/Test.exe\" " +
+ "--target-arguments \"-argument\" " +
+ "--snapshot-output \"/Working/result.dcvr\" " +
+ "--target-working-directory \"/Working\"", result.Args);
}
[Fact]
@@ -155,9 +156,9 @@ public void Should_Append_Scope()
var result = fixture.Run();
// Then
- Assert.Equal("Cover /TargetExecutable=\"/Working/tools/Test.exe\" " +
- "/TargetArguments=\"-argument\" " +
- "/Output=\"/Working/result.dcvr\" " +
+ 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);
}
@@ -173,9 +174,9 @@ public void Should_Append_Filters()
var result = fixture.Run();
// Then
- Assert.Equal("Cover /TargetExecutable=\"/Working/tools/Test.exe\" " +
- "/TargetArguments=\"-argument\" " +
- "/Output=\"/Working/result.dcvr\" " +
+ Assert.Equal("cover --target-executable \"/Working/tools/Test.exe\" " +
+ "--target-arguments \"-argument\" " +
+ "--snapshot-output \"/Working/result.dcvr\" " +
"/Filters=\"+:module=Test.*;-:myassembly\"", result.Args);
}
@@ -191,9 +192,9 @@ public void Should_Append_AttributeFilters()
var result = fixture.Run();
// Then
- Assert.Equal("Cover /TargetExecutable=\"/Working/tools/Test.exe\" " +
- "/TargetArguments=\"-argument\" " +
- "/Output=\"/Working/result.dcvr\" " +
+ Assert.Equal("cover --target-executable \"/Working/tools/Test.exe\" " +
+ "--target-arguments \"-argument\" " +
+ "--snapshot-output \"/Working/result.dcvr\" " +
"/AttributeFilters=\"filter1;filter2\"", result.Args);
}
@@ -208,9 +209,9 @@ public void Should_Append_DisableDefaultFilters()
var result = fixture.Run();
// Then
- Assert.Equal("Cover /TargetExecutable=\"/Working/tools/Test.exe\" " +
- "/TargetArguments=\"-argument\" " +
- "/Output=\"/Working/result.dcvr\" " +
+ Assert.Equal("cover --target-executable \"/Working/tools/Test.exe\" " +
+ "--target-arguments \"-argument\" " +
+ "--snapshot-output \"/Working/result.dcvr\" " +
"/DisableDefaultFilters", result.Args);
}
@@ -226,9 +227,9 @@ public void Should_Append_ProcessFilters()
var result = fixture.Run();
// Then
- Assert.Equal("Cover /TargetExecutable=\"/Working/tools/Test.exe\" " +
- "/TargetArguments=\"-argument\" " +
- "/Output=\"/Working/result.dcvr\" " +
+ Assert.Equal("cover --target-executable \"/Working/tools/Test.exe\" " +
+ "--target-arguments \"-argument\" " +
+ "--snapshot-output \"/Working/result.dcvr\" " +
"/ProcessFilters=\"+:test.exe;-:sqlservr.exe\"", result.Args);
}
@@ -249,9 +250,9 @@ public void Should_Capture_XUnit()
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);
+ Assert.Equal("cover --target-executable \"/Working/tools/xunit.console.exe\" " +
+ "--target-arguments \"\\\"/Working/Test.dll\\\" -noshadow\" " +
+ "--snapshot-output \"/Working/result.dcvr\"", result.Args);
}
[Fact]
@@ -271,9 +272,9 @@ public void Should_Capture_NUnit()
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);
+ Assert.Equal("cover --target-executable \"/Working/tools/nunit-console.exe\" " +
+ "--target-arguments \"\\\"/Working/Test.dll\\\" -noshadow\" " +
+ "--snapshot-output \"/Working/result.dcvr\"", result.Args);
}
[Fact]
@@ -287,10 +288,252 @@ public void Should_Append_ConfigurationFile()
var result = fixture.Run();
// Then
- Assert.Equal("Cover \"/Working/config.xml\" /TargetExecutable=\"/Working/tools/Test.exe\" " +
+ Assert.Equal("cover \"/Working/config.xml\" --target-executable \"/Working/tools/Test.exe\" " +
+ "--target-arguments \"-argument\" " +
+ "--snapshot-output \"/Working/result.dcvr\"", result.Args);
+ }
+
+ [Fact]
+ public void Should_Append_ExcludeAssemblies()
+ {
+ // Given
+ var fixture = new DotCoverCovererFixture();
+ fixture.Settings.WithExcludeAssembly("*.Tests")
+ .WithExcludeAssembly("Test.*");
+
+ // When
+ var result = fixture.Run();
+
+ // Then
+ Assert.Equal("cover --target-executable \"/Working/tools/Test.exe\" " +
+ "--target-arguments \"-argument\" " +
+ "--snapshot-output \"/Working/result.dcvr\" " +
+ "--exclude-assemblies \"*.Tests,Test.*\"", result.Args);
+ }
+
+ [Fact]
+ public void Should_Append_ExcludeAttributes()
+ {
+ // Given
+ var fixture = new DotCoverCovererFixture();
+ fixture.Settings.WithExcludeAttribute("System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute")
+ .WithExcludeAttribute("Custom.*Attribute");
+
+ // When
+ var result = fixture.Run();
+
+ // Then
+ Assert.Equal("cover --target-executable \"/Working/tools/Test.exe\" " +
+ "--target-arguments \"-argument\" " +
+ "--snapshot-output \"/Working/result.dcvr\" " +
+ "--exclude-attributes \"System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute,Custom.*Attribute\"", result.Args);
+ }
+
+ [Fact]
+ public void Should_Append_ExcludeProcesses()
+ {
+ // Given
+ var fixture = new DotCoverCovererFixture();
+ fixture.Settings.WithExcludeProcess("test.exe")
+ .WithExcludeProcess("*.vshost.exe");
+
+ // When
+ var result = fixture.Run();
+
+ // Then
+ Assert.Equal("cover --target-executable \"/Working/tools/Test.exe\" " +
+ "--target-arguments \"-argument\" " +
+ "--snapshot-output \"/Working/result.dcvr\" " +
+ "--exclude-processes \"test.exe,*.vshost.exe\"", result.Args);
+ }
+
+ [Fact]
+ public void Should_Append_JsonReportOutput()
+ {
+ // Given
+ var fixture = new DotCoverCovererFixture();
+ fixture.Settings.WithJsonReportOutput(new FilePath("/Working/coverage.json"));
+
+ // When
+ var result = fixture.Run();
+
+ // Then
+ Assert.Equal("cover --target-executable \"/Working/tools/Test.exe\" " +
+ "--target-arguments \"-argument\" " +
+ "--snapshot-output \"/Working/result.dcvr\" " +
+ "--json-report-output \"/Working/coverage.json\"", result.Args);
+ }
+
+ [Fact]
+ public void Should_Append_JsonReportCoveringTestsScope()
+ {
+ // Given
+ var fixture = new DotCoverCovererFixture();
+ fixture.Settings.WithJsonReportCoveringTestsScope(DotCoverReportScope.Method);
+
+ // When
+ var result = fixture.Run();
+
+ // Then
+ Assert.Equal("cover --target-executable \"/Working/tools/Test.exe\" " +
+ "--target-arguments \"-argument\" " +
+ "--snapshot-output \"/Working/result.dcvr\" " +
+ "--json-report-covering-tests-scope \"method\"", result.Args);
+ }
+
+ [Fact]
+ public void Should_Append_XmlReportOutput()
+ {
+ // Given
+ var fixture = new DotCoverCovererFixture();
+ fixture.Settings.WithXmlReportOutput(new FilePath("/Working/coverage.xml"));
+
+ // When
+ var result = fixture.Run();
+
+ // Then
+ Assert.Equal("cover --target-executable \"/Working/tools/Test.exe\" " +
+ "--target-arguments \"-argument\" " +
+ "--snapshot-output \"/Working/result.dcvr\" " +
+ "--xml-report-output \"/Working/coverage.xml\"", result.Args);
+ }
+
+ [Fact]
+ public void Should_Append_XmlReportCoveringTestsScope()
+ {
+ // Given
+ var fixture = new DotCoverCovererFixture();
+ fixture.Settings.WithXmlReportCoveringTestsScope(DotCoverReportScope.Statement);
+
+ // When
+ var result = fixture.Run();
+
+ // Then
+ Assert.Equal("cover --target-executable \"/Working/tools/Test.exe\" " +
+ "--target-arguments \"-argument\" " +
+ "--snapshot-output \"/Working/result.dcvr\" " +
+ "--xml-report-covering-tests-scope \"statement\"", result.Args);
+ }
+
+ [Fact]
+ public void Should_Append_TemporaryDirectory()
+ {
+ // Given
+ var fixture = new DotCoverCovererFixture();
+ fixture.Settings.WithTemporaryDirectory(new DirectoryPath("/Working/temp"));
+
+ // When
+ var result = fixture.Run();
+
+ // Then
+ Assert.Equal("cover --target-executable \"/Working/tools/Test.exe\" " +
+ "--target-arguments \"-argument\" " +
+ "--snapshot-output \"/Working/result.dcvr\" " +
+ "--temporary-directory \"/Working/temp\"", result.Args);
+ }
+
+ [Fact]
+ public void Should_Append_UseApi()
+ {
+ // Given
+ var fixture = new DotCoverCovererFixture();
+ fixture.Settings.WithUseApi();
+
+ // When
+ var result = fixture.Run();
+
+ // Then
+ Assert.Equal("cover --target-executable \"/Working/tools/Test.exe\" " +
+ "--target-arguments \"-argument\" " +
+ "--snapshot-output \"/Working/result.dcvr\" " +
+ "--use-api", result.Args);
+ }
+
+ [Fact]
+ public void Should_Append_NoNGen()
+ {
+ // Given
+ var fixture = new DotCoverCovererFixture();
+ fixture.Settings.WithNoNGen();
+
+ // When
+ var result = fixture.Run();
+
+ // Then
+ Assert.Equal("cover --target-executable \"/Working/tools/Test.exe\" " +
+ "--target-arguments \"-argument\" " +
+ "--snapshot-output \"/Working/result.dcvr\" " +
+ "--no-ngen", result.Args);
+ }
+
+ [Fact]
+ public void Should_Use_Legacy_Syntax_When_Enabled()
+ {
+ // 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);
}
+
+ [Fact]
+ public void Should_Use_New_Syntax_By_Default()
+ {
+ // Given
+ var fixture = new DotCoverCovererFixture();
+ // Don't set UseLegacySyntax - should default to false
+
+ // When
+ var result = fixture.Run();
+
+ // Then
+ Assert.Equal("cover --target-executable \"/Working/tools/Test.exe\" " +
+ "--target-arguments \"-argument\" " +
+ "--snapshot-output \"/Working/result.dcvr\"", result.Args);
+ }
+
+ [Fact]
+ 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");
+
+ // When
+ var result = fixture.Run();
+
+ // Then - New format features should not appear in legacy mode
+ Assert.Equal("cover /TargetExecutable=\"/Working/tools/Test.exe\" " +
+ "/TargetArguments=\"-argument\" " +
+ "/Output=\"/Working/result.dcvr\"", result.Args);
+ Assert.DoesNotContain("--json-report-output", result.Args);
+ Assert.DoesNotContain("--exclude-assemblies", result.Args);
+ }
+
+ [Fact]
+ public void Should_Support_New_Features_In_New_Mode()
+ {
+ // Given
+ var fixture = new DotCoverCovererFixture();
+ fixture.Settings.WithJsonReportOutput(new FilePath("/Working/report.json"))
+ .WithExcludeAssembly("*.Tests");
+
+ // When
+ var result = fixture.Run();
+
+ // Then - New format features should appear
+ Assert.Contains("--json-report-output \"/Working/report.json\"", result.Args);
+ Assert.Contains("--exclude-assemblies \"*.Tests\"", result.Args);
+ Assert.Contains("--snapshot-output", result.Args);
+ }
}
}
}
\ 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 6fd5c47a94..eadc7ce291 100644
--- a/src/Cake.Common/Tools/DotCover/Cover/DotCoverCoverSettings.cs
+++ b/src/Cake.Common/Tools/DotCover/Cover/DotCoverCoverSettings.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.Cover
{
///
@@ -9,5 +11,54 @@ namespace Cake.Common.Tools.DotCover.Cover
///
public sealed class DotCoverCoverSettings : DotCoverCoverageSettings
{
+ ///
+ /// Gets or sets the path to save formatted JSON report.
+ /// This represents the --json-report-output option.
+ ///
+ public FilePath JsonReportOutput { get; set; }
+
+ ///
+ /// Gets or sets the granularity for including covering tests in JSON reports.
+ /// This represents the --json-report-covering-tests-scope option.
+ ///
+ public DotCoverReportScope? JsonReportCoveringTestsScope { get; set; }
+
+ ///
+ /// Gets or sets the path to save formatted XML report.
+ /// This represents the --xml-report-output option.
+ ///
+ public FilePath XmlReportOutput { get; set; }
+
+ ///
+ /// Gets or sets the granularity for including covering tests in XML reports.
+ /// This represents the --xml-report-covering-tests-scope option.
+ ///
+ public DotCoverReportScope? XmlReportCoveringTestsScope { get; set; }
+
+ ///
+ /// Gets or sets the directory for temporary files.
+ /// This represents the --temporary-directory option.
+ ///
+ public DirectoryPath TemporaryDirectory { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether to control the coverage session using the profiler API.
+ /// This represents the --use-api option.
+ ///
+ public bool UseApi { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether to disable loading of NGen images during coverage.
+ /// 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/DotCoverCoverSettingsExtensions.cs b/src/Cake.Common/Tools/DotCover/Cover/DotCoverCoverSettingsExtensions.cs
new file mode 100644
index 0000000000..f8b5263f6c
--- /dev/null
+++ b/src/Cake.Common/Tools/DotCover/Cover/DotCoverCoverSettingsExtensions.cs
@@ -0,0 +1,119 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using Cake.Core.IO;
+
+namespace Cake.Common.Tools.DotCover.Cover
+{
+ ///
+ /// Contains extensions for .
+ ///
+ public static class DotCoverCoverSettingsExtensions
+ {
+ ///
+ /// Sets the JSON report output path.
+ ///
+ /// The settings.
+ /// The JSON report output path.
+ /// The same instance so that multiple calls can be chained.
+ public static DotCoverCoverSettings WithJsonReportOutput(this DotCoverCoverSettings settings, FilePath outputPath)
+ {
+ ArgumentNullException.ThrowIfNull(settings);
+ settings.JsonReportOutput = outputPath;
+ return settings;
+ }
+
+ ///
+ /// Sets the JSON report covering tests scope.
+ ///
+ /// The settings.
+ /// The granularity for including covering tests in JSON reports.
+ /// The same instance so that multiple calls can be chained.
+ public static DotCoverCoverSettings WithJsonReportCoveringTestsScope(this DotCoverCoverSettings settings, DotCoverReportScope scope)
+ {
+ ArgumentNullException.ThrowIfNull(settings);
+ settings.JsonReportCoveringTestsScope = scope;
+ return settings;
+ }
+
+ ///
+ /// Sets the XML report output path.
+ ///
+ /// The settings.
+ /// The XML report output path.
+ /// The same instance so that multiple calls can be chained.
+ public static DotCoverCoverSettings WithXmlReportOutput(this DotCoverCoverSettings settings, FilePath outputPath)
+ {
+ ArgumentNullException.ThrowIfNull(settings);
+ settings.XmlReportOutput = outputPath;
+ return settings;
+ }
+
+ ///
+ /// Sets the XML report covering tests scope.
+ ///
+ /// The settings.
+ /// The granularity for including covering tests in XML reports.
+ /// The same instance so that multiple calls can be chained.
+ public static DotCoverCoverSettings WithXmlReportCoveringTestsScope(this DotCoverCoverSettings settings, DotCoverReportScope scope)
+ {
+ ArgumentNullException.ThrowIfNull(settings);
+ settings.XmlReportCoveringTestsScope = scope;
+ return settings;
+ }
+
+ ///
+ /// Sets the temporary directory for files.
+ ///
+ /// The settings.
+ /// The temporary directory path.
+ /// The same instance so that multiple calls can be chained.
+ public static DotCoverCoverSettings WithTemporaryDirectory(this DotCoverCoverSettings settings, DirectoryPath directory)
+ {
+ ArgumentNullException.ThrowIfNull(settings);
+ settings.TemporaryDirectory = directory;
+ return settings;
+ }
+
+ ///
+ /// Enables control of the coverage session using the profiler API.
+ ///
+ /// The settings.
+ /// Whether to use the API.
+ /// The same instance so that multiple calls can be chained.
+ public static DotCoverCoverSettings WithUseApi(this DotCoverCoverSettings settings, bool useApi = true)
+ {
+ ArgumentNullException.ThrowIfNull(settings);
+ settings.UseApi = useApi;
+ return settings;
+ }
+
+ ///
+ /// Disables loading of NGen images during coverage.
+ ///
+ /// The settings.
+ /// Whether to disable NGen.
+ /// The same instance so that multiple calls can be chained.
+ public static DotCoverCoverSettings WithNoNGen(this DotCoverCoverSettings settings, bool noNGen = true)
+ {
+ ArgumentNullException.ThrowIfNull(settings);
+ settings.NoNGen = noNGen;
+ return settings;
+ }
+
+ ///
+ /// Configures whether to use legacy command syntax.
+ ///
+ /// The settings.
+ /// Whether to use legacy syntax. Default is false (new syntax).
+ /// The same instance so that multiple calls can be chained.
+ public static DotCoverCoverSettings WithLegacySyntax(this DotCoverCoverSettings settings, bool useLegacySyntax = true)
+ {
+ ArgumentNullException.ThrowIfNull(settings);
+ settings.UseLegacySyntax = useLegacySyntax;
+ return settings;
+ }
+ }
+}
\ 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 b37c455853..c3d53ab657 100644
--- a/src/Cake.Common/Tools/DotCover/Cover/DotCoverCoverer.cs
+++ b/src/Cake.Common/Tools/DotCover/Cover/DotCoverCoverer.cs
@@ -61,23 +61,163 @@ private ProcessArgumentBuilder GetArguments(
{
var builder = new ProcessArgumentBuilder();
- builder.Append("Cover");
+ // Command name - always lowercase 'cover' for both formats
+ builder.Append("cover");
// Set configuration file if exists.
GetConfigurationFileArgument(settings).CopyTo(builder);
- // Get Target executable arguments
- GetTargetArguments(context, action).CopyTo(builder);
+ if (settings.UseLegacySyntax)
+ {
+ // Use legacy format
+ GetTargetArguments(context, action).CopyTo(builder);
+ // Set the output file - legacy format
+ outputPath = outputPath.MakeAbsolute(_environment);
+ builder.AppendSwitch("/Output", "=", outputPath.FullPath.Quote());
+ // Get Coverage arguments - legacy format
+ GetCoverageArguments(settings).CopyTo(builder);
+ // Get base arguments - legacy format
+ GetArguments(settings).CopyTo(builder);
+ }
+ else
+ {
+ // Use new format
+ GetCoverTargetArguments(context, action).CopyTo(builder);
+ // Set the output file - new format
+ outputPath = outputPath.MakeAbsolute(_environment);
+ builder.AppendSwitch("--snapshot-output", outputPath.FullPath.Quote());
+ // Get Coverage arguments - new format
+ GetCoverCoverageArguments(settings).CopyTo(builder);
+ // New report options (only available in new format)
+ if (settings.JsonReportOutput != null)
+ {
+ builder.AppendSwitch("--json-report-output", settings.JsonReportOutput.MakeAbsolute(_environment).FullPath.Quote());
+ }
- // Set the output file.
- outputPath = outputPath.MakeAbsolute(_environment);
- builder.AppendSwitch("/Output", "=", outputPath.FullPath.Quote());
+ if (settings.JsonReportCoveringTestsScope.HasValue)
+ {
+ builder.AppendSwitch("--json-report-covering-tests-scope", settings.JsonReportCoveringTestsScope.Value.ToString().ToLowerInvariant().Quote());
+ }
- // Get Coverage arguments
- GetCoverageArguments(settings).CopyTo(builder);
+ if (settings.XmlReportOutput != null)
+ {
+ builder.AppendSwitch("--xml-report-output", settings.XmlReportOutput.MakeAbsolute(_environment).FullPath.Quote());
+ }
- // Get base arguments
- GetArguments(settings).CopyTo(builder);
+ if (settings.XmlReportCoveringTestsScope.HasValue)
+ {
+ builder.AppendSwitch("--xml-report-covering-tests-scope", settings.XmlReportCoveringTestsScope.Value.ToString().ToLowerInvariant().Quote());
+ }
+
+ if (settings.TemporaryDirectory != null)
+ {
+ builder.AppendSwitch("--temporary-directory", settings.TemporaryDirectory.MakeAbsolute(_environment).FullPath.Quote());
+ }
+
+ if (settings.UseApi)
+ {
+ builder.Append("--use-api");
+ }
+
+ if (settings.NoNGen)
+ {
+ builder.Append("--no-ngen");
+ }
+
+ // Get base arguments - new format
+ GetCoverArguments(settings).CopyTo(builder);
+ }
+
+ return builder;
+ }
+
+ ///
+ /// Get arguments from coverage settings for Cover command (using new format).
+ ///
+ /// The settings.
+ /// The process arguments.
+ private ProcessArgumentBuilder GetCoverCoverageArguments(DotCoverCoverageSettings settings)
+ {
+ var builder = new ProcessArgumentBuilder();
+
+ // TargetWorkingDir - using new format for Cover command
+ if (settings.TargetWorkingDir != null)
+ {
+ builder.AppendSwitch("--target-working-directory", settings.TargetWorkingDir.MakeAbsolute(_environment).FullPath.Quote());
+ }
+
+ // New filtering options (only available in new format)
+ if (settings.ExcludeAssemblies.Count > 0)
+ {
+ var excludeAssemblies = string.Join(',', settings.ExcludeAssemblies);
+ builder.AppendSwitch("--exclude-assemblies", excludeAssemblies.Quote());
+ }
+
+ if (settings.ExcludeAttributes.Count > 0)
+ {
+ var excludeAttributes = string.Join(',', settings.ExcludeAttributes);
+ builder.AppendSwitch("--exclude-attributes", excludeAttributes.Quote());
+ }
+
+ if (settings.ExcludeProcesses.Count > 0)
+ {
+ var excludeProcesses = string.Join(',', settings.ExcludeProcesses);
+ 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;
+ }
+
+ ///
+ /// Get arguments from global settings for Cover command (using new format).
+ ///
+ /// The settings.
+ /// The process arguments.
+ private ProcessArgumentBuilder GetCoverArguments(DotCoverSettings settings)
+ {
+ var builder = new ProcessArgumentBuilder();
+
+ // LogFile - using new format for Cover command
+ if (settings.LogFile != null)
+ {
+ var logFilePath = settings.LogFile.MakeAbsolute(_environment);
+ builder.AppendSwitch("--log-file", logFilePath.FullPath.Quote());
+ }
return builder;
}
diff --git a/src/Cake.Common/Tools/DotCover/DotCoverCoverageSettings.cs b/src/Cake.Common/Tools/DotCover/DotCoverCoverageSettings.cs
index a499d5d944..2e37d78c3a 100644
--- a/src/Cake.Common/Tools/DotCover/DotCoverCoverageSettings.cs
+++ b/src/Cake.Common/Tools/DotCover/DotCoverCoverageSettings.cs
@@ -17,10 +17,13 @@ public abstract class DotCoverCoverageSettings : DotCoverSettings
private readonly HashSet _filters;
private readonly HashSet _processFilters;
private readonly HashSet _attributeFilters;
+ private readonly HashSet _excludeAssemblies;
+ private readonly HashSet _excludeAttributes;
+ private readonly HashSet _excludeProcesses;
///
/// Gets or sets program working directory
- /// This represents the /TargetWorkingDir option.
+ /// This represents the --target-working-directory option for Cover command, /TargetWorkingDir for others.
///
public DirectoryPath TargetWorkingDir { get; set; }
@@ -65,6 +68,34 @@ public ISet ProcessFilters
get { return _processFilters; }
}
+ ///
+ /// Gets assembly names to exclude from analysis. Wildcards (*) allowed.
+ /// This represents the --exclude-assemblies option.
+ ///
+ public ISet ExcludeAssemblies
+ {
+ get { return _excludeAssemblies; }
+ }
+
+ ///
+ /// Gets fully qualified attribute names to exclude from analysis. Wildcards (*) allowed.
+ /// Code marked with these attributes will be excluded from coverage.
+ /// This represents the --exclude-attributes option.
+ ///
+ public ISet ExcludeAttributes
+ {
+ get { return _excludeAttributes; }
+ }
+
+ ///
+ /// Gets process names to ignore during analysis. Wildcards (*) allowed.
+ /// This represents the --exclude-processes option.
+ ///
+ public ISet ExcludeProcesses
+ {
+ get { return _excludeProcesses; }
+ }
+
///
/// Gets or sets a value indicating whether the default (automatically added) filters should be disabled
/// This represents the /DisableDefaultFilters option.
@@ -80,6 +111,9 @@ protected DotCoverCoverageSettings()
_filters = new HashSet(StringComparer.OrdinalIgnoreCase);
_attributeFilters = new HashSet(StringComparer.OrdinalIgnoreCase);
_processFilters = new HashSet(StringComparer.OrdinalIgnoreCase);
+ _excludeAssemblies = new HashSet(StringComparer.OrdinalIgnoreCase);
+ _excludeAttributes = new HashSet(StringComparer.OrdinalIgnoreCase);
+ _excludeProcesses = new HashSet(StringComparer.OrdinalIgnoreCase);
}
}
}
\ No newline at end of file
diff --git a/src/Cake.Common/Tools/DotCover/DotCoverCoverageSettingsExtensions.cs b/src/Cake.Common/Tools/DotCover/DotCoverCoverageSettingsExtensions.cs
index 5c8b0e4d8a..b2b02b94b5 100644
--- a/src/Cake.Common/Tools/DotCover/DotCoverCoverageSettingsExtensions.cs
+++ b/src/Cake.Common/Tools/DotCover/DotCoverCoverageSettingsExtensions.cs
@@ -66,5 +66,47 @@ public static T WithProcessFilter(this T settings, string filter) where T : D
settings.ProcessFilters.Add(filter);
return settings;
}
+
+ ///
+ /// Adds an assembly name to exclude from analysis.
+ ///
+ /// The settings.
+ /// The assembly name to exclude. Wildcards (*) are allowed.
+ /// The settings type, derived from .
+ /// The same instance so that multiple calls can be chained.
+ public static T WithExcludeAssembly(this T settings, string assemblyName) where T : DotCoverCoverageSettings
+ {
+ ArgumentNullException.ThrowIfNull(settings);
+ settings.ExcludeAssemblies.Add(assemblyName);
+ return settings;
+ }
+
+ ///
+ /// Adds a fully qualified attribute name to exclude from analysis.
+ ///
+ /// The settings.
+ /// The fully qualified attribute name. Wildcards (*) are allowed.
+ /// The settings type, derived from .
+ /// The same instance so that multiple calls can be chained.
+ public static T WithExcludeAttribute(this T settings, string attributeName) where T : DotCoverCoverageSettings
+ {
+ ArgumentNullException.ThrowIfNull(settings);
+ settings.ExcludeAttributes.Add(attributeName);
+ return settings;
+ }
+
+ ///
+ /// Adds a process name to ignore during analysis.
+ ///
+ /// The settings.
+ /// The process name to ignore. Wildcards (*) are allowed.
+ /// The settings type, derived from .
+ /// The same instance so that multiple calls can be chained.
+ public static T WithExcludeProcess(this T settings, string processName) where T : DotCoverCoverageSettings
+ {
+ ArgumentNullException.ThrowIfNull(settings);
+ settings.ExcludeProcesses.Add(processName);
+ return settings;
+ }
}
}
\ No newline at end of file
diff --git a/src/Cake.Common/Tools/DotCover/DotCoverCoverageTool.cs b/src/Cake.Common/Tools/DotCover/DotCoverCoverageTool.cs
index fafa0d4a16..030fe51e71 100644
--- a/src/Cake.Common/Tools/DotCover/DotCoverCoverageTool.cs
+++ b/src/Cake.Common/Tools/DotCover/DotCoverCoverageTool.cs
@@ -33,6 +33,35 @@ public DotCoverCoverageTool(
_environment = environment;
}
+ ///
+ /// Get arguments from the target executable for Cover command (using new format).
+ ///
+ /// The context.
+ /// The action to run DotCover for.
+ /// The process arguments.
+ protected ProcessArgumentBuilder GetCoverTargetArguments(ICakeContext context, Action action)
+ {
+ // Run the tool using the interceptor.
+ var targetContext = InterceptAction(context, action);
+
+ var builder = new ProcessArgumentBuilder();
+ // The target application to call.
+ builder.AppendSwitch("--target-executable", targetContext.FilePath.FullPath.Quote());
+
+ // The arguments to the target application.
+ if (targetContext.Settings != null && targetContext.Settings.Arguments != null)
+ {
+ var arguments = targetContext.Settings.Arguments.Render();
+ if (!string.IsNullOrWhiteSpace(arguments))
+ {
+ arguments = arguments.Replace("\"", "\\\"");
+ builder.AppendSwitch("--target-arguments", arguments.Quote());
+ }
+ }
+
+ return builder;
+ }
+
///
/// Get arguments from the target executable.
///
@@ -99,7 +128,7 @@ protected ProcessArgumentBuilder GetCoverageArguments(DotCoverCoverageSettings s
builder.AppendSwitch("/AttributeFilters", "=", attributeFilters.Quote());
}
- // Filters
+ // ProcessFilters
if (settings.ProcessFilters.Count > 0)
{
var processFilters = string.Join(';', settings.ProcessFilters);
@@ -131,4 +160,4 @@ private static DotCoverContext InterceptAction(
return interceptor;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Cake.Common/Tools/DotCover/DotCoverReportScope.cs b/src/Cake.Common/Tools/DotCover/DotCoverReportScope.cs
new file mode 100644
index 0000000000..f7753a2446
--- /dev/null
+++ b/src/Cake.Common/Tools/DotCover/DotCoverReportScope.cs
@@ -0,0 +1,37 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Cake.Common.Tools.DotCover
+{
+ ///
+ /// Represents the granularity for including covering tests in reports.
+ ///
+ public enum DotCoverReportScope
+ {
+ ///
+ /// No covering tests included.
+ ///
+ None,
+
+ ///
+ /// Include covering tests at assembly level.
+ ///
+ Assembly,
+
+ ///
+ /// Include covering tests at type level.
+ ///
+ Type,
+
+ ///
+ /// Include covering tests at method level.
+ ///
+ Method,
+
+ ///
+ /// Include covering tests at statement level.
+ ///
+ Statement
+ }
+}
\ No newline at end of file