Compare commits

..

5 Commits

Author SHA1 Message Date
Smaug123
8f0e8d6369 Failing test 2025-09-17 08:51:36 +01:00
Smaug123
e7780dc412 Docs 2025-09-17 08:49:23 +01:00
Smaug123
c3311bd350 README 2025-09-17 08:43:33 +01:00
Smaug123
07e9eaff38 Implement 2025-09-17 08:37:41 +01:00
Smaug123
2c539c13a3 Capturing mock 2025-09-16 23:33:35 +01:00
6 changed files with 264 additions and 825 deletions

View File

@@ -9,285 +9,180 @@ namespace SomeNamespace.CapturingMock
open System
open WoofWare.Myriad.Plugins
[<RequireQualifiedAccess>]
module internal PublicTypeMockCalls =
/// All the calls made to a PublicTypeMock mock
type internal Calls =
{
Mem1 : ResizeArray<string * int>
Mem2 : ResizeArray<string>
Mem3 : ResizeArray<int * System.Threading.CancellationToken option>
}
/// A fresh calls object which has not yet had any calls made.
static member Empty () : Calls =
{
Mem1 = ResizeArray ()
Mem2 = ResizeArray ()
Mem3 = ResizeArray ()
}
/// Mock record type for an interface
type internal PublicTypeMock =
{
Calls : PublicTypeMockCalls.Calls
Mem1 : string * int -> string list
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
Mem1_Calls : ResizeArray<string * int>
Mem2 : string -> int
Mem3 : int * System.Threading.CancellationToken option -> string
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
Mem2_Calls : ResizeArray<string>
Mem3 : int * option<System.Threading.CancellationToken> -> string
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
Mem3_Calls : ResizeArray<int * System.Threading.CancellationToken>
}
/// An implementation where every non-unit method throws.
static member Empty : PublicTypeMock =
{
Calls = PublicTypeMockCalls.Calls.Empty ()
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
Mem3 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem3"))
Mem1_Calls = ResizeArray ()
Mem2_Calls = ResizeArray ()
Mem3_Calls = ResizeArray ()
}
interface IPublicType with
member this.Mem1 (arg_0_0, arg_0_1) =
lock this.Calls.Mem1 (fun _ -> this.Calls.Mem1.Add (arg_0_0, arg_0_1))
this.Mem1 (arg_0_0, arg_0_1)
member this.Mem2 arg_0_0 =
lock this.Calls.Mem2 (fun _ -> this.Calls.Mem2.Add (arg_0_0))
this.Mem2 (arg_0_0)
member this.Mem3 (arg_0_0, arg_0_1) =
lock this.Calls.Mem3 (fun _ -> this.Calls.Mem3.Add (arg_0_0, arg_0_1))
this.Mem3 (arg_0_0, arg_0_1)
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0)
member this.Mem3 (arg_0_0, arg_0_1) = this.Mem3 (arg_0_0, arg_0_1)
namespace SomeNamespace.CapturingMock
open System
open WoofWare.Myriad.Plugins
[<RequireQualifiedAccess>]
module public PublicTypeInternalFalseMockCalls =
/// All the calls made to a PublicTypeInternalFalseMock mock
type public Calls =
{
Mem1 : ResizeArray<string * int>
Mem2 : ResizeArray<string>
Mem3 : ResizeArray<int * System.Threading.CancellationToken option>
}
/// A fresh calls object which has not yet had any calls made.
static member Empty () : Calls =
{
Mem1 = ResizeArray ()
Mem2 = ResizeArray ()
Mem3 = ResizeArray ()
}
/// Mock record type for an interface
type public PublicTypeInternalFalseMock =
{
Calls : PublicTypeInternalFalseMockCalls.Calls
Mem1 : string * int -> string list
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
Mem1_Calls : ResizeArray<string * int>
Mem2 : string -> int
Mem3 : int * System.Threading.CancellationToken option -> string
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
Mem2_Calls : ResizeArray<string>
Mem3 : int * option<System.Threading.CancellationToken> -> string
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
Mem3_Calls : ResizeArray<int * System.Threading.CancellationToken>
}
/// An implementation where every non-unit method throws.
static member Empty : PublicTypeInternalFalseMock =
{
Calls = PublicTypeInternalFalseMockCalls.Calls.Empty ()
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
Mem3 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem3"))
Mem1_Calls = ResizeArray ()
Mem2_Calls = ResizeArray ()
Mem3_Calls = ResizeArray ()
}
interface IPublicTypeInternalFalse with
member this.Mem1 (arg_0_0, arg_0_1) =
lock this.Calls.Mem1 (fun _ -> this.Calls.Mem1.Add (arg_0_0, arg_0_1))
this.Mem1 (arg_0_0, arg_0_1)
member this.Mem2 arg_0_0 =
lock this.Calls.Mem2 (fun _ -> this.Calls.Mem2.Add (arg_0_0))
this.Mem2 (arg_0_0)
member this.Mem3 (arg_0_0, arg_0_1) =
lock this.Calls.Mem3 (fun _ -> this.Calls.Mem3.Add (arg_0_0, arg_0_1))
this.Mem3 (arg_0_0, arg_0_1)
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0)
member this.Mem3 (arg_0_0, arg_0_1) = this.Mem3 (arg_0_0, arg_0_1)
namespace SomeNamespace.CapturingMock
open System
open WoofWare.Myriad.Plugins
[<RequireQualifiedAccess>]
module internal InternalTypeMockCalls =
/// All the calls made to a InternalTypeMock mock
type internal Calls =
{
Mem1 : ResizeArray<string * int>
Mem2 : ResizeArray<string>
}
/// A fresh calls object which has not yet had any calls made.
static member Empty () : Calls =
{
Mem1 = ResizeArray ()
Mem2 = ResizeArray ()
}
/// Mock record type for an interface
type internal InternalTypeMock =
{
Calls : InternalTypeMockCalls.Calls
Mem1 : string * int -> unit
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
Mem1_Calls : ResizeArray<string * int>
Mem2 : string -> int
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
Mem2_Calls : ResizeArray<string>
}
/// An implementation where every non-unit method throws.
static member Empty : InternalTypeMock =
{
Calls = InternalTypeMockCalls.Calls.Empty ()
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
Mem1_Calls = ResizeArray ()
Mem2_Calls = ResizeArray ()
}
interface InternalType with
member this.Mem1 (arg_0_0, arg_0_1) =
lock this.Calls.Mem1 (fun _ -> this.Calls.Mem1.Add (arg_0_0, arg_0_1))
this.Mem1 (arg_0_0, arg_0_1)
member this.Mem2 arg_0_0 =
lock this.Calls.Mem2 (fun _ -> this.Calls.Mem2.Add (arg_0_0))
this.Mem2 (arg_0_0)
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0)
namespace SomeNamespace.CapturingMock
open System
open WoofWare.Myriad.Plugins
[<RequireQualifiedAccess>]
module internal PrivateTypeMockCalls =
/// All the calls made to a PrivateTypeMock mock
type internal Calls =
{
Mem1 : ResizeArray<string * int>
Mem2 : ResizeArray<string>
}
/// A fresh calls object which has not yet had any calls made.
static member Empty () : Calls =
{
Mem1 = ResizeArray ()
Mem2 = ResizeArray ()
}
/// Mock record type for an interface
type private PrivateTypeMock =
{
Calls : PrivateTypeMockCalls.Calls
Mem1 : string * int -> unit
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
Mem1_Calls : ResizeArray<string * int>
Mem2 : string -> int
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
Mem2_Calls : ResizeArray<string>
}
/// An implementation where every non-unit method throws.
static member Empty : PrivateTypeMock =
{
Calls = PrivateTypeMockCalls.Calls.Empty ()
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
Mem1_Calls = ResizeArray ()
Mem2_Calls = ResizeArray ()
}
interface PrivateType with
member this.Mem1 (arg_0_0, arg_0_1) =
lock this.Calls.Mem1 (fun _ -> this.Calls.Mem1.Add (arg_0_0, arg_0_1))
this.Mem1 (arg_0_0, arg_0_1)
member this.Mem2 arg_0_0 =
lock this.Calls.Mem2 (fun _ -> this.Calls.Mem2.Add (arg_0_0))
this.Mem2 (arg_0_0)
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0)
namespace SomeNamespace.CapturingMock
open System
open WoofWare.Myriad.Plugins
[<RequireQualifiedAccess>]
module internal PrivateTypeInternalFalseMockCalls =
/// All the calls made to a PrivateTypeInternalFalseMock mock
type internal Calls =
{
Mem1 : ResizeArray<string * int>
Mem2 : ResizeArray<string>
}
/// A fresh calls object which has not yet had any calls made.
static member Empty () : Calls =
{
Mem1 = ResizeArray ()
Mem2 = ResizeArray ()
}
/// Mock record type for an interface
type private PrivateTypeInternalFalseMock =
{
Calls : PrivateTypeInternalFalseMockCalls.Calls
Mem1 : string * int -> unit
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
Mem1_Calls : ResizeArray<string * int>
Mem2 : string -> int
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
Mem2_Calls : ResizeArray<string>
}
/// An implementation where every non-unit method throws.
static member Empty : PrivateTypeInternalFalseMock =
{
Calls = PrivateTypeInternalFalseMockCalls.Calls.Empty ()
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
Mem1_Calls = ResizeArray ()
Mem2_Calls = ResizeArray ()
}
interface PrivateTypeInternalFalse with
member this.Mem1 (arg_0_0, arg_0_1) =
lock this.Calls.Mem1 (fun _ -> this.Calls.Mem1.Add (arg_0_0, arg_0_1))
this.Mem1 (arg_0_0, arg_0_1)
member this.Mem2 arg_0_0 =
lock this.Calls.Mem2 (fun _ -> this.Calls.Mem2.Add (arg_0_0))
this.Mem2 (arg_0_0)
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0)
namespace SomeNamespace.CapturingMock
open System
open WoofWare.Myriad.Plugins
[<RequireQualifiedAccess>]
module internal VeryPublicTypeMockCalls =
/// All the calls made to a VeryPublicTypeMock mock
type internal Calls<'a, 'b> =
{
Mem1 : ResizeArray<'a>
}
/// A fresh calls object which has not yet had any calls made.
static member Empty () : Calls<'a, 'b> =
{
Mem1 = ResizeArray ()
}
/// Mock record type for an interface
type internal VeryPublicTypeMock<'a, 'b> =
{
Calls : VeryPublicTypeMockCalls.Calls<'a, 'b>
Mem1 : 'a -> 'b
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
Mem1_Calls : ResizeArray<'a>
}
/// An implementation where every non-unit method throws.
static member Empty () : VeryPublicTypeMock<'a, 'b> =
{
Calls = VeryPublicTypeMockCalls.Calls.Empty ()
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
Mem1_Calls = ResizeArray ()
}
interface VeryPublicType<'a, 'b> with
member this.Mem1 arg_0_0 =
lock this.Calls.Mem1 (fun _ -> this.Calls.Mem1.Add (arg_0_0))
this.Mem1 (arg_0_0)
member this.Mem1 arg_0_0 = this.Mem1 (arg_0_0)
namespace SomeNamespace.CapturingMock
open System
open WoofWare.Myriad.Plugins
[<RequireQualifiedAccess>]
module internal CurriedMockCalls =
/// A single call to the Mem1 method
type internal Mem1Call<'a> =
@@ -331,178 +226,84 @@ module internal CurriedMockCalls =
Arg1 : 'a * int
}
/// All the calls made to a CurriedMock mock
type internal Calls<'a> =
{
Mem1 : ResizeArray<Mem1Call<'a>>
Mem2 : ResizeArray<Mem2Call<'a>>
Mem3 : ResizeArray<Mem3Call<'a>>
Mem4 : ResizeArray<Mem4Call<'a>>
Mem5 : ResizeArray<Mem5Call<'a>>
Mem6 : ResizeArray<Mem6Call<'a>>
}
/// A fresh calls object which has not yet had any calls made.
static member Empty () : Calls<'a> =
{
Mem1 = ResizeArray ()
Mem2 = ResizeArray ()
Mem3 = ResizeArray ()
Mem4 = ResizeArray ()
Mem5 = ResizeArray ()
Mem6 = ResizeArray ()
}
/// Mock record type for an interface
type internal CurriedMock<'a> =
{
Calls : CurriedMockCalls.Calls<'a>
Mem1 : int -> 'a -> string
Mem1_Calls : ResizeArray<CurriedMockCalls.Mem1Call<'a>>
Mem2 : int * string -> 'a -> string
Mem2_Calls : ResizeArray<CurriedMockCalls.Mem2Call<'a>>
Mem3 : (int * string) -> 'a -> string
Mem3_Calls : ResizeArray<CurriedMockCalls.Mem3Call<'a>>
Mem4 : (int * string) -> ('a * int) -> string
Mem4_Calls : ResizeArray<CurriedMockCalls.Mem4Call<'a>>
Mem5 : int * string -> ('a * int) -> string
Mem5_Calls : ResizeArray<CurriedMockCalls.Mem5Call<'a>>
Mem6 : int * string -> 'a * int -> string
Mem6_Calls : ResizeArray<CurriedMockCalls.Mem6Call<'a>>
}
/// An implementation where every non-unit method throws.
static member Empty () : CurriedMock<'a> =
{
Calls = CurriedMockCalls.Calls.Empty ()
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
Mem3 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem3"))
Mem4 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem4"))
Mem5 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem5"))
Mem6 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem6"))
Mem1_Calls = ResizeArray ()
Mem2_Calls = ResizeArray ()
Mem3_Calls = ResizeArray ()
Mem4_Calls = ResizeArray ()
Mem5_Calls = ResizeArray ()
Mem6_Calls = ResizeArray ()
}
interface Curried<'a> with
member this.Mem1 arg_0_0 arg_1_0 =
lock
this.Calls.Mem1
(fun _ ->
this.Calls.Mem1.Add
{
bar = arg_0_0
Arg1 = arg_1_0
}
)
this.Mem1 (arg_0_0) (arg_1_0)
member this.Mem2 (arg_0_0, arg_0_1) arg_1_0 =
lock
this.Calls.Mem2
(fun _ ->
this.Calls.Mem2.Add
{
Arg0 = arg_0_0, arg_0_1
baz = arg_1_0
}
)
this.Mem2 (arg_0_0, arg_0_1) (arg_1_0)
member this.Mem3 arg_0_0 arg_1_0 =
lock
this.Calls.Mem3
(fun _ ->
this.Calls.Mem3.Add
{
quux = arg_0_0
flurb = arg_1_0
}
)
this.Mem3 (arg_0_0) (arg_1_0)
member this.Mem1 arg_0_0 arg_1_0 = this.Mem1 (arg_0_0) (arg_1_0)
member this.Mem2 (arg_0_0, arg_0_1) arg_1_0 = this.Mem2 (arg_0_0, arg_0_1) (arg_1_0)
member this.Mem3 arg_0_0 arg_1_0 = this.Mem3 (arg_0_0) (arg_1_0)
member this.Mem4 ((arg_0_0, arg_0_1)) ((arg_1_0, arg_1_1)) =
lock
this.Calls.Mem4
(fun _ ->
this.Calls.Mem4.Add
{
Arg0 = arg_0_0, arg_0_1
Arg1 = arg_1_0, arg_1_1
}
)
this.Mem4 (arg_0_0, arg_0_1) (arg_1_0, arg_1_1)
member this.Mem5 (arg_0_0, arg_0_1) ((arg_1_0, arg_1_1)) =
lock
this.Calls.Mem5
(fun _ ->
this.Calls.Mem5.Add
{
Arg0 = arg_0_0, arg_0_1
Arg1 = arg_1_0, arg_1_1
}
)
this.Mem5 (arg_0_0, arg_0_1) (arg_1_0, arg_1_1)
member this.Mem6 (arg_0_0, arg_0_1) (arg_1_0, arg_1_1) =
lock
this.Calls.Mem6
(fun _ ->
this.Calls.Mem6.Add
{
Arg0 = arg_0_0, arg_0_1
Arg1 = arg_1_0, arg_1_1
}
)
this.Mem6 (arg_0_0, arg_0_1) (arg_1_0, arg_1_1)
namespace SomeNamespace.CapturingMock
open System
open WoofWare.Myriad.Plugins
[<RequireQualifiedAccess>]
module internal TypeWithInterfaceMockCalls =
/// All the calls made to a TypeWithInterfaceMock mock
type internal Calls =
{
Mem1 : ResizeArray<string option>
Mem2 : ResizeArray<unit>
}
/// A fresh calls object which has not yet had any calls made.
static member Empty () : Calls =
{
Mem1 = ResizeArray ()
Mem2 = ResizeArray ()
}
/// Mock record type for an interface
type internal TypeWithInterfaceMock =
{
Calls : TypeWithInterfaceMockCalls.Calls
/// Implementation of IDisposable.Dispose
Dispose : unit -> unit
Mem1 : string option -> string[] Async
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
Mem1_Calls : ResizeArray<string option>
Mem2 : unit -> string[] Async
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
Mem2_Calls : ResizeArray<unit>
}
/// An implementation where every non-unit method throws.
static member Empty : TypeWithInterfaceMock =
{
Calls = TypeWithInterfaceMockCalls.Calls.Empty ()
Dispose = (fun () -> ())
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
Mem1_Calls = ResizeArray ()
Mem2_Calls = ResizeArray ()
}
interface TypeWithInterface with
member this.Mem1 arg_0_0 =
lock this.Calls.Mem1 (fun _ -> this.Calls.Mem1.Add (arg_0_0))
this.Mem1 (arg_0_0)
member this.Mem2 () =
lock this.Calls.Mem2 (fun _ -> this.Calls.Mem2.Add (()))
this.Mem2 (())
member this.Mem1 arg_0_0 = this.Mem1 (arg_0_0)
member this.Mem2 () = this.Mem2 (())
interface System.IDisposable with
member this.Dispose () : unit = this.Dispose ()
@@ -511,50 +312,36 @@ namespace SomeNamespace.CapturingMock
open System
open WoofWare.Myriad.Plugins
[<RequireQualifiedAccess>]
module internal TypeWithPropertiesMockCalls =
/// All the calls made to a TypeWithPropertiesMock mock
type internal Calls =
{
Mem1 : ResizeArray<string option>
Prop1 : ResizeArray<unit>
Prop2 : ResizeArray<unit>
}
/// A fresh calls object which has not yet had any calls made.
static member Empty () : Calls =
{
Mem1 = ResizeArray ()
Prop1 = ResizeArray ()
Prop2 = ResizeArray ()
}
/// Mock record type for an interface
type internal TypeWithPropertiesMock =
{
Calls : TypeWithPropertiesMockCalls.Calls
/// Implementation of IDisposable.Dispose
Dispose : unit -> unit
Mem1 : string option -> string[] Async
Prop1 : unit -> int
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
Prop1_Calls : ResizeArray<unit>
Prop2 : unit -> unit Async
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
Prop2_Calls : ResizeArray<unit>
Mem1 : string option -> string[] Async
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
Mem1_Calls : ResizeArray<string option>
}
/// An implementation where every non-unit method throws.
static member Empty : TypeWithPropertiesMock =
{
Calls = TypeWithPropertiesMockCalls.Calls.Empty ()
Dispose = (fun () -> ())
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
Prop1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Prop1"))
Prop2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Prop2"))
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
Prop1_Calls = ResizeArray ()
Prop2_Calls = ResizeArray ()
Mem1_Calls = ResizeArray ()
}
interface TypeWithProperties with
member this.Mem1 arg_0_0 =
lock this.Calls.Mem1 (fun _ -> this.Calls.Mem1.Add (arg_0_0))
this.Mem1 (arg_0_0)
member this.Mem1 arg_0_0 = this.Mem1 (arg_0_0)
member this.Prop1 = this.Prop1 ()
member this.Prop2 = this.Prop2 ()

View File

@@ -8,279 +8,174 @@ namespace SomeNamespace.CapturingMock
open System
[<RequireQualifiedAccess>]
module internal PublicTypeNoAttrMockCalls =
/// All the calls made to a PublicTypeNoAttrMock mock
type internal Calls =
{
Mem1 : ResizeArray<string * int>
Mem2 : ResizeArray<string>
Mem3 : ResizeArray<int * System.Threading.CancellationToken option>
}
/// A fresh calls object which has not yet had any calls made.
static member Empty () : Calls =
{
Mem1 = ResizeArray ()
Mem2 = ResizeArray ()
Mem3 = ResizeArray ()
}
/// Mock record type for an interface
type internal PublicTypeNoAttrMock =
{
Calls : PublicTypeNoAttrMockCalls.Calls
Mem1 : string * int -> string list
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
Mem1_Calls : ResizeArray<string * int>
Mem2 : string -> int
Mem3 : int * System.Threading.CancellationToken option -> string
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
Mem2_Calls : ResizeArray<string>
Mem3 : int * option<System.Threading.CancellationToken> -> string
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
Mem3_Calls : ResizeArray<int * System.Threading.CancellationToken>
}
/// An implementation where every non-unit method throws.
static member Empty : PublicTypeNoAttrMock =
{
Calls = PublicTypeNoAttrMockCalls.Calls.Empty ()
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
Mem3 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem3"))
Mem1_Calls = ResizeArray ()
Mem2_Calls = ResizeArray ()
Mem3_Calls = ResizeArray ()
}
interface IPublicTypeNoAttr with
member this.Mem1 (arg_0_0, arg_0_1) =
lock this.Calls.Mem1 (fun _ -> this.Calls.Mem1.Add (arg_0_0, arg_0_1))
this.Mem1 (arg_0_0, arg_0_1)
member this.Mem2 arg_0_0 =
lock this.Calls.Mem2 (fun _ -> this.Calls.Mem2.Add (arg_0_0))
this.Mem2 (arg_0_0)
member this.Mem3 (arg_0_0, arg_0_1) =
lock this.Calls.Mem3 (fun _ -> this.Calls.Mem3.Add (arg_0_0, arg_0_1))
this.Mem3 (arg_0_0, arg_0_1)
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0)
member this.Mem3 (arg_0_0, arg_0_1) = this.Mem3 (arg_0_0, arg_0_1)
namespace SomeNamespace.CapturingMock
open System
[<RequireQualifiedAccess>]
module public PublicTypeInternalFalseNoAttrMockCalls =
/// All the calls made to a PublicTypeInternalFalseNoAttrMock mock
type public Calls =
{
Mem1 : ResizeArray<string * int>
Mem2 : ResizeArray<string>
Mem3 : ResizeArray<int * System.Threading.CancellationToken option>
}
/// A fresh calls object which has not yet had any calls made.
static member Empty () : Calls =
{
Mem1 = ResizeArray ()
Mem2 = ResizeArray ()
Mem3 = ResizeArray ()
}
/// Mock record type for an interface
type public PublicTypeInternalFalseNoAttrMock =
{
Calls : PublicTypeInternalFalseNoAttrMockCalls.Calls
Mem1 : string * int -> string list
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
Mem1_Calls : ResizeArray<string * int>
Mem2 : string -> int
Mem3 : int * System.Threading.CancellationToken option -> string
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
Mem2_Calls : ResizeArray<string>
Mem3 : int * option<System.Threading.CancellationToken> -> string
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
Mem3_Calls : ResizeArray<int * System.Threading.CancellationToken>
}
/// An implementation where every non-unit method throws.
static member Empty : PublicTypeInternalFalseNoAttrMock =
{
Calls = PublicTypeInternalFalseNoAttrMockCalls.Calls.Empty ()
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
Mem3 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem3"))
Mem1_Calls = ResizeArray ()
Mem2_Calls = ResizeArray ()
Mem3_Calls = ResizeArray ()
}
interface IPublicTypeInternalFalseNoAttr with
member this.Mem1 (arg_0_0, arg_0_1) =
lock this.Calls.Mem1 (fun _ -> this.Calls.Mem1.Add (arg_0_0, arg_0_1))
this.Mem1 (arg_0_0, arg_0_1)
member this.Mem2 arg_0_0 =
lock this.Calls.Mem2 (fun _ -> this.Calls.Mem2.Add (arg_0_0))
this.Mem2 (arg_0_0)
member this.Mem3 (arg_0_0, arg_0_1) =
lock this.Calls.Mem3 (fun _ -> this.Calls.Mem3.Add (arg_0_0, arg_0_1))
this.Mem3 (arg_0_0, arg_0_1)
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0)
member this.Mem3 (arg_0_0, arg_0_1) = this.Mem3 (arg_0_0, arg_0_1)
namespace SomeNamespace.CapturingMock
open System
[<RequireQualifiedAccess>]
module internal InternalTypeNoAttrMockCalls =
/// All the calls made to a InternalTypeNoAttrMock mock
type internal Calls =
{
Mem1 : ResizeArray<string * int>
Mem2 : ResizeArray<string>
}
/// A fresh calls object which has not yet had any calls made.
static member Empty () : Calls =
{
Mem1 = ResizeArray ()
Mem2 = ResizeArray ()
}
/// Mock record type for an interface
type internal InternalTypeNoAttrMock =
{
Calls : InternalTypeNoAttrMockCalls.Calls
Mem1 : string * int -> unit
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
Mem1_Calls : ResizeArray<string * int>
Mem2 : string -> int
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
Mem2_Calls : ResizeArray<string>
}
/// An implementation where every non-unit method throws.
static member Empty : InternalTypeNoAttrMock =
{
Calls = InternalTypeNoAttrMockCalls.Calls.Empty ()
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
Mem1_Calls = ResizeArray ()
Mem2_Calls = ResizeArray ()
}
interface InternalTypeNoAttr with
member this.Mem1 (arg_0_0, arg_0_1) =
lock this.Calls.Mem1 (fun _ -> this.Calls.Mem1.Add (arg_0_0, arg_0_1))
this.Mem1 (arg_0_0, arg_0_1)
member this.Mem2 arg_0_0 =
lock this.Calls.Mem2 (fun _ -> this.Calls.Mem2.Add (arg_0_0))
this.Mem2 (arg_0_0)
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0)
namespace SomeNamespace.CapturingMock
open System
[<RequireQualifiedAccess>]
module internal PrivateTypeNoAttrMockCalls =
/// All the calls made to a PrivateTypeNoAttrMock mock
type internal Calls =
{
Mem1 : ResizeArray<string * int>
Mem2 : ResizeArray<string>
}
/// A fresh calls object which has not yet had any calls made.
static member Empty () : Calls =
{
Mem1 = ResizeArray ()
Mem2 = ResizeArray ()
}
/// Mock record type for an interface
type private PrivateTypeNoAttrMock =
{
Calls : PrivateTypeNoAttrMockCalls.Calls
Mem1 : string * int -> unit
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
Mem1_Calls : ResizeArray<string * int>
Mem2 : string -> int
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
Mem2_Calls : ResizeArray<string>
}
/// An implementation where every non-unit method throws.
static member Empty : PrivateTypeNoAttrMock =
{
Calls = PrivateTypeNoAttrMockCalls.Calls.Empty ()
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
Mem1_Calls = ResizeArray ()
Mem2_Calls = ResizeArray ()
}
interface PrivateTypeNoAttr with
member this.Mem1 (arg_0_0, arg_0_1) =
lock this.Calls.Mem1 (fun _ -> this.Calls.Mem1.Add (arg_0_0, arg_0_1))
this.Mem1 (arg_0_0, arg_0_1)
member this.Mem2 arg_0_0 =
lock this.Calls.Mem2 (fun _ -> this.Calls.Mem2.Add (arg_0_0))
this.Mem2 (arg_0_0)
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0)
namespace SomeNamespace.CapturingMock
open System
[<RequireQualifiedAccess>]
module internal PrivateTypeInternalFalseNoAttrMockCalls =
/// All the calls made to a PrivateTypeInternalFalseNoAttrMock mock
type internal Calls =
{
Mem1 : ResizeArray<string * int>
Mem2 : ResizeArray<string>
}
/// A fresh calls object which has not yet had any calls made.
static member Empty () : Calls =
{
Mem1 = ResizeArray ()
Mem2 = ResizeArray ()
}
/// Mock record type for an interface
type private PrivateTypeInternalFalseNoAttrMock =
{
Calls : PrivateTypeInternalFalseNoAttrMockCalls.Calls
Mem1 : string * int -> unit
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
Mem1_Calls : ResizeArray<string * int>
Mem2 : string -> int
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
Mem2_Calls : ResizeArray<string>
}
/// An implementation where every non-unit method throws.
static member Empty : PrivateTypeInternalFalseNoAttrMock =
{
Calls = PrivateTypeInternalFalseNoAttrMockCalls.Calls.Empty ()
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
Mem1_Calls = ResizeArray ()
Mem2_Calls = ResizeArray ()
}
interface PrivateTypeInternalFalseNoAttr with
member this.Mem1 (arg_0_0, arg_0_1) =
lock this.Calls.Mem1 (fun _ -> this.Calls.Mem1.Add (arg_0_0, arg_0_1))
this.Mem1 (arg_0_0, arg_0_1)
member this.Mem2 arg_0_0 =
lock this.Calls.Mem2 (fun _ -> this.Calls.Mem2.Add (arg_0_0))
this.Mem2 (arg_0_0)
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0)
namespace SomeNamespace.CapturingMock
open System
[<RequireQualifiedAccess>]
module internal VeryPublicTypeNoAttrMockCalls =
/// All the calls made to a VeryPublicTypeNoAttrMock mock
type internal Calls<'a, 'b> =
{
Mem1 : ResizeArray<'a>
}
/// A fresh calls object which has not yet had any calls made.
static member Empty () : Calls<'a, 'b> =
{
Mem1 = ResizeArray ()
}
/// Mock record type for an interface
type internal VeryPublicTypeNoAttrMock<'a, 'b> =
{
Calls : VeryPublicTypeNoAttrMockCalls.Calls<'a, 'b>
Mem1 : 'a -> 'b
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
Mem1_Calls : ResizeArray<'a>
}
/// An implementation where every non-unit method throws.
static member Empty () : VeryPublicTypeNoAttrMock<'a, 'b> =
{
Calls = VeryPublicTypeNoAttrMockCalls.Calls.Empty ()
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
Mem1_Calls = ResizeArray ()
}
interface VeryPublicTypeNoAttr<'a, 'b> with
member this.Mem1 arg_0_0 =
lock this.Calls.Mem1 (fun _ -> this.Calls.Mem1.Add (arg_0_0))
this.Mem1 (arg_0_0)
member this.Mem1 arg_0_0 = this.Mem1 (arg_0_0)
namespace SomeNamespace.CapturingMock
open System
[<RequireQualifiedAccess>]
module internal CurriedNoAttrMockCalls =
/// A single call to the Mem1 method
type internal Mem1Call<'a> =
@@ -324,177 +219,83 @@ module internal CurriedNoAttrMockCalls =
Arg1 : 'a * int
}
/// All the calls made to a CurriedNoAttrMock mock
type internal Calls<'a> =
{
Mem1 : ResizeArray<Mem1Call<'a>>
Mem2 : ResizeArray<Mem2Call<'a>>
Mem3 : ResizeArray<Mem3Call<'a>>
Mem4 : ResizeArray<Mem4Call<'a>>
Mem5 : ResizeArray<Mem5Call<'a>>
Mem6 : ResizeArray<Mem6Call<'a>>
}
/// A fresh calls object which has not yet had any calls made.
static member Empty () : Calls<'a> =
{
Mem1 = ResizeArray ()
Mem2 = ResizeArray ()
Mem3 = ResizeArray ()
Mem4 = ResizeArray ()
Mem5 = ResizeArray ()
Mem6 = ResizeArray ()
}
/// Mock record type for an interface
type internal CurriedNoAttrMock<'a> =
{
Calls : CurriedNoAttrMockCalls.Calls<'a>
Mem1 : int -> 'a -> string
Mem1_Calls : ResizeArray<CurriedNoAttrMockCalls.Mem1Call<'a>>
Mem2 : int * string -> 'a -> string
Mem2_Calls : ResizeArray<CurriedNoAttrMockCalls.Mem2Call<'a>>
Mem3 : (int * string) -> 'a -> string
Mem3_Calls : ResizeArray<CurriedNoAttrMockCalls.Mem3Call<'a>>
Mem4 : (int * string) -> ('a * int) -> string
Mem4_Calls : ResizeArray<CurriedNoAttrMockCalls.Mem4Call<'a>>
Mem5 : int * string -> ('a * int) -> string
Mem5_Calls : ResizeArray<CurriedNoAttrMockCalls.Mem5Call<'a>>
Mem6 : int * string -> 'a * int -> string
Mem6_Calls : ResizeArray<CurriedNoAttrMockCalls.Mem6Call<'a>>
}
/// An implementation where every non-unit method throws.
static member Empty () : CurriedNoAttrMock<'a> =
{
Calls = CurriedNoAttrMockCalls.Calls.Empty ()
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
Mem3 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem3"))
Mem4 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem4"))
Mem5 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem5"))
Mem6 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem6"))
Mem1_Calls = ResizeArray ()
Mem2_Calls = ResizeArray ()
Mem3_Calls = ResizeArray ()
Mem4_Calls = ResizeArray ()
Mem5_Calls = ResizeArray ()
Mem6_Calls = ResizeArray ()
}
interface CurriedNoAttr<'a> with
member this.Mem1 arg_0_0 arg_1_0 =
lock
this.Calls.Mem1
(fun _ ->
this.Calls.Mem1.Add
{
Arg0 = arg_0_0
Arg1 = arg_1_0
}
)
this.Mem1 (arg_0_0) (arg_1_0)
member this.Mem2 (arg_0_0, arg_0_1) arg_1_0 =
lock
this.Calls.Mem2
(fun _ ->
this.Calls.Mem2.Add
{
Arg0 = arg_0_0, arg_0_1
Arg1 = arg_1_0
}
)
this.Mem2 (arg_0_0, arg_0_1) (arg_1_0)
member this.Mem3 ((arg_0_0, arg_0_1)) arg_1_0 =
lock
this.Calls.Mem3
(fun _ ->
this.Calls.Mem3.Add
{
Arg0 = arg_0_0, arg_0_1
Arg1 = arg_1_0
}
)
this.Mem3 (arg_0_0, arg_0_1) (arg_1_0)
member this.Mem1 arg_0_0 arg_1_0 = this.Mem1 (arg_0_0) (arg_1_0)
member this.Mem2 (arg_0_0, arg_0_1) arg_1_0 = this.Mem2 (arg_0_0, arg_0_1) (arg_1_0)
member this.Mem3 ((arg_0_0, arg_0_1)) arg_1_0 = this.Mem3 (arg_0_0, arg_0_1) (arg_1_0)
member this.Mem4 ((arg_0_0, arg_0_1)) ((arg_1_0, arg_1_1)) =
lock
this.Calls.Mem4
(fun _ ->
this.Calls.Mem4.Add
{
Arg0 = arg_0_0, arg_0_1
Arg1 = arg_1_0, arg_1_1
}
)
this.Mem4 (arg_0_0, arg_0_1) (arg_1_0, arg_1_1)
member this.Mem5 (arg_0_0, arg_0_1) ((arg_1_0, arg_1_1)) =
lock
this.Calls.Mem5
(fun _ ->
this.Calls.Mem5.Add
{
Arg0 = arg_0_0, arg_0_1
Arg1 = arg_1_0, arg_1_1
}
)
this.Mem5 (arg_0_0, arg_0_1) (arg_1_0, arg_1_1)
member this.Mem6 (arg_0_0, arg_0_1) (arg_1_0, arg_1_1) =
lock
this.Calls.Mem6
(fun _ ->
this.Calls.Mem6.Add
{
Arg0 = arg_0_0, arg_0_1
Arg1 = arg_1_0, arg_1_1
}
)
this.Mem6 (arg_0_0, arg_0_1) (arg_1_0, arg_1_1)
namespace SomeNamespace.CapturingMock
open System
[<RequireQualifiedAccess>]
module internal TypeWithInterfaceNoAttrMockCalls =
/// All the calls made to a TypeWithInterfaceNoAttrMock mock
type internal Calls =
{
Mem1 : ResizeArray<string option>
Mem2 : ResizeArray<unit>
}
/// A fresh calls object which has not yet had any calls made.
static member Empty () : Calls =
{
Mem1 = ResizeArray ()
Mem2 = ResizeArray ()
}
/// Mock record type for an interface
type internal TypeWithInterfaceNoAttrMock =
{
Calls : TypeWithInterfaceNoAttrMockCalls.Calls
/// Implementation of IDisposable.Dispose
Dispose : unit -> unit
Mem1 : string option -> string[] Async
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
Mem1_Calls : ResizeArray<string option>
Mem2 : unit -> string[] Async
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
Mem2_Calls : ResizeArray<unit>
}
/// An implementation where every non-unit method throws.
static member Empty : TypeWithInterfaceNoAttrMock =
{
Calls = TypeWithInterfaceNoAttrMockCalls.Calls.Empty ()
Dispose = (fun () -> ())
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
Mem1_Calls = ResizeArray ()
Mem2_Calls = ResizeArray ()
}
interface TypeWithInterfaceNoAttr with
member this.Mem1 arg_0_0 =
lock this.Calls.Mem1 (fun _ -> this.Calls.Mem1.Add (arg_0_0))
this.Mem1 (arg_0_0)
member this.Mem2 () =
lock this.Calls.Mem2 (fun _ -> this.Calls.Mem2.Add (()))
this.Mem2 (())
member this.Mem1 arg_0_0 = this.Mem1 (arg_0_0)
member this.Mem2 () = this.Mem2 (())
interface System.IDisposable with
member this.Dispose () : unit = this.Dispose ()

View File

@@ -478,51 +478,40 @@ It takes a type like this:
```fsharp
[<GenerateCapturingMock>]
type IPublicType =
abstract Mem1 : string * int -> thing : bool -> string list
abstract Mem1 : string * int -> string list
abstract Mem2 : baz : string -> unit -> int
```
and stamps out types like this:
```fsharp
[<RequireQualifiedAccess>]
module internal PublicTypeCalls =
type internal Mem1Call =
type internal Mem2Call =
{
Arg0 : string * int
thing : bool
baz : string
Arg1 : unit
}
type internal Calls =
{
Mem1 : ResizeArray<Mem1Call>
Mem2 : ResizeArray<string>
}
static member Empty () = { Mem1 = ResizeArray () ; Mem2 = ResizeArray () }
/// Mock record type for an interface
type internal PublicTypeMock =
{
Mem1 : string * int -> bool -> string list
Mem1 : string * int -> string list
Mem2 : string -> int
Calls : PublicTypeCalls.Calls
Mem2_Calls : ResizeArray<string * int>
Mem2_Calls : ResizeArray<PublicTypeCalls.Mem2Call>
}
static member Empty : PublicTypeMock =
{
Mem1 = (fun x -> raise (System.NotImplementedException "Unimplemented mock function"))
Mem2 = (fun x -> raise (System.NotImplementedException "Unimplemented mock function"))
Calls = PublicTypeMockCalls.Calls.Empty ()
Mem1_Calls = ResizeArray ()
Mem2_Calls = ResizeArray ()
}
interface IPublicType with
member this.Mem1 (arg0, arg1) =
lock this.Calls.Mem1 (fun () -> this.Calls.Mem1.Add { Arg0 = arg0 ; thing = arg1 })
this.Mem1 (arg0, arg1)
member this.Mem2 (arg0) =
lock this.Calls.Mem2 (fun () -> this.Calls.Mem2.Add arg0)
this.Mem2 (arg0)
member this.Mem1 (arg0, arg1) = this.Mem1 (arg0, arg1)
member this.Mem2 (arg0) = this.Mem2 (arg0)
```
### What's the point?
@@ -536,36 +525,6 @@ thereby allowing the programmer to use F#'s record-update syntax.
* You may supply an `isInternal : bool` argument to the attribute. By default, we make the resulting record type at most internal (never public), since this is intended only to be used in tests; but you can instead make it public with `[<GenerateMock false>]`.
### Gotchas (GenerateCapturingMock)
We use the same name for the record field as the implementing interface member:
```fsharp
type FooMock =
{
Field : string -> unit
}
interface IFoo with
member _.Field x = ...
```
If you have an object of type `FooMock` in scope, you'll get the *record field*, not the *interface member*.
You need to cast it to `IFoo` before using it (or pass it into a function which takes an `IFoo`):
```fsharp
let thing = FooMock.Empty () // of type FooMock
thing.Field "hello" // the wrong one! bypasses the IFoo implementation which captures calls
// correct:
let thing' = FooMock.Empty ()
let thing = thing' :> IFoo
thing.Field "hello" // the right one: this call does get recorded in the mock, because this is the interface member
// also correct, but beware because it leaves the chance of the above footgun lying around for later:
let thing = FooMock.Empty () // of type FooMock
doTheThing thing // where doTheThing : IFoo -> unit
```
## `CreateCatamorphism`
Takes a collection of mutually recursive discriminated unions:

View File

@@ -32,11 +32,7 @@ type GenerateMockAttribute (isInternal : bool) =
/// record update syntax to easily specify partially-implemented mock objects.
/// You may optionally specify `isInternal = false` to get a mock with the public visibility modifier.
///
/// The default implementation of each field throws.
///
/// The generated interface methods capture all calls made to them, before passing through to the relevant
/// field of the mock record; the calls can be accessed later through the `Calls` field of the generated
/// mock record.
/// The default implementation of each field captures all calls made to it, which can then be accessed later.
type GenerateCapturingMockAttribute (isInternal : bool) =
inherit Attribute ()
/// The default value of `isInternal`, the optional argument to the GenerateCapturingMockAttribute constructor.

View File

@@ -50,7 +50,7 @@ module TestCapturingMockGenerator =
[<Test>]
let ``Example of curried use`` () =
let mock' =
let mock =
{ CurriedMock<string>.Empty () with
Mem1 =
fun x y ->
@@ -59,11 +59,9 @@ module TestCapturingMockGenerator =
"it's me"
}
let mock = mock' :> Curried<_>
mock.Mem1 3 "hello" |> shouldEqual "it's me"
lock mock'.Calls.Mem1 (fun () -> Seq.toList mock'.Calls.Mem1)
lock mock.Mem1_Calls (fun () -> Seq.toList mock.Mem1_Calls)
|> List.exactlyOne
|> shouldEqual
{

View File

@@ -50,12 +50,7 @@ module internal CapturingInterfaceMockGenerator =
Attrs = []
Type =
tupledArg.Args
|> List.map (fun pi ->
if pi.IsOptional then
pi.Type |> SynType.appPostfix "option"
else
pi.Type
)
|> List.map (fun pi -> pi.Type)
|> SynType.tupleNoParen
|> Option.get
}
@@ -80,7 +75,7 @@ module internal CapturingInterfaceMockGenerator =
let private buildType (x : ParameterInfo) : SynType =
if x.IsOptional then
SynType.appPostfix "option" x.Type
SynType.app "option" [ x.Type ]
else
x.Type
@@ -144,12 +139,7 @@ module internal CapturingInterfaceMockGenerator =
| [] -> failwith "expected args in member"
| [ ty ] ->
ty.Args
|> List.map (fun pi ->
if pi.IsOptional then
SynType.appPostfix "option" pi.Type
else
pi.Type
)
|> List.map _.Type
|> SynType.tupleNoParen
|> Option.get
|> CallField.Original
@@ -224,9 +214,8 @@ module internal CapturingInterfaceMockGenerator =
| None -> failwith $"unexpectedly got a field with no identifier: %O{f}"
| Some idOpt -> idOpt.idText
fieldName, (f, extraType)
f, extraType, fieldName
)
|> Map.ofList
let failwithNotImplemented (fieldName : string) =
let failString = SynExpr.CreateConst $"Unimplemented mock function: %s{fieldName}"
@@ -259,16 +248,20 @@ module internal CapturingInterfaceMockGenerator =
let originalMembers =
fields
|> Map.toList
|> List.map (fun (fieldName, _) -> SynLongIdent.createS fieldName, failwithNotImplemented fieldName)
|> List.map (fun (_, _, fieldName) -> SynLongIdent.createS fieldName, failwithNotImplemented fieldName)
let callsObject =
SynLongIdent.createS "Calls",
SynExpr.applyFunction
(SynExpr.createLongIdent [ $"%s{name}Calls" ; "Calls" ; "Empty" ])
(SynExpr.CreateConst ())
let callsArrays =
fields
|> List.map (fun (_field, _, fieldName) ->
let name = SynLongIdent.createS $"%s{fieldName}_Calls"
callsObject :: interfaceExtras @ originalMembers
let init =
SynExpr.createIdent "ResizeArray" |> SynExpr.applyTo (SynExpr.CreateConst ())
name, init
)
interfaceExtras @ originalMembers @ callsArrays
let staticMemberEmpty =
SynBinding.basic
@@ -297,109 +290,43 @@ module internal CapturingInterfaceMockGenerator =
[]
let nonExtras =
fields |> Map.toSeq |> Seq.map (fun (_, (field, _)) -> field) |> Seq.toList
let calls =
let ty =
match interfaceType.Generics with
| None -> SynType.createLongIdent' [ $"%s{name}Calls" ; "Calls" ]
| Some generics ->
generics.TyparDecls
|> List.map (fun (SynTyparDecl (_, typar)) -> SynType.var typar)
|> SynType.app' (SynType.createLongIdent' [ $"%s{name}Calls" ; "Calls" ])
{
Attrs = []
Ident = Ident.create "Calls" |> Some
Type = ty
}
|> SynField.make
calls :: extras @ nonExtras
let access =
match interfaceType.Accessibility, spec.IsInternal with
| Some (SynAccess.Public _), true
| None, true -> SynAccess.Internal range0
| Some (SynAccess.Public _), false -> SynAccess.Public range0
| None, false -> SynAccess.Public range0
| Some (SynAccess.Internal _), _ -> SynAccess.Internal range0
| Some (SynAccess.Private _), _ -> SynAccess.Private range0
let accessAtLeastInternal =
match access with
| SynAccess.Private _ -> SynAccess.Internal range0
| access -> access
let callsObject =
let fields' =
fields
|> Map.toSeq
|> Seq.map (fun (fieldName, (_, callType)) ->
match callType with
| CallField.Original ty ->
{
Attrs = []
Ident = Some (fieldName |> Ident.create)
Type = SynType.app "ResizeArray" [ ty ]
}
|> SynField.make
| CallField.ArgsObject (argsObjectName, _, generics) ->
{
Attrs = []
Ident = Some (fieldName |> Ident.create)
Type =
match generics with
| None -> SynType.named argsObjectName.idText
| Some generics ->
generics.TyparDecls
|> List.map (fun (SynTyparDecl.SynTyparDecl (_, typar)) -> SynType.var typar)
|> SynType.app' (SynType.createLongIdent' [ argsObjectName.idText ])
|> List.singleton
|> SynType.app "ResizeArray"
}
|> SynField.make
|> List.collect (fun (field, callType, fieldName) ->
let callField =
match callType with
| CallField.Original ty ->
{
Attrs = []
Ident = Some (fieldName + "_Calls" |> Ident.create)
Type = SynType.app "ResizeArray" [ ty ]
}
|> SynField.make
|> SynField.withDocString (
PreXmlDoc.create
"Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it."
)
| CallField.ArgsObject (argsObjectName, _, generics) ->
{
Attrs = []
Ident = Some (fieldName + "_Calls" |> Ident.create)
Type =
match generics with
| None -> SynType.named argsObjectName.idText
| Some generics ->
generics.TyparDecls
|> List.map (fun (SynTyparDecl.SynTyparDecl (_, typar)) -> SynType.var typar)
|> SynType.app' (
SynType.createLongIdent' [ $"%s{name}Calls" ; argsObjectName.idText ]
)
|> List.singleton
|> SynType.app "ResizeArray"
}
|> SynField.make
[ field ; callField ]
)
|> Seq.toList
let emptyMember =
let returnType =
match interfaceType.Generics with
| None -> SynType.named "Calls"
| Some generics ->
let generics =
match generics with
| SynTyparDecls.PostfixList (decls = decls)
| SynTyparDecls.PrefixList (decls = decls) -> decls
| SynTyparDecls.SinglePrefix (decl = decl) -> [ decl ]
|> List.map (fun (SynTyparDecl.SynTyparDecl (_, typar)) -> SynType.var typar)
SynType.app "Calls" generics
fields
|> Map.toSeq
|> Seq.map (fun (name, _) ->
SynLongIdent.createS name,
SynExpr.applyFunction (SynExpr.createIdent "ResizeArray") (SynExpr.CreateConst ())
)
|> Seq.toList
|> SynExpr.createRecord None
|> SynBinding.basic [ Ident.create "Empty" ] [ SynPat.unit ]
|> SynBinding.withXmlDoc (PreXmlDoc.create "A fresh calls object which has not yet had any calls made.")
|> SynBinding.withReturnAnnotation returnType
|> SynMemberDefn.staticMember
{
RecordType.Name = Ident.create "Calls"
Fields = fields'
Members = Some [ emptyMember ]
XmlDoc = PreXmlDoc.create $"All the calls made to a %s{name} mock" |> Some
Generics = interfaceType.Generics
TypeAccessibility = Some accessAtLeastInternal
ImplAccessibility = None
Attributes = [ SynAttribute.requireQualifiedAccess ]
}
|> AstHelper.defineRecordType
extras @ nonExtras
let interfaceMembers =
let members =
@@ -423,65 +350,28 @@ module internal CapturingInterfaceMockGenerator =
|> fun i -> if tupledArgs.HasParen then SynPat.paren i else i
)
let body, addToCalls =
let tupleContents =
let body =
let tuples =
memberInfo.Args
|> List.mapi (fun i args ->
args.Args
|> List.mapi (fun j arg ->
match arg.Type with
| UnitType -> SynExpr.CreateConst (), arg.Id
| _ -> SynExpr.createIdent $"arg_%i{i}_%i{j}", arg.Id
| UnitType -> SynExpr.CreateConst ()
| _ -> SynExpr.createIdent $"arg_%i{i}_%i{j}"
)
|> SynExpr.tuple
)
let tuples = tupleContents |> List.map (List.map fst >> SynExpr.tuple)
match tuples |> List.rev with
| [] -> failwith "expected args but got none"
| last :: rest ->
let tuples = (last, rest) ||> List.fold SynExpr.applyTo
let body =
tuples
|> SynExpr.applyFunction (
SynExpr.createLongIdent' [ Ident.create "this" ; memberInfo.Identifier ]
)
let addToCalls =
match Map.tryFind memberInfo.Identifier.idText fields with
| None ->
failwith
$"unexpectedly looking up a nonexistent field %s{memberInfo.Identifier.idText}"
| Some (_, result) ->
match result with
| CallField.Original _ -> tuples
| CallField.ArgsObject _ ->
tupleContents
|> List.mapi (fun i fields ->
match fields with
| [ contents, Some ident ] -> SynLongIdent.create [ ident ], contents
| [ contents, None ] -> SynLongIdent.createS $"Arg%i{i}", contents
| _ ->
SynLongIdent.createS $"Arg%i{i}",
SynExpr.tupleNoParen (fields |> List.map fst)
)
|> SynExpr.createRecord None
|> SynExpr.applyFunction (
SynExpr.createLongIdent [ "this" ; "Calls" ; memberInfo.Identifier.idText ; "Add" ]
)
|> SynExpr.createLambda "_"
|> SynExpr.applyFunction (
SynExpr.createIdent "lock"
|> SynExpr.applyTo (
SynExpr.createLongIdent [ "this" ; "Calls" ; memberInfo.Identifier.idText ]
)
)
body, addToCalls
let body = [ addToCalls ; body ] |> SynExpr.sequential
(last, rest)
||> List.fold SynExpr.applyTo
|> SynExpr.applyFunction (
SynExpr.createLongIdent' [ Ident.create "this" ; memberInfo.Identifier ]
)
SynBinding.basic [ Ident.create "this" ; memberInfo.Identifier ] headArgs body
|> SynMemberDefn.memberImplementation
@@ -513,6 +403,15 @@ module internal CapturingInterfaceMockGenerator =
SynMemberDefn.Interface (interfaceName, Some range0, Some (members @ properties), range0)
let access =
match interfaceType.Accessibility, spec.IsInternal with
| Some (SynAccess.Public _), true
| None, true -> SynAccess.Internal range0
| Some (SynAccess.Public _), false -> SynAccess.Public range0
| None, false -> SynAccess.Public range0
| Some (SynAccess.Internal _), _ -> SynAccess.Internal range0
| Some (SynAccess.Private _), _ -> SynAccess.Private range0
let extraInterfaces =
inherits
|> Seq.map (fun inheritance ->
@@ -549,23 +448,22 @@ module internal CapturingInterfaceMockGenerator =
let typeDecl = AstHelper.defineRecordType record
let callsModule =
let types =
fields
|> Map.toSeq
|> Seq.choose (fun (_, (_, field)) ->
match field with
| CallField.Original _ -> None
| CallField.ArgsObject (_, callType, _) -> Some (SynModuleDecl.Types ([ callType ], range0))
)
|> Seq.toList
types @ [ SynModuleDecl.Types ([ callsObject ], range0) ]
|> SynModuleDecl.nestedModule (
SynComponentInfo.create (Ident.create $"%s{name}Calls")
|> SynComponentInfo.withAccessibility accessAtLeastInternal
|> SynComponentInfo.addAttributes [ SynAttribute.requireQualifiedAccess ]
fields
|> List.choose (fun (_, field, _) ->
match field with
| CallField.Original _ -> None
| CallField.ArgsObject (_, callType, _) -> Some callType
)
|> Some
|> function
| [] -> None
| l ->
SynModuleDecl.Types (l, range0)
|> List.singleton
|> SynModuleDecl.nestedModule (
SynComponentInfo.create (Ident.create $"%s{name}Calls")
|> SynComponentInfo.withAccessibility access
)
|> Some
(callsModule, SynModuleDecl.Types ([ typeDecl ], range0))