Compare commits

..

5 Commits

Author SHA1 Message Date
Patrick Stevens
1721ad1ac0 Unconditional function for empty generating mock (#430) 2025-09-30 21:52:59 +00:00
dependabot[bot]
857bde0ba9 Bump Nerdbank.GitVersioning from 3.8.38-alpha to 3.8.118 (#428)
* Bump Nerdbank.GitVersioning from 3.8.38-alpha to 3.8.118

---
updated-dependencies:
- dependency-name: Nerdbank.GitVersioning
  dependency-version: 3.8.118
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* Deps

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Smaug123 <3138005+Smaug123@users.noreply.github.com>
2025-09-29 23:52:31 +01:00
patrick-conscriptus[bot]
d10f608941 Automated commit (#427)
Co-authored-by: patrick-conscriptus[bot] <175414948+patrick-conscriptus[bot]@users.noreply.github.com>
2025-09-28 01:31:56 +00:00
patrick-conscriptus[bot]
46effedfc4 Automated commit (#426)
Co-authored-by: patrick-conscriptus[bot] <175414948+patrick-conscriptus[bot]@users.noreply.github.com>
2025-09-21 01:31:20 +00:00
Patrick Stevens
1b85182b9d GenerateCapturingMock that captures calls made to it (#425) 2025-09-18 15:42:10 +01:00
18 changed files with 1019 additions and 338 deletions

View File

@@ -1,5 +1,9 @@
Notable changes are recorded here. Notable changes are recorded here.
# WoofWare.Myriad.Plugins 8.1.1
Adds `GenerateCapturingMock`, which is `GenerateMock` but additionally records the calls made to each function.
# WoofWare.Myriad.Plugins 8.0.3 # WoofWare.Myriad.Plugins 8.0.3
The RestEase-style HTTP client generator now automatically adds the `application/json` content type header to requests which are POSTing a body that is known to be JSON-serialised. The RestEase-style HTTP client generator now automatically adds the `application/json` content type header to requests which are POSTing a body that is known to be JSON-serialised.

View File

@@ -5,7 +5,7 @@ open WoofWare.Myriad.Plugins
[<GenerateCapturingMock>] [<GenerateCapturingMock>]
type IPublicType = type IPublicType =
abstract Mem1 : string * int -> string list abstract Mem1 : foo : string * int -> string list
abstract Mem2 : string -> int abstract Mem2 : string -> int
abstract Mem3 : x : int * ?ct : System.Threading.CancellationToken -> string abstract Mem3 : x : int * ?ct : System.Threading.CancellationToken -> string
@@ -36,9 +36,9 @@ type VeryPublicType<'a, 'b> =
[<GenerateCapturingMock>] [<GenerateCapturingMock>]
type Curried<'a> = type Curried<'a> =
abstract Mem1 : int -> 'a -> string abstract Mem1 : bar : int -> 'a -> string
abstract Mem2 : int * string -> 'a -> string abstract Mem2 : int * string -> baz : 'a -> string
abstract Mem3 : (int * string) -> 'a -> string abstract Mem3 : quux : (int * string) -> flurb : 'a -> string
abstract Mem4 : (int * string) -> ('a * int) -> string abstract Mem4 : (int * string) -> ('a * int) -> string
abstract Mem5 : x : int * string -> ('a * int) -> string abstract Mem5 : x : int * string -> ('a * int) -> string
abstract Mem6 : int * string -> y : 'a * int -> string abstract Mem6 : int * string -> y : 'a * int -> string

View File

@@ -9,285 +9,500 @@ namespace SomeNamespace.CapturingMock
open System open System
open WoofWare.Myriad.Plugins 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 /// Mock record type for an interface
type internal PublicTypeMock = type internal PublicTypeMock =
{ {
Calls : PublicTypeMockCalls.Calls
Mem1 : string * int -> string list Mem1 : string * int -> string list
Mem1_Calls : ResizeArray<string * int>
Mem2 : string -> int Mem2 : string -> int
Mem2_Calls : ResizeArray<string> Mem3 : int * System.Threading.CancellationToken option -> string
Mem3 : int * option<System.Threading.CancellationToken> -> string
Mem3_Calls : ResizeArray<int * System.Threading.CancellationToken>
} }
/// An implementation where every non-unit method throws. /// An implementation where every non-unit method throws.
static member Empty : PublicTypeMock = static member Empty () : PublicTypeMock =
{ {
Calls = PublicTypeMockCalls.Calls.Empty ()
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1")) Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2")) Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
Mem3 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem3")) Mem3 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem3"))
Mem1_Calls = ResizeArray ()
Mem2_Calls = ResizeArray ()
Mem3_Calls = ResizeArray ()
} }
interface IPublicType with interface IPublicType with
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1) member this.Mem1 (arg_0_0, arg_0_1) =
member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0) lock this.Calls.Mem1 (fun _ -> this.Calls.Mem1.Add (arg_0_0, arg_0_1))
member this.Mem3 (arg_0_0, arg_0_1) = this.Mem3 (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)
namespace SomeNamespace.CapturingMock namespace SomeNamespace.CapturingMock
open System open System
open WoofWare.Myriad.Plugins 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 /// Mock record type for an interface
type public PublicTypeInternalFalseMock = type public PublicTypeInternalFalseMock =
{ {
Calls : PublicTypeInternalFalseMockCalls.Calls
Mem1 : string * int -> string list Mem1 : string * int -> string list
Mem1_Calls : ResizeArray<string * int>
Mem2 : string -> int Mem2 : string -> int
Mem2_Calls : ResizeArray<string> Mem3 : int * System.Threading.CancellationToken option -> string
Mem3 : int * option<System.Threading.CancellationToken> -> string
Mem3_Calls : ResizeArray<int * System.Threading.CancellationToken>
} }
/// An implementation where every non-unit method throws. /// An implementation where every non-unit method throws.
static member Empty : PublicTypeInternalFalseMock = static member Empty () : PublicTypeInternalFalseMock =
{ {
Calls = PublicTypeInternalFalseMockCalls.Calls.Empty ()
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1")) Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2")) Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
Mem3 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem3")) Mem3 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem3"))
Mem1_Calls = ResizeArray ()
Mem2_Calls = ResizeArray ()
Mem3_Calls = ResizeArray ()
} }
interface IPublicTypeInternalFalse with interface IPublicTypeInternalFalse with
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1) member this.Mem1 (arg_0_0, arg_0_1) =
member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0) lock this.Calls.Mem1 (fun _ -> this.Calls.Mem1.Add (arg_0_0, arg_0_1))
member this.Mem3 (arg_0_0, arg_0_1) = this.Mem3 (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)
namespace SomeNamespace.CapturingMock namespace SomeNamespace.CapturingMock
open System open System
open WoofWare.Myriad.Plugins 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 /// Mock record type for an interface
type internal InternalTypeMock = type internal InternalTypeMock =
{ {
Calls : InternalTypeMockCalls.Calls
Mem1 : string * int -> unit Mem1 : string * int -> unit
Mem1_Calls : ResizeArray<string * int>
Mem2 : string -> int Mem2 : string -> int
Mem2_Calls : ResizeArray<string>
} }
/// An implementation where every non-unit method throws. /// An implementation where every non-unit method throws.
static member Empty : InternalTypeMock = static member Empty () : InternalTypeMock =
{ {
Calls = InternalTypeMockCalls.Calls.Empty ()
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1")) Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2")) Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
Mem1_Calls = ResizeArray ()
Mem2_Calls = ResizeArray ()
} }
interface InternalType with interface InternalType with
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1) member this.Mem1 (arg_0_0, arg_0_1) =
member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0) 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)
namespace SomeNamespace.CapturingMock namespace SomeNamespace.CapturingMock
open System open System
open WoofWare.Myriad.Plugins 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 /// Mock record type for an interface
type private PrivateTypeMock = type private PrivateTypeMock =
{ {
Calls : PrivateTypeMockCalls.Calls
Mem1 : string * int -> unit Mem1 : string * int -> unit
Mem1_Calls : ResizeArray<string * int>
Mem2 : string -> int Mem2 : string -> int
Mem2_Calls : ResizeArray<string>
} }
/// An implementation where every non-unit method throws. /// An implementation where every non-unit method throws.
static member Empty : PrivateTypeMock = static member Empty () : PrivateTypeMock =
{ {
Calls = PrivateTypeMockCalls.Calls.Empty ()
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1")) Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2")) Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
Mem1_Calls = ResizeArray ()
Mem2_Calls = ResizeArray ()
} }
interface PrivateType with interface PrivateType with
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1) member this.Mem1 (arg_0_0, arg_0_1) =
member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0) 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)
namespace SomeNamespace.CapturingMock namespace SomeNamespace.CapturingMock
open System open System
open WoofWare.Myriad.Plugins 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 /// Mock record type for an interface
type private PrivateTypeInternalFalseMock = type private PrivateTypeInternalFalseMock =
{ {
Calls : PrivateTypeInternalFalseMockCalls.Calls
Mem1 : string * int -> unit Mem1 : string * int -> unit
Mem1_Calls : ResizeArray<string * int>
Mem2 : string -> int Mem2 : string -> int
Mem2_Calls : ResizeArray<string>
} }
/// An implementation where every non-unit method throws. /// An implementation where every non-unit method throws.
static member Empty : PrivateTypeInternalFalseMock = static member Empty () : PrivateTypeInternalFalseMock =
{ {
Calls = PrivateTypeInternalFalseMockCalls.Calls.Empty ()
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1")) Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2")) Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
Mem1_Calls = ResizeArray ()
Mem2_Calls = ResizeArray ()
} }
interface PrivateTypeInternalFalse with interface PrivateTypeInternalFalse with
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1) member this.Mem1 (arg_0_0, arg_0_1) =
member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0) 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)
namespace SomeNamespace.CapturingMock namespace SomeNamespace.CapturingMock
open System open System
open WoofWare.Myriad.Plugins 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 /// Mock record type for an interface
type internal VeryPublicTypeMock<'a, 'b> = type internal VeryPublicTypeMock<'a, 'b> =
{ {
Calls : VeryPublicTypeMockCalls.Calls<'a, 'b>
Mem1 : 'a -> 'b Mem1 : 'a -> 'b
Mem1_Calls : ResizeArray<'a>
} }
/// An implementation where every non-unit method throws. /// An implementation where every non-unit method throws.
static member Empty () : VeryPublicTypeMock<'a, 'b> = static member Empty () : VeryPublicTypeMock<'a, 'b> =
{ {
Calls = VeryPublicTypeMockCalls.Calls.Empty ()
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1")) Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
Mem1_Calls = ResizeArray ()
} }
interface VeryPublicType<'a, 'b> with interface VeryPublicType<'a, 'b> with
member this.Mem1 arg_0_0 = this.Mem1 (arg_0_0) member this.Mem1 arg_0_0 =
lock this.Calls.Mem1 (fun _ -> this.Calls.Mem1.Add (arg_0_0))
this.Mem1 (arg_0_0)
namespace SomeNamespace.CapturingMock namespace SomeNamespace.CapturingMock
open System open System
open WoofWare.Myriad.Plugins open WoofWare.Myriad.Plugins
/// A single call to the Mem1 method [<RequireQualifiedAccess>]
type internal Mem1Call<'a> = module internal CurriedMockCalls =
{ /// A single call to the Mem1 method
arg0 : int type internal Mem1Call<'a> =
arg1 : 'a {
} bar : int
Arg1 : 'a
}
/// A single call to the Mem2 method /// A single call to the Mem2 method
type internal Mem2Call<'a> = type internal Mem2Call<'a> =
{ {
arg0 : int * string Arg0 : int * string
arg1 : 'a baz : 'a
} }
/// A single call to the Mem3 method /// A single call to the Mem3 method
type internal Mem3Call<'a> = type internal Mem3Call<'a> =
{ {
arg0 : int * string quux : (int * string)
arg1 : 'a flurb : 'a
} }
/// A single call to the Mem4 method /// A single call to the Mem4 method
type internal Mem4Call<'a> = type internal Mem4Call<'a> =
{ {
arg0 : int * string Arg0 : int * string
arg1 : 'a * int Arg1 : 'a * int
} }
/// A single call to the Mem5 method /// A single call to the Mem5 method
type internal Mem5Call<'a> = type internal Mem5Call<'a> =
{ {
arg0 : int * string Arg0 : int * string
arg1 : 'a * int Arg1 : 'a * int
} }
/// A single call to the Mem6 method /// A single call to the Mem6 method
type internal Mem6Call<'a> = type internal Mem6Call<'a> =
{ {
arg0 : int * string Arg0 : int * string
arg1 : 'a * int 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 /// Mock record type for an interface
type internal CurriedMock<'a> = type internal CurriedMock<'a> =
{ {
Calls : CurriedMockCalls.Calls<'a>
Mem1 : int -> 'a -> string Mem1 : int -> 'a -> string
Mem1_Calls : ResizeArray<Mem1Call<'a>>
Mem2 : int * string -> 'a -> string Mem2 : int * string -> 'a -> string
Mem2_Calls : ResizeArray<Mem2Call<'a>>
Mem3 : (int * string) -> 'a -> string Mem3 : (int * string) -> 'a -> string
Mem3_Calls : ResizeArray<Mem3Call<'a>>
Mem4 : (int * string) -> ('a * int) -> string Mem4 : (int * string) -> ('a * int) -> string
Mem4_Calls : ResizeArray<Mem4Call<'a>>
Mem5 : int * string -> ('a * int) -> string Mem5 : int * string -> ('a * int) -> string
Mem5_Calls : ResizeArray<Mem5Call<'a>>
Mem6 : int * string -> 'a * int -> string Mem6 : int * string -> 'a * int -> string
Mem6_Calls : ResizeArray<Mem6Call<'a>>
} }
/// An implementation where every non-unit method throws. /// An implementation where every non-unit method throws.
static member Empty () : CurriedMock<'a> = static member Empty () : CurriedMock<'a> =
{ {
Calls = CurriedMockCalls.Calls.Empty ()
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1")) Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2")) Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
Mem3 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem3")) Mem3 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem3"))
Mem4 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem4")) Mem4 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem4"))
Mem5 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem5")) Mem5 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem5"))
Mem6 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem6")) 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 interface Curried<'a> with
member this.Mem1 arg_0_0 arg_1_0 = this.Mem1 (arg_0_0) (arg_1_0) member 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) lock
member this.Mem3 ((arg_0_0, arg_0_1)) arg_1_0 = this.Mem3 (arg_0_0, arg_0_1) (arg_1_0) 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.Mem4 ((arg_0_0, arg_0_1)) ((arg_1_0, arg_1_1)) = 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) 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)) = 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) 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) = 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) this.Mem6 (arg_0_0, arg_0_1) (arg_1_0, arg_1_1)
namespace SomeNamespace.CapturingMock namespace SomeNamespace.CapturingMock
open System open System
open WoofWare.Myriad.Plugins 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 /// Mock record type for an interface
type internal TypeWithInterfaceMock = type internal TypeWithInterfaceMock =
{ {
Calls : TypeWithInterfaceMockCalls.Calls
/// Implementation of IDisposable.Dispose /// Implementation of IDisposable.Dispose
Dispose : unit -> unit Dispose : unit -> unit
Mem1 : string option -> string[] Async Mem1 : string option -> string[] Async
Mem1_Calls : ResizeArray<string option>
Mem2 : unit -> string[] Async Mem2 : unit -> string[] Async
Mem2_Calls : ResizeArray<unit>
} }
/// An implementation where every non-unit method throws. /// An implementation where every non-unit method throws.
static member Empty : TypeWithInterfaceMock = static member Empty () : TypeWithInterfaceMock =
{ {
Calls = TypeWithInterfaceMockCalls.Calls.Empty ()
Dispose = (fun () -> ()) Dispose = (fun () -> ())
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1")) Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2")) Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
Mem1_Calls = ResizeArray ()
Mem2_Calls = ResizeArray ()
} }
interface TypeWithInterface with interface TypeWithInterface with
member this.Mem1 arg_0_0 = this.Mem1 (arg_0_0) member this.Mem1 arg_0_0 =
member this.Mem2 () = this.Mem2 (()) 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 (())
interface System.IDisposable with interface System.IDisposable with
member this.Dispose () : unit = this.Dispose () member this.Dispose () : unit = this.Dispose ()
@@ -296,33 +511,50 @@ namespace SomeNamespace.CapturingMock
open System open System
open WoofWare.Myriad.Plugins 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 /// Mock record type for an interface
type internal TypeWithPropertiesMock = type internal TypeWithPropertiesMock =
{ {
Calls : TypeWithPropertiesMockCalls.Calls
/// Implementation of IDisposable.Dispose /// Implementation of IDisposable.Dispose
Dispose : unit -> unit Dispose : unit -> unit
Prop1 : unit -> int
Prop1_Calls : ResizeArray<unit>
Prop2 : unit -> unit Async
Prop2_Calls : ResizeArray<unit>
Mem1 : string option -> string[] Async Mem1 : string option -> string[] Async
Mem1_Calls : ResizeArray<string option> Prop1 : unit -> int
Prop2 : unit -> unit Async
} }
/// An implementation where every non-unit method throws. /// An implementation where every non-unit method throws.
static member Empty : TypeWithPropertiesMock = static member Empty () : TypeWithPropertiesMock =
{ {
Calls = TypeWithPropertiesMockCalls.Calls.Empty ()
Dispose = (fun () -> ()) Dispose = (fun () -> ())
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
Prop1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Prop1")) Prop1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Prop1"))
Prop2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Prop2")) 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 interface TypeWithProperties with
member this.Mem1 arg_0_0 = this.Mem1 (arg_0_0) 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.Prop1 = this.Prop1 () member this.Prop1 = this.Prop1 ()
member this.Prop2 = this.Prop2 () member this.Prop2 = this.Prop2 ()

