Skip to content

Commit

Permalink
Merge pull request coverlet-coverage#112 from derhally/master
Browse files Browse the repository at this point in the history
Add support of ExcludeFromCodeCoverage attribute
  • Loading branch information
tonerdo committed Jun 5, 2018
2 parents e4c93fd + 4e4fa2b commit dd65743
Show file tree
Hide file tree
Showing 6 changed files with 155 additions and 69 deletions.
2 changes: 2 additions & 0 deletions README.md
Expand Up @@ -89,6 +89,8 @@ You can ignore a method or an entire class from code coverage by creating and ap

* ExcludeFromCoverage
* ExcludeFromCoverageAttribute
* ExcludeFromCodeCoverage
* ExcludeFromCodeCoverageAttribute

Coverlet just uses the type name, so the attributes can be created under any namespace of your choosing.

Expand Down
82 changes: 42 additions & 40 deletions coverlet.sln
@@ -1,19 +1,18 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26124.0
MinimumVisualStudioVersion = 15.0.26124.0
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E877EBA4-E78B-4F7D-A2D3-1E070FED04CD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "coverlet.core", "src\coverlet.core\coverlet.core.csproj", "{31084026-D563-4B91-BE71-174C4270CCF4}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "coverlet.core", "src\coverlet.core\coverlet.core.csproj", "{31084026-D563-4B91-BE71-174C4270CCF4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "coverlet.msbuild.tasks", "src\coverlet.msbuild.tasks\coverlet.msbuild.tasks.csproj", "{FA73E423-9790-4F35-B018-3C4E3CA338BA}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "coverlet.msbuild.tasks", "src\coverlet.msbuild.tasks\coverlet.msbuild.tasks.csproj", "{FA73E423-9790-4F35-B018-3C4E3CA338BA}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{2FEBDE1B-83E3-445B-B9F8-5644B0E0E134}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "coverlet.core.tests", "test\coverlet.core.tests\coverlet.core.tests.csproj", "{E7637CC6-43F7-461A-A0BF-3C14562419BD}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "coverlet.core.tests", "test\coverlet.core.tests\coverlet.core.tests.csproj", "{E7637CC6-43F7-461A-A0BF-3C14562419BD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "coverlet.console", "src\coverlet.console\coverlet.console.csproj", "{F3DBE7C3-ABBB-4B8B-A6CB-A1D3D607163E}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "coverlet.console", "src\coverlet.console\coverlet.console.csproj", "{F3DBE7C3-ABBB-4B8B-A6CB-A1D3D607163E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand All @@ -24,63 +23,66 @@ Global
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{31084026-D563-4B91-BE71-174C4270CCF4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{31084026-D563-4B91-BE71-174C4270CCF4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{31084026-D563-4B91-BE71-174C4270CCF4}.Debug|x64.ActiveCfg = Debug|x64
{31084026-D563-4B91-BE71-174C4270CCF4}.Debug|x64.Build.0 = Debug|x64
{31084026-D563-4B91-BE71-174C4270CCF4}.Debug|x86.ActiveCfg = Debug|x86
{31084026-D563-4B91-BE71-174C4270CCF4}.Debug|x86.Build.0 = Debug|x86
{31084026-D563-4B91-BE71-174C4270CCF4}.Debug|x64.ActiveCfg = Debug|Any CPU
{31084026-D563-4B91-BE71-174C4270CCF4}.Debug|x64.Build.0 = Debug|Any CPU
{31084026-D563-4B91-BE71-174C4270CCF4}.Debug|x86.ActiveCfg = Debug|Any CPU
{31084026-D563-4B91-BE71-174C4270CCF4}.Debug|x86.Build.0 = Debug|Any CPU
{31084026-D563-4B91-BE71-174C4270CCF4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{31084026-D563-4B91-BE71-174C4270CCF4}.Release|Any CPU.Build.0 = Release|Any CPU
{31084026-D563-4B91-BE71-174C4270CCF4}.Release|x64.ActiveCfg = Release|x64
{31084026-D563-4B91-BE71-174C4270CCF4}.Release|x64.Build.0 = Release|x64
{31084026-D563-4B91-BE71-174C4270CCF4}.Release|x86.ActiveCfg = Release|x86
{31084026-D563-4B91-BE71-174C4270CCF4}.Release|x86.Build.0 = Release|x86
{31084026-D563-4B91-BE71-174C4270CCF4}.Release|x64.ActiveCfg = Release|Any CPU
{31084026-D563-4B91-BE71-174C4270CCF4}.Release|x64.Build.0 = Release|Any CPU
{31084026-D563-4B91-BE71-174C4270CCF4}.Release|x86.ActiveCfg = Release|Any CPU
{31084026-D563-4B91-BE71-174C4270CCF4}.Release|x86.Build.0 = Release|Any CPU
{FA73E423-9790-4F35-B018-3C4E3CA338BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FA73E423-9790-4F35-B018-3C4E3CA338BA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FA73E423-9790-4F35-B018-3C4E3CA338BA}.Debug|x64.ActiveCfg = Debug|x64
{FA73E423-9790-4F35-B018-3C4E3CA338BA}.Debug|x64.Build.0 = Debug|x64
{FA73E423-9790-4F35-B018-3C4E3CA338BA}.Debug|x86.ActiveCfg = Debug|x86
{FA73E423-9790-4F35-B018-3C4E3CA338BA}.Debug|x86.Build.0 = Debug|x86
{FA73E423-9790-4F35-B018-3C4E3CA338BA}.Debug|x64.ActiveCfg = Debug|Any CPU
{FA73E423-9790-4F35-B018-3C4E3CA338BA}.Debug|x64.Build.0 = Debug|Any CPU
{FA73E423-9790-4F35-B018-3C4E3CA338BA}.Debug|x86.ActiveCfg = Debug|Any CPU
{FA73E423-9790-4F35-B018-3C4E3CA338BA}.Debug|x86.Build.0 = Debug|Any CPU
{FA73E423-9790-4F35-B018-3C4E3CA338BA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FA73E423-9790-4F35-B018-3C4E3CA338BA}.Release|Any CPU.Build.0 = Release|Any CPU
{FA73E423-9790-4F35-B018-3C4E3CA338BA}.Release|x64.ActiveCfg = Release|x64
{FA73E423-9790-4F35-B018-3C4E3CA338BA}.Release|x64.Build.0 = Release|x64
{FA73E423-9790-4F35-B018-3C4E3CA338BA}.Release|x86.ActiveCfg = Release|x86
{FA73E423-9790-4F35-B018-3C4E3CA338BA}.Release|x86.Build.0 = Release|x86
{FA73E423-9790-4F35-B018-3C4E3CA338BA}.Release|x64.ActiveCfg = Release|Any CPU
{FA73E423-9790-4F35-B018-3C4E3CA338BA}.Release|x64.Build.0 = Release|Any CPU
{FA73E423-9790-4F35-B018-3C4E3CA338BA}.Release|x86.ActiveCfg = Release|Any CPU
{FA73E423-9790-4F35-B018-3C4E3CA338BA}.Release|x86.Build.0 = Release|Any CPU
{E7637CC6-43F7-461A-A0BF-3C14562419BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E7637CC6-43F7-461A-A0BF-3C14562419BD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E7637CC6-43F7-461A-A0BF-3C14562419BD}.Debug|x64.ActiveCfg = Debug|x64
{E7637CC6-43F7-461A-A0BF-3C14562419BD}.Debug|x64.Build.0 = Debug|x64
{E7637CC6-43F7-461A-A0BF-3C14562419BD}.Debug|x86.ActiveCfg = Debug|x86
{E7637CC6-43F7-461A-A0BF-3C14562419BD}.Debug|x86.Build.0 = Debug|x86
{E7637CC6-43F7-461A-A0BF-3C14562419BD}.Debug|x64.ActiveCfg = Debug|Any CPU
{E7637CC6-43F7-461A-A0BF-3C14562419BD}.Debug|x64.Build.0 = Debug|Any CPU
{E7637CC6-43F7-461A-A0BF-3C14562419BD}.Debug|x86.ActiveCfg = Debug|Any CPU
{E7637CC6-43F7-461A-A0BF-3C14562419BD}.Debug|x86.Build.0 = Debug|Any CPU
{E7637CC6-43F7-461A-A0BF-3C14562419BD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E7637CC6-43F7-461A-A0BF-3C14562419BD}.Release|Any CPU.Build.0 = Release|Any CPU
{E7637CC6-43F7-461A-A0BF-3C14562419BD}.Release|x64.ActiveCfg = Release|x64
{E7637CC6-43F7-461A-A0BF-3C14562419BD}.Release|x64.Build.0 = Release|x64
{E7637CC6-43F7-461A-A0BF-3C14562419BD}.Release|x86.ActiveCfg = Release|x86
{E7637CC6-43F7-461A-A0BF-3C14562419BD}.Release|x86.Build.0 = Release|x86
{E7637CC6-43F7-461A-A0BF-3C14562419BD}.Release|x64.ActiveCfg = Release|Any CPU
{E7637CC6-43F7-461A-A0BF-3C14562419BD}.Release|x64.Build.0 = Release|Any CPU
{E7637CC6-43F7-461A-A0BF-3C14562419BD}.Release|x86.ActiveCfg = Release|Any CPU
{E7637CC6-43F7-461A-A0BF-3C14562419BD}.Release|x86.Build.0 = Release|Any CPU
{F3DBE7C3-ABBB-4B8B-A6CB-A1D3D607163E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F3DBE7C3-ABBB-4B8B-A6CB-A1D3D607163E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F3DBE7C3-ABBB-4B8B-A6CB-A1D3D607163E}.Debug|x64.ActiveCfg = Debug|x64
{F3DBE7C3-ABBB-4B8B-A6CB-A1D3D607163E}.Debug|x64.Build.0 = Debug|x64
{F3DBE7C3-ABBB-4B8B-A6CB-A1D3D607163E}.Debug|x86.ActiveCfg = Debug|x86
{F3DBE7C3-ABBB-4B8B-A6CB-A1D3D607163E}.Debug|x86.Build.0 = Debug|x86
{F3DBE7C3-ABBB-4B8B-A6CB-A1D3D607163E}.Debug|x64.ActiveCfg = Debug|Any CPU
{F3DBE7C3-ABBB-4B8B-A6CB-A1D3D607163E}.Debug|x64.Build.0 = Debug|Any CPU
{F3DBE7C3-ABBB-4B8B-A6CB-A1D3D607163E}.Debug|x86.ActiveCfg = Debug|Any CPU
{F3DBE7C3-ABBB-4B8B-A6CB-A1D3D607163E}.Debug|x86.Build.0 = Debug|Any CPU
{F3DBE7C3-ABBB-4B8B-A6CB-A1D3D607163E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F3DBE7C3-ABBB-4B8B-A6CB-A1D3D607163E}.Release|Any CPU.Build.0 = Release|Any CPU
{F3DBE7C3-ABBB-4B8B-A6CB-A1D3D607163E}.Release|x64.ActiveCfg = Release|x64
{F3DBE7C3-ABBB-4B8B-A6CB-A1D3D607163E}.Release|x64.Build.0 = Release|x64
{F3DBE7C3-ABBB-4B8B-A6CB-A1D3D607163E}.Release|x86.ActiveCfg = Release|x86
{F3DBE7C3-ABBB-4B8B-A6CB-A1D3D607163E}.Release|x86.Build.0 = Release|x86
{F3DBE7C3-ABBB-4B8B-A6CB-A1D3D607163E}.Release|x64.ActiveCfg = Release|Any CPU
{F3DBE7C3-ABBB-4B8B-A6CB-A1D3D607163E}.Release|x64.Build.0 = Release|Any CPU
{F3DBE7C3-ABBB-4B8B-A6CB-A1D3D607163E}.Release|x86.ActiveCfg = Release|Any CPU
{F3DBE7C3-ABBB-4B8B-A6CB-A1D3D607163E}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{31084026-D563-4B91-BE71-174C4270CCF4} = {E877EBA4-E78B-4F7D-A2D3-1E070FED04CD}
{FA73E423-9790-4F35-B018-3C4E3CA338BA} = {E877EBA4-E78B-4F7D-A2D3-1E070FED04CD}
{E7637CC6-43F7-461A-A0BF-3C14562419BD} = {2FEBDE1B-83E3-445B-B9F8-5644B0E0E134}
{F3DBE7C3-ABBB-4B8B-A6CB-A1D3D607163E} = {E877EBA4-E78B-4F7D-A2D3-1E070FED04CD}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {9CA57C02-97B0-4C38-A027-EA61E8741F10}
EndGlobalSection
EndGlobal
12 changes: 11 additions & 1 deletion src/coverlet.core/Instrumentation/Instrumenter.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Reflection;
Expand Down Expand Up @@ -269,7 +270,16 @@ private static void ReplaceExceptionHandlerBoundary(ExceptionHandler handler, In

private static bool IsExcludeAttribute(CustomAttribute customAttribute)
{
return customAttribute.AttributeType.Name == nameof(ExcludeFromCoverageAttribute) || customAttribute.AttributeType.Name == "ExcludeFromCoverage";
var excludeAttributeNames = new[]
{
nameof(ExcludeFromCoverageAttribute),
"ExcludeFromCoverage",
nameof(ExcludeFromCodeCoverageAttribute),
"ExcludeFromCodeCoverage"
};

var attributeName = customAttribute.AttributeType.Name;
return excludeAttributeNames.Any(a => a.Equals(attributeName));
}

private static Mono.Cecil.Cil.MethodBody GetMethodBody(MethodDefinition method)
Expand Down
54 changes: 48 additions & 6 deletions test/coverlet.core.tests/Instrumentation/InstrumenterTests.cs
@@ -1,33 +1,75 @@
using System;
using System.IO;

using System.Linq;
using Xunit;
using Coverlet.Core.Instrumentation;
using Coverlet.Core.Samples.Tests;

namespace Coverlet.Core.Instrumentation.Tests
{
public class InstrumenterTests
{
[Fact]
public void TestInstrument()
{
var instrumenterTest = CreateInstrumentor();

var result = instrumenterTest.Instrumenter.Instrument();

Assert.Equal(Path.GetFileNameWithoutExtension(instrumenterTest.Module), result.Module);
Assert.Equal(instrumenterTest.Module, result.ModulePath);

instrumenterTest.Directory.Delete(true);
}

[Theory]
[InlineData(typeof(ClassExcludedByCodeAnalysisCodeCoverageAttr))]
[InlineData(typeof(ClassExcludedByCoverletCodeCoverageAttr))]
public void TestInstrument_ClassesWithExcludeAttributeAreExcluded(Type excludedType)
{
var instrumenterTest = CreateInstrumentor();
var result = instrumenterTest.Instrumenter.Instrument();

var doc = result.Documents.FirstOrDefault(d => Path.GetFileName(d.Path) == "Samples.cs");
Assert.NotNull(doc);

var found = doc.Lines.Any(l => l.Class == excludedType.FullName);
Assert.False(found, "Class decorated with with exclude attribute should be excluded");

instrumenterTest.Directory.Delete(true);
}

private InstrumenterTest CreateInstrumentor()
{
string module = GetType().Assembly.Location;
string pdb = Path.Combine(Path.GetDirectoryName(module), Path.GetFileNameWithoutExtension(module) + ".pdb");
string identifier = Guid.NewGuid().ToString();

var directory = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), identifier));
DirectoryInfo directory = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), identifier));

File.Copy(module, Path.Combine(directory.FullName, Path.GetFileName(module)), true);
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, Array.Empty<string>(), Array.Empty<string>());
var result = instrumenter.Instrument();
return new InstrumenterTest
{
Instrumenter = instrumenter,
Module = module,
Identifier = identifier,
Directory = directory
};
}

class InstrumenterTest
{
public Instrumenter Instrumenter { get; set; }

public string Module { get; set; }

Assert.Equal(Path.GetFileNameWithoutExtension(module), result.Module);
Assert.Equal(module, result.ModulePath);
public string Identifier { get; set; }

directory.Delete(true);
public DirectoryInfo Directory { get; set; }
}
}
}
30 changes: 30 additions & 0 deletions test/coverlet.core.tests/Samples/Samples.cs
@@ -1,9 +1,11 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Coverlet.Core.Attributes;

