From d3b2db17eab77927ed62a27d1ea2e6c645b8a2a8 Mon Sep 17 00:00:00 2001 From: Ido David Date: Thu, 26 Apr 2018 00:12:09 -0400 Subject: [PATCH 1/3] Implementation exclusion of files according to source file paths (including file globbing) --- src/coverlet.core/Coverage.cs | 6 ++-- .../Helpers/InstrumentationHelper.cs | 27 ++++++++++++-- .../Instrumentation/Instrumenter.cs | 10 +++++- src/coverlet.core/coverlet.core.csproj | 1 + .../InstrumentationTask.cs | 36 +++++++++---------- src/coverlet.msbuild/coverlet.msbuild.props | 1 + src/coverlet.msbuild/coverlet.msbuild.targets | 4 +++ test/coverlet.core.tests/CoverageTests.cs | 2 +- .../Instrumentation/InstrumenterTests.cs | 2 +- .../coverlet.core.tests.csproj | 1 + 10 files changed, 63 insertions(+), 27 deletions(-) diff --git a/src/coverlet.core/Coverage.cs b/src/coverlet.core/Coverage.cs index 10cecca..690e87b 100644 --- a/src/coverlet.core/Coverage.cs +++ b/src/coverlet.core/Coverage.cs @@ -12,12 +12,14 @@ namespace Coverlet.Core { private string _module; private string _identifier; + private IEnumerable _excludedFiles; private List _results; - public Coverage(string module, string identifier) + public Coverage(string module, string identifier, IEnumerable excludedFiles) { _module = module; _identifier = identifier; + _excludedFiles = excludedFiles; _results = new List(); } @@ -26,7 +28,7 @@ namespace Coverlet.Core string[] modules = InstrumentationHelper.GetDependencies(_module); foreach (var module in modules) { - var instrumenter = new Instrumenter(module, _identifier); + var instrumenter = new Instrumenter(module, _identifier, _excludedFiles); if (instrumenter.CanInstrument()) { InstrumentationHelper.BackupOriginalModule(module, _identifier); diff --git a/src/coverlet.core/Helpers/InstrumentationHelper.cs b/src/coverlet.core/Helpers/InstrumentationHelper.cs index f88af59..68e37e5 100644 --- a/src/coverlet.core/Helpers/InstrumentationHelper.cs +++ b/src/coverlet.core/Helpers/InstrumentationHelper.cs @@ -3,12 +3,14 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection.PortableExecutable; +using Microsoft.Extensions.FileSystemGlobbing; using Coverlet.Core.Instrumentation; +using Microsoft.Extensions.FileSystemGlobbing.Abstractions; namespace Coverlet.Core.Helpers { - internal static class InstrumentationHelper + public static class InstrumentationHelper { public static string[] GetDependencies(string module) { @@ -106,5 +108,26 @@ namespace Coverlet.Core.Helpers RetryHelper.Retry(() => File.Delete(path), retryStrategy, 10); } + + public static string[] GetExcludedFiles(string[] exclusionRules, string parentDir) { + if (exclusionRules == null || exclusionRules.Length == 0 ) return null; + var matcher = new Matcher(); + foreach (var exclusionRule in exclusionRules) + { + matcher.AddInclude(exclusionRule); + } + + DirectoryInfo directoryInfo = new DirectoryInfo(parentDir); + + var fileMatchResult = matcher.Execute(new DirectoryInfoWrapper(directoryInfo)); + return fileMatchResult.Files + .Select( + f => System.IO.Path.GetFullPath( + System.IO.Path.Combine(directoryInfo.ToString(), f.Path) + ) + ) + .ToArray(); + } } -} \ No newline at end of file +} + diff --git a/src/coverlet.core/Instrumentation/Instrumenter.cs b/src/coverlet.core/Instrumentation/Instrumenter.cs index 27f1720..c37d38e 100644 --- a/src/coverlet.core/Instrumentation/Instrumenter.cs +++ b/src/coverlet.core/Instrumentation/Instrumenter.cs @@ -8,6 +8,8 @@ using Coverlet.Core.Extensions; using Mono.Cecil; using Mono.Cecil.Cil; using Mono.Cecil.Rocks; +using System; +using System.Xml.Linq; namespace Coverlet.Core.Instrumentation { @@ -15,12 +17,14 @@ namespace Coverlet.Core.Instrumentation { private string _module; private string _identifier; + private IEnumerable _excludedFiles; private InstrumenterResult _result; - public Instrumenter(string module, string identifier) + public Instrumenter(string module, string identifier, IEnumerable excludedFiles = null) { _module = module; _identifier = identifier; + _excludedFiles = excludedFiles; } public bool CanInstrument() => InstrumentationHelper.HasPdb(_module); @@ -61,6 +65,10 @@ namespace Coverlet.Core.Instrumentation foreach (var method in type.Methods) { + var sourceFiles = method.DebugInformation.SequencePoints.Select(s => s.Document.Url).Distinct(); + if (_excludedFiles != null && sourceFiles.Any(_excludedFiles.Contains)) { + continue; + } if (!method.CustomAttributes.Any(a => a.AttributeType.Name == "ExcludeFromCoverageAttribute" || a.AttributeType.Name == "ExcludeFromCoverage")) InstrumentMethod(method); } diff --git a/src/coverlet.core/coverlet.core.csproj b/src/coverlet.core/coverlet.core.csproj index 130a1d5..bda5a61 100644 --- a/src/coverlet.core/coverlet.core.csproj +++ b/src/coverlet.core/coverlet.core.csproj @@ -9,6 +9,7 @@ + diff --git a/src/coverlet.msbuild.tasks/InstrumentationTask.cs b/src/coverlet.msbuild.tasks/InstrumentationTask.cs index 5c141d1..c3524c6 100644 --- a/src/coverlet.msbuild.tasks/InstrumentationTask.cs +++ b/src/coverlet.msbuild.tasks/InstrumentationTask.cs @@ -1,35 +1,31 @@ using System; using Coverlet.Core; - +using Coverlet.Core.Helpers; using Microsoft.Build.Framework; -using Microsoft.Build.Utilities; - +using Microsoft.Build.Utilities; + namespace Coverlet.MSbuild.Tasks { public class InstrumentationTask : Task - { - private string _path; - private static Coverage _coverage; - - internal static Coverage Coverage - { - get { return _coverage; } - private set { _coverage = value; } - } + { + internal static Coverage Coverage { get; private set; } [Required] - public string Path - { - get { return _path; } - set { _path = value; } - } - + public string Path { get; set; } + + [Required] + public string[] ExclusionRules { get; set; } + + public string ExclusionParentDir { get; set; } + public override bool Execute() { try { - _coverage = new Coverage(_path, Guid.NewGuid().ToString()); - _coverage.PrepareModules(); + var excludedFiles = InstrumentationHelper.GetExcludedFiles( + ExclusionRules, ExclusionParentDir); + Coverage = new Coverage(Path, Guid.NewGuid().ToString(), excludedFiles); + Coverage.PrepareModules(); } catch(Exception ex) { diff --git a/src/coverlet.msbuild/coverlet.msbuild.props b/src/coverlet.msbuild/coverlet.msbuild.props index da98609..c92158f 100644 --- a/src/coverlet.msbuild/coverlet.msbuild.props +++ b/src/coverlet.msbuild/coverlet.msbuild.props @@ -6,6 +6,7 @@ $(MSBuildProjectDirectory) coverage $([MSBuild]::EnsureTrailingSlash('$(CoverletOutputDirectory)'))$(CoverletOutputName) + $(MSBuildProjectDirectory) 0 false diff --git a/src/coverlet.msbuild/coverlet.msbuild.targets b/src/coverlet.msbuild/coverlet.msbuild.targets index d761d98..5cf3974 100644 --- a/src/coverlet.msbuild/coverlet.msbuild.targets +++ b/src/coverlet.msbuild/coverlet.msbuild.targets @@ -6,12 +6,16 @@ diff --git a/test/coverlet.core.tests/CoverageTests.cs b/test/coverlet.core.tests/CoverageTests.cs index e895a47..1f54fba 100644 --- a/test/coverlet.core.tests/CoverageTests.cs +++ b/test/coverlet.core.tests/CoverageTests.cs @@ -21,7 +21,7 @@ namespace Coverlet.Core.Tests File.Copy(module, tempModule, true); - var coverage = new Coverage(tempModule, identifier); + var coverage = new Coverage(tempModule, identifier, null); coverage.PrepareModules(); var result = coverage.GetCoverageResult(); diff --git a/test/coverlet.core.tests/Instrumentation/InstrumenterTests.cs b/test/coverlet.core.tests/Instrumentation/InstrumenterTests.cs index 2bb738c..158da51 100644 --- a/test/coverlet.core.tests/Instrumentation/InstrumenterTests.cs +++ b/test/coverlet.core.tests/Instrumentation/InstrumenterTests.cs @@ -3,6 +3,7 @@ using System.IO; using Xunit; using Coverlet.Core.Instrumentation; +using Coverlet.MSbuild.Tasks; namespace Coverlet.Core.Instrumentation.Tests { @@ -21,7 +22,6 @@ namespace Coverlet.Core.Instrumentation.Tests File.Copy(pdb, Path.Combine(directory.FullName, Path.GetFileName(pdb)), true); module = Path.Combine(directory.FullName, Path.GetFileName(module)); - Instrumenter instrumenter = new Instrumenter(module, identifier); var result = instrumenter.Instrument(); diff --git a/test/coverlet.core.tests/coverlet.core.tests.csproj b/test/coverlet.core.tests/coverlet.core.tests.csproj index d80f070..467e7b7 100644 --- a/test/coverlet.core.tests/coverlet.core.tests.csproj +++ b/test/coverlet.core.tests/coverlet.core.tests.csproj @@ -17,6 +17,7 @@ + From 8adfb45d35a1264859e5961597f3b8144eccf532 Mon Sep 17 00:00:00 2001 From: Ido David Date: Thu, 26 Apr 2018 23:59:28 -0400 Subject: [PATCH 2/3] addressing first comments --- src/coverlet.core/Coverage.cs | 2 +- src/coverlet.core/Helpers/InstrumentationHelper.cs | 8 ++------ src/coverlet.core/Instrumentation/Instrumenter.cs | 6 +++--- test/coverlet.core.tests/CoverageTests.cs | 2 +- .../Instrumentation/InstrumenterTests.cs | 1 - test/coverlet.core.tests/coverlet.core.tests.csproj | 1 - 6 files changed, 7 insertions(+), 13 deletions(-) diff --git a/src/coverlet.core/Coverage.cs b/src/coverlet.core/Coverage.cs index 690e87b..a51ff75 100644 --- a/src/coverlet.core/Coverage.cs +++ b/src/coverlet.core/Coverage.cs @@ -15,7 +15,7 @@ namespace Coverlet.Core private IEnumerable _excludedFiles; private List _results; - public Coverage(string module, string identifier, IEnumerable excludedFiles) + public Coverage(string module, string identifier, IEnumerable excludedFiles = null) { _module = module; _identifier = identifier; diff --git a/src/coverlet.core/Helpers/InstrumentationHelper.cs b/src/coverlet.core/Helpers/InstrumentationHelper.cs index 68e37e5..54cc501 100644 --- a/src/coverlet.core/Helpers/InstrumentationHelper.cs +++ b/src/coverlet.core/Helpers/InstrumentationHelper.cs @@ -110,7 +110,7 @@ namespace Coverlet.Core.Helpers } public static string[] GetExcludedFiles(string[] exclusionRules, string parentDir) { - if (exclusionRules == null || exclusionRules.Length == 0 ) return null; + if (!(exclusionRules?.Length > 0) ) return null; var matcher = new Matcher(); foreach (var exclusionRule in exclusionRules) { @@ -121,11 +121,7 @@ namespace Coverlet.Core.Helpers var fileMatchResult = matcher.Execute(new DirectoryInfoWrapper(directoryInfo)); return fileMatchResult.Files - .Select( - f => System.IO.Path.GetFullPath( - System.IO.Path.Combine(directoryInfo.ToString(), f.Path) - ) - ) + .Select(f => Path.GetFullPath(Path.Combine(directoryInfo.ToString(), f.Path))) .ToArray(); } } diff --git a/src/coverlet.core/Instrumentation/Instrumenter.cs b/src/coverlet.core/Instrumentation/Instrumenter.cs index c37d38e..70262eb 100644 --- a/src/coverlet.core/Instrumentation/Instrumenter.cs +++ b/src/coverlet.core/Instrumentation/Instrumenter.cs @@ -24,7 +24,7 @@ namespace Coverlet.Core.Instrumentation { _module = module; _identifier = identifier; - _excludedFiles = excludedFiles; + _excludedFiles = excludedFiles ?? Enumerable.Empty(); } public bool CanInstrument() => InstrumentationHelper.HasPdb(_module); @@ -65,8 +65,8 @@ namespace Coverlet.Core.Instrumentation foreach (var method in type.Methods) { - var sourceFiles = method.DebugInformation.SequencePoints.Select(s => s.Document.Url).Distinct(); - if (_excludedFiles != null && sourceFiles.Any(_excludedFiles.Contains)) { + var sourceFile = method.DebugInformation.SequencePoints.Select(s => s.Document.Url).FirstOrDefault(); + if (!string.IsNullOrEmpty(sourceFile) && _excludedFiles.Contains(sourceFile)) { continue; } if (!method.CustomAttributes.Any(a => a.AttributeType.Name == "ExcludeFromCoverageAttribute" || a.AttributeType.Name == "ExcludeFromCoverage")) diff --git a/test/coverlet.core.tests/CoverageTests.cs b/test/coverlet.core.tests/CoverageTests.cs index 1f54fba..e895a47 100644 --- a/test/coverlet.core.tests/CoverageTests.cs +++ b/test/coverlet.core.tests/CoverageTests.cs @@ -21,7 +21,7 @@ namespace Coverlet.Core.Tests File.Copy(module, tempModule, true); - var coverage = new Coverage(tempModule, identifier, null); + var coverage = new Coverage(tempModule, identifier); coverage.PrepareModules(); var result = coverage.GetCoverageResult(); diff --git a/test/coverlet.core.tests/Instrumentation/InstrumenterTests.cs b/test/coverlet.core.tests/Instrumentation/InstrumenterTests.cs index 158da51..e206a72 100644 --- a/test/coverlet.core.tests/Instrumentation/InstrumenterTests.cs +++ b/test/coverlet.core.tests/Instrumentation/InstrumenterTests.cs @@ -3,7 +3,6 @@ using System.IO; using Xunit; using Coverlet.Core.Instrumentation; -using Coverlet.MSbuild.Tasks; namespace Coverlet.Core.Instrumentation.Tests { diff --git a/test/coverlet.core.tests/coverlet.core.tests.csproj b/test/coverlet.core.tests/coverlet.core.tests.csproj index 467e7b7..d80f070 100644 --- a/test/coverlet.core.tests/coverlet.core.tests.csproj +++ b/test/coverlet.core.tests/coverlet.core.tests.csproj @@ -17,7 +17,6 @@ - From ccdca640f08350752297e2a68b8daf41cc6ced59 Mon Sep 17 00:00:00 2001 From: Ido David Date: Sat, 28 Apr 2018 19:23:35 -0400 Subject: [PATCH 3/3] addressing further comments --- src/coverlet.core/Coverage.cs | 9 +++++---- .../Helpers/InstrumentationHelper.cs | 16 +++++++++------- .../InstrumentationTask.cs | 11 +++-------- src/coverlet.msbuild/coverlet.msbuild.props | 3 +-- src/coverlet.msbuild/coverlet.msbuild.targets | 8 +++----- 5 files changed, 21 insertions(+), 26 deletions(-) diff --git a/src/coverlet.core/Coverage.cs b/src/coverlet.core/Coverage.cs index a51ff75..0ec0b4c 100644 --- a/src/coverlet.core/Coverage.cs +++ b/src/coverlet.core/Coverage.cs @@ -12,23 +12,24 @@ namespace Coverlet.Core { private string _module; private string _identifier; - private IEnumerable _excludedFiles; + private IEnumerable _excludeRules; private List _results; - public Coverage(string module, string identifier, IEnumerable excludedFiles = null) + public Coverage(string module, string identifier, IEnumerable excludeRules = null) { _module = module; _identifier = identifier; - _excludedFiles = excludedFiles; + _excludeRules = excludeRules; _results = new List(); } public void PrepareModules() { string[] modules = InstrumentationHelper.GetDependencies(_module); + var excludedFiles = InstrumentationHelper.GetExcludedFiles(_excludeRules); foreach (var module in modules) { - var instrumenter = new Instrumenter(module, _identifier, _excludedFiles); + var instrumenter = new Instrumenter(module, _identifier, excludedFiles); if (instrumenter.CanInstrument()) { InstrumentationHelper.BackupOriginalModule(module, _identifier); diff --git a/src/coverlet.core/Helpers/InstrumentationHelper.cs b/src/coverlet.core/Helpers/InstrumentationHelper.cs index 54cc501..c0ff877 100644 --- a/src/coverlet.core/Helpers/InstrumentationHelper.cs +++ b/src/coverlet.core/Helpers/InstrumentationHelper.cs @@ -10,7 +10,7 @@ using Microsoft.Extensions.FileSystemGlobbing.Abstractions; namespace Coverlet.Core.Helpers { - public static class InstrumentationHelper + internal static class InstrumentationHelper { public static string[] GetDependencies(string module) { @@ -109,20 +109,22 @@ namespace Coverlet.Core.Helpers RetryHelper.Retry(() => File.Delete(path), retryStrategy, 10); } - public static string[] GetExcludedFiles(string[] exclusionRules, string parentDir) { - if (!(exclusionRules?.Length > 0) ) return null; + public static IEnumerable GetExcludedFiles(IEnumerable excludeRules, + string parentDir = null) + { + parentDir = string.IsNullOrWhiteSpace(parentDir)? Directory.GetCurrentDirectory() : parentDir; + if (excludeRules == null || !excludeRules.Any()) return Enumerable.Empty(); var matcher = new Matcher(); - foreach (var exclusionRule in exclusionRules) + foreach (var excludeRule in excludeRules) { - matcher.AddInclude(exclusionRule); + matcher.AddInclude(excludeRule); } DirectoryInfo directoryInfo = new DirectoryInfo(parentDir); var fileMatchResult = matcher.Execute(new DirectoryInfoWrapper(directoryInfo)); return fileMatchResult.Files - .Select(f => Path.GetFullPath(Path.Combine(directoryInfo.ToString(), f.Path))) - .ToArray(); + .Select(f => Path.GetFullPath(Path.Combine(directoryInfo.ToString(), f.Path))); } } } diff --git a/src/coverlet.msbuild.tasks/InstrumentationTask.cs b/src/coverlet.msbuild.tasks/InstrumentationTask.cs index c3524c6..8a1f810 100644 --- a/src/coverlet.msbuild.tasks/InstrumentationTask.cs +++ b/src/coverlet.msbuild.tasks/InstrumentationTask.cs @@ -1,6 +1,5 @@ using System; using Coverlet.Core; -using Coverlet.Core.Helpers; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; @@ -14,17 +13,13 @@ namespace Coverlet.MSbuild.Tasks public string Path { get; set; } [Required] - public string[] ExclusionRules { get; set; } - - public string ExclusionParentDir { get; set; } - + public string[] Exclude { get; set; } + public override bool Execute() { try { - var excludedFiles = InstrumentationHelper.GetExcludedFiles( - ExclusionRules, ExclusionParentDir); - Coverage = new Coverage(Path, Guid.NewGuid().ToString(), excludedFiles); + Coverage = new Coverage(Path, Guid.NewGuid().ToString(), Exclude); Coverage.PrepareModules(); } catch(Exception ex) diff --git a/src/coverlet.msbuild/coverlet.msbuild.props b/src/coverlet.msbuild/coverlet.msbuild.props index c92158f..6f7c3a1 100644 --- a/src/coverlet.msbuild/coverlet.msbuild.props +++ b/src/coverlet.msbuild/coverlet.msbuild.props @@ -6,8 +6,7 @@ $(MSBuildProjectDirectory) coverage $([MSBuild]::EnsureTrailingSlash('$(CoverletOutputDirectory)'))$(CoverletOutputName) - $(MSBuildProjectDirectory) - + 0 false diff --git a/src/coverlet.msbuild/coverlet.msbuild.targets b/src/coverlet.msbuild/coverlet.msbuild.targets index 5cf3974..5174fb8 100644 --- a/src/coverlet.msbuild/coverlet.msbuild.targets +++ b/src/coverlet.msbuild/coverlet.msbuild.targets @@ -6,16 +6,14 @@ @@ -27,4 +25,4 @@ Threshold="$(Threshold)" /> - \ No newline at end of file +