diff --git a/Documentation/GlobalTool.md b/Documentation/GlobalTool.md index 01ff23b94..bb76dc9e5 100644 --- a/Documentation/GlobalTool.md +++ b/Documentation/GlobalTool.md @@ -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. diff --git a/Documentation/MSBuildIntegration.md b/Documentation/MSBuildIntegration.md index 0ef0c22f6..4b0032a9e 100644 --- a/Documentation/MSBuildIntegration.md +++ b/Documentation/MSBuildIntegration.md @@ -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 ```,```. diff --git a/Documentation/VSTestIntegration.md b/Documentation/VSTestIntegration.md index 0b5831336..6b35e976e 100644 --- a/Documentation/VSTestIntegration.md +++ b/Documentation/VSTestIntegration.md @@ -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? ``` @@ -97,6 +98,7 @@ How to specify these options via runsettings? false true true + true diff --git a/README.md b/README.md index 42e154614..6cbe84631 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/src/coverlet.collector/DataCollection/CoverageWrapper.cs b/src/coverlet.collector/DataCollection/CoverageWrapper.cs index e65a918d6..d99e3bd8d 100644 --- a/src/coverlet.collector/DataCollection/CoverageWrapper.cs +++ b/src/coverlet.collector/DataCollection/CoverageWrapper.cs @@ -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( diff --git a/src/coverlet.collector/DataCollection/CoverletSettings.cs b/src/coverlet.collector/DataCollection/CoverletSettings.cs index 825cbfe36..eaa1afbb6 100644 --- a/src/coverlet.collector/DataCollection/CoverletSettings.cs +++ b/src/coverlet.collector/DataCollection/CoverletSettings.cs @@ -63,20 +63,26 @@ internal class CoverletSettings /// public bool IncludeTestAssembly { get; set; } + /// + /// Neither track nor record auto-implemented properties. + /// + 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())); - builder.AppendFormat("IncludeDirectories: '{0}', ", string.Join(",", this.IncludeDirectories ?? Enumerable.Empty())); - builder.AppendFormat("ExcludeFilters: '{0}', ", string.Join(",", this.ExcludeFilters ?? Enumerable.Empty())); - builder.AppendFormat("ExcludeSourceFiles: '{0}', ", string.Join(",", this.ExcludeSourceFiles ?? Enumerable.Empty())); - builder.AppendFormat("ExcludeAttributes: '{0}', ", string.Join(",", this.ExcludeAttributes ?? Enumerable.Empty())); - 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())); + builder.AppendFormat("IncludeDirectories: '{0}', ", string.Join(",", IncludeDirectories ?? Enumerable.Empty())); + builder.AppendFormat("ExcludeFilters: '{0}', ", string.Join(",", ExcludeFilters ?? Enumerable.Empty())); + builder.AppendFormat("ExcludeSourceFiles: '{0}', ", string.Join(",", ExcludeSourceFiles ?? Enumerable.Empty())); + builder.AppendFormat("ExcludeAttributes: '{0}', ", string.Join(",", ExcludeAttributes ?? Enumerable.Empty())); + 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(); } diff --git a/src/coverlet.collector/DataCollection/CoverletSettingsParser.cs b/src/coverlet.collector/DataCollection/CoverletSettingsParser.cs index cbaaca3d1..ce37c237c 100644 --- a/src/coverlet.collector/DataCollection/CoverletSettingsParser.cs +++ b/src/coverlet.collector/DataCollection/CoverletSettingsParser.cs @@ -29,23 +29,24 @@ public CoverletSettings Parse(XmlElement configurationElement, IEnumerable + /// Parse skipautoprops flag + /// + /// Configuration element + /// Include Test Assembly Flag + private bool ParseSkipAutoProps(XmlElement configurationElement) + { + XmlElement skipAutoPropsElement = configurationElement[CoverletConstants.SkipAutoProps]; + bool.TryParse(skipAutoPropsElement?.InnerText, out bool skipAutoProps); + return skipAutoProps; + } + /// /// Splits a comma separated elements into an array /// diff --git a/src/coverlet.collector/Utilities/CoverletConstants.cs b/src/coverlet.collector/Utilities/CoverletConstants.cs index d3e6469af..c89846a59 100644 --- a/src/coverlet.collector/Utilities/CoverletConstants.cs +++ b/src/coverlet.collector/Utilities/CoverletConstants.cs @@ -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"; } } diff --git a/src/coverlet.console/Program.cs b/src/coverlet.console/Program.cs index 16cc7fa44..0099b4db0 100644 --- a/src/coverlet.console/Program.cs +++ b/src/coverlet.console/Program.cs @@ -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); @@ -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, @@ -97,7 +99,7 @@ static int Main(string[] args) fileSystem, serviceProvider.GetRequiredService(), serviceProvider.GetRequiredService()); - coverage.PrepareModules(); + coverage.PrepareModules(); Process process = new Process(); process.StartInfo.FileName = target.Value(); diff --git a/src/coverlet.core/Coverage.cs b/src/coverlet.core/Coverage.cs index c19d007ce..7d6c6695c 100644 --- a/src/coverlet.core/Coverage.cs +++ b/src/coverlet.core/Coverage.cs @@ -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 @@ -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; @@ -73,6 +75,7 @@ public Coverage(string module, _fileSystem = fileSystem; _sourceRootTranslator = sourceRootTranslator; _cecilSymbolHelper = cecilSymbolHelper; + _skipAutoProps = parameters.SkipAutoProps; _identifier = Guid.NewGuid().ToString(); _results = new List(); @@ -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()) { diff --git a/src/coverlet.core/Instrumentation/Instrumenter.cs b/src/coverlet.core/Instrumentation/Instrumenter.cs index 23b8f3a26..6f99eabce 100644 --- a/src/coverlet.core/Instrumentation/Instrumenter.cs +++ b/src/coverlet.core/Instrumentation/Instrumenter.cs @@ -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; @@ -55,6 +56,7 @@ public Instrumenter( string[] excludedFiles, string[] excludedAttributes, bool singleHit, + bool skipAutoProps, ILogger logger, IInstrumentationHelper instrumentationHelper, IFileSystem fileSystem, @@ -84,6 +86,7 @@ public Instrumenter( _fileSystem = fileSystem; _sourceRootTranslator = sourceRootTranslator; _cecilSymbolHelper = cecilSymbolHelper; + _skipAutoProps = skipAutoProps; } public bool CanInstrument() @@ -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); diff --git a/src/coverlet.msbuild.tasks/CoverageResultTask.cs b/src/coverlet.msbuild.tasks/CoverageResultTask.cs index 12a807ea5..704576f88 100644 --- a/src/coverlet.msbuild.tasks/CoverageResultTask.cs +++ b/src/coverlet.msbuild.tasks/CoverageResultTask.cs @@ -14,62 +14,27 @@ namespace Coverlet.MSbuild.Tasks { public class CoverageResultTask : BaseTask { - private string _output; - private string _format; - private double _threshold; - private string _thresholdType; - private string _thresholdStat; - private string _coverletMultiTargetFrameworksCurrentTFM; - private ITaskItem _instrumenterState; private MSBuildLogger _logger; [Required] - public string Output - { - get { return _output; } - set { _output = value; } - } + public string Output { get; set; } [Required] - public string OutputFormat - { - get { return _format; } - set { _format = value; } - } + public string OutputFormat { get; set; } [Required] - public double Threshold - { - get { return _threshold; } - set { _threshold = value; } - } + public double Threshold { get; set; } [Required] - public string ThresholdType - { - get { return _thresholdType; } - set { _thresholdType = value; } - } + public string ThresholdType { get; set; } [Required] - public string ThresholdStat - { - get { return _thresholdStat; } - set { _thresholdStat = value; } - } + public string ThresholdStat { get; set; } [Required] - public ITaskItem InstrumenterState - { - get { return _instrumenterState; } - set { _instrumenterState = value; } - } + public ITaskItem InstrumenterState { get; set; } - public string CoverletMultiTargetFrameworksCurrentTFM - { - get { return _coverletMultiTargetFrameworksCurrentTFM; } - set { _coverletMultiTargetFrameworksCurrentTFM = value; } - } + public string CoverletMultiTargetFrameworksCurrentTFM { get; set; } public CoverageResultTask() { @@ -111,7 +76,7 @@ public override bool Execute() CoverageResult result = coverage.GetCoverageResult(); - var directory = Path.GetDirectoryName(_output); + var directory = Path.GetDirectoryName(Output); if (directory == string.Empty) { directory = Directory.GetCurrentDirectory(); @@ -121,7 +86,7 @@ public override bool Execute() Directory.CreateDirectory(directory); } - var formats = _format.Split(','); + var formats = OutputFormat.Split(','); foreach (var format in formats) { var reporter = new ReporterFactory(format).CreateReporter(); @@ -138,9 +103,9 @@ public override bool Execute() } else { - ReportWriter writer = new ReportWriter(_coverletMultiTargetFrameworksCurrentTFM, + ReportWriter writer = new ReportWriter(CoverletMultiTargetFrameworksCurrentTFM, directory, - _output, + Output, reporter, fileSystem, ServiceProvider.GetService(), @@ -152,7 +117,7 @@ public override bool Execute() var thresholdTypeFlags = ThresholdTypeFlags.None; var thresholdStat = ThresholdStatistic.Minimum; - foreach (var thresholdType in _thresholdType.Split(',').Select(t => t.Trim())) + foreach (var thresholdType in ThresholdType.Split(',').Select(t => t.Trim())) { if (thresholdType.Equals("line", StringComparison.OrdinalIgnoreCase)) { @@ -168,11 +133,11 @@ public override bool Execute() } } - if (_thresholdStat.Equals("average", StringComparison.OrdinalIgnoreCase)) + if (ThresholdStat.Equals("average", StringComparison.OrdinalIgnoreCase)) { thresholdStat = ThresholdStatistic.Average; } - else if (_thresholdStat.Equals("total", StringComparison.OrdinalIgnoreCase)) + else if (ThresholdStat.Equals("total", StringComparison.OrdinalIgnoreCase)) { thresholdStat = ThresholdStatistic.Total; } @@ -214,23 +179,23 @@ public override bool Execute() Console.WriteLine(coverageTable.ToStringAlternative()); - thresholdTypeFlags = result.GetThresholdTypesBelowThreshold(summary, _threshold, thresholdTypeFlags, thresholdStat); + thresholdTypeFlags = result.GetThresholdTypesBelowThreshold(summary, Threshold, thresholdTypeFlags, thresholdStat); if (thresholdTypeFlags != ThresholdTypeFlags.None) { var exceptionMessageBuilder = new StringBuilder(); if ((thresholdTypeFlags & ThresholdTypeFlags.Line) != ThresholdTypeFlags.None) { - exceptionMessageBuilder.AppendLine($"The {thresholdStat.ToString().ToLower()} line coverage is below the specified {_threshold}"); + exceptionMessageBuilder.AppendLine($"The {thresholdStat.ToString().ToLower()} line coverage is below the specified {Threshold}"); } if ((thresholdTypeFlags & ThresholdTypeFlags.Branch) != ThresholdTypeFlags.None) { - exceptionMessageBuilder.AppendLine($"The {thresholdStat.ToString().ToLower()} branch coverage is below the specified {_threshold}"); + exceptionMessageBuilder.AppendLine($"The {thresholdStat.ToString().ToLower()} branch coverage is below the specified {Threshold}"); } if ((thresholdTypeFlags & ThresholdTypeFlags.Method) != ThresholdTypeFlags.None) { - exceptionMessageBuilder.AppendLine($"The {thresholdStat.ToString().ToLower()} method coverage is below the specified {_threshold}"); + exceptionMessageBuilder.AppendLine($"The {thresholdStat.ToString().ToLower()} method coverage is below the specified {Threshold}"); } throw new Exception(exceptionMessageBuilder.ToString()); diff --git a/src/coverlet.msbuild.tasks/InstrumentationTask.cs b/src/coverlet.msbuild.tasks/InstrumentationTask.cs index 98b35bce2..cb2a34784 100644 --- a/src/coverlet.msbuild.tasks/InstrumentationTask.cs +++ b/src/coverlet.msbuild.tasks/InstrumentationTask.cs @@ -15,86 +15,33 @@ namespace Coverlet.MSbuild.Tasks { public class InstrumentationTask : BaseTask { - private string _path; - private string _include; - private string _includeDirectory; - private string _exclude; - private string _excludeByFile; - private string _excludeByAttribute; - private bool _includeTestAssembly; - private bool _singleHit; - private string _mergeWith; - private bool _useSourceLink; - private ITaskItem _instrumenterState; private readonly MSBuildLogger _logger; [Required] - public string Path - { - get { return _path; } - set { _path = value; } - } + public string Path { get; set; } - public string Include - { - get { return _include; } - set { _include = value; } - } + public string Include { get; set; } - public string IncludeDirectory - { - get { return _includeDirectory; } - set { _includeDirectory = value; } - } + public string IncludeDirectory { get; set; } - public string Exclude - { - get { return _exclude; } - set { _exclude = value; } - } + public string Exclude { get; set; } - public string ExcludeByFile - { - get { return _excludeByFile; } - set { _excludeByFile = value; } - } + public string ExcludeByFile { get; set; } - public string ExcludeByAttribute - { - get { return _excludeByAttribute; } - set { _excludeByAttribute = value; } - } + public string ExcludeByAttribute { get; set; } - public bool IncludeTestAssembly - { - get { return _includeTestAssembly; } - set { _includeTestAssembly = value; } - } + public bool IncludeTestAssembly { get; set; } - public bool SingleHit - { - get { return _singleHit; } - set { _singleHit = value; } - } + public bool SingleHit { get; set; } - public string MergeWith - { - get { return _mergeWith; } - set { _mergeWith = value; } - } + public string MergeWith { get; set; } - public bool UseSourceLink - { - get { return _useSourceLink; } - set { _useSourceLink = value; } - } + public bool UseSourceLink { get; set; } + + public bool SkipAutoProps { get; set; } [Output] - public ITaskItem InstrumenterState - { - get { return _instrumenterState; } - set { _instrumenterState = value; } - } + public ITaskItem InstrumenterState { get; set; } public InstrumentationTask() { @@ -129,7 +76,7 @@ public override bool Execute() serviceCollection.AddTransient(_ => _logger); serviceCollection.AddTransient(); // We cache resolutions - serviceCollection.AddSingleton(serviceProvider => new SourceRootTranslator(_path, serviceProvider.GetRequiredService(), serviceProvider.GetRequiredService())); + serviceCollection.AddSingleton(serviceProvider => new SourceRootTranslator(Path, serviceProvider.GetRequiredService(), serviceProvider.GetRequiredService())); // We need to keep singleton/static semantics serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); @@ -142,18 +89,19 @@ public override bool Execute() CoverageParameters parameters = new CoverageParameters { - IncludeFilters = _include?.Split(','), - IncludeDirectories = _includeDirectory?.Split(','), - ExcludeFilters = _exclude?.Split(','), - ExcludedSourceFiles = _excludeByFile?.Split(','), - ExcludeAttributes = _excludeByAttribute?.Split(','), - IncludeTestAssembly = _includeTestAssembly, - SingleHit = _singleHit, - MergeWith = _mergeWith, - UseSourceLink = _useSourceLink + IncludeFilters = Include?.Split(','), + IncludeDirectories = IncludeDirectory?.Split(','), + ExcludeFilters = Exclude?.Split(','), + ExcludedSourceFiles = ExcludeByFile?.Split(','), + ExcludeAttributes = ExcludeByAttribute?.Split(','), + IncludeTestAssembly = IncludeTestAssembly, + SingleHit = SingleHit, + MergeWith = MergeWith, + UseSourceLink = UseSourceLink, + SkipAutoProps = SkipAutoProps }; - Coverage coverage = new Coverage(_path, + Coverage coverage = new Coverage(Path, parameters, _logger, ServiceProvider.GetService(), diff --git a/src/coverlet.msbuild.tasks/coverlet.msbuild.targets b/src/coverlet.msbuild.tasks/coverlet.msbuild.targets index 4f3d4ee15..fefd1cbdb 100644 --- a/src/coverlet.msbuild.tasks/coverlet.msbuild.targets +++ b/src/coverlet.msbuild.tasks/coverlet.msbuild.targets @@ -5,7 +5,7 @@ + UseSourceLink="$(UseSourceLink)" + SkipAutoProps="$(SkipAutoProps)" > diff --git a/test/coverlet.collector.tests/CoverletSettingsParserTests.cs b/test/coverlet.collector.tests/CoverletSettingsParserTests.cs index 40d0ec112..dd56a6572 100644 --- a/test/coverlet.collector.tests/CoverletSettingsParserTests.cs +++ b/test/coverlet.collector.tests/CoverletSettingsParserTests.cs @@ -73,6 +73,7 @@ public void ParseShouldCorrectlyParseConfigurationElement(string includeFilters, this.CreateCoverletNodes(doc, configElement, CoverletConstants.UseSourceLinkElementName, "false"); this.CreateCoverletNodes(doc, configElement, CoverletConstants.SingleHitElementName, "true"); this.CreateCoverletNodes(doc, configElement, CoverletConstants.IncludeTestAssemblyElementName, "true"); + this.CreateCoverletNodes(doc, configElement, CoverletConstants.SkipAutoProps, "true"); CoverletSettings coverletSettings = _coverletSettingsParser.Parse(configElement, testModules); @@ -90,10 +91,11 @@ public void ParseShouldCorrectlyParseConfigurationElement(string includeFilters, Assert.Equal("[coverlet.*]*", coverletSettings.ExcludeFilters[0]); Assert.Equal("[coverlet.*.tests?]*", coverletSettings.ExcludeFilters[1]); Assert.Equal("[coverlet.*.tests.*]*", coverletSettings.ExcludeFilters[2]); - + Assert.False(coverletSettings.UseSourceLink); Assert.True(coverletSettings.SingleHit); Assert.True(coverletSettings.IncludeTestAssembly); + Assert.True(coverletSettings.SkipAutoProps); } [Fact] @@ -104,7 +106,7 @@ public void ParseShouldCorrectlyParseConfigurationElementWithNullInnerText() var configElement = doc.CreateElement("Configuration"); this.CreateCoverleteNullInnerTextNodes(doc, configElement, CoverletConstants.IncludeFiltersElementName); this.CreateCoverleteNullInnerTextNodes(doc, configElement, CoverletConstants.ExcludeFiltersElementName); - this.CreateCoverleteNullInnerTextNodes(doc, configElement, CoverletConstants.IncludeDirectoriesElementName); + this.CreateCoverleteNullInnerTextNodes(doc, configElement, CoverletConstants.IncludeDirectoriesElementName); this.CreateCoverleteNullInnerTextNodes(doc, configElement, CoverletConstants.ExcludeSourceFilesElementName); this.CreateCoverleteNullInnerTextNodes(doc, configElement, CoverletConstants.ExcludeAttributesElementName); diff --git a/test/coverlet.core.tests/Coverage/CoverageTests.AutoProps.cs b/test/coverlet.core.tests/Coverage/CoverageTests.AutoProps.cs new file mode 100644 index 000000000..799912d27 --- /dev/null +++ b/test/coverlet.core.tests/Coverage/CoverageTests.AutoProps.cs @@ -0,0 +1,54 @@ +using System.IO; +using System.Threading.Tasks; +using Coverlet.Core.Samples.Tests; +using Xunit; + +namespace Coverlet.Core.Tests +{ + public partial class CoverageTests + { + [Theory] + [InlineData(true)] + [InlineData(false)] + public void SkipAutoProps(bool skipAutoProps) + { + string path = Path.GetTempFileName(); + try + { + FunctionExecutor.Run(async (string[] parameters) => + { + CoveragePrepareResult coveragePrepareResult = await TestInstrumentationHelper.Run(instance => + { + instance.AutoPropsNonInit = 10; + instance.AutoPropsInit = 20; + int readVal = instance.AutoPropsNonInit; + readVal = instance.AutoPropsInit; + return Task.CompletedTask; + }, + persistPrepareResultToFile: parameters[0], skipAutoProps: bool.Parse(parameters[1])); + + return 0; + }, new string[] { path, skipAutoProps.ToString() }); + + if (skipAutoProps) + { + TestInstrumentationHelper.GetCoverageResult(path) + .Document("Instrumentation.AutoProps.cs") + .AssertNonInstrumentedLines(BuildConfiguration.Debug, 12, 12) + .AssertLinesCoveredFromTo(BuildConfiguration.Debug, 7, 11) + .AssertLinesCovered(BuildConfiguration.Debug, (13, 1)); + } + else + { + TestInstrumentationHelper.GetCoverageResult(path) + .Document("Instrumentation.AutoProps.cs") + .AssertLinesCoveredFromTo(BuildConfiguration.Debug, 7, 13); + } + } + finally + { + File.Delete(path); + } + } + } +} diff --git a/test/coverlet.core.tests/Coverage/CoverageTest.Yield.cs b/test/coverlet.core.tests/Coverage/CoverageTests.Yield.cs similarity index 100% rename from test/coverlet.core.tests/Coverage/CoverageTest.Yield.cs rename to test/coverlet.core.tests/Coverage/CoverageTests.Yield.cs diff --git a/test/coverlet.core.tests/Coverage/InstrumenterHelper.cs b/test/coverlet.core.tests/Coverage/InstrumenterHelper.cs index 2faabf3d7..e548996f1 100644 --- a/test/coverlet.core.tests/Coverage/InstrumenterHelper.cs +++ b/test/coverlet.core.tests/Coverage/InstrumenterHelper.cs @@ -67,7 +67,12 @@ public static CoverageResult GetCoverageResult(string filePath) return coverage.GetCoverageResult(); } - async public static Task Run(Func callMethod, Func includeFilter = null, Func excludeFilter = null, string persistPrepareResultToFile = null, bool disableRestoreModules = false) + async public static Task Run(Func callMethod, + Func includeFilter = null, + Func excludeFilter = null, + string persistPrepareResultToFile = null, + bool disableRestoreModules = false, + bool skipAutoProps = false) { if (persistPrepareResultToFile is null) { @@ -105,7 +110,8 @@ async public static Task Run(Func callM IncludeTestAssembly = true, SingleHit = false, MergeWith = string.Empty, - UseSourceLink = false + UseSourceLink = false, + SkipAutoProps = skipAutoProps }; // Instrument module diff --git a/test/coverlet.core.tests/Instrumentation/InstrumenterTests.cs b/test/coverlet.core.tests/Instrumentation/InstrumenterTests.cs index 78e5365b5..71ef28073 100644 --- a/test/coverlet.core.tests/Instrumentation/InstrumenterTests.cs +++ b/test/coverlet.core.tests/Instrumentation/InstrumenterTests.cs @@ -77,7 +77,7 @@ public void TestCoreLibInstrumentation() InstrumentationHelper instrumentationHelper = new InstrumentationHelper(new ProcessExitHandler(), new RetryHelper(), partialMockFileSystem.Object, _mockLogger.Object, sourceRootTranslator); Instrumenter instrumenter = new Instrumenter(Path.Combine(directory.FullName, files[0]), "_coverlet_instrumented", Array.Empty(), Array.Empty(), Array.Empty(), - Array.Empty(), false, _mockLogger.Object, instrumentationHelper, partialMockFileSystem.Object, sourceRootTranslator, new CecilSymbolHelper()); + Array.Empty(), false, false, _mockLogger.Object, instrumentationHelper, partialMockFileSystem.Object, sourceRootTranslator, new CecilSymbolHelper()); Assert.True(instrumenter.CanInstrument()); InstrumenterResult result = instrumenter.Instrument(); @@ -242,7 +242,7 @@ private InstrumenterTest CreateInstrumentor(bool fakeCoreLibModule = false, stri new InstrumentationHelper(new ProcessExitHandler(), new RetryHelper(), new FileSystem(), new Mock().Object, new SourceRootTranslator(new Mock().Object, new FileSystem())); module = Path.Combine(directory.FullName, destModule); - Instrumenter instrumenter = new Instrumenter(module, identifier, Array.Empty(), Array.Empty(), Array.Empty(), attributesToIgnore, false, + Instrumenter instrumenter = new Instrumenter(module, identifier, Array.Empty(), Array.Empty(), Array.Empty(), attributesToIgnore, false, false, _mockLogger.Object, instrumentationHelper, new FileSystem(), new SourceRootTranslator(_mockLogger.Object, new FileSystem()), new CecilSymbolHelper()); return new InstrumenterTest { @@ -420,7 +420,7 @@ public void SkipEmbeddedPpdbWithoutLocalSource() new SourceRootTranslator(xunitDll, new Mock().Object, new FileSystem())); Instrumenter instrumenter = new Instrumenter(xunitDll, "_xunit_instrumented", Array.Empty(), Array.Empty(), Array.Empty(), - Array.Empty(), false, loggerMock.Object, instrumentationHelper, new FileSystem(), new SourceRootTranslator(xunitDll, loggerMock.Object, new FileSystem()), new CecilSymbolHelper()); + Array.Empty(), false, false, loggerMock.Object, instrumentationHelper, new FileSystem(), new SourceRootTranslator(xunitDll, loggerMock.Object, new FileSystem()), new CecilSymbolHelper()); Assert.True(instrumentationHelper.HasPdb(xunitDll, out bool embedded)); Assert.True(embedded); Assert.False(instrumenter.CanInstrument()); @@ -433,7 +433,7 @@ public void SkipEmbeddedPpdbWithoutLocalSource() new SourceRootTranslator(sample, new Mock().Object, new FileSystem())); instrumenter = new Instrumenter(sample, "_coverlet_tests_projectsample_empty", Array.Empty(), Array.Empty(), Array.Empty(), - Array.Empty(), false, loggerMock.Object, instrumentationHelper, new FileSystem(), new SourceRootTranslator(sample, loggerMock.Object, new FileSystem()), new CecilSymbolHelper()); + Array.Empty(), false, false, loggerMock.Object, instrumentationHelper, new FileSystem(), new SourceRootTranslator(sample, loggerMock.Object, new FileSystem()), new CecilSymbolHelper()); Assert.True(instrumentationHelper.HasPdb(sample, out embedded)); Assert.False(embedded); @@ -479,7 +479,7 @@ public void SkipPpdbWithoutLocalSource() string sample = Directory.GetFiles(Path.Combine(Directory.GetCurrentDirectory(), "TestAssets"), dllFileName).First(); var loggerMock = new Mock(); Instrumenter instrumenter = new Instrumenter(sample, "_75d9f96508d74def860a568f426ea4a4_instrumented", Array.Empty(), Array.Empty(), Array.Empty(), - Array.Empty(), false, loggerMock.Object, instrumentationHelper, partialMockFileSystem.Object, new SourceRootTranslator(loggerMock.Object, new FileSystem()), new CecilSymbolHelper()); + Array.Empty(), false, false, loggerMock.Object, instrumentationHelper, partialMockFileSystem.Object, new SourceRootTranslator(loggerMock.Object, new FileSystem()), new CecilSymbolHelper()); Assert.True(instrumentationHelper.HasPdb(sample, out bool embedded)); Assert.False(embedded); Assert.False(instrumenter.CanInstrument()); @@ -496,7 +496,7 @@ public void TestInstrument_MissingModule() new SourceRootTranslator(new Mock().Object, new FileSystem())); var instrumenter = new Instrumenter("test", "_test_instrumented", Array.Empty(), Array.Empty(), Array.Empty(), - Array.Empty(), false, loggerMock.Object, instrumentationHelper, new FileSystem(), new SourceRootTranslator(loggerMock.Object, new FileSystem()), new CecilSymbolHelper()); + Array.Empty(), false, false, loggerMock.Object, instrumentationHelper, new FileSystem(), new SourceRootTranslator(loggerMock.Object, new FileSystem()), new CecilSymbolHelper()); Assert.False(instrumenter.CanInstrument()); loggerMock.Verify(l => l.LogWarning(It.IsAny())); } @@ -519,7 +519,7 @@ public void TestInstrument_AssemblyMarkedAsExcludeFromCodeCoverage() new SourceRootTranslator(new Mock().Object, new FileSystem())); Instrumenter instrumenter = new Instrumenter(excludedbyattributeDll, "_xunit_excludedbyattribute", Array.Empty(), Array.Empty(), Array.Empty(), - Array.Empty(), false, loggerMock.Object, instrumentationHelper, partialMockFileSystem.Object, new SourceRootTranslator(loggerMock.Object, new FileSystem()), new CecilSymbolHelper()); + Array.Empty(), false, false, loggerMock.Object, instrumentationHelper, partialMockFileSystem.Object, new SourceRootTranslator(loggerMock.Object, new FileSystem()), new CecilSymbolHelper()); InstrumenterResult result = instrumenter.Instrument(); Assert.Empty(result.Documents); loggerMock.Verify(l => l.LogVerbose(It.IsAny())); diff --git a/test/coverlet.core.tests/Samples/Instrumentation.AutoProps.cs b/test/coverlet.core.tests/Samples/Instrumentation.AutoProps.cs new file mode 100644 index 000000000..4378ca9e7 --- /dev/null +++ b/test/coverlet.core.tests/Samples/Instrumentation.AutoProps.cs @@ -0,0 +1,15 @@ +using System; + +namespace Coverlet.Core.Samples.Tests +{ + public class AutoProps + { + private int _myVal = 0; + public AutoProps() + { + _myVal = new Random().Next(); + } + public int AutoPropsNonInit { get; set; } + public int AutoPropsInit { get; set; } = 10; + } +}