namespace Coverlet.Core.Samples.Tests
{
Expand Down Expand Up @@ -161,4 +163,32 @@ public IEnumerable<string> Fetch()
yield return "two";
}
}

[ExcludeFromCoverage]
public class ClassExcludedByCoverletCodeCoverageAttr
{

public string Method(string input)
{
if(string.IsNullOrEmpty(input))
throw new ArgumentException("Cannot be empty", nameof(input));

return input;
}
}

[ExcludeFromCodeCoverage]
public class ClassExcludedByCodeAnalysisCodeCoverageAttr
{

public string Method(string input)
{
if (string.IsNullOrEmpty(input))
throw new ArgumentException("Cannot be empty", nameof(input));

return input;
}
}


}
44 changes: 22 additions & 22 deletions test/coverlet.core.tests/Symbols/CecilSymbolHelperTests.cs
Expand Up @@ -39,8 +39,8 @@ public void GetBranchPoints_OneBranch()
Assert.Equal(points[0].Offset, points[1].Offset);
Assert.Equal(0, points[0].Path);
Assert.Equal(1, points[1].Path);
Assert.Equal(19, points[0].StartLine);
Assert.Equal(19, points[1].StartLine);
Assert.Equal(21, points[0].StartLine);
Assert.Equal(21, points[1].StartLine);
Assert.NotNull(points[1].Document);
Assert.Equal(points[0].Document, points[1].Document);
}
Expand Down Expand Up @@ -86,8 +86,8 @@ public void GetBranchPoints_TwoBranch()
Assert.Equal(4, points.Count());
Assert.Equal(points[0].Offset, points[1].Offset);
Assert.Equal(points[2].Offset, points[3].Offset);
Assert.Equal(25, points[0].StartLine);
Assert.Equal(26, points[2].StartLine);
Assert.Equal(27, points[0].StartLine);
Assert.Equal(28, points[2].StartLine);
}