View File

@@ -8,278 +8,493 @@ namespace SomeNamespace.CapturingMock
open System 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 /// Mock record type for an interface
type internal PublicTypeNoAttrMock = type internal PublicTypeNoAttrMock =
{ {
Calls : PublicTypeNoAttrMockCalls.Calls
Mem1 : string * int -> string list Mem1 : string * int -> string list
Mem1_Calls : ResizeArray<string * int>
Mem2 : string -> int Mem2 : string -> int
Mem2_Calls : ResizeArray<string> Mem3 : int * System.Threading.CancellationToken option -> string
Mem3 : int * option<System.Threading.CancellationToken> -> string
Mem3_Calls : ResizeArray<int * System.Threading.CancellationToken>
} }
/// An implementation where every non-unit method throws. /// An implementation where every non-unit method throws.
static member Empty : PublicTypeNoAttrMock = static member Empty () : PublicTypeNoAttrMock =
{ {
Calls = PublicTypeNoAttrMockCalls.Calls.Empty ()
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1")) Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2")) Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
Mem3 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem3")) Mem3 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem3"))
Mem1_Calls = ResizeArray ()
Mem2_Calls = ResizeArray ()
Mem3_Calls = ResizeArray ()
} }
interface IPublicTypeNoAttr with interface IPublicTypeNoAttr with
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1) member this.Mem1 (arg_0_0, arg_0_1) =
member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0) lock this.Calls.Mem1 (fun _ -> this.Calls.Mem1.Add (arg_0_0, arg_0_1))
member this.Mem3 (arg_0_0, arg_0_1) = this.Mem3 (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)
namespace SomeNamespace.CapturingMock namespace SomeNamespace.CapturingMock
open System 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 /// Mock record type for an interface
type public PublicTypeInternalFalseNoAttrMock = type public PublicTypeInternalFalseNoAttrMock =
{ {
Calls : PublicTypeInternalFalseNoAttrMockCalls.Calls
Mem1 : string * int -> string list Mem1 : string * int -> string list
Mem1_Calls : ResizeArray<string * int>
Mem2 : string -> int Mem2 : string -> int
Mem2_Calls : ResizeArray<string> Mem3 : int * System.Threading.CancellationToken option -> string
Mem3 : int * option<System.Threading.CancellationToken> -> string
Mem3_Calls : ResizeArray<int * System.Threading.CancellationToken>
} }
/// An implementation where every non-unit method throws. /// An implementation where every non-unit method throws.
static member Empty : PublicTypeInternalFalseNoAttrMock = static member Empty () : PublicTypeInternalFalseNoAttrMock =
{ {
Calls = PublicTypeInternalFalseNoAttrMockCalls.Calls.Empty ()
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1")) Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2")) Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
Mem3 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem3")) Mem3 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem3"))
Mem1_Calls = ResizeArray ()
Mem2_Calls = ResizeArray ()
Mem3_Calls = ResizeArray ()
} }
interface IPublicTypeInternalFalseNoAttr with interface IPublicTypeInternalFalseNoAttr with
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1) member this.Mem1 (arg_0_0, arg_0_1) =
member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0) lock this.Calls.Mem1 (fun _ -> this.Calls.Mem1.Add (arg_0_0, arg_0_1))
member this.Mem3 (arg_0_0, arg_0_1) = this.Mem3 (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)
namespace SomeNamespace.CapturingMock namespace SomeNamespace.CapturingMock
open System 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 /// Mock record type for an interface
type internal InternalTypeNoAttrMock = type internal InternalTypeNoAttrMock =
{ {
Calls : InternalTypeNoAttrMockCalls.Calls
Mem1 : string * int -> unit Mem1 : string * int -> unit
Mem1_Calls : ResizeArray<string * int>
Mem2 : string -> int Mem2 : string -> int
Mem2_Calls : ResizeArray<string>
} }
/// An implementation where every non-unit method throws. /// An implementation where every non-unit method throws.
static member Empty : InternalTypeNoAttrMock = static member Empty () : InternalTypeNoAttrMock =
{ {
Calls = InternalTypeNoAttrMockCalls.Calls.Empty ()
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1")) Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2")) Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
Mem1_Calls = ResizeArray ()
Mem2_Calls = ResizeArray ()
} }
interface InternalTypeNoAttr with interface InternalTypeNoAttr with
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1) member this.Mem1 (arg_0_0, arg_0_1) =
member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0) 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)
namespace SomeNamespace.CapturingMock namespace SomeNamespace.CapturingMock
open System 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 /// Mock record type for an interface
type private PrivateTypeNoAttrMock = type private PrivateTypeNoAttrMock =
{ {
Calls : PrivateTypeNoAttrMockCalls.Calls
Mem1 : string * int -> unit Mem1 : string * int -> unit
Mem1_Calls : ResizeArray<string * int>
Mem2 : string -> int Mem2 : string -> int
Mem2_Calls : ResizeArray<string>
} }
/// An implementation where every non-unit method throws. /// An implementation where every non-unit method throws.
static member Empty : PrivateTypeNoAttrMock = static member Empty () : PrivateTypeNoAttrMock =
{ {
Calls = PrivateTypeNoAttrMockCalls.Calls.Empty ()
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1")) Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2")) Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
Mem1_Calls = ResizeArray ()
Mem2_Calls = ResizeArray ()
} }
interface PrivateTypeNoAttr with interface PrivateTypeNoAttr with
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1) member this.Mem1 (arg_0_0, arg_0_1) =
member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0) 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)
namespace SomeNamespace.CapturingMock namespace SomeNamespace.CapturingMock
open System 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 /// Mock record type for an interface
type private PrivateTypeInternalFalseNoAttrMock = type private PrivateTypeInternalFalseNoAttrMock =
{ {
Calls : PrivateTypeInternalFalseNoAttrMockCalls.Calls
Mem1 : string * int -> unit Mem1 : string * int -> unit
Mem1_Calls : ResizeArray<string * int>
Mem2 : string -> int Mem2 : string -> int
Mem2_Calls : ResizeArray<string>
} }
/// An implementation where every non-unit method throws. /// An implementation where every non-unit method throws.
static member Empty : PrivateTypeInternalFalseNoAttrMock = static member Empty () : PrivateTypeInternalFalseNoAttrMock =
{ {
Calls = PrivateTypeInternalFalseNoAttrMockCalls.Calls.Empty ()
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1")) Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2")) Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
Mem1_Calls = ResizeArray ()
Mem2_Calls = ResizeArray ()
} }
interface PrivateTypeInternalFalseNoAttr with interface PrivateTypeInternalFalseNoAttr with
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1) member this.Mem1 (arg_0_0, arg_0_1) =
member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0) 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)
namespace SomeNamespace.CapturingMock namespace SomeNamespace.CapturingMock
open System 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 /// Mock record type for an interface
type internal VeryPublicTypeNoAttrMock<'a, 'b> = type internal VeryPublicTypeNoAttrMock<'a, 'b> =
{ {
Calls : VeryPublicTypeNoAttrMockCalls.Calls<'a, 'b>
Mem1 : 'a -> 'b Mem1 : 'a -> 'b
Mem1_Calls : ResizeArray<'a>
} }
/// An implementation where every non-unit method throws. /// An implementation where every non-unit method throws.
static member Empty () : VeryPublicTypeNoAttrMock<'a, 'b> = static member Empty () : VeryPublicTypeNoAttrMock<'a, 'b> =
{ {
Calls = VeryPublicTypeNoAttrMockCalls.Calls.Empty ()
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1")) Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
Mem1_Calls = ResizeArray ()
} }
interface VeryPublicTypeNoAttr<'a, 'b> with interface VeryPublicTypeNoAttr<'a, 'b> with
member this.Mem1 arg_0_0 = this.Mem1 (arg_0_0) member this.Mem1 arg_0_0 =
lock this.Calls.Mem1 (fun _ -> this.Calls.Mem1.Add (arg_0_0))
this.Mem1 (arg_0_0)
namespace SomeNamespace.CapturingMock namespace SomeNamespace.CapturingMock
open System open System
/// A single call to the Mem1 method [<RequireQualifiedAccess>]
type internal Mem1Call<'a> = module internal CurriedNoAttrMockCalls =
{ /// A single call to the Mem1 method
arg0 : int type internal Mem1Call<'a> =
arg1 : 'a {
} Arg0 : int
Arg1 : 'a
}
/// A single call to the Mem2 method /// A single call to the Mem2 method
type internal Mem2Call<'a> = type internal Mem2Call<'a> =
{ {
arg0 : int * string Arg0 : int * string
arg1 : 'a Arg1 : 'a
} }
/// A single call to the Mem3 method /// A single call to the Mem3 method
type internal Mem3Call<'a> = type internal Mem3Call<'a> =
{ {
arg0 : int * string Arg0 : int * string
arg1 : 'a Arg1 : 'a
} }
/// A single call to the Mem4 method /// A single call to the Mem4 method
type internal Mem4Call<'a> = type internal Mem4Call<'a> =
{ {
arg0 : int * string Arg0 : int * string
arg1 : 'a * int Arg1 : 'a * int
} }
/// A single call to the Mem5 method /// A single call to the Mem5 method
type internal Mem5Call<'a> = type internal Mem5Call<'a> =
{ {
arg0 : int * string Arg0 : int * string
arg1 : 'a * int Arg1 : 'a * int
} }
/// A single call to the Mem6 method /// A single call to the Mem6 method
type internal Mem6Call<'a> = type internal Mem6Call<'a> =
{ {
arg0 : int * string Arg0 : int * string
arg1 : 'a * int 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 /// Mock record type for an interface
type internal CurriedNoAttrMock<'a> = type internal CurriedNoAttrMock<'a> =
{ {
Calls : CurriedNoAttrMockCalls.Calls<'a>
Mem1 : int -> 'a -> string Mem1 : int -> 'a -> string
Mem1_Calls : ResizeArray<Mem1Call<'a>>
Mem2 : int * string -> 'a -> string Mem2 : int * string -> 'a -> string
Mem2_Calls : ResizeArray<Mem2Call<'a>>
Mem3 : (int * string) -> 'a -> string Mem3 : (int * string) -> 'a -> string
Mem3_Calls : ResizeArray<Mem3Call<'a>>
Mem4 : (int * string) -> ('a * int) -> string Mem4 : (int * string) -> ('a * int) -> string
Mem4_Calls : ResizeArray<Mem4Call<'a>>
Mem5 : int * string -> ('a * int) -> string Mem5 : int * string -> ('a * int) -> string
Mem5_Calls : ResizeArray<Mem5Call<'a>>
Mem6 : int * string -> 'a * int -> string Mem6 : int * string -> 'a * int -> string
Mem6_Calls : ResizeArray<Mem6Call<'a>>
} }
/// An implementation where every non-unit method throws. /// An implementation where every non-unit method throws.
static member Empty () : CurriedNoAttrMock<'a> = static member Empty () : CurriedNoAttrMock<'a> =
{ {
Calls = CurriedNoAttrMockCalls.Calls.Empty ()
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1")) Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2")) Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
Mem3 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem3")) Mem3 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem3"))
Mem4 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem4")) Mem4 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem4"))
Mem5 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem5")) Mem5 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem5"))
Mem6 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem6")) 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 interface CurriedNoAttr<'a> with
member this.Mem1 arg_0_0 arg_1_0 = this.Mem1 (arg_0_0) (arg_1_0) member 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) lock
member this.Mem3 ((arg_0_0, arg_0_1)) arg_1_0 = this.Mem3 (arg_0_0, arg_0_1) (arg_1_0) 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.Mem4 ((arg_0_0, arg_0_1)) ((arg_1_0, arg_1_1)) = 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) 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)) = 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) 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) = 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) this.Mem6 (arg_0_0, arg_0_1) (arg_1_0, arg_1_1)
namespace SomeNamespace.CapturingMock namespace SomeNamespace.CapturingMock
open System 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 /// Mock record type for an interface
type internal TypeWithInterfaceNoAttrMock = type internal TypeWithInterfaceNoAttrMock =
{ {
Calls : TypeWithInterfaceNoAttrMockCalls.Calls
/// Implementation of IDisposable.Dispose /// Implementation of IDisposable.Dispose
Dispose : unit -> unit Dispose : unit -> unit
Mem1 : string option -> string[] Async Mem1 : string option -> string[] Async
Mem1_Calls : ResizeArray<string option>
Mem2 : unit -> string[] Async Mem2 : unit -> string[] Async
Mem2_Calls : ResizeArray<unit>
} }
/// An implementation where every non-unit method throws. /// An implementation where every non-unit method throws.
static member Empty : TypeWithInterfaceNoAttrMock = static member Empty () : TypeWithInterfaceNoAttrMock =
{ {
Calls = TypeWithInterfaceNoAttrMockCalls.Calls.Empty ()
Dispose = (fun () -> ()) Dispose = (fun () -> ())
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1")) Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2")) Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
Mem1_Calls = ResizeArray ()
Mem2_Calls = ResizeArray ()
} }
interface TypeWithInterfaceNoAttr with interface TypeWithInterfaceNoAttr with
member this.Mem1 arg_0_0 = this.Mem1 (arg_0_0) member this.Mem1 arg_0_0 =
member this.Mem2 () = this.Mem2 (()) 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 (())
interface System.IDisposable with interface System.IDisposable with
member this.Dispose () : unit = this.Dispose () member this.Dispose () : unit = this.Dispose ()

