Skip to content
This repository has been archived by the owner on Nov 15, 2021. It is now read-only.

Commit

Permalink
#169 - skip auto implemented properties
Browse files Browse the repository at this point in the history
  • Loading branch information
sawilde committed Aug 23, 2013
1 parent 73f7432 commit 4ce5341
Show file tree
Hide file tree
Showing 12 changed files with 327 additions and 176 deletions.
Binary file modified main/OpenCover.Documentation/Usage.pdf
Binary file not shown.
334 changes: 174 additions & 160 deletions main/OpenCover.Documentation/Usage.rtf

Large diffs are not rendered by default.

31 changes: 31 additions & 0 deletions main/OpenCover.Framework/CommandLineParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,29 @@

namespace OpenCover.Framework
{
/// <summary>
/// What registration method
/// </summary>
public enum Registration
{
/// <summary>
/// normal
/// </summary>
Normal,

/// <summary>
/// user
/// </summary>
User,

/// <summary>
/// use path to 32 bit profiler
/// </summary>
Path32,

/// <summary>
/// use path to 64 bit profiler
/// </summary>
Path64
}

Expand Down Expand Up @@ -74,6 +92,7 @@ public string Usage()
builder.AppendLine(" [-service]");
builder.AppendLine(" [-threshold:<max count>]");
builder.AppendLine(" [-enableperformancecounters]");
builder.AppendLine(" [-skipautoprops]");
builder.AppendLine(" [-oldStyle]");
builder.AppendLine("or");
builder.AppendLine(" -?");
Expand Down Expand Up @@ -177,6 +196,9 @@ public void ExtractAndValidateArguments()
Threshold = ExtractValue<ulong>("threshold", () =>
{ throw new InvalidOperationException("The threshold must be an integer"); });
break;
case "skipautoprops":
SkipAutoImplementedProperties = true;
break;
case "?":
PrintUsage = true;
break;
Expand Down Expand Up @@ -235,6 +257,7 @@ private static List<SkippedMethod> ExtractSkipped(string skipped)
list.Add(SkippedMethod.File);
list.Add(SkippedMethod.Filter);
list.Add(SkippedMethod.MissingPdb);
list.Add(SkippedMethod.AutoImplementedProperty);
break;
default:
SkippedMethod result;
Expand All @@ -259,6 +282,11 @@ private static List<SkippedMethod> ExtractSkipped(string skipped)
/// </summary>
public Registration Registration { get; private set; }

/// <summary>
/// whether auto-implemented properties sould be skipped
/// </summary>
public bool SkipAutoImplementedProperties { get; private set; }

/// <summary>
/// The target executable that is to be profiles
/// </summary>
Expand Down Expand Up @@ -344,6 +372,9 @@ private static List<SkippedMethod> ExtractSkipped(string skipped)
/// </summary>
public ulong Threshold { get; private set; }

/// <summary>
/// activate trace by test feature
/// </summary>
public bool TraceByTest { get; private set; }

/// <summary>
Expand Down
16 changes: 16 additions & 0 deletions main/OpenCover.Framework/Filter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.RegularExpressions;
using Mono.Cecil;
Expand Down Expand Up @@ -80,6 +81,13 @@ public interface IFilter
/// </summary>
/// <param name="testFilters"></param>
void AddTestFileFilters(string[] testFilters);

/// <summary>
/// Is the method an auto-implemented property get/set
/// </summary>
/// <param name="method"></param>
/// <returns></returns>
bool IsAutoImplementedProperty(MethodDefinition method);
}

internal static class FilterHelper
Expand Down Expand Up @@ -328,5 +336,13 @@ public void AddTestFileFilters(string[] testFilters)
}
}

public bool IsAutoImplementedProperty(MethodDefinition method)
{
if ((method.IsSetter || method.IsGetter) && method.HasCustomAttributes)
{
return method.CustomAttributes.Any(x => x.AttributeType.FullName == typeof(CompilerGeneratedAttribute).FullName);
}
return false;
}
}
}
5 changes: 5 additions & 0 deletions main/OpenCover.Framework/ICommandLine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,10 @@ public interface ICommandLine
/// The type of profiler registration
/// </summary>
Registration Registration { get; }

/// <summary>
/// Should auto implemented properties be skipped
/// </summary>
bool SkipAutoImplementedProperties { get; }
}
}
5 changes: 5 additions & 0 deletions main/OpenCover.Framework/Model/SkippedMethod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,10 @@ public enum SkippedMethod
/// Entity was skipped by inference (usually related to File filters)
/// </summary>
Inferred = 5,

/// <summary>
/// Entity (method) was skipped as it is an auto-implemented property.
/// </summary>
AutoImplementedProperty = 6,
}
}
4 changes: 4 additions & 0 deletions main/OpenCover.Framework/Persistance/BasePersistance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ public virtual void Commit()
RemoveSkippedMethods(SkippedMethod.Attribute);
RemoveEmptyClasses();
break;
case SkippedMethod.AutoImplementedProperty:
RemoveSkippedMethods(SkippedMethod.Attribute);
RemoveEmptyClasses();
break;
}
}
}
Expand Down
26 changes: 14 additions & 12 deletions main/OpenCover.Framework/Symbols/CecilSymbolManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -176,15 +176,15 @@ private static void GetInstrumentableTypes(IEnumerable<TypeDefinition> typeDefin
}
if (typeDefinition.HasNestedTypes)
GetInstrumentableTypes(typeDefinition.NestedTypes, classes, filter, moduleName);
}
}
}


