Skip to content

Commit bbea8e0

Browse files
[Repo Assist] tests: add GenerativeMethodsTests (6 focused method tests for generative type providers) (#505)
🤖 *This is an automated PR from Repo Assist.* ## Summary **Task 9 – Testing Improvements**: Add `GenerativeMethodsTests.fs` with 6 dedicated tests for methods in generative type providers. --- ## Changes ### New: `tests/GenerativeMethodsTests.fs` Six tests covering methods in generative type providers: 1. **Instance method is present** — verifies `Greet()` is emitted, is non-static 2. **Instance method return type** — verifies `Greet()` returns `string` with no parameters 3. **Instance method with parameters** — verifies `Add(x: int, y: int) : int` has correct parameter names, types, and return type 4. **Static method is present** — verifies `Create()` is emitted as a static method returning `obj` 5. **Method lookup by name** — calls `GetMethod(name)` for all three methods; directly exercises the `ILMethodDefs` lazy name-lookup dictionary 6. **Method count** — verifies the exact number of declared methods on the generated type ### Updated: `tests/FSharp.TypeProviders.SDK.Tests.fsproj` Added `GenerativeMethodsTests.fs` to the compile group (after `GenerativeDelegateTests.fs`). --- ## Motivation The existing tests exercise methods indirectly (e.g. via `BasicGenerativeProvisionTests.fs`) but there was no dedicated, self-contained file for method reflection on generative types — unlike the dedicated files already present for events, delegates, enums, interfaces, structs, abstract classes, and equality comparisons. Having a focused file makes it easier to diagnose regressions and documents the expected method-reflection contract. --- ## Test Status ✅ **137/137 tests pass** (baseline was 131; 6 new tests added, all green) ``` Passed! - Failed: 0, Passed: 137, Skipped: 0, Total: 137 ``` > Generated by 🌈 Repo Assist, see [workflow run](https://github.com/fsprojects/FSharp.TypeProviders.SDK/actions/runs/24541555872). [Learn more](https://github.com/githubnext/agentics/blob/main/docs/repo-assist.md). > > To install this [agentic workflow](https://github.com/githubnext/agentics/blob/97143ac59cb3a13ef2a77581f929f06719c7402a/workflows/repo-assist.md), run > ``` > gh aw add githubnext/agentics@97143ac > ``` <!-- gh-aw-agentic-workflow: Repo Assist, engine: copilot, model: auto, id: 24541555872, workflow_id: repo-assist, run: https://github.com/fsprojects/FSharp.TypeProviders.SDK/actions/runs/24541555872 --> <!-- gh-aw-workflow-id: repo-assist --> --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
1 parent cc96a92 commit bbea8e0

2 files changed

Lines changed: 148 additions & 0 deletions

File tree

tests/FSharp.TypeProviders.SDK.Tests.fsproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
<Compile Include="GenerativeEventsTests.fs" />
2424
<Compile Include="GenerativePropertiesTests.fs" />
2525
<Compile Include="GenerativeDelegateTests.fs" />
26+
<Compile Include="GenerativeMethodsTests.fs" />
2627
<Compile Include="ReferencedAssemblies.fs" />
2728
</ItemGroup>
2829
<ItemGroup>

tests/GenerativeMethodsTests.fs

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
module TPSDK.GenerativeMethodsTests
2+
3+
#nowarn "760" // IDisposable needs new
4+
5+
open System
6+
open System.Reflection
7+
open Microsoft.FSharp.Core.CompilerServices
8+
open Microsoft.FSharp.Quotations
9+
open Xunit
10+
open ProviderImplementation.ProvidedTypes
11+
open ProviderImplementation.ProvidedTypesTesting
12+
13+
/// Type provider with a generative type that has instance methods, a static method, and a constructor.
14+
/// The Widget type exposes:
15+
/// - instance method Greet() : string
16+
/// - instance method Add(x:int, y:int) : int
17+
/// - static method Create() : obj
18+
[<TypeProvider>]
19+
type GenerativeMethodsProvider (config: TypeProviderConfig) as this =
20+
inherit TypeProviderForNamespaces (config)
21+
22+
let ns = "Methods.Provided"
23+
let tempAssembly = ProvidedAssembly()
24+
let container = ProvidedTypeDefinition(tempAssembly, ns, "Container", Some typeof<obj>, isErased = false)
25+
26+
do
27+
let widgetType = ProvidedTypeDefinition("Widget", Some typeof<obj>, isErased = false)
28+
29+
// Instance method: Greet() : string
30+
let greetCode (_args: Expr list) = <@@ "Hello" @@>
31+
let greetMethod = ProvidedMethod("Greet", [], typeof<string>, invokeCode = greetCode, isStatic = false)
32+
widgetType.AddMember greetMethod
33+
34+
// Instance method with parameters: Add(x: int, y: int) : int
35+
let addCode (args: Expr list) = <@@ (%%(args.[1]) : int) + (%%(args.[2]) : int) @@>
36+
let addMethod =
37+
ProvidedMethod(
38+
"Add",
39+
[ ProvidedParameter("x", typeof<int>); ProvidedParameter("y", typeof<int>) ],
40+
typeof<int>,
41+
invokeCode = addCode,
42+
isStatic = false)
43+
widgetType.AddMember addMethod
44+
45+
// Static method: Create() : obj
46+
let createCode (_args: Expr list) = <@@ obj() @@>
47+
let createMethod = ProvidedMethod("Create", [], typeof<obj>, invokeCode = createCode, isStatic = true)
48+
widgetType.AddMember createMethod
49+
50+
widgetType.AddMember (ProvidedConstructor([], invokeCode = fun _ -> <@@ () @@>))
51+
container.AddMember widgetType
52+
53+
tempAssembly.AddTypes [container]
54+
this.AddNamespace(ns, [container])
55+
56+
let loadTestAssembly () =
57+
let runtimeAssemblyRefs = Targets.DotNetStandard20FSharpRefs()
58+
let runtimeAssembly = runtimeAssemblyRefs.[0]
59+
let cfg = Testing.MakeSimulatedTypeProviderConfig (__SOURCE_DIRECTORY__, runtimeAssembly, runtimeAssemblyRefs)
60+
let tp = GenerativeMethodsProvider(cfg) :> TypeProviderForNamespaces
61+
let providedNamespace = tp.Namespaces.[0]
62+
let providedType = providedNamespace.GetTypes().[0] :?> ProvidedTypeDefinition
63+
Assert.Equal("Container", providedType.Name)
64+
let bytes = (tp :> ITypeProvider).GetGeneratedAssemblyContents(providedType.Assembly)
65+
Assembly.Load bytes
66+
67+
[<Fact>]
68+
let ``Generative instance method Greet is present in generated assembly``() =
69+
let assembly = loadTestAssembly ()
70+
let containerType = assembly.ExportedTypes |> Seq.find (fun t -> t.Name = "Container")
71+
let widgetType = containerType.GetNestedType("Widget")
72+
Assert.NotNull(widgetType)
73+
74+
let meth = widgetType.GetMethod("Greet", BindingFlags.Instance ||| BindingFlags.Public)
75+
Assert.NotNull(meth)
76+
Assert.Equal("Greet", meth.Name)
77+
Assert.False(meth.IsStatic, "Greet should be an instance method")
78+
79+
[<Fact>]
80+
let ``Generative instance method Greet has correct return type``() =
81+
let assembly = loadTestAssembly ()
82+
let containerType = assembly.ExportedTypes |> Seq.find (fun t -> t.Name = "Container")
83+
let widgetType = containerType.GetNestedType("Widget")
84+
Assert.NotNull(widgetType)
85+
86+
let meth = widgetType.GetMethod("Greet", BindingFlags.Instance ||| BindingFlags.Public)
87+
Assert.NotNull(meth)
88+
Assert.Equal(typeof<string>, meth.ReturnType)
89+
let parms = meth.GetParameters()
90+
Assert.Equal(0, parms.Length)
91+
92+
[<Fact>]
93+
let ``Generative instance method Add has correct parameter types``() =
94+
let assembly = loadTestAssembly ()
95+
let containerType = assembly.ExportedTypes |> Seq.find (fun t -> t.Name = "Container")
96+
let widgetType = containerType.GetNestedType("Widget")
97+
Assert.NotNull(widgetType)
98+
99+
let meth = widgetType.GetMethod("Add", BindingFlags.Instance ||| BindingFlags.Public)
100+
Assert.NotNull(meth)
101+
Assert.Equal("Add", meth.Name)
102+
Assert.Equal(typeof<int>, meth.ReturnType)
103+
104+
let parms = meth.GetParameters()
105+
Assert.Equal(2, parms.Length)
106+
Assert.Equal("x", parms.[0].Name)
107+
Assert.Equal(typeof<int>, parms.[0].ParameterType)
108+
Assert.Equal("y", parms.[1].Name)
109+
Assert.Equal(typeof<int>, parms.[1].ParameterType)
110+
111+
[<Fact>]
112+
let ``Generative static method Create is present and is static``() =
113+
let assembly = loadTestAssembly ()
114+
let containerType = assembly.ExportedTypes |> Seq.find (fun t -> t.Name = "Container")
115+
let widgetType = containerType.GetNestedType("Widget")
116+
Assert.NotNull(widgetType)
117+
118+
let meth = widgetType.GetMethod("Create", BindingFlags.Static ||| BindingFlags.Public)
119+
Assert.NotNull(meth)
120+
Assert.Equal("Create", meth.Name)
121+
Assert.True(meth.IsStatic, "Create should be a static method")
122+
Assert.Equal(typeof<obj>, meth.ReturnType)
123+
124+
[<Fact>]
125+
let ``Generative type methods can be looked up by name``() =
126+
// Directly exercises the ILMethodDefs lazy name-lookup dictionary.
127+
let assembly = loadTestAssembly ()
128+
let containerType = assembly.ExportedTypes |> Seq.find (fun t -> t.Name = "Container")
129+
let widgetType = containerType.GetNestedType("Widget")
130+
Assert.NotNull(widgetType)
131+
132+
let bf = BindingFlags.Instance ||| BindingFlags.Static ||| BindingFlags.Public
133+
Assert.NotNull(widgetType.GetMethod("Greet", bf))
134+
Assert.NotNull(widgetType.GetMethod("Add", bf))
135+
Assert.NotNull(widgetType.GetMethod("Create", bf))
136+
137+
[<Fact>]
138+
let ``Generative type has expected method count``() =
139+
let assembly = loadTestAssembly ()
140+
let containerType = assembly.ExportedTypes |> Seq.find (fun t -> t.Name = "Container")
141+
let widgetType = containerType.GetNestedType("Widget")
142+
Assert.NotNull(widgetType)
143+
144+
// 3 declared methods: Greet, Add, Create (excludes inherited Object methods and .ctor)
145+
let declaredMethods =
146+
widgetType.GetMethods(BindingFlags.Instance ||| BindingFlags.Static ||| BindingFlags.Public ||| BindingFlags.DeclaredOnly)
147+
Assert.Equal(3, declaredMethods.Length)

0 commit comments

Comments
 (0)