Add InterfaceMock attribute (#17)

This commit is contained in:
Patrick Stevens
2024-10-08 08:35:02 +01:00
committed by GitHub
parent 105e6a9ca3
commit b9761f6dee
11 changed files with 159 additions and 7 deletions

View File

@@ -190,6 +190,11 @@ jobs:
with:
name: nuget-package-httpclient
path: Plugins/HttpClient/WoofWare.Whippet.Plugin.HttpClient/bin/Release/WoofWare.Whippet.Plugin.HttpClient.*.nupkg
- name: Upload NuGet artifact (interfacemock attrs)
uses: actions/upload-artifact@v4
with:
name: nuget-package-interfacemock-attrs
path: Plugins/InterfaceMock/WoofWare.Whippet.Plugin.InterfaceMock.Attributes/bin/Release/WoofWare.Whippet.Plugin.InterfaceMock.Attributes.*.nupkg
- name: Upload NuGet artifact (interfacemock plugin)
uses: actions/upload-artifact@v4
with:
@@ -272,6 +277,14 @@ jobs:
- name: Check NuGet contents
# Verify that there is exactly one nupkg in the artifact that would be NuGet published
run: if [[ $(find packed-httpclient -maxdepth 1 -name 'WoofWare.Whippet.Plugin.HttpClient.*.nupkg' -printf c | wc -c) -ne "1" ]]; then exit 1; fi
- name: Download NuGet artifact (interfacemock attrs)
uses: actions/download-artifact@v4
with:
name: nuget-package-interfacemock-attrs
path: packed-interfacemock-attrs
- name: Check NuGet contents
# Verify that there is exactly one nupkg in the artifact that would be NuGet published
run: if [[ $(find packed-interfacemock-attrs -maxdepth 1 -name 'WoofWare.Whippet.Plugin.InterfaceMock.Attributes.*.nupkg' -printf c | wc -c) -ne "1" ]]; then exit 1; fi
- name: Download NuGet artifact (interfacemock plugin)
uses: actions/download-artifact@v4
with:
@@ -612,3 +625,35 @@ jobs:
nupkg-dir: packed/
dotnet: ${{ steps.dotnet-identify.outputs.dotnet }}
nuget-publish-interfacemock-attrs:
runs-on: ubuntu-latest
if: ${{ !github.event.repository.fork && github.ref == 'refs/heads/main' }}
needs: [all-required-checks-complete]
environment: main-deploy
permissions:
id-token: write
attestations: write
contents: read
steps:
- uses: actions/checkout@v4
- name: Install Nix
uses: cachix/install-nix-action@v29
with:
extra_nix_config: |
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
- name: Download NuGet artifact
uses: actions/download-artifact@v4
with:
name: nuget-package-interfacemock-attrs
path: packed
- name: Identify `dotnet`
id: dotnet-identify
run: nix develop --command bash -c 'echo "dotnet=$(which dotnet)" >> $GITHUB_OUTPUT'
- name: Publish to NuGet
id: publish-success
uses: G-Research/common-actions/publish-nuget@2b7dc49cb14f3344fbe6019c14a31165e258c059
with:
package-name: WoofWare.Whippet.Plugin.InterfaceMock.Attributes
nuget-key: ${{ secrets.NUGET_API_KEY }}
nupkg-dir: packed/
dotnet: ${{ steps.dotnet-identify.outputs.dotnet }}

View File

@@ -0,0 +1,15 @@
namespace WoofWare.Whippet.Plugin.InterfaceMock
/// Attribute indicating an interface type for which the "Interface Mock" Whippet
/// generator should apply during build.
/// This generator creates a record which implements the interface,
/// but where each method is represented as a record field, so you can use
/// record update syntax to easily specify partially-implemented mock objects.
/// You may optionally specify `isInternal = false` to get a mock with the public visibility modifier.
type InterfaceMockAttribute (isInternal : bool) =
inherit System.Attribute ()
/// The default value of `isInternal`, the optional argument to the InterfaceMockAttribute constructor.
static member DefaultIsInternal = true
/// Shorthand for the "isExtensionMethod = false" constructor; see documentation there for details.
new () = InterfaceMockAttribute InterfaceMockAttribute.DefaultIsInternal

View File

@@ -0,0 +1,6 @@
# WoofWare.Whippet.Plugin.InterfaceMock.Attributes
This is a very slim runtime dependency which consumers of WoofWare.Whippet.Plugin.InterfaceMock may optionally take.
This dependency contains attributes which control that source generator,
although you may instead omit this dependency and control the generator entirely through configuration in consumer's `.fsproj`.
Please see WoofWare.Whippet.Plugin.InterfaceMock's README for further information.

View File

@@ -0,0 +1,5 @@
WoofWare.Whippet.Plugin.InterfaceMock.InterfaceMockAttribute inherit System.Attribute
WoofWare.Whippet.Plugin.InterfaceMock.InterfaceMockAttribute..ctor [constructor]: bool
WoofWare.Whippet.Plugin.InterfaceMock.InterfaceMockAttribute..ctor [constructor]: unit
WoofWare.Whippet.Plugin.InterfaceMock.InterfaceMockAttribute.DefaultIsInternal [static property]: [read-only] bool
WoofWare.Whippet.Plugin.InterfaceMock.InterfaceMockAttribute.get_DefaultIsInternal [static method]: unit -> bool

View File

@@ -0,0 +1,30 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<Authors>Patrick Stevens</Authors>
<Copyright>Copyright (c) Patrick Stevens 2024</Copyright>
<Description>Attributes to accompany the WoofWare.Whippet.Plugin.InterfaceMock source generator, to indicate what you want your types to be doing.</Description>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/Smaug123/WoofWare.Whippet</RepositoryUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageTags>fsharp;source-generator;source-gen;whippet;mock</PackageTags>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<WarnOn>FS3559</WarnOn>
<PackageId>WoofWare.Whippet.Plugin.InterfaceMock.Attributes</PackageId>
</PropertyGroup>
<ItemGroup>
<Compile Include="Attributes.fs" />
<EmbeddedResource Include="SurfaceBaseline.txt" />
<EmbeddedResource Include="version.json" />
<None Include="README.md">
<Pack>True</Pack>
<PackagePath>/</PackagePath>
<Link>README.md</Link>
</None>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,11 @@
{
"version": "0.1",
"publicReleaseRefSpec": [
"^refs/heads/main$"
],
"pathFilters": [
"./",
":/global.json",
":/Directory.Build.props"
]
}

View File

@@ -36,7 +36,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\WoofWare.Whippet.Plugin.InterfaceMock\WoofWare.Whippet.Plugin.InterfaceMock.fsproj" WhippetPlugin="true" />
<ProjectReference Include="..\WoofWare.Whippet.Plugin.InterfaceMock\WoofWare.Whippet.Plugin.InterfaceMock.fsproj" WhippetPlugin="true" PrivateAssets="all" />
<!-- Dance to get a binary dependency on a locally-built Whippet -->
<!-- ProjectReference Include="..\..\..\WoofWare.Whippet\WoofWare.Whippet.fsproj" PrivateAssets="all" -->
<PackageReference Include="WoofWare.Whippet" Version="*-*" PrivateAssets="all" />

View File

@@ -80,3 +80,8 @@ You may supply an `isInternal : bool` argument:
By default, we make the resulting record type at most internal (never public),
since this is intended only to be used in tests;
but you can instead make it public by setting the `false` boolean.
Instead of configuring the client with `<WhippetParamMyType>InterfaceMock</WhippetParamMyType>`,
you may choose to add an attribute called `InterfaceMock` (with an optional "isInternal" argument)
to any type you wish to use as an input.
You may use `WoofWare.Whippet.Plugin.InterfaceMock.Attributes` to provide this attribute, or you may define it yourself.

View File

@@ -0,0 +1,26 @@
namespace WoofWare.Whippet.Plugin.InterfaceMock.Test
open NUnit.Framework
open WoofWare.Whippet.Plugin.InterfaceMock
open ApiSurface
[<TestFixture>]
module TestAttributeSurface =
let assembly = typeof<InterfaceMockAttribute>.Assembly
[<Test>]
let ``Ensure API surface has not been modified`` () = ApiSurface.assertIdentical assembly
(*
[<Test>]
let ``Check version against remote`` () =
MonotonicVersion.validate assembly "WoofWare.Whippet.Plugin.InterfaceMock.Attributes"
*)
[<Test ; Explicit>]
let ``Update API surface`` () =
ApiSurface.writeAssemblyBaseline assembly
[<Test>]
let ``Ensure public API is fully documented`` () =
DocCoverage.assertFullyDocumented assembly

View File

@@ -10,6 +10,7 @@
<ItemGroup>
<Compile Include="TestMockGenerator.fs" />
<Compile Include="TestMockGeneratorNoAttr.fs" />
<Compile Include="TestSurface.fs" />
</ItemGroup>
<ItemGroup>
@@ -17,9 +18,11 @@
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1"/>
<PackageReference Include="NUnit" Version="4.2.2"/>
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0"/>
<PackageReference Include="ApiSurface" Version="4.1.6"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\WoofWare.Whippet.Plugin.InterfaceMock.Attributes\WoofWare.Whippet.Plugin.InterfaceMock.Attributes.fsproj" />
<ProjectReference Include="..\..\WoofWare.Whippet.Plugin.InterfaceMock.Consumer\WoofWare.Whippet.Plugin.InterfaceMock.Consumer.fsproj" />
</ItemGroup>

View File

@@ -42,6 +42,8 @@ Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "WoofWare.Whippet.Plugin.Int
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "WoofWare.Whippet.Plugin.InterfaceMock.Test", "Plugins\InterfaceMock\WoofWare.Whippet.Plugin.InterfaceMock\WoofWare.Whippet.Plugin.InterfaceMock.Test\WoofWare.Whippet.Plugin.InterfaceMock.Test.fsproj", "{1B0D4C01-66CD-4E91-9DA5-9ED4F3319AFA}"
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "WoofWare.Whippet.Plugin.InterfaceMock.Attributes", "Plugins\InterfaceMock\WoofWare.Whippet.Plugin.InterfaceMock.Attributes\WoofWare.Whippet.Plugin.InterfaceMock.Attributes.fsproj", "{E73EA066-2725-42CD-BE7D-39264C24AA97}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -132,5 +134,9 @@ Global
{1B0D4C01-66CD-4E91-9DA5-9ED4F3319AFA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1B0D4C01-66CD-4E91-9DA5-9ED4F3319AFA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1B0D4C01-66CD-4E91-9DA5-9ED4F3319AFA}.Release|Any CPU.Build.0 = Release|Any CPU
{E73EA066-2725-42CD-BE7D-39264C24AA97}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E73EA066-2725-42CD-BE7D-39264C24AA97}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E73EA066-2725-42CD-BE7D-39264C24AA97}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E73EA066-2725-42CD-BE7D-39264C24AA97}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal