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