[Fact]
Expand All @@ -104,8 +104,8 @@ public void GetBranchPoints_CompleteIf()
Assert.NotNull(points);
Assert.Equal(2, points.Count());
Assert.Equal(points[0].Offset, points[1].Offset);
Assert.Equal(32, points[0].StartLine);
Assert.Equal(32, points[1].StartLine);
Assert.Equal(34, points[0].StartLine);
Assert.Equal(34, points[1].StartLine);
}

[Fact]
Expand All @@ -125,10 +125,10 @@ public void GetBranchPoints_Switch()
Assert.Equal(points[0].Offset, points[2].Offset);
Assert.Equal(3, points[3].Path);

Assert.Equal(44, points[0].StartLine);
Assert.Equal(44, points[1].StartLine);
Assert.Equal(44, points[2].StartLine);
Assert.Equal(44, points[3].StartLine);
Assert.Equal(46, points[0].StartLine);
Assert.Equal(46, points[1].StartLine);
Assert.Equal(46, points[2].StartLine);
Assert.Equal(46, points[3].StartLine);
}

[Fact]
Expand All @@ -148,10 +148,10 @@ public void GetBranchPoints_SwitchWithDefault()
Assert.Equal(points[0].Offset, points[2].Offset);
Assert.Equal(3, points[3].Path);

