Skip to content

Commit

Permalink
Merge branch 'develop/Caba' into release/Caba
Browse files Browse the repository at this point in the history
  • Loading branch information
SteveGilham committed May 12, 2018
2 parents 32154e0 + daed8df commit 827df67
Show file tree
Hide file tree
Showing 16 changed files with 191 additions and 88 deletions.
15 changes: 4 additions & 11 deletions AltCover.Recorder/AltCover.Recorder.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,6 @@
</Otherwise>
</Choose>
<Import Project="$(FSharpTargetsPath)" Condition="Exists('$(FSharpTargetsPath)')" />
<Import Project="..\packages\FSharpLint.MSBuild.0.9.0\build\FSharpLint.MSBuild.targets" Condition="Exists('..\packages\FSharpLint.MSBuild.0.9.0\build\FSharpLint.MSBuild.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\FSharpLint.MSBuild.0.9.0\build\FSharpLint.MSBuild.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\FSharpLint.MSBuild.0.9.0\build\FSharpLint.MSBuild.targets'))" />
</Target>
<ItemGroup>
<Compile Include="AssemblyInfo.fs" />
<Compile Include="..\_Generated\AssemblyVersion.fs">
Expand All @@ -97,21 +90,21 @@
<Reference Include="System" />
<Reference Include="System.Xml" />
</ItemGroup>
<Import Project="..\packages\FSharpLint.MSBuild.0.9.1-beta\build\FSharpLint.MSBuild.targets" Condition="Exists('..\packages\FSharpLint.MSBuild.0.9.1-beta\build\FSharpLint.MSBuild.targets')" />
<!-- Import Project="..\packages\FSharpLint.MSBuild.0.9.1-beta\build\FSharpLint.MSBuild.targets" Condition="Exists('..\packages\FSharpLint.MSBuild.0.9.1-beta\build\FSharpLint.MSBuild.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\FSharpLint.MSBuild.0.9.1-beta\build\FSharpLint.MSBuild.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\FSharpLint.MSBuild.0.9.1-beta\build\FSharpLint.MSBuild.targets'))" />
</Target>
</Target -->
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
<Target Name="FSharpLint" BeforeTargets="AfterBuild" Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' AND '$(FSharpLintEnabled)' != 'false'">
<!-- Target Name="FSharpLint" BeforeTargets="AfterBuild" Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' AND '$(FSharpLintEnabled)' != 'false'">
<FSharpLintTask Project="$(MSBuildProjectFullPath)" TreatWarningsAsErrors="true" />
</Target>
</Target -->
</Project>
7 changes: 7 additions & 0 deletions AltCover.Recorder/Base.fs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ type internal Track =
| Call of int
| Both of (int64 * int)

module Assist =
let internal SafeDispose x =
try
(x :> IDisposable).Dispose()
with
| :? ObjectDisposedException -> ()

module Counter =
/// <summary>
/// The offset flag for branch counts
Expand Down
13 changes: 7 additions & 6 deletions AltCover.Recorder/Recorder.fs
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ module Instance =
FlushAll ()
channel.Reply ()
mailboxOK <- false
(inbox :> IDisposable).Dispose()
Assist.SafeDispose inbox
}

let internal MakeMailbox () =
Expand Down Expand Up @@ -265,12 +265,11 @@ module Instance =
let internal PayloadSelector enable =
PayloadControl Granularity enable

let mutable internal Wait = 10
let mutable internal Capacity = 127
let mutable internal Capacity = 1023

let UnbufferedVisit (f: unit -> bool) =
if f() then
mailbox.TryPostAndReply ((fun c -> Item (buffer |> Seq.toArray, c)), Wait) |> ignore
mailbox.PostAndReply (fun c -> Item (buffer |> Seq.toArray, c))
else buffer |> Seq.toArray |> Array.toSeq |> AsyncItem |> mailbox.Post

let internal VisitSelection (f: unit -> bool) track moduleId hitPointId =
Expand All @@ -289,14 +288,16 @@ module Instance =

let Visit moduleId hitPointId =
if Recording && mailboxOK then
VisitSelection (fun () -> trace.IsConnected() || Backlog() > 10)
VisitSelection (fun () -> trace.IsConnected() || Backlog() > 0)
(PayloadSelector IsOpenCoverRunner) moduleId hitPointId

let internal FlushCounter (finish:Close) _ =
if mailboxOK then
Recording <- finish = Resume
lock (buffer) (fun () ->
if not Recording then UnbufferedVisit (fun _ -> true)
buffer.Clear()
buffer.Clear())
mailbox.TryPostAndReply ((fun c -> Finish (finish, c)), 2000) |> ignore

