Skip to content

Add skipautoprops feature #912

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Documentation/GlobalTool.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ Options:
--single-hit Specifies whether to limit code coverage hit reporting to a single hit for each location.
--merge-with Path to existing coverage result to merge.
--use-source-link Specifies whether to use SourceLink URIs in place of file system paths.
--skipautoprops Neither track nor record auto-implemented properties.
```

NB. For a [multiple value] options you have to specify values multiple times i.e.
Expand Down
5 changes: 5 additions & 0 deletions Documentation/MSBuildIntegration.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,11 @@ Both `Exclude` and `Include` properties can be used together but `Exclude` takes

You can also include coverage of the test assembly itself by setting `/p:IncludeTestAssembly` to `true`.

### Skip auto-implemented properties

Neither track nor record auto-implemented properties.
Syntax: `/p:SkipAutoProps=true`

### Note for Powershell / VSTS users
To exclude or include multiple assemblies when using Powershell scripts or creating a .yaml file for a VSTS build ```%2c``` should be used as a separator. Msbuild will translate this symbol to ```,```.

Expand Down
2 changes: 2 additions & 0 deletions Documentation/VSTestIntegration.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ These are a list of options that are supported by coverlet. These can be specifi
|SingleHit | Specifies whether to limit code coverage hit reporting to a single hit for each location.|
|UseSourceLink | Specifies whether to use SourceLink URIs in place of file system paths. |
|IncludeTestAssembly | Include coverage of the test assembly. |
|SkipAutoProps | Neither track nor record auto-implemented properties. |

How to specify these options via runsettings?
```
Expand All @@ -97,6 +98,7 @@ How to specify these options via runsettings?
<SingleHit>false</SingleHit>
<UseSourceLink>true</UseSourceLink>
<IncludeTestAssembly>true</IncludeTestAssembly>
<SkipAutoProps>true</SkipAutoProps>
</Configuration>
</DataCollector>
</DataCollectors>
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,10 @@ to clarify expected behavior in our community.

