Skip to content

Commit 71d8ecf

Browse files
committed
Centralize Coverlet command-line option definitions
Refactor to introduce CoverletCommandLineOptionDefinitions as the single source of truth for all command-line options, eliminating duplication and inconsistencies. Remove CoverletCommandLineOptionsProvider and update CoverletExtensionCommandLineProvider to use the centralized definitions and validation. Rename and clean up option constants in CoverletOptionNames. Update CoverageConfiguration and related logging for new source mapping file handling. Adjust tests and namespaces for consistency with new option names and structure.
1 parent 605a48e commit 71d8ecf

File tree

9 files changed

+87
-187
lines changed

9 files changed

+87
-187
lines changed

eng/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ steps:
4242
artifacts\bin\coverlet.MTP.unit.tests\debug\coverlet.MTP.unit.tests.exe --diagnostic --diagnostic-verbosity trace --report-xunit-trx --report-xunit-trx-filename "coverlet.MTP.unit.tests.trx" --diagnostic --diagnostic-output-directory "$(Build.SourcesDirectory)/artifacts/log/$(BuildConfiguration)" --diagnostic-file-prefix "coverlet.MTP.unit.tests_"
4343
artifacts\bin\coverlet.MTP.validation.tests\debug\coverlet.MTP.validation.tests.exe --diagnostic --diagnostic-verbosity trace --report-xunit-trx --report-xunit-trx-filename "coverlet.MTP.validation.tests.trx" --diagnostic --diagnostic-output-directory "$(Build.SourcesDirectory)/artifacts/log/$(BuildConfiguration)" --diagnostic-file-prefix "coverlet.MTP.validation.tests_"
4444
dotnet test test/coverlet.core.tests/coverlet.core.tests.csproj -c $(BuildConfiguration) --no-build -bl:test.core.binlog /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*%2c[coverlet.tests.projectsample]*" /p:ExcludeByAttribute="GeneratedCodeAttribute" --diag:"$(Build.SourcesDirectory)/artifacts/log/$(BuildConfiguration)/coverlet.core.tests.diag;tracelevel=verbose"
45-
dotnet test test/coverlet.core.coverage.tests/coverlet.core.coverage.tests.csproj -c $(BuildConfiguration) --no-build -bl:test.core.coverage.binlog /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*%2c[coverlet.tests.projectsample]*" /p:ExcludeByAttribute="GeneratedCodeAttribute" -- --results-directory "$(Build.SourcesDirectory))/artifacts/reports" --report-xunit-trx --report-xunit-trx-filename "coverlet.core.coverage.tests.trx" --diagnostic-verbosity trace --diagnostic --diagnostic-output-directory "$(Build.SourcesDirectory)/artifacts/log/$(BuildConfiguration)" --diagnostic-file-prefix "coverlet.core.coverage.tests_"
45+
dotnet test test/coverlet.core.coverage.tests/coverlet.core.coverage.tests.csproj -c $(BuildConfiguration) --no-build -bl:test.core.coverage.binlog /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*%2c[coverlet.tests.projectsample]*" /p:ExcludeByAttribute="GeneratedCodeAttribute" -- --results-directory "$(Build.SourcesDirectory))/artifacts/reports" --report-xunit-trx --report-xunit-trx-filename "coverlet.core.coverage.tests.trx" --diagnostic-verbosity trace --diagnostic --diagnostic-output-directory "$(Build.SourcesDirectory)/artifacts/log/$(BuildConfiguration)" --diagnostic-output-fileprefix "coverlet.core.coverage.tests_"
4646
dotnet test test/coverlet.msbuild.tasks.tests\coverlet.msbuild.tasks.tests.csproj -c $(BuildConfiguration) --no-build -bl:test.msbuild.tasks.binlog /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*%2c[coverlet.tests.projectsample]*" /p:ExcludeByAttribute="GeneratedCodeAttribute" --diag:"$(Build.SourcesDirectory)/artifacts/log/$(BuildConfiguration)/coverlet.msbuild.tasks.tests.diag;tracelevel=verbose"
4747
dotnet test test/coverlet.collector.tests/coverlet.collector.tests.csproj -c $(BuildConfiguration) --no-build -bl:test.collector.binlog /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[coverlet.core.tests.samples.netstandard]*%2c[coverlet.tests.projectsample]*" /p:ExcludeByAttribute="GeneratedCodeAttribute" --diag:"$(Build.SourcesDirectory)/artifacts/log/coverlet.collector.tests.diag.$(BuildConfiguration).log;tracelevel=verbose"
4848
dotnet test test/coverlet.integration.tests/coverlet.integration.tests.csproj -c $(BuildConfiguration) -f net8.0 --no-build -bl:test.integration.binlog --diag:"$(Build.SourcesDirectory)/artifacts/log/coverlet.integration.tests.diag.net8.0.$(BuildConfiguration).log;tracelevel=verbose"
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Copyright (c) Toni Solarin-Sodara
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using Microsoft.Testing.Platform.Extensions.CommandLine;
5+
6+
namespace Coverlet.MTP.CommandLine;
7+
8+
/// <summary>
9+
/// Centralized definitions for all Coverlet command line options.
10+
/// This ensures consistency and avoids duplication across providers.
11+
/// </summary>
12+
internal static class CoverletCommandLineOptionDefinitions
13+
{
14+
public static readonly string[] SupportedFormats = ["json", "lcov", "opencover", "cobertura", "teamcity"];
15+
16+
public static IReadOnlyCollection<CommandLineOption> GetAllOptions()
17+
{
18+
return
19+
[
20+
new CommandLineOption(CoverletOptionNames.Coverage, "Enable code coverage data collection.", ArgumentArity.Zero, isHidden: false),
21+
new CommandLineOption(CoverletOptionNames.Formats, "Output format(s) for coverage report (json, lcov, opencover, cobertura).", ArgumentArity.OneOrMore, isHidden: false),
22+
new CommandLineOption(CoverletOptionNames.Output, "Output path for coverage files.", ArgumentArity.ExactlyOne, isHidden: false),
23+
new CommandLineOption(CoverletOptionNames.Include, "Include assemblies matching filters (e.g., [Assembly]Type).", ArgumentArity.OneOrMore, isHidden: false),
24+
new CommandLineOption(CoverletOptionNames.IncludeDirectory, "Include additional directories for instrumentation.", ArgumentArity.OneOrMore, isHidden: false),
25+
new CommandLineOption(CoverletOptionNames.Exclude, "Exclude assemblies matching filters (e.g., [Assembly]Type).", ArgumentArity.OneOrMore, isHidden: false),
26+
new CommandLineOption(CoverletOptionNames.ExcludeByFile, "Exclude source files matching glob patterns.", ArgumentArity.OneOrMore, isHidden: false),
27+
new CommandLineOption(CoverletOptionNames.ExcludeByAttribute, "Exclude methods/classes decorated with attributes.", ArgumentArity.OneOrMore, isHidden: false),
28+
new CommandLineOption(CoverletOptionNames.IncludeTestAssembly, "Include test assembly in coverage.", ArgumentArity.Zero, isHidden: false),
29+
new CommandLineOption(CoverletOptionNames.SingleHit, "Limit the number of hits to one for each location.", ArgumentArity.Zero, isHidden: false),
30+
new CommandLineOption(CoverletOptionNames.SkipAutoProps, "Skip auto-implemented properties.", ArgumentArity.Zero, isHidden: false),
31+
new CommandLineOption(CoverletOptionNames.DoesNotReturnAttribute, "Attributes that mark methods as not returning.", ArgumentArity.ZeroOrMore, isHidden: false),
32+
new CommandLineOption(CoverletOptionNames.ExcludeAssembliesWithoutSources, "Exclude assemblies without source code.", ArgumentArity.ZeroOrOne, isHidden: false),
33+
new CommandLineOption(CoverletOptionNames.SourceMappingFile, "Output path for SourceRootsMappings file.", ArgumentArity.ZeroOrOne, isHidden: false)
34+
];
35+
}
36+
}