Assert.Equal(58, points[0].StartLine);
Assert.Equal(58, points[1].StartLine);
Assert.Equal(58, points[2].StartLine);
Assert.Equal(58, points[3].StartLine);
Assert.Equal(60, points[0].StartLine);
Assert.Equal(60, points[1].StartLine);
Assert.Equal(60, points[2].StartLine);
Assert.Equal(60, points[3].StartLine);
}

[Fact]
Expand All @@ -171,10 +171,10 @@ public void GetBranchPoints_SwitchWithBreaks()
Assert.Equal(points[0].Offset, points[2].Offset);
Assert.Equal(3, points[3].Path);

Assert.Equal(74, points[0].StartLine);
Assert.Equal(74, points[1].StartLine);
Assert.Equal(74, points[2].StartLine);
Assert.Equal(74, points[3].StartLine);
Assert.Equal(76, points[0].StartLine);
Assert.Equal(76, points[1].StartLine);
Assert.Equal(76, points[2].StartLine);
Assert.Equal(76, points[3].StartLine);
}

[Fact]
Expand All @@ -195,10 +195,10 @@ public void GetBranchPoints_SwitchWithMultipleCases()
Assert.Equal(points[0].Offset, points[3].Offset);
Assert.Equal(3, points[3].Path);

Assert.Equal(92, points[0].StartLine);
Assert.Equal(92, points[1].StartLine);
Assert.Equal(92, points[2].StartLine);
Assert.Equal(92, points[3].StartLine);
Assert.Equal(94, points[0].StartLine);
Assert.Equal(94, points[1].StartLine);
Assert.Equal(94, points[2].StartLine);
Assert.Equal(94, points[3].StartLine);
}

[Fact]
Expand Down

0 comments on commit dd65743

Please sign in to comment.