Skip to content

Commit 2778dce

Browse files
dsymegithub-actions[bot]Copilot
authored
[Repo Assist] tests: interface inheritance + class-implementing-interface coverage; ci: remove duplicate SDK setup step (#488)
- Add IExtended (interface inheriting IContract) to GenerativeInterfacesProvider - Add Impl (concrete class implementing IMarker + IContract) - Add 3 new Fact tests: IExtended inherits IContract, Impl implements both interfaces, and Impl method signatures match the contract - ci: remove duplicate 'Setup .NET Core 8' step from push.yml and pr.yml; the matrix already installs 8.0.124 via the first setup-dotnet step Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 5faea56 commit 2778dce

3 files changed

Lines changed: 68 additions & 10 deletions

File tree

.github/workflows/pr.yml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,6 @@ jobs:
2828
with:
2929
dotnet-version: 6.0.425
3030

31-
- name: Setup .NET Core 8
32-
uses: actions/setup-dotnet@v4
33-
with:
34-
dotnet-version: 8.0.124
35-
3631
- name: Build on Windows
3732
if: matrix.os == 'windows-latest'
3833
run: .\build.cmd

.github/workflows/push.yml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,6 @@ jobs:
3232
with:
3333
dotnet-version: 6.0.425
3434

35-
- name: Setup .NET Core 8
36-
uses: actions/setup-dotnet@v4
37-
with:
38-
dotnet-version: 8.0.124
39-
4035
- name: Build on Windows
4136
if: matrix.os == 'windows-latest'
4237
run: .\build.cmd

tests/GenerativeInterfacesTests.fs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,24 @@ type GenerativeInterfacesProvider (config: TypeProviderConfig) as this =
4141
let contract = createInterface "IContract" members
4242
container.AddMember contract
4343

44+
// IExtended inherits from IContract and adds an extra method
45+
let extended = createInterface "IExtended" [ "GetLength", [("s", typeof<string>)], typeof<int> ]
46+
extended.AddInterfaceImplementation(contract)
47+
container.AddMember extended
48+
49+
// Impl is a concrete class that implements both IMarker and IContract
50+
let impl = ProvidedTypeDefinition("Impl", Some typeof<obj>, isErased = false)
51+
let getString = ProvidedMethod("GetString", [], typeof<string>, invokeCode = fun _args -> <@@ "hello" @@>)
52+
getString.AddMethodAttrs(MethodAttributes.Virtual)
53+
let sum = ProvidedMethod("Sum", [ProvidedParameter("x", typeof<int>); ProvidedParameter("y", typeof<int>)], typeof<int>,
54+
invokeCode = fun args -> <@@ (%%args.[1] : int) + (%%args.[2] : int) @@>)
55+
sum.AddMethodAttrs(MethodAttributes.Virtual)
56+
impl.AddMember getString
57+
impl.AddMember sum
58+
impl.AddInterfaceImplementation(marker)
59+
impl.AddInterfaceImplementation(contract)
60+
container.AddMember impl
61+
4462
tempAssembly.AddTypes [container]
4563
this.AddNamespace(container.Namespace, [container])
4664

@@ -89,3 +107,53 @@ let ``Interfaces with methods are generated correctly``() =
89107
Assert.True(contractSum.IsAbstract, "Expected Sum method to be abstract")
90108
Assert.True(contractSum.IsVirtual, "Expected Sum method to be virtual")
91109

110+
[<Fact>]
111+
let ``Interface inheritance: IExtended extends IContract``() =
112+
testProvidedAssembly <| fun container ->
113+
let extended = container.GetNestedType "IExtended"
114+
Assert.NotNull(extended)
115+
Assert.True(extended.IsInterface, "Expected IExtended to be an interface")
116+
117+
// IExtended declares its own method
118+
let getLength = extended.GetMethod("GetLength")
119+
Assert.NotNull(getLength)
120+
Assert.True(getLength.IsAbstract, "Expected GetLength to be abstract")
121+
122+
// IExtended inherits IContract
123+
let ifaces = extended.GetInterfaces()
124+
let hasIContract = ifaces |> Array.exists (fun i -> i.Name = "IContract")
125+
Assert.True(hasIContract, "Expected IExtended to implement IContract")
126+
127+
[<Fact>]
128+
let ``Concrete class implementing interfaces is generated correctly``() =
129+
testProvidedAssembly <| fun container ->
130+
let impl = container.GetNestedType "Impl"
131+
Assert.NotNull(impl)
132+
Assert.False(impl.IsInterface, "Impl should not be an interface")
133+
Assert.False(impl.IsAbstract, "Impl should not be abstract")
134+
135+
// Impl implements both IMarker and IContract
136+
let ifaces = impl.GetInterfaces()
137+
let hasIMarker = ifaces |> Array.exists (fun i -> i.Name = "IMarker")
138+
let hasIContract = ifaces |> Array.exists (fun i -> i.Name = "IContract")
139+
Assert.True(hasIMarker, "Expected Impl to implement IMarker")
140+
Assert.True(hasIContract, "Expected Impl to implement IContract")
141+
142+
[<Fact>]
143+
let ``Concrete class methods satisfy interface contract``() =
144+
testProvidedAssembly <| fun container ->
145+
let impl = container.GetNestedType "Impl"
146+
Assert.NotNull(impl)
147+
148+
let getString = impl.GetMethod("GetString")
149+
Assert.NotNull(getString)
150+
Assert.False(getString.IsAbstract, "GetString on Impl should not be abstract")
151+
152+
let sum = impl.GetMethod("Sum")
153+
Assert.NotNull(sum)
154+
let ps = sum.GetParameters()
155+
Assert.Equal(2, ps.Length)
156+
Assert.Equal(typeof<int>, ps.[0].ParameterType)
157+
Assert.Equal(typeof<int>, ps.[1].ParameterType)
158+
Assert.Equal(typeof<int>, sum.ReturnType)
159+

0 commit comments

Comments
 (0)