sawilde/opencover — Issue #57: Value types (structs) are filtered out from coverage report
Author: ldelabre
Created: 2011-12-07 07:29:13+00:00
State: open

Enums, like structs, are being filtered out from the coverage report:
https://github.com/sawilde/opencover/commit/9b9c025a5728991cc3d3fd2ab72334cad48b891f

While it's understandable for enums (they don't have instrumentable code) ; it can sometimes be wrong for structs, which can contains code just like any other classes.

Here's a (rather stupid) example I came up with for the need of instrumentation of value types :

```csharp
namespace WhyNotStruct
{
using NUnit.Framework;

public class ZeClass
{
private int value;

public ZeClass(int value)
{
this.value = value;
}

public override bool Equals(object obj)
{
ZeClass c;

if (!(obj is ZeClass))
{
return false;
}

if (object.ReferenceEquals(this, obj))
{
return true;
}

c = (ZeClass)obj;
return c.value == this.value;
}
}

[TestFixture]
public class ZeFixture
{
[Test]
public void ZeClassEqualsZeClassWithSameValueReturnsTrue()
{
Assert.That(new ZeClass(20).Equals(new ZeClass(20)), Is.True);
}

[Test]
public void ZeClassEqualsZeClassWithDifferentValueReturnsFalse()
{
Assert.That(new ZeClass(20).Equals(new ZeClass(-1)), Is.False);
}

[Test]
public void ZeClassEqualsObjectReturnsFalse()
{
Assert.That(new ZeClass(20).Equals(new object()), Is.False);
}

[Test]
public void ZeClassEqualsSameInstanceReturnsTrue()
{
ZeClass c;

c = new ZeClass(10);
Assert.That(c.Equals(c), Is.True);
}
}

}
```

All tests pass ok and both sequence and branch coverages are 100%.

Now, what if you changes ZeClass into a struct ?
Well, all tests passes ok. But you never enter the branch of object.ReferenceEquals(this, obj) !
Put a throw instead of return true the unit tests keep showing all green !

```csharp
namespace WhyNotStruct
{
using NUnit.Framework;

public struct ZeClass
{
private int value;

public ZeClass(int value)
{
this.value = value;
}

public override bool Equals(object obj)
{
ZeClass c;

if (!(obj is ZeClass))
{
return false;
}

if (object.ReferenceEquals(this, obj))
{
throw new System.NotImplementedException();
}

c = (ZeClass)obj;
return c.value == this.value;
}
}

[TestFixture]
public class ZeFixture
{
[Test]
public void ZeClassEqualsZeClassWithSameValueReturnsTrue()
{
Assert.That(new ZeClass(20).Equals(new ZeClass(20)), Is.True);
}

[Test]
public void ZeClassEqualsZeClassWithDifferentValueReturnsFalse()
{
Assert.That(new ZeClass(20).Equals(new ZeClass(-1)), Is.False);
}

[Test]
public void ZeClassEqualsObjectReturnsFalse()
{
Assert.That(new ZeClass(20).Equals(new object()), Is.False);
}

[Test]
public void ZeClassEqualsSameInstanceReturnsTrue()
{
ZeClass c;

c = new ZeClass(10);
Assert.That(c.Equals(c), Is.True);
}
}

}
```

Structs should only be filtered out when no instrumentable code can be found.