View File

@@ -10,7 +10,7 @@
<WarnOn>FS3388,FS3559</WarnOn> <WarnOn>FS3388,FS3559</WarnOn>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Nerdbank.GitVersioning" Version="3.8.38-alpha" PrivateAssets="all" /> <PackageReference Include="Nerdbank.GitVersioning" Version="3.8.118" PrivateAssets="all" />
<SourceLinkGitHubHost Include="github.com" ContentUrl="https://raw.githubusercontent.com" /> <SourceLinkGitHubHost Include="github.com" ContentUrl="https://raw.githubusercontent.com" />
</ItemGroup> </ItemGroup>
<PropertyGroup Condition="'$(GITHUB_ACTION)' != ''"> <PropertyGroup Condition="'$(GITHUB_ACTION)' != ''">

View File

@@ -13,7 +13,7 @@ Currently implemented:
* `JsonParse` (to stamp out `jsonParse : JsonNode -> 'T` methods). * `JsonParse` (to stamp out `jsonParse : JsonNode -> 'T` methods).
* `JsonSerialize` (to stamp out `toJsonNode : 'T -> JsonNode` methods). * `JsonSerialize` (to stamp out `toJsonNode : 'T -> JsonNode` methods).
* `HttpClient` (to stamp out a [RestEase](https://github.com/canton7/RestEase)-style HTTP client). * `HttpClient` (to stamp out a [RestEase](https://github.com/canton7/RestEase)-style HTTP client).
* `GenerateMock` (to stamp out a record type corresponding to an interface, like a compile-time [Foq](https://github.com/fsprojects/Foq)). * `GenerateMock` and `GenerateCapturingMock` (to stamp out a record type corresponding to an interface, like a compile-time [Foq](https://github.com/fsprojects/Foq)).
* `ArgParser` (to stamp out a basic argument parser). * `ArgParser` (to stamp out a basic argument parser).
* `SwaggerClient` (to stamp out an HTTP client for a Swagger API). * `SwaggerClient` (to stamp out an HTTP client for a Swagger API).
* `CreateCatamorphism` (to stamp out a non-stack-overflowing [catamorphism](https://fsharpforfunandprofit.com/posts/recursive-types-and-folds/) for a discriminated union). * `CreateCatamorphism` (to stamp out a non-stack-overflowing [catamorphism](https://fsharpforfunandprofit.com/posts/recursive-types-and-folds/) for a discriminated union).
@@ -440,9 +440,9 @@ There are also some design decisions:
so arguments are forced to be tupled. so arguments are forced to be tupled.
* The `[<Optional>]` attribute is not supported and will probably not be supported, because I consider it to be cursed. * The `[<Optional>]` attribute is not supported and will probably not be supported, because I consider it to be cursed.
## `GenerateMock` ## `GenerateMock` and `GenerateCapturingMock`
Takes a type like this: `GenerateMock` takes a type like this:
```fsharp ```fsharp
[<GenerateMock>] [<GenerateMock>]
@@ -472,6 +472,59 @@ type internal PublicTypeMock =
member this.Mem2 (arg0) = this.Mem2 (arg0) member this.Mem2 (arg0) = this.Mem2 (arg0)
``` ```
`GenerateCapturingMock` additionally captures the calls made to each function (except for `Dispose`).
It takes a type like this:
```fsharp
[<GenerateCapturingMock>]
type IPublicType =
abstract Mem1 : string * int -> thing : bool -> string list
abstract Mem2 : baz : string -> unit -> int
```
and stamps out types like this:
```fsharp
[<RequireQualifiedAccess>]
module internal PublicTypeCalls =
type internal Mem1Call =
{
Arg0 : string * int
thing : bool
}
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
Mem2 : string -> int
Calls : PublicTypeCalls.Calls
}
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 ()
}
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)
```
### What's the point? ### What's the point?
Reflective mocking libraries like [Foq](https://github.com/fsprojects/Foq) in my experience are a rich source of flaky tests. Reflective mocking libraries like [Foq](https://github.com/fsprojects/Foq) in my experience are a rich source of flaky tests.
@@ -483,6 +536,36 @@ 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>]`. * 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` ## `CreateCatamorphism`
Takes a collection of mutually recursive discriminated unions: Takes a collection of mutually recursive discriminated unions:

View File

@@ -32,7 +32,11 @@ type GenerateMockAttribute (isInternal : bool) =
/// record update syntax to easily specify partially-implemented mock objects. /// 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. /// You may optionally specify `isInternal = false` to get a mock with the public visibility modifier.
/// ///
/// The default implementation of each field captures all calls made to it, which can then be accessed later. /// 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.
type GenerateCapturingMockAttribute (isInternal : bool) = type GenerateCapturingMockAttribute (isInternal : bool) =
inherit Attribute () inherit Attribute ()
/// The default value of `isInternal`, the optional argument to the GenerateCapturingMockAttribute constructor. /// The default value of `isInternal`, the optional argument to the GenerateCapturingMockAttribute constructor.

View File

@@ -15,6 +15,11 @@ WoofWare.Myriad.Plugins.ArgumentLongForm inherit System.Attribute
WoofWare.Myriad.Plugins.ArgumentLongForm..ctor [constructor]: string WoofWare.Myriad.Plugins.ArgumentLongForm..ctor [constructor]: string
WoofWare.Myriad.Plugins.CreateCatamorphismAttribute inherit System.Attribute WoofWare.Myriad.Plugins.CreateCatamorphismAttribute inherit System.Attribute
WoofWare.Myriad.Plugins.CreateCatamorphismAttribute..ctor [constructor]: string WoofWare.Myriad.Plugins.CreateCatamorphismAttribute..ctor [constructor]: string
WoofWare.Myriad.Plugins.GenerateCapturingMockAttribute inherit System.Attribute
WoofWare.Myriad.Plugins.GenerateCapturingMockAttribute..ctor [constructor]: bool
WoofWare.Myriad.Plugins.GenerateCapturingMockAttribute..ctor [constructor]: unit
WoofWare.Myriad.Plugins.GenerateCapturingMockAttribute.DefaultIsInternal [static property]: [read-only] bool
WoofWare.Myriad.Plugins.GenerateCapturingMockAttribute.get_DefaultIsInternal [static method]: unit -> bool
WoofWare.Myriad.Plugins.GenerateMockAttribute inherit System.Attribute WoofWare.Myriad.Plugins.GenerateMockAttribute inherit System.Attribute
WoofWare.Myriad.Plugins.GenerateMockAttribute..ctor [constructor]: bool WoofWare.Myriad.Plugins.GenerateMockAttribute..ctor [constructor]: bool
WoofWare.Myriad.Plugins.GenerateMockAttribute..ctor [constructor]: unit WoofWare.Myriad.Plugins.GenerateMockAttribute..ctor [constructor]: unit

View File

@@ -1,5 +1,5 @@
{ {
"version": "3.6", "version": "3.7",
"publicReleaseRefSpec": [ "publicReleaseRefSpec": [
"^refs/heads/main$" "^refs/heads/main$"
], ],

View File

@@ -6,12 +6,12 @@ open NUnit.Framework
open FsUnitTyped open FsUnitTyped
[<TestFixture>] [<TestFixture>]
module TestMockGenerator = module TestCapturingMockGenerator =
[<Test>] [<Test>]
let ``Example of use: IPublicType`` () = let ``Example of use: IPublicType`` () =
let mock : IPublicType = let mock : IPublicType =
{ PublicTypeMock.Empty with { PublicTypeMock.Empty () with
Mem1 = fun (s, count) -> List.replicate count s Mem1 = fun (s, count) -> List.replicate count s
} }
:> _ :> _
@@ -38,7 +38,7 @@ module TestMockGenerator =
[<Test>] [<Test>]
let ``Example of use: properties`` () = let ``Example of use: properties`` () =
let mock : TypeWithProperties = let mock : TypeWithProperties =
{ TypeWithPropertiesMock.Empty with { TypeWithPropertiesMock.Empty () with
Mem1 = fun i -> async { return Option.toArray i } Mem1 = fun i -> async { return Option.toArray i }
Prop1 = fun () -> 44 Prop1 = fun () -> 44
} }
@@ -47,3 +47,26 @@ module TestMockGenerator =
mock.Mem1 (Some "hi") |> Async.RunSynchronously |> shouldEqual [| "hi" |] mock.Mem1 (Some "hi") |> Async.RunSynchronously |> shouldEqual [| "hi" |]
mock.Prop1 |> shouldEqual 44 mock.Prop1 |> shouldEqual 44
[<Test>]
let ``Example of curried use`` () =
let mock' =
{ CurriedMock<string>.Empty () with
Mem1 =
fun x y ->
x |> shouldEqual 3
y |> shouldEqual "hello"
"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)
|> List.exactlyOne
|> shouldEqual
{
bar = 3
Arg1 = "hello"
}

View File

@@ -11,7 +11,7 @@ module TestCapturingMockGeneratorNoAttr =
[<Test>] [<Test>]
let ``Example of use: IPublicType`` () = let ``Example of use: IPublicType`` () =
let mock : IPublicTypeNoAttr = let mock : IPublicTypeNoAttr =
{ PublicTypeNoAttrMock.Empty with { PublicTypeNoAttrMock.Empty () with
Mem1 = fun (s, count) -> List.replicate count s Mem1 = fun (s, count) -> List.replicate count s
} }
:> _ :> _

View File

@@ -6,7 +6,7 @@ open NUnit.Framework
open FsUnitTyped open FsUnitTyped
[<TestFixture>] [<TestFixture>]
module TestCapturingMockGeneratorNoAttr = module TestMockGeneratorNoAttr =
[<Test>] [<Test>]
let ``Example of use: IPublicType`` () = let ``Example of use: IPublicType`` () =

View File

@@ -28,7 +28,9 @@
<Compile Include="TestHttpClient\TestVaultClient.fs" /> <Compile Include="TestHttpClient\TestVaultClient.fs" />
<Compile Include="TestHttpClient\TestVariableHeader.fs" /> <Compile Include="TestHttpClient\TestVariableHeader.fs" />
<Compile Include="TestMockGenerator\TestMockGenerator.fs" /> <Compile Include="TestMockGenerator\TestMockGenerator.fs" />
<Compile Include="TestMockGenerator\TestCapturingMockGeneratorNoAttr.fs" /> <Compile Include="TestMockGenerator\TestMockGeneratorNoAttr.fs" />
<Compile Include="TestCapturingMockGenerator\TestCapturingMockGenerator.fs" />
<Compile Include="TestCapturingMockGenerator\TestCapturingMockGeneratorNoAttr.fs" />
<Compile Include="TestJsonSerialize\TestJsonSerde.fs" /> <Compile Include="TestJsonSerialize\TestJsonSerde.fs" />
<Compile Include="TestCataGenerator\TestCataGenerator.fs" /> <Compile Include="TestCataGenerator\TestCataGenerator.fs" />
<Compile Include="TestCataGenerator\TestDirectory.fs" /> <Compile Include="TestCataGenerator\TestDirectory.fs" />
@@ -67,9 +69,4 @@
<ProjectReference Include="..\ConsumePlugin\ConsumePlugin.fsproj" /> <ProjectReference Include="..\ConsumePlugin\ConsumePlugin.fsproj" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Compile Include="TestCapturingMockGenerator\TestCapturingMockGenerator.fs" />
<Compile Include="TestCapturingMockGenerator\TestCapturingMockGeneratorNoAttr.fs" />
</ItemGroup>
</Project> </Project>

View File

@@ -41,11 +41,21 @@ module internal CapturingInterfaceMockGenerator =
args args
|> List.mapi (fun i tupledArg -> |> List.mapi (fun i tupledArg ->
{ {
SynFieldData.Ident = $"arg%i{i}" |> Ident.create |> Some SynFieldData.Ident =
match tupledArg.Args with
| [ arg ] -> arg.Id
| _ -> None
|> Option.defaultValue (Ident.create $"Arg%i{i}")
|> Some
Attrs = [] Attrs = []
Type = Type =
tupledArg.Args tupledArg.Args
|> List.map (fun pi -> pi.Type) |> List.map (fun pi ->
if pi.IsOptional then
pi.Type |> SynType.appPostfix "option"
else
pi.Type
)
|> SynType.tupleNoParen |> SynType.tupleNoParen
|> Option.get |> Option.get
} }
@@ -70,7 +80,7 @@ module internal CapturingInterfaceMockGenerator =
let private buildType (x : ParameterInfo) : SynType = let private buildType (x : ParameterInfo) : SynType =
if x.IsOptional then if x.IsOptional then
SynType.app "option" [ x.Type ] SynType.appPostfix "option" x.Type
else else
x.Type x.Type
@@ -115,12 +125,7 @@ module internal CapturingInterfaceMockGenerator =
/// Builds the record field for the mock object, and also if applicable a type representing a single call to /// Builds the record field for the mock object, and also if applicable a type representing a single call to
/// that object (packaging up the args of the call). /// that object (packaging up the args of the call).
let private constructMember let private constructMember (spec : CapturingInterfaceMockOutputSpec) (mem : MemberInfo) : SynField * CallField =
(spec : CapturingInterfaceMockOutputSpec)
(generics : SynTyparDecls option)
(mem : MemberInfo)
: SynField * CallField
=
let inputType = mem.Args |> List.map constructMemberSinglePlace let inputType = mem.Args |> List.map constructMemberSinglePlace
let funcType = SynType.toFun inputType mem.ReturnType let funcType = SynType.toFun inputType mem.ReturnType
@@ -139,7 +144,12 @@ module internal CapturingInterfaceMockGenerator =
| [] -> failwith "expected args in member" | [] -> failwith "expected args in member"
| [ ty ] -> | [ ty ] ->
ty.Args ty.Args
|> List.map _.Type |> List.map (fun pi ->
if pi.IsOptional then
SynType.appPostfix "option" pi.Type
else
pi.Type
)
|> SynType.tupleNoParen |> SynType.tupleNoParen
|> Option.get |> Option.get
|> CallField.Original |> CallField.Original
@@ -179,11 +189,11 @@ module internal CapturingInterfaceMockGenerator =
(name : string) (name : string)
(interfaceType : InterfaceType) (interfaceType : InterfaceType)
(xmlDoc : PreXmlDoc) (xmlDoc : PreXmlDoc)
: SynModuleDecl : SynModuleDecl option * SynModuleDecl
= =
let fields = let fields =
interfaceType.Members interfaceType.Members
|> List.map (constructMember spec interfaceType.Generics) |> List.map (constructMember spec)
|> List.append ( |> List.append (
interfaceType.Properties interfaceType.Properties
|> List.map constructProperty |> List.map constructProperty
@@ -214,8 +224,9 @@ module internal CapturingInterfaceMockGenerator =
| None -> failwith $"unexpectedly got a field with no identifier: %O{f}" | None -> failwith $"unexpectedly got a field with no identifier: %O{f}"
| Some idOpt -> idOpt.idText | Some idOpt -> idOpt.idText
f, extraType, fieldName fieldName, (f, extraType)
) )
|> Map.ofList
let failwithNotImplemented (fieldName : string) = let failwithNotImplemented (fieldName : string) =
let failString = SynExpr.CreateConst $"Unimplemented mock function: %s{fieldName}" let failString = SynExpr.CreateConst $"Unimplemented mock function: %s{fieldName}"
@@ -248,32 +259,21 @@ module internal CapturingInterfaceMockGenerator =
let originalMembers = let originalMembers =
fields fields
|> List.map (fun (_, _, fieldName) -> SynLongIdent.createS fieldName, failwithNotImplemented fieldName) |> Map.toList
|> List.map (fun (fieldName, _) -> SynLongIdent.createS fieldName, failwithNotImplemented fieldName)
let callsArrays = let callsObject =
fields SynLongIdent.createS "Calls",
|> List.map (fun (_field, extraType, fieldName) -> SynExpr.applyFunction
let name = SynLongIdent.createS $"{fieldName}_Calls" (SynExpr.createLongIdent [ $"%s{name}Calls" ; "Calls" ; "Empty" ])
(SynExpr.CreateConst ())
let init = callsObject :: interfaceExtras @ originalMembers
match extraType with
| CallField.Original _ ->
SynExpr.createIdent "ResizeArray" |> SynExpr.applyTo (SynExpr.CreateConst ())
| CallField.ArgsObject _ ->
SynExpr.createIdent "ResizeArray" |> SynExpr.applyTo (SynExpr.CreateConst ())
name, init
)
interfaceExtras @ originalMembers @ callsArrays
let staticMemberEmpty = let staticMemberEmpty =
SynBinding.basic SynBinding.basic
[ Ident.create "Empty" ] [ Ident.create "Empty" ]
(if interfaceType.Generics.IsNone then [ SynPat.unit ]
[]
else
[ SynPat.unit ])
(SynExpr.createRecord None emptyRecordFieldInstantiations) (SynExpr.createRecord None emptyRecordFieldInstantiations)
|> SynBinding.withXmlDoc (PreXmlDoc.create "An implementation where every non-unit method throws.") |> SynBinding.withXmlDoc (PreXmlDoc.create "An implementation where every non-unit method throws.")
|> SynBinding.withReturnAnnotation constructorReturnType |> SynBinding.withReturnAnnotation constructorReturnType
@@ -294,37 +294,109 @@ module internal CapturingInterfaceMockGenerator =
[] []
let nonExtras = 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 fields
|> List.collect (fun (field, callType, fieldName) -> |> Map.toSeq
let callField = |> Seq.map (fun (fieldName, (_, callType)) ->
match callType with match callType with
| CallField.Original ty -> | CallField.Original ty ->
{ {
Attrs = [] Attrs = []
Ident = Some (fieldName + "_Calls" |> Ident.create) Ident = Some (fieldName |> Ident.create)
Type = SynType.app "ResizeArray" [ ty ] Type = SynType.app "ResizeArray" [ ty ]
} }
|> SynField.make |> SynField.make
| CallField.ArgsObject (name, _, generics) -> | CallField.ArgsObject (argsObjectName, _, generics) ->
{ {
Attrs = [] Attrs = []
Ident = Some (fieldName + "_Calls" |> Ident.create) Ident = Some (fieldName |> Ident.create)
Type = Type =
match generics with match generics with
| None -> SynType.named name.idText | None -> SynType.named argsObjectName.idText
| Some generics -> | Some generics ->
generics.TyparDecls generics.TyparDecls
|> List.map (fun (SynTyparDecl.SynTyparDecl (_, typar)) -> SynType.var typar) |> List.map (fun (SynTyparDecl.SynTyparDecl (_, typar)) -> SynType.var typar)
|> SynType.app name.idText |> SynType.app' (SynType.createLongIdent' [ argsObjectName.idText ])
|> List.singleton |> List.singleton
|> SynType.app "ResizeArray" |> SynType.app "ResizeArray"
} }
|> SynField.make |> SynField.make
[ field ; callField ]
) )
|> Seq.toList
extras @ nonExtras 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
let interfaceMembers = let interfaceMembers =
let members = let members =
@@ -348,28 +420,65 @@ module internal CapturingInterfaceMockGenerator =
|> fun i -> if tupledArgs.HasParen then SynPat.paren i else i |> fun i -> if tupledArgs.HasParen then SynPat.paren i else i
) )
let body = let body, addToCalls =
let tuples = let tupleContents =
memberInfo.Args memberInfo.Args
|> List.mapi (fun i args -> |> List.mapi (fun i args ->
args.Args args.Args
|> List.mapi (fun j arg -> |> List.mapi (fun j arg ->
match arg.Type with match arg.Type with
| UnitType -> SynExpr.CreateConst () | UnitType -> SynExpr.CreateConst (), arg.Id
| _ -> SynExpr.createIdent $"arg_%i{i}_%i{j}" | _ -> SynExpr.createIdent $"arg_%i{i}_%i{j}", arg.Id
) )
|> SynExpr.tuple
) )
let tuples = tupleContents |> List.map (List.map fst >> SynExpr.tuple)
match tuples |> List.rev with match tuples |> List.rev with
| [] -> failwith "expected args but got none" | [] -> failwith "expected args but got none"
| last :: rest -> | last :: rest ->
(last, rest) let tuples = (last, rest) ||> List.fold SynExpr.applyTo
||> List.fold SynExpr.applyTo
|> SynExpr.applyFunction ( let body =
SynExpr.createLongIdent' [ Ident.create "this" ; memberInfo.Identifier ] 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
SynBinding.basic [ Ident.create "this" ; memberInfo.Identifier ] headArgs body SynBinding.basic [ Ident.create "this" ; memberInfo.Identifier ] headArgs body
|> SynMemberDefn.memberImplementation |> SynMemberDefn.memberImplementation
@@ -401,15 +510,6 @@ module internal CapturingInterfaceMockGenerator =
SynMemberDefn.Interface (interfaceName, Some range0, Some (members @ properties), range0) 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 = let extraInterfaces =
inherits inherits
|> Seq.map (fun inheritance -> |> Seq.map (fun inheritance ->
@@ -445,16 +545,26 @@ module internal CapturingInterfaceMockGenerator =
let typeDecl = AstHelper.defineRecordType record let typeDecl = AstHelper.defineRecordType record
SynModuleDecl.Types ( let callsModule =
[ let types =
for _, field, _ in fields do fields
|> Map.toSeq
|> Seq.choose (fun (_, (_, field)) ->
match field with match field with
| CallField.Original _ -> () | CallField.Original _ -> None
| CallField.ArgsObject (_, callType, _) -> yield callType | CallField.ArgsObject (_, callType, _) -> Some (SynModuleDecl.Types ([ callType ], range0))
yield typeDecl )
], |> Seq.toList
range0
) types @ [ SynModuleDecl.Types ([ callsObject ], range0) ]
|> SynModuleDecl.nestedModule (
SynComponentInfo.create (Ident.create $"%s{name}Calls")
|> SynComponentInfo.withAccessibility accessAtLeastInternal
|> SynComponentInfo.addAttributes [ SynAttribute.requireQualifiedAccess ]
)
|> Some
(callsModule, SynModuleDecl.Types ([ typeDecl ], range0))
let createRecord let createRecord
(namespaceId : LongIdent) (namespaceId : LongIdent)
@@ -476,9 +586,15 @@ module internal CapturingInterfaceMockGenerator =
s s
|> fun s -> s + "Mock" |> fun s -> s + "Mock"
let typeDecl = createType spec name interfaceType docString let callsTypes, typeDecl = createType spec name interfaceType docString
[ yield! opens |> List.map SynModuleDecl.openAny ; yield typeDecl ] [
yield! opens |> List.map SynModuleDecl.openAny
match callsTypes with
| None -> ()
| Some c -> yield c
yield typeDecl
]
|> SynModuleOrNamespace.createNamespace namespaceId |> SynModuleOrNamespace.createNamespace namespaceId
open Myriad.Core open Myriad.Core

View File

@@ -1,5 +1,7 @@
WoofWare.Myriad.Plugins.ArgParserGenerator inherit obj, implements Myriad.Core.IMyriadGenerator WoofWare.Myriad.Plugins.ArgParserGenerator inherit obj, implements Myriad.Core.IMyriadGenerator
WoofWare.Myriad.Plugins.ArgParserGenerator..ctor [constructor]: unit WoofWare.Myriad.Plugins.ArgParserGenerator..ctor [constructor]: unit
WoofWare.Myriad.Plugins.CapturingInterfaceMockGenerator inherit obj, implements Myriad.Core.IMyriadGenerator
WoofWare.Myriad.Plugins.CapturingInterfaceMockGenerator..ctor [constructor]: unit
WoofWare.Myriad.Plugins.CreateCatamorphismGenerator inherit obj, implements Myriad.Core.IMyriadGenerator WoofWare.Myriad.Plugins.CreateCatamorphismGenerator inherit obj, implements Myriad.Core.IMyriadGenerator
WoofWare.Myriad.Plugins.CreateCatamorphismGenerator..ctor [constructor]: unit WoofWare.Myriad.Plugins.CreateCatamorphismGenerator..ctor [constructor]: unit
WoofWare.Myriad.Plugins.HttpClientGenerator inherit obj, implements Myriad.Core.IMyriadGenerator WoofWare.Myriad.Plugins.HttpClientGenerator inherit obj, implements Myriad.Core.IMyriadGenerator

View File

@@ -1,5 +1,5 @@
{ {
"version": "8.0", "version": "9.0",
"publicReleaseRefSpec": [ "publicReleaseRefSpec": [
"^refs/heads/main$" "^refs/heads/main$"
], ],

6
flake.lock generated
View File

@@ -20,11 +20,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1757746433, "lastModified": 1758976413,
"narHash": "sha256-fEvTiU4s9lWgW7mYEU/1QUPirgkn+odUBTaindgiziY=", "narHash": "sha256-hEIDTaIqvW1NMfaNgz6pjhZPZKTmACJmXxGr/H6isIg=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "6d7ec06d6868ac6d94c371458fc2391ded9ff13d", "rev": "e3a3b32cc234f1683258d36c6232f150d57df015",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

@@ -216,8 +216,8 @@
}, },
{ {
"pname": "Nerdbank.GitVersioning", "pname": "Nerdbank.GitVersioning",
"version": "3.8.38-alpha", "version": "3.8.118",
"hash": "sha256-gPMrVbjOZxXoofczF/pn6eVkLhjVSJIyQrLO2oljrDc=" "hash": "sha256-Hmyy0ZKOmwN4zIhI4+MqoN8geZNc1sd033aZJ6APrO8="
}, },
{ {
"pname": "NETStandard.Library", "pname": "NETStandard.Library",