mirror of
https://github.com/Smaug123/WoofWare.Myriad
synced 2025-10-05 03:58:40 +00:00
Compare commits
31 Commits
WoofWare.M
...
8f0e8d6369
Author | SHA1 | Date | |
---|---|---|---|
|
8f0e8d6369 | ||
|
e7780dc412 | ||
|
c3311bd350 | ||
|
07e9eaff38 | ||
|
2c539c13a3 | ||
|
738e0c1f1b | ||
|
8e415ea679 | ||
|
b7427b523a | ||
|
d4891dfa29 | ||
|
3e51eb764e | ||
|
a704e3b959 | ||
|
e1e7198cc4 | ||
|
dd55b3dcbc | ||
|
7483658b41 | ||
|
fd7c513bb3 | ||
|
aca60f1b6a | ||
|
1715975fa3 | ||
|
628f87d67f | ||
|
0374bc00f2 | ||
|
69f1112a52 | ||
|
bc69a7a364 | ||
|
72f3800826 | ||
|
88500f0043 | ||
|
6491fc68f4 | ||
|
57af5ffa1a | ||
|
7f20ed9761 | ||
|
c5c5bbd02a | ||
|
470b073884 | ||
|
3b9fa7f3b8 | ||
|
510c4da2ca | ||
|
d0d5fa4040 |
@@ -3,13 +3,13 @@
|
||||
"isRoot": true,
|
||||
"tools": {
|
||||
"fantomas": {
|
||||
"version": "7.0.2",
|
||||
"version": "7.0.3",
|
||||
"commands": [
|
||||
"fantomas"
|
||||
]
|
||||
},
|
||||
"fsharp-analyzers": {
|
||||
"version": "0.31.0",
|
||||
"version": "0.32.1",
|
||||
"commands": [
|
||||
"fsharp-analyzers"
|
||||
]
|
||||
|
22
.envrc
22
.envrc
@@ -1 +1,23 @@
|
||||
use flake
|
||||
DOTNET_PATH=$(readlink "$(which dotnet)")
|
||||
SETTINGS_FILE=$(find . -maxdepth 1 -type f -name '*.sln.DotSettings.user')
|
||||
MSBUILD=$(realpath "$(find "$(dirname "$DOTNET_PATH")/../share/dotnet/sdk" -maxdepth 2 -type f -name MSBuild.dll)")
|
||||
if [ -f "$SETTINGS_FILE" ] ; then
|
||||
xmlstarlet ed --inplace \
|
||||
-N wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation" \
|
||||
-N x="http://schemas.microsoft.com/winfx/2006/xaml" \
|
||||
-N s="clr-namespace:System;assembly=mscorlib" \
|
||||
-N ss="urn:shemas-jetbrains-com:settings-storage-xaml" \
|
||||
--update "//s:String[@x:Key='/Default/Environment/Hierarchy/Build/BuildTool/DotNetCliExePath/@EntryValue']" \
|
||||
--value "$(realpath "$(dirname "$DOTNET_PATH")/../share/dotnet/dotnet")" \
|
||||
"$SETTINGS_FILE"
|
||||
|
||||
xmlstarlet ed --inplace \
|
||||
-N wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation" \
|
||||
-N x="http://schemas.microsoft.com/winfx/2006/xaml" \
|
||||
-N s="clr-namespace:System;assembly=mscorlib" \
|
||||
-N ss="urn:shemas-jetbrains-com:settings-storage-xaml" \
|
||||
--update "//s:String[@x:Key='/Default/Environment/Hierarchy/Build/BuildTool/CustomBuildToolPath/@EntryValue']" \
|
||||
--value "$MSBUILD" \
|
||||
"$SETTINGS_FILE"
|
||||
fi
|
||||
|
42
.github/workflows/dotnet.yaml
vendored
42
.github/workflows/dotnet.yaml
vendored
@@ -25,7 +25,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0 # so that NerdBank.GitVersioning has access to history
|
||||
- name: Install Nix
|
||||
@@ -46,7 +46,7 @@ jobs:
|
||||
security-events: write
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0 # so that NerdBank.GitVersioning has access to history
|
||||
- name: Install Nix
|
||||
@@ -65,7 +65,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@v31
|
||||
with:
|
||||
@@ -80,7 +80,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@v31
|
||||
with:
|
||||
@@ -93,7 +93,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0 # so that NerdBank.GitVersioning has access to history
|
||||
- name: Install Nix
|
||||
@@ -114,7 +114,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@v31
|
||||
with:
|
||||
@@ -152,7 +152,7 @@ jobs:
|
||||
nuget-pack:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0 # so that NerdBank.GitVersioning has access to history
|
||||
- name: Install Nix
|
||||
@@ -182,7 +182,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Download NuGet artifact (plugin)
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v5
|
||||
with:
|
||||
name: nuget-package-plugin
|
||||
path: packed-plugin
|
||||
@@ -190,7 +190,7 @@ jobs:
|
||||
# Verify that there is exactly one nupkg in the artifact that would be NuGet published
|
||||
run: if [[ $(find packed-plugin -maxdepth 1 -name 'WoofWare.Myriad.Plugins.*.nupkg' -printf c | wc -c) -ne "1" ]]; then exit 1; fi
|
||||
- name: Download NuGet artifact (attributes)
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v5
|
||||
with:
|
||||
name: nuget-package-attribute
|
||||
path: packed-attribute
|
||||
@@ -207,9 +207,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [nuget-pack]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- name: Download NuGet artifact
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v5
|
||||
with:
|
||||
name: ${{ matrix.artifact }}
|
||||
- name: Compute package path
|
||||
@@ -249,12 +249,12 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: Download NuGet artifact
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v5
|
||||
with:
|
||||
name: nuget-package-attribute
|
||||
path: packed
|
||||
- name: Attest Build Provenance
|
||||
uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2.4.0
|
||||
uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3.0.0
|
||||
with:
|
||||
subject-path: "packed/*.nupkg"
|
||||
|
||||
@@ -268,12 +268,12 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: Download NuGet artifact
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v5
|
||||
with:
|
||||
name: nuget-package-plugin
|
||||
path: packed
|
||||
- name: Attest Build Provenance
|
||||
uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2.4.0
|
||||
uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3.0.0
|
||||
with:
|
||||
subject-path: "packed/*.nupkg"
|
||||
|
||||
@@ -287,14 +287,14 @@ jobs:
|
||||
attestations: write
|
||||
contents: read
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@v31
|
||||
with:
|
||||
extra_nix_config: |
|
||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Download NuGet artifact
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v5
|
||||
with:
|
||||
name: nuget-package-attribute
|
||||
path: packed
|
||||
@@ -320,14 +320,14 @@ jobs:
|
||||
attestations: write
|
||||
contents: read
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@v31
|
||||
with:
|
||||
extra_nix_config: |
|
||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Download NuGet artifact
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v5
|
||||
with:
|
||||
name: nuget-package-plugin
|
||||
path: packed
|
||||
@@ -356,9 +356,9 @@ jobs:
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- name: Download NuGet artifact
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v5
|
||||
with:
|
||||
name: ${{ matrix.artifact }}
|
||||
- name: Compute package path
|
||||
|
2
.github/workflows/flake_update.yaml
vendored
2
.github/workflows/flake_update.yaml
vendored
@@ -11,7 +11,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Install Nix
|
||||
uses: DeterminateSystems/nix-installer-action@main
|
||||
|
@@ -1,5 +1,9 @@
|
||||
Notable changes are recorded here.
|
||||
|
||||
# WoofWare.Myriad.Plugins 8.1.1
|
||||
|
||||
Adds `GenerateCapturingMock`, which is `GenerateMock` but additionally records the calls made to each function.
|
||||
|
||||
# WoofWare.Myriad.Plugins 8.0.3
|
||||
|
||||
The RestEase-style HTTP client generator now automatically adds the `application/json` content type header to requests which are POSTing a body that is known to be JSON-serialised.
|
||||
|
57
ConsumePlugin/CapturingMockExample.fs
Normal file
57
ConsumePlugin/CapturingMockExample.fs
Normal file
@@ -0,0 +1,57 @@
|
||||
namespace SomeNamespace.CapturingMock
|
||||
|
||||
open System
|
||||
open WoofWare.Myriad.Plugins
|
||||
|
||||
[<GenerateCapturingMock>]
|
||||
type IPublicType =
|
||||
abstract Mem1 : foo : string * int -> string list
|
||||
abstract Mem2 : string -> int
|
||||
abstract Mem3 : x : int * ?ct : System.Threading.CancellationToken -> string
|
||||
|
||||
[<GenerateCapturingMock false>]
|
||||
type IPublicTypeInternalFalse =
|
||||
abstract Mem1 : string * int -> string list
|
||||
abstract Mem2 : string -> int
|
||||
abstract Mem3 : x : int * ?ct : System.Threading.CancellationToken -> string
|
||||
|
||||
[<GenerateCapturingMock>]
|
||||
type internal InternalType =
|
||||
abstract Mem1 : string * int -> unit
|
||||
abstract Mem2 : string -> int
|
||||
|
||||
[<GenerateCapturingMock>]
|
||||
type private PrivateType =
|
||||
abstract Mem1 : string * int -> unit
|
||||
abstract Mem2 : string -> int
|
||||
|
||||
[<GenerateCapturingMock false>]
|
||||
type private PrivateTypeInternalFalse =
|
||||
abstract Mem1 : string * int -> unit
|
||||
abstract Mem2 : string -> int
|
||||
|
||||
[<GenerateCapturingMock>]
|
||||
type VeryPublicType<'a, 'b> =
|
||||
abstract Mem1 : 'a -> 'b
|
||||
|
||||
[<GenerateCapturingMock>]
|
||||
type Curried<'a> =
|
||||
abstract Mem1 : bar : int -> 'a -> string
|
||||
abstract Mem2 : int * string -> baz : 'a -> string
|
||||
abstract Mem3 : quux : (int * string) -> flurb : 'a -> string
|
||||
abstract Mem4 : (int * string) -> ('a * int) -> string
|
||||
abstract Mem5 : x : int * string -> ('a * int) -> string
|
||||
abstract Mem6 : int * string -> y : 'a * int -> string
|
||||
|
||||
[<GenerateCapturingMock>]
|
||||
type TypeWithInterface =
|
||||
inherit IDisposable
|
||||
abstract Mem1 : string option -> string[] Async
|
||||
abstract Mem2 : unit -> string[] Async
|
||||
|
||||
[<GenerateCapturingMock>]
|
||||
type TypeWithProperties =
|
||||
inherit IDisposable
|
||||
abstract Mem1 : string option -> string[] Async
|
||||
abstract Prop1 : int
|
||||
abstract Prop2 : unit Async
|
41
ConsumePlugin/CapturingMockExampleNoAttributes.fs
Normal file
41
ConsumePlugin/CapturingMockExampleNoAttributes.fs
Normal file
@@ -0,0 +1,41 @@
|
||||
namespace SomeNamespace.CapturingMock
|
||||
|
||||
open System
|
||||
|
||||
type IPublicTypeNoAttr =
|
||||
abstract Mem1 : string * int -> string list
|
||||
abstract Mem2 : string -> int
|
||||
abstract Mem3 : x : int * ?ct : System.Threading.CancellationToken -> string
|
||||
|
||||
type IPublicTypeInternalFalseNoAttr =
|
||||
abstract Mem1 : string * int -> string list
|
||||
abstract Mem2 : string -> int
|
||||
abstract Mem3 : x : int * ?ct : System.Threading.CancellationToken -> string
|
||||
|
||||
type internal InternalTypeNoAttr =
|
||||
abstract Mem1 : string * int -> unit
|
||||
abstract Mem2 : string -> int
|
||||
|
||||
type private PrivateTypeNoAttr =
|
||||
abstract Mem1 : string * int -> unit
|
||||
abstract Mem2 : string -> int
|
||||
|
||||
type private PrivateTypeInternalFalseNoAttr =
|
||||
abstract Mem1 : string * int -> unit
|
||||
abstract Mem2 : string -> int
|
||||
|
||||
type VeryPublicTypeNoAttr<'a, 'b> =
|
||||
abstract Mem1 : 'a -> 'b
|
||||
|
||||
type CurriedNoAttr<'a> =
|
||||
abstract Mem1 : int -> 'a -> string
|
||||
abstract Mem2 : int * string -> 'a -> string
|
||||
abstract Mem3 : (int * string) -> 'a -> string
|
||||
abstract Mem4 : (int * string) -> ('a * int) -> string
|
||||
abstract Mem5 : x : int * string -> ('a * int) -> string
|
||||
abstract Mem6 : int * string -> y : 'a * int -> string
|
||||
|
||||
type TypeWithInterfaceNoAttr =
|
||||
inherit IDisposable
|
||||
abstract Mem1 : string option -> string[] Async
|
||||
abstract Mem2 : unit -> string[] Async
|
@@ -33,6 +33,10 @@
|
||||
<Compile Include="GeneratedMock.fs">
|
||||
<MyriadFile>MockExample.fs</MyriadFile>
|
||||
</Compile>
|
||||
<Compile Include="CapturingMockExample.fs" />
|
||||
<Compile Include="GeneratedCapturingMock.fs">
|
||||
<MyriadFile>CapturingMockExample.fs</MyriadFile>
|
||||
</Compile>
|
||||
<Compile Include="MockExampleNoAttributes.fs" />
|
||||
<Compile Include="GeneratedMockNoAttributes.fs">
|
||||
<MyriadFile>MockExampleNoAttributes.fs</MyriadFile>
|
||||
@@ -47,6 +51,20 @@
|
||||
<TypeWithInterfaceNoAttr>GenerateMock</TypeWithInterfaceNoAttr>
|
||||
</MyriadParams>
|
||||
</Compile>
|
||||
<Compile Include="CapturingMockExampleNoAttributes.fs" />
|
||||
<Compile Include="GeneratedCapturingMockNoAttributes.fs">
|
||||
<MyriadFile>CapturingMockExampleNoAttributes.fs</MyriadFile>
|
||||
<MyriadParams>
|
||||
<IPublicTypeNoAttr>GenerateCapturingMock</IPublicTypeNoAttr>
|
||||
<IPublicTypeInternalFalseNoAttr>GenerateCapturingMock(false)</IPublicTypeInternalFalseNoAttr>
|
||||
<InternalTypeNoAttr>GenerateCapturingMock</InternalTypeNoAttr>
|
||||
<PrivateTypeNoAttr>GenerateCapturingMock</PrivateTypeNoAttr>
|
||||
<PrivateTypeInternalFalseNoAttr>GenerateCapturingMock(false)</PrivateTypeInternalFalseNoAttr>
|
||||
<VeryPublicTypeNoAttr>GenerateCapturingMock</VeryPublicTypeNoAttr>
|
||||
<CurriedNoAttr>GenerateCapturingMock</CurriedNoAttr>
|
||||
<TypeWithInterfaceNoAttr>GenerateCapturingMock</TypeWithInterfaceNoAttr>
|
||||
</MyriadParams>
|
||||
</Compile>
|
||||
<Compile Include="Vault.fs" />
|
||||
<Compile Include="GeneratedVault.fs">
|
||||
<MyriadFile>Vault.fs</MyriadFile>
|
||||
|
@@ -4,6 +4,7 @@
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
namespace Gitea
|
||||
|
||||
open WoofWare.Myriad.Plugins
|
||||
|
@@ -8,6 +8,7 @@
|
||||
|
||||
|
||||
|
||||
|
||||
namespace ConsumePlugin
|
||||
|
||||
open System
|
||||
|
349
ConsumePlugin/GeneratedCapturingMock.fs
Normal file
349
ConsumePlugin/GeneratedCapturingMock.fs
Normal file
@@ -0,0 +1,349 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// This code was generated by myriad.
|
||||
// Changes to this file will be lost when the code is regenerated.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
namespace SomeNamespace.CapturingMock
|
||||
|
||||
open System
|
||||
open WoofWare.Myriad.Plugins
|
||||
|
||||
/// Mock record type for an interface
|
||||
type internal PublicTypeMock =
|
||||
{
|
||||
Mem1 : string * int -> string list
|
||||
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
|
||||
Mem1_Calls : ResizeArray<string * int>
|
||||
Mem2 : string -> int
|
||||
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
|
||||
Mem2_Calls : ResizeArray<string>
|
||||
Mem3 : int * option<System.Threading.CancellationToken> -> string
|
||||
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
|
||||
Mem3_Calls : ResizeArray<int * System.Threading.CancellationToken>
|
||||
}
|
||||
|
||||
/// An implementation where every non-unit method throws.
|
||||
static member Empty : PublicTypeMock =
|
||||
{
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
|
||||
Mem3 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem3"))
|
||||
Mem1_Calls = ResizeArray ()
|
||||
Mem2_Calls = ResizeArray ()
|
||||
Mem3_Calls = ResizeArray ()
|
||||
}
|
||||
|
||||
interface IPublicType with
|
||||
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
|
||||
member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0)
|
||||
member this.Mem3 (arg_0_0, arg_0_1) = this.Mem3 (arg_0_0, arg_0_1)
|
||||
namespace SomeNamespace.CapturingMock
|
||||
|
||||
open System
|
||||
open WoofWare.Myriad.Plugins
|
||||
|
||||
/// Mock record type for an interface
|
||||
type public PublicTypeInternalFalseMock =
|
||||
{
|
||||
Mem1 : string * int -> string list
|
||||
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
|
||||
Mem1_Calls : ResizeArray<string * int>
|
||||
Mem2 : string -> int
|
||||
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
|
||||
Mem2_Calls : ResizeArray<string>
|
||||
Mem3 : int * option<System.Threading.CancellationToken> -> string
|
||||
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
|
||||
Mem3_Calls : ResizeArray<int * System.Threading.CancellationToken>
|
||||
}
|
||||
|
||||
/// An implementation where every non-unit method throws.
|
||||
static member Empty : PublicTypeInternalFalseMock =
|
||||
{
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
|
||||
Mem3 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem3"))
|
||||
Mem1_Calls = ResizeArray ()
|
||||
Mem2_Calls = ResizeArray ()
|
||||
Mem3_Calls = ResizeArray ()
|
||||
}
|
||||
|
||||
interface IPublicTypeInternalFalse with
|
||||
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
|
||||
member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0)
|
||||
member this.Mem3 (arg_0_0, arg_0_1) = this.Mem3 (arg_0_0, arg_0_1)
|
||||
namespace SomeNamespace.CapturingMock
|
||||
|
||||
open System
|
||||
open WoofWare.Myriad.Plugins
|
||||
|
||||
/// Mock record type for an interface
|
||||
type internal InternalTypeMock =
|
||||
{
|
||||
Mem1 : string * int -> unit
|
||||
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
|
||||
Mem1_Calls : ResizeArray<string * int>
|
||||
Mem2 : string -> int
|
||||
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
|
||||
Mem2_Calls : ResizeArray<string>
|
||||
}
|
||||
|
||||
/// An implementation where every non-unit method throws.
|
||||
static member Empty : InternalTypeMock =
|
||||
{
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
|
||||
Mem1_Calls = ResizeArray ()
|
||||
Mem2_Calls = ResizeArray ()
|
||||
}
|
||||
|
||||
interface InternalType with
|
||||
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
|
||||
member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0)
|
||||
namespace SomeNamespace.CapturingMock
|
||||
|
||||
open System
|
||||
open WoofWare.Myriad.Plugins
|
||||
|
||||
/// Mock record type for an interface
|
||||
type private PrivateTypeMock =
|
||||
{
|
||||
Mem1 : string * int -> unit
|
||||
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
|
||||
Mem1_Calls : ResizeArray<string * int>
|
||||
Mem2 : string -> int
|
||||
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
|
||||
Mem2_Calls : ResizeArray<string>
|
||||
}
|
||||
|
||||
/// An implementation where every non-unit method throws.
|
||||
static member Empty : PrivateTypeMock =
|
||||
{
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
|
||||
Mem1_Calls = ResizeArray ()
|
||||
Mem2_Calls = ResizeArray ()
|
||||
}
|
||||
|
||||
interface PrivateType with
|
||||
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
|
||||
member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0)
|
||||
namespace SomeNamespace.CapturingMock
|
||||
|
||||
open System
|
||||
open WoofWare.Myriad.Plugins
|
||||
|
||||
/// Mock record type for an interface
|
||||
type private PrivateTypeInternalFalseMock =
|
||||
{
|
||||
Mem1 : string * int -> unit
|
||||
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
|
||||
Mem1_Calls : ResizeArray<string * int>
|
||||
Mem2 : string -> int
|
||||
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
|
||||
Mem2_Calls : ResizeArray<string>
|
||||
}
|
||||
|
||||
/// An implementation where every non-unit method throws.
|
||||
static member Empty : PrivateTypeInternalFalseMock =
|
||||
{
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
|
||||
Mem1_Calls = ResizeArray ()
|
||||
Mem2_Calls = ResizeArray ()
|
||||
}
|
||||
|
||||
interface PrivateTypeInternalFalse with
|
||||
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
|
||||
member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0)
|
||||
namespace SomeNamespace.CapturingMock
|
||||
|
||||
open System
|
||||
open WoofWare.Myriad.Plugins
|
||||
|
||||
/// Mock record type for an interface
|
||||
type internal VeryPublicTypeMock<'a, 'b> =
|
||||
{
|
||||
Mem1 : 'a -> 'b
|
||||
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
|
||||
Mem1_Calls : ResizeArray<'a>
|
||||
}
|
||||
|
||||
/// An implementation where every non-unit method throws.
|
||||
static member Empty () : VeryPublicTypeMock<'a, 'b> =
|
||||
{
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
Mem1_Calls = ResizeArray ()
|
||||
}
|
||||
|
||||
interface VeryPublicType<'a, 'b> with
|
||||
member this.Mem1 arg_0_0 = this.Mem1 (arg_0_0)
|
||||
namespace SomeNamespace.CapturingMock
|
||||
|
||||
open System
|
||||
open WoofWare.Myriad.Plugins
|
||||
|
||||
module internal CurriedMockCalls =
|
||||
/// A single call to the Mem1 method
|
||||
type internal Mem1Call<'a> =
|
||||
{
|
||||
bar : int
|
||||
Arg1 : 'a
|
||||
}
|
||||
|
||||
/// A single call to the Mem2 method
|
||||
type internal Mem2Call<'a> =
|
||||
{
|
||||
Arg0 : int * string
|
||||
baz : 'a
|
||||
}
|
||||
|
||||
/// A single call to the Mem3 method
|
||||
type internal Mem3Call<'a> =
|
||||
{
|
||||
quux : (int * string)
|
||||
flurb : 'a
|
||||
}
|
||||
|
||||
/// A single call to the Mem4 method
|
||||
type internal Mem4Call<'a> =
|
||||
{
|
||||
Arg0 : int * string
|
||||
Arg1 : 'a * int
|
||||
}
|
||||
|
||||
/// A single call to the Mem5 method
|
||||
type internal Mem5Call<'a> =
|
||||
{
|
||||
Arg0 : int * string
|
||||
Arg1 : 'a * int
|
||||
}
|
||||
|
||||
/// A single call to the Mem6 method
|
||||
type internal Mem6Call<'a> =
|
||||
{
|
||||
Arg0 : int * string
|
||||
Arg1 : 'a * int
|
||||
}
|
||||
|
||||
/// Mock record type for an interface
|
||||
type internal CurriedMock<'a> =
|
||||
{
|
||||
Mem1 : int -> 'a -> string
|
||||
Mem1_Calls : ResizeArray<CurriedMockCalls.Mem1Call<'a>>
|
||||
Mem2 : int * string -> 'a -> string
|
||||
Mem2_Calls : ResizeArray<CurriedMockCalls.Mem2Call<'a>>
|
||||
Mem3 : (int * string) -> 'a -> string
|
||||
Mem3_Calls : ResizeArray<CurriedMockCalls.Mem3Call<'a>>
|
||||
Mem4 : (int * string) -> ('a * int) -> string
|
||||
Mem4_Calls : ResizeArray<CurriedMockCalls.Mem4Call<'a>>
|
||||
Mem5 : int * string -> ('a * int) -> string
|
||||
Mem5_Calls : ResizeArray<CurriedMockCalls.Mem5Call<'a>>
|
||||
Mem6 : int * string -> 'a * int -> string
|
||||
Mem6_Calls : ResizeArray<CurriedMockCalls.Mem6Call<'a>>
|
||||
}
|
||||
|
||||
/// An implementation where every non-unit method throws.
|
||||
static member Empty () : CurriedMock<'a> =
|
||||
{
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
|
||||
Mem3 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem3"))
|
||||
Mem4 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem4"))
|
||||
Mem5 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem5"))
|
||||
Mem6 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem6"))
|
||||
Mem1_Calls = ResizeArray ()
|
||||
Mem2_Calls = ResizeArray ()
|
||||
Mem3_Calls = ResizeArray ()
|
||||
Mem4_Calls = ResizeArray ()
|
||||
Mem5_Calls = ResizeArray ()
|
||||
Mem6_Calls = ResizeArray ()
|
||||
}
|
||||
|
||||
interface Curried<'a> with
|
||||
member this.Mem1 arg_0_0 arg_1_0 = this.Mem1 (arg_0_0) (arg_1_0)
|
||||
member this.Mem2 (arg_0_0, arg_0_1) arg_1_0 = this.Mem2 (arg_0_0, arg_0_1) (arg_1_0)
|
||||
member this.Mem3 arg_0_0 arg_1_0 = this.Mem3 (arg_0_0) (arg_1_0)
|
||||
|
||||
member this.Mem4 ((arg_0_0, arg_0_1)) ((arg_1_0, arg_1_1)) =
|
||||
this.Mem4 (arg_0_0, arg_0_1) (arg_1_0, arg_1_1)
|
||||
|
||||
member this.Mem5 (arg_0_0, arg_0_1) ((arg_1_0, arg_1_1)) =
|
||||
this.Mem5 (arg_0_0, arg_0_1) (arg_1_0, arg_1_1)
|
||||
|
||||
member this.Mem6 (arg_0_0, arg_0_1) (arg_1_0, arg_1_1) =
|
||||
this.Mem6 (arg_0_0, arg_0_1) (arg_1_0, arg_1_1)
|
||||
namespace SomeNamespace.CapturingMock
|
||||
|
||||
open System
|
||||
open WoofWare.Myriad.Plugins
|
||||
|
||||
/// Mock record type for an interface
|
||||
type internal TypeWithInterfaceMock =
|
||||
{
|
||||
/// Implementation of IDisposable.Dispose
|
||||
Dispose : unit -> unit
|
||||
Mem1 : string option -> string[] Async
|
||||
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
|
||||
Mem1_Calls : ResizeArray<string option>
|
||||
Mem2 : unit -> string[] Async
|
||||
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
|
||||
Mem2_Calls : ResizeArray<unit>
|
||||
}
|
||||
|
||||
/// An implementation where every non-unit method throws.
|
||||
static member Empty : TypeWithInterfaceMock =
|
||||
{
|
||||
Dispose = (fun () -> ())
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
|
||||
Mem1_Calls = ResizeArray ()
|
||||
Mem2_Calls = ResizeArray ()
|
||||
}
|
||||
|
||||
interface TypeWithInterface with
|
||||
member this.Mem1 arg_0_0 = this.Mem1 (arg_0_0)
|
||||
member this.Mem2 () = this.Mem2 (())
|
||||
|
||||
interface System.IDisposable with
|
||||
member this.Dispose () : unit = this.Dispose ()
|
||||
namespace SomeNamespace.CapturingMock
|
||||
|
||||
open System
|
||||
open WoofWare.Myriad.Plugins
|
||||
|
||||
/// Mock record type for an interface
|
||||
type internal TypeWithPropertiesMock =
|
||||
{
|
||||
/// Implementation of IDisposable.Dispose
|
||||
Dispose : unit -> unit
|
||||
Prop1 : unit -> int
|
||||
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
|
||||
Prop1_Calls : ResizeArray<unit>
|
||||
Prop2 : unit -> unit Async
|
||||
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
|
||||
Prop2_Calls : ResizeArray<unit>
|
||||
Mem1 : string option -> string[] Async
|
||||
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
|
||||
Mem1_Calls : ResizeArray<string option>
|
||||
}
|
||||
|
||||
/// An implementation where every non-unit 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"))
|
||||
Prop1_Calls = ResizeArray ()
|
||||
Prop2_Calls = ResizeArray ()
|
||||
Mem1_Calls = ResizeArray ()
|
||||
}
|
||||
|
||||
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 ()
|
301
ConsumePlugin/GeneratedCapturingMockNoAttributes.fs
Normal file
301
ConsumePlugin/GeneratedCapturingMockNoAttributes.fs
Normal file
@@ -0,0 +1,301 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// This code was generated by myriad.
|
||||
// Changes to this file will be lost when the code is regenerated.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
namespace SomeNamespace.CapturingMock
|
||||
|
||||
open System
|
||||
|
||||
/// Mock record type for an interface
|
||||
type internal PublicTypeNoAttrMock =
|
||||
{
|
||||
Mem1 : string * int -> string list
|
||||
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
|
||||
Mem1_Calls : ResizeArray<string * int>
|
||||
Mem2 : string -> int
|
||||
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
|
||||
Mem2_Calls : ResizeArray<string>
|
||||
Mem3 : int * option<System.Threading.CancellationToken> -> string
|
||||
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
|
||||
Mem3_Calls : ResizeArray<int * System.Threading.CancellationToken>
|
||||
}
|
||||
|
||||
/// An implementation where every non-unit method throws.
|
||||
static member Empty : PublicTypeNoAttrMock =
|
||||
{
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
|
||||
Mem3 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem3"))
|
||||
Mem1_Calls = ResizeArray ()
|
||||
Mem2_Calls = ResizeArray ()
|
||||
Mem3_Calls = ResizeArray ()
|
||||
}
|
||||
|
||||
interface IPublicTypeNoAttr with
|
||||
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
|
||||
member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0)
|
||||
member this.Mem3 (arg_0_0, arg_0_1) = this.Mem3 (arg_0_0, arg_0_1)
|
||||
namespace SomeNamespace.CapturingMock
|
||||
|
||||
open System
|
||||
|
||||
/// Mock record type for an interface
|
||||
type public PublicTypeInternalFalseNoAttrMock =
|
||||
{
|
||||
Mem1 : string * int -> string list
|
||||
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
|
||||
Mem1_Calls : ResizeArray<string * int>
|
||||
Mem2 : string -> int
|
||||
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
|
||||
Mem2_Calls : ResizeArray<string>
|
||||
Mem3 : int * option<System.Threading.CancellationToken> -> string
|
||||
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
|
||||
Mem3_Calls : ResizeArray<int * System.Threading.CancellationToken>
|
||||
}
|
||||
|
||||
/// An implementation where every non-unit method throws.
|
||||
static member Empty : PublicTypeInternalFalseNoAttrMock =
|
||||
{
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
|
||||
Mem3 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem3"))
|
||||
Mem1_Calls = ResizeArray ()
|
||||
Mem2_Calls = ResizeArray ()
|
||||
Mem3_Calls = ResizeArray ()
|
||||
}
|
||||
|
||||
interface IPublicTypeInternalFalseNoAttr with
|
||||
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
|
||||
member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0)
|
||||
member this.Mem3 (arg_0_0, arg_0_1) = this.Mem3 (arg_0_0, arg_0_1)
|
||||
namespace SomeNamespace.CapturingMock
|
||||
|
||||
open System
|
||||
|
||||
/// Mock record type for an interface
|
||||
type internal InternalTypeNoAttrMock =
|
||||
{
|
||||
Mem1 : string * int -> unit
|
||||
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
|
||||
Mem1_Calls : ResizeArray<string * int>
|
||||
Mem2 : string -> int
|
||||
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
|
||||
Mem2_Calls : ResizeArray<string>
|
||||
}
|
||||
|
||||
/// An implementation where every non-unit method throws.
|
||||
static member Empty : InternalTypeNoAttrMock =
|
||||
{
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
|
||||
Mem1_Calls = ResizeArray ()
|
||||
Mem2_Calls = ResizeArray ()
|
||||
}
|
||||
|
||||
interface InternalTypeNoAttr with
|
||||
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
|
||||
member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0)
|
||||
namespace SomeNamespace.CapturingMock
|
||||
|
||||
open System
|
||||
|
||||
/// Mock record type for an interface
|
||||
type private PrivateTypeNoAttrMock =
|
||||
{
|
||||
Mem1 : string * int -> unit
|
||||
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
|
||||
Mem1_Calls : ResizeArray<string * int>
|
||||
Mem2 : string -> int
|
||||
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
|
||||
Mem2_Calls : ResizeArray<string>
|
||||
}
|
||||
|
||||
/// An implementation where every non-unit method throws.
|
||||
static member Empty : PrivateTypeNoAttrMock =
|
||||
{
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
|
||||
Mem1_Calls = ResizeArray ()
|
||||
Mem2_Calls = ResizeArray ()
|
||||
}
|
||||
|
||||
interface PrivateTypeNoAttr with
|
||||
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
|
||||
member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0)
|
||||
namespace SomeNamespace.CapturingMock
|
||||
|
||||
open System
|
||||
|
||||
/// Mock record type for an interface
|
||||
type private PrivateTypeInternalFalseNoAttrMock =
|
||||
{
|
||||
Mem1 : string * int -> unit
|
||||
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
|
||||
Mem1_Calls : ResizeArray<string * int>
|
||||
Mem2 : string -> int
|
||||
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
|
||||
Mem2_Calls : ResizeArray<string>
|
||||
}
|
||||
|
||||
/// An implementation where every non-unit method throws.
|
||||
static member Empty : PrivateTypeInternalFalseNoAttrMock =
|
||||
{
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
|
||||
Mem1_Calls = ResizeArray ()
|
||||
Mem2_Calls = ResizeArray ()
|
||||
}
|
||||
|
||||
interface PrivateTypeInternalFalseNoAttr with
|
||||
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
|
||||
member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0)
|
||||
namespace SomeNamespace.CapturingMock
|
||||
|
||||
open System
|
||||
|
||||
/// Mock record type for an interface
|
||||
type internal VeryPublicTypeNoAttrMock<'a, 'b> =
|
||||
{
|
||||
Mem1 : 'a -> 'b
|
||||
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
|
||||
Mem1_Calls : ResizeArray<'a>
|
||||
}
|
||||
|
||||
/// An implementation where every non-unit method throws.
|
||||
static member Empty () : VeryPublicTypeNoAttrMock<'a, 'b> =
|
||||
{
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
Mem1_Calls = ResizeArray ()
|
||||
}
|
||||
|
||||
interface VeryPublicTypeNoAttr<'a, 'b> with
|
||||
member this.Mem1 arg_0_0 = this.Mem1 (arg_0_0)
|
||||
namespace SomeNamespace.CapturingMock
|
||||
|
||||
open System
|
||||
|
||||
module internal CurriedNoAttrMockCalls =
|
||||
/// A single call to the Mem1 method
|
||||
type internal Mem1Call<'a> =
|
||||
{
|
||||
Arg0 : int
|
||||
Arg1 : 'a
|
||||
}
|
||||
|
||||
/// A single call to the Mem2 method
|
||||
type internal Mem2Call<'a> =
|
||||
{
|
||||
Arg0 : int * string
|
||||
Arg1 : 'a
|
||||
}
|
||||
|
||||
/// A single call to the Mem3 method
|
||||
type internal Mem3Call<'a> =
|
||||
{
|
||||
Arg0 : int * string
|
||||
Arg1 : 'a
|
||||
}
|
||||
|
||||
/// A single call to the Mem4 method
|
||||
type internal Mem4Call<'a> =
|
||||
{
|
||||
Arg0 : int * string
|
||||
Arg1 : 'a * int
|
||||
}
|
||||
|
||||
/// A single call to the Mem5 method
|
||||
type internal Mem5Call<'a> =
|
||||
{
|
||||
Arg0 : int * string
|
||||
Arg1 : 'a * int
|
||||
}
|
||||
|
||||
/// A single call to the Mem6 method
|
||||
type internal Mem6Call<'a> =
|
||||
{
|
||||
Arg0 : int * string
|
||||
Arg1 : 'a * int
|
||||
}
|
||||
|
||||
/// Mock record type for an interface
|
||||
type internal CurriedNoAttrMock<'a> =
|
||||
{
|
||||
Mem1 : int -> 'a -> string
|
||||
Mem1_Calls : ResizeArray<CurriedNoAttrMockCalls.Mem1Call<'a>>
|
||||
Mem2 : int * string -> 'a -> string
|
||||
Mem2_Calls : ResizeArray<CurriedNoAttrMockCalls.Mem2Call<'a>>
|
||||
Mem3 : (int * string) -> 'a -> string
|
||||
Mem3_Calls : ResizeArray<CurriedNoAttrMockCalls.Mem3Call<'a>>
|
||||
Mem4 : (int * string) -> ('a * int) -> string
|
||||
Mem4_Calls : ResizeArray<CurriedNoAttrMockCalls.Mem4Call<'a>>
|
||||
Mem5 : int * string -> ('a * int) -> string
|
||||
Mem5_Calls : ResizeArray<CurriedNoAttrMockCalls.Mem5Call<'a>>
|
||||
Mem6 : int * string -> 'a * int -> string
|
||||
Mem6_Calls : ResizeArray<CurriedNoAttrMockCalls.Mem6Call<'a>>
|
||||
}
|
||||
|
||||
/// An implementation where every non-unit method throws.
|
||||
static member Empty () : CurriedNoAttrMock<'a> =
|
||||
{
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
|
||||
Mem3 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem3"))
|
||||
Mem4 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem4"))
|
||||
Mem5 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem5"))
|
||||
Mem6 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem6"))
|
||||
Mem1_Calls = ResizeArray ()
|
||||
Mem2_Calls = ResizeArray ()
|
||||
Mem3_Calls = ResizeArray ()
|
||||
Mem4_Calls = ResizeArray ()
|
||||
Mem5_Calls = ResizeArray ()
|
||||
Mem6_Calls = ResizeArray ()
|
||||
}
|
||||
|
||||
interface CurriedNoAttr<'a> with
|
||||
member this.Mem1 arg_0_0 arg_1_0 = this.Mem1 (arg_0_0) (arg_1_0)
|
||||
member this.Mem2 (arg_0_0, arg_0_1) arg_1_0 = this.Mem2 (arg_0_0, arg_0_1) (arg_1_0)
|
||||
member this.Mem3 ((arg_0_0, arg_0_1)) arg_1_0 = this.Mem3 (arg_0_0, arg_0_1) (arg_1_0)
|
||||
|
||||
member this.Mem4 ((arg_0_0, arg_0_1)) ((arg_1_0, arg_1_1)) =
|
||||
this.Mem4 (arg_0_0, arg_0_1) (arg_1_0, arg_1_1)
|
||||
|
||||
member this.Mem5 (arg_0_0, arg_0_1) ((arg_1_0, arg_1_1)) =
|
||||
this.Mem5 (arg_0_0, arg_0_1) (arg_1_0, arg_1_1)
|
||||
|
||||
member this.Mem6 (arg_0_0, arg_0_1) (arg_1_0, arg_1_1) =
|
||||
this.Mem6 (arg_0_0, arg_0_1) (arg_1_0, arg_1_1)
|
||||
namespace SomeNamespace.CapturingMock
|
||||
|
||||
open System
|
||||
|
||||
/// Mock record type for an interface
|
||||
type internal TypeWithInterfaceNoAttrMock =
|
||||
{
|
||||
/// Implementation of IDisposable.Dispose
|
||||
Dispose : unit -> unit
|
||||
Mem1 : string option -> string[] Async
|
||||
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
|
||||
Mem1_Calls : ResizeArray<string option>
|
||||
Mem2 : unit -> string[] Async
|
||||
/// Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it.
|
||||
Mem2_Calls : ResizeArray<unit>
|
||||
}
|
||||
|
||||
/// An implementation where every non-unit method throws.
|
||||
static member Empty : TypeWithInterfaceNoAttrMock =
|
||||
{
|
||||
Dispose = (fun () -> ())
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
|
||||
Mem1_Calls = ResizeArray ()
|
||||
Mem2_Calls = ResizeArray ()
|
||||
}
|
||||
|
||||
interface TypeWithInterfaceNoAttr with
|
||||
member this.Mem1 arg_0_0 = this.Mem1 (arg_0_0)
|
||||
member this.Mem2 () = this.Mem2 (())
|
||||
|
||||
interface System.IDisposable with
|
||||
member this.Dispose () : unit = this.Dispose ()
|
@@ -7,6 +7,7 @@
|
||||
|
||||
|
||||
|
||||
|
||||
namespace ConsumePlugin
|
||||
|
||||
open WoofWare.Myriad.Plugins
|
||||
|
@@ -7,6 +7,7 @@
|
||||
|
||||
|
||||
|
||||
|
||||
namespace ConsumePlugin
|
||||
|
||||
open WoofWare.Myriad.Plugins
|
||||
|
@@ -4,6 +4,7 @@
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
namespace ConsumePlugin
|
||||
|
||||
open System.Text.Json.Serialization
|
||||
|
@@ -4,6 +4,7 @@
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
namespace PureGym
|
||||
|
||||
open System
|
||||
|
@@ -6,6 +6,7 @@
|
||||
|
||||
|
||||
|
||||
|
||||
namespace PureGym
|
||||
|
||||
open System
|
||||
|
@@ -4,6 +4,7 @@
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
namespace ConsumePlugin
|
||||
|
||||
open System
|
||||
|
@@ -9,6 +9,7 @@
|
||||
|
||||
|
||||
|
||||
|
||||
namespace Gitea
|
||||
|
||||
open WoofWare.Myriad.Plugins
|
||||
|
@@ -5,6 +5,7 @@
|
||||
|
||||
|
||||
|
||||
|
||||
namespace ConsumePlugin
|
||||
|
||||
/// Module containing JSON parsing methods for the JwtVaultAuthResponse type
|
||||
|
@@ -7,6 +7,7 @@
|
||||
|
||||
|
||||
|
||||
|
||||
namespace ConsumePlugin
|
||||
|
||||
open WoofWare.Myriad.Plugins
|
||||
|
@@ -10,8 +10,8 @@
|
||||
<WarnOn>FS3388,FS3559</WarnOn>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Nerdbank.GitVersioning" Version="3.8.38-alpha" PrivateAssets="all"/>
|
||||
<SourceLinkGitHubHost Include="github.com" ContentUrl="https://raw.githubusercontent.com"/>
|
||||
<PackageReference Include="Nerdbank.GitVersioning" Version="3.8.38-alpha" PrivateAssets="all" />
|
||||
<SourceLinkGitHubHost Include="github.com" ContentUrl="https://raw.githubusercontent.com" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Condition="'$(GITHUB_ACTION)' != ''">
|
||||
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
|
||||
|
48
README.md
48
README.md
@@ -13,7 +13,7 @@ Currently implemented:
|
||||
* `JsonParse` (to stamp out `jsonParse : JsonNode -> 'T` methods).
|
||||
* `JsonSerialize` (to stamp out `toJsonNode : 'T -> JsonNode` methods).
|
||||
* `HttpClient` (to stamp out a [RestEase](https://github.com/canton7/RestEase)-style HTTP client).
|
||||
* `GenerateMock` (to stamp out a record type corresponding to an interface, like a compile-time [Foq](https://github.com/fsprojects/Foq)).
|
||||
* `GenerateMock` and `GenerateCapturingMock` (to stamp out a record type corresponding to an interface, like a compile-time [Foq](https://github.com/fsprojects/Foq)).
|
||||
* `ArgParser` (to stamp out a basic argument parser).
|
||||
* `SwaggerClient` (to stamp out an HTTP client for a Swagger API).
|
||||
* `CreateCatamorphism` (to stamp out a non-stack-overflowing [catamorphism](https://fsharpforfunandprofit.com/posts/recursive-types-and-folds/) for a discriminated union).
|
||||
@@ -440,9 +440,9 @@ There are also some design decisions:
|
||||
so arguments are forced to be tupled.
|
||||
* The `[<Optional>]` attribute is not supported and will probably not be supported, because I consider it to be cursed.
|
||||
|
||||
## `GenerateMock`
|
||||
## `GenerateMock` and `GenerateCapturingMock`
|
||||
|
||||
Takes a type like this:
|
||||
`GenerateMock` takes a type like this:
|
||||
|
||||
```fsharp
|
||||
[<GenerateMock>]
|
||||
@@ -472,6 +472,48 @@ type internal PublicTypeMock =
|
||||
member this.Mem2 (arg0) = this.Mem2 (arg0)
|
||||
```
|
||||
|
||||
`GenerateCapturingMock` additionally captures the calls made to each function (except for `Dispose`).
|
||||
It takes a type like this:
|
||||
|
||||
```fsharp
|
||||
[<GenerateCapturingMock>]
|
||||
type IPublicType =
|
||||
abstract Mem1 : string * int -> string list
|
||||
abstract Mem2 : baz : string -> unit -> int
|
||||
```
|
||||
|
||||
and stamps out types like this:
|
||||
|
||||
```fsharp
|
||||
module internal PublicTypeCalls =
|
||||
type internal Mem2Call =
|
||||
{
|
||||
baz : string
|
||||
Arg1 : unit
|
||||
}
|
||||
|
||||
/// Mock record type for an interface
|
||||
type internal PublicTypeMock =
|
||||
{
|
||||
Mem1 : string * int -> string list
|
||||
Mem2 : string -> int
|
||||
Mem2_Calls : ResizeArray<string * int>
|
||||
Mem2_Calls : ResizeArray<PublicTypeCalls.Mem2Call>
|
||||
}
|
||||
|
||||
static member Empty : PublicTypeMock =
|
||||
{
|
||||
Mem1 = (fun x -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||
Mem2 = (fun x -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||
Mem1_Calls = ResizeArray ()
|
||||
Mem2_Calls = ResizeArray ()
|
||||
}
|
||||
|
||||
interface IPublicType with
|
||||
member this.Mem1 (arg0, arg1) = this.Mem1 (arg0, arg1)
|
||||
member this.Mem2 (arg0) = this.Mem2 (arg0)
|
||||
```
|
||||
|
||||
### What's the point?
|
||||
|
||||
Reflective mocking libraries like [Foq](https://github.com/fsprojects/Foq) in my experience are a rich source of flaky tests.
|
||||
|
@@ -14,6 +14,9 @@ type RemoveOptionsAttribute () =
|
||||
/// 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.
|
||||
///
|
||||
/// The default implementation of each field throws (except for default implementations of IDisposable, which are
|
||||
/// no-ops).
|
||||
type GenerateMockAttribute (isInternal : bool) =
|
||||
inherit Attribute ()
|
||||
/// The default value of `isInternal`, the optional argument to the GenerateMockAttribute constructor.
|
||||
@@ -22,6 +25,22 @@ type GenerateMockAttribute (isInternal : bool) =
|
||||
/// Shorthand for the "isExtensionMethod = false" constructor; see documentation there for details.
|
||||
new () = GenerateMockAttribute GenerateMockAttribute.DefaultIsInternal
|
||||
|
||||
/// Attribute indicating an interface type for which the "Generate Capturing Mock" Myriad
|
||||
/// 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.
|
||||
///
|
||||
/// The default implementation of each field captures all calls made to it, which can then be accessed later.
|
||||
type GenerateCapturingMockAttribute (isInternal : bool) =
|
||||
inherit Attribute ()
|
||||
/// The default value of `isInternal`, the optional argument to the GenerateCapturingMockAttribute constructor.
|
||||
static member DefaultIsInternal = true
|
||||
|
||||
/// Shorthand for the "isExtensionMethod = false" constructor; see documentation there for details.
|
||||
new () = GenerateCapturingMockAttribute GenerateCapturingMockAttribute.DefaultIsInternal
|
||||
|
||||
/// Attribute indicating a record type to which the "Add JSON serializer" Myriad
|
||||
/// generator should apply during build.
|
||||
/// The purpose of this generator is to create methods (possibly extension methods) of the form
|
||||
|
@@ -15,6 +15,11 @@ WoofWare.Myriad.Plugins.ArgumentLongForm inherit System.Attribute
|
||||
WoofWare.Myriad.Plugins.ArgumentLongForm..ctor [constructor]: string
|
||||
WoofWare.Myriad.Plugins.CreateCatamorphismAttribute inherit System.Attribute
|
||||
WoofWare.Myriad.Plugins.CreateCatamorphismAttribute..ctor [constructor]: string
|
||||
WoofWare.Myriad.Plugins.GenerateCapturingMockAttribute inherit System.Attribute
|
||||
WoofWare.Myriad.Plugins.GenerateCapturingMockAttribute..ctor [constructor]: bool
|
||||
WoofWare.Myriad.Plugins.GenerateCapturingMockAttribute..ctor [constructor]: unit
|
||||
WoofWare.Myriad.Plugins.GenerateCapturingMockAttribute.DefaultIsInternal [static property]: [read-only] bool
|
||||
WoofWare.Myriad.Plugins.GenerateCapturingMockAttribute.get_DefaultIsInternal [static method]: unit -> bool
|
||||
WoofWare.Myriad.Plugins.GenerateMockAttribute inherit System.Attribute
|
||||
WoofWare.Myriad.Plugins.GenerateMockAttribute..ctor [constructor]: bool
|
||||
WoofWare.Myriad.Plugins.GenerateMockAttribute..ctor [constructor]: unit
|
||||
|
@@ -17,7 +17,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ApiSurface" Version="4.1.21" />
|
||||
<PackageReference Include="ApiSurface" Version="5.0.1" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1"/>
|
||||
<PackageReference Include="NUnit" Version="4.3.2"/>
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="5.0.0"/>
|
||||
|
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "3.6",
|
||||
"version": "3.7",
|
||||
"publicReleaseRefSpec": [
|
||||
"^refs/heads/main$"
|
||||
],
|
||||
|
@@ -0,0 +1,70 @@
|
||||
namespace WoofWare.Myriad.Plugins.Test
|
||||
|
||||
open System
|
||||
open SomeNamespace.CapturingMock
|
||||
open NUnit.Framework
|
||||
open FsUnitTyped
|
||||
|
||||
[<TestFixture>]
|
||||
module TestCapturingMockGenerator =
|
||||
|
||||
[<Test>]
|
||||
let ``Example of use: IPublicType`` () =
|
||||
let mock : IPublicType =
|
||||
{ PublicTypeMock.Empty with
|
||||
Mem1 = fun (s, count) -> List.replicate count s
|
||||
}
|
||||
:> _
|
||||
|
||||
let _ =
|
||||
Assert.Throws<NotImplementedException> (fun () -> mock.Mem2 "hi" |> ignore<int>)
|
||||
|
||||
mock.Mem1 ("hi", 3) |> shouldEqual [ "hi" ; "hi" ; "hi" ]
|
||||
|
||||
[<Test>]
|
||||
let ``Example of use: curried args`` () =
|
||||
let mock : Curried<_> =
|
||||
{ CurriedMock.Empty () with
|
||||
Mem1 = fun i c -> Array.replicate i c |> String
|
||||
Mem2 = fun (i, s) c -> String.concat $"%c{c}" (List.replicate i s)
|
||||
Mem3 = fun (i, s) c -> String.concat $"%c{c}" (List.replicate i s)
|
||||
}
|
||||
:> _
|
||||
|
||||
mock.Mem1 3 'a' |> shouldEqual "aaa"
|
||||
mock.Mem2 (3, "hi") 'a' |> shouldEqual "hiahiahi"
|
||||
mock.Mem3 (3, "hi") 'a' |> shouldEqual "hiahiahi"
|
||||
|
||||
[<Test>]
|
||||
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
|
||||
|
||||
[<Test>]
|
||||
let ``Example of curried use`` () =
|
||||
let mock =
|
||||
{ CurriedMock<string>.Empty () with
|
||||
Mem1 =
|
||||
fun x y ->
|
||||
x |> shouldEqual 3
|
||||
y |> shouldEqual "hello"
|
||||
"it's me"
|
||||
}
|
||||
|
||||
mock.Mem1 3 "hello" |> shouldEqual "it's me"
|
||||
|
||||
lock mock.Mem1_Calls (fun () -> Seq.toList mock.Mem1_Calls)
|
||||
|> List.exactlyOne
|
||||
|> shouldEqual
|
||||
{
|
||||
bar = 3
|
||||
Arg1 = "hello"
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
namespace WoofWare.Myriad.Plugins.Test
|
||||
|
||||
open System
|
||||
open SomeNamespace.CapturingMock
|
||||
open NUnit.Framework
|
||||
open FsUnitTyped
|
||||
|
||||
[<TestFixture>]
|
||||
module TestCapturingMockGeneratorNoAttr =
|
||||
|
||||
[<Test>]
|
||||
let ``Example of use: IPublicType`` () =
|
||||
let mock : IPublicTypeNoAttr =
|
||||
{ PublicTypeNoAttrMock.Empty with
|
||||
Mem1 = fun (s, count) -> List.replicate count s
|
||||
}
|
||||
:> _
|
||||
|
||||
let _ =
|
||||
Assert.Throws<NotImplementedException> (fun () -> mock.Mem2 "hi" |> ignore<int>)
|
||||
|
||||
mock.Mem1 ("hi", 3) |> shouldEqual [ "hi" ; "hi" ; "hi" ]
|
||||
|
||||
[<Test>]
|
||||
let ``Example of use: curried args`` () =
|
||||
let mock : CurriedNoAttr<_> =
|
||||
{ CurriedNoAttrMock.Empty () with
|
||||
Mem1 = fun i c -> Array.replicate i c |> String
|
||||
Mem2 = fun (i, s) c -> String.concat $"%c{c}" (List.replicate i s)
|
||||
Mem3 = fun (i, s) c -> String.concat $"%c{c}" (List.replicate i s)
|
||||
}
|
||||
:> _
|
||||
|
||||
mock.Mem1 3 'a' |> shouldEqual "aaa"
|
||||
mock.Mem2 (3, "hi") 'a' |> shouldEqual "hiahiahi"
|
||||
mock.Mem3 (3, "hi") 'a' |> shouldEqual "hiahiahi"
|
@@ -14,8 +14,8 @@
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="Assembly.fs" />
|
||||
<Compile Include="HttpClient.fs"/>
|
||||
<Compile Include="PureGymDtos.fs"/>
|
||||
<Compile Include="HttpClient.fs" />
|
||||
<Compile Include="PureGymDtos.fs" />
|
||||
<Compile Include="TestJsonParse\TestJsonParse.fs" />
|
||||
<Compile Include="TestJsonParse\TestPureGymJson.fs" />
|
||||
<Compile Include="TestJsonParse\TestExtensionMethod.fs" />
|
||||
@@ -29,6 +29,8 @@
|
||||
<Compile Include="TestHttpClient\TestVariableHeader.fs" />
|
||||
<Compile Include="TestMockGenerator\TestMockGenerator.fs" />
|
||||
<Compile Include="TestMockGenerator\TestMockGeneratorNoAttr.fs" />
|
||||
<Compile Include="TestCapturingMockGenerator\TestCapturingMockGenerator.fs" />
|
||||
<Compile Include="TestCapturingMockGenerator\TestCapturingMockGeneratorNoAttr.fs" />
|
||||
<Compile Include="TestJsonSerialize\TestJsonSerde.fs" />
|
||||
<Compile Include="TestCataGenerator\TestCataGenerator.fs" />
|
||||
<Compile Include="TestCataGenerator\TestDirectory.fs" />
|
||||
@@ -47,24 +49,24 @@
|
||||
<EmbeddedResource Include="TestSwagger\tictactoe.json" />
|
||||
<EmbeddedResource Include="TestSwagger\uspto.json" />
|
||||
<EmbeddedResource Include="TestSwagger\webhook-example.json" />
|
||||
<Compile Include="TestRemoveOptions.fs"/>
|
||||
<Compile Include="TestSurface.fs"/>
|
||||
<Compile Include="TestRemoveOptions.fs" />
|
||||
<Compile Include="TestSurface.fs" />
|
||||
<None Include="../.github/workflows/dotnet.yaml" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ApiSurface" Version="4.1.21"/>
|
||||
<PackageReference Include="FsCheck" Version="3.3.0"/>
|
||||
<PackageReference Include="FsUnit" Version="7.0.1"/>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1"/>
|
||||
<PackageReference Include="NUnit" Version="4.3.2"/>
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="5.0.0"/>
|
||||
<PackageReference Include="WoofWare.Expect" Version="0.4.2" />
|
||||
<PackageReference Include="ApiSurface" Version="5.0.1" />
|
||||
<PackageReference Include="FsCheck" Version="3.3.1" />
|
||||
<PackageReference Include="FsUnit" Version="7.1.1" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
|
||||
<PackageReference Include="NUnit" Version="4.3.2" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="5.0.0" />
|
||||
<PackageReference Include="WoofWare.Expect" Version="0.8.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\WoofWare.Myriad.Plugins\WoofWare.Myriad.Plugins.fsproj"/>
|
||||
<ProjectReference Include="..\ConsumePlugin\ConsumePlugin.fsproj"/>
|
||||
<ProjectReference Include="..\WoofWare.Myriad.Plugins\WoofWare.Myriad.Plugins.fsproj" />
|
||||
<ProjectReference Include="..\ConsumePlugin\ConsumePlugin.fsproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
578
WoofWare.Myriad.Plugins/CapturingInterfaceMockGenerator.fs
Normal file
578
WoofWare.Myriad.Plugins/CapturingInterfaceMockGenerator.fs
Normal file
@@ -0,0 +1,578 @@
|
||||
namespace WoofWare.Myriad.Plugins
|
||||
|
||||
open System
|
||||
open Fantomas.FCS.Syntax
|
||||
open Fantomas.FCS.Xml
|
||||
open WoofWare.Whippet.Fantomas
|
||||
|
||||
type internal CapturingInterfaceMockOutputSpec =
|
||||
{
|
||||
IsInternal : bool
|
||||
}
|
||||
|
||||
type private CallField =
|
||||
| ArgsObject of Ident * SynTypeDefn * SynTyparDecls option
|
||||
| Original of SynType
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal CapturingInterfaceMockGenerator =
|
||||
open Fantomas.FCS.Text.Range
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
type private KnownInheritance = | IDisposable
|
||||
|
||||
/// Expects the input `args` list to have more than one element.
|
||||
let private createTypeForArgs
|
||||
(spec : CapturingInterfaceMockOutputSpec)
|
||||
(memberName : Ident)
|
||||
(generics : SynTyparDecls option)
|
||||
(args : TupledArg list)
|
||||
: Ident * SynTypeDefn
|
||||
=
|
||||
let name = memberName.idText + "Call" |> Ident.create
|
||||
|
||||
let access =
|
||||
if spec.IsInternal then
|
||||
SynAccess.Internal range0
|
||||
else
|
||||
SynAccess.Public range0
|
||||
|
||||
let recordFields =
|
||||
args
|
||||
|> List.mapi (fun i tupledArg ->
|
||||
{
|
||||
SynFieldData.Ident =
|
||||
match tupledArg.Args with
|
||||
| [ arg ] -> arg.Id
|
||||
| _ -> None
|
||||
|> Option.defaultValue (Ident.create $"Arg%i{i}")
|
||||
|> Some
|
||||
Attrs = []
|
||||
Type =
|
||||
tupledArg.Args
|
||||
|> List.map (fun pi -> pi.Type)
|
||||
|> SynType.tupleNoParen
|
||||
|> Option.get
|
||||
}
|
||||
|> SynField.make
|
||||
)
|
||||
|
||||
let record =
|
||||
{
|
||||
Name = name
|
||||
Fields = recordFields
|
||||
Members = None
|
||||
XmlDoc = Some (PreXmlDoc.create $"A single call to the %s{memberName.idText} method")
|
||||
Generics = generics
|
||||
TypeAccessibility = Some access
|
||||
ImplAccessibility = None
|
||||
Attributes = []
|
||||
}
|
||||
|
||||
let typeDecl = AstHelper.defineRecordType record
|
||||
|
||||
name, typeDecl
|
||||
|
||||
let private buildType (x : ParameterInfo) : SynType =
|
||||
if x.IsOptional then
|
||||
SynType.app "option" [ x.Type ]
|
||||
else
|
||||
x.Type
|
||||
|
||||
let private constructMemberSinglePlace (tuple : TupledArg) : SynType =
|
||||
tuple.Args
|
||||
|> List.map buildType
|
||||
|> SynType.tupleNoParen
|
||||
|> Option.defaultWith (fun () -> failwith "no-arg functions not supported yet")
|
||||
|> if tuple.HasParen then SynType.paren else id
|
||||
|
||||
let rec private collectGenerics' (ty : SynType) : Ident list =
|
||||
match ty with
|
||||
| SynType.Var (typar = SynTypar (ident = typar)) -> [ typar ]
|
||||
| SynType.HashConstraint (innerType = ty)
|
||||
| SynType.WithGlobalConstraints (typeName = ty)
|
||||
| SynType.Paren (innerType = ty)
|
||||
| SynType.MeasurePower (baseMeasure = ty)
|
||||
| SynType.SignatureParameter (usedType = ty)
|
||||
| SynType.Array (elementType = ty) -> collectGenerics' ty
|
||||
| SynType.StaticConstant _
|
||||
| SynType.StaticConstantNamed _
|
||||
| SynType.StaticConstantExpr _
|
||||
| SynType.FromParseError _
|
||||
| SynType.Anon _
|
||||
| SynType.LongIdent _ -> []
|
||||
| SynType.LongIdentApp (typeArgs = tys)
|
||||
| SynType.App (typeArgs = tys) -> tys |> List.collect collectGenerics'
|
||||
| SynType.Tuple (path = path) ->
|
||||
path
|
||||
|> List.collect (fun seg ->
|
||||
match seg with
|
||||
| SynTupleTypeSegment.Type ty -> collectGenerics' ty
|
||||
| SynTupleTypeSegment.Star _
|
||||
| SynTupleTypeSegment.Slash _ -> []
|
||||
)
|
||||
| SynType.AnonRecd (fields = fields) -> fields |> List.collect (fun (_, ty) -> collectGenerics' ty)
|
||||
| SynType.Fun (argType = t1 ; returnType = t2)
|
||||
| SynType.Or (lhsType = t1 ; rhsType = t2) -> collectGenerics' t1 @ collectGenerics' t2
|
||||
|
||||
let private collectGenerics (ty : SynType) =
|
||||
collectGenerics' ty |> List.distinctBy _.idText
|
||||
|
||||
/// Builds the record field for the mock object, and also if applicable a type representing a single call to
|
||||
/// that object (packaging up the args of the call).
|
||||
let private constructMember (spec : CapturingInterfaceMockOutputSpec) (mem : MemberInfo) : SynField * CallField =
|
||||
let inputType = mem.Args |> List.map constructMemberSinglePlace
|
||||
|
||||
let funcType = SynType.toFun inputType mem.ReturnType
|
||||
|
||||
let field =
|
||||
{
|
||||
Type = funcType
|
||||
Attrs = []
|
||||
Ident = Some mem.Identifier
|
||||
}
|
||||
|> SynField.make
|
||||
|> SynField.withDocString (mem.XmlDoc |> Option.defaultValue PreXmlDoc.Empty)
|
||||
|
||||
let argsType =
|
||||
match mem.Args with
|
||||
| [] -> failwith "expected args in member"
|
||||
| [ ty ] ->
|
||||
ty.Args
|
||||
|> List.map _.Type
|
||||
|> SynType.tupleNoParen
|
||||
|> Option.get
|
||||
|> CallField.Original
|
||||
| args ->
|
||||
let genericsUsed =
|
||||
args
|
||||
|> List.collect (fun arg -> arg.Args |> List.map _.Type |> List.collect collectGenerics)
|
||||
|> List.distinctBy _.idText
|
||||
|
||||
let genericsUsed =
|
||||
match genericsUsed with
|
||||
| [] -> None
|
||||
| genericsUsed ->
|
||||
genericsUsed
|
||||
|> List.map (fun i ->
|
||||
SynTyparDecl.SynTyparDecl ([], SynTypar.SynTypar (i, TyparStaticReq.None, false))
|
||||
)
|
||||
|> fun l -> SynTyparDecls.PostfixList (l, [], range0)
|
||||
|> Some
|
||||
|
||||
let name, defn = createTypeForArgs spec mem.Identifier genericsUsed args
|
||||
CallField.ArgsObject (name, defn, genericsUsed)
|
||||
|
||||
field, argsType
|
||||
|
||||
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 createType
|
||||
(spec : CapturingInterfaceMockOutputSpec)
|
||||
(name : string)
|
||||
(interfaceType : InterfaceType)
|
||||
(xmlDoc : PreXmlDoc)
|
||||
: SynModuleDecl option * SynModuleDecl
|
||||
=
|
||||
let fields =
|
||||
interfaceType.Members
|
||||
|> List.map (constructMember spec)
|
||||
|> List.append (
|
||||
interfaceType.Properties
|
||||
|> List.map constructProperty
|
||||
|> List.map (Tuple.withRight (CallField.Original SynType.unit))
|
||||
)
|
||||
|
||||
let inherits =
|
||||
interfaceType.Inherits
|
||||
|> Seq.map (fun ty ->
|
||||
match ty with
|
||||
| SynType.LongIdent (SynLongIdent.SynLongIdent (name, _, _)) ->
|
||||
match name |> List.map _.idText with
|
||||
| [] -> failwith "Unexpected empty identifier in inheritance declaration"
|
||||
| [ "IDisposable" ]
|
||||
| [ "System" ; "IDisposable" ] -> KnownInheritance.IDisposable
|
||||
| _ -> failwithf $"Unrecognised inheritance identifier: %+A{name}"
|
||||
| x -> failwithf $"Unrecognised type in inheritance: %+A{x}"
|
||||
)
|
||||
|> Set.ofSeq
|
||||
|
||||
// TODO: for each field, if there are multiple arguments to the member, stamp out a new type to represent them;
|
||||
// then store that type name in this list alongside the field name
|
||||
let fields =
|
||||
fields
|
||||
|> List.map (fun (SynField (idOpt = idOpt) as f, extraType) ->
|
||||
let fieldName =
|
||||
match idOpt with
|
||||
| None -> failwith $"unexpectedly got a field with no identifier: %O{f}"
|
||||
| Some idOpt -> idOpt.idText
|
||||
|
||||
f, extraType, fieldName
|
||||
)
|
||||
|
||||
let failwithNotImplemented (fieldName : string) =
|
||||
let failString = SynExpr.CreateConst $"Unimplemented mock function: %s{fieldName}"
|
||||
|
||||
SynExpr.createLongIdent [ "System" ; "NotImplementedException" ]
|
||||
|> SynExpr.applyTo failString
|
||||
|> SynExpr.paren
|
||||
|> SynExpr.applyFunction (SynExpr.createIdent "raise")
|
||||
|> SynExpr.createLambda "_"
|
||||
|
||||
let constructorReturnType =
|
||||
match interfaceType.Generics with
|
||||
| None -> SynType.createLongIdent' [ name ]
|
||||
| Some generics ->
|
||||
|
||||
let generics =
|
||||
generics.TyparDecls
|
||||
|> List.map (fun (SynTyparDecl (_, typar)) -> SynType.var typar)
|
||||
|
||||
SynType.app name generics
|
||||
|
||||
let emptyRecordFieldInstantiations =
|
||||
let interfaceExtras =
|
||||
if inherits.Contains KnownInheritance.IDisposable then
|
||||
let unitFun = SynExpr.createThunk (SynExpr.CreateConst ())
|
||||
|
||||
[ SynLongIdent.createS "Dispose", unitFun ]
|
||||
else
|
||||
[]
|
||||
|
||||
let originalMembers =
|
||||
fields
|
||||
|> List.map (fun (_, _, fieldName) -> SynLongIdent.createS fieldName, failwithNotImplemented fieldName)
|
||||
|
||||
let callsArrays =
|
||||
fields
|
||||
|> List.map (fun (_field, _, fieldName) ->
|
||||
let name = SynLongIdent.createS $"%s{fieldName}_Calls"
|
||||
|
||||
let init =
|
||||
SynExpr.createIdent "ResizeArray" |> SynExpr.applyTo (SynExpr.CreateConst ())
|
||||
|
||||
name, init
|
||||
)
|
||||
|
||||
interfaceExtras @ originalMembers @ callsArrays
|
||||
|
||||
let staticMemberEmpty =
|
||||
SynBinding.basic
|
||||
[ Ident.create "Empty" ]
|
||||
(if interfaceType.Generics.IsNone then
|
||||
[]
|
||||
else
|
||||
[ SynPat.unit ])
|
||||
(SynExpr.createRecord None emptyRecordFieldInstantiations)
|
||||
|> SynBinding.withXmlDoc (PreXmlDoc.create "An implementation where every non-unit method throws.")
|
||||
|> SynBinding.withReturnAnnotation constructorReturnType
|
||||
|> SynMemberDefn.staticMember
|
||||
|
||||
let recordFields =
|
||||
let extras =
|
||||
if inherits.Contains KnownInheritance.IDisposable then
|
||||
{
|
||||
Attrs = []
|
||||
Ident = Some (Ident.create "Dispose")
|
||||
Type = SynType.funFromDomain SynType.unit SynType.unit
|
||||
}
|
||||
|> SynField.make
|
||||
|> SynField.withDocString (PreXmlDoc.create "Implementation of IDisposable.Dispose")
|
||||
|> List.singleton
|
||||
else
|
||||
[]
|
||||
|
||||
let nonExtras =
|
||||
fields
|
||||
|> List.collect (fun (field, callType, fieldName) ->
|
||||
let callField =
|
||||
match callType with
|
||||
| CallField.Original ty ->
|
||||
{
|
||||
Attrs = []
|
||||
Ident = Some (fieldName + "_Calls" |> Ident.create)
|
||||
Type = SynType.app "ResizeArray" [ ty ]
|
||||
}
|
||||
|> SynField.make
|
||||
|> SynField.withDocString (
|
||||
PreXmlDoc.create
|
||||
"Additions to this ResizeArray are locked on itself. For maximum safety, lock on this field before reading it."
|
||||
)
|
||||
| CallField.ArgsObject (argsObjectName, _, generics) ->
|
||||
{
|
||||
Attrs = []
|
||||
Ident = Some (fieldName + "_Calls" |> Ident.create)
|
||||
Type =
|
||||
match generics with
|
||||
| None -> SynType.named argsObjectName.idText
|
||||
| Some generics ->
|
||||
generics.TyparDecls
|
||||
|> List.map (fun (SynTyparDecl.SynTyparDecl (_, typar)) -> SynType.var typar)
|
||||
|> SynType.app' (
|
||||
SynType.createLongIdent' [ $"%s{name}Calls" ; argsObjectName.idText ]
|
||||
)
|
||||
|> List.singleton
|
||||
|> SynType.app "ResizeArray"
|
||||
}
|
||||
|> SynField.make
|
||||
|
||||
[ field ; callField ]
|
||||
)
|
||||
|
||||
extras @ nonExtras
|
||||
|
||||
let interfaceMembers =
|
||||
let members =
|
||||
interfaceType.Members
|
||||
|> List.map (fun memberInfo ->
|
||||
let headArgs =
|
||||
memberInfo.Args
|
||||
|> List.mapi (fun i tupledArgs ->
|
||||
let args =
|
||||
tupledArgs.Args
|
||||
|> List.mapi (fun j ty ->
|
||||
match ty.Type with
|
||||
| UnitType -> SynPat.unit
|
||||
| _ -> SynPat.named $"arg_%i{i}_%i{j}"
|
||||
)
|
||||
|
||||
match args with
|
||||
| [] -> failwith "somehow got no args at all"
|
||||
| [ arg ] -> arg
|
||||
| args -> SynPat.tuple args
|
||||
|> fun i -> if tupledArgs.HasParen then SynPat.paren i else i
|
||||
)
|
||||
|
||||
let body =
|
||||
let tuples =
|
||||
memberInfo.Args
|
||||
|> List.mapi (fun i args ->
|
||||
args.Args
|
||||
|> List.mapi (fun j arg ->
|
||||
match arg.Type with
|
||||
| UnitType -> SynExpr.CreateConst ()
|
||||
| _ -> SynExpr.createIdent $"arg_%i{i}_%i{j}"
|
||||
)
|
||||
|> SynExpr.tuple
|
||||
)
|
||||
|
||||
match tuples |> List.rev with
|
||||
| [] -> failwith "expected args but got none"
|
||||
| last :: rest ->
|
||||
|
||||
(last, rest)
|
||||
||> List.fold SynExpr.applyTo
|
||||
|> SynExpr.applyFunction (
|
||||
SynExpr.createLongIdent' [ Ident.create "this" ; memberInfo.Identifier ]
|
||||
)
|
||||
|
||||
SynBinding.basic [ Ident.create "this" ; memberInfo.Identifier ] headArgs body
|
||||
|> 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
|
||||
|
||||
match interfaceType.Generics with
|
||||
| None -> baseName
|
||||
| Some generics ->
|
||||
let generics =
|
||||
match generics with
|
||||
| SynTyparDecls.PostfixList (decls, _, _) -> decls
|
||||
| SynTyparDecls.PrefixList (decls, _) -> decls
|
||||
| SynTyparDecls.SinglePrefix (decl, _) -> [ decl ]
|
||||
|> List.map (fun (SynTyparDecl (_, typar)) -> SynType.var typar)
|
||||
|
||||
SynType.app' baseName generics
|
||||
|
||||
SynMemberDefn.Interface (interfaceName, Some range0, Some (members @ properties), range0)
|
||||
|
||||
let access =
|
||||
match interfaceType.Accessibility, spec.IsInternal with
|
||||
| Some (SynAccess.Public _), true
|
||||
| None, true -> SynAccess.Internal range0
|
||||
| Some (SynAccess.Public _), false -> SynAccess.Public range0
|
||||
| None, false -> SynAccess.Public range0
|
||||
| Some (SynAccess.Internal _), _ -> SynAccess.Internal range0
|
||||
| Some (SynAccess.Private _), _ -> SynAccess.Private range0
|
||||
|
||||
let extraInterfaces =
|
||||
inherits
|
||||
|> Seq.map (fun inheritance ->
|
||||
match inheritance with
|
||||
| KnownInheritance.IDisposable ->
|
||||
let mem =
|
||||
SynExpr.createLongIdent [ "this" ; "Dispose" ]
|
||||
|> SynExpr.applyTo (SynExpr.CreateConst ())
|
||||
|> SynBinding.basic [ Ident.create "this" ; Ident.create "Dispose" ] [ SynPat.unit ]
|
||||
|> SynBinding.withReturnAnnotation SynType.unit
|
||||
|> SynMemberDefn.memberImplementation
|
||||
|
||||
SynMemberDefn.Interface (
|
||||
SynType.createLongIdent' [ "System" ; "IDisposable" ],
|
||||
Some range0,
|
||||
Some [ mem ],
|
||||
range0
|
||||
)
|
||||
)
|
||||
|> Seq.toList
|
||||
|
||||
let record =
|
||||
{
|
||||
Name = Ident.create name
|
||||
Fields = recordFields
|
||||
Members = Some ([ staticMemberEmpty ; interfaceMembers ] @ extraInterfaces)
|
||||
XmlDoc = Some xmlDoc
|
||||
Generics = interfaceType.Generics
|
||||
TypeAccessibility = Some access
|
||||
ImplAccessibility = None
|
||||
Attributes = []
|
||||
}
|
||||
|
||||
let typeDecl = AstHelper.defineRecordType record
|
||||
|
||||
let callsModule =
|
||||
fields
|
||||
|> List.choose (fun (_, field, _) ->
|
||||
match field with
|
||||
| CallField.Original _ -> None
|
||||
| CallField.ArgsObject (_, callType, _) -> Some callType
|
||||
)
|
||||
|> function
|
||||
| [] -> None
|
||||
| l ->
|
||||
SynModuleDecl.Types (l, range0)
|
||||
|> List.singleton
|
||||
|> SynModuleDecl.nestedModule (
|
||||
SynComponentInfo.create (Ident.create $"%s{name}Calls")
|
||||
|> SynComponentInfo.withAccessibility access
|
||||
)
|
||||
|> Some
|
||||
|
||||
(callsModule, SynModuleDecl.Types ([ typeDecl ], range0))
|
||||
|
||||
let createRecord
|
||||
(namespaceId : LongIdent)
|
||||
(opens : SynOpenDeclTarget list)
|
||||
(interfaceType : SynTypeDefn, spec : CapturingInterfaceMockOutputSpec)
|
||||
: SynModuleOrNamespace
|
||||
=
|
||||
let interfaceType = AstHelper.parseInterface interfaceType
|
||||
|
||||
let docString = PreXmlDoc.create "Mock record type for an interface"
|
||||
|
||||
let name =
|
||||
List.last interfaceType.Name
|
||||
|> _.idText
|
||||
|> fun s ->
|
||||
if s.StartsWith 'I' && s.Length > 1 && Char.IsUpper s.[1] then
|
||||
s.Substring 1
|
||||
else
|
||||
s
|
||||
|> fun s -> s + "Mock"
|
||||
|
||||
let callsTypes, typeDecl = createType spec name interfaceType docString
|
||||
|
||||
[
|
||||
yield! opens |> List.map SynModuleDecl.openAny
|
||||
match callsTypes with
|
||||
| None -> ()
|
||||
| Some c -> yield c
|
||||
yield typeDecl
|
||||
]
|
||||
|> SynModuleOrNamespace.createNamespace namespaceId
|
||||
|
||||
open Myriad.Core
|
||||
|
||||
/// Myriad generator that creates a record which implements the given interface,
|
||||
/// but with every field mocked out.
|
||||
[<MyriadGenerator("capturing-interface-mock")>]
|
||||
type CapturingInterfaceMockGenerator () =
|
||||
|
||||
interface IMyriadGenerator with
|
||||
member _.ValidInputExtensions = [ ".fs" ]
|
||||
|
||||
member _.Generate (context : GeneratorContext) =
|
||||
let targetedTypes =
|
||||
MyriadParamParser.render context.AdditionalParameters
|
||||
|> Map.map (fun _ v -> v.Split '!' |> Array.toList |> List.map DesiredGenerator.Parse)
|
||||
|
||||
let ast, _ =
|
||||
Ast.fromFilename context.InputFilename |> Async.RunSynchronously |> Array.head
|
||||
|
||||
let types = Ast.getTypes ast
|
||||
|
||||
let namespaceAndInterfaces =
|
||||
types
|
||||
|> List.choose (fun (ns, types) ->
|
||||
types
|
||||
|> List.choose (fun typeDef ->
|
||||
match SynTypeDefn.getAttribute typeof<GenerateCapturingMockAttribute>.Name typeDef with
|
||||
| None ->
|
||||
let name = SynTypeDefn.getName typeDef |> List.map _.idText |> String.concat "."
|
||||
|
||||
match Map.tryFind name targetedTypes with
|
||||
| Some desired ->
|
||||
desired
|
||||
|> List.tryPick (fun generator ->
|
||||
match generator with
|
||||
| DesiredGenerator.CapturingInterfaceMock arg ->
|
||||
let spec =
|
||||
{
|
||||
IsInternal =
|
||||
arg
|
||||
|> Option.defaultValue
|
||||
GenerateCapturingMockAttribute.DefaultIsInternal
|
||||
}
|
||||
|
||||
Some (typeDef, spec)
|
||||
| _ -> None
|
||||
)
|
||||
| _ -> None
|
||||
|
||||
| Some attr ->
|
||||
let arg =
|
||||
match SynExpr.stripOptionalParen attr.ArgExpr with
|
||||
| SynExpr.Const (SynConst.Bool value, _) -> value
|
||||
| SynExpr.Const (SynConst.Unit, _) -> GenerateCapturingMockAttribute.DefaultIsInternal
|
||||
| arg ->
|
||||
failwith
|
||||
$"Unrecognised argument %+A{arg} to [<%s{nameof GenerateCapturingMockAttribute}>]. Literals are not supported. Use `true` or `false` (or unit) only."
|
||||
|
||||
let spec =
|
||||
{
|
||||
IsInternal = arg
|
||||
}
|
||||
|
||||
Some (typeDef, spec)
|
||||
)
|
||||
|> function
|
||||
| [] -> None
|
||||
| ty -> Some (ns, ty)
|
||||
)
|
||||
|
||||
let opens = AstHelper.extractOpens ast
|
||||
|
||||
let modules =
|
||||
namespaceAndInterfaces
|
||||
|> List.collect (fun (ns, records) ->
|
||||
records |> List.map (CapturingInterfaceMockGenerator.createRecord ns opens)
|
||||
)
|
||||
|
||||
Output.Ast modules
|
@@ -2,6 +2,7 @@ namespace WoofWare.Myriad.Plugins
|
||||
|
||||
type internal DesiredGenerator =
|
||||
| InterfaceMock of isInternal : bool option
|
||||
| CapturingInterfaceMock of isInternal : bool option
|
||||
| JsonParse of extensionMethod : bool option
|
||||
| JsonSerialize of extensionMethod : bool option
|
||||
| HttpClient of extensionMethod : bool option
|
||||
@@ -11,6 +12,9 @@ type internal DesiredGenerator =
|
||||
| "GenerateMock" -> DesiredGenerator.InterfaceMock None
|
||||
| "GenerateMock(true)" -> DesiredGenerator.InterfaceMock (Some true)
|
||||
| "GenerateMock(false)" -> DesiredGenerator.InterfaceMock (Some false)
|
||||
| "GenerateCapturingMock" -> DesiredGenerator.CapturingInterfaceMock None
|
||||
| "GenerateCapturingMock(true)" -> DesiredGenerator.CapturingInterfaceMock (Some true)
|
||||
| "GenerateCapturingMock(false)" -> DesiredGenerator.CapturingInterfaceMock (Some false)
|
||||
| "JsonParse" -> DesiredGenerator.JsonParse None
|
||||
| "JsonParse(true)" -> DesiredGenerator.JsonParse (Some true)
|
||||
| "JsonParse(false)" -> DesiredGenerator.JsonParse (Some false)
|
||||
|
@@ -1,5 +1,7 @@
|
||||
WoofWare.Myriad.Plugins.ArgParserGenerator inherit obj, implements Myriad.Core.IMyriadGenerator
|
||||
WoofWare.Myriad.Plugins.ArgParserGenerator..ctor [constructor]: unit
|
||||
WoofWare.Myriad.Plugins.CapturingInterfaceMockGenerator inherit obj, implements Myriad.Core.IMyriadGenerator
|
||||
WoofWare.Myriad.Plugins.CapturingInterfaceMockGenerator..ctor [constructor]: unit
|
||||
WoofWare.Myriad.Plugins.CreateCatamorphismGenerator inherit obj, implements Myriad.Core.IMyriadGenerator
|
||||
WoofWare.Myriad.Plugins.CreateCatamorphismGenerator..ctor [constructor]: unit
|
||||
WoofWare.Myriad.Plugins.HttpClientGenerator inherit obj, implements Myriad.Core.IMyriadGenerator
|
||||
|
6
WoofWare.Myriad.Plugins/Tuple.fs
Normal file
6
WoofWare.Myriad.Plugins/Tuple.fs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace WoofWare.Myriad.Plugins
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal Tuple =
|
||||
let withLeft left right = left, right
|
||||
let withRight right left = left, right
|
@@ -30,6 +30,7 @@
|
||||
<ItemGroup>
|
||||
<Compile Include="AssemblyInfo.fs" />
|
||||
<Compile Include="List.fs"/>
|
||||
<Compile Include="Tuple.fs" />
|
||||
<Compile Include="Text.fs" />
|
||||
<Compile Include="Measure.fs" />
|
||||
<Compile Include="AstHelper.fs" />
|
||||
@@ -37,6 +38,7 @@
|
||||
<Compile Include="RemoveOptionsGenerator.fs"/>
|
||||
<Compile Include="MyriadParamParser.fs" />
|
||||
<Compile Include="InterfaceMockGenerator.fs"/>
|
||||
<Compile Include="CapturingInterfaceMockGenerator.fs" />
|
||||
<Compile Include="JsonSerializeGenerator.fs"/>
|
||||
<Compile Include="JsonParseGenerator.fs"/>
|
||||
<Compile Include="HttpClientGenerator.fs"/>
|
||||
|
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "8.0",
|
||||
"version": "8.1",
|
||||
"publicReleaseRefSpec": [
|
||||
"^refs/heads/main$"
|
||||
],
|
||||
|
@@ -10,7 +10,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageDownload Include="G-Research.FSharp.Analyzers" Version="[0.15.0]" />
|
||||
<PackageDownload Include="G-Research.FSharp.Analyzers" Version="[0.17.0]" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
6
flake.lock
generated
6
flake.lock
generated
@@ -20,11 +20,11 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1749903597,
|
||||
"narHash": "sha256-jp0D4vzBcRKwNZwfY4BcWHemLGUs4JrS3X9w5k/JYDA=",
|
||||
"lastModified": 1757746433,
|
||||
"narHash": "sha256-fEvTiU4s9lWgW7mYEU/1QUPirgkn+odUBTaindgiziY=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "41da1e3ea8e23e094e5e3eeb1e6b830468a7399e",
|
||||
"rev": "6d7ec06d6868ac6d94c371458fc2391ded9ff13d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@@ -66,6 +66,7 @@
|
||||
pkgs.alejandra
|
||||
pkgs.nodePackages.markdown-link-check
|
||||
pkgs.shellcheck
|
||||
pkgs.xmlstarlet
|
||||
];
|
||||
};
|
||||
});
|
||||
|
@@ -1,13 +1,13 @@
|
||||
[
|
||||
{
|
||||
"pname": "ApiSurface",
|
||||
"version": "4.1.21",
|
||||
"hash": "sha256-v2adBYoE9NZPaQR3u2qq9r/9PxAM/wqi2Uiky0xGq+E="
|
||||
"version": "5.0.1",
|
||||
"hash": "sha256-0GMXEMFgWbbE2OGxW+6h4zGgQHg+IZy1aI13Dn97xSU="
|
||||
},
|
||||
{
|
||||
"pname": "fantomas",
|
||||
"version": "7.0.2",
|
||||
"hash": "sha256-BAaENIm/ksTiXrUImRgKoIXTGIlgsX7ch6ayoFjhJXA="
|
||||
"version": "7.0.3",
|
||||
"hash": "sha256-0XlfV7SxXPDnk/CjkUesJSaH0cxlNHJ+Jj86zNUhkNA="
|
||||
},
|
||||
{
|
||||
"pname": "Fantomas.Core",
|
||||
@@ -19,15 +19,20 @@
|
||||
"version": "6.1.1",
|
||||
"hash": "sha256-NuZ8msPEHYA8T3EYREB28F1RcNgUU8V54eg2+UttYxw="
|
||||
},
|
||||
{
|
||||
"pname": "Fantomas.FCS",
|
||||
"version": "7.0.3",
|
||||
"hash": "sha256-BmCUq+ZQ3b25nrMBTc5tcxdO2soryEjNx9Fn/FJpi1c="
|
||||
},
|
||||
{
|
||||
"pname": "FsCheck",
|
||||
"version": "3.3.0",
|
||||
"hash": "sha256-TFDR/uAGv4OqrMX8/reQ4faaAhH9hxTHr1T/YkNPCCU="
|
||||
"version": "3.3.1",
|
||||
"hash": "sha256-k65ksdOSOGz+meRUUND+yuqJtm5ChaKuaxmRIdKzx2Y="
|
||||
},
|
||||
{
|
||||
"pname": "fsharp-analyzers",
|
||||
"version": "0.31.0",
|
||||
"hash": "sha256-PoAvaXbXsmvVw870UsnqdD20HoBHO7u4bzoaz5DXfzM="
|
||||
"version": "0.32.1",
|
||||
"hash": "sha256-le6rPnAF7cKGBZ2w8H2u9glK+6rT2ZjiAVnrkH2IhrM="
|
||||
},
|
||||
{
|
||||
"pname": "FSharp.Core",
|
||||
@@ -41,8 +46,8 @@
|
||||
},
|
||||
{
|
||||
"pname": "FSharp.Core",
|
||||
"version": "9.0.202",
|
||||
"hash": "sha256-64Gub0qemmCoMa1tDus6TeTuB1+5sHfE6KD2j4o84mA="
|
||||
"version": "9.0.303",
|
||||
"hash": "sha256-AxR6wqodeU23KOTgkUfIgbavgbcSuzD4UBP+tiFydgA="
|
||||
},
|
||||
{
|
||||
"pname": "FSharp.SystemTextJson",
|
||||
@@ -51,8 +56,8 @@
|
||||
},
|
||||
{
|
||||
"pname": "FsUnit",
|
||||
"version": "7.0.1",
|
||||
"hash": "sha256-K85CIdxMeFSHEKZk6heIXp/oFjWAn7dBILKrw49pJUY="
|
||||
"version": "7.1.1",
|
||||
"hash": "sha256-UMCEGKxQ4ytjmPuVpiNaAPbi3RQH9gqa61JJIUS/6hg="
|
||||
},
|
||||
{
|
||||
"pname": "Microsoft.ApplicationInsights",
|
||||
@@ -149,11 +154,6 @@
|
||||
"version": "1.1.1",
|
||||
"hash": "sha256-8hLiUKvy/YirCWlFwzdejD2Db3DaXhHxT7GSZx/znJg="
|
||||
},
|
||||
{
|
||||
"pname": "Microsoft.NETCore.Platforms",
|
||||
"version": "2.0.0",
|
||||
"hash": "sha256-IEvBk6wUXSdyCnkj6tHahOJv290tVVT8tyemYcR0Yro="
|
||||
},
|
||||
{
|
||||
"pname": "Microsoft.NETCore.Targets",
|
||||
"version": "1.1.0",
|
||||
@@ -309,26 +309,26 @@
|
||||
"version": "7.0.0",
|
||||
"hash": "sha256-9Wk8cHSkjKtqkN6xW7KnXoQVtF/VNbKeBq79WqDesMs="
|
||||
},
|
||||
{
|
||||
"pname": "System.Diagnostics.DiagnosticSource",
|
||||
"version": "8.0.1",
|
||||
"hash": "sha256-zmwHjcJgKcbkkwepH038QhcnsWMJcHys+PEbFGC0Jgo="
|
||||
},
|
||||
{
|
||||
"pname": "System.Formats.Asn1",
|
||||
"version": "6.0.0",
|
||||
"hash": "sha256-KaMHgIRBF7Nf3VwOo+gJS1DcD+41cJDPWFh+TDQ8ee8="
|
||||
},
|
||||
{
|
||||
"pname": "System.IO.Abstractions",
|
||||
"version": "4.2.13",
|
||||
"hash": "sha256-nkC/PiqE6+c1HJ2yTwg3x+qdBh844Z8n3ERWDW8k6Gg="
|
||||
},
|
||||
{
|
||||
"pname": "System.IO.FileSystem.AccessControl",
|
||||
"version": "4.5.0",
|
||||
"hash": "sha256-ck44YBQ0M+2Im5dw0VjBgFD1s0XuY54cujrodjjSBL8="
|
||||
},
|
||||
{
|
||||
"pname": "System.Memory",
|
||||
"version": "4.5.5",
|
||||
"hash": "sha256-EPQ9o1Kin7KzGI5O3U3PUQAZTItSbk9h/i4rViN3WiI="
|
||||
},
|
||||
{
|
||||
"pname": "System.Memory",
|
||||
"version": "4.6.0",
|
||||
"hash": "sha256-OhAEKzUM6eEaH99DcGaMz2pFLG/q/N4KVWqqiBYUOFo="
|
||||
},
|
||||
{
|
||||
"pname": "System.Private.Uri",
|
||||
"version": "4.3.0",
|
||||
@@ -349,11 +349,6 @@
|
||||
"version": "6.0.0",
|
||||
"hash": "sha256-bEG1PnDp7uKYz/OgLOWs3RWwQSVYm+AnPwVmAmcgp2I="
|
||||
},
|
||||
{
|
||||
"pname": "System.Security.AccessControl",
|
||||
"version": "4.5.0",
|
||||
"hash": "sha256-AFsKPb/nTk2/mqH/PYpaoI8PLsiKKimaXf+7Mb5VfPM="
|
||||
},
|
||||
{
|
||||
"pname": "System.Security.Cryptography.Pkcs",
|
||||
"version": "6.0.4",
|
||||
@@ -364,11 +359,6 @@
|
||||
"version": "4.4.0",
|
||||
"hash": "sha256-Ri53QmFX8I8UH0x4PikQ1ZA07ZSnBUXStd5rBfGWFOE="
|
||||
},
|
||||
{
|
||||
"pname": "System.Security.Principal.Windows",
|
||||
"version": "4.5.0",
|
||||
"hash": "sha256-BkUYNguz0e4NJp1kkW7aJBn3dyH9STwB5N8XqnlCsmY="
|
||||
},
|
||||
{
|
||||
"pname": "System.Text.Json",
|
||||
"version": "6.0.10",
|
||||
@@ -391,8 +381,8 @@
|
||||
},
|
||||
{
|
||||
"pname": "WoofWare.Expect",
|
||||
"version": "0.4.2",
|
||||
"hash": "sha256-CaVcj9Fo0VSMgfKIukM9WHGufPWHDqMO1D4VYVdJKJk="
|
||||
"version": "0.8.2",
|
||||
"hash": "sha256-iqt4FPkUr24/4dnRfh7P5nPNNlaPzaItP6/yrGRrQyo="
|
||||
},
|
||||
{
|
||||
"pname": "WoofWare.Whippet.Fantomas",
|
||||
|
Reference in New Issue
Block a user