public Method[] GetMethodsForType(Class type, File[] files)
{
var methods = new List<Method>();
IEnumerable<TypeDefinition> typeDefinitions = SourceAssembly.MainModule.Types;
GetMethodsForType(typeDefinitions, type.FullName, methods, files, _filter);
GetMethodsForType(typeDefinitions, type.FullName, methods, files, _filter, _commandLine);
return methods.ToArray();
}

Expand All @@ -201,54 +201,54 @@ private static string GetFirstFile(MethodDefinition definition)
return null;
}

private static void GetMethodsForType(IEnumerable<TypeDefinition> typeDefinitions, string fullName, List<Method> methods, File[] files, IFilter filter)
private static void GetMethodsForType(IEnumerable<TypeDefinition> typeDefinitions, string fullName, List<Method> methods, File[] files, IFilter filter,ICommandLine commandLine)
{
foreach (var typeDefinition in typeDefinitions)
{
if (typeDefinition.FullName == fullName)
{
BuildPropertyMethods(methods, files, filter, typeDefinition);
BuildMethods(methods, files, filter, typeDefinition);
BuildPropertyMethods(methods, files, filter, typeDefinition, commandLine);
BuildMethods(methods, files, filter, typeDefinition, commandLine);
}
if (typeDefinition.HasNestedTypes)
GetMethodsForType(typeDefinition.NestedTypes, fullName, methods, files, filter);
GetMethodsForType(typeDefinition.NestedTypes, fullName, methods, files, filter, commandLine);
}
}

private static void BuildMethods(ICollection<Method> methods, File[] files, IFilter filter, TypeDefinition typeDefinition)
private static void BuildMethods(ICollection<Method> methods, File[] files, IFilter filter, TypeDefinition typeDefinition, ICommandLine commandLine)
{
foreach (var methodDefinition in typeDefinition.Methods)
{
if (methodDefinition.IsAbstract) continue;
if (methodDefinition.IsGetter) continue;
if (methodDefinition.IsSetter) continue;

var method = BuildMethod(files, filter, methodDefinition, false);
var method = BuildMethod(files, filter, methodDefinition, false, commandLine);
methods.Add(method);
}
}

private static void BuildPropertyMethods(ICollection<Method> methods, File[] files, IFilter filter, TypeDefinition typeDefinition)
private static void BuildPropertyMethods(ICollection<Method> methods, File[] files, IFilter filter, TypeDefinition typeDefinition, ICommandLine commandLine)
{
foreach (var propertyDefinition in typeDefinition.Properties)
{
var skipped = filter.ExcludeByAttribute(propertyDefinition);

if (propertyDefinition.GetMethod != null && !propertyDefinition.GetMethod.IsAbstract)
{
var method = BuildMethod(files, filter, propertyDefinition.GetMethod, skipped);
var method = BuildMethod(files, filter, propertyDefinition.GetMethod, skipped, commandLine);
methods.Add(method);
}

if (propertyDefinition.SetMethod != null && !propertyDefinition.SetMethod.IsAbstract)
{
var method = BuildMethod(files, filter, propertyDefinition.SetMethod, skipped);
var method = BuildMethod(files, filter, propertyDefinition.SetMethod, skipped, commandLine);
methods.Add(method);
}
}
}

private static Method BuildMethod(IEnumerable<File> files, IFilter filter, MethodDefinition methodDefinition, bool alreadySkippedDueToAttr)
private static Method BuildMethod(IEnumerable<File> files, IFilter filter, MethodDefinition methodDefinition, bool alreadySkippedDueToAttr, ICommandLine commandLine)
{
var method = new Method();
method.Name = methodDefinition.FullName;
Expand All @@ -262,6 +262,8 @@ private static Method BuildMethod(IEnumerable<File> files, IFilter filter, Metho
method.MarkAsSkipped(SkippedMethod.Attribute);
else if (filter.ExcludeByFile(GetFirstFile(methodDefinition)))
method.MarkAsSkipped(SkippedMethod.File);
else if (commandLine.SkipAutoImplementedProperties && filter.IsAutoImplementedProperty(methodDefinition))
method.MarkAsSkipped(SkippedMethod.AutoImplementedProperty);

var definition = methodDefinition;
method.FileRef = files.Where(x => x.FullPath == GetFirstFile(definition))
Expand Down
18 changes: 15 additions & 3 deletions main/OpenCover.Test/Framework/CommandLineParserTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public void ParserHasKnownDefaultArguments()
Assert.IsFalse(parser.MergeByHash);
Assert.IsFalse(parser.EnablePerformanceCounters);
Assert.IsFalse(parser.TraceByTest);
Assert.IsFalse(parser.SkipAutoImplementedProperties);

}

Expand Down Expand Up @@ -539,7 +540,7 @@ public void ExtractsHideSkipped_ConvertsAll()
parser.ExtractAndValidateArguments();

// assert
Assert.AreEqual(4, parser.HideSkipped.Distinct().Count());
Assert.AreEqual(5, parser.HideSkipped.Distinct().Count());
}