src/coverlet.MTP/CommandLine/CoverletCommandLineOptionsProvider.cs

Lines changed: 0 additions & 115 deletions
This file was deleted.

src/coverlet.MTP/CommandLine/CoverletOptionNames.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,5 @@ internal static class CoverletOptionNames
1818
public const string SkipAutoProps = "coverage-skip-auto-props";
1919
public const string DoesNotReturnAttribute = "coverage-does-not-return-attribute";
2020
public const string ExcludeAssembliesWithoutSources = "coverage-exclude-assemblies-without-sources";
21-
public const string SourceLink = "coverage-source-link";
22-
public const string SourceMappingFile = "source-mapping-file";
23-
public const string MergeWith = "coverage-merge-with";
21+
public const string SourceMappingFile = "coverage-source-mapping-file";
2422
}

src/coverlet.MTP/Configuration/CoverageConfiguration.cs

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,22 @@ public string[] GetOutputFormats()
5555
return defaultFormats;
5656
}
5757

58+
public string GetOutputSourceMappingDirectory()
59+
{
60+
if (_commandLineOptions.TryGetOptionArgumentList(
61+
CoverletOptionNames.SourceMappingFile,
62+
out string[]? outputPath))
63+
{
64+
LogOptionValue(CoverletOptionNames.SourceMappingFile, outputPath, isExplicit: true);
65+
return outputPath[0];
66+
}
67+
// Default: TestResults folder next to test assembly
68+
string testDir = Path.GetDirectoryName(GetTestAssemblyPath()) ?? AppContext.BaseDirectory;
69+
string defaultPath = Path.Combine(testDir, "TestResults");
70+
LogOptionValue(CoverletOptionNames.Output, new[] { defaultPath }, isExplicit: false);
71+
return defaultPath;
72+
}
73+
5874
public string GetOutputDirectory()
5975
{
6076
if (_commandLineOptions.TryGetOptionArgumentList(
@@ -168,22 +184,6 @@ public string[] GetDoesNotReturnAttributes()
168184
public bool ExcludeAssembliesWithoutSources =>
169185
GetBoolOptionWithDefault(CoverletOptionNames.ExcludeAssembliesWithoutSources, defaultValue: true);
170186

171-
public bool UseSourceLink =>
172-
_commandLineOptions.IsOptionSet(CoverletOptionNames.SourceLink);
173-
174-
public string? GetMergeWith()
175-
{
176-
if (_commandLineOptions.TryGetOptionArgumentList(
177-
CoverletOptionNames.MergeWith,
178-
out string[]? mergeWith))
179-
{
180-
LogOptionValue(CoverletOptionNames.MergeWith, mergeWith, isExplicit: true);
181-
return mergeWith[0];
182-
}
183-
184-
return null;
185-
}
186-
187187
/// <summary>
188188
/// Gets the test assembly path using multiple fallback strategies.
189189
/// </summary>
@@ -242,8 +242,7 @@ public void LogConfigurationSummary()
242242
_logger.LogInformation($"Include Test Assembly: {IncludeTestAssembly}");
243243
_logger.LogInformation($"Skip Auto Properties: {SkipAutoProps}");
244244
_logger.LogInformation($"Exclude Assemblies Without Sources: {ExcludeAssembliesWithoutSources}");
245-
_logger.LogInformation($"Use Source Link: {UseSourceLink}");
246-
_logger.LogInformation($"Merge With: {GetMergeWith() ?? "(none)"}");
245+
_logger.LogInformation($"Output directory for source mapping file: {GetOutputSourceMappingDirectory()}");
247246
_logger.LogInformation("========================================");
248247
}
249248

src/coverlet.MTP/CoverletExtensionCommandLineProvider.cs

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ namespace Coverlet.MTP.CommandLine;
88

99
internal sealed class CoverletExtensionCommandLineProvider : ICommandLineOptionsProvider
1010
{
11-
private static readonly string[] s_supportedFormats = ["json", "lcov", "opencover", "cobertura", "teamcity"];
12-
1311
private readonly IExtension _extension;
1412

1513
public CoverletExtensionCommandLineProvider(IExtension extension)
@@ -25,24 +23,7 @@ public CoverletExtensionCommandLineProvider(IExtension extension)
2523
public Task<bool> IsEnabledAsync() => Task.FromResult(true);
2624

2725
public IReadOnlyCollection<CommandLineOption> GetCommandLineOptions()
28-
{
29-
return
30-
[
31-
new CommandLineOption(CoverletOptionNames.Coverage, "Enable code coverage collection.", ArgumentArity.Zero, isHidden: false),
32-
new CommandLineOption(CoverletOptionNames.Formats, "Specifies the output formats for the coverage report (e.g., 'json', 'lcov').", ArgumentArity.OneOrMore, isHidden: false),
33-
new CommandLineOption(CoverletOptionNames.Exclude, "Filter expressions to exclude specific modules and types.", ArgumentArity.OneOrMore, isHidden: false),
34-
new CommandLineOption(CoverletOptionNames.Include, "Filter expressions to include only specific modules and type", ArgumentArity.OneOrMore, isHidden: false),
35-
new CommandLineOption(CoverletOptionNames.ExcludeByFile, "Glob patterns specifying source files to exclude.", ArgumentArity.OneOrMore, isHidden: false),
36-
new CommandLineOption(CoverletOptionNames.IncludeDirectory, "Include directories containing additional assemblies to be instrumented.", ArgumentArity.OneOrMore, isHidden: false),
37-
new CommandLineOption(CoverletOptionNames.ExcludeByAttribute, "Attributes to exclude from code coverage.", ArgumentArity.OneOrMore, isHidden: false),
38-
new CommandLineOption(CoverletOptionNames.IncludeTestAssembly, "Specifies whether to report code coverage of the test assembly.", ArgumentArity.Zero, isHidden: false),
39-
new CommandLineOption(CoverletOptionNames.SingleHit, "Specifies whether to limit code coverage hit reporting to a single hit for each location", ArgumentArity.Zero, isHidden: false),
40-
new CommandLineOption(CoverletOptionNames.SkipAutoProps, "Neither track nor record auto-implemented properties.", ArgumentArity.Zero, isHidden: false),
41-
new CommandLineOption(CoverletOptionNames.DoesNotReturnAttribute, "Attributes that mark methods that do not return", ArgumentArity.ZeroOrMore, isHidden: false),
42-
new CommandLineOption(CoverletOptionNames.ExcludeAssembliesWithoutSources, "Specifies behavior of heuristic to ignore assemblies with missing source documents.", ArgumentArity.ZeroOrOne, isHidden: false),
43-
//new CommandLineOption(CoverletOptionNames.SourceMappingFile, "Specifies the path to a SourceRootsMappings file.", ArgumentArity.ZeroOrOne, isHidden: false)
44-
];
45-
}
26+
=> CoverletCommandLineOptionDefinitions.GetAllOptions();
4627

4728
public Task<ValidationResult> ValidateOptionArgumentsAsync(CommandLineOption commandOption, string[] arguments)
4829
{
@@ -55,8 +36,7 @@ public Task<ValidationResult> ValidateOptionArgumentsAsync(CommandLineOption com
5536

5637
foreach (string format in arguments)
5738
{
58-
// does not support string with multiple formats e.g. "json,lcov"
59-
if (!s_supportedFormats.Contains(format))
39+
if (!CoverletCommandLineOptionDefinitions.SupportedFormats.Contains(format))
6040
{
6141
return Task.FromResult(ValidationResult.Invalid($"The value '{format}' is not a valid option for '{commandOption.Name}'."));
6242
}

test/coverlet.MTP.validation.tests/CollectCoverageTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
using System.Xml.Linq;
77
using Xunit;
88

9-
namespace coverlet.MTP.validation.tests;
9+
namespace Coverlet.MTP.validation.tests;
1010

1111
/// <summary>
1212
/// Integration tests for Coverlet Microsoft Testing Platform extension.

0 commit comments

Comments
 (0)