Skip to content

Commit 4cb726a

Browse files
Smaug123claude
andauthored
Record property accesses in capturing mocks (#547)
The capturing mock's Calls record has an entry per property, but the generated property implementations invoked only the configured function and never appended to those logs, so the call arrays stayed empty forever. Property getters now record into Calls under a lock, mirroring the method implementations. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent d7440bb commit 4cb726a

3 files changed

Lines changed: 48 additions & 4 deletions

File tree

ConsumePlugin/GeneratedCapturingMock.fs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -555,8 +555,13 @@ type internal TypeWithPropertiesMock =
555555
lock this.Calls.Mem1 (fun _ -> this.Calls.Mem1.Add (arg_0_0))
556556
this.Mem1 (arg_0_0)
557557

558-
member this.Prop1 = this.Prop1 ()
559-
member this.Prop2 = this.Prop2 ()
558+
member this.Prop1 =
559+
lock this.Calls.Prop1 (fun _ -> this.Calls.Prop1.Add ())
560+
this.Prop1 ()
561+
562+
member this.Prop2 =
563+
lock this.Calls.Prop2 (fun _ -> this.Calls.Prop2.Add ())
564+
this.Prop2 ()
560565

561566
interface System.IDisposable with
562567
member this.Dispose () : unit = this.Dispose ()

WoofWare.Myriad.Plugins.Test/TestCapturingMockGenerator/TestCapturingMockGenerator.fs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,30 @@ module TestCapturingMockGenerator =
3535
mock.Mem2 (3, "hi") 'a' |> shouldEqual "hiahiahi"
3636
mock.Mem3 (3, "hi") 'a' |> shouldEqual "hiahiahi"
3737

38+
[<Test>]
39+
let ``Property accesses are recorded in Calls`` () =
40+
let mock =
41+
{ TypeWithPropertiesMock.Empty () with
42+
Prop1 = fun () -> 44
43+
Prop2 = fun () -> async { return () }
44+
}
45+
46+
let itf = mock :> TypeWithProperties
47+
48+
mock.Calls.Prop1.Count |> shouldEqual 0
49+
mock.Calls.Prop2.Count |> shouldEqual 0
50+
51+
itf.Prop1 |> shouldEqual 44
52+
mock.Calls.Prop1.Count |> shouldEqual 1
53+
mock.Calls.Prop2.Count |> shouldEqual 0
54+
55+
itf.Prop1 |> shouldEqual 44
56+
mock.Calls.Prop1.Count |> shouldEqual 2
57+
58+
// note: we don't attempt to track async scheduling or anything
59+
itf.Prop2 |> ignore<_ Async>
60+
mock.Calls.Prop2.Count |> shouldEqual 1
61+
3862
[<Test>]
3963
let ``Example of use: properties`` () =
4064
let mock : TypeWithProperties =

WoofWare.Myriad.Plugins/CapturingInterfaceMockGenerator.fs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -524,8 +524,23 @@ module internal CapturingInterfaceMockGenerator =
524524
let properties =
525525
interfaceType.Properties
526526
|> List.map (fun pi ->
527-
SynExpr.createLongIdent' [ Ident.create "this" ; pi.Identifier ]
528-
|> SynExpr.applyTo (SynExpr.CreateConst ())
527+
let addToCalls =
528+
SynExpr.CreateConst ()
529+
|> SynExpr.applyFunction (
530+
SynExpr.createLongIdent [ "this" ; "Calls" ; pi.Identifier.idText ; "Add" ]
531+
)
532+
|> SynExpr.createLambda "_"
533+
|> SynExpr.applyFunction (
534+
SynExpr.createIdent "lock"
535+
|> SynExpr.applyTo (SynExpr.createLongIdent [ "this" ; "Calls" ; pi.Identifier.idText ])
536+
)
537+
538+
let body =
539+
SynExpr.createLongIdent' [ Ident.create "this" ; pi.Identifier ]
540+
|> SynExpr.applyTo (SynExpr.CreateConst ())
541+
542+
[ addToCalls ; body ]
543+
|> SynExpr.sequential
529544
|> SynBinding.basic [ Ident.create "this" ; pi.Identifier ] []
530545
|> SynMemberDefn.memberImplementation
531546
)

0 commit comments

Comments
 (0)