@@ -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.
|
||||
|
||||
@@ -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 ```,```.
|
||||
|
||||
|
||||
@@ -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?
|
||||
<SingleHit>false</SingleHit>
|
||||
<UseSourceLink>true</UseSourceLink>
|
||||
<IncludeTestAssembly>true</IncludeTestAssembly>
|
||||
<SkipAutoProps>true</SkipAutoProps>
|
||||
</Configuration>
|
||||
</DataCollector>
|
||||
</DataCollectors>
|
||||
|
||||
@@ -167,6 +167,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.
|
||||
|
||||
@@ -27,7 +27,8 @@ namespace Coverlet.Collector.DataCollection
|
||||
IncludeTestAssembly = settings.IncludeTestAssembly,
|
||||
SingleHit = settings.SingleHit,
|
||||
MergeWith = settings.MergeWith,
|
||||
UseSourceLink = settings.UseSourceLink
|
||||
UseSourceLink = settings.UseSourceLink,
|
||||
SkipAutoProps = settings.SkipAutoProps
|
||||
};
|
||||
|
||||
return new Coverage(
|
||||
|
||||
@@ -63,20 +63,26 @@ namespace Coverlet.Collector.DataCollection
|
||||
/// </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();
|
||||
}
|
||||
|
||||
@@ -29,23 +29,24 @@ namespace Coverlet.Collector.DataCollection
|
||||
{
|
||||
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)
|
||||
{
|
||||
@@ -205,6 +206,18 @@ namespace Coverlet.Collector.DataCollection
|
||||
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>
|
||||
|
||||
@@ -20,5 +20,6 @@
|
||||
public const string ReportFormatElementName = "Format";
|
||||
public const string DefaultExcludeFilter = "[coverlet.*]*";
|
||||
public const string InProcDataCollectorName = "CoverletInProcDataCollector";
|
||||
public const string SkipAutoProps = "SkipAutoProps";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,6 +60,7 @@ namespace Coverlet.Console
|
||||
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 @@ namespace Coverlet.Console
|
||||
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 @@ namespace Coverlet.Console
|
||||
fileSystem,
|
||||
serviceProvider.GetRequiredService<ISourceRootTranslator>(),
|
||||
serviceProvider.GetRequiredService<ICecilSymbolHelper>());
|
||||
coverage.PrepareModules();
|
||||
coverage.PrepareModules();
|
||||
|
||||
Process process = new Process();
|
||||
process.StartInfo.FileName = target.Value();
|
||||
|
||||
@@ -23,6 +23,7 @@ namespace Coverlet.Core
|
||||
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 @@ namespace Coverlet.Core
|
||||
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 @@ namespace Coverlet.Core
|
||||
_fileSystem = fileSystem;
|
||||
_sourceRootTranslator = sourceRootTranslator;
|
||||
_cecilSymbolHelper = cecilSymbolHelper;
|
||||
_skipAutoProps = parameters.SkipAutoProps;
|
||||
|
||||
_identifier = Guid.NewGuid().ToString();
|
||||
_results = new List<InstrumenterResult>();
|
||||
@@ -115,7 +118,19 @@ namespace Coverlet.Core
|
||||
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())
|
||||
{
|
||||
|
||||
@@ -25,6 +25,7 @@ namespace Coverlet.Core.Instrumentation
|
||||
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 @@ namespace Coverlet.Core.Instrumentation
|
||||
string[] excludedFiles,
|
||||
string[] excludedAttributes,
|
||||
bool singleHit,
|
||||
bool skipAutoProps,
|
||||
ILogger logger,
|
||||
IInstrumentationHelper instrumentationHelper,
|
||||
IFileSystem fileSystem,
|
||||
@@ -84,6 +86,7 @@ namespace Coverlet.Core.Instrumentation
|
||||
_fileSystem = fileSystem;
|
||||
_sourceRootTranslator = sourceRootTranslator;
|
||||
_cecilSymbolHelper = cecilSymbolHelper;
|
||||
_skipAutoProps = skipAutoProps;
|
||||
}
|
||||
|
||||
public bool CanInstrument()
|
||||
@@ -432,6 +435,11 @@ namespace Coverlet.Core.Instrumentation
|
||||
|
||||
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);
|
||||
|
||||
@@ -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 @@ namespace Coverlet.MSbuild.Tasks
|
||||
|
||||
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 @@ namespace Coverlet.MSbuild.Tasks
|
||||
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 @@ namespace Coverlet.MSbuild.Tasks
|
||||
}
|
||||
else
|
||||
{
|
||||
ReportWriter writer = new ReportWriter(_coverletMultiTargetFrameworksCurrentTFM,
|
||||
ReportWriter writer = new ReportWriter(CoverletMultiTargetFrameworksCurrentTFM,
|
||||
directory,
|
||||
_output,
|
||||
Output,
|
||||
reporter,
|
||||
fileSystem,
|
||||
ServiceProvider.GetService<IConsole>(),
|
||||
@@ -152,7 +117,7 @@ namespace Coverlet.MSbuild.Tasks
|
||||
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 @@ namespace Coverlet.MSbuild.Tasks
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ namespace Coverlet.MSbuild.Tasks
|
||||
|
||||
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());
|
||||
|
||||
@@ -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 @@ namespace Coverlet.MSbuild.Tasks
|
||||
serviceCollection.AddTransient<ILogger, MSBuildLogger>(_ => _logger);
|
||||
serviceCollection.AddTransient<IRetryHelper, RetryHelper>();
|
||||
// We cache resolutions
|
||||
serviceCollection.AddSingleton<ISourceRootTranslator, SourceRootTranslator>(serviceProvider => new SourceRootTranslator(_path, serviceProvider.GetRequiredService<ILogger>(), serviceProvider.GetRequiredService<IFileSystem>()));
|
||||
serviceCollection.AddSingleton<ISourceRootTranslator, SourceRootTranslator>(serviceProvider => new SourceRootTranslator(Path, serviceProvider.GetRequiredService<ILogger>(), serviceProvider.GetRequiredService<IFileSystem>()));
|
||||
// We need to keep singleton/static semantics
|
||||
serviceCollection.AddSingleton<IInstrumentationHelper, InstrumentationHelper>();
|
||||
serviceCollection.AddSingleton<ICecilSymbolHelper, CecilSymbolHelper>();
|
||||
@@ -142,18 +89,19 @@ namespace Coverlet.MSbuild.Tasks
|
||||
|
||||
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<IInstrumentationHelper>(),
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
<Target Name="ReferencedPathMaps" BeforeTargets="CoreCompile" DependsOnTargets="ResolveProjectReferences" >
|
||||
<MSBuild Projects="@(AnnotatedProjects->'%(FullPath)')"
|
||||
Targets="CoverletGetPathMap"
|
||||
Targets="CoverletGetPathMap"
|
||||
Properties="TargetFramework=%(AnnotatedProjects.NearestTargetFramework)"
|
||||
SkipNonexistentTargets="true">
|
||||
<Output TaskParameter="TargetOutputs"
|
||||
@@ -38,7 +38,8 @@
|
||||
IncludeTestAssembly="$(IncludeTestAssembly)"
|
||||
SingleHit="$(SingleHit)"
|
||||
MergeWith="$(MergeWith)"
|
||||
UseSourceLink="$(UseSourceLink)" >
|
||||
UseSourceLink="$(UseSourceLink)"
|
||||
SkipAutoProps="$(SkipAutoProps)" >
|
||||
<Output TaskParameter="InstrumenterState" PropertyName="InstrumenterState"/>
|
||||
</Coverlet.MSbuild.Tasks.InstrumentationTask>
|
||||
</Target>
|
||||
|
||||
@@ -73,6 +73,7 @@ namespace Coverlet.Collector.Tests
|
||||
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 @@ namespace Coverlet.Collector.Tests
|
||||
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 @@ namespace Coverlet.Collector.Tests
|
||||
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);
|
||||
|
||||
|
||||
@@ -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<AutoProps>(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -67,7 +67,12 @@ namespace Coverlet.Core.Tests
|
||||
return coverage.GetCoverageResult();
|
||||
}
|
||||
|
||||
async public static Task<CoveragePrepareResult> Run<T>(Func<dynamic, Task> callMethod, Func<string, string[]> includeFilter = null, Func<string, string[]> excludeFilter = null, string persistPrepareResultToFile = null, bool disableRestoreModules = false)
|
||||
async public static Task<CoveragePrepareResult> Run<T>(Func<dynamic, Task> callMethod,
|
||||
Func<string, string[]> includeFilter = null,
|
||||
Func<string, string[]> excludeFilter = null,
|
||||
string persistPrepareResultToFile = null,
|
||||
bool disableRestoreModules = false,
|
||||
bool skipAutoProps = false)
|
||||
{
|
||||
if (persistPrepareResultToFile is null)
|
||||
{
|
||||
@@ -105,7 +110,8 @@ namespace Coverlet.Core.Tests
|
||||
IncludeTestAssembly = true,
|
||||
SingleHit = false,
|
||||
MergeWith = string.Empty,
|
||||
UseSourceLink = false
|
||||
UseSourceLink = false,
|
||||
SkipAutoProps = skipAutoProps
|
||||
};
|
||||
|
||||
// Instrument module
|
||||
|
||||
@@ -77,7 +77,7 @@ namespace Coverlet.Core.Instrumentation.Tests
|
||||
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<string>(), Array.Empty<string>(), Array.Empty<string>(),
|
||||
Array.Empty<string>(), false, _mockLogger.Object, instrumentationHelper, partialMockFileSystem.Object, sourceRootTranslator, new CecilSymbolHelper());
|
||||
Array.Empty<string>(), false, false, _mockLogger.Object, instrumentationHelper, partialMockFileSystem.Object, sourceRootTranslator, new CecilSymbolHelper());
|
||||
|
||||
Assert.True(instrumenter.CanInstrument());
|
||||
InstrumenterResult result = instrumenter.Instrument();
|
||||
@@ -242,7 +242,7 @@ namespace Coverlet.Core.Instrumentation.Tests
|
||||
new InstrumentationHelper(new ProcessExitHandler(), new RetryHelper(), new FileSystem(), new Mock<ILogger>().Object, new SourceRootTranslator(new Mock<ILogger>().Object, new FileSystem()));
|
||||
|
||||
module = Path.Combine(directory.FullName, destModule);
|
||||
Instrumenter instrumenter = new Instrumenter(module, identifier, Array.Empty<string>(), Array.Empty<string>(), Array.Empty<string>(), attributesToIgnore, false,
|
||||
Instrumenter instrumenter = new Instrumenter(module, identifier, Array.Empty<string>(), Array.Empty<string>(), Array.Empty<string>(), attributesToIgnore, false, false,
|
||||
_mockLogger.Object, instrumentationHelper, new FileSystem(), new SourceRootTranslator(_mockLogger.Object, new FileSystem()), new CecilSymbolHelper());
|
||||
return new InstrumenterTest
|
||||
{
|
||||
@@ -420,7 +420,7 @@ namespace Coverlet.Core.Instrumentation.Tests
|
||||
new SourceRootTranslator(xunitDll, new Mock<ILogger>().Object, new FileSystem()));
|
||||
|
||||
Instrumenter instrumenter = new Instrumenter(xunitDll, "_xunit_instrumented", Array.Empty<string>(), Array.Empty<string>(), Array.Empty<string>(),
|
||||
Array.Empty<string>(), false, loggerMock.Object, instrumentationHelper, new FileSystem(), new SourceRootTranslator(xunitDll, loggerMock.Object, new FileSystem()), new CecilSymbolHelper());
|
||||
Array.Empty<string>(), 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 @@ namespace Coverlet.Core.Instrumentation.Tests
|
||||
new SourceRootTranslator(sample, new Mock<ILogger>().Object, new FileSystem()));
|
||||
|
||||
instrumenter = new Instrumenter(sample, "_coverlet_tests_projectsample_empty", Array.Empty<string>(), Array.Empty<string>(), Array.Empty<string>(),
|
||||
Array.Empty<string>(), false, loggerMock.Object, instrumentationHelper, new FileSystem(), new SourceRootTranslator(sample, loggerMock.Object, new FileSystem()), new CecilSymbolHelper());
|
||||
Array.Empty<string>(), 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 @@ namespace Coverlet.Core.Instrumentation.Tests
|
||||
string sample = Directory.GetFiles(Path.Combine(Directory.GetCurrentDirectory(), "TestAssets"), dllFileName).First();
|
||||
var loggerMock = new Mock<ILogger>();
|
||||
Instrumenter instrumenter = new Instrumenter(sample, "_75d9f96508d74def860a568f426ea4a4_instrumented", Array.Empty<string>(), Array.Empty<string>(), Array.Empty<string>(),
|
||||
Array.Empty<string>(), false, loggerMock.Object, instrumentationHelper, partialMockFileSystem.Object, new SourceRootTranslator(loggerMock.Object, new FileSystem()), new CecilSymbolHelper());
|
||||
Array.Empty<string>(), 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 @@ namespace Coverlet.Core.Instrumentation.Tests
|
||||
new SourceRootTranslator(new Mock<ILogger>().Object, new FileSystem()));
|
||||
|
||||
var instrumenter = new Instrumenter("test", "_test_instrumented", Array.Empty<string>(), Array.Empty<string>(), Array.Empty<string>(),
|
||||
Array.Empty<string>(), false, loggerMock.Object, instrumentationHelper, new FileSystem(), new SourceRootTranslator(loggerMock.Object, new FileSystem()), new CecilSymbolHelper());
|
||||
Array.Empty<string>(), 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<string>()));
|
||||
}
|
||||
@@ -519,7 +519,7 @@ namespace Coverlet.Core.Instrumentation.Tests
|
||||
new SourceRootTranslator(new Mock<ILogger>().Object, new FileSystem()));
|
||||
|
||||
Instrumenter instrumenter = new Instrumenter(excludedbyattributeDll, "_xunit_excludedbyattribute", Array.Empty<string>(), Array.Empty<string>(), Array.Empty<string>(),
|
||||
Array.Empty<string>(), false, loggerMock.Object, instrumentationHelper, partialMockFileSystem.Object, new SourceRootTranslator(loggerMock.Object, new FileSystem()), new CecilSymbolHelper());
|
||||
Array.Empty<string>(), 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<string>()));
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user