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

Commit

Permalink
Merge pull request #770 from SteveGilham/feature-issue-615-f#-nonpubl…
Browse files Browse the repository at this point in the history
…ic-types

Feature issue 615 f# nonpublic types
  • Loading branch information
sawilde committed Dec 2, 2017
2 parents 15373d9 + 81286d9 commit 43b354f
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 29 deletions.
15 changes: 9 additions & 6 deletions main/OpenCover.Framework/Filter.cs
Expand Up @@ -379,26 +379,29 @@ public bool IsFSharpInternal(MethodDefinition method)
{
// expect 01, 00, 01, 00, 00, 00, 00, 00 or 01, 00, 02, 00, 00, 00, 00, 00
var y = x.GetBlob();
if(y.Length != 8 || y[0] != 1 || y[1] != 0 || y.Skip(3).Any(z => z!=0))
if (y.Length != 8 || y[0] != 1 || y[1] != 0 || y.Skip(3).Any(z => z != 0))
{
return false;
}
return y[2].Equals(1) // sum
|| y[2].Equals(2); // record
// Mask out the class kind from its public/non-public state
// SourceConstructFlags.NonPublicRepresentation = 32
// SourceConstructFlags.KindMask = 31
return (y[2] & 31).Equals(1) // SourceConstructFlags.SumType = 1
|| (y[2] & 31).Equals(2); // SourceConstructFlags.RecordType = 2
}).ToList();

var fieldGetter = false;
if(method.IsGetter)
if (method.IsGetter)
{
// record type has getters marked as field
var owner = method.DeclaringType.Properties
.Where(x => x.GetMethod == method)
.First();
if(owner.HasCustomAttributes)
if (owner.HasCustomAttributes)
{
fieldGetter = owner.CustomAttributes.Where(x => x.AttributeType.FullName == "Microsoft.FSharp.Core.CompilationMappingAttribute")
.Any(x => x.GetBlob()[2] == 4); // Field
.Any(x => (x.GetBlob()[2] & 31) == 4); // SourceConstructFlags.Field = 4
}
}

Expand Down
61 changes: 38 additions & 23 deletions main/OpenCover.Test/Framework/FilterTests.cs
Expand Up @@ -569,34 +569,49 @@ public void Can_Identify_Excluded_Properties()
}
}

[Test]
public void Can_Identify_Excluded_FSharp_Methods()
{
var location = System.IO.Path.Combine(
System.IO.Path.GetDirectoryName(this.GetType().Assembly.Location),
@"Samples\Library1.dll");
[Test]
public void Can_Identify_Excluded_FSharp_Methods()
{
var location = System.IO.Path.Combine(
System.IO.Path.GetDirectoryName(this.GetType().Assembly.Location),
@"Samples\Library1.dll");
var sourceAssembly = AssemblyDefinition.ReadAssembly(location);

var direct = sourceAssembly.MainModule.Types.ToList();
var indirect = direct
.Where(t => t.HasNestedTypes).SelectMany(t => t.NestedTypes).ToList(); // MyUnion, MyThing
var indirect2 = indirect.Where(t => t.HasNestedTypes).SelectMany(t => t.NestedTypes).ToList(); // Foo, Bar, ...
Assert.That(
indirect2.Where(t => t.HasNestedTypes).SelectMany(t => t.NestedTypes).ToList(),
Is.Empty);

var filter = new Filter(false);
var pass = direct.Concat(indirect).Concat(indirect2).SelectMany(x => x.Methods)
.Where(x => !filter.IsFSharpInternal(x))
.Select(x => x.Name)
.OrderBy(x => x)
.ToList();

var expected = new[] { "as_bar", "bytes", "makeThing", "returnBar", "returnFoo", "testMakeThing", "testMakeUnion" };

Assert.That(pass, Is.EquivalentTo(expected));
Identify_FSharp_Methods(sourceAssembly, expected);
}

[Test]
public void Can_Identify_Excluded_FSharp_NonPublic_Methods()
{
var location = System.IO.Path.Combine(
System.IO.Path.GetDirectoryName(this.GetType().Assembly.Location),
@"Samples\Library2.dll");
var sourceAssembly = AssemblyDefinition.ReadAssembly(location);
var expected = new[] { "as_bar", "bytes", "makeThing", "returnBar", "returnFoo", "testMakeThing2", "testMakeUnion2" };

Identify_FSharp_Methods(sourceAssembly, expected);
}

private static void Identify_FSharp_Methods(AssemblyDefinition sourceAssembly, string[] expected)
{
var direct = sourceAssembly.MainModule.Types.ToList();
var indirect = direct
.Where(t => t.HasNestedTypes).SelectMany(t => t.NestedTypes).ToList(); // MyUnion, MyThing
var indirect2 = indirect.Where(t => t.HasNestedTypes).SelectMany(t => t.NestedTypes).ToList(); // Foo, Bar, ...
Assert.That(
indirect2.Where(t => t.HasNestedTypes).SelectMany(t => t.NestedTypes).ToList(),
Is.Empty);

var filter = new Filter(false);
var pass = direct.Concat(indirect).Concat(indirect2).SelectMany(x => x.Methods)
.Where(x => !filter.IsFSharpInternal(x))
.Select(x => x.Name)
.OrderBy(x => x)
.ToList();

Assert.That(pass, Is.EquivalentTo(expected));
}

[Test]
public void Can_Identify_Excluded_Anonymous_Issue99()
Expand Down
7 changes: 7 additions & 0 deletions main/OpenCover.Test/OpenCover.Test.csproj
Expand Up @@ -212,6 +212,13 @@
<None Include="Samples\Library1.pdb">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Samples\Library2.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Samples\Library2.fs" />
<None Include="Samples\Library2.pdb">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<Content Include="Samples\ReadMe.txt" />
</ItemGroup>
<ItemGroup>
Expand Down
Binary file added main/OpenCover.Test/Samples/Library2.dll
Binary file not shown.
29 changes: 29 additions & 0 deletions main/OpenCover.Test/Samples/Library2.fs
@@ -0,0 +1,29 @@
namespace N
open NUnit.Framework
module M =
type private Thing = { Thing: string } with
member this.bytes () = System.Text.Encoding.UTF8.GetBytes(this.Thing)
let private makeThing s = { Thing = s }

[<Test>]
let testMakeThing2() =
Assert.AreEqual("s", (makeThing "s").Thing)
Assert.AreEqual(5, (makeThing "aeiou").bytes().Length)

module DU =
type private MyUnion =
| Foo of int
| Bar of string
with member this.as_bar() = match this with
| Foo n -> Bar (string n)
| bar -> bar

let private returnFoo v = Foo v

let private returnBar v = Bar v

[<Test>]
let testMakeUnion2() =
Assert.AreEqual(returnFoo 10, Foo 10)
Assert.AreEqual(returnBar "s", Bar "s")
Assert.AreEqual(Bar "10", (Foo 10).as_bar())
Binary file added main/OpenCover.Test/Samples/Library2.pdb
Binary file not shown.

0 comments on commit 43b354f

Please sign in to comment.