[Test]
Expand All @@ -551,7 +552,7 @@ public void ExtractsHideSkipped_Merges_AllFile()
parser.ExtractAndValidateArguments();

// assert
Assert.AreEqual(4, parser.HideSkipped.Distinct().Count());
Assert.AreEqual(5, parser.HideSkipped.Distinct().Count());
}

[Test]
Expand All @@ -575,8 +576,19 @@ public void ExtractsHideSkipped_DefaultsToAll()
parser.ExtractAndValidateArguments();

// assert
Assert.AreEqual(4, parser.HideSkipped.Distinct().Count());
Assert.AreEqual(5, parser.HideSkipped.Distinct().Count());
}

[Test]
public void Extracts_SkipAutoImplementedProperties()
{
// arrange
var parser = new CommandLineParser(new[] { "-skipautoprops", RequiredArgs });

parser.ExtractAndValidateArguments();

// assert
Assert.IsTrue(parser.SkipAutoImplementedProperties);
}
}
}
30 changes: 29 additions & 1 deletion main/OpenCover.Test/Framework/FilterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -546,7 +546,35 @@ public void Handles_Issue117()
mockDefinition.SetupGet(x => x.Name).Returns("<>f_ddd");
mockDefinition.SetupGet(x => x.DeclaringType).Returns(new TypeDefinition("","f_ddd", TypeAttributes.Public));

filter.ExcludeByAttribute(mockDefinition.Object);
Assert.DoesNotThrow(() => filter.ExcludeByAttribute(mockDefinition.Object));
}

[Test]
public void CanIdentify_AutoImplementedProperties()
{
// arrange
var sourceAssembly = AssemblyDefinition.ReadAssembly(typeof(Samples.Concrete).Assembly.Location);
var type = sourceAssembly.MainModule.Types.First(x => x.FullName == typeof(Samples.DeclaredMethodClass).FullName);

// act/assert
var filter = new Filter();
var wasTested = false;
foreach (var methodDefinition in type.Methods
.Where(x => x.IsGetter || x.IsSetter).Where(x => x.Name.EndsWith("AutoProperty")))
{
wasTested = true;
Assert.IsTrue(filter.IsAutoImplementedProperty(methodDefinition));
}
Assert.IsTrue(wasTested);

wasTested = false;
foreach (var methodDefinition in type.Methods
.Where(x => x.IsGetter || x.IsSetter).Where(x => x.Name.EndsWith("PropertyWithBackingField")))
{
wasTested = true;
Assert.IsFalse(filter.IsAutoImplementedProperty(methodDefinition));
}
Assert.IsTrue(wasTested);
}
}
}
27 changes: 27 additions & 0 deletions main/OpenCover.Test/Framework/Symbols/CecilSymbolManagerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,33 @@ public void Can_Exclude_A_Method_By_An_FileFilter()
Assert.True(methods.First(y => y.Name.EndsWith("::Method()")).SkippedDueTo == SkippedMethod.File);
}

[Test]
public void Can_Exclude_AutoImplmentedProperties()
{
// arrange
var filter = new Filter();
_mockFilter
.Setup(x => x.InstrumentClass(It.IsAny<string>(), It.IsAny<string>()))
.Returns(true);

_mockFilter
.Setup(x => x.IsAutoImplementedProperty(It.IsAny<MethodDefinition>()))
.Returns<MethodDefinition>(x => filter.IsAutoImplementedProperty(x));

_mockCommandLine.Setup(x => x.SkipAutoImplementedProperties).Returns(true);

var types = _reader.GetInstrumentableTypes();
var target = types.First(x => x.FullName == typeof(DeclaredMethodClass).FullName);

// act
var methods = _reader.GetMethodsForType(target, new File[0]);

// assert
Assert.True(methods.Any());
Assert.AreEqual(SkippedMethod.AutoImplementedProperty, methods.First(y => y.Name.EndsWith("AutoProperty()")).SkippedDueTo);
Assert.AreEqual((SkippedMethod)0, methods.First(y => y.Name.EndsWith("PropertyWithBackingField()")).SkippedDueTo);
}

[Test]
public void GetTrackedMethods_NoTrackedMethods_When_NoStrategies()
{
Expand Down
7 changes: 7 additions & 0 deletions main/OpenCover.Test/Samples/Samples.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,17 @@ public bool HasSwitch(int input)

class DeclaredMethodClass
{
private string _propertyWithBackingField;
void Method() {}

string AutoProperty { get; set;}

string PropertyWithBackingField
{
get { return _propertyWithBackingField; }
set { _propertyWithBackingField = value; }
}

void DoThing(Action<object> doThing)
{
doThing(1);
Expand Down

0 comments on commit 4ce5341

Please sign in to comment.