let internal AddErrorHandler (box:MailboxProcessor<'a>) =
Expand All @@ -307,7 +308,7 @@ module Instance =

let internal RunMailbox () =
Recording <- true
(mailbox :> IDisposable).Dispose()
Assist.SafeDispose mailbox
mailbox <- MakeMailbox ()
mailboxOK <- true
AddErrorHandler mailbox
Expand Down
4 changes: 3 additions & 1 deletion AltCover/AltCover.fs
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,9 @@ module Main =
result

let internal Main arguments =
if "Runner".StartsWith(arguments |> Seq.head, StringComparison.OrdinalIgnoreCase)
let first = arguments |> Seq.tryHead |> Option.getOrElse String.Empty
if (first |> String.IsNullOrWhiteSpace |> not) &&
"Runner".StartsWith(first, StringComparison.OrdinalIgnoreCase)
then Runner.init()
Runner.DoCoverage arguments (DeclareOptions())
else init()
Expand Down
8 changes: 4 additions & 4 deletions AltCover/AltCover.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -137,21 +137,21 @@
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq" />
</ItemGroup>
<Import Project="..\packages\FSharpLint.MSBuild.0.9.1-beta\build\FSharpLint.MSBuild.targets" Condition="Exists('..\packages\FSharpLint.MSBuild.0.9.1-beta\build\FSharpLint.MSBuild.targets')" />
<!-- Import Project="..\packages\FSharpLint.MSBuild.0.9.1-beta\build\FSharpLint.MSBuild.targets" Condition="Exists('..\packages\FSharpLint.MSBuild.0.9.1-beta\build\FSharpLint.MSBuild.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\FSharpLint.MSBuild.0.9.1-beta\build\FSharpLint.MSBuild.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\FSharpLint.MSBuild.0.9.1-beta\build\FSharpLint.MSBuild.targets'))" />
</Target>
</Target -->
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
<Target Name="FSharpLint" BeforeTargets="AfterBuild" Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' AND '$(FSharpLintEnabled)' != 'false'">
<!-- Target Name="FSharpLint" BeforeTargets="AfterBuild" Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' AND '$(FSharpLintEnabled)' != 'false'">
<FSharpLintTask Project="$(MSBuildProjectFullPath)" TreatWarningsAsErrors="true" />
</Target>
</Target -->
</Project>
1 change: 1 addition & 0 deletions AltCover/CommandLine.fs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ module Output =

[<CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2202", Justification="Multiple Close() should be safe")>]
let LogExceptionToFile path e =
Directory.CreateDirectory(path |> Path.GetDirectoryName) |> ignore
use stream = File.Open(path, FileMode.Append, FileAccess.Write)
use writer = new StreamWriter(stream)

Expand Down
84 changes: 64 additions & 20 deletions AltCover/Visitor.fs
Original file line number Diff line number Diff line change
Expand Up @@ -277,39 +277,79 @@ module Visitor =
MethodNumber <- id
(id, n))

let private CSharpDeclaringMethod (name:string) (source:TypeDefinition)
(target:TypeDefinition) index =
let private CSharpContainingMethod (name:string) (ct:TypeDefinition) index predicate =
let stripped = name.Substring(1, index)
let candidates = target.Methods
let methods = ct.Methods
let candidates = methods
|> Seq.filter (fun mx -> (mx.Name = stripped) && mx.HasBody)
|> Seq.toList
match candidates with
| [x] -> Some x
| _ -> candidates
|> Seq.tryFind(fun m -> m.Body.Instructions
|> Seq.filter(fun i -> i.OpCode = OpCodes.Newobj)
|> Seq.exists(fun i -> let tn = (i.Operand :?> MethodReference).DeclaringType
tn = (source :> TypeReference)))

let private FSharpDeclaringMethod (t:TypeDefinition) (tx:TypeReference) =
| _ -> let tag = "<" + stripped + ">"
candidates.Concat(methods
|> Seq.filter (fun mx -> (mx.Name.IndexOf(tag, StringComparison.Ordinal) >=0)
&& mx.HasBody)).Concat (
ct.NestedTypes
|> Seq.filter (fun tx -> tx.Name.StartsWith("<", StringComparison.Ordinal))
|> Seq.collect (fun tx -> tx.Methods)
|> Seq.filter (fun mx -> mx.HasBody &&
(mx.Name.IndexOf(tag, StringComparison.Ordinal) >=0 ||
mx.DeclaringType.Name.IndexOf(tag, StringComparison.Ordinal) >=0)))
|> Seq.tryFind predicate

let SameType (target:TypeReference) (candidate:TypeReference) =
if target = candidate then true
else if target.HasGenericParameters then
let cname = candidate.FullName
let last = cname.LastIndexOf('<')
if last < 0 then false
else let stripped = cname.Substring(0, last)
let tname = target.FullName
stripped.Equals(tname)
else false

let SameFunction (target:MethodReference) (candidate:MethodReference) =
if target = candidate then true
else if SameType target.DeclaringType candidate.DeclaringType then
let cname = candidate.Name
let tname = target.Name
tname.Equals cname
else false

let MethodConstructsType (t:TypeReference) (m:MethodDefinition) =
m.Body.Instructions
|> Seq.filter(fun i -> i.OpCode = OpCodes.Newobj)
|> Seq.exists(fun i -> let tn = (i.Operand :?> MethodReference).DeclaringType
SameType t tn)

let private FSharpContainingMethod (t:TypeDefinition) (tx:TypeReference) =
let candidates = t.DeclaringType.Methods.Concat
(t.DeclaringType.NestedTypes
|> Seq.filter (fun t2 -> (t2 :> TypeReference) <> tx)
|> Seq.collect (fun t2 -> t2.Methods))
|> Seq.filter (fun m -> m.HasBody)

candidates
|> Seq.tryFind(fun m -> m.Body.Instructions
|> Seq.filter(fun i -> i.OpCode = OpCodes.Newobj)
|> Seq.exists(fun i -> let tn = (i.Operand :?> MethodReference).DeclaringType
tn = tx))
|> Seq.tryFind (MethodConstructsType tx)

let MethodCallsMethod (t:MethodReference) (m:MethodDefinition) =
m.Body.Instructions
|> Seq.filter(fun i -> i.OpCode = OpCodes.Call)
|> Seq.exists(fun i -> let tn = (i.Operand :?> MethodReference)
SameFunction t tn)

let MethodLoadsMethod (t:MethodReference) (m:MethodDefinition) =
m.Body.Instructions
|> Seq.filter(fun i -> i.OpCode = OpCodes.Ldftn)
|> Seq.exists(fun i -> let tn = (i.Operand :?> MethodReference)
SameFunction t tn)

let internal DeclaringMethod (m:MethodDefinition) =
let internal ContainingMethod (m:MethodDefinition) =
let mname = m.Name
let t = m.DeclaringType
if mname.StartsWith("<", StringComparison.Ordinal) && mname.IndexOf('|') > 0 then
let index = mname.IndexOf('>') - 1
CSharpDeclaringMethod mname t t index
CSharpContainingMethod mname t index (MethodCallsMethod m)
else
let n = t.Name
if t.IsNested |> not then
Expand All @@ -321,7 +361,9 @@ module Visitor =

let index = name.IndexOf('>') - 1
if (index < 1) then None
else CSharpDeclaringMethod name t t.DeclaringType index
else CSharpContainingMethod name t.DeclaringType index
(fun mx -> MethodConstructsType t mx ||
MethodLoadsMethod m mx)
else if n.IndexOf('@') >= 0 then
let tx = if n.EndsWith("T", StringComparison.Ordinal)
then match t.Methods |> Seq.tryFind (fun m -> m.IsConstructor && m.HasParameters && (m.Parameters.Count = 1))
Expand All @@ -330,7 +372,7 @@ module Visitor =
| Some other -> other.ParameterType

else t :> TypeReference
FSharpDeclaringMethod t tx
FSharpContainingMethod t tx
else None

let private VisitType (t:TypeDefinition) included buildSequence =
Expand All @@ -343,7 +385,7 @@ module Visitor =
|> Seq.collect ((fun m -> let methods = Seq.unfold (fun (state:MethodDefinition option) ->
match state with
| None -> None
| Some x -> Some (x, DeclaringMethod x)) (Some m)
| Some x -> Some (x, ContainingMethod x)) (Some m)
let inclusion = Seq.fold UpdateInspection
included
methods
Expand Down Expand Up @@ -420,7 +462,9 @@ module Visitor =
|> Seq.filter (fun _ -> dbg |> isNull |> not)
|> Seq.concat
|> Seq.filter (fun (i:Instruction) -> i.OpCode.FlowControl = FlowControl.Cond_Branch)
|> Seq.skip skip
|> Seq.mapi (fun n i -> (n, i)) //
|> Seq.filter (fun (n, _) -> n >= skip) // like skip, but OK if there aren't enough elements
|> Seq.map snd //
|> Seq.map (fun (i:Instruction) -> getJumps dbg i // if two or more jumps go between the same two places, coalesce them
|> List.groupBy (fun (_,_,o,_) -> o)
|> List.map (fun (_,records) ->
Expand Down
4 changes: 2 additions & 2 deletions Build/targets.fsx
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ Target "UnitTest" (fun _ ->
numeric))
|> Seq.toList

if numbers |> List.tryFind (fun n -> n >= 90.0) |> Option.isNone && numbers |> List.length > 2 then
if numbers |> List.tryFind (fun n -> n <= 99.0) |> Option.isSome then
Assert.Fail("Coverage is too low")
)

Expand Down Expand Up @@ -755,7 +755,7 @@ Target "UnitTestWithAltCoverCoreRunner" (fun _ ->

printfn "Instrument the XUnit tests"
let xDir = "_Binaries/AltCover.XTests/Debug+AnyCPU/netcoreapp2.0"
let xReport = reports @@ "XTestWithAltCoverCore.xml"
let xReport = reports @@ "XTestWithAltCoverCoreRunner.xml"
let xOut = Path.getFullName "XTests/_Binaries/AltCover.XTests/Debug+AnyCPU/netcoreapp2.0"
Shell.cleanDir xOut

Expand Down
7 changes: 7 additions & 0 deletions ReleaseNotes.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
# 3.0.475 (Caba series release 11)
* Fine tune the speed-up in data collection (marginal improvements only)
* [BUGFIX] -- some corner cases for nested functions (including uses of generics) were not being detected for purposes of exclusion by containing function
* [BUGFIX] -- Issue #17 : restore intended behaviour when no arguments supplied
* [BUGFIX] -- Issue #18 : protect against certain degenerate cases when looking for branch coverage
* other minor build process changes

# 3.0.466 (Caba series release 10)
* Support for starting/pausing/resuming coverage collection during operation -- see https://github.com/SteveGilham/altcover/wiki/Pause%E2%95%B1Resume-and-the-Control-File
* Major speed-up in data collection by reducing the amount of synchronization being done while writing data to file -- this means significant reductions in the time taken for instrumented code to execute
Expand Down
28 changes: 22 additions & 6 deletions Sample5/Class1.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ int Recursive(int c)
return input.Select(x =>
{
var l = new List<char> { x };
return Interior(l.Select(c => f(c)).Last(), 6);
return Interior(l.Select(f).Last(), 6);
}).Sum();
}

Expand Down Expand Up @@ -61,15 +61,20 @@ private class Inner
public int G1(string input)
{
// function Sample5.Class1+Inner+<>c.<G1>b__0_0
Func<char, int> f = (c => { return (int)c; });
Func<char, int> f = (c => { return 5 + (int)c; });

T[] InteriorToArray<T>(T v)
{
return new[] { v };
}

// function Sample5.Class1.<F1>g__Interior|0_1
int Interior(int a, int b)
{
// Sample5.Class1.<F1>g__Recursive|0_3
int Recursive(int c)
{
return c * c;
return c * c * InteriorToArray(c).Length;
}

return Recursive(a) % b;
Expand All @@ -80,20 +85,31 @@ int Recursive(int c)
return input.Select(x =>
{
var l = new List<char> { x };
return Interior(l.Select(c => f(c)).Last(), 6);
return Interior(l.Select(f).Last(), 6);
}).Sum();
}

public void G1(int label)
{
Console.WriteLine(2 * label);
}

[ExcludeFromCodeCoverage]
public IEnumerable<int> G2(string input)
public IEnumerable<T> G2<T>(T input)
{
// class Sample5.Class1+Inner+<G2>d__1
foreach (char c in input)
var source = new[] { input };
foreach (var c in source)
{
yield return c;
}
}

public void G2(int label)
{
Console.WriteLine(2 * label);
}

[ExcludeFromCodeCoverage]
public async Task<string> G3(string input)
{
Expand Down
3 changes: 2 additions & 1 deletion Sample6/Library1.fs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ open System.Net

module Module =
let F1 l =
let aux i = i + 1
let FI li =
let rec FII lii acc =
match lii with
| [] -> acc
| x::xs -> FII xs (acc + 1)
| x::xs -> FII xs (aux acc)
FII li 0

l
Expand Down
Loading

0 comments on commit 827df67

Please sign in to comment.