diff --git a/Plugins/InterfaceMock/WoofWare.Whippet.Plugin.InterfaceMock.Consumer/GeneratedMockExample.fs b/Plugins/InterfaceMock/WoofWare.Whippet.Plugin.InterfaceMock.Consumer/GeneratedMockExample.fs
index dfd53d2..9aaea94 100644
--- a/Plugins/InterfaceMock/WoofWare.Whippet.Plugin.InterfaceMock.Consumer/GeneratedMockExample.fs
+++ b/Plugins/InterfaceMock/WoofWare.Whippet.Plugin.InterfaceMock.Consumer/GeneratedMockExample.fs
@@ -193,3 +193,33 @@ type internal TypeWithInterfaceNoAttrMock =
interface System.IDisposable with
member this.Dispose () : unit = this.Dispose ()
+namespace SomeNamespace
+
+open System
+
+/// Mock record type for an interface
+type internal TypeWithPropertiesMock =
+ {
+ /// Implementation of IDisposable.Dispose
+ Dispose : unit -> unit
+ Prop1 : unit -> int
+ Prop2 : unit -> unit Async
+ Mem1 : string option -> string[] Async
+ }
+
+ /// An implementation where every method throws.
+ static member Empty : TypeWithPropertiesMock =
+ {
+ Dispose = (fun () -> ())
+ 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"))
+ }
+
+ interface TypeWithProperties with
+ member this.Mem1 arg_0_0 = this.Mem1 (arg_0_0)
+ member this.Prop1 = this.Prop1 ()
+ member this.Prop2 = this.Prop2 ()
+
+ interface System.IDisposable with
+ member this.Dispose () : unit = this.Dispose ()
diff --git a/Plugins/InterfaceMock/WoofWare.Whippet.Plugin.InterfaceMock.Consumer/MockExample.fs b/Plugins/InterfaceMock/WoofWare.Whippet.Plugin.InterfaceMock.Consumer/MockExample.fs
index 3d181fb..d7ea37d 100644
--- a/Plugins/InterfaceMock/WoofWare.Whippet.Plugin.InterfaceMock.Consumer/MockExample.fs
+++ b/Plugins/InterfaceMock/WoofWare.Whippet.Plugin.InterfaceMock.Consumer/MockExample.fs
@@ -39,3 +39,9 @@ type TypeWithInterfaceNoAttr =
inherit IDisposable
abstract Mem1 : string option -> string[] Async
abstract Mem2 : unit -> string[] Async
+
+type TypeWithProperties =
+ inherit IDisposable
+ abstract Mem1 : string option -> string[] Async
+ abstract Prop1 : int
+ abstract Prop2 : unit Async
diff --git a/Plugins/InterfaceMock/WoofWare.Whippet.Plugin.InterfaceMock.Consumer/WoofWare.Whippet.Plugin.InterfaceMock.Consumer.fsproj b/Plugins/InterfaceMock/WoofWare.Whippet.Plugin.InterfaceMock.Consumer/WoofWare.Whippet.Plugin.InterfaceMock.Consumer.fsproj
index a41f520..667dae8 100644
--- a/Plugins/InterfaceMock/WoofWare.Whippet.Plugin.InterfaceMock.Consumer/WoofWare.Whippet.Plugin.InterfaceMock.Consumer.fsproj
+++ b/Plugins/InterfaceMock/WoofWare.Whippet.Plugin.InterfaceMock.Consumer/WoofWare.Whippet.Plugin.InterfaceMock.Consumer.fsproj
@@ -20,6 +20,7 @@
InterfaceMock
InterfaceMock
InterfaceMock
+ InterfaceMock
diff --git a/Plugins/InterfaceMock/WoofWare.Whippet.Plugin.InterfaceMock/InterfaceMockGenerator.fs b/Plugins/InterfaceMock/WoofWare.Whippet.Plugin.InterfaceMock/InterfaceMockGenerator.fs
index 56b76d1..4ba4751 100644
--- a/Plugins/InterfaceMock/WoofWare.Whippet.Plugin.InterfaceMock/InterfaceMockGenerator.fs
+++ b/Plugins/InterfaceMock/WoofWare.Whippet.Plugin.InterfaceMock/InterfaceMockGenerator.fs
@@ -160,6 +160,15 @@ module internal InterfaceMockGenerator =
|> SynMemberDefn.memberImplementation
)
+ let properties =
+ interfaceType.Properties
+ |> List.map (fun pi ->
+ SynExpr.createLongIdent' [ Ident.create "this" ; pi.Identifier ]
+ |> SynExpr.applyTo (SynExpr.CreateConst ())
+ |> SynBinding.basic [ Ident.create "this" ; pi.Identifier ] []
+ |> SynMemberDefn.memberImplementation
+ )
+
let interfaceName =
let baseName = SynType.createLongIdent interfaceType.Name
@@ -175,7 +184,7 @@ module internal InterfaceMockGenerator =
SynType.app' baseName generics
- SynMemberDefn.Interface (interfaceName, Some range0, Some members, range0)
+ SynMemberDefn.Interface (interfaceName, Some range0, Some (members @ properties), range0)
let access =
match interfaceType.Accessibility, spec.IsInternal with
@@ -249,6 +258,15 @@ module internal InterfaceMockGenerator =
|> SynField.make
|> SynField.withDocString (mem.XmlDoc |> Option.defaultValue PreXmlDoc.Empty)
+ let constructProperty (prop : PropertyInfo) : SynField =
+ {
+ Attrs = []
+ Ident = Some prop.Identifier
+ Type = SynType.toFun [ SynType.unit ] prop.Type
+ }
+ |> SynField.make
+ |> SynField.withDocString (prop.XmlDoc |> Option.defaultValue PreXmlDoc.Empty)
+
let createRecord
(namespaceId : LongIdent)
(opens : SynOpenDeclTarget list)
@@ -256,7 +274,12 @@ module internal InterfaceMockGenerator =
: SynModuleOrNamespace
=
let interfaceType = AstHelper.parseInterface interfaceType
- let fields = interfaceType.Members |> List.map constructMember
+
+ let fields =
+ interfaceType.Members
+ |> List.map constructMember
+ |> List.append (interfaceType.Properties |> List.map constructProperty)
+
let docString = PreXmlDoc.create "Mock record type for an interface"
let name =
@@ -274,7 +297,7 @@ module internal InterfaceMockGenerator =
[ yield! opens |> List.map SynModuleDecl.openAny ; yield typeDecl ]
|> SynModuleOrNamespace.createNamespace namespaceId
-/// Myriad generator that creates a record which implements the given interface,
+/// Whippet generator that creates a record which implements the given interface,
/// but with every field mocked out.
[]
type InterfaceMockGenerator () =
diff --git a/Plugins/InterfaceMock/WoofWare.Whippet.Plugin.InterfaceMock/WoofWare.Whippet.Plugin.InterfaceMock.Test/TestMockGenerator.fs b/Plugins/InterfaceMock/WoofWare.Whippet.Plugin.InterfaceMock/WoofWare.Whippet.Plugin.InterfaceMock.Test/TestMockGenerator.fs
index cb322c8..7614662 100644
--- a/Plugins/InterfaceMock/WoofWare.Whippet.Plugin.InterfaceMock/WoofWare.Whippet.Plugin.InterfaceMock.Test/TestMockGenerator.fs
+++ b/Plugins/InterfaceMock/WoofWare.Whippet.Plugin.InterfaceMock/WoofWare.Whippet.Plugin.InterfaceMock.Test/TestMockGenerator.fs
@@ -34,3 +34,16 @@ module TestMockGenerator =
mock.Mem1 3 'a' |> shouldEqual "aaa"
mock.Mem2 (3, "hi") 'a' |> shouldEqual "hiahiahi"
mock.Mem3 (3, "hi") 'a' |> shouldEqual "hiahiahi"
+
+ []
+ let ``Example of use: properties`` () =
+ let mock : TypeWithProperties =
+ { TypeWithPropertiesMock.Empty with
+ Mem1 = fun i -> async { return Option.toArray i }
+ Prop1 = fun () -> 44
+ }
+ :> _
+
+ mock.Mem1 (Some "hi") |> Async.RunSynchronously |> shouldEqual [| "hi" |]
+
+ mock.Prop1 |> shouldEqual 44