For more information, see the [.NET Foundation Code of Conduct](https://dotnetfoundation.org/code-of-conduct).

## Credits

Part of the code is based on work done by OpenCover team https://github.com/OpenCover

## License

This project is licensed under the MIT license. See the [LICENSE](LICENSE) file for more info.
Expand Down
3 changes: 2 additions & 1 deletion src/coverlet.collector/DataCollection/CoverageWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ public Coverage CreateCoverage(CoverletSettings settings, ILogger coverletLogger
IncludeTestAssembly = settings.IncludeTestAssembly,
SingleHit = settings.SingleHit,
MergeWith = settings.MergeWith,
UseSourceLink = settings.UseSourceLink
UseSourceLink = settings.UseSourceLink,
SkipAutoProps = settings.SkipAutoProps
};

return new Coverage(
Expand Down
26 changes: 16 additions & 10 deletions src/coverlet.collector/DataCollection/CoverletSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,20 +63,26 @@ internal class CoverletSettings
/// </summary>
public bool IncludeTestAssembly { get; set; }

/// <summary>
/// Neither track nor record auto-implemented properties.
/// </summary>
public bool SkipAutoProps { get; set; }

public override string ToString()
{
var builder = new StringBuilder();

builder.AppendFormat("TestModule: '{0}', ", this.TestModule);
builder.AppendFormat("IncludeFilters: '{0}', ", string.Join(",", this.IncludeFilters ?? Enumerable.Empty<string>()));
builder.AppendFormat("IncludeDirectories: '{0}', ", string.Join(",", this.IncludeDirectories ?? Enumerable.Empty<string>()));
builder.AppendFormat("ExcludeFilters: '{0}', ", string.Join(",", this.ExcludeFilters ?? Enumerable.Empty<string>()));
builder.AppendFormat("ExcludeSourceFiles: '{0}', ", string.Join(",", this.ExcludeSourceFiles ?? Enumerable.Empty<string>()));
builder.AppendFormat("ExcludeAttributes: '{0}', ", string.Join(",", this.ExcludeAttributes ?? Enumerable.Empty<string>()));
builder.AppendFormat("MergeWith: '{0}', ", this.MergeWith);
builder.AppendFormat("UseSourceLink: '{0}'", this.UseSourceLink);
builder.AppendFormat("SingleHit: '{0}'", this.SingleHit);
builder.AppendFormat("IncludeTestAssembly: '{0}'", this.IncludeTestAssembly);
builder.AppendFormat("TestModule: '{0}', ", TestModule);
builder.AppendFormat("IncludeFilters: '{0}', ", string.Join(",", IncludeFilters ?? Enumerable.Empty<string>()));
builder.AppendFormat("IncludeDirectories: '{0}', ", string.Join(",", IncludeDirectories ?? Enumerable.Empty<string>()));
builder.AppendFormat("ExcludeFilters: '{0}', ", string.Join(",", ExcludeFilters ?? Enumerable.Empty<string>()));
builder.AppendFormat("ExcludeSourceFiles: '{0}', ", string.Join(",", ExcludeSourceFiles ?? Enumerable.Empty<string>()));
builder.AppendFormat("ExcludeAttributes: '{0}', ", string.Join(",", ExcludeAttributes ?? Enumerable.Empty<string>()));
builder.AppendFormat("MergeWith: '{0}', ", MergeWith);
builder.AppendFormat("UseSourceLink: '{0}'", UseSourceLink);
builder.AppendFormat("SingleHit: '{0}'", SingleHit);
builder.AppendFormat("IncludeTestAssembly: '{0}'", IncludeTestAssembly);
builder.AppendFormat("SkipAutoProps: '{0}'", SkipAutoProps);

return builder.ToString();
}
Expand Down
35 changes: 24 additions & 11 deletions src/coverlet.collector/DataCollection/CoverletSettingsParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,23 +29,24 @@ public CoverletSettings Parse(XmlElement configurationElement, IEnumerable<strin
{
var coverletSettings = new CoverletSettings
{
TestModule = this.ParseTestModule(testModules)
TestModule = ParseTestModule(testModules)
};

if (configurationElement != null)
{
coverletSettings.IncludeFilters = this.ParseIncludeFilters(configurationElement);
coverletSettings.IncludeDirectories = this.ParseIncludeDirectories(configurationElement);
coverletSettings.ExcludeAttributes = this.ParseExcludeAttributes(configurationElement);
coverletSettings.ExcludeSourceFiles = this.ParseExcludeSourceFiles(configurationElement);
coverletSettings.MergeWith = this.ParseMergeWith(configurationElement);
coverletSettings.UseSourceLink = this.ParseUseSourceLink(configurationElement);
coverletSettings.SingleHit = this.ParseSingleHit(configurationElement);
coverletSettings.IncludeTestAssembly = this.ParseIncludeTestAssembly(configurationElement);
coverletSettings.IncludeFilters = ParseIncludeFilters(configurationElement);
coverletSettings.IncludeDirectories = ParseIncludeDirectories(configurationElement);
coverletSettings.ExcludeAttributes = ParseExcludeAttributes(configurationElement);
coverletSettings.ExcludeSourceFiles = ParseExcludeSourceFiles(configurationElement);
coverletSettings.MergeWith = ParseMergeWith(configurationElement);
coverletSettings.UseSourceLink = ParseUseSourceLink(configurationElement);
coverletSettings.SingleHit = ParseSingleHit(configurationElement);
coverletSettings.IncludeTestAssembly = ParseIncludeTestAssembly(configurationElement);
coverletSettings.SkipAutoProps = ParseSkipAutoProps(configurationElement);
}

coverletSettings.ReportFormats = this.ParseReportFormats(configurationElement);
coverletSettings.ExcludeFilters = this.ParseExcludeFilters(configurationElement);
coverletSettings.ReportFormats = ParseReportFormats(configurationElement);
coverletSettings.ExcludeFilters = ParseExcludeFilters(configurationElement);

if (_eqtTrace.IsVerboseEnabled)
{
Expand Down Expand Up @@ -205,6 +206,18 @@ private bool ParseIncludeTestAssembly(XmlElement configurationElement)
return includeTestAssembly;
}

/// <summary>
/// Parse skipautoprops flag
/// </summary>
/// <param name="configurationElement">Configuration element</param>
/// <returns>Include Test Assembly Flag</returns>
private bool ParseSkipAutoProps(XmlElement configurationElement)
{
XmlElement skipAutoPropsElement = configurationElement[CoverletConstants.SkipAutoProps];
bool.TryParse(skipAutoPropsElement?.InnerText, out bool skipAutoProps);
return skipAutoProps;
}

/// <summary>
/// Splits a comma separated elements into an array
/// </summary>
Expand Down
1 change: 1 addition & 0 deletions src/coverlet.collector/Utilities/CoverletConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@ internal static class CoverletConstants
public const string ReportFormatElementName = "Format";
public const string DefaultExcludeFilter = "[coverlet.*]*";
public const string InProcDataCollectorName = "CoverletInProcDataCollector";
public const string SkipAutoProps = "SkipAutoProps";
}
}
6 changes: 4 additions & 2 deletions src/coverlet.console/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ static int Main(string[] args)
CommandOption excludeAttributes = app.Option("--exclude-by-attribute", "Attributes to exclude from code coverage.", CommandOptionType.MultipleValue);
CommandOption includeTestAssembly = app.Option("--include-test-assembly", "Specifies whether to report code coverage of the test assembly.", CommandOptionType.NoValue);
CommandOption singleHit = app.Option("--single-hit", "Specifies whether to limit code coverage hit reporting to a single hit for each location", CommandOptionType.NoValue);
CommandOption skipAutoProp = app.Option("--skipautoprops", "Neither track nor record auto-implemented properties.", CommandOptionType.NoValue);
CommandOption mergeWith = app.Option("--merge-with", "Path to existing coverage result to merge.", CommandOptionType.SingleValue);
CommandOption useSourceLink = app.Option("--use-source-link", "Specifies whether to use SourceLink URIs in place of file system paths.", CommandOptionType.NoValue);

Expand Down Expand Up @@ -87,7 +88,8 @@ static int Main(string[] args)
IncludeTestAssembly = includeTestAssembly.HasValue(),
SingleHit = singleHit.HasValue(),
MergeWith = mergeWith.Value(),
UseSourceLink = useSourceLink.HasValue()
UseSourceLink = useSourceLink.HasValue(),
SkipAutoProps = skipAutoProp.HasValue()
};

Coverage coverage = new Coverage(module.Value,
Expand All @@ -97,7 +99,7 @@ static int Main(string[] args)
fileSystem,
serviceProvider.GetRequiredService<ISourceRootTranslator>(),
serviceProvider.GetRequiredService<ICecilSymbolHelper>());
coverage.PrepareModules();
coverage.PrepareModules();

Process process = new Process();
process.StartInfo.FileName = target.Value();
Expand Down
17 changes: 16 additions & 1 deletion src/coverlet.core/Coverage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ internal class CoverageParameters
public bool SingleHit { get; set; }
public string MergeWith { get; set; }
public bool UseSourceLink { get; set; }
public bool SkipAutoProps { get; set; }
}

