mirror of
https://github.com/Smaug123/WoofWare.Myriad
synced 2025-12-14 21:05:39 +00:00
Compare commits
1 Commits
WoofWare.M
...
dependabot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
17e9faae5b |
@@ -9,16 +9,10 @@
|
||||
]
|
||||
},
|
||||
"fsharp-analyzers": {
|
||||
"version": "0.34.1",
|
||||
"version": "0.32.1",
|
||||
"commands": [
|
||||
"fsharp-analyzers"
|
||||
]
|
||||
},
|
||||
"woofware.nunittestrunner": {
|
||||
"version": "0.3.9",
|
||||
"commands": [
|
||||
"woofware.nunittestrunner"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
60
.github/workflows/dotnet.yaml
vendored
60
.github/workflows/dotnet.yaml
vendored
@@ -25,7 +25,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v4
|
||||
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@v6
|
||||
uses: actions/checkout@v4
|
||||
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@v6
|
||||
uses: actions/checkout@v4
|
||||
- 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@v6
|
||||
uses: actions/checkout@v4
|
||||
- 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@v6
|
||||
uses: actions/checkout@v4
|
||||
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@v6
|
||||
uses: actions/checkout@v4
|
||||
- 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@v6
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0 # so that NerdBank.GitVersioning has access to history
|
||||
- name: Install Nix
|
||||
@@ -167,12 +167,12 @@ jobs:
|
||||
- name: Pack
|
||||
run: nix develop --command dotnet pack --configuration Release
|
||||
- name: Upload NuGet artifact (plugin)
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: nuget-package-plugin
|
||||
path: WoofWare.Myriad.Plugins/bin/Release/WoofWare.Myriad.Plugins.*.nupkg
|
||||
- name: Upload NuGet artifact (attributes)
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: nuget-package-attribute
|
||||
path: WoofWare.Myriad.Plugins.Attributes/bin/Release/WoofWare.Myriad.Plugins.Attributes.*.nupkg
|
||||
@@ -182,7 +182,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Download NuGet artifact (plugin)
|
||||
uses: actions/download-artifact@v6
|
||||
uses: actions/download-artifact@v4
|
||||
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@v6
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: nuget-package-attribute
|
||||
path: packed-attribute
|
||||
@@ -207,9 +207,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [nuget-pack]
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v4
|
||||
- name: Download NuGet artifact
|
||||
uses: actions/download-artifact@v6
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.artifact }}
|
||||
- name: Compute package path
|
||||
@@ -249,12 +249,12 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: Download NuGet artifact
|
||||
uses: actions/download-artifact@v6
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: nuget-package-attribute
|
||||
path: packed
|
||||
- name: Attest Build Provenance
|
||||
uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3.0.0
|
||||
uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2.4.0
|
||||
with:
|
||||
subject-path: "packed/*.nupkg"
|
||||
|
||||
@@ -268,12 +268,12 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: Download NuGet artifact
|
||||
uses: actions/download-artifact@v6
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: nuget-package-plugin
|
||||
path: packed
|
||||
- name: Attest Build Provenance
|
||||
uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3.0.0
|
||||
uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2.4.0
|
||||
with:
|
||||
subject-path: "packed/*.nupkg"
|
||||
|
||||
@@ -287,31 +287,26 @@ jobs:
|
||||
attestations: write
|
||||
contents: read
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v4
|
||||
- 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@v6
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: nuget-package-attribute
|
||||
path: packed
|
||||
- name: Identify `dotnet`
|
||||
id: dotnet-identify
|
||||
run: nix develop --command bash -c 'echo "dotnet=$(which dotnet)" >> $GITHUB_OUTPUT'
|
||||
- name: Obtain NuGet key
|
||||
uses: NuGet/login@d22cc5f58ff5b88bf9bd452535b4335137e24544
|
||||
id: login
|
||||
with:
|
||||
user: ${{ secrets.NUGET_USER }}
|
||||
- name: Publish to NuGet
|
||||
id: publish-success
|
||||
uses: G-Research/common-actions/publish-nuget@2b7dc49cb14f3344fbe6019c14a31165e258c059
|
||||
with:
|
||||
package-name: WoofWare.Myriad.Plugins.Attributes
|
||||
nuget-key: ${{ steps.login.outputs.NUGET_API_KEY }}
|
||||
nuget-key: ${{ secrets.NUGET_API_KEY }}
|
||||
nupkg-dir: packed/
|
||||
dotnet: ${{ steps.dotnet-identify.outputs.dotnet }}
|
||||
|
||||
@@ -325,31 +320,26 @@ jobs:
|
||||
attestations: write
|
||||
contents: read
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v4
|
||||
- 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@v6
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: nuget-package-plugin
|
||||
path: packed
|
||||
- name: Identify `dotnet`
|
||||
id: dotnet-identify
|
||||
run: nix develop --command bash -c 'echo "dotnet=$(which dotnet)" >> $GITHUB_OUTPUT'
|
||||
- name: Obtain NuGet key
|
||||
uses: NuGet/login@d22cc5f58ff5b88bf9bd452535b4335137e24544
|
||||
id: login
|
||||
with:
|
||||
user: ${{ secrets.NUGET_USER }}
|
||||
- name: Publish to NuGet
|
||||
id: publish-success
|
||||
uses: G-Research/common-actions/publish-nuget@2b7dc49cb14f3344fbe6019c14a31165e258c059
|
||||
with:
|
||||
package-name: WoofWare.Myriad.Plugins
|
||||
nuget-key: ${{ steps.login.outputs.NUGET_API_KEY }}
|
||||
nuget-key: ${{ secrets.NUGET_API_KEY }}
|
||||
nupkg-dir: packed/
|
||||
dotnet: ${{ steps.dotnet-identify.outputs.dotnet }}
|
||||
|
||||
@@ -366,9 +356,9 @@ jobs:
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v4
|
||||
- name: Download NuGet artifact
|
||||
uses: actions/download-artifact@v6
|
||||
uses: actions/download-artifact@v4
|
||||
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@v6
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Nix
|
||||
uses: DeterminateSystems/nix-installer-action@main
|
||||
|
||||
15
CHANGELOG.md
15
CHANGELOG.md
@@ -1,20 +1,5 @@
|
||||
Notable changes are recorded here.
|
||||
|
||||
# WoofWare.Myriad.Plugins 9.1.1, WoofWare.Myriad.Plugins.Attributes 3.8.1
|
||||
|
||||
Adds the `[<ArgumentNegateWithPrefix>]` attribute, which can be placed on a boolean or flag-valued field when using the `ArgParser` generator.
|
||||
This causes the boolean to be specifiable with the `--no-` prefix to negate its value.
|
||||
(For example, `Foo : bool` is normally specified as `--foo`; this new attribute lets the user additionally give `--no-foo` to get the same semantics as `--foo=false`.)
|
||||
|
||||
# WoofWare.Myriad.Plugins 9.0.1
|
||||
|
||||
Converts the `static member Empty` field on each generated mock (from `GeneratedMock`) into a function, so as to permit the `GeneratedCapturingMock` to have the same signature.
|
||||
(`GeneratedCapturingMock` contains mutable state, so must be created afresh each time.)
|
||||
|
||||
# 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.
|
||||
|
||||
@@ -44,7 +44,7 @@ git config blame.ignoreRevsFile .git-blame-ignore-revs
|
||||
## Dependencies
|
||||
|
||||
I try to keep this repository's dependencies as few as possible, because (for example) any consumer of the source generator will also consume this project via the attributes.
|
||||
When adding dependencies, you will need to `nix run .#fetchDeps` to obtain a new copy of [the dependency lockfile](./nix/deps.json).
|
||||
When adding dependencies, you will need to `nix run .#fetchDeps` to obtain a new copy of [the dependency lockfile](./nix/deps.nix).
|
||||
|
||||
## Branch strategy
|
||||
|
||||
|
||||
@@ -1,124 +0,0 @@
|
||||
namespace ConsumePlugin
|
||||
|
||||
open WoofWare.Myriad.Plugins
|
||||
|
||||
// This file contains test cases for conflict detection in the ArgParser generator.
|
||||
// These are expected to FAIL at build time with appropriate error messages.
|
||||
// Uncomment each section one at a time to test the specific conflict detection.
|
||||
|
||||
// ============================================================================
|
||||
// Test 1: Field named NoFooBar conflicts with FooBar's --no- variant
|
||||
// ============================================================================
|
||||
// Expected error: Argument name conflict: '--no-foo-bar' collides with the --no- variant
|
||||
// of field 'FooBar' (which has [<ArgumentNegateWithPrefix>])
|
||||
|
||||
(*
|
||||
[<ArgParser>]
|
||||
type ConflictingFieldNames =
|
||||
{
|
||||
[<ArgumentNegateWithPrefix>]
|
||||
FooBar : bool
|
||||
NoFooBar : bool
|
||||
}
|
||||
*)
|
||||
|
||||
// ============================================================================
|
||||
// Test 2: ArgumentLongForm "no-foo" conflicts with Foo's --no- variant
|
||||
// ============================================================================
|
||||
// Expected error: Argument name conflict: '--no-foo' collides with the --no- variant
|
||||
// of field 'Foo' (which has [<ArgumentNegateWithPrefix>])
|
||||
|
||||
(*
|
||||
[<ArgParser>]
|
||||
type ConflictingLongForm =
|
||||
{
|
||||
[<ArgumentNegateWithPrefix>]
|
||||
Foo : bool
|
||||
[<ArgumentLongForm "no-foo">]
|
||||
Bar : bool
|
||||
}
|
||||
*)
|
||||
|
||||
// ============================================================================
|
||||
// Test 3: Multiple ArgumentLongForm, one conflicts
|
||||
// ============================================================================
|
||||
// Expected error: Argument name conflict: '--no-verbose' collides with...
|
||||
|
||||
(*
|
||||
[<ArgParser>]
|
||||
type ConflictingMultipleLongForms =
|
||||
{
|
||||
[<ArgumentLongForm "verbose">]
|
||||
[<ArgumentLongForm "v">]
|
||||
[<ArgumentNegateWithPrefix>]
|
||||
VerboseMode : bool
|
||||
|
||||
[<ArgumentLongForm "no-verbose">]
|
||||
Quiet : bool
|
||||
}
|
||||
*)
|
||||
|
||||
// ============================================================================
|
||||
// Test 4: ArgumentNegateWithPrefix on non-boolean field
|
||||
// ============================================================================
|
||||
// Expected error: [<ArgumentNegateWithPrefix>] can only be applied to boolean
|
||||
// or flag DU fields, but was applied to field NotABool of type string
|
||||
|
||||
(*
|
||||
[<ArgParser>]
|
||||
type InvalidAttributeOnNonBool =
|
||||
{
|
||||
[<ArgumentNegateWithPrefix>]
|
||||
NotABool : string
|
||||
}
|
||||
*)
|
||||
|
||||
// ============================================================================
|
||||
// Test 5: ArgumentNegateWithPrefix on non-flag int field
|
||||
// ============================================================================
|
||||
// Expected error: [<ArgumentNegateWithPrefix>] can only be applied to boolean
|
||||
// or flag DU fields
|
||||
|
||||
(*
|
||||
[<ArgParser>]
|
||||
type InvalidAttributeOnInt =
|
||||
{
|
||||
[<ArgumentNegateWithPrefix>]
|
||||
NotAFlag : int
|
||||
}
|
||||
*)
|
||||
|
||||
// ============================================================================
|
||||
// Test 6: Complex conflict with custom names
|
||||
// ============================================================================
|
||||
// This tests a more complex scenario where a custom ArgumentLongForm creates
|
||||
// a conflict with a different field's negated form
|
||||
|
||||
(*
|
||||
[<ArgParser>]
|
||||
type ComplexConflict =
|
||||
{
|
||||
[<ArgumentLongForm "enable">]
|
||||
[<ArgumentNegateWithPrefix>]
|
||||
FeatureA : bool
|
||||
|
||||
[<ArgumentLongForm "no-enable">]
|
||||
DisableAll : bool
|
||||
}
|
||||
*)
|
||||
|
||||
// ============================================================================
|
||||
// Test 7: Valid usage - no conflicts (this SHOULD compile)
|
||||
// ============================================================================
|
||||
|
||||
[<ArgParser>]
|
||||
type NoConflict =
|
||||
{
|
||||
[<ArgumentNegateWithPrefix>]
|
||||
EnableFeature : bool
|
||||
|
||||
[<ArgumentNegateWithPrefix>]
|
||||
VerboseMode : bool
|
||||
|
||||
NormalField : string
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
namespace ConsumePlugin
|
||||
|
||||
open WoofWare.Myriad.Plugins
|
||||
|
||||
// Test types for ArgumentNegateWithPrefix functionality
|
||||
|
||||
type TestDryRunMode =
|
||||
| [<ArgumentFlag false>] Wet
|
||||
| [<ArgumentFlag true>] Dry
|
||||
|
||||
[<ArgParser true>]
|
||||
type BoolNegation =
|
||||
{
|
||||
[<ArgumentNegateWithPrefix>]
|
||||
EnableFeature : bool
|
||||
}
|
||||
|
||||
[<ArgParser true>]
|
||||
type FlagNegation =
|
||||
{
|
||||
[<ArgumentNegateWithPrefix>]
|
||||
DryRun : TestDryRunMode
|
||||
}
|
||||
|
||||
[<ArgParser true>]
|
||||
type MultipleFormsNegation =
|
||||
{
|
||||
[<ArgumentLongForm "verbose">]
|
||||
[<ArgumentLongForm "v">]
|
||||
[<ArgumentNegateWithPrefix>]
|
||||
VerboseMode : bool
|
||||
}
|
||||
|
||||
[<ArgParser true>]
|
||||
type CombinedFeatures =
|
||||
{
|
||||
[<ArgumentNegateWithPrefix>]
|
||||
[<ArgumentDefaultFunction>]
|
||||
Verbose : Choice<bool, bool>
|
||||
|
||||
[<ArgumentNegateWithPrefix>]
|
||||
[<ArgumentHelpText "Enable debug mode">]
|
||||
Debug : bool
|
||||
|
||||
NormalBool : bool
|
||||
}
|
||||
|
||||
static member DefaultVerbose () = false
|
||||
@@ -235,27 +235,3 @@ type FlagsIntoPositionalArgs' =
|
||||
[<PositionalArgs false>]
|
||||
DontGrabEverything : string list
|
||||
}
|
||||
|
||||
[<ArgParser>]
|
||||
[<ArgumentHelpText "Parse command-line arguments for a basic configuration. This help text appears before the argument list.">]
|
||||
type WithTypeHelp =
|
||||
{
|
||||
[<ArgumentHelpText "The configuration file path">]
|
||||
ConfigFile : string
|
||||
[<ArgumentHelpText "Enable verbose output">]
|
||||
Verbose : bool
|
||||
Port : int
|
||||
}
|
||||
|
||||
[<ArgParser>]
|
||||
[<ArgumentHelpText "This is a multiline help text example.
|
||||
It spans multiple lines to test that multiline strings work correctly.
|
||||
You can use this to provide detailed documentation for your argument parser.">]
|
||||
type WithMultilineTypeHelp =
|
||||
{
|
||||
[<ArgumentHelpText "Input file to process">]
|
||||
InputFile : string
|
||||
[<ArgumentHelpText "Output directory">]
|
||||
OutputDir : string
|
||||
Force : bool
|
||||
}
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
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
|
||||
|
||||
[<GenerateCapturingMock>]
|
||||
type TypeWithAsyncDisposable =
|
||||
inherit IAsyncDisposable
|
||||
abstract Mem1 : string option -> string[] Async
|
||||
abstract Mem2 : unit -> string[] Async
|
||||
|
||||
[<GenerateCapturingMock>]
|
||||
type TypeWithBothDisposables =
|
||||
inherit IDisposable
|
||||
inherit IAsyncDisposable
|
||||
abstract Mem1 : string -> int
|
||||
@@ -1,41 +0,0 @@
|
||||
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
|
||||
@@ -1,19 +0,0 @@
|
||||
namespace ConsumePluginNoAttr
|
||||
|
||||
type ConstNoAttr<'a> =
|
||||
| Verbatim of 'a
|
||||
| String of string
|
||||
|
||||
type PairOpKindNoAttr =
|
||||
| NormalSeq
|
||||
| ThenDoSeq
|
||||
|
||||
type TreeNoAttr<'a, 'b> =
|
||||
| Const of ConstNoAttr<'a> * 'b
|
||||
| Pair of TreeNoAttr<'a, 'b> * TreeNoAttr<'a, 'b> * PairOpKindNoAttr
|
||||
| Sequential of TreeNoAttr<'a, 'b> list
|
||||
| Builder of TreeNoAttr<'a, 'b> * TreeBuilderNoAttr<'b, 'a>
|
||||
|
||||
and TreeBuilderNoAttr<'b, 'a> =
|
||||
| Child of TreeBuilderNoAttr<'b, 'a>
|
||||
| Parent of TreeNoAttr<'a, 'b>
|
||||
@@ -33,10 +33,6 @@
|
||||
<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>
|
||||
@@ -51,20 +47,6 @@
|
||||
<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>
|
||||
@@ -77,13 +59,6 @@
|
||||
<Compile Include="GeneratedCatamorphism.fs">
|
||||
<MyriadFile>Catamorphism.fs</MyriadFile>
|
||||
</Compile>
|
||||
<Compile Include="CatamorphismNoAttribute.fs" />
|
||||
<Compile Include="GeneratedCatamorphismNoAttribute.fs">
|
||||
<MyriadFile>CatamorphismNoAttribute.fs</MyriadFile>
|
||||
<MyriadParams>
|
||||
<TreeNoAttr>CreateCatamorphism(TreeNoAttrCata)</TreeNoAttr>
|
||||
</MyriadParams>
|
||||
</Compile>
|
||||
<Compile Include="FSharpForFunAndProfitCata.fs" />
|
||||
<Compile Include="GeneratedFileSystem.fs">
|
||||
<MyriadFile>FSharpForFunAndProfitCata.fs</MyriadFile>
|
||||
@@ -96,17 +71,6 @@
|
||||
<Compile Include="GeneratedArgs.fs">
|
||||
<MyriadFile>Args.fs</MyriadFile>
|
||||
</Compile>
|
||||
<Compile Include="ArgParserNegationTests.fs" />
|
||||
<Compile Include="GeneratedArgParserNegationTests.fs">
|
||||
<MyriadFile>ArgParserNegationTests.fs</MyriadFile>
|
||||
</Compile>
|
||||
<!-- Not compiled, because by design they *don't* compile. That makes them very hard to test in an automated way! -->
|
||||
<None Include="ArgParserConflictTests.fs" />
|
||||
<!-- To run the conflict tests:
|
||||
<Compile Include="GeneratedArgParserConflictTests.fs">
|
||||
<MyriadFile>ArgParserConflictTests.fs</MyriadFile>
|
||||
</Compile>
|
||||
-->
|
||||
<None Include="swagger-gitea.json" />
|
||||
<Compile Include="GeneratedSwaggerGitea.fs">
|
||||
<MyriadFile>swagger-gitea.json</MyriadFile>
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
namespace Gitea
|
||||
|
||||
open WoofWare.Myriad.Plugins
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,6 @@
|
||||
|
||||
|
||||
|
||||
|
||||
namespace ConsumePlugin
|
||||
|
||||
open System
|
||||
@@ -4346,438 +4345,3 @@ module FlagsIntoPositionalArgs'ArgParse =
|
||||
|
||||
static member parse (args : string list) : FlagsIntoPositionalArgs' =
|
||||
FlagsIntoPositionalArgs'.parse' (System.Environment.GetEnvironmentVariable >> Option.ofObj) args
|
||||
namespace ConsumePlugin
|
||||
|
||||
open System
|
||||
open System.IO
|
||||
open WoofWare.Myriad.Plugins
|
||||
|
||||
/// Methods to parse arguments for the type WithTypeHelp
|
||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
module WithTypeHelp =
|
||||
type private ParseState_WithTypeHelp =
|
||||
/// Ready to consume a key or positional arg
|
||||
| AwaitingKey
|
||||
/// Waiting to receive a value for the key we've already consumed
|
||||
| AwaitingValue of key : string
|
||||
|
||||
let parse' (getEnvironmentVariable : string -> string option) (args : string list) : WithTypeHelp =
|
||||
let ArgParser_errors = ResizeArray ()
|
||||
|
||||
let helpText () =
|
||||
[
|
||||
"Parse command-line arguments for a basic configuration. This help text appears before the argument list."
|
||||
""
|
||||
|
||||
(sprintf
|
||||
"%s string%s%s"
|
||||
(sprintf "--%s" "config-file")
|
||||
""
|
||||
(sprintf " : %s" ("The configuration file path")))
|
||||
|
||||
(sprintf "%s bool%s%s" (sprintf "--%s" "verbose") "" (sprintf " : %s" ("Enable verbose output")))
|
||||
(sprintf "%s int32%s%s" (sprintf "--%s" "port") "" "")
|
||||
]
|
||||
|> String.concat "\n"
|
||||
|
||||
let parser_LeftoverArgs : string ResizeArray = ResizeArray ()
|
||||
let mutable arg_0 : string option = None
|
||||
let mutable arg_1 : bool option = None
|
||||
let mutable arg_2 : int option = None
|
||||
|
||||
/// Processes the key-value pair, returning Error if no key was matched.
|
||||
/// If the key is an arg which can have arity 1, but throws when consuming that arg, we return Error(<the message>).
|
||||
/// This can nevertheless be a successful parse, e.g. when the key may have arity 0.
|
||||
let processKeyValue (key : string) (value : string) : Result<unit, string option> =
|
||||
if System.String.Equals (key, sprintf "--%s" "port", System.StringComparison.OrdinalIgnoreCase) then
|
||||
match arg_2 with
|
||||
| Some x ->
|
||||
sprintf
|
||||
"Argument '%s' was supplied multiple times: %s and %s"
|
||||
(sprintf "--%s" "port")
|
||||
(x.ToString ())
|
||||
(value.ToString ())
|
||||
|> ArgParser_errors.Add
|
||||
|
||||
Ok ()
|
||||
| None ->
|
||||
try
|
||||
arg_2 <- value |> (fun x -> System.Int32.Parse x) |> Some
|
||||
Ok ()
|
||||
with _ as exc ->
|
||||
exc.Message |> Some |> Error
|
||||
else if System.String.Equals (key, sprintf "--%s" "verbose", System.StringComparison.OrdinalIgnoreCase) then
|
||||
match arg_1 with
|
||||
| Some x ->
|
||||
sprintf
|
||||
"Argument '%s' was supplied multiple times: %s and %s"
|
||||
(sprintf "--%s" "verbose")
|
||||
(x.ToString ())
|
||||
(value.ToString ())
|
||||
|> ArgParser_errors.Add
|
||||
|
||||
Ok ()
|
||||
| None ->
|
||||
try
|
||||
arg_1 <- value |> (fun x -> System.Boolean.Parse x) |> Some
|
||||
Ok ()
|
||||
with _ as exc ->
|
||||
exc.Message |> Some |> Error
|
||||
else if
|
||||
System.String.Equals (key, sprintf "--%s" "config-file", System.StringComparison.OrdinalIgnoreCase)
|
||||
then
|
||||
match arg_0 with
|
||||
| Some x ->
|
||||
sprintf
|
||||
"Argument '%s' was supplied multiple times: %s and %s"
|
||||
(sprintf "--%s" "config-file")
|
||||
(x.ToString ())
|
||||
(value.ToString ())
|
||||
|> ArgParser_errors.Add
|
||||
|
||||
Ok ()
|
||||
| None ->
|
||||
try
|
||||
arg_0 <- value |> (fun x -> x) |> Some
|
||||
Ok ()
|
||||
with _ as exc ->
|
||||
exc.Message |> Some |> Error
|
||||
else
|
||||
Error None
|
||||
|
||||
/// Returns false if we didn't set a value.
|
||||
let setFlagValue (key : string) : bool =
|
||||
if System.String.Equals (key, sprintf "--%s" "verbose", System.StringComparison.OrdinalIgnoreCase) then
|
||||
match arg_1 with
|
||||
| Some x ->
|
||||
sprintf "Flag '%s' was supplied multiple times" (sprintf "--%s" "verbose")
|
||||
|> ArgParser_errors.Add
|
||||
|
||||
true
|
||||
| None ->
|
||||
arg_1 <- true |> Some
|
||||
true
|
||||
else
|
||||
false
|
||||
|
||||
let rec go (state : ParseState_WithTypeHelp) (args : string list) =
|
||||
match args with
|
||||
| [] ->
|
||||
match state with
|
||||
| ParseState_WithTypeHelp.AwaitingKey -> ()
|
||||
| ParseState_WithTypeHelp.AwaitingValue key ->
|
||||
if setFlagValue key then
|
||||
()
|
||||
else
|
||||
sprintf
|
||||
"Trailing argument %s had no value. Use a double-dash to separate positional args from key-value args."
|
||||
key
|
||||
|> ArgParser_errors.Add
|
||||
| "--" :: rest -> parser_LeftoverArgs.AddRange (rest |> Seq.map (fun x -> x))
|
||||
| arg :: args ->
|
||||
match state with
|
||||
| ParseState_WithTypeHelp.AwaitingKey ->
|
||||
if arg.StartsWith ("--", System.StringComparison.Ordinal) then
|
||||
if arg = "--help" then
|
||||
helpText () |> failwithf "Help text requested.\n%s"
|
||||
else
|
||||
let equals = arg.IndexOf (char 61)
|
||||
|
||||
if equals < 0 then
|
||||
args |> go (ParseState_WithTypeHelp.AwaitingValue arg)
|
||||
else
|
||||
let key = arg.[0 .. equals - 1]
|
||||
let value = arg.[equals + 1 ..]
|
||||
|
||||
match processKeyValue key value with
|
||||
| Ok () -> go ParseState_WithTypeHelp.AwaitingKey args
|
||||
| Error x ->
|
||||
match x with
|
||||
| None ->
|
||||
failwithf "Unable to process argument %s as key %s and value %s" arg key value
|
||||
| Some msg ->
|
||||
sprintf "%s (at arg %s)" msg arg |> ArgParser_errors.Add
|
||||
go ParseState_WithTypeHelp.AwaitingKey args
|
||||
else
|
||||
arg |> (fun x -> x) |> parser_LeftoverArgs.Add
|
||||
go ParseState_WithTypeHelp.AwaitingKey args
|
||||
| ParseState_WithTypeHelp.AwaitingValue key ->
|
||||
match processKeyValue key arg with
|
||||
| Ok () -> go ParseState_WithTypeHelp.AwaitingKey args
|
||||
| Error exc ->
|
||||
if setFlagValue key then
|
||||
go ParseState_WithTypeHelp.AwaitingKey (arg :: args)
|
||||
else
|
||||
match exc with
|
||||
| None ->
|
||||
failwithf "Unable to process supplied arg %s. Help text follows.\n%s" key (helpText ())
|
||||
| Some msg -> msg |> ArgParser_errors.Add
|
||||
|
||||
go ParseState_WithTypeHelp.AwaitingKey args
|
||||
|
||||
let parser_LeftoverArgs =
|
||||
if 0 = parser_LeftoverArgs.Count then
|
||||
()
|
||||
else
|
||||
parser_LeftoverArgs
|
||||
|> String.concat " "
|
||||
|> sprintf "There were leftover args: %s"
|
||||
|> ArgParser_errors.Add
|
||||
|
||||
Unchecked.defaultof<_>
|
||||
|
||||
let arg_0 =
|
||||
match arg_0 with
|
||||
| None ->
|
||||
sprintf "Required argument '%s' received no value" (sprintf "--%s" "config-file")
|
||||
|> ArgParser_errors.Add
|
||||
|
||||
Unchecked.defaultof<_>
|
||||
| Some x -> x
|
||||
|
||||
let arg_1 =
|
||||
match arg_1 with
|
||||
| None ->
|
||||
sprintf "Required argument '%s' received no value" (sprintf "--%s" "verbose")
|
||||
|> ArgParser_errors.Add
|
||||
|
||||
Unchecked.defaultof<_>
|
||||
| Some x -> x
|
||||
|
||||
let arg_2 =
|
||||
match arg_2 with
|
||||
| None ->
|
||||
sprintf "Required argument '%s' received no value" (sprintf "--%s" "port")
|
||||
|> ArgParser_errors.Add
|
||||
|
||||
Unchecked.defaultof<_>
|
||||
| Some x -> x
|
||||
|
||||
if 0 = ArgParser_errors.Count then
|
||||
{
|
||||
ConfigFile = arg_0
|
||||
Port = arg_2
|
||||
Verbose = arg_1
|
||||
}
|
||||
else
|
||||
ArgParser_errors |> String.concat "\n" |> failwithf "Errors during parse!\n%s"
|
||||
|
||||
let parse (args : string list) : WithTypeHelp =
|
||||
parse' (System.Environment.GetEnvironmentVariable >> Option.ofObj) args
|
||||
namespace ConsumePlugin
|
||||
|
||||
open System
|
||||
open System.IO
|
||||
open WoofWare.Myriad.Plugins
|
||||
|
||||
/// Methods to parse arguments for the type WithMultilineTypeHelp
|
||||
[<RequireQualifiedAccess ; CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
module WithMultilineTypeHelp =
|
||||
type private ParseState_WithMultilineTypeHelp =
|
||||
/// Ready to consume a key or positional arg
|
||||
| AwaitingKey
|
||||
/// Waiting to receive a value for the key we've already consumed
|
||||
| AwaitingValue of key : string
|
||||
|
||||
let parse' (getEnvironmentVariable : string -> string option) (args : string list) : WithMultilineTypeHelp =
|
||||
let ArgParser_errors = ResizeArray ()
|
||||
|
||||
let helpText () =
|
||||
[
|
||||
"This is a multiline help text example.
|
||||
It spans multiple lines to test that multiline strings work correctly.
|
||||
You can use this to provide detailed documentation for your argument parser."
|
||||
|
||||
""
|
||||
(sprintf "%s string%s%s" (sprintf "--%s" "input-file") "" (sprintf " : %s" ("Input file to process")))
|
||||
(sprintf "%s string%s%s" (sprintf "--%s" "output-dir") "" (sprintf " : %s" ("Output directory")))
|
||||
(sprintf "%s bool%s%s" (sprintf "--%s" "force") "" "")
|
||||
]
|
||||
|> String.concat "\n"
|
||||
|
||||
let parser_LeftoverArgs : string ResizeArray = ResizeArray ()
|
||||
let mutable arg_0 : string option = None
|
||||
let mutable arg_1 : string option = None
|
||||
let mutable arg_2 : bool option = None
|
||||
|
||||
/// Processes the key-value pair, returning Error if no key was matched.
|
||||
/// If the key is an arg which can have arity 1, but throws when consuming that arg, we return Error(<the message>).
|
||||
/// This can nevertheless be a successful parse, e.g. when the key may have arity 0.
|
||||
let processKeyValue (key : string) (value : string) : Result<unit, string option> =
|
||||
if System.String.Equals (key, sprintf "--%s" "force", System.StringComparison.OrdinalIgnoreCase) then
|
||||
match arg_2 with
|
||||
| Some x ->
|
||||
sprintf
|
||||
"Argument '%s' was supplied multiple times: %s and %s"
|
||||
(sprintf "--%s" "force")
|
||||
(x.ToString ())
|
||||
(value.ToString ())
|
||||
|> ArgParser_errors.Add
|
||||
|
||||
Ok ()
|
||||
| None ->
|
||||
try
|
||||
arg_2 <- value |> (fun x -> System.Boolean.Parse x) |> Some
|
||||
Ok ()
|
||||
with _ as exc ->
|
||||
exc.Message |> Some |> Error
|
||||
else if
|
||||
System.String.Equals (key, sprintf "--%s" "output-dir", System.StringComparison.OrdinalIgnoreCase)
|
||||
then
|
||||
match arg_1 with
|
||||
| Some x ->
|
||||
sprintf
|
||||
"Argument '%s' was supplied multiple times: %s and %s"
|
||||
(sprintf "--%s" "output-dir")
|
||||
(x.ToString ())
|
||||
(value.ToString ())
|
||||
|> ArgParser_errors.Add
|
||||
|
||||
Ok ()
|
||||
| None ->
|
||||
try
|
||||
arg_1 <- value |> (fun x -> x) |> Some
|
||||
Ok ()
|
||||
with _ as exc ->
|
||||
exc.Message |> Some |> Error
|
||||
else if
|
||||
System.String.Equals (key, sprintf "--%s" "input-file", System.StringComparison.OrdinalIgnoreCase)
|
||||
then
|
||||
match arg_0 with
|
||||
| Some x ->
|
||||
sprintf
|
||||
"Argument '%s' was supplied multiple times: %s and %s"
|
||||
(sprintf "--%s" "input-file")
|
||||
(x.ToString ())
|
||||
(value.ToString ())
|
||||
|> ArgParser_errors.Add
|
||||
|
||||
Ok ()
|
||||
| None ->
|
||||
try
|
||||
arg_0 <- value |> (fun x -> x) |> Some
|
||||
Ok ()
|
||||
with _ as exc ->
|
||||
exc.Message |> Some |> Error
|
||||
else
|
||||
Error None
|
||||
|
||||
/// Returns false if we didn't set a value.
|
||||
let setFlagValue (key : string) : bool =
|
||||
if System.String.Equals (key, sprintf "--%s" "force", System.StringComparison.OrdinalIgnoreCase) then
|
||||
match arg_2 with
|
||||
| Some x ->
|
||||
sprintf "Flag '%s' was supplied multiple times" (sprintf "--%s" "force")
|
||||
|> ArgParser_errors.Add
|
||||
|
||||
true
|
||||
| None ->
|
||||
arg_2 <- true |> Some
|
||||
true
|
||||
else
|
||||
false
|
||||
|
||||
let rec go (state : ParseState_WithMultilineTypeHelp) (args : string list) =
|
||||
match args with
|
||||
| [] ->
|
||||
match state with
|
||||
| ParseState_WithMultilineTypeHelp.AwaitingKey -> ()
|
||||
| ParseState_WithMultilineTypeHelp.AwaitingValue key ->
|
||||
if setFlagValue key then
|
||||
()
|
||||
else
|
||||
sprintf
|
||||
"Trailing argument %s had no value. Use a double-dash to separate positional args from key-value args."
|
||||
key
|
||||
|> ArgParser_errors.Add
|
||||
| "--" :: rest -> parser_LeftoverArgs.AddRange (rest |> Seq.map (fun x -> x))
|
||||
| arg :: args ->
|
||||
match state with
|
||||
| ParseState_WithMultilineTypeHelp.AwaitingKey ->
|
||||
if arg.StartsWith ("--", System.StringComparison.Ordinal) then
|
||||
if arg = "--help" then
|
||||
helpText () |> failwithf "Help text requested.\n%s"
|
||||
else
|
||||
let equals = arg.IndexOf (char 61)
|
||||
|
||||
if equals < 0 then
|
||||
args |> go (ParseState_WithMultilineTypeHelp.AwaitingValue arg)
|
||||
else
|
||||
let key = arg.[0 .. equals - 1]
|
||||
let value = arg.[equals + 1 ..]
|
||||
|
||||
match processKeyValue key value with
|
||||
| Ok () -> go ParseState_WithMultilineTypeHelp.AwaitingKey args
|
||||
| Error x ->
|
||||
match x with
|
||||
| None ->
|
||||
failwithf "Unable to process argument %s as key %s and value %s" arg key value
|
||||
| Some msg ->
|
||||
sprintf "%s (at arg %s)" msg arg |> ArgParser_errors.Add
|
||||
go ParseState_WithMultilineTypeHelp.AwaitingKey args
|
||||
else
|
||||
arg |> (fun x -> x) |> parser_LeftoverArgs.Add
|
||||
go ParseState_WithMultilineTypeHelp.AwaitingKey args
|
||||
| ParseState_WithMultilineTypeHelp.AwaitingValue key ->
|
||||
match processKeyValue key arg with
|
||||
| Ok () -> go ParseState_WithMultilineTypeHelp.AwaitingKey args
|
||||
| Error exc ->
|
||||
if setFlagValue key then
|
||||
go ParseState_WithMultilineTypeHelp.AwaitingKey (arg :: args)
|
||||
else
|
||||
match exc with
|
||||
| None ->
|
||||
failwithf "Unable to process supplied arg %s. Help text follows.\n%s" key (helpText ())
|
||||
| Some msg -> msg |> ArgParser_errors.Add
|
||||
|
||||
go ParseState_WithMultilineTypeHelp.AwaitingKey args
|
||||
|
||||
let parser_LeftoverArgs =
|
||||
if 0 = parser_LeftoverArgs.Count then
|
||||
()
|
||||
else
|
||||
parser_LeftoverArgs
|
||||
|> String.concat " "
|
||||
|> sprintf "There were leftover args: %s"
|
||||
|> ArgParser_errors.Add
|
||||
|
||||
Unchecked.defaultof<_>
|
||||
|
||||
let arg_0 =
|
||||
match arg_0 with
|
||||
| None ->
|
||||
sprintf "Required argument '%s' received no value" (sprintf "--%s" "input-file")
|
||||
|> ArgParser_errors.Add
|
||||
|
||||
Unchecked.defaultof<_>
|
||||
| Some x -> x
|
||||
|
||||
let arg_1 =
|
||||
match arg_1 with
|
||||
| None ->
|
||||
sprintf "Required argument '%s' received no value" (sprintf "--%s" "output-dir")
|
||||
|> ArgParser_errors.Add
|
||||
|
||||
Unchecked.defaultof<_>
|
||||
| Some x -> x
|
||||
|
||||
let arg_2 =
|
||||
match arg_2 with
|
||||
| None ->
|
||||
sprintf "Required argument '%s' received no value" (sprintf "--%s" "force")
|
||||
|> ArgParser_errors.Add
|
||||
|
||||
Unchecked.defaultof<_>
|
||||
| Some x -> x
|
||||
|
||||
if 0 = ArgParser_errors.Count then
|
||||
{
|
||||
Force = arg_2
|
||||
InputFile = arg_0
|
||||
OutputDir = arg_1
|
||||
}
|
||||
else
|
||||
ArgParser_errors |> String.concat "\n" |> failwithf "Errors during parse!\n%s"
|
||||
|
||||
let parse (args : string list) : WithMultilineTypeHelp =
|
||||
parse' (System.Environment.GetEnvironmentVariable >> Option.ofObj) args
|
||||
|
||||
@@ -1,662 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 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
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal PublicTypeMockCalls =
|
||||
/// All the calls made to a PublicTypeMock mock
|
||||
type internal Calls =
|
||||
{
|
||||
Mem1 : ResizeArray<string * int>
|
||||
Mem2 : ResizeArray<string>
|
||||
Mem3 : ResizeArray<int * System.Threading.CancellationToken option>
|
||||
}
|
||||
|
||||
/// A fresh calls object which has not yet had any calls made.
|
||||
static member Empty () : Calls =
|
||||
{
|
||||
Mem1 = ResizeArray ()
|
||||
Mem2 = ResizeArray ()
|
||||
Mem3 = ResizeArray ()
|
||||
}
|
||||
|
||||
/// Mock record type for an interface
|
||||
type internal PublicTypeMock =
|
||||
{
|
||||
Calls : PublicTypeMockCalls.Calls
|
||||
Mem1 : string * int -> string list
|
||||
Mem2 : string -> int
|
||||
Mem3 : int * System.Threading.CancellationToken option -> string
|
||||
}
|
||||
|
||||
/// An implementation where every non-disposal method throws.
|
||||
static member Empty () : PublicTypeMock =
|
||||
{
|
||||
Calls = PublicTypeMockCalls.Calls.Empty ()
|
||||
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"))
|
||||
}
|
||||
|
||||
interface IPublicType with
|
||||
member this.Mem1 (arg_0_0, arg_0_1) =
|
||||
lock this.Calls.Mem1 (fun _ -> this.Calls.Mem1.Add (arg_0_0, arg_0_1))
|
||||
this.Mem1 (arg_0_0, arg_0_1)
|
||||
|
||||
member this.Mem2 arg_0_0 =
|
||||
lock this.Calls.Mem2 (fun _ -> this.Calls.Mem2.Add (arg_0_0))
|
||||
this.Mem2 (arg_0_0)
|
||||
|
||||
member this.Mem3 (arg_0_0, arg_0_1) =
|
||||
lock this.Calls.Mem3 (fun _ -> this.Calls.Mem3.Add (arg_0_0, arg_0_1))
|
||||
this.Mem3 (arg_0_0, arg_0_1)
|
||||
namespace SomeNamespace.CapturingMock
|
||||
|
||||
open System
|
||||
open WoofWare.Myriad.Plugins
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module public PublicTypeInternalFalseMockCalls =
|
||||
/// All the calls made to a PublicTypeInternalFalseMock mock
|
||||
type public Calls =
|
||||
{
|
||||
Mem1 : ResizeArray<string * int>
|
||||
Mem2 : ResizeArray<string>
|
||||
Mem3 : ResizeArray<int * System.Threading.CancellationToken option>
|
||||
}
|
||||
|
||||
/// A fresh calls object which has not yet had any calls made.
|
||||
static member Empty () : Calls =
|
||||
{
|
||||
Mem1 = ResizeArray ()
|
||||
Mem2 = ResizeArray ()
|
||||
Mem3 = ResizeArray ()
|
||||
}
|
||||
|
||||
/// Mock record type for an interface
|
||||
type public PublicTypeInternalFalseMock =
|
||||
{
|
||||
Calls : PublicTypeInternalFalseMockCalls.Calls
|
||||
Mem1 : string * int -> string list
|
||||
Mem2 : string -> int
|
||||
Mem3 : int * System.Threading.CancellationToken option -> string
|
||||
}
|
||||
|
||||
/// An implementation where every non-disposal method throws.
|
||||
static member Empty () : PublicTypeInternalFalseMock =
|
||||
{
|
||||
Calls = PublicTypeInternalFalseMockCalls.Calls.Empty ()
|
||||
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"))
|
||||
}
|
||||
|
||||
interface IPublicTypeInternalFalse with
|
||||
member this.Mem1 (arg_0_0, arg_0_1) =
|
||||
lock this.Calls.Mem1 (fun _ -> this.Calls.Mem1.Add (arg_0_0, arg_0_1))
|
||||
this.Mem1 (arg_0_0, arg_0_1)
|
||||
|
||||
member this.Mem2 arg_0_0 =
|
||||
lock this.Calls.Mem2 (fun _ -> this.Calls.Mem2.Add (arg_0_0))
|
||||
this.Mem2 (arg_0_0)
|
||||
|
||||
member this.Mem3 (arg_0_0, arg_0_1) =
|
||||
lock this.Calls.Mem3 (fun _ -> this.Calls.Mem3.Add (arg_0_0, arg_0_1))
|
||||
this.Mem3 (arg_0_0, arg_0_1)
|
||||
namespace SomeNamespace.CapturingMock
|
||||
|
||||
open System
|
||||
open WoofWare.Myriad.Plugins
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal InternalTypeMockCalls =
|
||||
/// All the calls made to a InternalTypeMock mock
|
||||
type internal Calls =
|
||||
{
|
||||
Mem1 : ResizeArray<string * int>
|
||||
Mem2 : ResizeArray<string>
|
||||
}
|
||||
|
||||
/// A fresh calls object which has not yet had any calls made.
|
||||
static member Empty () : Calls =
|
||||
{
|
||||
Mem1 = ResizeArray ()
|
||||
Mem2 = ResizeArray ()
|
||||
}
|
||||
|
||||
/// Mock record type for an interface
|
||||
type internal InternalTypeMock =
|
||||
{
|
||||
Calls : InternalTypeMockCalls.Calls
|
||||
Mem1 : string * int -> unit
|
||||
Mem2 : string -> int
|
||||
}
|
||||
|
||||
/// An implementation where every non-disposal method throws.
|
||||
static member Empty () : InternalTypeMock =
|
||||
{
|
||||
Calls = InternalTypeMockCalls.Calls.Empty ()
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
|
||||
}
|
||||
|
||||
interface InternalType with
|
||||
member this.Mem1 (arg_0_0, arg_0_1) =
|
||||
lock this.Calls.Mem1 (fun _ -> this.Calls.Mem1.Add (arg_0_0, arg_0_1))
|
||||
this.Mem1 (arg_0_0, arg_0_1)
|
||||
|
||||
member this.Mem2 arg_0_0 =
|
||||
lock this.Calls.Mem2 (fun _ -> this.Calls.Mem2.Add (arg_0_0))
|
||||
this.Mem2 (arg_0_0)
|
||||
namespace SomeNamespace.CapturingMock
|
||||
|
||||
open System
|
||||
open WoofWare.Myriad.Plugins
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal PrivateTypeMockCalls =
|
||||
/// All the calls made to a PrivateTypeMock mock
|
||||
type internal Calls =
|
||||
{
|
||||
Mem1 : ResizeArray<string * int>
|
||||
Mem2 : ResizeArray<string>
|
||||
}
|
||||
|
||||
/// A fresh calls object which has not yet had any calls made.
|
||||
static member Empty () : Calls =
|
||||
{
|
||||
Mem1 = ResizeArray ()
|
||||
Mem2 = ResizeArray ()
|
||||
}
|
||||
|
||||
/// Mock record type for an interface
|
||||
type private PrivateTypeMock =
|
||||
{
|
||||
Calls : PrivateTypeMockCalls.Calls
|
||||
Mem1 : string * int -> unit
|
||||
Mem2 : string -> int
|
||||
}
|
||||
|
||||
/// An implementation where every non-disposal method throws.
|
||||
static member Empty () : PrivateTypeMock =
|
||||
{
|
||||
Calls = PrivateTypeMockCalls.Calls.Empty ()
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
|
||||
}
|
||||
|
||||
interface PrivateType with
|
||||
member this.Mem1 (arg_0_0, arg_0_1) =
|
||||
lock this.Calls.Mem1 (fun _ -> this.Calls.Mem1.Add (arg_0_0, arg_0_1))
|
||||
this.Mem1 (arg_0_0, arg_0_1)
|
||||
|
||||
member this.Mem2 arg_0_0 =
|
||||
lock this.Calls.Mem2 (fun _ -> this.Calls.Mem2.Add (arg_0_0))
|
||||
this.Mem2 (arg_0_0)
|
||||
namespace SomeNamespace.CapturingMock
|
||||
|
||||
open System
|
||||
open WoofWare.Myriad.Plugins
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal PrivateTypeInternalFalseMockCalls =
|
||||
/// All the calls made to a PrivateTypeInternalFalseMock mock
|
||||
type internal Calls =
|
||||
{
|
||||
Mem1 : ResizeArray<string * int>
|
||||
Mem2 : ResizeArray<string>
|
||||
}
|
||||
|
||||
/// A fresh calls object which has not yet had any calls made.
|
||||
static member Empty () : Calls =
|
||||
{
|
||||
Mem1 = ResizeArray ()
|
||||
Mem2 = ResizeArray ()
|
||||
}
|
||||
|
||||
/// Mock record type for an interface
|
||||
type private PrivateTypeInternalFalseMock =
|
||||
{
|
||||
Calls : PrivateTypeInternalFalseMockCalls.Calls
|
||||
Mem1 : string * int -> unit
|
||||
Mem2 : string -> int
|
||||
}
|
||||
|
||||
/// An implementation where every non-disposal method throws.
|
||||
static member Empty () : PrivateTypeInternalFalseMock =
|
||||
{
|
||||
Calls = PrivateTypeInternalFalseMockCalls.Calls.Empty ()
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
|
||||
}
|
||||
|
||||
interface PrivateTypeInternalFalse with
|
||||
member this.Mem1 (arg_0_0, arg_0_1) =
|
||||
lock this.Calls.Mem1 (fun _ -> this.Calls.Mem1.Add (arg_0_0, arg_0_1))
|
||||
this.Mem1 (arg_0_0, arg_0_1)
|
||||
|
||||
member this.Mem2 arg_0_0 =
|
||||
lock this.Calls.Mem2 (fun _ -> this.Calls.Mem2.Add (arg_0_0))
|
||||
this.Mem2 (arg_0_0)
|
||||
namespace SomeNamespace.CapturingMock
|
||||
|
||||
open System
|
||||
open WoofWare.Myriad.Plugins
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal VeryPublicTypeMockCalls =
|
||||
/// All the calls made to a VeryPublicTypeMock mock
|
||||
type internal Calls<'a, 'b> =
|
||||
{
|
||||
Mem1 : ResizeArray<'a>
|
||||
}
|
||||
|
||||
/// A fresh calls object which has not yet had any calls made.
|
||||
static member Empty () : Calls<'a, 'b> =
|
||||
{
|
||||
Mem1 = ResizeArray ()
|
||||
}
|
||||
|
||||
/// Mock record type for an interface
|
||||
type internal VeryPublicTypeMock<'a, 'b> =
|
||||
{
|
||||
Calls : VeryPublicTypeMockCalls.Calls<'a, 'b>
|
||||
Mem1 : 'a -> 'b
|
||||
}
|
||||
|
||||
/// An implementation where every non-disposal method throws.
|
||||
static member Empty () : VeryPublicTypeMock<'a, 'b> =
|
||||
{
|
||||
Calls = VeryPublicTypeMockCalls.Calls.Empty ()
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
}
|
||||
|
||||
interface VeryPublicType<'a, 'b> with
|
||||
member this.Mem1 arg_0_0 =
|
||||
lock this.Calls.Mem1 (fun _ -> this.Calls.Mem1.Add (arg_0_0))
|
||||
this.Mem1 (arg_0_0)
|
||||
namespace SomeNamespace.CapturingMock
|
||||
|
||||
open System
|
||||
open WoofWare.Myriad.Plugins
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
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
|
||||
}
|
||||
|
||||
/// All the calls made to a CurriedMock mock
|
||||
type internal Calls<'a> =
|
||||
{
|
||||
Mem1 : ResizeArray<Mem1Call<'a>>
|
||||
Mem2 : ResizeArray<Mem2Call<'a>>
|
||||
Mem3 : ResizeArray<Mem3Call<'a>>
|
||||
Mem4 : ResizeArray<Mem4Call<'a>>
|
||||
Mem5 : ResizeArray<Mem5Call<'a>>
|
||||
Mem6 : ResizeArray<Mem6Call<'a>>
|
||||
}
|
||||
|
||||
/// A fresh calls object which has not yet had any calls made.
|
||||
static member Empty () : Calls<'a> =
|
||||
{
|
||||
Mem1 = ResizeArray ()
|
||||
Mem2 = ResizeArray ()
|
||||
Mem3 = ResizeArray ()
|
||||
Mem4 = ResizeArray ()
|
||||
Mem5 = ResizeArray ()
|
||||
Mem6 = ResizeArray ()
|
||||
}
|
||||
|
||||
/// Mock record type for an interface
|
||||
type internal CurriedMock<'a> =
|
||||
{
|
||||
Calls : CurriedMockCalls.Calls<'a>
|
||||
Mem1 : int -> 'a -> string
|
||||
Mem2 : int * string -> 'a -> string
|
||||
Mem3 : (int * string) -> 'a -> string
|
||||
Mem4 : (int * string) -> ('a * int) -> string
|
||||
Mem5 : int * string -> ('a * int) -> string
|
||||
Mem6 : int * string -> 'a * int -> string
|
||||
}
|
||||
|
||||
/// An implementation where every non-disposal method throws.
|
||||
static member Empty () : CurriedMock<'a> =
|
||||
{
|
||||
Calls = CurriedMockCalls.Calls.Empty ()
|
||||
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"))
|
||||
}
|
||||
|
||||
interface Curried<'a> with
|
||||
member this.Mem1 arg_0_0 arg_1_0 =
|
||||
lock
|
||||
this.Calls.Mem1
|
||||
(fun _ ->
|
||||
this.Calls.Mem1.Add
|
||||
{
|
||||
bar = arg_0_0
|
||||
Arg1 = arg_1_0
|
||||
}
|
||||
)
|
||||
|
||||
this.Mem1 (arg_0_0) (arg_1_0)
|
||||
|
||||
member this.Mem2 (arg_0_0, arg_0_1) arg_1_0 =
|
||||
lock
|
||||
this.Calls.Mem2
|
||||
(fun _ ->
|
||||
this.Calls.Mem2.Add
|
||||
{
|
||||
Arg0 = arg_0_0, arg_0_1
|
||||
baz = arg_1_0
|
||||
}
|
||||
)
|
||||
|
||||
this.Mem2 (arg_0_0, arg_0_1) (arg_1_0)
|
||||
|
||||
member this.Mem3 arg_0_0 arg_1_0 =
|
||||
lock
|
||||
this.Calls.Mem3
|
||||
(fun _ ->
|
||||
this.Calls.Mem3.Add
|
||||
{
|
||||
quux = arg_0_0
|
||||
flurb = 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)) =
|
||||
lock
|
||||
this.Calls.Mem4
|
||||
(fun _ ->
|
||||
this.Calls.Mem4.Add
|
||||
{
|
||||
Arg0 = arg_0_0, arg_0_1
|
||||
Arg1 = 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)) =
|
||||
lock
|
||||
this.Calls.Mem5
|
||||
(fun _ ->
|
||||
this.Calls.Mem5.Add
|
||||
{
|
||||
Arg0 = arg_0_0, arg_0_1
|
||||
Arg1 = 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) =
|
||||
lock
|
||||
this.Calls.Mem6
|
||||
(fun _ ->
|
||||
this.Calls.Mem6.Add
|
||||
{
|
||||
Arg0 = arg_0_0, arg_0_1
|
||||
Arg1 = 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
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal TypeWithInterfaceMockCalls =
|
||||
/// All the calls made to a TypeWithInterfaceMock mock
|
||||
type internal Calls =
|
||||
{
|
||||
Mem1 : ResizeArray<string option>
|
||||
Mem2 : ResizeArray<unit>
|
||||
}
|
||||
|
||||
/// A fresh calls object which has not yet had any calls made.
|
||||
static member Empty () : Calls =
|
||||
{
|
||||
Mem1 = ResizeArray ()
|
||||
Mem2 = ResizeArray ()
|
||||
}
|
||||
|
||||
/// Mock record type for an interface
|
||||
type internal TypeWithInterfaceMock =
|
||||
{
|
||||
Calls : TypeWithInterfaceMockCalls.Calls
|
||||
/// Implementation of IDisposable.Dispose
|
||||
Dispose : unit -> unit
|
||||
Mem1 : string option -> string[] Async
|
||||
Mem2 : unit -> string[] Async
|
||||
}
|
||||
|
||||
/// An implementation where every non-disposal method throws.
|
||||
static member Empty () : TypeWithInterfaceMock =
|
||||
{
|
||||
Calls = TypeWithInterfaceMockCalls.Calls.Empty ()
|
||||
Dispose = (fun () -> ())
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
|
||||
}
|
||||
|
||||
interface TypeWithInterface with
|
||||
member this.Mem1 arg_0_0 =
|
||||
lock this.Calls.Mem1 (fun _ -> this.Calls.Mem1.Add (arg_0_0))
|
||||
this.Mem1 (arg_0_0)
|
||||
|
||||
member this.Mem2 () =
|
||||
lock this.Calls.Mem2 (fun _ -> this.Calls.Mem2.Add (()))
|
||||
this.Mem2 (())
|
||||
|
||||
interface System.IDisposable with
|
||||
member this.Dispose () : unit = this.Dispose ()
|
||||
namespace SomeNamespace.CapturingMock
|
||||
|
||||
open System
|
||||
open WoofWare.Myriad.Plugins
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal TypeWithPropertiesMockCalls =
|
||||
/// All the calls made to a TypeWithPropertiesMock mock
|
||||
type internal Calls =
|
||||
{
|
||||
Mem1 : ResizeArray<string option>
|
||||
Prop1 : ResizeArray<unit>
|
||||
Prop2 : ResizeArray<unit>
|
||||
}
|
||||
|
||||
/// A fresh calls object which has not yet had any calls made.
|
||||
static member Empty () : Calls =
|
||||
{
|
||||
Mem1 = ResizeArray ()
|
||||
Prop1 = ResizeArray ()
|
||||
Prop2 = ResizeArray ()
|
||||
}
|
||||
|
||||
/// Mock record type for an interface
|
||||
type internal TypeWithPropertiesMock =
|
||||
{
|
||||
Calls : TypeWithPropertiesMockCalls.Calls
|
||||
/// Implementation of IDisposable.Dispose
|
||||
Dispose : unit -> unit
|
||||
Mem1 : string option -> string[] Async
|
||||
Prop1 : unit -> int
|
||||
Prop2 : unit -> unit Async
|
||||
}
|
||||
|
||||
/// An implementation where every non-disposal method throws.
|
||||
static member Empty () : TypeWithPropertiesMock =
|
||||
{
|
||||
Calls = TypeWithPropertiesMockCalls.Calls.Empty ()
|
||||
Dispose = (fun () -> ())
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
Prop1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Prop1"))
|
||||
Prop2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Prop2"))
|
||||
}
|
||||
|
||||
interface TypeWithProperties with
|
||||
member this.Mem1 arg_0_0 =
|
||||
lock this.Calls.Mem1 (fun _ -> this.Calls.Mem1.Add (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 ()
|
||||
namespace SomeNamespace.CapturingMock
|
||||
|
||||
open System
|
||||
open WoofWare.Myriad.Plugins
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal TypeWithAsyncDisposableMockCalls =
|
||||
/// All the calls made to a TypeWithAsyncDisposableMock mock
|
||||
type internal Calls =
|
||||
{
|
||||
Mem1 : ResizeArray<string option>
|
||||
Mem2 : ResizeArray<unit>
|
||||
}
|
||||
|
||||
/// A fresh calls object which has not yet had any calls made.
|
||||
static member Empty () : Calls =
|
||||
{
|
||||
Mem1 = ResizeArray ()
|
||||
Mem2 = ResizeArray ()
|
||||
}
|
||||
|
||||
/// Mock record type for an interface
|
||||
type internal TypeWithAsyncDisposableMock =
|
||||
{
|
||||
Calls : TypeWithAsyncDisposableMockCalls.Calls
|
||||
/// Implementation of IAsyncDisposable.DisposeAsync
|
||||
DisposeAsync : unit -> System.Threading.Tasks.ValueTask
|
||||
Mem1 : string option -> string[] Async
|
||||
Mem2 : unit -> string[] Async
|
||||
}
|
||||
|
||||
/// An implementation where every non-disposal method throws.
|
||||
static member Empty () : TypeWithAsyncDisposableMock =
|
||||
{
|
||||
Calls = TypeWithAsyncDisposableMockCalls.Calls.Empty ()
|
||||
DisposeAsync = (fun () -> (System.Threading.Tasks.ValueTask ()))
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
|
||||
}
|
||||
|
||||
interface TypeWithAsyncDisposable with
|
||||
member this.Mem1 arg_0_0 =
|
||||
lock this.Calls.Mem1 (fun _ -> this.Calls.Mem1.Add (arg_0_0))
|
||||
this.Mem1 (arg_0_0)
|
||||
|
||||
member this.Mem2 () =
|
||||
lock this.Calls.Mem2 (fun _ -> this.Calls.Mem2.Add (()))
|
||||
this.Mem2 (())
|
||||
|
||||
interface System.IAsyncDisposable with
|
||||
member this.DisposeAsync () : System.Threading.Tasks.ValueTask = this.DisposeAsync ()
|
||||
namespace SomeNamespace.CapturingMock
|
||||
|
||||
open System
|
||||
open WoofWare.Myriad.Plugins
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal TypeWithBothDisposablesMockCalls =
|
||||
/// All the calls made to a TypeWithBothDisposablesMock mock
|
||||
type internal Calls =
|
||||
{
|
||||
Mem1 : ResizeArray<string>
|
||||
}
|
||||
|
||||
/// A fresh calls object which has not yet had any calls made.
|
||||
static member Empty () : Calls =
|
||||
{
|
||||
Mem1 = ResizeArray ()
|
||||
}
|
||||
|
||||
/// Mock record type for an interface
|
||||
type internal TypeWithBothDisposablesMock =
|
||||
{
|
||||
Calls : TypeWithBothDisposablesMockCalls.Calls
|
||||
/// Implementation of IDisposable.Dispose
|
||||
Dispose : unit -> unit
|
||||
/// Implementation of IAsyncDisposable.DisposeAsync
|
||||
DisposeAsync : unit -> System.Threading.Tasks.ValueTask
|
||||
Mem1 : string -> int
|
||||
}
|
||||
|
||||
/// An implementation where every non-disposal method throws.
|
||||
static member Empty () : TypeWithBothDisposablesMock =
|
||||
{
|
||||
Calls = TypeWithBothDisposablesMockCalls.Calls.Empty ()
|
||||
Dispose = (fun () -> ())
|
||||
DisposeAsync = (fun () -> (System.Threading.Tasks.ValueTask ()))
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
}
|
||||
|
||||
interface TypeWithBothDisposables with
|
||||
member this.Mem1 arg_0_0 =
|
||||
lock this.Calls.Mem1 (fun _ -> this.Calls.Mem1.Add (arg_0_0))
|
||||
this.Mem1 (arg_0_0)
|
||||
|
||||
interface System.IDisposable with
|
||||
member this.Dispose () : unit = this.Dispose ()
|
||||
|
||||
interface System.IAsyncDisposable with
|
||||
member this.DisposeAsync () : System.Threading.Tasks.ValueTask = this.DisposeAsync ()
|
||||
@@ -1,500 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// This code was generated by myriad.
|
||||
// Changes to this file will be lost when the code is regenerated.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
namespace SomeNamespace.CapturingMock
|
||||
|
||||
open System
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal PublicTypeNoAttrMockCalls =
|
||||
/// All the calls made to a PublicTypeNoAttrMock mock
|
||||
type internal Calls =
|
||||
{
|
||||
Mem1 : ResizeArray<string * int>
|
||||
Mem2 : ResizeArray<string>
|
||||
Mem3 : ResizeArray<int * System.Threading.CancellationToken option>
|
||||
}
|
||||
|
||||
/// A fresh calls object which has not yet had any calls made.
|
||||
static member Empty () : Calls =
|
||||
{
|
||||
Mem1 = ResizeArray ()
|
||||
Mem2 = ResizeArray ()
|
||||
Mem3 = ResizeArray ()
|
||||
}
|
||||
|
||||
/// Mock record type for an interface
|
||||
type internal PublicTypeNoAttrMock =
|
||||
{
|
||||
Calls : PublicTypeNoAttrMockCalls.Calls
|
||||
Mem1 : string * int -> string list
|
||||
Mem2 : string -> int
|
||||
Mem3 : int * System.Threading.CancellationToken option -> string
|
||||
}
|
||||
|
||||
/// An implementation where every non-disposal method throws.
|
||||
static member Empty () : PublicTypeNoAttrMock =
|
||||
{
|
||||
Calls = PublicTypeNoAttrMockCalls.Calls.Empty ()
|
||||
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"))
|
||||
}
|
||||
|
||||
interface IPublicTypeNoAttr with
|
||||
member this.Mem1 (arg_0_0, arg_0_1) =
|
||||
lock this.Calls.Mem1 (fun _ -> this.Calls.Mem1.Add (arg_0_0, arg_0_1))
|
||||
this.Mem1 (arg_0_0, arg_0_1)
|
||||
|
||||
member this.Mem2 arg_0_0 =
|
||||
lock this.Calls.Mem2 (fun _ -> this.Calls.Mem2.Add (arg_0_0))
|
||||
this.Mem2 (arg_0_0)
|
||||
|
||||
member this.Mem3 (arg_0_0, arg_0_1) =
|
||||
lock this.Calls.Mem3 (fun _ -> this.Calls.Mem3.Add (arg_0_0, arg_0_1))
|
||||
this.Mem3 (arg_0_0, arg_0_1)
|
||||
namespace SomeNamespace.CapturingMock
|
||||
|
||||
open System
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module public PublicTypeInternalFalseNoAttrMockCalls =
|
||||
/// All the calls made to a PublicTypeInternalFalseNoAttrMock mock
|
||||
type public Calls =
|
||||
{
|
||||
Mem1 : ResizeArray<string * int>
|
||||
Mem2 : ResizeArray<string>
|
||||
Mem3 : ResizeArray<int * System.Threading.CancellationToken option>
|
||||
}
|
||||
|
||||
/// A fresh calls object which has not yet had any calls made.
|
||||
static member Empty () : Calls =
|
||||
{
|
||||
Mem1 = ResizeArray ()
|
||||
Mem2 = ResizeArray ()
|
||||
Mem3 = ResizeArray ()
|
||||
}
|
||||
|
||||
/// Mock record type for an interface
|
||||
type public PublicTypeInternalFalseNoAttrMock =
|
||||
{
|
||||
Calls : PublicTypeInternalFalseNoAttrMockCalls.Calls
|
||||
Mem1 : string * int -> string list
|
||||
Mem2 : string -> int
|
||||
Mem3 : int * System.Threading.CancellationToken option -> string
|
||||
}
|
||||
|
||||
/// An implementation where every non-disposal method throws.
|
||||
static member Empty () : PublicTypeInternalFalseNoAttrMock =
|
||||
{
|
||||
Calls = PublicTypeInternalFalseNoAttrMockCalls.Calls.Empty ()
|
||||
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"))
|
||||
}
|
||||
|
||||
interface IPublicTypeInternalFalseNoAttr with
|
||||
member this.Mem1 (arg_0_0, arg_0_1) =
|
||||
lock this.Calls.Mem1 (fun _ -> this.Calls.Mem1.Add (arg_0_0, arg_0_1))
|
||||
this.Mem1 (arg_0_0, arg_0_1)
|
||||
|
||||
member this.Mem2 arg_0_0 =
|
||||
lock this.Calls.Mem2 (fun _ -> this.Calls.Mem2.Add (arg_0_0))
|
||||
this.Mem2 (arg_0_0)
|
||||
|
||||
member this.Mem3 (arg_0_0, arg_0_1) =
|
||||
lock this.Calls.Mem3 (fun _ -> this.Calls.Mem3.Add (arg_0_0, arg_0_1))
|
||||
this.Mem3 (arg_0_0, arg_0_1)
|
||||
namespace SomeNamespace.CapturingMock
|
||||
|
||||
open System
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal InternalTypeNoAttrMockCalls =
|
||||
/// All the calls made to a InternalTypeNoAttrMock mock
|
||||
type internal Calls =
|
||||
{
|
||||
Mem1 : ResizeArray<string * int>
|
||||
Mem2 : ResizeArray<string>
|
||||
}
|
||||
|
||||
/// A fresh calls object which has not yet had any calls made.
|
||||
static member Empty () : Calls =
|
||||
{
|
||||
Mem1 = ResizeArray ()
|
||||
Mem2 = ResizeArray ()
|
||||
}
|
||||
|
||||
/// Mock record type for an interface
|
||||
type internal InternalTypeNoAttrMock =
|
||||
{
|
||||
Calls : InternalTypeNoAttrMockCalls.Calls
|
||||
Mem1 : string * int -> unit
|
||||
Mem2 : string -> int
|
||||
}
|
||||
|
||||
/// An implementation where every non-disposal method throws.
|
||||
static member Empty () : InternalTypeNoAttrMock =
|
||||
{
|
||||
Calls = InternalTypeNoAttrMockCalls.Calls.Empty ()
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
|
||||
}
|
||||
|
||||
interface InternalTypeNoAttr with
|
||||
member this.Mem1 (arg_0_0, arg_0_1) =
|
||||
lock this.Calls.Mem1 (fun _ -> this.Calls.Mem1.Add (arg_0_0, arg_0_1))
|
||||
this.Mem1 (arg_0_0, arg_0_1)
|
||||
|
||||
member this.Mem2 arg_0_0 =
|
||||
lock this.Calls.Mem2 (fun _ -> this.Calls.Mem2.Add (arg_0_0))
|
||||
this.Mem2 (arg_0_0)
|
||||
namespace SomeNamespace.CapturingMock
|
||||
|
||||
open System
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal PrivateTypeNoAttrMockCalls =
|
||||
/// All the calls made to a PrivateTypeNoAttrMock mock
|
||||
type internal Calls =
|
||||
{
|
||||
Mem1 : ResizeArray<string * int>
|
||||
Mem2 : ResizeArray<string>
|
||||
}
|
||||
|
||||
/// A fresh calls object which has not yet had any calls made.
|
||||
static member Empty () : Calls =
|
||||
{
|
||||
Mem1 = ResizeArray ()
|
||||
Mem2 = ResizeArray ()
|
||||
}
|
||||
|
||||
/// Mock record type for an interface
|
||||
type private PrivateTypeNoAttrMock =
|
||||
{
|
||||
Calls : PrivateTypeNoAttrMockCalls.Calls
|
||||
Mem1 : string * int -> unit
|
||||
Mem2 : string -> int
|
||||
}
|
||||
|
||||
/// An implementation where every non-disposal method throws.
|
||||
static member Empty () : PrivateTypeNoAttrMock =
|
||||
{
|
||||
Calls = PrivateTypeNoAttrMockCalls.Calls.Empty ()
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
|
||||
}
|
||||
|
||||
interface PrivateTypeNoAttr with
|
||||
member this.Mem1 (arg_0_0, arg_0_1) =
|
||||
lock this.Calls.Mem1 (fun _ -> this.Calls.Mem1.Add (arg_0_0, arg_0_1))
|
||||
this.Mem1 (arg_0_0, arg_0_1)
|
||||
|
||||
member this.Mem2 arg_0_0 =
|
||||
lock this.Calls.Mem2 (fun _ -> this.Calls.Mem2.Add (arg_0_0))
|
||||
this.Mem2 (arg_0_0)
|
||||
namespace SomeNamespace.CapturingMock
|
||||
|
||||
open System
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal PrivateTypeInternalFalseNoAttrMockCalls =
|
||||
/// All the calls made to a PrivateTypeInternalFalseNoAttrMock mock
|
||||
type internal Calls =
|
||||
{
|
||||
Mem1 : ResizeArray<string * int>
|
||||
Mem2 : ResizeArray<string>
|
||||
}
|
||||
|
||||
/// A fresh calls object which has not yet had any calls made.
|
||||
static member Empty () : Calls =
|
||||
{
|
||||
Mem1 = ResizeArray ()
|
||||
Mem2 = ResizeArray ()
|
||||
}
|
||||
|
||||
/// Mock record type for an interface
|
||||
type private PrivateTypeInternalFalseNoAttrMock =
|
||||
{
|
||||
Calls : PrivateTypeInternalFalseNoAttrMockCalls.Calls
|
||||
Mem1 : string * int -> unit
|
||||
Mem2 : string -> int
|
||||
}
|
||||
|
||||
/// An implementation where every non-disposal method throws.
|
||||
static member Empty () : PrivateTypeInternalFalseNoAttrMock =
|
||||
{
|
||||
Calls = PrivateTypeInternalFalseNoAttrMockCalls.Calls.Empty ()
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
|
||||
}
|
||||
|
||||
interface PrivateTypeInternalFalseNoAttr with
|
||||
member this.Mem1 (arg_0_0, arg_0_1) =
|
||||
lock this.Calls.Mem1 (fun _ -> this.Calls.Mem1.Add (arg_0_0, arg_0_1))
|
||||
this.Mem1 (arg_0_0, arg_0_1)
|
||||
|
||||
member this.Mem2 arg_0_0 =
|
||||
lock this.Calls.Mem2 (fun _ -> this.Calls.Mem2.Add (arg_0_0))
|
||||
this.Mem2 (arg_0_0)
|
||||
namespace SomeNamespace.CapturingMock
|
||||
|
||||
open System
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal VeryPublicTypeNoAttrMockCalls =
|
||||
/// All the calls made to a VeryPublicTypeNoAttrMock mock
|
||||
type internal Calls<'a, 'b> =
|
||||
{
|
||||
Mem1 : ResizeArray<'a>
|
||||
}
|
||||
|
||||
/// A fresh calls object which has not yet had any calls made.
|
||||
static member Empty () : Calls<'a, 'b> =
|
||||
{
|
||||
Mem1 = ResizeArray ()
|
||||
}
|
||||
|
||||
/// Mock record type for an interface
|
||||
type internal VeryPublicTypeNoAttrMock<'a, 'b> =
|
||||
{
|
||||
Calls : VeryPublicTypeNoAttrMockCalls.Calls<'a, 'b>
|
||||
Mem1 : 'a -> 'b
|
||||
}
|
||||
|
||||
/// An implementation where every non-disposal method throws.
|
||||
static member Empty () : VeryPublicTypeNoAttrMock<'a, 'b> =
|
||||
{
|
||||
Calls = VeryPublicTypeNoAttrMockCalls.Calls.Empty ()
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
}
|
||||
|
||||
interface VeryPublicTypeNoAttr<'a, 'b> with
|
||||
member this.Mem1 arg_0_0 =
|
||||
lock this.Calls.Mem1 (fun _ -> this.Calls.Mem1.Add (arg_0_0))
|
||||
this.Mem1 (arg_0_0)
|
||||
namespace SomeNamespace.CapturingMock
|
||||
|
||||
open System
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
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
|
||||
}
|
||||
|
||||
/// All the calls made to a CurriedNoAttrMock mock
|
||||
type internal Calls<'a> =
|
||||
{
|
||||
Mem1 : ResizeArray<Mem1Call<'a>>
|
||||
Mem2 : ResizeArray<Mem2Call<'a>>
|
||||
Mem3 : ResizeArray<Mem3Call<'a>>
|
||||
Mem4 : ResizeArray<Mem4Call<'a>>
|
||||
Mem5 : ResizeArray<Mem5Call<'a>>
|
||||
Mem6 : ResizeArray<Mem6Call<'a>>
|
||||
}
|
||||
|
||||
/// A fresh calls object which has not yet had any calls made.
|
||||
static member Empty () : Calls<'a> =
|
||||
{
|
||||
Mem1 = ResizeArray ()
|
||||
Mem2 = ResizeArray ()
|
||||
Mem3 = ResizeArray ()
|
||||
Mem4 = ResizeArray ()
|
||||
Mem5 = ResizeArray ()
|
||||
Mem6 = ResizeArray ()
|
||||
}
|
||||
|
||||
/// Mock record type for an interface
|
||||
type internal CurriedNoAttrMock<'a> =
|
||||
{
|
||||
Calls : CurriedNoAttrMockCalls.Calls<'a>
|
||||
Mem1 : int -> 'a -> string
|
||||
Mem2 : int * string -> 'a -> string
|
||||
Mem3 : (int * string) -> 'a -> string
|
||||
Mem4 : (int * string) -> ('a * int) -> string
|
||||
Mem5 : int * string -> ('a * int) -> string
|
||||
Mem6 : int * string -> 'a * int -> string
|
||||
}
|
||||
|
||||
/// An implementation where every non-disposal method throws.
|
||||
static member Empty () : CurriedNoAttrMock<'a> =
|
||||
{
|
||||
Calls = CurriedNoAttrMockCalls.Calls.Empty ()
|
||||
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"))
|
||||
}
|
||||
|
||||
interface CurriedNoAttr<'a> with
|
||||
member this.Mem1 arg_0_0 arg_1_0 =
|
||||
lock
|
||||
this.Calls.Mem1
|
||||
(fun _ ->
|
||||
this.Calls.Mem1.Add
|
||||
{
|
||||
Arg0 = arg_0_0
|
||||
Arg1 = arg_1_0
|
||||
}
|
||||
)
|
||||
|
||||
this.Mem1 (arg_0_0) (arg_1_0)
|
||||
|
||||
member this.Mem2 (arg_0_0, arg_0_1) arg_1_0 =
|
||||
lock
|
||||
this.Calls.Mem2
|
||||
(fun _ ->
|
||||
this.Calls.Mem2.Add
|
||||
{
|
||||
Arg0 = arg_0_0, arg_0_1
|
||||
Arg1 = 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 =
|
||||
lock
|
||||
this.Calls.Mem3
|
||||
(fun _ ->
|
||||
this.Calls.Mem3.Add
|
||||
{
|
||||
Arg0 = arg_0_0, arg_0_1
|
||||
Arg1 = 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)) =
|
||||
lock
|
||||
this.Calls.Mem4
|
||||
(fun _ ->
|
||||
this.Calls.Mem4.Add
|
||||
{
|
||||
Arg0 = arg_0_0, arg_0_1
|
||||
Arg1 = 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)) =
|
||||
lock
|
||||
this.Calls.Mem5
|
||||
(fun _ ->
|
||||
this.Calls.Mem5.Add
|
||||
{
|
||||
Arg0 = arg_0_0, arg_0_1
|
||||
Arg1 = 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) =
|
||||
lock
|
||||
this.Calls.Mem6
|
||||
(fun _ ->
|
||||
this.Calls.Mem6.Add
|
||||
{
|
||||
Arg0 = arg_0_0, arg_0_1
|
||||
Arg1 = 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
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal TypeWithInterfaceNoAttrMockCalls =
|
||||
/// All the calls made to a TypeWithInterfaceNoAttrMock mock
|
||||
type internal Calls =
|
||||
{
|
||||
Mem1 : ResizeArray<string option>
|
||||
Mem2 : ResizeArray<unit>
|
||||
}
|
||||
|
||||
/// A fresh calls object which has not yet had any calls made.
|
||||
static member Empty () : Calls =
|
||||
{
|
||||
Mem1 = ResizeArray ()
|
||||
Mem2 = ResizeArray ()
|
||||
}
|
||||
|
||||
/// Mock record type for an interface
|
||||
type internal TypeWithInterfaceNoAttrMock =
|
||||
{
|
||||
Calls : TypeWithInterfaceNoAttrMockCalls.Calls
|
||||
/// Implementation of IDisposable.Dispose
|
||||
Dispose : unit -> unit
|
||||
Mem1 : string option -> string[] Async
|
||||
Mem2 : unit -> string[] Async
|
||||
}
|
||||
|
||||
/// An implementation where every non-disposal method throws.
|
||||
static member Empty () : TypeWithInterfaceNoAttrMock =
|
||||
{
|
||||
Calls = TypeWithInterfaceNoAttrMockCalls.Calls.Empty ()
|
||||
Dispose = (fun () -> ())
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
|
||||
}
|
||||
|
||||
interface TypeWithInterfaceNoAttr with
|
||||
member this.Mem1 arg_0_0 =
|
||||
lock this.Calls.Mem1 (fun _ -> this.Calls.Mem1.Add (arg_0_0))
|
||||
this.Mem1 (arg_0_0)
|
||||
|
||||
member this.Mem2 () =
|
||||
lock this.Calls.Mem2 (fun _ -> this.Calls.Mem2.Add (()))
|
||||
this.Mem2 (())
|
||||
|
||||
interface System.IDisposable with
|
||||
member this.Dispose () : unit = this.Dispose ()
|
||||
@@ -7,7 +7,6 @@
|
||||
|
||||
|
||||
|
||||
|
||||
namespace ConsumePlugin
|
||||
|
||||
open WoofWare.Myriad.Plugins
|
||||
|
||||
@@ -1,144 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// This code was generated by myriad.
|
||||
// Changes to this file will be lost when the code is regenerated.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
namespace ConsumePluginNoAttr
|
||||
|
||||
/// Description of how to combine cases during a fold
|
||||
type TreeBuilderNoAttrCataCase<'b, 'a, 'TreeBuilderNoAttr, 'TreeNoAttr> =
|
||||
/// How to operate on the Child case
|
||||
abstract Child : 'TreeBuilderNoAttr -> 'TreeBuilderNoAttr
|
||||
/// How to operate on the Parent case
|
||||
abstract Parent : 'TreeNoAttr -> 'TreeBuilderNoAttr
|
||||
|
||||
/// Description of how to combine cases during a fold
|
||||
type TreeNoAttrCataCase<'a, 'b, 'TreeBuilderNoAttr, 'TreeNoAttr> =
|
||||
/// How to operate on the Const case
|
||||
abstract Const : ConstNoAttr<'a> -> 'b -> 'TreeNoAttr
|
||||
/// How to operate on the Pair case
|
||||
abstract Pair : 'TreeNoAttr -> 'TreeNoAttr -> PairOpKindNoAttr -> 'TreeNoAttr
|
||||
/// How to operate on the Sequential case
|
||||
abstract Sequential : 'TreeNoAttr list -> 'TreeNoAttr
|
||||
/// How to operate on the Builder case
|
||||
abstract Builder : 'TreeNoAttr -> 'TreeBuilderNoAttr -> 'TreeNoAttr
|
||||
|
||||
/// Specifies how to perform a fold (catamorphism) over the type TreeNoAttr and its friends.
|
||||
type TreeNoAttrCata<'b, 'a, 'TreeBuilderNoAttr, 'TreeNoAttr> =
|
||||
{
|
||||
/// How to perform a fold (catamorphism) over the type TreeBuilderNoAttr
|
||||
TreeBuilderNoAttr : TreeBuilderNoAttrCataCase<'b, 'a, 'TreeBuilderNoAttr, 'TreeNoAttr>
|
||||
/// How to perform a fold (catamorphism) over the type TreeNoAttr
|
||||
TreeNoAttr : TreeNoAttrCataCase<'a, 'b, 'TreeBuilderNoAttr, 'TreeNoAttr>
|
||||
}
|
||||
|
||||
/// Methods to perform a catamorphism over the type TreeNoAttr
|
||||
[<RequireQualifiedAccess>]
|
||||
module TreeNoAttrCata =
|
||||
[<RequireQualifiedAccess>]
|
||||
type private Instruction<'b, 'a> =
|
||||
| Process__TreeBuilderNoAttr of TreeBuilderNoAttr<'b, 'a>
|
||||
| Process__TreeNoAttr of TreeNoAttr<'a, 'b>
|
||||
| TreeBuilderNoAttr_Child
|
||||
| TreeBuilderNoAttr_Parent
|
||||
| TreeNoAttr_Pair of PairOpKindNoAttr
|
||||
| TreeNoAttr_Sequential of int
|
||||
| TreeNoAttr_Builder
|
||||
|
||||
let private loop
|
||||
(cata : TreeNoAttrCata<'b, 'a, 'TreeBuilderNoAttr, 'TreeNoAttr>)
|
||||
(instructions : ResizeArray<Instruction<'b, 'a>>)
|
||||
=
|
||||
let treeNoAttrStack = ResizeArray<'TreeNoAttr> ()
|
||||
let treeBuilderNoAttrStack = ResizeArray<'TreeBuilderNoAttr> ()
|
||||
|
||||
while instructions.Count > 0 do
|
||||
let currentInstruction = instructions.[instructions.Count - 1]
|
||||
instructions.RemoveAt (instructions.Count - 1)
|
||||
|
||||
match currentInstruction with
|
||||
| Instruction.Process__TreeBuilderNoAttr x ->
|
||||
match x with
|
||||
| TreeBuilderNoAttr.Child (arg0_0) ->
|
||||
instructions.Add Instruction.TreeBuilderNoAttr_Child
|
||||
instructions.Add (Instruction.Process__TreeBuilderNoAttr arg0_0)
|
||||
| TreeBuilderNoAttr.Parent (arg0_0) ->
|
||||
instructions.Add Instruction.TreeBuilderNoAttr_Parent
|
||||
instructions.Add (Instruction.Process__TreeNoAttr arg0_0)
|
||||
| Instruction.Process__TreeNoAttr x ->
|
||||
match x with
|
||||
| TreeNoAttr.Const (arg0_0, arg1_0) -> cata.TreeNoAttr.Const arg0_0 arg1_0 |> treeNoAttrStack.Add
|
||||
| TreeNoAttr.Pair (arg0_0, arg1_0, arg2_0) ->
|
||||
instructions.Add (Instruction.TreeNoAttr_Pair (arg2_0))
|
||||
instructions.Add (Instruction.Process__TreeNoAttr arg0_0)
|
||||
instructions.Add (Instruction.Process__TreeNoAttr arg1_0)
|
||||
| TreeNoAttr.Sequential (arg0_0) ->
|
||||
instructions.Add (Instruction.TreeNoAttr_Sequential ((List.length arg0_0)))
|
||||
|
||||
for elt in arg0_0 do
|
||||
instructions.Add (Instruction.Process__TreeNoAttr elt)
|
||||
| TreeNoAttr.Builder (arg0_0, arg1_0) ->
|
||||
instructions.Add Instruction.TreeNoAttr_Builder
|
||||
instructions.Add (Instruction.Process__TreeNoAttr arg0_0)
|
||||
instructions.Add (Instruction.Process__TreeBuilderNoAttr arg1_0)
|
||||
| Instruction.TreeBuilderNoAttr_Child ->
|
||||
let arg0_0 = treeBuilderNoAttrStack.[treeBuilderNoAttrStack.Count - 1]
|
||||
treeBuilderNoAttrStack.RemoveAt (treeBuilderNoAttrStack.Count - 1)
|
||||
cata.TreeBuilderNoAttr.Child arg0_0 |> treeBuilderNoAttrStack.Add
|
||||
| Instruction.TreeBuilderNoAttr_Parent ->
|
||||
let arg0_0 = treeNoAttrStack.[treeNoAttrStack.Count - 1]
|
||||
treeNoAttrStack.RemoveAt (treeNoAttrStack.Count - 1)
|
||||
cata.TreeBuilderNoAttr.Parent arg0_0 |> treeBuilderNoAttrStack.Add
|
||||
| Instruction.TreeNoAttr_Pair arg2_0 ->
|
||||
let arg0_0 = treeNoAttrStack.[treeNoAttrStack.Count - 1]
|
||||
treeNoAttrStack.RemoveAt (treeNoAttrStack.Count - 1)
|
||||
let arg1_0 = treeNoAttrStack.[treeNoAttrStack.Count - 1]
|
||||
treeNoAttrStack.RemoveAt (treeNoAttrStack.Count - 1)
|
||||
cata.TreeNoAttr.Pair arg0_0 arg1_0 arg2_0 |> treeNoAttrStack.Add
|
||||
| Instruction.TreeNoAttr_Sequential arg0_0 ->
|
||||
let arg0_0_len = arg0_0
|
||||
|
||||
let arg0_0 =
|
||||
seq {
|
||||
for i = treeNoAttrStack.Count - 1 downto treeNoAttrStack.Count - arg0_0 do
|
||||
yield treeNoAttrStack.[i]
|
||||
}
|
||||
|> Seq.toList
|
||||
|
||||
treeNoAttrStack.RemoveRange (treeNoAttrStack.Count - arg0_0_len, arg0_0_len)
|
||||
cata.TreeNoAttr.Sequential arg0_0 |> treeNoAttrStack.Add
|
||||
| Instruction.TreeNoAttr_Builder ->
|
||||
let arg0_0 = treeNoAttrStack.[treeNoAttrStack.Count - 1]
|
||||
treeNoAttrStack.RemoveAt (treeNoAttrStack.Count - 1)
|
||||
let arg1_0 = treeBuilderNoAttrStack.[treeBuilderNoAttrStack.Count - 1]
|
||||
treeBuilderNoAttrStack.RemoveAt (treeBuilderNoAttrStack.Count - 1)
|
||||
cata.TreeNoAttr.Builder arg0_0 arg1_0 |> treeNoAttrStack.Add
|
||||
|
||||
treeBuilderNoAttrStack, treeNoAttrStack
|
||||
|
||||
/// Execute the catamorphism.
|
||||
let runTreeBuilderNoAttr
|
||||
(cata : TreeNoAttrCata<'b, 'a, 'TreeBuilderNoAttrRet, 'TreeNoAttrRet>)
|
||||
(x : TreeBuilderNoAttr<'b, 'a>)
|
||||
: 'TreeBuilderNoAttrRet
|
||||
=
|
||||
let instructions = ResizeArray ()
|
||||
instructions.Add (Instruction.Process__TreeBuilderNoAttr x)
|
||||
let treeBuilderNoAttrRetStack, treeNoAttrRetStack = loop cata instructions
|
||||
Seq.exactlyOne treeBuilderNoAttrRetStack
|
||||
|
||||
/// Execute the catamorphism.
|
||||
let runTreeNoAttr
|
||||
(cata : TreeNoAttrCata<'b, 'a, 'TreeBuilderNoAttrRet, 'TreeNoAttrRet>)
|
||||
(x : TreeNoAttr<'a, 'b>)
|
||||
: 'TreeNoAttrRet
|
||||
=
|
||||
let instructions = ResizeArray ()
|
||||
instructions.Add (Instruction.Process__TreeNoAttr x)
|
||||
let treeBuilderNoAttrRetStack, treeNoAttrRetStack = loop cata instructions
|
||||
Seq.exactlyOne treeNoAttrRetStack
|
||||
@@ -7,7 +7,6 @@
|
||||
|
||||
|
||||
|
||||
|
||||
namespace ConsumePlugin
|
||||
|
||||
open WoofWare.Myriad.Plugins
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
namespace ConsumePlugin
|
||||
|
||||
open System.Text.Json.Serialization
|
||||
|
||||
@@ -16,7 +16,7 @@ type internal PublicTypeMock =
|
||||
Mem3 : int * option<System.Threading.CancellationToken> -> string
|
||||
}
|
||||
|
||||
/// An implementation where every non-disposal method throws.
|
||||
/// An implementation where every method throws.
|
||||
static member Empty : PublicTypeMock =
|
||||
{
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
@@ -41,7 +41,7 @@ type public PublicTypeInternalFalseMock =
|
||||
Mem3 : int * option<System.Threading.CancellationToken> -> string
|
||||
}
|
||||
|
||||
/// An implementation where every non-disposal method throws.
|
||||
/// An implementation where every method throws.
|
||||
static member Empty : PublicTypeInternalFalseMock =
|
||||
{
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
@@ -65,7 +65,7 @@ type internal InternalTypeMock =
|
||||
Mem2 : string -> int
|
||||
}
|
||||
|
||||
/// An implementation where every non-disposal method throws.
|
||||
/// An implementation where every method throws.
|
||||
static member Empty : InternalTypeMock =
|
||||
{
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
@@ -87,7 +87,7 @@ type private PrivateTypeMock =
|
||||
Mem2 : string -> int
|
||||
}
|
||||
|
||||
/// An implementation where every non-disposal method throws.
|
||||
/// An implementation where every method throws.
|
||||
static member Empty : PrivateTypeMock =
|
||||
{
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
@@ -109,7 +109,7 @@ type private PrivateTypeInternalFalseMock =
|
||||
Mem2 : string -> int
|
||||
}
|
||||
|
||||
/// An implementation where every non-disposal method throws.
|
||||
/// An implementation where every method throws.
|
||||
static member Empty : PrivateTypeInternalFalseMock =
|
||||
{
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
@@ -130,7 +130,7 @@ type internal VeryPublicTypeMock<'a, 'b> =
|
||||
Mem1 : 'a -> 'b
|
||||
}
|
||||
|
||||
/// An implementation where every non-disposal method throws.
|
||||
/// An implementation where every method throws.
|
||||
static member Empty () : VeryPublicTypeMock<'a, 'b> =
|
||||
{
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
@@ -154,7 +154,7 @@ type internal CurriedMock<'a> =
|
||||
Mem6 : int * string -> 'a * int -> string
|
||||
}
|
||||
|
||||
/// An implementation where every non-disposal method throws.
|
||||
/// An implementation where every method throws.
|
||||
static member Empty () : CurriedMock<'a> =
|
||||
{
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
@@ -192,7 +192,7 @@ type internal TypeWithInterfaceMock =
|
||||
Mem2 : unit -> string[] Async
|
||||
}
|
||||
|
||||
/// An implementation where every non-disposal method throws.
|
||||
/// An implementation where every method throws.
|
||||
static member Empty : TypeWithInterfaceMock =
|
||||
{
|
||||
Dispose = (fun () -> ())
|
||||
@@ -221,7 +221,7 @@ type internal TypeWithPropertiesMock =
|
||||
Mem1 : string option -> string[] Async
|
||||
}
|
||||
|
||||
/// An implementation where every non-disposal method throws.
|
||||
/// An implementation where every method throws.
|
||||
static member Empty : TypeWithPropertiesMock =
|
||||
{
|
||||
Dispose = (fun () -> ())
|
||||
@@ -237,62 +237,3 @@ type internal TypeWithPropertiesMock =
|
||||
|
||||
interface System.IDisposable with
|
||||
member this.Dispose () : unit = this.Dispose ()
|
||||
namespace SomeNamespace
|
||||
|
||||
open System
|
||||
open WoofWare.Myriad.Plugins
|
||||
|
||||
/// Mock record type for an interface
|
||||
type internal TypeWithAsyncDisposableMock =
|
||||
{
|
||||
/// Implementation of IAsyncDisposable.DisposeAsync
|
||||
DisposeAsync : unit -> System.Threading.Tasks.ValueTask
|
||||
Mem1 : string option -> string[] Async
|
||||
Mem2 : unit -> string[] Async
|
||||
}
|
||||
|
||||
/// An implementation where every non-disposal method throws.
|
||||
static member Empty : TypeWithAsyncDisposableMock =
|
||||
{
|
||||
DisposeAsync = (fun () -> (System.Threading.Tasks.ValueTask ()))
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem2"))
|
||||
}
|
||||
|
||||
interface TypeWithAsyncDisposable with
|
||||
member this.Mem1 arg_0_0 = this.Mem1 (arg_0_0)
|
||||
member this.Mem2 () = this.Mem2 (())
|
||||
|
||||
interface System.IAsyncDisposable with
|
||||
member this.DisposeAsync () : System.Threading.Tasks.ValueTask = this.DisposeAsync ()
|
||||
namespace SomeNamespace
|
||||
|
||||
open System
|
||||
open WoofWare.Myriad.Plugins
|
||||
|
||||
/// Mock record type for an interface
|
||||
type internal TypeWithBothDisposablesMock =
|
||||
{
|
||||
/// Implementation of IDisposable.Dispose
|
||||
Dispose : unit -> unit
|
||||
/// Implementation of IAsyncDisposable.DisposeAsync
|
||||
DisposeAsync : unit -> System.Threading.Tasks.ValueTask
|
||||
Mem1 : string -> int
|
||||
}
|
||||
|
||||
/// An implementation where every non-disposal method throws.
|
||||
static member Empty : TypeWithBothDisposablesMock =
|
||||
{
|
||||
Dispose = (fun () -> ())
|
||||
DisposeAsync = (fun () -> (System.Threading.Tasks.ValueTask ()))
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
}
|
||||
|
||||
interface TypeWithBothDisposables with
|
||||
member this.Mem1 arg_0_0 = this.Mem1 (arg_0_0)
|
||||
|
||||
interface System.IDisposable with
|
||||
member this.Dispose () : unit = this.Dispose ()
|
||||
|
||||
interface System.IAsyncDisposable with
|
||||
member this.DisposeAsync () : System.Threading.Tasks.ValueTask = this.DisposeAsync ()
|
||||
|
||||
@@ -15,7 +15,7 @@ type internal PublicTypeNoAttrMock =
|
||||
Mem3 : int * option<System.Threading.CancellationToken> -> string
|
||||
}
|
||||
|
||||
/// An implementation where every non-disposal method throws.
|
||||
/// An implementation where every method throws.
|
||||
static member Empty : PublicTypeNoAttrMock =
|
||||
{
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
@@ -39,7 +39,7 @@ type public PublicTypeInternalFalseNoAttrMock =
|
||||
Mem3 : int * option<System.Threading.CancellationToken> -> string
|
||||
}
|
||||
|
||||
/// An implementation where every non-disposal method throws.
|
||||
/// An implementation where every method throws.
|
||||
static member Empty : PublicTypeInternalFalseNoAttrMock =
|
||||
{
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
@@ -62,7 +62,7 @@ type internal InternalTypeNoAttrMock =
|
||||
Mem2 : string -> int
|
||||
}
|
||||
|
||||
/// An implementation where every non-disposal method throws.
|
||||
/// An implementation where every method throws.
|
||||
static member Empty : InternalTypeNoAttrMock =
|
||||
{
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
@@ -83,7 +83,7 @@ type private PrivateTypeNoAttrMock =
|
||||
Mem2 : string -> int
|
||||
}
|
||||
|
||||
/// An implementation where every non-disposal method throws.
|
||||
/// An implementation where every method throws.
|
||||
static member Empty : PrivateTypeNoAttrMock =
|
||||
{
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
@@ -104,7 +104,7 @@ type private PrivateTypeInternalFalseNoAttrMock =
|
||||
Mem2 : string -> int
|
||||
}
|
||||
|
||||
/// An implementation where every non-disposal method throws.
|
||||
/// An implementation where every method throws.
|
||||
static member Empty : PrivateTypeInternalFalseNoAttrMock =
|
||||
{
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
@@ -124,7 +124,7 @@ type internal VeryPublicTypeNoAttrMock<'a, 'b> =
|
||||
Mem1 : 'a -> 'b
|
||||
}
|
||||
|
||||
/// An implementation where every non-disposal method throws.
|
||||
/// An implementation where every method throws.
|
||||
static member Empty () : VeryPublicTypeNoAttrMock<'a, 'b> =
|
||||
{
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
@@ -147,7 +147,7 @@ type internal CurriedNoAttrMock<'a> =
|
||||
Mem6 : int * string -> 'a * int -> string
|
||||
}
|
||||
|
||||
/// An implementation where every non-disposal method throws.
|
||||
/// An implementation where every method throws.
|
||||
static member Empty () : CurriedNoAttrMock<'a> =
|
||||
{
|
||||
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function: Mem1"))
|
||||
@@ -184,7 +184,7 @@ type internal TypeWithInterfaceNoAttrMock =
|
||||
Mem2 : unit -> string[] Async
|
||||
}
|
||||
|
||||
/// An implementation where every non-disposal method throws.
|
||||
/// An implementation where every method throws.
|
||||
static member Empty : TypeWithInterfaceNoAttrMock =
|
||||
{
|
||||
Dispose = (fun () -> ())
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
namespace PureGym
|
||||
|
||||
open System
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
|
||||
|
||||
|
||||
namespace PureGym
|
||||
|
||||
open System
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
namespace ConsumePlugin
|
||||
|
||||
open System
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
|
||||
|
||||
|
||||
|
||||
namespace Gitea
|
||||
|
||||
open WoofWare.Myriad.Plugins
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
|
||||
|
||||
|
||||
namespace ConsumePlugin
|
||||
|
||||
/// Module containing JSON parsing methods for the JwtVaultAuthResponse type
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
|
||||
|
||||
|
||||
|
||||
namespace ConsumePlugin
|
||||
|
||||
open WoofWare.Myriad.Plugins
|
||||
|
||||
@@ -55,15 +55,3 @@ type TypeWithProperties =
|
||||
abstract Mem1 : string option -> string[] Async
|
||||
abstract Prop1 : int
|
||||
abstract Prop2 : unit Async
|
||||
|
||||
[<GenerateMock>]
|
||||
type TypeWithAsyncDisposable =
|
||||
inherit IAsyncDisposable
|
||||
abstract Mem1 : string option -> string[] Async
|
||||
abstract Mem2 : unit -> string[] Async
|
||||
|
||||
[<GenerateMock>]
|
||||
type TypeWithBothDisposables =
|
||||
inherit IDisposable
|
||||
inherit IAsyncDisposable
|
||||
abstract Mem1 : string -> int
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<WarnOn>FS3388,FS3559</WarnOn>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Nerdbank.GitVersioning" Version="3.9.50" PrivateAssets="all" />
|
||||
<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)' != ''">
|
||||
|
||||
93
README.md
93
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` and `GenerateCapturingMock` (to stamp out a record type corresponding to an interface, like a compile-time [Foq](https://github.com/fsprojects/Foq)).
|
||||
* `GenerateMock` (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` and `GenerateCapturingMock`
|
||||
## `GenerateMock`
|
||||
|
||||
`GenerateMock` takes a type like this:
|
||||
Takes a type like this:
|
||||
|
||||
```fsharp
|
||||
[<GenerateMock>]
|
||||
@@ -472,59 +472,6 @@ 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 -> thing : bool -> string list
|
||||
abstract Mem2 : baz : string -> unit -> int
|
||||
```
|
||||
|
||||
and stamps out types like this:
|
||||
|
||||
```fsharp
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal PublicTypeCalls =
|
||||
type internal Mem1Call =
|
||||
{
|
||||
Arg0 : string * int
|
||||
thing : bool
|
||||
}
|
||||
|
||||
type internal Calls =
|
||||
{
|
||||
Mem1 : ResizeArray<Mem1Call>
|
||||
Mem2 : ResizeArray<string>
|
||||
}
|
||||
|
||||
static member Empty () = { Mem1 = ResizeArray () ; Mem2 = ResizeArray () }
|
||||
|
||||
/// Mock record type for an interface
|
||||
type internal PublicTypeMock =
|
||||
{
|
||||
Mem1 : string * int -> bool -> string list
|
||||
Mem2 : string -> int
|
||||
Calls : PublicTypeCalls.Calls
|
||||
}
|
||||
|
||||
static member Empty : PublicTypeMock =
|
||||
{
|
||||
Mem1 = (fun x -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||
Mem2 = (fun x -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||
Calls = PublicTypeMockCalls.Calls.Empty ()
|
||||
}
|
||||
|
||||
interface IPublicType with
|
||||
member this.Mem1 (arg0, arg1) =
|
||||
lock this.Calls.Mem1 (fun () -> this.Calls.Mem1.Add { Arg0 = arg0 ; thing = arg1 })
|
||||
this.Mem1 (arg0, arg1)
|
||||
member this.Mem2 (arg0) =
|
||||
lock this.Calls.Mem2 (fun () -> this.Calls.Mem2.Add 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.
|
||||
@@ -536,36 +483,6 @@ thereby allowing the programmer to use F#'s record-update syntax.
|
||||
|
||||
* You may supply an `isInternal : bool` argument to the attribute. 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 with `[<GenerateMock false>]`.
|
||||
|
||||
### Gotchas (GenerateCapturingMock)
|
||||
|
||||
We use the same name for the record field as the implementing interface member:
|
||||
|
||||
```fsharp
|
||||
type FooMock =
|
||||
{
|
||||
Field : string -> unit
|
||||
}
|
||||
interface IFoo with
|
||||
member _.Field x = ...
|
||||
```
|
||||
|
||||
If you have an object of type `FooMock` in scope, you'll get the *record field*, not the *interface member*.
|
||||
You need to cast it to `IFoo` before using it (or pass it into a function which takes an `IFoo`):
|
||||
|
||||
```fsharp
|
||||
let thing = FooMock.Empty () // of type FooMock
|
||||
thing.Field "hello" // the wrong one! bypasses the IFoo implementation which captures calls
|
||||
|
||||
// correct:
|
||||
let thing' = FooMock.Empty ()
|
||||
let thing = thing' :> IFoo
|
||||
thing.Field "hello" // the right one: this call does get recorded in the mock, because this is the interface member
|
||||
|
||||
// also correct, but beware because it leaves the chance of the above footgun lying around for later:
|
||||
let thing = FooMock.Empty () // of type FooMock
|
||||
doTheThing thing // where doTheThing : IFoo -> unit
|
||||
```
|
||||
|
||||
## `CreateCatamorphism`
|
||||
|
||||
Takes a collection of mutually recursive discriminated unions:
|
||||
@@ -652,13 +569,13 @@ For example, [PureGymDto.fs](./ConsumePlugin/PureGymDto.fs) is a real-world set
|
||||
* In your `.fsproj` file, define a helper variable so that subsequent steps don't all have to be kept in sync:
|
||||
```xml
|
||||
<PropertyGroup>
|
||||
<WoofWareMyriadPluginVersion>9.0.1</WoofWareMyriadPluginVersion>
|
||||
<WoofWareMyriadPluginVersion>2.0.1</WoofWareMyriadPluginVersion>
|
||||
</PropertyGroup>
|
||||
```
|
||||
* Take a reference on `WoofWare.Myriad.Plugins.Attributes` (which has no other dependencies), to obtain access to the attributes which the generator will recognise:
|
||||
```xml
|
||||
<ItemGroup>
|
||||
<PackageReference Include="WoofWare.Myriad.Plugins.Attributes" Version="3.7.2" />
|
||||
<PackageReference Include="WoofWare.Myriad.Plugins.Attributes" Version="2.0.2" />
|
||||
</ItemGroup>
|
||||
```
|
||||
* Take a reference (with private assets, to prevent these from propagating to your own assembly) on `WoofWare.Myriad.Plugins`, to obtain the plugins which Myriad will run, and on `Myriad.Sdk`, to obtain the Myriad binary itself:
|
||||
|
||||
@@ -62,10 +62,8 @@ type ArgumentDefaultFunctionAttribute () =
|
||||
type ArgumentDefaultEnvironmentVariableAttribute (envVar : string) =
|
||||
inherit Attribute ()
|
||||
|
||||
/// Attribute indicating that this field or type shall have the given help text, when `--help` is invoked
|
||||
/// Attribute indicating that this field shall have the given help text, when `--help` is invoked
|
||||
/// or when a parse error causes us to print help text.
|
||||
/// When applied to a record type, the help text appears at the top of the help output, before the field descriptions.
|
||||
/// When applied to a field, the help text appears next to that field's description.
|
||||
type ArgumentHelpTextAttribute (helpText : string) =
|
||||
inherit Attribute ()
|
||||
|
||||
@@ -102,24 +100,3 @@ type ArgumentFlagAttribute (flagValue : bool) =
|
||||
[<AttributeUsage(AttributeTargets.Field, AllowMultiple = true)>]
|
||||
type ArgumentLongForm (s : string) =
|
||||
inherit Attribute ()
|
||||
|
||||
/// Attribute indicating that this boolean or flag field should accept `--no-` prefix for negation.
|
||||
/// When this attribute is present on a boolean or flag DU field, the generated parser will accept
|
||||
/// both --field-name and --no-field-name as argument forms.
|
||||
///
|
||||
/// For boolean fields:
|
||||
/// --field-name (or --field-name=true) sets the value to true
|
||||
/// --no-field-name (or --no-field-name=true) sets the value to false
|
||||
/// --field-name=false sets the value to false
|
||||
/// --no-field-name=false sets the value to true
|
||||
///
|
||||
/// For flag DU fields with [<ArgumentFlag>]:
|
||||
/// --field-name (or --field-name=true) sets to the case marked with [<ArgumentFlag true>]
|
||||
/// --no-field-name (or --no-field-name=true) sets to the case marked with [<ArgumentFlag false>]
|
||||
/// --field-name=false sets to the [<ArgumentFlag false>] case
|
||||
/// --no-field-name=false sets to the [<ArgumentFlag true>] case
|
||||
///
|
||||
/// This attribute can only be applied to bool fields or flag DU fields (two-case DUs with [<ArgumentFlag>]).
|
||||
[<AttributeUsage(AttributeTargets.Field, AllowMultiple = false)>]
|
||||
type ArgumentNegateWithPrefixAttribute () =
|
||||
inherit Attribute ()
|
||||
|
||||
@@ -14,9 +14,6 @@ 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.
|
||||
@@ -25,26 +22,6 @@ 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 throws.
|
||||
///
|
||||
/// The generated interface methods capture all calls made to them, before passing through to the relevant
|
||||
/// field of the mock record; the calls can be accessed later through the `Calls` field of the generated
|
||||
/// mock record.
|
||||
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
|
||||
|
||||
@@ -13,15 +13,8 @@ WoofWare.Myriad.Plugins.ArgumentHelpTextAttribute inherit System.Attribute
|
||||
WoofWare.Myriad.Plugins.ArgumentHelpTextAttribute..ctor [constructor]: string
|
||||
WoofWare.Myriad.Plugins.ArgumentLongForm inherit System.Attribute
|
||||
WoofWare.Myriad.Plugins.ArgumentLongForm..ctor [constructor]: string
|
||||
WoofWare.Myriad.Plugins.ArgumentNegateWithPrefixAttribute inherit System.Attribute
|
||||
WoofWare.Myriad.Plugins.ArgumentNegateWithPrefixAttribute..ctor [constructor]: unit
|
||||
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,10 +17,10 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ApiSurface" Version="5.0.3" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1"/>
|
||||
<PackageReference Include="NUnit" Version="4.3.2"/>
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="5.2.0"/>
|
||||
<PackageReference Include="ApiSurface" Version="4.1.22" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1"/>
|
||||
<PackageReference Include="NUnit" Version="4.4.0"/>
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="5.0.0"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "3.8",
|
||||
"version": "3.6",
|
||||
"publicReleaseRefSpec": [
|
||||
"^refs/heads/main$"
|
||||
],
|
||||
|
||||
@@ -444,7 +444,7 @@ Required argument '--exact' received no value"""
|
||||
]
|
||||
|> List.map TestCaseData
|
||||
|
||||
[<TestCaseSource(nameof boolCases)>]
|
||||
[<TestCaseSource(nameof (boolCases))>]
|
||||
let ``Bool env vars can be populated`` (envValue : string, boolValue : bool) =
|
||||
let getEnvVar (s : string) =
|
||||
s |> shouldEqual "CONSUMEPLUGIN_THINGS"
|
||||
@@ -704,87 +704,3 @@ Required argument '--exact' received no value"""
|
||||
// Again, we don't try to detect that the user has missed out the desired argument to `--a`.
|
||||
exc.Message
|
||||
|> shouldEqual """Unable to process argument --c=hi as key --c and value hi"""
|
||||
|
||||
[<Test>]
|
||||
let ``Type-level help text appears in help output`` () =
|
||||
let getEnvVar (_ : string) = None
|
||||
|
||||
let exc =
|
||||
Assert.Throws<exn> (fun () -> WithTypeHelp.parse' getEnvVar [ "--help" ] |> ignore<WithTypeHelp>)
|
||||
|
||||
exc.Message
|
||||
|> shouldContainText
|
||||
"Parse command-line arguments for a basic configuration. This help text appears before the argument list."
|
||||
|
||||
exc.Message
|
||||
|> shouldContainText "--config-file string : The configuration file path"
|
||||
|
||||
exc.Message |> shouldContainText "--verbose bool : Enable verbose output"
|
||||
exc.Message |> shouldContainText "--port int32"
|
||||
|
||||
[<Test>]
|
||||
let ``Type-level help text appears before field help`` () =
|
||||
let getEnvVar (_ : string) = None
|
||||
|
||||
let exc =
|
||||
Assert.Throws<exn> (fun () -> WithTypeHelp.parse' getEnvVar [ "--help" ] |> ignore<WithTypeHelp>)
|
||||
|
||||
// Verify that the type help appears before the field help
|
||||
let typeHelpIndex =
|
||||
exc.Message.IndexOf "Parse command-line arguments for a basic configuration"
|
||||
|
||||
let fieldHelpIndex = exc.Message.IndexOf "--config-file"
|
||||
|
||||
typeHelpIndex |> shouldBeSmallerThan fieldHelpIndex
|
||||
|
||||
[<Test>]
|
||||
let ``Multiline type-level help text works`` () =
|
||||
let getEnvVar (_ : string) = None
|
||||
|
||||
let exc =
|
||||
Assert.Throws<exn> (fun () ->
|
||||
WithMultilineTypeHelp.parse' getEnvVar [ "--help" ]
|
||||
|> ignore<WithMultilineTypeHelp>
|
||||
)
|
||||
|
||||
exc.Message |> shouldContainText "This is a multiline help text example."
|
||||
|
||||
exc.Message
|
||||
|> shouldContainText "It spans multiple lines to test that multiline strings work correctly."
|
||||
|
||||
exc.Message
|
||||
|> shouldContainText "You can use this to provide detailed documentation for your argument parser."
|
||||
|
||||
exc.Message |> shouldContainText "--input-file string : Input file to process"
|
||||
exc.Message |> shouldContainText "--output-dir string : Output directory"
|
||||
exc.Message |> shouldContainText "--force bool"
|
||||
|
||||
[<Test>]
|
||||
let ``Type-level help text appears in error messages`` () =
|
||||
let getEnvVar (_ : string) = None
|
||||
|
||||
let exc =
|
||||
Assert.Throws<exn> (fun () ->
|
||||
WithTypeHelp.parse' getEnvVar [ "--unknown-arg" ; "value" ]
|
||||
|> ignore<WithTypeHelp>
|
||||
)
|
||||
|
||||
// Verify that the type help appears in error messages too
|
||||
exc.Message
|
||||
|> shouldContainText
|
||||
"Parse command-line arguments for a basic configuration. This help text appears before the argument list."
|
||||
|
||||
exc.Message |> shouldContainText "--config-file"
|
||||
|
||||
[<Test>]
|
||||
let ``Types without type-level help still work`` () =
|
||||
let getEnvVar (_ : string) = None
|
||||
|
||||
let exc =
|
||||
Assert.Throws<exn> (fun () -> Basic.parse' getEnvVar [ "--help" ] |> ignore<Basic>)
|
||||
|
||||
// Should not contain any type-level help, just the field help
|
||||
exc.Message |> shouldContainText "--foo int32 : This is a foo!"
|
||||
exc.Message |> shouldContainText "--bar string"
|
||||
// Make sure there's no extra blank line at the beginning
|
||||
exc.Message.StartsWith '\n' |> shouldEqual false
|
||||
|
||||
@@ -1,372 +0,0 @@
|
||||
namespace WoofWare.Myriad.Plugins.Test
|
||||
|
||||
open System.Threading
|
||||
open NUnit.Framework
|
||||
open FsUnitTyped
|
||||
open ConsumePlugin
|
||||
|
||||
[<TestFixture>]
|
||||
module TestArgParserNegation =
|
||||
|
||||
[<Test>]
|
||||
let ``Boolean field with ArgumentNegateWithPrefix: --foo sets to true`` () =
|
||||
let getEnvVar (_ : string) = failwith "should not call"
|
||||
|
||||
let result = BoolNegation.parse' getEnvVar [ "--enable-feature" ]
|
||||
|
||||
result.EnableFeature |> shouldEqual true
|
||||
|
||||
[<Test>]
|
||||
let ``Boolean field with ArgumentNegateWithPrefix: --foo=true sets to true`` () =
|
||||
let getEnvVar (_ : string) = failwith "should not call"
|
||||
|
||||
let result = BoolNegation.parse' getEnvVar [ "--enable-feature=true" ]
|
||||
|
||||
result.EnableFeature |> shouldEqual true
|
||||
|
||||
[<Test>]
|
||||
let ``Boolean field with ArgumentNegateWithPrefix: --foo true sets to true`` () =
|
||||
let getEnvVar (_ : string) = failwith "should not call"
|
||||
|
||||
let result = BoolNegation.parse' getEnvVar [ "--enable-feature" ; "true" ]
|
||||
|
||||
result.EnableFeature |> shouldEqual true
|
||||
|
||||
[<Test>]
|
||||
let ``Boolean field with ArgumentNegateWithPrefix: --foo=false sets to false`` () =
|
||||
let getEnvVar (_ : string) = failwith "should not call"
|
||||
|
||||
let result = BoolNegation.parse' getEnvVar [ "--enable-feature=false" ]
|
||||
|
||||
result.EnableFeature |> shouldEqual false
|
||||
|
||||
[<Test>]
|
||||
let ``Boolean field with ArgumentNegateWithPrefix: --foo false sets to false`` () =
|
||||
let getEnvVar (_ : string) = failwith "should not call"
|
||||
|
||||
let result = BoolNegation.parse' getEnvVar [ "--enable-feature" ; "false" ]
|
||||
|
||||
result.EnableFeature |> shouldEqual false
|
||||
|
||||
[<Test>]
|
||||
let ``Boolean field with ArgumentNegateWithPrefix: --no-foo sets to false`` () =
|
||||
let getEnvVar (_ : string) = failwith "should not call"
|
||||
|
||||
let result = BoolNegation.parse' getEnvVar [ "--no-enable-feature" ]
|
||||
|
||||
result.EnableFeature |> shouldEqual false
|
||||
|
||||
[<Test>]
|
||||
let ``Boolean field with ArgumentNegateWithPrefix: --no-foo=true sets to false`` () =
|
||||
let getEnvVar (_ : string) = failwith "should not call"
|
||||
|
||||
let result = BoolNegation.parse' getEnvVar [ "--no-enable-feature=true" ]
|
||||
|
||||
result.EnableFeature |> shouldEqual false
|
||||
|
||||
[<Test>]
|
||||
let ``Boolean field with ArgumentNegateWithPrefix: --no-foo true sets to false`` () =
|
||||
let getEnvVar (_ : string) = failwith "should not call"
|
||||
|
||||
let result = BoolNegation.parse' getEnvVar [ "--no-enable-feature" ; "true" ]
|
||||
|
||||
result.EnableFeature |> shouldEqual false
|
||||
|
||||
[<Test>]
|
||||
let ``Boolean field with ArgumentNegateWithPrefix: --no-foo=false sets to true`` () =
|
||||
let getEnvVar (_ : string) = failwith "should not call"
|
||||
|
||||
let result = BoolNegation.parse' getEnvVar [ "--no-enable-feature=false" ]
|
||||
|
||||
result.EnableFeature |> shouldEqual true
|
||||
|
||||
[<Test>]
|
||||
let ``Boolean field with ArgumentNegateWithPrefix: --no-foo false sets to true`` () =
|
||||
let getEnvVar (_ : string) = failwith "should not call"
|
||||
|
||||
let result = BoolNegation.parse' getEnvVar [ "--no-enable-feature" ; "false" ]
|
||||
|
||||
result.EnableFeature |> shouldEqual true
|
||||
|
||||
[<Test>]
|
||||
let ``Flag DU with ArgumentNegateWithPrefix: --dry-run sets to Dry`` () =
|
||||
let getEnvVar (_ : string) = failwith "should not call"
|
||||
|
||||
let result = FlagNegation.parse' getEnvVar [ "--dry-run" ]
|
||||
|
||||
result.DryRun |> shouldEqual TestDryRunMode.Dry
|
||||
|
||||
[<Test>]
|
||||
let ``Flag DU with ArgumentNegateWithPrefix: --dry-run=true sets to Dry`` () =
|
||||
let getEnvVar (_ : string) = failwith "should not call"
|
||||
|
||||
let result = FlagNegation.parse' getEnvVar [ "--dry-run=true" ]
|
||||
|
||||
result.DryRun |> shouldEqual TestDryRunMode.Dry
|
||||
|
||||
[<Test>]
|
||||
let ``Flag DU with ArgumentNegateWithPrefix: --dry-run true sets to Dry`` () =
|
||||
let getEnvVar (_ : string) = failwith "should not call"
|
||||
|
||||
let result = FlagNegation.parse' getEnvVar [ "--dry-run" ; "true" ]
|
||||
|
||||
result.DryRun |> shouldEqual TestDryRunMode.Dry
|
||||
|
||||
[<Test>]
|
||||
let ``Flag DU with ArgumentNegateWithPrefix: --dry-run=false sets to Wet`` () =
|
||||
let getEnvVar (_ : string) = failwith "should not call"
|
||||
|
||||
let result = FlagNegation.parse' getEnvVar [ "--dry-run=false" ]
|
||||
|
||||
result.DryRun |> shouldEqual TestDryRunMode.Wet
|
||||
|
||||
[<Test>]
|
||||
let ``Flag DU with ArgumentNegateWithPrefix: --dry-run false sets to Wet`` () =
|
||||
let getEnvVar (_ : string) = failwith "should not call"
|
||||
|
||||
let result = FlagNegation.parse' getEnvVar [ "--dry-run" ; "false" ]
|
||||
|
||||
result.DryRun |> shouldEqual TestDryRunMode.Wet
|
||||
|
||||
[<Test>]
|
||||
let ``Flag DU with ArgumentNegateWithPrefix: --no-dry-run sets to Wet`` () =
|
||||
let getEnvVar (_ : string) = failwith "should not call"
|
||||
|
||||
let result = FlagNegation.parse' getEnvVar [ "--no-dry-run" ]
|
||||
|
||||
result.DryRun |> shouldEqual TestDryRunMode.Wet
|
||||
|
||||
[<Test>]
|
||||
let ``Flag DU with ArgumentNegateWithPrefix: --no-dry-run=true sets to Wet`` () =
|
||||
let getEnvVar (_ : string) = failwith "should not call"
|
||||
|
||||
let result = FlagNegation.parse' getEnvVar [ "--no-dry-run=true" ]
|
||||
|
||||
result.DryRun |> shouldEqual TestDryRunMode.Wet
|
||||
|
||||
[<Test>]
|
||||
let ``Flag DU with ArgumentNegateWithPrefix: --no-dry-run true sets to Wet`` () =
|
||||
let getEnvVar (_ : string) = failwith "should not call"
|
||||
|
||||
let result = FlagNegation.parse' getEnvVar [ "--no-dry-run" ; "true" ]
|
||||
|
||||
result.DryRun |> shouldEqual TestDryRunMode.Wet
|
||||
|
||||
[<Test>]
|
||||
let ``Flag DU with ArgumentNegateWithPrefix: --no-dry-run=false sets to Dry`` () =
|
||||
let getEnvVar (_ : string) = failwith "should not call"
|
||||
|
||||
let result = FlagNegation.parse' getEnvVar [ "--no-dry-run=false" ]
|
||||
|
||||
result.DryRun |> shouldEqual TestDryRunMode.Dry
|
||||
|
||||
[<Test>]
|
||||
let ``Flag DU with ArgumentNegateWithPrefix: --no-dry-run false sets to Dry`` () =
|
||||
let getEnvVar (_ : string) = failwith "should not call"
|
||||
|
||||
let result = FlagNegation.parse' getEnvVar [ "--no-dry-run" ; "false" ]
|
||||
|
||||
result.DryRun |> shouldEqual TestDryRunMode.Dry
|
||||
|
||||
[<Test>]
|
||||
let ``ArgumentNegateWithPrefix works with multiple ArgumentLongForm: --verbose`` () =
|
||||
let getEnvVar (_ : string) = failwith "should not call"
|
||||
|
||||
let result = MultipleFormsNegation.parse' getEnvVar [ "--verbose" ]
|
||||
|
||||
result.VerboseMode |> shouldEqual true
|
||||
|
||||
[<Test>]
|
||||
let ``ArgumentNegateWithPrefix works with multiple ArgumentLongForm: --v`` () =
|
||||
let getEnvVar (_ : string) = failwith "should not call"
|
||||
|
||||
let result = MultipleFormsNegation.parse' getEnvVar [ "--v" ]
|
||||
|
||||
result.VerboseMode |> shouldEqual true
|
||||
|
||||
[<Test>]
|
||||
let ``ArgumentNegateWithPrefix works with multiple ArgumentLongForm: --no-verbose`` () =
|
||||
let getEnvVar (_ : string) = failwith "should not call"
|
||||
|
||||
let result = MultipleFormsNegation.parse' getEnvVar [ "--no-verbose" ]
|
||||
|
||||
result.VerboseMode |> shouldEqual false
|
||||
|
||||
[<Test>]
|
||||
let ``ArgumentNegateWithPrefix works with multiple ArgumentLongForm: --no-v`` () =
|
||||
let getEnvVar (_ : string) = failwith "should not call"
|
||||
|
||||
let result = MultipleFormsNegation.parse' getEnvVar [ "--no-v" ]
|
||||
|
||||
result.VerboseMode |> shouldEqual false
|
||||
|
||||
[<Test>]
|
||||
let ``ArgumentNegateWithPrefix works with multiple ArgumentLongForm: --verbose=false`` () =
|
||||
let getEnvVar (_ : string) = failwith "should not call"
|
||||
|
||||
let result = MultipleFormsNegation.parse' getEnvVar [ "--verbose=false" ]
|
||||
|
||||
result.VerboseMode |> shouldEqual false
|
||||
|
||||
[<Test>]
|
||||
let ``ArgumentNegateWithPrefix works with multiple ArgumentLongForm: --no-v=false`` () =
|
||||
let getEnvVar (_ : string) = failwith "should not call"
|
||||
|
||||
let result = MultipleFormsNegation.parse' getEnvVar [ "--no-v=false" ]
|
||||
|
||||
result.VerboseMode |> shouldEqual true
|
||||
|
||||
[<Test>]
|
||||
let ``Help text shows both standard and negated forms for boolean`` () =
|
||||
let getEnvVar (_ : string) = failwith "do not call"
|
||||
|
||||
let exc =
|
||||
Assert.Throws<exn> (fun () -> BoolNegation.parse' getEnvVar [ "--help" ] |> ignore<BoolNegation>)
|
||||
|
||||
exc.Message
|
||||
|> shouldEqual
|
||||
"""Help text requested.
|
||||
--enable-feature / --no-enable-feature bool"""
|
||||
|
||||
[<Test>]
|
||||
let ``Help text shows both standard and negated forms for flag DU`` () =
|
||||
let getEnvVar (_ : string) = failwith "do not call"
|
||||
|
||||
let exc =
|
||||
Assert.Throws<exn> (fun () -> FlagNegation.parse' getEnvVar [ "--help" ] |> ignore<FlagNegation>)
|
||||
|
||||
exc.Message
|
||||
|> shouldEqual
|
||||
"""Help text requested.
|
||||
--dry-run / --no-dry-run bool"""
|
||||
|
||||
[<Test>]
|
||||
let ``Help text with multiple long forms shows all variants`` () =
|
||||
let getEnvVar (_ : string) = failwith "do not call"
|
||||
|
||||
let exc =
|
||||
Assert.Throws<exn> (fun () ->
|
||||
MultipleFormsNegation.parse' getEnvVar [ "--help" ]
|
||||
|> ignore<MultipleFormsNegation>
|
||||
)
|
||||
|
||||
exc.Message
|
||||
|> shouldEqual
|
||||
"""Help text requested.
|
||||
--verbose / --v / --no-verbose / --no-v bool"""
|
||||
|
||||
[<Test>]
|
||||
let ``Multiple occurrences error: --foo and --no-foo both supplied`` () =
|
||||
let getEnvVar (_ : string) = failwith "should not call"
|
||||
|
||||
let exc =
|
||||
Assert.Throws<exn> (fun () ->
|
||||
BoolNegation.parse' getEnvVar [ "--enable-feature" ; "--no-enable-feature" ]
|
||||
|> ignore<BoolNegation>
|
||||
)
|
||||
|
||||
// Should report as duplicate argument
|
||||
exc.Message |> shouldContainText "supplied multiple times"
|
||||
|
||||
[<Test>]
|
||||
let ``Multiple occurrences error: --no-foo and --foo both supplied`` () =
|
||||
let getEnvVar (_ : string) = failwith "should not call"
|
||||
|
||||
let exc =
|
||||
Assert.Throws<exn> (fun () ->
|
||||
BoolNegation.parse' getEnvVar [ "--no-enable-feature" ; "--enable-feature" ]
|
||||
|> ignore<BoolNegation>
|
||||
)
|
||||
|
||||
// Should report as duplicate argument
|
||||
exc.Message |> shouldContainText "supplied multiple times"
|
||||
|
||||
[<Test>]
|
||||
let ``Multiple occurrences error: --foo=true and --no-foo=false both supplied`` () =
|
||||
let getEnvVar (_ : string) = failwith "should not call"
|
||||
|
||||
let exc =
|
||||
Assert.Throws<exn> (fun () ->
|
||||
BoolNegation.parse' getEnvVar [ "--enable-feature=true" ; "--no-enable-feature=false" ]
|
||||
|> ignore<BoolNegation>
|
||||
)
|
||||
|
||||
// Should report as duplicate argument
|
||||
exc.Message |> shouldContainText "supplied multiple times"
|
||||
|
||||
[<Test>]
|
||||
let ``CombinedFeatures: verbose with default value works with negation`` () =
|
||||
let getEnvVar (_ : string) = failwith "should not call"
|
||||
|
||||
let result = CombinedFeatures.parse' getEnvVar [ "--debug" ; "--normal-bool" ]
|
||||
|
||||
result.Verbose |> shouldEqual (Choice2Of2 false)
|
||||
result.Debug |> shouldEqual true
|
||||
result.NormalBool |> shouldEqual true
|
||||
|
||||
[<Test>]
|
||||
let ``CombinedFeatures: can override default with --verbose`` () =
|
||||
let getEnvVar (_ : string) = failwith "should not call"
|
||||
|
||||
let result =
|
||||
CombinedFeatures.parse' getEnvVar [ "--verbose" ; "--debug" ; "--normal-bool" ]
|
||||
|
||||
result.Verbose |> shouldEqual (Choice1Of2 true)
|
||||
result.Debug |> shouldEqual true
|
||||
result.NormalBool |> shouldEqual true
|
||||
|
||||
[<Test>]
|
||||
let ``CombinedFeatures: can override default with --no-verbose`` () =
|
||||
let getEnvVar (_ : string) = failwith "should not call"
|
||||
|
||||
let result =
|
||||
CombinedFeatures.parse' getEnvVar [ "--no-verbose" ; "--debug" ; "--normal-bool" ]
|
||||
|
||||
result.Verbose |> shouldEqual (Choice1Of2 false)
|
||||
result.Debug |> shouldEqual true
|
||||
result.NormalBool |> shouldEqual true
|
||||
|
||||
[<Test>]
|
||||
let ``CombinedFeatures: --no-debug sets debug to false`` () =
|
||||
let getEnvVar (_ : string) = failwith "should not call"
|
||||
|
||||
let result = CombinedFeatures.parse' getEnvVar [ "--no-debug" ; "--normal-bool" ]
|
||||
|
||||
result.Debug |> shouldEqual false
|
||||
|
||||
[<Test>]
|
||||
let ``CombinedFeatures: help text shows negation for fields with attribute`` () =
|
||||
let getEnvVar (_ : string) = failwith "do not call"
|
||||
|
||||
let exc =
|
||||
Assert.Throws<exn> (fun () -> CombinedFeatures.parse' getEnvVar [ "--help" ] |> ignore<CombinedFeatures>)
|
||||
|
||||
// Verbose and Debug should have --no- forms, NormalBool should not
|
||||
exc.Message |> shouldContainText "--verbose / --no-verbose"
|
||||
exc.Message |> shouldContainText "--debug / --no-debug"
|
||||
exc.Message |> shouldContainText "--normal-bool bool"
|
||||
exc.Message |> shouldNotContainText "--no-normal-bool"
|
||||
|
||||
[<Test>]
|
||||
let ``Case insensitivity: --NO-ENABLE-FEATURE works`` () =
|
||||
let getEnvVar (_ : string) = failwith "should not call"
|
||||
|
||||
let result = BoolNegation.parse' getEnvVar [ "--NO-ENABLE-FEATURE" ]
|
||||
|
||||
result.EnableFeature |> shouldEqual false
|
||||
|
||||
[<Test>]
|
||||
let ``Case insensitivity: --No-Enable-Feature works`` () =
|
||||
let getEnvVar (_ : string) = failwith "should not call"
|
||||
|
||||
let result = BoolNegation.parse' getEnvVar [ "--No-Enable-Feature" ]
|
||||
|
||||
result.EnableFeature |> shouldEqual false
|
||||
|
||||
[<Test>]
|
||||
let ``Case insensitivity: --NO-DRY-RUN works`` () =
|
||||
let getEnvVar (_ : string) = failwith "should not call"
|
||||
|
||||
let result = FlagNegation.parse' getEnvVar [ "--NO-DRY-RUN" ]
|
||||
|
||||
result.DryRun |> shouldEqual TestDryRunMode.Wet
|
||||
@@ -1,132 +0,0 @@
|
||||
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"
|
||||
}
|
||||
|
||||
let mock = mock' :> Curried<_>
|
||||
|
||||
mock.Mem1 3 "hello" |> shouldEqual "it's me"
|
||||
|
||||
lock mock'.Calls.Mem1 (fun () -> Seq.toList mock'.Calls.Mem1)
|
||||
|> List.exactlyOne
|
||||
|> shouldEqual
|
||||
{
|
||||
bar = 3
|
||||
Arg1 = "hello"
|
||||
}
|
||||
|
||||
[<Test>]
|
||||
let ``Example of use IAsyncDisposable`` () =
|
||||
let mock' =
|
||||
{ TypeWithAsyncDisposableMock.Empty () with
|
||||
Mem1 = fun i -> async { return Option.toArray i }
|
||||
Mem2 = fun () -> async { return [||] }
|
||||
}
|
||||
|
||||
let mock = mock' :> TypeWithAsyncDisposable
|
||||
|
||||
mock.Mem1 (Some "hi") |> Async.RunSynchronously |> shouldEqual [| "hi" |]
|
||||
mock.Mem2 () |> Async.RunSynchronously |> shouldEqual [||]
|
||||
|
||||
// Test that DisposeAsync returns a completed ValueTask
|
||||
let asyncDisposable = mock :> IAsyncDisposable
|
||||
let valueTask = asyncDisposable.DisposeAsync ()
|
||||
valueTask.IsCompleted |> shouldEqual true
|
||||
|
||||
// Verify calls were captured
|
||||
lock mock'.Calls.Mem1 (fun () -> Seq.toList mock'.Calls.Mem1)
|
||||
|> List.exactlyOne
|
||||
|> shouldEqual (Some "hi")
|
||||
|
||||
lock mock'.Calls.Mem2 (fun () -> Seq.toList mock'.Calls.Mem2)
|
||||
|> List.exactlyOne
|
||||
|> shouldEqual ()
|
||||
|
||||
[<Test>]
|
||||
let ``Example of use: Both IDisposable and IAsyncDisposable`` () =
|
||||
let mutable disposed = false
|
||||
let mutable disposedAsync = false
|
||||
|
||||
let mock' =
|
||||
{ TypeWithBothDisposablesMock.Empty () with
|
||||
Dispose = fun () -> disposed <- true
|
||||
DisposeAsync =
|
||||
fun () ->
|
||||
disposedAsync <- true
|
||||
System.Threading.Tasks.ValueTask ()
|
||||
Mem1 = fun s -> s.Length
|
||||
}
|
||||
|
||||
let mock = mock' :> TypeWithBothDisposables
|
||||
|
||||
mock.Mem1 "hello" |> shouldEqual 5
|
||||
mock.Mem1 "world" |> shouldEqual 5
|
||||
|
||||
// Test IDisposable.Dispose
|
||||
(mock :> IDisposable).Dispose ()
|
||||
disposed |> shouldEqual true
|
||||
|
||||
// Test IAsyncDisposable.DisposeAsync
|
||||
let valueTask = (mock :> IAsyncDisposable).DisposeAsync ()
|
||||
valueTask.IsCompleted |> shouldEqual true
|
||||
disposedAsync |> shouldEqual true
|
||||
|
||||
// Verify calls were captured
|
||||
lock mock'.Calls.Mem1 (fun () -> Seq.toList mock'.Calls.Mem1)
|
||||
|> shouldEqual [ "hello" ; "world" ]
|
||||
@@ -1,36 +0,0 @@
|
||||
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"
|
||||
@@ -1,51 +0,0 @@
|
||||
namespace WoofWare.Myriad.Plugins.Test
|
||||
|
||||
open System.Threading
|
||||
open NUnit.Framework
|
||||
open FsUnitTyped
|
||||
open ConsumePluginNoAttr
|
||||
open FsCheck
|
||||
|
||||
[<TestFixture>]
|
||||
module TestCataGeneratorNoAttr =
|
||||
let idCata<'a, 'b> : TreeNoAttrCata<'a, 'b, _, _> =
|
||||
{
|
||||
TreeNoAttr =
|
||||
{ new TreeNoAttrCataCase<_, _, _, _> with
|
||||
member _.Const x y = Const (x, y)
|
||||
member _.Pair x y z = Pair (x, y, z)
|
||||
member _.Sequential xs = Sequential xs
|
||||
member _.Builder x b = Builder (x, b)
|
||||
}
|
||||
TreeBuilderNoAttr =
|
||||
{ new TreeBuilderNoAttrCataCase<_, _, _, _> with
|
||||
member _.Child x = Child x
|
||||
member _.Parent x = Parent x
|
||||
}
|
||||
}
|
||||
|
||||
[<Test>]
|
||||
let ``Example`` () =
|
||||
let x =
|
||||
TreeNoAttr.Pair (
|
||||
TreeNoAttr.Const (ConstNoAttr.Verbatim 0, "hi"),
|
||||
TreeNoAttr.Const (ConstNoAttr.String "", "bye"),
|
||||
PairOpKindNoAttr.ThenDoSeq
|
||||
)
|
||||
|
||||
TreeNoAttrCata.runTreeNoAttr idCata x |> shouldEqual x
|
||||
|
||||
|
||||
[<Test>]
|
||||
let ``Cata works`` () =
|
||||
let builderCases = ref 0
|
||||
|
||||
let property (x : TreeNoAttr<int, string>) =
|
||||
match x with
|
||||
| TreeNoAttr.Builder _ -> Interlocked.Increment builderCases |> ignore
|
||||
| _ -> ()
|
||||
|
||||
TreeNoAttrCata.runTreeNoAttr idCata x = x
|
||||
|
||||
Check.QuickThrowOnFailure property
|
||||
builderCases.Value |> shouldBeGreaterThan 10
|
||||
@@ -47,45 +47,3 @@ module TestMockGenerator =
|
||||
mock.Mem1 (Some "hi") |> Async.RunSynchronously |> shouldEqual [| "hi" |]
|
||||
|
||||
mock.Prop1 |> shouldEqual 44
|
||||
|
||||
[<Test>]
|
||||
let ``Example of use: IAsyncDisposable`` () =
|
||||
let mock : TypeWithAsyncDisposable =
|
||||
{ TypeWithAsyncDisposableMock.Empty with
|
||||
Mem1 = fun i -> async { return Option.toArray i }
|
||||
}
|
||||
:> _
|
||||
|
||||
mock.Mem1 (Some "hi") |> Async.RunSynchronously |> shouldEqual [| "hi" |]
|
||||
|
||||
// Test that DisposeAsync returns a completed ValueTask
|
||||
let asyncDisposable = mock :> IAsyncDisposable
|
||||
let valueTask = asyncDisposable.DisposeAsync ()
|
||||
valueTask.IsCompleted |> shouldEqual true
|
||||
|
||||
[<Test>]
|
||||
let ``Example of use: Both IDisposable and IAsyncDisposable`` () =
|
||||
let mutable disposed = false
|
||||
let mutable disposedAsync = false
|
||||
|
||||
let mock : TypeWithBothDisposables =
|
||||
{ TypeWithBothDisposablesMock.Empty with
|
||||
Dispose = fun () -> disposed <- true
|
||||
DisposeAsync =
|
||||
fun () ->
|
||||
disposedAsync <- true
|
||||
System.Threading.Tasks.ValueTask ()
|
||||
Mem1 = fun s -> s.Length
|
||||
}
|
||||
:> _
|
||||
|
||||
mock.Mem1 "hello" |> shouldEqual 5
|
||||
|
||||
// Test IDisposable.Dispose
|
||||
(mock :> IDisposable).Dispose ()
|
||||
disposed |> shouldEqual true
|
||||
|
||||
// Test IAsyncDisposable.DisposeAsync
|
||||
let valueTask = (mock :> IAsyncDisposable).DisposeAsync ()
|
||||
valueTask.IsCompleted |> shouldEqual true
|
||||
disposedAsync |> shouldEqual true
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
I have not yet seen a single instance where I care about this warning
|
||||
-->
|
||||
<NoWarn>$(NoWarn),NU1903</NoWarn>
|
||||
<TestingPlatformDotnetTestSupport>true</TestingPlatformDotnetTestSupport>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -28,17 +29,13 @@
|
||||
<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\TestCataGeneratorNoAttr.fs" />
|
||||
<Compile Include="TestCataGenerator\TestDirectory.fs" />
|
||||
<Compile Include="TestCataGenerator\TestGift.fs" />
|
||||
<Compile Include="TestCataGenerator\TestMyList.fs" />
|
||||
<Compile Include="TestCataGenerator\TestMyList2.fs" />
|
||||
<Compile Include="TestArgParser\TestArgParser.fs" />
|
||||
<Compile Include="TestArgParser\TestArgParserNegation.fs" />
|
||||
<Compile Include="TestSwagger\TestSwaggerParse.fs" />
|
||||
<Compile Include="TestSwagger\TestOpenApi3Parse.fs" />
|
||||
<EmbeddedResource Include="TestSwagger\api-with-examples.json" />
|
||||
@@ -56,13 +53,13 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ApiSurface" Version="5.0.3" />
|
||||
<PackageReference Include="FsCheck" Version="3.3.2" />
|
||||
<PackageReference Include="ApiSurface" Version="4.1.22" />
|
||||
<PackageReference Include="FsCheck" Version="3.3.0" />
|
||||
<PackageReference Include="FsUnit" Version="7.1.1" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
|
||||
<PackageReference Include="NUnit" Version="4.3.2" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="5.2.0" />
|
||||
<PackageReference Include="WoofWare.Expect" Version="0.8.5" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
|
||||
<PackageReference Include="NUnit" Version="4.4.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="5.0.0" />
|
||||
<PackageReference Include="WoofWare.Expect" Version="0.8.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -72,38 +72,16 @@ type private ParseFunction<'acc> =
|
||||
/// and choices and so on.
|
||||
TargetType : SynType
|
||||
Accumulation : 'acc
|
||||
/// If true, this boolean/flag field accepts --no- prefix for negation (has [<ArgumentNegateWithPrefix>])
|
||||
AcceptsNegation : bool
|
||||
}
|
||||
|
||||
/// A SynExpr of type `string` which we can display to the user at generated-program runtime to display all
|
||||
/// the ways they can refer to this arg.
|
||||
member arg.HumanReadableArgForm : SynExpr =
|
||||
if arg.AcceptsNegation then
|
||||
// Include both standard and --no- variants
|
||||
// E.g., "--foo / --bar / --no-foo / --no-bar"
|
||||
let standardFormatString =
|
||||
List.replicate arg.ArgForm.Length "--%s" |> String.concat " / "
|
||||
let formatString = List.replicate arg.ArgForm.Length "--%s" |> String.concat " / "
|
||||
|
||||
let negatedFormatString =
|
||||
List.replicate arg.ArgForm.Length "--no-%s" |> String.concat " / "
|
||||
|
||||
let combinedFormatString = standardFormatString + " / " + negatedFormatString
|
||||
|
||||
// Apply all arg forms twice (once for standard, once for negated)
|
||||
let allArgForms = arg.ArgForm @ arg.ArgForm
|
||||
|
||||
(SynExpr.applyFunction (SynExpr.createIdent "sprintf") (SynExpr.CreateConst combinedFormatString),
|
||||
allArgForms)
|
||||
||> List.fold SynExpr.applyFunction
|
||||
|> SynExpr.paren
|
||||
else
|
||||
// Standard behavior: just --foo / --bar
|
||||
let formatString = List.replicate arg.ArgForm.Length "--%s" |> String.concat " / "
|
||||
|
||||
(SynExpr.applyFunction (SynExpr.createIdent "sprintf") (SynExpr.CreateConst formatString), arg.ArgForm)
|
||||
||> List.fold SynExpr.applyFunction
|
||||
|> SynExpr.paren
|
||||
(SynExpr.applyFunction (SynExpr.createIdent "sprintf") (SynExpr.CreateConst formatString), arg.ArgForm)
|
||||
||> List.fold SynExpr.applyFunction
|
||||
|> SynExpr.paren
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
type private ChoicePositional =
|
||||
@@ -244,8 +222,8 @@ module private ParseTree =
|
||||
nonPos @ nonPos2, Some pos
|
||||
|
||||
|> fun (nonPos, pos) ->
|
||||
// Extract all arg form strings for validation
|
||||
let allArgForms =
|
||||
let duplicateArgs =
|
||||
// This is best-effort. We can't necessarily detect all SynExprs here, but usually it'll be strings.
|
||||
Option.toList (pos |> Option.map _.ArgForm) @ (nonPos |> List.map _.ArgForm)
|
||||
|> Seq.concat
|
||||
|> Seq.choose (fun expr ->
|
||||
@@ -254,57 +232,14 @@ module private ParseTree =
|
||||
| _ -> None
|
||||
)
|
||||
|> List.ofSeq
|
||||
|
||||
// Check for direct duplicates
|
||||
let duplicateArgs =
|
||||
allArgForms
|
||||
|> List.groupBy id
|
||||
|> List.choose (fun (key, v) -> if v.Length > 1 then Some key else None)
|
||||
|
||||
match duplicateArgs with
|
||||
| dups when not dups.IsEmpty ->
|
||||
| [] -> nonPos, pos
|
||||
| dups ->
|
||||
let dups = dups |> String.concat " "
|
||||
failwith $"Duplicate args detected! %s{dups}"
|
||||
| _ ->
|
||||
|
||||
// Check for --no- prefix conflicts
|
||||
// Build a map of arg names that have AcceptsNegation=true
|
||||
let negatedForms =
|
||||
nonPos
|
||||
|> List.filter _.AcceptsNegation
|
||||
|> List.collect (fun pf ->
|
||||
pf.ArgForm
|
||||
|> List.choose (fun expr ->
|
||||
match expr |> SynExpr.stripOptionalParen with
|
||||
| SynExpr.Const (SynConst.String (s, _, _), _) -> Some (pf.FieldName.idText, s)
|
||||
| _ -> None
|
||||
)
|
||||
)
|
||||
|> List.map (fun (fieldName, argForm) -> $"no-%s{argForm}", fieldName)
|
||||
|> Map.ofList
|
||||
|
||||
// Check if any existing arg form conflicts with a --no- variant
|
||||
let conflicts =
|
||||
allArgForms
|
||||
|> List.choose (fun argForm ->
|
||||
match negatedForms.TryFind argForm with
|
||||
| Some fieldWithNegation -> Some (argForm, fieldWithNegation)
|
||||
| None -> None
|
||||
)
|
||||
|
||||
match conflicts with
|
||||
| [] -> ()
|
||||
| conflicts ->
|
||||
let conflictMessages =
|
||||
conflicts
|
||||
|> List.map (fun (argForm, fieldWithNegation) ->
|
||||
$"Argument name conflict: '--%s{argForm}' collides with the --no- variant of field '%s{fieldWithNegation}' (which has [<ArgumentNegateWithPrefix>])"
|
||||
)
|
||||
|> String.concat "\n"
|
||||
|
||||
failwith $"Conflicting argument names detected:\n%s{conflictMessages}"
|
||||
|
||||
nonPos, pos
|
||||
|
||||
/// Build the return value.
|
||||
let rec instantiate<'a> (tree : ParseTree<'a>) : SynExpr =
|
||||
@@ -680,7 +615,6 @@ module internal ArgParserGenerator =
|
||||
ArgForm = longForms
|
||||
Help = helpText
|
||||
BoolCases = isBoolLike
|
||||
AcceptsNegation = false
|
||||
}
|
||||
|> fun t -> ParseTree.PositionalLeaf (t, Teq.refl)
|
||||
| Accumulation.List Accumulation.Required ->
|
||||
@@ -693,7 +627,6 @@ module internal ArgParserGenerator =
|
||||
ArgForm = longForms
|
||||
Help = helpText
|
||||
BoolCases = isBoolLike
|
||||
AcceptsNegation = false
|
||||
}
|
||||
|> fun t -> ParseTree.PositionalLeaf (t, Teq.refl)
|
||||
| Accumulation.Choice _
|
||||
@@ -718,27 +651,6 @@ module internal ArgParserGenerator =
|
||||
Some (Choice2Of2 ())
|
||||
| parseTy -> identifyAsFlag flagDus parseTy |> Option.map Choice1Of2
|
||||
|
||||
let hasNegateAttr =
|
||||
attrs
|
||||
|> List.exists (fun attr ->
|
||||
match attr.TypeName with
|
||||
| SynLongIdent.SynLongIdent (ident, _, _) ->
|
||||
match (List.last ident).idText with
|
||||
| "ArgumentNegateWithPrefixAttribute"
|
||||
| "ArgumentNegateWithPrefix" -> true
|
||||
| _ -> false
|
||||
)
|
||||
|
||||
let acceptsNegation =
|
||||
if hasNegateAttr then
|
||||
match isBoolLike with
|
||||
| Some _ -> true
|
||||
| None ->
|
||||
failwith
|
||||
$"[<ArgumentNegateWithPrefix>] can only be applied to boolean or flag DU fields, but was applied to field %s{ident.idText} of type %O{fieldType}"
|
||||
else
|
||||
false
|
||||
|
||||
{
|
||||
FieldName = ident
|
||||
Parser = parser
|
||||
@@ -748,7 +660,6 @@ module internal ArgParserGenerator =
|
||||
ArgForm = longForms
|
||||
Help = helpText
|
||||
BoolCases = isBoolLike
|
||||
AcceptsNegation = acceptsNegation
|
||||
}
|
||||
|> fun t -> ParseTree.NonPositionalLeaf (t, Teq.refl)
|
||||
|> ParseTreeCrate.make
|
||||
@@ -769,7 +680,6 @@ module internal ArgParserGenerator =
|
||||
|
||||
/// let helpText : string = ...
|
||||
let private helpText
|
||||
(typeHelp : SynExpr option)
|
||||
(typeName : Ident)
|
||||
(positional : ParseFunctionPositional option)
|
||||
(args : ParseFunctionNonPositional list)
|
||||
@@ -851,61 +761,18 @@ module internal ArgParserGenerator =
|
||||
|> SynExpr.applyTo helpText
|
||||
|> SynExpr.paren
|
||||
|
||||
let fieldHelp =
|
||||
args
|
||||
|> List.map (toPrintable describeNonPositional)
|
||||
|> fun l ->
|
||||
match positional with
|
||||
| None -> l
|
||||
| Some pos -> l @ [ toPrintable describePositional pos ]
|
||||
|
||||
let allHelp =
|
||||
match typeHelp with
|
||||
| Some helpExpr ->
|
||||
// Prepend type help, followed by blank line, then field help
|
||||
[ helpExpr ; SynExpr.CreateConst "" ] @ fieldHelp
|
||||
| None ->
|
||||
// No type help, just field help
|
||||
fieldHelp
|
||||
|
||||
allHelp
|
||||
args
|
||||
|> List.map (toPrintable describeNonPositional)
|
||||
|> fun l ->
|
||||
match positional with
|
||||
| None -> l
|
||||
| Some pos -> l @ [ toPrintable describePositional pos ]
|
||||
|> SynExpr.listLiteral
|
||||
|> SynExpr.pipeThroughFunction (
|
||||
SynExpr.applyFunction (SynExpr.createLongIdent [ "String" ; "concat" ]) (SynExpr.CreateConst @"\n")
|
||||
)
|
||||
|> SynBinding.basic [ Ident.create "helpText" ] [ SynPat.unit ]
|
||||
|
||||
/// Helper to create a negated parser for boolean/flag fields.
|
||||
/// Returns a SynExpr that represents: string -> (negated bool or negated flag DU)
|
||||
/// For booleans: `fun x -> not (Boolean.Parse x)`
|
||||
/// For flag DUs: `fun x -> FlagDu.FromBoolean flagDu (not (Boolean.Parse x))`
|
||||
let private createNegatedParser (arg : ParseFunction<'acc>) : SynExpr =
|
||||
match arg.BoolCases with
|
||||
| None -> failwith $"LOGIC ERROR: createNegatedParser called on non-boolean field %s{arg.FieldName.idText}"
|
||||
| Some (Choice2Of2 ()) ->
|
||||
// Boolean: parse and negate
|
||||
// fun x -> not (System.Boolean.Parse x)
|
||||
let parseExpr =
|
||||
SynExpr.createIdent "x"
|
||||
|> SynExpr.applyFunction (SynExpr.createLongIdent [ "System" ; "Boolean" ; "Parse" ])
|
||||
|> SynExpr.paren
|
||||
|
||||
parseExpr
|
||||
|> SynExpr.applyFunction (SynExpr.createIdent "not")
|
||||
|> SynExpr.createLambda "x"
|
||||
| Some (Choice1Of2 flagDu) ->
|
||||
// Flag DU: parse as bool, negate, then convert to flag DU
|
||||
// fun x -> x |> System.Boolean.Parse |> not |> FlagDu.FromBoolean flagDu
|
||||
let parseExpr =
|
||||
SynExpr.createIdent "x"
|
||||
|> SynExpr.applyFunction (SynExpr.createLongIdent [ "System" ; "Boolean" ; "Parse" ])
|
||||
|> SynExpr.paren
|
||||
|
||||
parseExpr
|
||||
|> SynExpr.applyFunction (SynExpr.createIdent "not")
|
||||
|> FlagDu.FromBoolean flagDu
|
||||
|> SynExpr.createLambda "x"
|
||||
|
||||
/// `let processKeyValue (key : string) (value : string) : Result<unit, string option> = ...`
|
||||
/// Returns a possible error.
|
||||
/// A parse failure might not be fatal (e.g. maybe the input was optionally of arity 0, and we failed to do
|
||||
@@ -919,209 +786,109 @@ module internal ArgParserGenerator =
|
||||
let args =
|
||||
args
|
||||
|> List.map (fun arg ->
|
||||
let assignmentExpr =
|
||||
match arg.Accumulation with
|
||||
| Accumulation.Required
|
||||
| Accumulation.Choice _
|
||||
| Accumulation.Optional ->
|
||||
let multipleErrorMessage =
|
||||
SynExpr.createIdent "sprintf"
|
||||
|> SynExpr.applyTo (
|
||||
SynExpr.CreateConst "Argument '%s' was supplied multiple times: %s and %s"
|
||||
)
|
||||
|> SynExpr.applyTo arg.HumanReadableArgForm
|
||||
|> SynExpr.applyTo (
|
||||
SynExpr.createIdent "x" |> SynExpr.callMethod "ToString" |> SynExpr.paren
|
||||
)
|
||||
|> SynExpr.applyTo (
|
||||
SynExpr.createIdent "value" |> SynExpr.callMethod "ToString" |> SynExpr.paren
|
||||
)
|
||||
match arg.Accumulation with
|
||||
| Accumulation.Required
|
||||
| Accumulation.Choice _
|
||||
| Accumulation.Optional ->
|
||||
let multipleErrorMessage =
|
||||
SynExpr.createIdent "sprintf"
|
||||
|> SynExpr.applyTo (SynExpr.CreateConst "Argument '%s' was supplied multiple times: %s and %s")
|
||||
|> SynExpr.applyTo arg.HumanReadableArgForm
|
||||
|> SynExpr.applyTo (SynExpr.createIdent "x" |> SynExpr.callMethod "ToString" |> SynExpr.paren)
|
||||
|> SynExpr.applyTo (
|
||||
SynExpr.createIdent "value" |> SynExpr.callMethod "ToString" |> SynExpr.paren
|
||||
)
|
||||
|
||||
let performAssignment =
|
||||
[
|
||||
SynExpr.createIdent "value"
|
||||
|> SynExpr.pipeThroughFunction arg.Parser
|
||||
|> SynExpr.pipeThroughFunction (SynExpr.createIdent "Some")
|
||||
|> SynExpr.assign (SynLongIdent.createI arg.TargetVariable)
|
||||
|
||||
SynExpr.applyFunction (SynExpr.createIdent "Ok") (SynExpr.CreateConst ())
|
||||
]
|
||||
|> SynExpr.sequential
|
||||
|
||||
[
|
||||
SynMatchClause.create
|
||||
(SynPat.nameWithArgs "Some" [ SynPat.named "x" ])
|
||||
(SynExpr.sequential
|
||||
[
|
||||
multipleErrorMessage
|
||||
|> SynExpr.pipeThroughFunction (
|
||||
SynExpr.dotGet "Add" (SynExpr.createIdent' argParseErrors)
|
||||
)
|
||||
SynExpr.applyFunction (SynExpr.createIdent "Ok") (SynExpr.CreateConst ())
|
||||
])
|
||||
SynMatchClause.create
|
||||
(SynPat.named "None")
|
||||
(SynExpr.pipeThroughTryWith
|
||||
SynPat.anon
|
||||
(SynExpr.createLongIdent [ "exc" ; "Message" ]
|
||||
|> SynExpr.pipeThroughFunction (SynExpr.createIdent "Some")
|
||||
|> SynExpr.pipeThroughFunction (SynExpr.createIdent "Error"))
|
||||
performAssignment)
|
||||
]
|
||||
|> SynExpr.createMatch (SynExpr.createIdent' arg.TargetVariable)
|
||||
| Accumulation.List (Accumulation.List _)
|
||||
| Accumulation.List Accumulation.Optional
|
||||
| Accumulation.List (Accumulation.Choice _) ->
|
||||
failwith
|
||||
"WoofWare.Myriad invariant violated: expected a list to contain only a Required accumulation. Non-positional lists cannot be optional or Choice, nor can they themselves contain lists."
|
||||
| Accumulation.List Accumulation.Required ->
|
||||
let performAssignment =
|
||||
[
|
||||
SynExpr.createIdent "value"
|
||||
|> SynExpr.pipeThroughFunction arg.Parser
|
||||
|> SynExpr.pipeThroughFunction (
|
||||
SynExpr.createLongIdent' [ arg.TargetVariable ; Ident.create "Add" ]
|
||||
)
|
||||
SynExpr.CreateConst () |> SynExpr.pipeThroughFunction (SynExpr.createIdent "Ok")
|
||||
|> SynExpr.pipeThroughFunction (SynExpr.createIdent "Some")
|
||||
|> SynExpr.assign (SynLongIdent.createI arg.TargetVariable)
|
||||
|
||||
SynExpr.applyFunction (SynExpr.createIdent "Ok") (SynExpr.CreateConst ())
|
||||
]
|
||||
|> SynExpr.sequential
|
||||
|
||||
// Return (argForms, assignmentExpr), argMetadata
|
||||
(arg.ArgForm, assignmentExpr), Some arg
|
||||
[
|
||||
SynMatchClause.create
|
||||
(SynPat.nameWithArgs "Some" [ SynPat.named "x" ])
|
||||
(SynExpr.sequential
|
||||
[
|
||||
multipleErrorMessage
|
||||
|> SynExpr.pipeThroughFunction (
|
||||
SynExpr.dotGet "Add" (SynExpr.createIdent' argParseErrors)
|
||||
)
|
||||
SynExpr.applyFunction (SynExpr.createIdent "Ok") (SynExpr.CreateConst ())
|
||||
])
|
||||
SynMatchClause.create
|
||||
(SynPat.named "None")
|
||||
(SynExpr.pipeThroughTryWith
|
||||
SynPat.anon
|
||||
(SynExpr.createLongIdent [ "exc" ; "Message" ]
|
||||
|> SynExpr.pipeThroughFunction (SynExpr.createIdent "Some")
|
||||
|> SynExpr.pipeThroughFunction (SynExpr.createIdent "Error"))
|
||||
performAssignment)
|
||||
]
|
||||
|> SynExpr.createMatch (SynExpr.createIdent' arg.TargetVariable)
|
||||
| Accumulation.List (Accumulation.List _)
|
||||
| Accumulation.List Accumulation.Optional
|
||||
| Accumulation.List (Accumulation.Choice _) ->
|
||||
failwith
|
||||
"WoofWare.Myriad invariant violated: expected a list to contain only a Required accumulation. Non-positional lists cannot be optional or Choice, nor can they themselves contain lists."
|
||||
| Accumulation.List Accumulation.Required ->
|
||||
[
|
||||
SynExpr.createIdent "value"
|
||||
|> SynExpr.pipeThroughFunction arg.Parser
|
||||
|> SynExpr.pipeThroughFunction (
|
||||
SynExpr.createLongIdent' [ arg.TargetVariable ; Ident.create "Add" ]
|
||||
)
|
||||
SynExpr.CreateConst () |> SynExpr.pipeThroughFunction (SynExpr.createIdent "Ok")
|
||||
]
|
||||
|> SynExpr.sequential
|
||||
|> fun expr -> arg.ArgForm, expr
|
||||
)
|
||||
|
||||
let posArg =
|
||||
match pos with
|
||||
| None -> []
|
||||
| Some pos ->
|
||||
let posExpr =
|
||||
[
|
||||
SynExpr.createIdent "value"
|
||||
|> SynExpr.pipeThroughFunction pos.Parser
|
||||
|> fun p ->
|
||||
match pos.Accumulation with
|
||||
| ChoicePositional.Choice _ ->
|
||||
p |> SynExpr.pipeThroughFunction (SynExpr.createIdent "Choice1Of2")
|
||||
| ChoicePositional.Normal _ -> p
|
||||
|> SynExpr.pipeThroughFunction (
|
||||
SynExpr.createLongIdent' [ pos.TargetVariable ; Ident.create "Add" ]
|
||||
)
|
||||
SynExpr.CreateConst () |> SynExpr.pipeThroughFunction (SynExpr.createIdent "Ok")
|
||||
]
|
||||
|> SynExpr.sequential
|
||||
|
||||
// Positional args don't support negation, so metadata is None
|
||||
[ (pos.ArgForm, posExpr), None ]
|
||||
[
|
||||
SynExpr.createIdent "value"
|
||||
|> SynExpr.pipeThroughFunction pos.Parser
|
||||
|> fun p ->
|
||||
match pos.Accumulation with
|
||||
| ChoicePositional.Choice _ ->
|
||||
p |> SynExpr.pipeThroughFunction (SynExpr.createIdent "Choice1Of2")
|
||||
| ChoicePositional.Normal _ -> p
|
||||
|> SynExpr.pipeThroughFunction (
|
||||
SynExpr.createLongIdent' [ pos.TargetVariable ; Ident.create "Add" ]
|
||||
)
|
||||
SynExpr.CreateConst () |> SynExpr.pipeThroughFunction (SynExpr.createIdent "Ok")
|
||||
]
|
||||
|> SynExpr.sequential
|
||||
|> fun expr -> pos.ArgForm, expr
|
||||
|> List.singleton
|
||||
|
||||
(SynExpr.applyFunction (SynExpr.createIdent "Error") (SynExpr.createIdent "None"), posArg @ args)
|
||||
||> List.fold (fun finalBranch ((argForm, arg), argMetadata) ->
|
||||
||> List.fold (fun finalBranch (argForm, arg) ->
|
||||
(finalBranch, argForm)
|
||||
||> List.fold (fun finalBranch argForm ->
|
||||
// Standard match: --argForm
|
||||
let standardMatch =
|
||||
arg
|
||||
|> SynExpr.ifThenElse
|
||||
(SynExpr.applyFunction
|
||||
(SynExpr.createLongIdent [ "System" ; "String" ; "Equals" ])
|
||||
(SynExpr.tuple
|
||||
[
|
||||
SynExpr.createIdent "key"
|
||||
SynExpr.applyFunction
|
||||
(SynExpr.applyFunction
|
||||
(SynExpr.createIdent "sprintf")
|
||||
(SynExpr.CreateConst "--%s"))
|
||||
argForm
|
||||
SynExpr.createLongIdent [ "System" ; "StringComparison" ; "OrdinalIgnoreCase" ]
|
||||
]))
|
||||
finalBranch
|
||||
|
||||
// If this arg accepts negation, also match --no-argForm
|
||||
match argMetadata with
|
||||
| None -> standardMatch
|
||||
| Some (parseFn : ParseFunctionNonPositional) when parseFn.AcceptsNegation ->
|
||||
// Create negated assignment (same structure as `arg` but with negated parser)
|
||||
let negatedParser = createNegatedParser parseFn
|
||||
|
||||
let negatedArg =
|
||||
match parseFn.Accumulation with
|
||||
| Accumulation.Required
|
||||
| Accumulation.Choice _
|
||||
| Accumulation.Optional ->
|
||||
let multipleErrorMessage =
|
||||
SynExpr.createIdent "sprintf"
|
||||
|> SynExpr.applyTo (
|
||||
SynExpr.CreateConst "Argument '%s' was supplied multiple times: %s and %s"
|
||||
)
|
||||
|> SynExpr.applyTo parseFn.HumanReadableArgForm
|
||||
|> SynExpr.applyTo (
|
||||
SynExpr.createIdent "x" |> SynExpr.callMethod "ToString" |> SynExpr.paren
|
||||
)
|
||||
|> SynExpr.applyTo (
|
||||
SynExpr.createIdent "value" |> SynExpr.callMethod "ToString" |> SynExpr.paren
|
||||
)
|
||||
|
||||
let performNegatedAssignment =
|
||||
[
|
||||
SynExpr.createIdent "value"
|
||||
|> SynExpr.pipeThroughFunction negatedParser
|
||||
|> SynExpr.pipeThroughFunction (SynExpr.createIdent "Some")
|
||||
|> SynExpr.assign (SynLongIdent.createI parseFn.TargetVariable)
|
||||
|
||||
SynExpr.applyFunction (SynExpr.createIdent "Ok") (SynExpr.CreateConst ())
|
||||
]
|
||||
|> SynExpr.sequential
|
||||
|
||||
arg
|
||||
|> SynExpr.ifThenElse
|
||||
(SynExpr.applyFunction
|
||||
(SynExpr.createLongIdent [ "System" ; "String" ; "Equals" ])
|
||||
(SynExpr.tuple
|
||||
[
|
||||
SynMatchClause.create
|
||||
(SynPat.nameWithArgs "Some" [ SynPat.named "x" ])
|
||||
(SynExpr.sequential
|
||||
[
|
||||
multipleErrorMessage
|
||||
|> SynExpr.pipeThroughFunction (
|
||||
SynExpr.dotGet "Add" (SynExpr.createIdent' argParseErrors)
|
||||
)
|
||||
SynExpr.applyFunction (SynExpr.createIdent "Ok") (SynExpr.CreateConst ())
|
||||
])
|
||||
SynMatchClause.create
|
||||
(SynPat.named "None")
|
||||
(SynExpr.pipeThroughTryWith
|
||||
SynPat.anon
|
||||
(SynExpr.createLongIdent [ "exc" ; "Message" ]
|
||||
|> SynExpr.pipeThroughFunction (SynExpr.createIdent "Some")
|
||||
|> SynExpr.pipeThroughFunction (SynExpr.createIdent "Error"))
|
||||
performNegatedAssignment)
|
||||
]
|
||||
|> SynExpr.createMatch (SynExpr.createIdent' parseFn.TargetVariable)
|
||||
| Accumulation.List Accumulation.Required ->
|
||||
[
|
||||
SynExpr.createIdent "value"
|
||||
|> SynExpr.pipeThroughFunction negatedParser
|
||||
|> SynExpr.pipeThroughFunction (
|
||||
SynExpr.createLongIdent' [ parseFn.TargetVariable ; Ident.create "Add" ]
|
||||
)
|
||||
SynExpr.CreateConst () |> SynExpr.pipeThroughFunction (SynExpr.createIdent "Ok")
|
||||
]
|
||||
|> SynExpr.sequential
|
||||
| _ ->
|
||||
failwith
|
||||
"WoofWare.Myriad invariant violated: unexpected accumulation type for negated arg"
|
||||
|
||||
// Match --no-argForm
|
||||
negatedArg
|
||||
|> SynExpr.ifThenElse
|
||||
(SynExpr.applyFunction
|
||||
(SynExpr.createLongIdent [ "System" ; "String" ; "Equals" ])
|
||||
(SynExpr.tuple
|
||||
[
|
||||
SynExpr.createIdent "key"
|
||||
SynExpr.applyFunction
|
||||
(SynExpr.applyFunction
|
||||
(SynExpr.createIdent "sprintf")
|
||||
(SynExpr.CreateConst "--no-%s"))
|
||||
argForm
|
||||
SynExpr.createLongIdent [ "System" ; "StringComparison" ; "OrdinalIgnoreCase" ]
|
||||
]))
|
||||
standardMatch
|
||||
| Some _ -> standardMatch
|
||||
SynExpr.createIdent "key"
|
||||
SynExpr.applyFunction
|
||||
(SynExpr.applyFunction
|
||||
(SynExpr.createIdent "sprintf")
|
||||
(SynExpr.CreateConst "--%s"))
|
||||
argForm
|
||||
SynExpr.createLongIdent [ "System" ; "StringComparison" ; "OrdinalIgnoreCase" ]
|
||||
]))
|
||||
finalBranch
|
||||
)
|
||||
)
|
||||
|> SynBinding.basic
|
||||
@@ -1142,34 +909,6 @@ module internal ArgParserGenerator =
|
||||
|> PreXmlDoc.create'
|
||||
)
|
||||
|
||||
/// Try to extract a constant bool value from a SynExpr.
|
||||
/// Returns Some true/false if the expr is a constant bool, None otherwise.
|
||||
let private tryGetConstBool (expr : SynExpr) : bool option =
|
||||
match expr |> SynExpr.stripOptionalParen with
|
||||
| SynExpr.Const (SynConst.Bool v, _) -> Some v
|
||||
| _ -> None
|
||||
|
||||
/// Helper to get the "false" case for a boolean/flag field.
|
||||
/// For booleans: `false`
|
||||
/// For flag DUs: the case marked with [<ArgumentFlag false>]
|
||||
let private getFalseCase (flag : ParseFunction<'a>) : SynExpr =
|
||||
match flag.BoolCases with
|
||||
| None -> failwith $"LOGIC ERROR: getFalseCase called on non-boolean field %s{flag.FieldName.idText}"
|
||||
| Some (Choice2Of2 ()) ->
|
||||
// Boolean: return false
|
||||
SynExpr.CreateConst false
|
||||
| Some (Choice1Of2 flagDu) ->
|
||||
// Flag DU: return the case associated with false
|
||||
// Check which case has false as its arg
|
||||
match tryGetConstBool flagDu.Case1Arg, tryGetConstBool flagDu.Case2Arg with
|
||||
| Some false, _ -> SynExpr.createLongIdent' [ flagDu.Name ; flagDu.Case1Name ]
|
||||
| _, Some false -> SynExpr.createLongIdent' [ flagDu.Name ; flagDu.Case2Name ]
|
||||
| Some true, _ -> SynExpr.createLongIdent' [ flagDu.Name ; flagDu.Case2Name ]
|
||||
| _, Some true -> SynExpr.createLongIdent' [ flagDu.Name ; flagDu.Case1Name ]
|
||||
| None, None ->
|
||||
// Can't determine at compile time, use FlagDu.FromBoolean with false
|
||||
FlagDu.FromBoolean flagDu (SynExpr.CreateConst false)
|
||||
|
||||
/// `let setFlagValue (key : string) : bool = ...`
|
||||
/// The second member of the `flags` list tuple is the constant "true" with which we will interpret the
|
||||
/// arity-0 `--foo`. So in the case of a boolean-typed field, this is `true`; in the case of a Flag-typed field,
|
||||
@@ -1210,72 +949,21 @@ module internal ArgParserGenerator =
|
||||
|
||||
(finalExpr, flag.ArgForm)
|
||||
||> List.fold (fun finalExpr argForm ->
|
||||
// Standard match: --argForm sets to trueCase
|
||||
let standardMatch =
|
||||
SynExpr.ifThenElse
|
||||
(SynExpr.applyFunction
|
||||
(SynExpr.createLongIdent [ "System" ; "String" ; "Equals" ])
|
||||
(SynExpr.tuple
|
||||
[
|
||||
SynExpr.createIdent "key"
|
||||
SynExpr.applyFunction
|
||||
(SynExpr.applyFunction
|
||||
(SynExpr.createIdent "sprintf")
|
||||
(SynExpr.CreateConst "--%s"))
|
||||
argForm
|
||||
SynExpr.createLongIdent [ "System" ; "StringComparison" ; "OrdinalIgnoreCase" ]
|
||||
]))
|
||||
finalExpr
|
||||
matchFlag
|
||||
|
||||
// If this flag accepts negation, also match --no-argForm sets to falseCase
|
||||
if flag.AcceptsNegation then
|
||||
let falseCase = getFalseCase flag
|
||||
|
||||
let matchNegatedFlag =
|
||||
[
|
||||
SynMatchClause.create
|
||||
(SynPat.nameWithArgs "Some" [ SynPat.named "x" ])
|
||||
// This is an error, but it's one we can gracefully report at the end.
|
||||
(SynExpr.sequential
|
||||
[
|
||||
multipleErrorMessage
|
||||
|> SynExpr.pipeThroughFunction (
|
||||
SynExpr.dotGet "Add" (SynExpr.createIdent' argParseErrors)
|
||||
)
|
||||
SynExpr.CreateConst true
|
||||
])
|
||||
|
||||
SynMatchClause.create
|
||||
(SynPat.named "None")
|
||||
([
|
||||
SynExpr.assign
|
||||
(SynLongIdent.createI flag.TargetVariable)
|
||||
(SynExpr.pipeThroughFunction (SynExpr.createIdent "Some") falseCase)
|
||||
SynExpr.CreateConst true
|
||||
]
|
||||
|> SynExpr.sequential)
|
||||
]
|
||||
|> SynExpr.createMatch (SynExpr.createIdent' flag.TargetVariable)
|
||||
|
||||
// Match --no-argForm
|
||||
SynExpr.ifThenElse
|
||||
(SynExpr.applyFunction
|
||||
(SynExpr.createLongIdent [ "System" ; "String" ; "Equals" ])
|
||||
(SynExpr.tuple
|
||||
[
|
||||
SynExpr.createIdent "key"
|
||||
SynExpr.applyFunction
|
||||
(SynExpr.applyFunction
|
||||
(SynExpr.createIdent "sprintf")
|
||||
(SynExpr.CreateConst "--no-%s"))
|
||||
argForm
|
||||
SynExpr.createLongIdent [ "System" ; "StringComparison" ; "OrdinalIgnoreCase" ]
|
||||
]))
|
||||
standardMatch
|
||||
matchNegatedFlag
|
||||
else
|
||||
standardMatch
|
||||
SynExpr.ifThenElse
|
||||
(SynExpr.applyFunction
|
||||
(SynExpr.createLongIdent [ "System" ; "String" ; "Equals" ])
|
||||
(SynExpr.tuple
|
||||
[
|
||||
SynExpr.createIdent "key"
|
||||
SynExpr.applyFunction
|
||||
(SynExpr.applyFunction
|
||||
(SynExpr.createIdent "sprintf")
|
||||
(SynExpr.CreateConst "--%s"))
|
||||
argForm
|
||||
SynExpr.createLongIdent [ "System" ; "StringComparison" ; "OrdinalIgnoreCase" ]
|
||||
]))
|
||||
finalExpr
|
||||
matchFlag
|
||||
)
|
||||
)
|
||||
|> SynBinding.basic [ Ident.create "setFlagValue" ] [ SynPat.annotateType SynType.string (SynPat.named "key") ]
|
||||
@@ -1573,7 +1261,6 @@ module internal ArgParserGenerator =
|
||||
|
||||
/// Takes a single argument, `args : string list`, and returns something of the type indicated by `recordType`.
|
||||
let createRecordParse
|
||||
(typeHelpText : SynExpr option)
|
||||
(parseState : Ident)
|
||||
(flagDus : FlagDu list)
|
||||
(ambientRecords : RecordType list)
|
||||
@@ -1640,7 +1327,7 @@ module internal ArgParserGenerator =
|
||||
|> SynExpr.applyTo (SynExpr.CreateConst ())
|
||||
|> SynBinding.basic [ argParseErrors ] []
|
||||
|
||||
let helpText = helpText typeHelpText recordType.Name pos nonPos
|
||||
let helpText = helpText recordType.Name pos nonPos
|
||||
|
||||
let bindings = errorCollection :: helpText :: bindings
|
||||
|
||||
@@ -1937,25 +1624,14 @@ module internal ArgParserGenerator =
|
||||
| _ -> None
|
||||
)
|
||||
|
||||
let taggedType, typeHelpText =
|
||||
let taggedType =
|
||||
match taggedType with
|
||||
| SynTypeDefn.SynTypeDefn (SynComponentInfo.SynComponentInfo (attributes = attrs) as sci,
|
||||
| SynTypeDefn.SynTypeDefn (sci,
|
||||
SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Record (access, fields, _), _),
|
||||
smd,
|
||||
_,
|
||||
_,
|
||||
_) ->
|
||||
let typeHelp =
|
||||
attrs
|
||||
|> SynAttributes.toAttrs
|
||||
|> List.tryPick (fun a ->
|
||||
match (List.last a.TypeName.LongIdent).idText with
|
||||
| "ArgumentHelpTextAttribute"
|
||||
| "ArgumentHelpText" -> Some a.ArgExpr
|
||||
| _ -> None
|
||||
)
|
||||
|
||||
RecordType.OfRecord sci smd access fields, typeHelp
|
||||
_) -> RecordType.OfRecord sci smd access fields
|
||||
| _ -> failwith "[<ArgParser>] currently only supports being placed on records."
|
||||
|
||||
let modAttrs, modName =
|
||||
@@ -2013,7 +1689,7 @@ module internal ArgParserGenerator =
|
||||
|> SynPat.annotateType (SynType.appPostfix "list" SynType.string)
|
||||
|
||||
let parsePrime =
|
||||
createRecordParse typeHelpText parseStateIdent flagDus allRecordTypes taggedType
|
||||
createRecordParse parseStateIdent flagDus allRecordTypes taggedType
|
||||
|> SynBinding.basic
|
||||
[ Ident.create "parse'" ]
|
||||
[
|
||||
|
||||
@@ -1,731 +0,0 @@
|
||||
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
|
||||
| IAsyncDisposable
|
||||
|
||||
/// 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 ->
|
||||
if pi.IsOptional then
|
||||
pi.Type |> SynType.appPostfix "option"
|
||||
else
|
||||
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.appPostfix "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 (fun pi ->
|
||||
if pi.IsOptional then
|
||||
SynType.appPostfix "option" pi.Type
|
||||
else
|
||||
pi.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
|
||||
| [ "IAsyncDisposable" ]
|
||||
| [ "System" ; "IAsyncDisposable" ] -> KnownInheritance.IAsyncDisposable
|
||||
| _ -> 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
|
||||
|
||||
fieldName, (f, extraType)
|
||||
)
|
||||
|> Map.ofList
|
||||
|
||||
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 =
|
||||
let disposable =
|
||||
if inherits.Contains KnownInheritance.IDisposable then
|
||||
let unitFun = SynExpr.createThunk (SynExpr.CreateConst ())
|
||||
[ SynLongIdent.createS "Dispose", unitFun ]
|
||||
else
|
||||
[]
|
||||
|
||||
let asyncDisposable =
|
||||
if inherits.Contains KnownInheritance.IAsyncDisposable then
|
||||
let valueTaskCtor =
|
||||
SynExpr.createLongIdent [ "System" ; "Threading" ; "Tasks" ; "ValueTask" ]
|
||||
|> SynExpr.applyTo (SynExpr.CreateConst ())
|
||||
|> SynExpr.paren
|
||||
|> SynExpr.createLambda "()"
|
||||
|
||||
[ SynLongIdent.createS "DisposeAsync", valueTaskCtor ]
|
||||
else
|
||||
[]
|
||||
|
||||
disposable @ asyncDisposable
|
||||
|
||||
let originalMembers =
|
||||
fields
|
||||
|> Map.toList
|
||||
|> List.map (fun (fieldName, _) -> SynLongIdent.createS fieldName, failwithNotImplemented fieldName)
|
||||
|
||||
let callsObject =
|
||||
SynLongIdent.createS "Calls",
|
||||
SynExpr.applyFunction
|
||||
(SynExpr.createLongIdent [ $"%s{name}Calls" ; "Calls" ; "Empty" ])
|
||||
(SynExpr.CreateConst ())
|
||||
|
||||
callsObject :: interfaceExtras @ originalMembers
|
||||
|
||||
let staticMemberEmpty =
|
||||
SynBinding.basic
|
||||
[ Ident.create "Empty" ]
|
||||
[ SynPat.unit ]
|
||||
(SynExpr.createRecord None emptyRecordFieldInstantiations)
|
||||
|> SynBinding.withXmlDoc (PreXmlDoc.create "An implementation where every non-disposal method throws.")
|
||||
|> SynBinding.withReturnAnnotation constructorReturnType
|
||||
|> SynMemberDefn.staticMember
|
||||
|
||||
let recordFields =
|
||||
let extras =
|
||||
let disposable =
|
||||
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 asyncDisposable =
|
||||
if inherits.Contains KnownInheritance.IAsyncDisposable then
|
||||
{
|
||||
Attrs = []
|
||||
Ident = Some (Ident.create "DisposeAsync")
|
||||
Type =
|
||||
SynType.funFromDomain
|
||||
SynType.unit
|
||||
(SynType.createLongIdent' [ "System" ; "Threading" ; "Tasks" ; "ValueTask" ])
|
||||
}
|
||||
|> SynField.make
|
||||
|> SynField.withDocString (PreXmlDoc.create "Implementation of IAsyncDisposable.DisposeAsync")
|
||||
|> List.singleton
|
||||
else
|
||||
[]
|
||||
|
||||
disposable @ asyncDisposable
|
||||
|
||||
let nonExtras =
|
||||
fields |> Map.toSeq |> Seq.map (fun (_, (field, _)) -> field) |> Seq.toList
|
||||
|
||||
let calls =
|
||||
let ty =
|
||||
match interfaceType.Generics with
|
||||
| None -> SynType.createLongIdent' [ $"%s{name}Calls" ; "Calls" ]
|
||||
| Some generics ->
|
||||
generics.TyparDecls
|
||||
|> List.map (fun (SynTyparDecl (_, typar)) -> SynType.var typar)
|
||||
|> SynType.app' (SynType.createLongIdent' [ $"%s{name}Calls" ; "Calls" ])
|
||||
|
||||
{
|
||||
Attrs = []
|
||||
Ident = Ident.create "Calls" |> Some
|
||||
Type = ty
|
||||
}
|
||||
|> SynField.make
|
||||
|
||||
calls :: extras @ nonExtras
|
||||
|
||||
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 accessAtLeastInternal =
|
||||
match access with
|
||||
| SynAccess.Private _ -> SynAccess.Internal range0
|
||||
| access -> access
|
||||
|
||||
let callsObject =
|
||||
let fields' =
|
||||
fields
|
||||
|> Map.toSeq
|
||||
|> Seq.map (fun (fieldName, (_, callType)) ->
|
||||
match callType with
|
||||
| CallField.Original ty ->
|
||||
{
|
||||
Attrs = []
|
||||
Ident = Some (fieldName |> Ident.create)
|
||||
Type = SynType.app "ResizeArray" [ ty ]
|
||||
}
|
||||
|> SynField.make
|
||||
| CallField.ArgsObject (argsObjectName, _, generics) ->
|
||||
{
|
||||
Attrs = []
|
||||
Ident = Some (fieldName |> 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' [ argsObjectName.idText ])
|
||||
|> List.singleton
|
||||
|> SynType.app "ResizeArray"
|
||||
}
|
||||
|> SynField.make
|
||||
)
|
||||
|> Seq.toList
|
||||
|
||||
let emptyMember =
|
||||
let returnType =
|
||||
match interfaceType.Generics with
|
||||
| None -> SynType.named "Calls"
|
||||
| Some generics ->
|
||||
let generics =
|
||||
match generics with
|
||||
| SynTyparDecls.PostfixList (decls = decls)
|
||||
| SynTyparDecls.PrefixList (decls = decls) -> decls
|
||||
| SynTyparDecls.SinglePrefix (decl = decl) -> [ decl ]
|
||||
|> List.map (fun (SynTyparDecl.SynTyparDecl (_, typar)) -> SynType.var typar)
|
||||
|
||||
SynType.app "Calls" generics
|
||||
|
||||
fields
|
||||
|> Map.toSeq
|
||||
|> Seq.map (fun (name, _) ->
|
||||
SynLongIdent.createS name,
|
||||
SynExpr.applyFunction (SynExpr.createIdent "ResizeArray") (SynExpr.CreateConst ())
|
||||
)
|
||||
|> Seq.toList
|
||||
|> SynExpr.createRecord None
|
||||
|> SynBinding.basic [ Ident.create "Empty" ] [ SynPat.unit ]
|
||||
|> SynBinding.withXmlDoc (PreXmlDoc.create "A fresh calls object which has not yet had any calls made.")
|
||||
|> SynBinding.withReturnAnnotation returnType
|
||||
|> SynMemberDefn.staticMember
|
||||
|
||||
{
|
||||
RecordType.Name = Ident.create "Calls"
|
||||
Fields = fields'
|
||||
Members = Some [ emptyMember ]
|
||||
XmlDoc = PreXmlDoc.create $"All the calls made to a %s{name} mock" |> Some
|
||||
Generics = interfaceType.Generics
|
||||
TypeAccessibility = Some accessAtLeastInternal
|
||||
ImplAccessibility = None
|
||||
Attributes = [ SynAttribute.requireQualifiedAccess ]
|
||||
}
|
||||
|> AstHelper.defineRecordType
|
||||
|
||||
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, addToCalls =
|
||||
let tupleContents =
|
||||
memberInfo.Args
|
||||
|> List.mapi (fun i args ->
|
||||
args.Args
|
||||
|> List.mapi (fun j arg ->
|
||||
match arg.Type with
|
||||
| UnitType -> SynExpr.CreateConst (), arg.Id
|
||||
| _ -> SynExpr.createIdent $"arg_%i{i}_%i{j}", arg.Id
|
||||
)
|
||||
)
|
||||
|
||||
let tuples = tupleContents |> List.map (List.map fst >> SynExpr.tuple)
|
||||
|
||||
match tuples |> List.rev with
|
||||
| [] -> failwith "expected args but got none"
|
||||
| last :: rest ->
|
||||
|
||||
let tuples = (last, rest) ||> List.fold SynExpr.applyTo
|
||||
|
||||
let body =
|
||||
tuples
|
||||
|> SynExpr.applyFunction (
|
||||
SynExpr.createLongIdent' [ Ident.create "this" ; memberInfo.Identifier ]
|
||||
)
|
||||
|
||||
let addToCalls =
|
||||
match Map.tryFind memberInfo.Identifier.idText fields with
|
||||
| None ->
|
||||
failwith
|
||||
$"unexpectedly looking up a nonexistent field %s{memberInfo.Identifier.idText}"
|
||||
| Some (_, result) ->
|
||||
match result with
|
||||
| CallField.Original _ -> tuples
|
||||
| CallField.ArgsObject _ ->
|
||||
tupleContents
|
||||
|> List.mapi (fun i fields ->
|
||||
match fields with
|
||||
| [ contents, Some ident ] -> SynLongIdent.create [ ident ], contents
|
||||
| [ contents, None ] -> SynLongIdent.createS $"Arg%i{i}", contents
|
||||
| _ ->
|
||||
SynLongIdent.createS $"Arg%i{i}",
|
||||
SynExpr.tupleNoParen (fields |> List.map fst)
|
||||
)
|
||||
|> SynExpr.createRecord None
|
||||
|> SynExpr.applyFunction (
|
||||
SynExpr.createLongIdent [ "this" ; "Calls" ; memberInfo.Identifier.idText ; "Add" ]
|
||||
)
|
||||
|> SynExpr.createLambda "_"
|
||||
|> SynExpr.applyFunction (
|
||||
SynExpr.createIdent "lock"
|
||||
|> SynExpr.applyTo (
|
||||
SynExpr.createLongIdent [ "this" ; "Calls" ; memberInfo.Identifier.idText ]
|
||||
)
|
||||
)
|
||||
|
||||
body, addToCalls
|
||||
|
||||
let body = [ addToCalls ; body ] |> SynExpr.sequential
|
||||
|
||||
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 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
|
||||
)
|
||||
|
||||
| KnownInheritance.IAsyncDisposable ->
|
||||
let mem =
|
||||
SynExpr.createLongIdent [ "this" ; "DisposeAsync" ]
|
||||
|> SynExpr.applyTo (SynExpr.CreateConst ())
|
||||
|> SynBinding.basic [ Ident.create "this" ; Ident.create "DisposeAsync" ] [ SynPat.unit ]
|
||||
|> SynBinding.withReturnAnnotation (
|
||||
SynType.createLongIdent' [ "System" ; "Threading" ; "Tasks" ; "ValueTask" ]
|
||||
)
|
||||
|> SynMemberDefn.memberImplementation
|
||||
|
||||
SynMemberDefn.Interface (
|
||||
SynType.createLongIdent' [ "System" ; "IAsyncDisposable" ],
|
||||
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 =
|
||||
let types =
|
||||
fields
|
||||
|> Map.toSeq
|
||||
|> Seq.choose (fun (_, (_, field)) ->
|
||||
match field with
|
||||
| CallField.Original _ -> None
|
||||
| CallField.ArgsObject (_, callType, _) -> Some (SynModuleDecl.Types ([ callType ], range0))
|
||||
)
|
||||
|> Seq.toList
|
||||
|
||||
types @ [ SynModuleDecl.Types ([ callsObject ], range0) ]
|
||||
|> SynModuleDecl.nestedModule (
|
||||
SynComponentInfo.create (Ident.create $"%s{name}Calls")
|
||||
|> SynComponentInfo.withAccessibility accessAtLeastInternal
|
||||
|> SynComponentInfo.addAttributes [ SynAttribute.requireQualifiedAccess ]
|
||||
)
|
||||
|> 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
|
||||
@@ -1209,10 +1209,6 @@ type CreateCatamorphismGenerator () =
|
||||
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
|
||||
|
||||
@@ -1222,26 +1218,17 @@ type CreateCatamorphismGenerator () =
|
||||
|
||||
let namespaceAndTypes =
|
||||
types
|
||||
|> List.collect (fun (ns, types) ->
|
||||
types
|
||||
|> List.choose (fun typeDef ->
|
||||
match SynTypeDefn.getAttribute typeof<CreateCatamorphismAttribute>.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.CreateCatamorphism cataOutputName ->
|
||||
Some (SynExpr.CreateConst cataOutputName, typeDef)
|
||||
| _ -> None
|
||||
)
|
||||
|> List.choose (fun (ns, types) ->
|
||||
let typeWithAttr =
|
||||
types
|
||||
|> List.tryPick (fun ty ->
|
||||
match SynTypeDefn.getAttribute typeof<CreateCatamorphismAttribute>.Name ty with
|
||||
| None -> None
|
||||
| Some attr -> Some (attr.ArgExpr, typeDef)
|
||||
)
|
||||
|> List.map (fun (typeName, taggedType) ->
|
||||
| Some attr -> Some (attr.ArgExpr, ty)
|
||||
)
|
||||
|
||||
match typeWithAttr with
|
||||
| Some taggedType ->
|
||||
let unions, records, others =
|
||||
(([], [], []), types)
|
||||
||> List.fold (fun
|
||||
@@ -1259,8 +1246,8 @@ type CreateCatamorphismGenerator () =
|
||||
failwith
|
||||
$"Error: all types recursively defined together with a CreateCatamorphism type must be discriminated unions or records. %+A{others}"
|
||||
|
||||
(ns, (typeName, taggedType), unions, records)
|
||||
)
|
||||
Some (ns, taggedType, unions, records)
|
||||
| _ -> None
|
||||
)
|
||||
|
||||
let modules =
|
||||
|
||||
@@ -20,9 +20,7 @@ module internal InterfaceMockGenerator =
|
||||
| Some id -> id
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
type private KnownInheritance =
|
||||
| IDisposable
|
||||
| IAsyncDisposable
|
||||
type private KnownInheritance = | IDisposable
|
||||
|
||||
let createType
|
||||
(spec : GenerateMockOutputSpec)
|
||||
@@ -41,8 +39,6 @@ module internal InterfaceMockGenerator =
|
||||
| [] -> failwith "Unexpected empty identifier in inheritance declaration"
|
||||
| [ "IDisposable" ]
|
||||
| [ "System" ; "IDisposable" ] -> KnownInheritance.IDisposable
|
||||
| [ "IAsyncDisposable" ]
|
||||
| [ "System" ; "IAsyncDisposable" ] -> KnownInheritance.IAsyncDisposable
|
||||
| _ -> failwithf "Unrecognised inheritance identifier: %+A" name
|
||||
| x -> failwithf "Unrecognised type in inheritance: %+A" x
|
||||
)
|
||||
@@ -73,26 +69,12 @@ module internal InterfaceMockGenerator =
|
||||
|
||||
let constructorFields =
|
||||
let extras =
|
||||
let disposable =
|
||||
if inherits.Contains KnownInheritance.IDisposable then
|
||||
let unitFun = SynExpr.createThunk (SynExpr.CreateConst ())
|
||||
[ SynLongIdent.createS "Dispose", unitFun ]
|
||||
else
|
||||
[]
|
||||
if inherits.Contains KnownInheritance.IDisposable then
|
||||
let unitFun = SynExpr.createThunk (SynExpr.CreateConst ())
|
||||
|
||||
let asyncDisposable =
|
||||
if inherits.Contains KnownInheritance.IAsyncDisposable then
|
||||
let valueTaskCtor =
|
||||
SynExpr.createLongIdent [ "System" ; "Threading" ; "Tasks" ; "ValueTask" ]
|
||||
|> SynExpr.applyTo (SynExpr.CreateConst ())
|
||||
|> SynExpr.paren
|
||||
|> SynExpr.createLambda "()"
|
||||
|
||||
[ SynLongIdent.createS "DisposeAsync", valueTaskCtor ]
|
||||
else
|
||||
[]
|
||||
|
||||
disposable @ asyncDisposable
|
||||
[ SynLongIdent.createS "Dispose", unitFun ]
|
||||
else
|
||||
[]
|
||||
|
||||
let nonExtras =
|
||||
fields
|
||||
@@ -108,42 +90,23 @@ module internal InterfaceMockGenerator =
|
||||
else
|
||||
[ SynPat.unit ])
|
||||
(SynExpr.createRecord None constructorFields)
|
||||
|> SynBinding.withXmlDoc (PreXmlDoc.create "An implementation where every non-disposal method throws.")
|
||||
|> SynBinding.withXmlDoc (PreXmlDoc.create "An implementation where every method throws.")
|
||||
|> SynBinding.withReturnAnnotation constructorReturnType
|
||||
|> SynMemberDefn.staticMember
|
||||
|
||||
let fields =
|
||||
let extras =
|
||||
let disposable =
|
||||
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 asyncDisposable =
|
||||
if inherits.Contains KnownInheritance.IAsyncDisposable then
|
||||
{
|
||||
Attrs = []
|
||||
Ident = Some (Ident.create "DisposeAsync")
|
||||
Type =
|
||||
SynType.funFromDomain
|
||||
SynType.unit
|
||||
(SynType.createLongIdent' [ "System" ; "Threading" ; "Tasks" ; "ValueTask" ])
|
||||
}
|
||||
|> SynField.make
|
||||
|> SynField.withDocString (PreXmlDoc.create "Implementation of IAsyncDisposable.DisposeAsync")
|
||||
|> List.singleton
|
||||
else
|
||||
[]
|
||||
|
||||
disposable @ asyncDisposable
|
||||
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
|
||||
[]
|
||||
|
||||
extras @ fields
|
||||
|
||||
@@ -249,23 +212,6 @@ module internal InterfaceMockGenerator =
|
||||
Some [ mem ],
|
||||
range0
|
||||
)
|
||||
|
||||
| KnownInheritance.IAsyncDisposable ->
|
||||
let mem =
|
||||
SynExpr.createLongIdent [ "this" ; "DisposeAsync" ]
|
||||
|> SynExpr.applyTo (SynExpr.CreateConst ())
|
||||
|> SynBinding.basic [ Ident.create "this" ; Ident.create "DisposeAsync" ] [ SynPat.unit ]
|
||||
|> SynBinding.withReturnAnnotation (
|
||||
SynType.createLongIdent' [ "System" ; "Threading" ; "Tasks" ; "ValueTask" ]
|
||||
)
|
||||
|> SynMemberDefn.memberImplementation
|
||||
|
||||
SynMemberDefn.Interface (
|
||||
SynType.createLongIdent' [ "System" ; "IAsyncDisposable" ],
|
||||
Some range0,
|
||||
Some [ mem ],
|
||||
range0
|
||||
)
|
||||
)
|
||||
|> Seq.toList
|
||||
|
||||
|
||||
@@ -1,23 +1,16 @@
|
||||
namespace WoofWare.Myriad.Plugins
|
||||
|
||||
open System
|
||||
|
||||
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
|
||||
| CreateCatamorphism of typeName : string
|
||||
|
||||
static member Parse (s : string) =
|
||||
match s with
|
||||
| "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)
|
||||
@@ -27,10 +20,4 @@ type internal DesiredGenerator =
|
||||
| "HttpClient" -> DesiredGenerator.HttpClient None
|
||||
| "HttpClient(true)" -> DesiredGenerator.HttpClient (Some true)
|
||||
| "HttpClient(false)" -> DesiredGenerator.HttpClient (Some false)
|
||||
| _ ->
|
||||
let prefix = "CreateCatamorphism("
|
||||
|
||||
if s.StartsWith (prefix, StringComparison.Ordinal) && s.EndsWith ')' then
|
||||
DesiredGenerator.CreateCatamorphism (s.Substring (prefix.Length, s.Length - prefix.Length - 1))
|
||||
else
|
||||
failwith $"Failed to parse as a generator specification: %s{s}"
|
||||
| _ -> failwith $"Failed to parse as a generator specification: %s{s}"
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
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
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
namespace WoofWare.Myriad.Plugins
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module internal Tuple =
|
||||
let withLeft left right = left, right
|
||||
let withRight right left = left, right
|
||||
@@ -21,8 +21,8 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Myriad.Core" Version="0.8.3" />
|
||||
<PackageReference Include="TypeEquality" Version="0.4.2" />
|
||||
<PackageReference Include="WoofWare.Whippet.Fantomas" Version="0.6.4" />
|
||||
<PackageReference Include="TypeEquality" Version="0.3.0" />
|
||||
<PackageReference Include="WoofWare.Whippet.Fantomas" Version="0.6.3" />
|
||||
<!-- the lowest version allowed by Myriad.Core -->
|
||||
<PackageReference Update="FSharp.Core" Version="6.0.1" PrivateAssets="all"/>
|
||||
</ItemGroup>
|
||||
@@ -30,7 +30,6 @@
|
||||
<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" />
|
||||
@@ -38,7 +37,6 @@
|
||||
<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": "9.1",
|
||||
"version": "8.0",
|
||||
"publicReleaseRefSpec": [
|
||||
"^refs/heads/main$"
|
||||
],
|
||||
@@ -11,4 +11,4 @@
|
||||
":/README.md",
|
||||
":/Directory.Build.props"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -10,8 +10,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageDownload Include="WoofWare.FSharpAnalyzers" Version="[0.2.2]" />
|
||||
<PackageDownload Include="G-Research.FSharp.Analyzers" Version="[0.20.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": 1764138170,
|
||||
"narHash": "sha256-2bCmfCUZyi2yj9FFXYKwsDiaZmizN75cLhI/eWmf3tk=",
|
||||
"lastModified": 1754711617,
|
||||
"narHash": "sha256-WrZ280bT6NzNbBo+CKeJA/NW1rhvN/RUPZczqCpu2mI=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "bb813de6d2241bcb1b5af2d3059f560c66329967",
|
||||
"rev": "00b574b1ba8a352f0601c4dde4faff4b534ebb1e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
||||
115
nix/deps.json
115
nix/deps.json
@@ -1,8 +1,8 @@
|
||||
[
|
||||
{
|
||||
"pname": "ApiSurface",
|
||||
"version": "5.0.3",
|
||||
"hash": "sha256-uU5mqLL6zMt17oPYMzhB57ryYC6O6FzSjmdTFg7LvNo="
|
||||
"version": "4.1.22",
|
||||
"hash": "sha256-voj9m3YmyJ95FAMLV4sWzQMod3Em0mTjzf0LBUUFOso="
|
||||
},
|
||||
{
|
||||
"pname": "fantomas",
|
||||
@@ -26,13 +26,13 @@
|
||||
},
|
||||
{
|
||||
"pname": "FsCheck",
|
||||
"version": "3.3.2",
|
||||
"hash": "sha256-3ydyTGpqySynjbcWbmFVeCBnT3KDH3miPSJYJlyxrGs="
|
||||
"version": "3.3.0",
|
||||
"hash": "sha256-TFDR/uAGv4OqrMX8/reQ4faaAhH9hxTHr1T/YkNPCCU="
|
||||
},
|
||||
{
|
||||
"pname": "fsharp-analyzers",
|
||||
"version": "0.34.1",
|
||||
"hash": "sha256-Y6PzfVGob2EgX29ZhZIde5EhiZ28Y1+U2pJ6ybIsHV0="
|
||||
"version": "0.32.1",
|
||||
"hash": "sha256-le6rPnAF7cKGBZ2w8H2u9glK+6rT2ZjiAVnrkH2IhrM="
|
||||
},
|
||||
{
|
||||
"pname": "FSharp.Core",
|
||||
@@ -46,8 +46,8 @@
|
||||
},
|
||||
{
|
||||
"pname": "FSharp.Core",
|
||||
"version": "9.0.303",
|
||||
"hash": "sha256-AxR6wqodeU23KOTgkUfIgbavgbcSuzD4UBP+tiFydgA="
|
||||
"version": "9.0.300",
|
||||
"hash": "sha256-eBGcd/OwlGuW2009Fb/ym813OWI9tHJXCY6oi4iGOyA="
|
||||
},
|
||||
{
|
||||
"pname": "FSharp.SystemTextJson",
|
||||
@@ -61,8 +61,8 @@
|
||||
},
|
||||
{
|
||||
"pname": "Microsoft.ApplicationInsights",
|
||||
"version": "2.23.0",
|
||||
"hash": "sha256-5sf3bg7CZZjHseK+F3foOchEhmVeioePxMZVvS6Rjb0="
|
||||
"version": "2.22.0",
|
||||
"hash": "sha256-mUQ63atpT00r49ca50uZu2YCiLg3yd6r3HzTryqcuEA="
|
||||
},
|
||||
{
|
||||
"pname": "Microsoft.AspNetCore.App.Ref",
|
||||
@@ -91,13 +91,13 @@
|
||||
},
|
||||
{
|
||||
"pname": "Microsoft.CodeCoverage",
|
||||
"version": "18.0.1",
|
||||
"hash": "sha256-G6y5iyHZ3R2shlLCW/uTusio/UqcnWT79X+UAbxvDQY="
|
||||
"version": "17.14.1",
|
||||
"hash": "sha256-f8QytG8GvRoP47rO2KEmnDLxIpyesaq26TFjDdW40Gs="
|
||||
},
|
||||
{
|
||||
"pname": "Microsoft.NET.Test.Sdk",
|
||||
"version": "18.0.1",
|
||||
"hash": "sha256-0c3/rp9di0w7E5UmfRh6Prrm3Aeyi8NOj5bm2i6jAh0="
|
||||
"version": "17.14.1",
|
||||
"hash": "sha256-mZUzDFvFp7x1nKrcnRd0hhbNu5g8EQYt8SKnRgdhT/A="
|
||||
},
|
||||
{
|
||||
"pname": "Microsoft.NETCore.App.Host.linux-arm64",
|
||||
@@ -154,6 +154,11 @@
|
||||
"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",
|
||||
@@ -166,48 +171,43 @@
|
||||
},
|
||||
{
|
||||
"pname": "Microsoft.Testing.Extensions.Telemetry",
|
||||
"version": "1.9.0",
|
||||
"hash": "sha256-JT91ThKLEyoRS/8ZJqZwlSTT7ofC2QhNqPFI3pYmMaw="
|
||||
"version": "1.5.3",
|
||||
"hash": "sha256-bIXwPSa3jkr2b6xINOqMUs6/uj/r4oVFM7xq3uVIZDU="
|
||||
},
|
||||
{
|
||||
"pname": "Microsoft.Testing.Extensions.TrxReport.Abstractions",
|
||||
"version": "1.9.0",
|
||||
"hash": "sha256-oscZOEKw7gM6eRdDrOS3x+CwqIvXWRmfmi0ugCxBRw0="
|
||||
"version": "1.5.3",
|
||||
"hash": "sha256-IfMRfcyaIKEMRtx326ICKtinDBEfGw/Sv8ZHawJ96Yc="
|
||||
},
|
||||
{
|
||||
"pname": "Microsoft.Testing.Extensions.VSTestBridge",
|
||||
"version": "1.9.0",
|
||||
"hash": "sha256-CadXLWD093sUDaWhnppzD9LvpxSRqqt93ZEOFiIAPyw="
|
||||
"version": "1.5.3",
|
||||
"hash": "sha256-XpM/yFjhLSsuzyDV+xKubs4V1zVVYiV05E0+N4S1h0g="
|
||||
},
|
||||
{
|
||||
"pname": "Microsoft.Testing.Platform",
|
||||
"version": "1.9.0",
|
||||
"hash": "sha256-6nzjoYbJOh7v/GB7d+TDuM0l/xglCshFX6KWjg7+cFI="
|
||||
"version": "1.5.3",
|
||||
"hash": "sha256-y61Iih6w5D79dmrj2V675mcaeIiHoj1HSa1FRit2BLM="
|
||||
},
|
||||
{
|
||||
"pname": "Microsoft.Testing.Platform.MSBuild",
|
||||
"version": "1.9.0",
|
||||
"hash": "sha256-/bileP4b+9RZp8yjgS6eynXwc2mohyyzf6p/0LZJd8I="
|
||||
},
|
||||
{
|
||||
"pname": "Microsoft.TestPlatform.AdapterUtilities",
|
||||
"version": "17.13.0",
|
||||
"hash": "sha256-Vr+3Tad/h/nk7f/5HMExn3HvCGFCarehFAzJSfCBaOc="
|
||||
"version": "1.5.3",
|
||||
"hash": "sha256-YspvjE5Jfi587TAfsvfDVJXNrFOkx1B3y1CKV6m7YLY="
|
||||
},
|
||||
{
|
||||
"pname": "Microsoft.TestPlatform.ObjectModel",
|
||||
"version": "17.13.0",
|
||||
"hash": "sha256-6S0fjfj8vA+h6dJVNwLi6oZhYDO/I/6hBZaq2VTW+Uk="
|
||||
"version": "17.12.0",
|
||||
"hash": "sha256-3XBHBSuCxggAIlHXmKNQNlPqMqwFlM952Av6RrLw1/w="
|
||||
},
|
||||
{
|
||||
"pname": "Microsoft.TestPlatform.ObjectModel",
|
||||
"version": "18.0.1",
|
||||
"hash": "sha256-oJbS7SZ46RzyOQ+gCysW7qJRy7V8RlQVa5d8uajb91M="
|
||||
"version": "17.14.1",
|
||||
"hash": "sha256-QMf6O+w0IT+16Mrzo7wn+N20f3L1/mDhs/qjmEo1rYs="
|
||||
},
|
||||
{
|
||||
"pname": "Microsoft.TestPlatform.TestHost",
|
||||
"version": "18.0.1",
|
||||
"hash": "sha256-OXYf5vg4piDr10ve0bZ2ZSb+nb3yOiHayJV3cu5sMV4="
|
||||
"version": "17.14.1",
|
||||
"hash": "sha256-1cxHWcvHRD7orQ3EEEPPxVGEkTpxom1/zoICC9SInJs="
|
||||
},
|
||||
{
|
||||
"pname": "Myriad.Core",
|
||||
@@ -221,8 +221,8 @@
|
||||
},
|
||||
{
|
||||
"pname": "Nerdbank.GitVersioning",
|
||||
"version": "3.9.50",
|
||||
"hash": "sha256-BiBfXwr8ob2HTaFk2L5TwAgtvd/EPoqudSI9nhAjQPI="
|
||||
"version": "3.8.38-alpha",
|
||||
"hash": "sha256-gPMrVbjOZxXoofczF/pn6eVkLhjVSJIyQrLO2oljrDc="
|
||||
},
|
||||
{
|
||||
"pname": "NETStandard.Library",
|
||||
@@ -276,8 +276,8 @@
|
||||
},
|
||||
{
|
||||
"pname": "NUnit3TestAdapter",
|
||||
"version": "5.2.0",
|
||||
"hash": "sha256-ybTutL4VkX/fq61mS+O3Ruh+adic4fpv+MKgQ0IZvGg="
|
||||
"version": "5.0.0",
|
||||
"hash": "sha256-7jZM4qAbIzne3AcdFfMbvbgogqpxvVe6q2S7Ls8xQy0="
|
||||
},
|
||||
{
|
||||
"pname": "RestEase",
|
||||
@@ -324,6 +324,16 @@
|
||||
"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",
|
||||
@@ -354,6 +364,11 @@
|
||||
"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,6 +379,11 @@
|
||||
"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",
|
||||
@@ -381,22 +401,17 @@
|
||||
},
|
||||
{
|
||||
"pname": "TypeEquality",
|
||||
"version": "0.4.2",
|
||||
"hash": "sha256-YxK6BGHjcuP76j5BbTDi814jxGqOevQSgS00IJcjZSA="
|
||||
"version": "0.3.0",
|
||||
"hash": "sha256-V50xAOzzyUJrY+MYPRxtnqW5MVeATXCes89wPprv1r4="
|
||||
},
|
||||
{
|
||||
"pname": "WoofWare.Expect",
|
||||
"version": "0.8.5",
|
||||
"hash": "sha256-rMlkk1osadQYwxmb0KAHqsB51hinTf7NzI0zyovpx04="
|
||||
},
|
||||
{
|
||||
"pname": "WoofWare.NUnitTestRunner",
|
||||
"version": "0.3.9",
|
||||
"hash": "sha256-+QVx5NYdY1JZoMcWfJRwFgvEj2dBxWlJU0mu1Hmnlhs="
|
||||
"version": "0.8.1",
|
||||
"hash": "sha256-OeOay7YvrTBysPAvJhlN3ff+4y5z95ah6F4lPT/fjh0="
|
||||
},
|
||||
{
|
||||
"pname": "WoofWare.Whippet.Fantomas",
|
||||
"version": "0.6.4",
|
||||
"hash": "sha256-ScZ7EEcxLvXyam2ZVqDK58QlK3RcePWghzRvtLLLdZI="
|
||||
"version": "0.6.3",
|
||||
"hash": "sha256-FkW/HtVp8/HE2k6d7yFpnJcnP3FNNe9kGlkoIWmNgDw="
|
||||
}
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user