internal class Coverage
Expand All @@ -38,6 +39,7 @@ internal class Coverage
private bool _singleHit;
private string _mergeWith;
private bool _useSourceLink;
private bool _skipAutoProps;
private ILogger _logger;
private IInstrumentationHelper _instrumentationHelper;
private IFileSystem _fileSystem;
Expand Down Expand Up @@ -73,6 +75,7 @@ public Coverage(string module,
_fileSystem = fileSystem;
_sourceRootTranslator = sourceRootTranslator;
_cecilSymbolHelper = cecilSymbolHelper;
_skipAutoProps = parameters.SkipAutoProps;

_identifier = Guid.NewGuid().ToString();
_results = new List<InstrumenterResult>();
Expand Down Expand Up @@ -115,7 +118,19 @@ public CoveragePrepareResult PrepareModules()
continue;
}

var instrumenter = new Instrumenter(module, _identifier, _excludeFilters, _includeFilters, _excludedSourceFiles, _excludeAttributes, _singleHit, _logger, _instrumentationHelper, _fileSystem, _sourceRootTranslator, _cecilSymbolHelper);
var instrumenter = new Instrumenter(module,
_identifier,
_excludeFilters,
_includeFilters,
_excludedSourceFiles,
_excludeAttributes,
_singleHit,
_skipAutoProps,
_logger,
_instrumentationHelper,
_fileSystem,
_sourceRootTranslator,
_cecilSymbolHelper);

if (instrumenter.CanInstrument())
{
Expand Down
8 changes: 8 additions & 0 deletions src/coverlet.core/Instrumentation/Instrumenter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ internal class Instrumenter
private readonly ExcludedFilesHelper _excludedFilesHelper;
private readonly string[] _excludedAttributes;
private readonly bool _singleHit;
private readonly bool _skipAutoProps;
private readonly bool _isCoreLibrary;
private readonly ILogger _logger;
private readonly IInstrumentationHelper _instrumentationHelper;
Expand Down Expand Up @@ -55,6 +56,7 @@ public Instrumenter(
string[] excludedFiles,
string[] excludedAttributes,
bool singleHit,
bool skipAutoProps,
ILogger logger,
IInstrumentationHelper instrumentationHelper,
IFileSystem fileSystem,
Expand Down Expand Up @@ -84,6 +86,7 @@ public Instrumenter(
_fileSystem = fileSystem;
_sourceRootTranslator = sourceRootTranslator;
_cecilSymbolHelper = cecilSymbolHelper;
_skipAutoProps = skipAutoProps;
}

public bool CanInstrument()
Expand Down Expand Up @@ -432,6 +435,11 @@ private void InstrumentType(TypeDefinition type)

if (actualMethod.IsGetter || actualMethod.IsSetter)
{
if (_skipAutoProps && actualMethod.CustomAttributes.Any(ca => ca.AttributeType.FullName == typeof(CompilerGeneratedAttribute).FullName))
{
continue;
}

PropertyDefinition prop = type.Properties.FirstOrDefault(p => (p.GetMethod ?? p.SetMethod).FullName.Equals(actualMethod.FullName));
if (prop?.HasCustomAttributes == true)
customAttributes = customAttributes.Union(prop.CustomAttributes);
Expand Down
Loading