From 43311e56f1a361185e71ae07d6112a730bfb4688 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 13 Apr 2026 16:47:56 +0000 Subject: [PATCH 1/4] feat: remove SwaggerClientProvider and v2 compiler, simplify folder structure Closes #376 Changes: - Remove SwaggerClientProvider (deprecated v2 type provider) - Remove v2 compiler pipeline (Parser, DefinitionCompiler, OperationCompiler) - Remove v2-specific provider tests and schema test files - Move v3 compiler files from v3/ subfolders to project roots - Rename namespace SwaggerProvider.Internal.v3.Compilers -> SwaggerProvider.Internal.Compilers - Flatten Schemas/v2/ and Schemas/v3/ into Schemas/ root - Move gettyimages.com.json to unsupported/ (fails v3 compiler pipeline) - Update docs: remove SwaggerClientProvider.md, update index.html nav - Update Schema.Parser.Tests.fs to use only v3 pipeline OpenApiClientProvider supports both OpenAPI 3.0 and Swagger 2.0 via Microsoft.OpenApi, so no functionality is lost. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/SwaggerClientProvider.md | 77 -- docs/index.html | 4 - paket.lock | 8 +- .../{v3 => }/DefinitionCompiler.fs | 2 +- .../{v3 => }/OperationCompiler.fs | 2 +- .../Provider.OpenApiClient.fs | 2 +- .../Provider.SwaggerClient.fs | 114 --- .../SwaggerProvider.DesignTime.fsproj | 11 +- .../v2/DefinitionCompiler.fs | 387 -------- .../v2/OperationCompiler.fs | 382 -------- .../v2/Parser/Parsers.fs | 512 ----------- .../v2/Parser/Schema.fs | 242 ----- .../v2/Parser/SchemaParserExceptions.fs | 26 - .../v2/Parser/SwaggerParser.fs | 162 ---- .../Schemas/{v2 => }/Instagram.json | 0 .../Schemas/{v2 => }/azure-arm-storage.json | 0 .../Schemas/{v2 => }/clickmeter.com.json | 0 .../Schemas/{v2 => }/github.json | 0 .../Schemas/{v2 => }/i0027.json | 0 .../Schemas/{v3 => }/issue132.json | 0 .../Schemas/{v3 => }/issue173.json | 0 .../Schemas/{v3 => }/issue181.yaml | 0 .../Schemas/{v3 => }/issue219.yaml | 0 .../Schemas/{v3 => }/issue255.yaml | 0 .../Schemas/{v3 => }/issue279.json | 0 .../Schemas/{v2 => }/my-swashbuckle.json | 0 .../Schemas/{v3 => }/nullable-date.yaml | 0 .../{v3 => }/nullable-parameter-issue261.json | 0 .../{v2/petstore.json => petstore-v2.json} | 0 .../Schemas/{v3 => }/petstore.yaml | 0 .../Schemas/{v2 => }/slack.json | 0 .../Schemas/{v2 => }/swashbuckle.json | 0 .../{v2 => unsupported}/gettyimages.com.json | 0 .../{v3 => }/unsupported/issue0204.yaml | 0 .../{v3 => }/Swagger.I0173.Tests.fs | 2 +- .../{v3 => }/Swagger.I0181.Tests.fs | 2 +- .../{v3 => }/Swagger.I0219.Tests.fs | 2 +- .../{v3 => }/Swagger.I0279.Tests.fs | 2 +- .../{v3 => }/Swagger.NullableDate.Tests.fs | 2 +- .../{v3 => }/Swagger.PetStore.Tests.fs | 2 +- .../Swagger.SchemaReaderErrors.Tests.fs | 4 +- .../SwaggerProvider.ProviderTests.fsproj | 41 +- .../Swashbuckle.CancellationToken.Tests.fs | 2 +- .../Swashbuckle.FileController.Tests.fs | 2 +- .../Swashbuckle.NoContentControllers.Tests.fs | 2 +- .../Swashbuckle.ResourceControllers.Tests.fs | 0 .../Swashbuckle.ReturnControllers.Tests.fs | 2 +- ...Swashbuckle.ReturnTextControllers.Tests.fs | 2 +- ...ashbuckle.SpecialCasesControllers.Tests.fs | 0 .../Swashbuckle.UpdateControllers.Tests.fs | 2 +- .../v2/Swagger.GitHub.Tests.fs | 68 -- .../v2/Swagger.Instagram.Tests.fs | 10 - .../v2/Swagger.Namespaces.Tests.fs | 25 - .../v2/Swagger.PetStore.Tests.fs | 105 --- .../v2/Swagger.Slack.Tests.fs | 36 - .../v2/Swagger.i0027.Tests.fs | 10 - .../Swashbuckle.NoContentControllers.Tests.fs | 35 - .../Swashbuckle.ResourceControllers.Tests.fs | 31 - .../v2/Swashbuckle.ReturnControllers.Tests.fs | 170 ---- ...ashbuckle.SpecialCasesControllers.Tests.fs | 8 - .../v2/Swashbuckle.UpdateControllers.Tests.fs | 182 ---- .../PathResolutionTests.fs | 12 +- .../Schema.ArrayAndMapTypeMappingTests.fs | 2 +- .../{v3 => }/Schema.DefinitionPathTests.fs | 4 +- .../Schema.OperationCompilationTests.fs | 2 +- .../Schema.Parser.Tests.fs | 35 +- .../{v3 => }/Schema.TestHelpers.fs | 4 +- .../{v3 => }/Schema.TypeMappingTests.fs | 2 +- .../Schema.V2SchemaCompilationTests.fs | 4 +- .../{v3 => }/Schema.XmlDocTests.fs | 4 +- .../SsrfSecurityTests.fs | 4 +- .../SwaggerProvider.Tests.fsproj | 18 +- .../v2/Schema.DefinitionsTests.fs | 134 --- .../v2/Schema.PathsTests.fs | 45 - .../v2/Schema.Spec.Json.Tests.fs | 866 ------------------ .../v2/Schema.Spec.Yaml.Tests.fs | 728 --------------- 76 files changed, 72 insertions(+), 4472 deletions(-) delete mode 100644 docs/SwaggerClientProvider.md rename src/SwaggerProvider.DesignTime/{v3 => }/DefinitionCompiler.fs (99%) rename src/SwaggerProvider.DesignTime/{v3 => }/OperationCompiler.fs (99%) delete mode 100644 src/SwaggerProvider.DesignTime/Provider.SwaggerClient.fs delete mode 100644 src/SwaggerProvider.DesignTime/v2/DefinitionCompiler.fs delete mode 100644 src/SwaggerProvider.DesignTime/v2/OperationCompiler.fs delete mode 100644 src/SwaggerProvider.DesignTime/v2/Parser/Parsers.fs delete mode 100644 src/SwaggerProvider.DesignTime/v2/Parser/Schema.fs delete mode 100644 src/SwaggerProvider.DesignTime/v2/Parser/SchemaParserExceptions.fs delete mode 100644 src/SwaggerProvider.DesignTime/v2/Parser/SwaggerParser.fs rename tests/SwaggerProvider.ProviderTests/Schemas/{v2 => }/Instagram.json (100%) rename tests/SwaggerProvider.ProviderTests/Schemas/{v2 => }/azure-arm-storage.json (100%) mode change 100755 => 100644 rename tests/SwaggerProvider.ProviderTests/Schemas/{v2 => }/clickmeter.com.json (100%) rename tests/SwaggerProvider.ProviderTests/Schemas/{v2 => }/github.json (100%) rename tests/SwaggerProvider.ProviderTests/Schemas/{v2 => }/i0027.json (100%) rename tests/SwaggerProvider.ProviderTests/Schemas/{v3 => }/issue132.json (100%) rename tests/SwaggerProvider.ProviderTests/Schemas/{v3 => }/issue173.json (100%) rename tests/SwaggerProvider.ProviderTests/Schemas/{v3 => }/issue181.yaml (100%) rename tests/SwaggerProvider.ProviderTests/Schemas/{v3 => }/issue219.yaml (100%) rename tests/SwaggerProvider.ProviderTests/Schemas/{v3 => }/issue255.yaml (100%) rename tests/SwaggerProvider.ProviderTests/Schemas/{v3 => }/issue279.json (100%) rename tests/SwaggerProvider.ProviderTests/Schemas/{v2 => }/my-swashbuckle.json (100%) rename tests/SwaggerProvider.ProviderTests/Schemas/{v3 => }/nullable-date.yaml (100%) rename tests/SwaggerProvider.ProviderTests/Schemas/{v3 => }/nullable-parameter-issue261.json (100%) rename tests/SwaggerProvider.ProviderTests/Schemas/{v2/petstore.json => petstore-v2.json} (100%) mode change 100755 => 100644 rename tests/SwaggerProvider.ProviderTests/Schemas/{v3 => }/petstore.yaml (100%) rename tests/SwaggerProvider.ProviderTests/Schemas/{v2 => }/slack.json (100%) rename tests/SwaggerProvider.ProviderTests/Schemas/{v2 => }/swashbuckle.json (100%) mode change 100755 => 100644 rename tests/SwaggerProvider.ProviderTests/Schemas/{v2 => unsupported}/gettyimages.com.json (100%) rename tests/SwaggerProvider.ProviderTests/Schemas/{v3 => }/unsupported/issue0204.yaml (100%) rename tests/SwaggerProvider.ProviderTests/{v3 => }/Swagger.I0173.Tests.fs (68%) rename tests/SwaggerProvider.ProviderTests/{v3 => }/Swagger.I0181.Tests.fs (66%) rename tests/SwaggerProvider.ProviderTests/{v3 => }/Swagger.I0219.Tests.fs (67%) rename tests/SwaggerProvider.ProviderTests/{v3 => }/Swagger.I0279.Tests.fs (66%) rename tests/SwaggerProvider.ProviderTests/{v3 => }/Swagger.NullableDate.Tests.fs (97%) rename tests/SwaggerProvider.ProviderTests/{v3 => }/Swagger.PetStore.Tests.fs (98%) rename tests/SwaggerProvider.ProviderTests/{v3 => }/Swagger.SchemaReaderErrors.Tests.fs (87%) rename tests/SwaggerProvider.ProviderTests/{v3 => }/Swashbuckle.CancellationToken.Tests.fs (98%) rename tests/SwaggerProvider.ProviderTests/{v3 => }/Swashbuckle.FileController.Tests.fs (97%) rename tests/SwaggerProvider.ProviderTests/{v3 => }/Swashbuckle.NoContentControllers.Tests.fs (93%) rename tests/SwaggerProvider.ProviderTests/{v3 => }/Swashbuckle.ResourceControllers.Tests.fs (100%) rename tests/SwaggerProvider.ProviderTests/{v3 => }/Swashbuckle.ReturnControllers.Tests.fs (99%) rename tests/SwaggerProvider.ProviderTests/{v3 => }/Swashbuckle.ReturnTextControllers.Tests.fs (94%) rename tests/SwaggerProvider.ProviderTests/{v3 => }/Swashbuckle.SpecialCasesControllers.Tests.fs (100%) rename tests/SwaggerProvider.ProviderTests/{v3 => }/Swashbuckle.UpdateControllers.Tests.fs (99%) delete mode 100644 tests/SwaggerProvider.ProviderTests/v2/Swagger.GitHub.Tests.fs delete mode 100644 tests/SwaggerProvider.ProviderTests/v2/Swagger.Instagram.Tests.fs delete mode 100644 tests/SwaggerProvider.ProviderTests/v2/Swagger.Namespaces.Tests.fs delete mode 100644 tests/SwaggerProvider.ProviderTests/v2/Swagger.PetStore.Tests.fs delete mode 100644 tests/SwaggerProvider.ProviderTests/v2/Swagger.Slack.Tests.fs delete mode 100644 tests/SwaggerProvider.ProviderTests/v2/Swagger.i0027.Tests.fs delete mode 100644 tests/SwaggerProvider.ProviderTests/v2/Swashbuckle.NoContentControllers.Tests.fs delete mode 100644 tests/SwaggerProvider.ProviderTests/v2/Swashbuckle.ResourceControllers.Tests.fs delete mode 100644 tests/SwaggerProvider.ProviderTests/v2/Swashbuckle.ReturnControllers.Tests.fs delete mode 100644 tests/SwaggerProvider.ProviderTests/v2/Swashbuckle.SpecialCasesControllers.Tests.fs delete mode 100644 tests/SwaggerProvider.ProviderTests/v2/Swashbuckle.UpdateControllers.Tests.fs rename tests/SwaggerProvider.Tests/{v3 => }/Schema.ArrayAndMapTypeMappingTests.fs (98%) rename tests/SwaggerProvider.Tests/{v3 => }/Schema.DefinitionPathTests.fs (97%) rename tests/SwaggerProvider.Tests/{v3 => }/Schema.OperationCompilationTests.fs (99%) rename tests/SwaggerProvider.Tests/{v3 => }/Schema.TestHelpers.fs (97%) rename tests/SwaggerProvider.Tests/{v3 => }/Schema.TypeMappingTests.fs (99%) rename tests/SwaggerProvider.Tests/{v3 => }/Schema.V2SchemaCompilationTests.fs (98%) rename tests/SwaggerProvider.Tests/{v3 => }/Schema.XmlDocTests.fs (97%) delete mode 100644 tests/SwaggerProvider.Tests/v2/Schema.DefinitionsTests.fs delete mode 100644 tests/SwaggerProvider.Tests/v2/Schema.PathsTests.fs delete mode 100644 tests/SwaggerProvider.Tests/v2/Schema.Spec.Json.Tests.fs delete mode 100644 tests/SwaggerProvider.Tests/v2/Schema.Spec.Yaml.Tests.fs diff --git a/docs/SwaggerClientProvider.md b/docs/SwaggerClientProvider.md deleted file mode 100644 index 0c5c0e33..00000000 --- a/docs/SwaggerClientProvider.md +++ /dev/null @@ -1,77 +0,0 @@ -# Swagger Client Provider - - - -The SwaggerClientProvider is outdated. There are no plans to improve the custom Swagger 2.0 schema parser or bring new features to this type provider. We hope to remove it from the source code when users migrate to [OpenApiClientProvider](/OpenApiClientProvider) and OpenApi 3.0 schemas. - - - -SwaggerClientProvider is a generative F# Type Provider, built on top of a custom Swagger schema parser that supports **only** 2.0 schema format. - -```fsharp -open SwaggerProvider - -let []schema = "http://petstore.swagger.io/v2/swagger.json" -type PetStore = SwaggerClientProvider -let petStore = PetStore.Client() -``` - -## Parameters - -When you use TP you can specify the following parameters - -| Parameter | Description | -|-----------|-------------| -| `Schema` | Url or Path to Swagger schema file. | -| `Headers` | HTTP Headers required to access the schema. | -| `IgnoreOperationId` | Do not use `operationsId` and generate method names using `path` only. Default value `false`. | -| `IgnoreControllerPrefix` | Do not parse `operationsId` as `_` and generate one client class for all operations. Default value `true`. | -| `PreferNullable` | Provide `Nullable<_>` for not required properties, instead of `Option<_>`. Defaults value `false`. | -| `PreferAsync` | Generate async actions of type `Async<'T>` instead of `Task<'T>`. Defaults value `false`. | -| `SsrfProtection` | Enable SSRF protection (blocks HTTP and localhost). Set to `false` for development/testing. Default value `true`. | - -More configuration scenarios are described in [Customization section](/Customization) - -## Security (SSRF Protection) - -By default, SwaggerProvider blocks HTTP URLs and localhost/private IP addresses to prevent [SSRF attacks](https://owasp.org/www-community/attacks/Server_Side_Request_Forgery). - -For **development and testing** with local servers, disable SSRF protection: - -```fsharp -// Development: Allow HTTP and localhost -type LocalApi = SwaggerClientProvider<"http://localhost:5000/swagger.json", SsrfProtection=false> - -// Production: HTTPS with SSRF protection (default) -type ProdApi = SwaggerClientProvider<"https://api.example.com/swagger.json"> -``` - -**Warning:** Never set `SsrfProtection=false` in production code. - -## Sample - -The usage is very similar to [OpenApiClientProvider](/OpenApiClientProvider#sample) - -```fsharp -open SwaggerProvider - -let [] Schema = "https://petstore.swagger.io/v2/swagger.json" -// Explicitly request Async<'a> methods instead of Task<'a> -type PetStore = SwaggerClientProvider - -[] -let main argv = - // Type Provider creates HttpClient for you under the hood - let client = PetStore.Client() - async { - // Create a new instance of the provided type and add it to the store - let pet = PetStore.Pet(Id = Some(24L), Name = "Shani") - do! client.AddPet(pet) - - // Request data back and deserialize to provided type - let! myPet = client.GetPetById(24L) - printfn "Waw, my name is %A" myPet.Name - } - |> Async.RunSynchronously - 0 -``` diff --git a/docs/index.html b/docs/index.html index 87e4a57f..c8906883 100644 --- a/docs/index.html +++ b/docs/index.html @@ -48,10 +48,6 @@ { title: 'OpenApiClientProvider', link: '/OpenApiClientProvider' - }, - { - title: 'SwaggerClientProvider', - link: '/SwaggerClientProvider', } ] }, diff --git a/paket.lock b/paket.lock index 55820538..b28f5d42 100644 --- a/paket.lock +++ b/paket.lock @@ -45,11 +45,11 @@ NUGET YamlDotNet (16.3) GITHUB remote: fsprojects/FSharp.TypeProviders.SDK - src/ProvidedTypes.fs (41c316752bea3e6ed52859144270a5ff47ba7446) - src/ProvidedTypes.fsi (41c316752bea3e6ed52859144270a5ff47ba7446) + src/ProvidedTypes.fs (75ac6119896431f6573bfcfb663bac2fe3d3df63) + src/ProvidedTypes.fsi (75ac6119896431f6573bfcfb663bac2fe3d3df63) remote: fsprojects/FSharp.Data - src/FSharp.Data.Runtime.Utilities/NameUtils.fs (7fca47a17aed46f69ad6cb326b3ac5d644bd624f) - src/FSharp.Data.Runtime.Utilities/Pluralizer.fs (7fca47a17aed46f69ad6cb326b3ac5d644bd624f) + src/FSharp.Data.Runtime.Utilities/NameUtils.fs (a1ee1414cacb3d2e6fa26b2726a164f563502728) + src/FSharp.Data.Runtime.Utilities/Pluralizer.fs (a1ee1414cacb3d2e6fa26b2726a164f563502728) GROUP Server RESTRICTION: == net10.0 NUGET diff --git a/src/SwaggerProvider.DesignTime/v3/DefinitionCompiler.fs b/src/SwaggerProvider.DesignTime/DefinitionCompiler.fs similarity index 99% rename from src/SwaggerProvider.DesignTime/v3/DefinitionCompiler.fs rename to src/SwaggerProvider.DesignTime/DefinitionCompiler.fs index 306a344e..b5aa7f08 100644 --- a/src/SwaggerProvider.DesignTime/v3/DefinitionCompiler.fs +++ b/src/SwaggerProvider.DesignTime/DefinitionCompiler.fs @@ -1,4 +1,4 @@ -namespace SwaggerProvider.Internal.v3.Compilers +namespace SwaggerProvider.Internal.Compilers open System open System.Reflection diff --git a/src/SwaggerProvider.DesignTime/v3/OperationCompiler.fs b/src/SwaggerProvider.DesignTime/OperationCompiler.fs similarity index 99% rename from src/SwaggerProvider.DesignTime/v3/OperationCompiler.fs rename to src/SwaggerProvider.DesignTime/OperationCompiler.fs index e075687f..ef9a345b 100644 --- a/src/SwaggerProvider.DesignTime/v3/OperationCompiler.fs +++ b/src/SwaggerProvider.DesignTime/OperationCompiler.fs @@ -1,4 +1,4 @@ -namespace SwaggerProvider.Internal.v3.Compilers +namespace SwaggerProvider.Internal.Compilers open System open System.Collections.Generic diff --git a/src/SwaggerProvider.DesignTime/Provider.OpenApiClient.fs b/src/SwaggerProvider.DesignTime/Provider.OpenApiClient.fs index 576a7e7e..ffec8dcf 100644 --- a/src/SwaggerProvider.DesignTime/Provider.OpenApiClient.fs +++ b/src/SwaggerProvider.DesignTime/Provider.OpenApiClient.fs @@ -9,7 +9,7 @@ open Microsoft.FSharp.Quotations open Microsoft.FSharp.Reflection open Swagger open SwaggerProvider.Internal -open SwaggerProvider.Internal.v3.Compilers +open SwaggerProvider.Internal.Compilers module OpenApiCache = let providedTypes = Caching.createInMemoryCache(TimeSpan.FromMinutes 5.0) diff --git a/src/SwaggerProvider.DesignTime/Provider.SwaggerClient.fs b/src/SwaggerProvider.DesignTime/Provider.SwaggerClient.fs deleted file mode 100644 index 24153569..00000000 --- a/src/SwaggerProvider.DesignTime/Provider.SwaggerClient.fs +++ /dev/null @@ -1,114 +0,0 @@ -namespace SwaggerProvider - -open System -open System.Reflection -open ProviderImplementation.ProvidedTypes -open Microsoft.FSharp.Core.CompilerServices -open Swagger -open SwaggerProvider.Internal -open SwaggerProvider.Internal.v2.Parser -open SwaggerProvider.Internal.v2.Compilers - -module SwaggerCache = - let providedTypes = Caching.createInMemoryCache(TimeSpan.FromMinutes 5.0) - -/// The Swagger Type Provider. -[] -type public SwaggerTypeProvider(cfg: TypeProviderConfig) as this = - inherit - TypeProviderForNamespaces( - cfg, - assemblyReplacementMap = [ ("SwaggerProvider.DesignTime", "SwaggerProvider.Runtime") ], - addDefaultProbingLocation = true - ) - - let ns = "SwaggerProvider" - let asm = Assembly.GetExecutingAssembly() - - // check we contain a copy of runtime files, and are not referencing the runtime DLL - do assert (typeof.Assembly.GetName().Name = asm.GetName().Name) - - let myParamType = - let t = - ProvidedTypeDefinition(asm, ns, "SwaggerClientProvider", Some typeof, isErased = false) - - let staticParams = - [ ProvidedStaticParameter("Schema", typeof) - ProvidedStaticParameter("Headers", typeof, "") - ProvidedStaticParameter("IgnoreOperationId", typeof, false) - ProvidedStaticParameter("IgnoreControllerPrefix", typeof, true) - ProvidedStaticParameter("PreferNullable", typeof, false) - ProvidedStaticParameter("PreferAsync", typeof, false) - ProvidedStaticParameter("SsrfProtection", typeof, true) ] - - t.AddXmlDoc - """Statically typed Swagger provider. - Url or Path to Swagger schema file. - HTTP Headers requiried to access the schema. - Do not use `operationsId` and generate method names using `path` only. Default value `false`. - Do not parse `operationsId` as `_` and generate one client class for all operations. Default value `true`. - Provide `Nullable<_>` for not required properties, instead of `Option<_>`. Defaults value `false`. - Generate async actions of type `Async<'T>` instead of `Task<'T>`. Defaults value `false`. - Enable SSRF protection (blocks HTTP and localhost). Set to false for development/testing. Default value `true`.""" - - t.DefineStaticParameters( - staticParams, - fun typeName args -> - let schemaPathRaw = unbox args.[0] - let headersStr = unbox args.[1] - let ignoreOperationId = unbox args.[2] - let ignoreControllerPrefix = unbox args.[3] - let preferNullable = unbox args.[4] - let preferAsync = unbox args.[5] - let ssrfProtection = unbox args.[6] - - // Cache key includes cfg.RuntimeAssembly, cfg.ResolutionFolder, and cfg.SystemRuntimeAssemblyVersion - // to differentiate between different TFM builds (same approach as FSharp.Data) - // See: https://github.com/fsprojects/FSharp.Data/blob/main/src/FSharp.Data.DesignTime/CommonProviderImplementation/Helpers.fs - let cacheKey = - (schemaPathRaw, - headersStr, - ignoreOperationId, - ignoreControllerPrefix, - preferNullable, - preferAsync, - ssrfProtection, - cfg.RuntimeAssembly, - cfg.ResolutionFolder, - cfg.SystemRuntimeAssemblyVersion) - |> sprintf "%A" - - let addCache() = - lazy - let schemaData = - SchemaReader.readSchemaPath (not ssrfProtection) headersStr cfg.ResolutionFolder schemaPathRaw - |> Async.RunSynchronously - - let schema = SwaggerParser.parseSchema schemaData - - let useDateOnly = cfg.SystemRuntimeAssemblyVersion.Major >= 6 - let defCompiler = DefinitionCompiler(schema, preferNullable, useDateOnly) - - let opCompiler = - OperationCompiler(schema, defCompiler, ignoreControllerPrefix, ignoreOperationId, preferAsync) - - opCompiler.CompileProvidedClients(defCompiler.Namespace) - let tys = defCompiler.Namespace.GetProvidedTypes() - - let tempAsm = ProvidedAssembly() - - let ty = - ProvidedTypeDefinition(tempAsm, ns, typeName, Some typeof, isErased = false, hideObjectMethods = true) - - ty.AddXmlDoc("Swagger Provider for " + schemaPathRaw) - ty.AddMembers tys - tempAsm.AddTypes [ ty ] - - ty - - SwaggerCache.providedTypes.GetOrAdd(cacheKey, addCache).Value - ) - - t - - do this.AddNamespace(ns, [ myParamType ]) diff --git a/src/SwaggerProvider.DesignTime/SwaggerProvider.DesignTime.fsproj b/src/SwaggerProvider.DesignTime/SwaggerProvider.DesignTime.fsproj index a5501dbb..9453d8f5 100644 --- a/src/SwaggerProvider.DesignTime/SwaggerProvider.DesignTime.fsproj +++ b/src/SwaggerProvider.DesignTime/SwaggerProvider.DesignTime.fsproj @@ -40,17 +40,10 @@ AssemblyInfo.fs - - - - - - - - + + - diff --git a/src/SwaggerProvider.DesignTime/v2/DefinitionCompiler.fs b/src/SwaggerProvider.DesignTime/v2/DefinitionCompiler.fs deleted file mode 100644 index 7d145000..00000000 --- a/src/SwaggerProvider.DesignTime/v2/DefinitionCompiler.fs +++ /dev/null @@ -1,387 +0,0 @@ -namespace SwaggerProvider.Internal.v2.Compilers - -open System -open System.Reflection -open ProviderImplementation.ProvidedTypes -open UncheckedQuotations -open FSharp.Data.Runtime.NameUtils -open SwaggerProvider.Internal.v2.Parser.Schema -open Swagger.Internal -open SwaggerProvider.Internal -open Microsoft.FSharp.Quotations - -type DefinitionPath = - { Namespace: string list - RequestedTypeName: string - ProvidedTypeNameCandidate: string } - - static member Parse(definition: string) = - let definitionPrefix, nsSeparator = "#/definitions/", '.' - - if (not <| definition.StartsWith(definitionPrefix)) then - failwithf $"Definition path does not start with %s{definitionPrefix}" - - let definitionPath = definition.Substring(definitionPrefix.Length) - - let rec getCharInTypeName ind = - if ind = definitionPath.Length then - ind - 1 - elif - Char.IsLetterOrDigit definitionPath[ind] - || definitionPath[ind] = nsSeparator - then - getCharInTypeName(ind + 1) - else - ind - - let lastDot = definitionPath.LastIndexOf(nsSeparator, getCharInTypeName 0) - - if lastDot < 0 then - { Namespace = [] - RequestedTypeName = definitionPath - ProvidedTypeNameCandidate = nicePascalName definitionPath } - else - let nsPath = - definitionPath.Substring(0, lastDot).Split([| nsSeparator |], StringSplitOptions.RemoveEmptyEntries) - |> List.ofArray - - let tyName = definitionPath.Substring(lastDot + 1) - - { Namespace = nsPath - RequestedTypeName = tyName - ProvidedTypeNameCandidate = nicePascalName tyName } - -type NamespaceEntry = - | Reservation - | NameAlias - | ProvidedType of ProvidedTypeDefinition - | Namespace of NamespaceAbstraction - | NestedType of ProvidedTypeDefinition * NamespaceAbstraction - -and NamespaceAbstraction(name: string) = - let providedTys = Collections.Generic.Dictionary() - - let updateReservation opName tyName updateFunc = - match providedTys.TryGetValue tyName with - | true, Reservation -> updateFunc() - | false, _ -> failwithf $"Cannot %s{opName} '%s{tyName}' because name was not reserved" - | _, value -> failwithf $"Cannot %s{opName} '%s{tyName}' because the slot is used by %A{value}" - - /// Namespace name - member _.Name = name - - /// Generate unique name and reserve it for the type - member _.ReserveUniqueName namePref nameSuffix = // TODO: Strange signature - think more - let rec findUniq prefix i = - let newName = sprintf "%s%s" prefix (if i = 0 then "" else i.ToString()) - - if not <| providedTys.ContainsKey newName then - newName - else - findUniq prefix (i + 1) - - let newName = findUniq (namePref + nameSuffix) 0 - providedTys.Add(newName, Reservation) - newName - - /// Release previously reserved name - member _.ReleaseNameReservation tyName = - updateReservation "release the name" tyName (fun () -> providedTys.Remove(tyName) |> ignore) - - /// Mark type name as named alias for basic type - member _.MarkTypeAsNameAlias tyName = - updateReservation "mark as Alias type" tyName (fun () -> providedTys[tyName] <- NameAlias) - - /// Associate ProvidedType with reserved type name - member _.RegisterType(tyName, ty) = - match providedTys.TryGetValue tyName with - | true, Reservation -> providedTys[tyName] <- ProvidedType ty - | true, Namespace ns -> providedTys[tyName] <- NestedType(ty, ns) - | false, _ -> failwithf $"Cannot register the type '%s{tyName}' because name was not reserved" - | _, value -> failwithf $"Cannot register the type '%s{tyName}' because the slot is used by %A{value}" - - /// Get or create sub-namespace - member _.GetOrCreateNamespace name = - match providedTys.TryGetValue name with - | true, Namespace ns -> ns - | true, NestedType(_, ns) -> ns - | true, ProvidedType ty -> - let ns = NamespaceAbstraction(name) - providedTys[name] <- NestedType(ty, ns) - ns - | false, _ - | true, Reservation -> - let ns = NamespaceAbstraction(name) - providedTys[name] <- Namespace ns - ns - | true, value -> failwithf $"Name collision, cannot create namespace '%s{name}' because it used by '%A{value}'" - - /// Resolve DefinitionPath according to current namespace - member this.Resolve(dPath: DefinitionPath) = - match dPath.Namespace with - | [] -> this, this.ReserveUniqueName dPath.RequestedTypeName "" - | name :: tail -> - let ns = this.GetOrCreateNamespace name - ns.Resolve { dPath with Namespace = tail } - - /// Create Provided representation of Namespace - member _.GetProvidedTypes() = - List.ofSeq providedTys - |> List.choose(fun kv -> - match kv.Value with - | Reservation -> failwithf $"Reservation without type found '%s{kv.Key}'. This is a bug in DefinitionCompiler" - | NameAlias -> None - | ProvidedType ty -> Some ty - | Namespace ns -> - let types = ns.GetProvidedTypes() - - if types.Length = 0 then - None - else - let nsTy = ProvidedTypeDefinition(ns.Name, Some typeof, isErased = false) - - nsTy.AddMember - <| ProvidedConstructor([], invokeCode = (fun _ -> <@@ () @@>)) // hack - - nsTy.AddMembers <| types - Some nsTy - | NestedType(ty, ns) -> - ty.AddMembers <| ns.GetProvidedTypes() - Some ty) - -/// Object for compiling definitions. -type DefinitionCompiler(schema: SwaggerObject, provideNullable, useDateOnly: bool) as this = - let definitionToSchemaObject = - let dict = Collections.Generic.Dictionary() - - for name, schemaObj in schema.Definitions do - dict.Add(name, schemaObj) - - dict - - let definitionToType = Collections.Generic.Dictionary<_, _>() - let nsRoot = NamespaceAbstraction("Root") - let nsOps = nsRoot.GetOrCreateNamespace "OperationTypes" - - let generateProperty (scope: UniqueNameGenerator) propName ty = - let propertyName = scope.MakeUnique <| nicePascalName propName - - let providedField = - let fieldName = $"_%c{Char.ToLower propertyName[0]}%s{propertyName.Substring(1)}" - - ProvidedField(fieldName, ty) - - let providedProperty = - ProvidedProperty( - propertyName, - ty, - getterCode = - (function - | [ this ] -> Expr.FieldGetUnchecked(this, providedField) - | _ -> failwith "invalid property getter params"), - setterCode = - (function - | [ this; v ] -> Expr.FieldSetUnchecked(this, providedField, v) - | _ -> failwith "invalid property setter params") - ) - - if propName <> propertyName then - providedProperty.AddCustomAttribute - <| RuntimeHelpers.getPropertyNameAttribute propName - - providedField, providedProperty - - let registerInNsAndInDef tyDefName (ns: NamespaceAbstraction) (name, ty: ProvidedTypeDefinition) = - if definitionToType.ContainsKey tyDefName then - failwithf $"Second time compilation of type definition '%s{tyDefName}'. This is a bug in DefinitionCompiler" - else - definitionToType.Add(tyDefName, ty) - - ns.RegisterType(name, ty) - - let rec compileDefinition(tyDefName: string) : Type = - match definitionToType.TryGetValue tyDefName with - | true, ty -> ty :> Type - | false, _ -> - match definitionToSchemaObject.TryGetValue tyDefName with - | true, def -> - let ns, tyName = tyDefName |> DefinitionPath.Parse |> nsRoot.Resolve - let ty = compileSchemaObject ns tyName def true (registerInNsAndInDef tyDefName ns) - ty :> Type - | false, _ when tyDefName.StartsWith("#/definitions/") -> - failwithf $"Cannot find definition '%s{tyDefName}' in schema definitions %A{definitionToType.Keys |> Seq.toArray}" - | _ -> failwithf $"Cannot find definition '%s{tyDefName}' (references to relative documents are not supported yet)" - - and compileSchemaObject (ns: NamespaceAbstraction) tyName (schemaObj: SchemaObject) isRequired registerNew = - let compileNewObject(properties: DefinitionProperty[]) = - if properties.Length = 0 then - if not <| isNull tyName then - ns.MarkTypeAsNameAlias tyName - - typeof - else if isNull tyName then - failwithf $"Swagger provider does not support anonymous types: %A{schemaObj}" - else - // Register every ProvidedTypeDefinition - let ty = ProvidedTypeDefinition(tyName, Some typeof, isErased = false) - registerNew(tyName, ty) - - // Generate fields and properties - let members = - let generateProperty = generateProperty(UniqueNameGenerator()) - - List.ofArray properties - |> List.map(fun p -> - if String.IsNullOrEmpty(p.Name) then - failwithf $"Property cannot be created with empty name. TypeName:%A{tyName}; SchemaObj:%A{schemaObj}" - - let pTy = - compileSchemaObject ns (ns.ReserveUniqueName tyName (nicePascalName p.Name)) p.Type p.IsRequired ns.RegisterType - - let pField, pProp = generateProperty p.Name pTy - - if not <| String.IsNullOrWhiteSpace p.Description then - pProp.AddXmlDoc p.Description - - pField, pProp) - - // Add fields and properties to type - ty.AddMembers - <| (members - |> List.collect(fun (f, p) -> [ f :> MemberInfo; p :> MemberInfo ])) - - // Add default constructor - ty.AddMember - <| ProvidedConstructor([], invokeCode = (fun _ -> <@@ () @@>)) - // Add full-init constructor - let ctorParams, fields = - let required, optional = - List.zip (List.ofArray properties) members - |> List.partition(fun (x, _) -> x.IsRequired) - - (required @ optional) - |> List.map(fun (x, (f, p)) -> - let paramName = niceCamelName p.Name - - let prParam = - if x.IsRequired then - ProvidedParameter(paramName, f.FieldType) - else - let paramDefaultValue = this.GetDefaultValue f.FieldType - ProvidedParameter(paramName, f.FieldType, false, paramDefaultValue) - - prParam, f) - |> List.unzip - - ty.AddMember - <| ProvidedConstructor( - ctorParams, - invokeCode = - fun args -> - let this, args = - match args with - | x :: xs -> (x, xs) - | _ -> failwith "Wrong constructor arguments" - - List.zip args fields - |> List.map(fun (arg, f) -> Expr.FieldSetUnchecked(this, f, arg)) - |> List.rev - |> List.fold (fun a b -> Expr.Sequential(a, b)) <@@ () @@> - ) - - // Override `.ToString()` - // Delegates to the shared RuntimeHelpers.formatObject helper so that - // each generated type's method body is a single static call (O(1) IL). - let toStr = - ProvidedMethod( - "ToString", - [], - typeof, - isStatic = false, - invokeCode = - fun args -> - let this = args[0] - let thisObj = Expr.Coerce(this, typeof) - <@@ RuntimeHelpers.formatObject(%%thisObj: obj) @@> - ) - - toStr.SetMethodAttrs(MethodAttributes.Public ||| MethodAttributes.Virtual) - - let objToStr = typeof.GetMethod("ToString", [||]) - ty.DefineMethodOverride(toStr, objToStr) - ty.AddMember <| toStr - - ty :> Type - - let tyType = - match schemaObj with - | Reference path -> - ns.ReleaseNameReservation tyName - compileDefinition path - | Object props -> compileNewObject props - | _ -> - ns.MarkTypeAsNameAlias tyName - - match schemaObj with - | Boolean -> typeof - | Byte -> typeof - | Int32 -> typeof - | Int64 -> typeof - | Float -> typeof - | Double -> typeof - | String -> typeof - | Date -> - // Use DateOnly only when the target runtime supports it (.NET 6+). - // We check useDateOnly (derived from cfg.SystemRuntimeAssemblyVersion) rather than - // probing the design-time host process, which may differ from the consumer's runtime. - if useDateOnly then - System.Type.GetType("System.DateOnly") - |> Option.ofObj - |> Option.defaultValue typeof - else - typeof - | DateTime -> typeof - | File -> typeof.MakeArrayType 1 - | Enum(_, "string") -> typeof - | Enum(_, "boolean") -> typeof - | Enum _ -> typeof - | Array eTy -> (compileSchemaObject ns (ns.ReserveUniqueName tyName "Item") eTy true ns.RegisterType).MakeArrayType(1) - | Dictionary eTy -> - ProvidedTypeBuilder.MakeGenericType( - typedefof>, - [ typeof - compileSchemaObject ns (ns.ReserveUniqueName tyName "Item") eTy false ns.RegisterType ] - ) - | Reference _ - | Object _ -> failwith "This case should be caught by other match statement" - - if isRequired then - tyType - else if tyType.IsValueType then - let baseGenTy = - if provideNullable then - typedefof> - else - typedefof> - - ProvidedTypeBuilder.MakeGenericType(baseGenTy, [ tyType ]) - else - tyType - - // Precompile types defined in the `definitions` part of the schema - do - schema.Definitions - |> Seq.iter(fun (name, _) -> compileDefinition name |> ignore) - - /// Namespace that represent provided type space - member _.Namespace = nsRoot - - /// Method that allow OperationCompiler to resolve object reference, compile basic and anonymous types. - member _.CompileTy opName tyUseSuffix ty required = - compileSchemaObject nsOps (nsOps.ReserveUniqueName opName tyUseSuffix) ty required nsOps.RegisterType - - /// Default value for optional parameters - member _.GetDefaultValue _ = - // This method is only used for not required types - // Reference types, Option and Nullable - null diff --git a/src/SwaggerProvider.DesignTime/v2/OperationCompiler.fs b/src/SwaggerProvider.DesignTime/v2/OperationCompiler.fs deleted file mode 100644 index 6d13c1ff..00000000 --- a/src/SwaggerProvider.DesignTime/v2/OperationCompiler.fs +++ /dev/null @@ -1,382 +0,0 @@ -namespace SwaggerProvider.Internal.v2.Compilers - -open ProviderImplementation.ProvidedTypes -open FSharp.Data.Runtime.NameUtils -open SwaggerProvider.Internal.v2.Parser.Schema -open Swagger.Internal - -open System -open System.Net.Http -open System.Text.Json -open System.Text.RegularExpressions - -open Microsoft.FSharp.Quotations -open Microsoft.FSharp.Quotations.ExprShape -open SwaggerProvider.Internal -open Swagger - -/// Object for compiling operations. -type OperationCompiler(schema: SwaggerObject, defCompiler: DefinitionCompiler, ignoreControllerPrefix, ignoreOperationId, asAsync: bool) = - let compileOperation (methodName: string) (op: OperationObject) = - if String.IsNullOrWhiteSpace methodName then - failwithf $"Operation name could not be empty. See '%s{op.Path}/%A{op.Type}'" - - let parameters = - /// handles deduping Swagger parameter names if the same parameter name - /// appears in multiple locations in a given operation definition. - let uniqueParamName existing (current: ParameterObject) = - let name = niceCamelName current.Name - - if Set.contains name existing then - Set.add current.UnambiguousName existing, current.UnambiguousName - else - Set.add name existing, name - - let required, optional = op.Parameters |> Array.partition(_.Required) - - Array.append required optional - |> Array.fold - (fun (names, parameters) current -> - let names, paramName = uniqueParamName names current - - let paramType = - defCompiler.CompileTy methodName paramName current.Type current.Required - - let providedParam = - if current.Required then - ProvidedParameter(paramName, paramType) - else - let paramDefaultValue = defCompiler.GetDefaultValue paramType - ProvidedParameter(paramName, paramType, false, paramDefaultValue) - - (names, providedParam :: parameters)) - (Set.empty, []) - |> snd - // because we built up our list in reverse order with the fold, - // reverse it again so that all required properties come first - |> List.rev - - // find the inner type value - let retTy = - let okResponse = - op.Responses - |> Array.tryFind(fun (code, _) -> code.IsSome && code.Value = 200) - |> Option.orElseWith(fun () -> - op.Responses - |> Array.tryFind(fun (code, _) -> code.IsSome && code.Value >= 201 && code.Value < 300)) - |> Option.orElseWith(fun () -> op.Responses |> Array.tryFind(fun (code, _) -> code.IsNone)) - - match okResponse with - | Some(_, resp) -> - match resp.Schema with - | None -> None - | Some ty -> Some <| defCompiler.CompileTy methodName "Response" ty true - | None -> None - - let overallReturnType = - ProvidedTypeBuilder.MakeGenericType( - (if asAsync then - typedefof> - else - typedefof>), - [ defaultArg retTy typeof ] - ) - - let m = - ProvidedMethod( - methodName, - parameters, - overallReturnType, - invokeCode = - fun args -> - let this = - Expr.Coerce(args[0], typeof) - |> Expr.Cast - - let httpMethod = op.Type.ToString() - let basePath = schema.BasePath - - let headers = - let jsonConsumable = - op.Consumes |> Seq.exists(fun mt -> mt = MediaTypes.ApplicationJson) - - let jsonProducible = - op.Produces |> Seq.exists(fun mt -> mt = MediaTypes.ApplicationJson) - - <@ - [| if jsonProducible then - "Accept", MediaTypes.ApplicationJson - if jsonConsumable then - "Content-Type", MediaTypes.ApplicationJson |] - @> - - // Locates parameters matching the arguments - let parameters = - List.tail args // skip `this` param - |> List.map (function - | ShapeVar sVar as expr -> - let param = - op.Parameters - |> Array.find(fun x -> - // pain point: we have to make sure that the set of names we search for here are the same as the set of names generated when we make `parameters` above - let baseName = niceCamelName x.Name - baseName = sVar.Name || x.UnambiguousName = sVar.Name) - - param, expr - | _ -> failwithf $"Function '%s{methodName}' does not support functions as arguments.") - - // Makes argument a string // TODO: Make body an exception - let coerceString defType (format: CollectionFormat) exp = - let obj = Expr.Coerce(exp, typeof) |> Expr.Cast - <@ let x = (%obj) in RuntimeHelpers.toParam x @> - - let rec coerceQueryString name expr = - let obj = Expr.Coerce(expr, typeof) - <@ let o = (%%obj: obj) in RuntimeHelpers.toQueryParams name o (%this) @> - - let replacePathTemplate (path: Expr) (name: string) (value: Expr) = - let pattern = $"{{%s{name}}}" - // Escape $ in the replacement to avoid regex back-reference interpretation ($0, $& etc.) - let escaped = <@ (%value).Replace("$", "$$") @> - <@ Regex.Replace(%path, pattern, %escaped) @> - - let addPayload load (param: ParameterObject) (exp: Expr) = - let name = param.Name - let var = coerceString param.Type param.CollectionFormat exp - - match load with - | Some(FormData, b) -> Some(FormData, <@@ Seq.append %%b [ name, (%var: string) ] @@>) - | None -> - match param.In with - | Body -> Some(Body, Expr.Coerce(exp, typeof)) - | _ -> Some(FormData, <@@ (seq [ name, (%var: string) ]) @@>) - | _ -> failwith("Can only contain one payload") - - let addQuery (quer: Expr<(string * string) list>) name (exp: Expr) = - let listValues = coerceQueryString name exp - <@ List.append %quer %listValues @> - - let addHeader (heads: Expr<(string * string)[]>) name (value: Expr) = - <@ Array.append %heads [| name, %value |] @> - - // Partitions arguments based on their locations - let path, payload, queries, heads = - let mPath = op.Path - - parameters - |> List.fold - (fun (path, load, quer, head) (param: ParameterObject, exp) -> - let name = param.Name - - match param.In with - | Path -> - let value = coerceString param.Type param.CollectionFormat exp - (replacePathTemplate path name value, load, quer, head) - | FormData - | Body -> (path, addPayload load param exp, quer, head) - | Query -> (path, load, addQuery quer name exp, head) - | Header -> - let value = coerceString param.Type param.CollectionFormat exp - (path, load, quer, addHeader head name value)) - (<@ mPath @>, None, <@ [] @>, headers) - - let address = <@ RuntimeHelpers.combineUrl basePath %path @> - - let innerReturnType = defaultArg retTy null - - let httpRequestMessage = - <@ RuntimeHelpers.createHttpRequest httpMethod %address %queries @> - - let httpRequestMessageWithPayload = - match payload with - | None -> httpRequestMessage - | Some(FormData, b) -> - <@ - let data = (%%b: seq) |> Seq.map(fun (k, v) -> (k, box v)) - let content = RuntimeHelpers.toFormUrlEncodedContent data - let msg = %httpRequestMessage - msg.Content <- content - msg - @> - | Some(Body, b) -> - <@ - let valueStr = (%this).Serialize(%%b: obj) - let content = RuntimeHelpers.toStringContent(valueStr) - let msg = %httpRequestMessage - msg.Content <- content - msg - @> - | Some(x, _) -> failwith("Payload should not be able to have type: " + string x) - - let action = - <@ - let msg = %httpRequestMessageWithPayload - RuntimeHelpers.fillHeaders msg %heads - - task { - let! response = (%this).HttpClient.SendAsync(msg) - return response.EnsureSuccessStatusCode().Content - } - @> - - let responseObj = - <@ - let x = %action - - task { - let! response = x - let! content = response.ReadAsStringAsync() - return (%this).Deserialize(content, innerReturnType) - } - @> - - let responseUnit = - <@ - let x = %action - - task { - let! _ = x - return () - } - @> - - let awaitTask t = - <@ Async.AwaitTask(%t) @> - - // if we're an async method, then we can just return the above, coerced to the overallReturnType. - // if we're not async, then run that^ through Async.RunSynchronously before doing the coercion. - match asAsync, retTy with - | false, Some t -> Expr.Coerce(<@ RuntimeHelpers.taskCast t %responseObj @>, overallReturnType) - | false, None -> responseUnit.Raw - | true, Some t -> Expr.Coerce(<@ RuntimeHelpers.asyncCast t %(awaitTask responseObj) @>, overallReturnType) - | true, None -> (awaitTask responseUnit).Raw - ) - - let xmlDoc = - let paramDescriptions = - [ for p in op.Parameters -> niceCamelName p.Name, p.Description ] - - XmlDoc.buildXmlDoc op.Summary op.Description paramDescriptions - - if not(String.IsNullOrEmpty xmlDoc) then - m.AddXmlDoc xmlDoc - - if op.Deprecated then - m.AddObsoleteAttribute("Operation is deprecated", false) - - m - - static member GetMethodNameCandidate (op: OperationObject) skipLength ignoreOperationId = - if ignoreOperationId || String.IsNullOrWhiteSpace(op.OperationId) then - let _, pathParts = - (op.Path.Split([| '/' |], StringSplitOptions.RemoveEmptyEntries), (false, [])) - ||> Array.foldBack(fun x (nextIsArg, pathParts) -> - if x.StartsWith("{") then - (true, pathParts) - else - (false, (if nextIsArg then singularize x else x) :: pathParts)) - - String.Join("_", op.Type.ToString() :: pathParts) - else - op.OperationId.Substring(skipLength) - |> nicePascalName - - member _.CompileProvidedClients(ns: NamespaceAbstraction) = - let defaultHost = - let protocol = - match schema.Schemes with - | [||] -> "http" // Should use the scheme used to access the Swagger definition itself. - | array -> array[0] - - $"%s{protocol}://%s{schema.Host}" - - let baseTy = Some typeof - let baseCtor = baseTy.Value.GetConstructors().[0] - - List.ofArray schema.Paths - |> List.groupBy(fun x -> - if ignoreControllerPrefix then - String.Empty // - else - let ind = x.OperationId.IndexOf("_") - - if ind <= 0 then - String.Empty - else - x.OperationId.Substring(0, ind)) - |> List.iter(fun (clientName, operations) -> - let tyName = ns.ReserveUniqueName clientName "Client" - - let ty = - ProvidedTypeDefinition(tyName, baseTy, isErased = false, isSealed = false, hideObjectMethods = true) - - ns.RegisterType(tyName, ty) - - if not <| String.IsNullOrEmpty clientName then - ty.AddXmlDoc $"Client for '%s{clientName}_*' operations" - - [ ProvidedConstructor( - [ ProvidedParameter("httpClient", typeof) - ProvidedParameter("options", typeof) ], - invokeCode = - (fun args -> - match args with - | [] -> failwith "Generated constructors should always pass the instance as the first argument!" - | _ -> <@@ () @@>), - BaseConstructorCall = fun args -> (baseCtor, args) - ) - ProvidedConstructor( - [ ProvidedParameter("httpClient", typeof) ], - invokeCode = - (fun args -> - match args with - | [] -> failwith "Generated constructors should always pass the instance as the first argument!" - | _ -> <@@ () @@>), - BaseConstructorCall = - fun args -> - let args' = args @ [ <@@ null @@> ] - (baseCtor, args') - ) - ProvidedConstructor( - [ ProvidedParameter("options", typeof) ], - invokeCode = (fun _ -> <@@ () @@>), - BaseConstructorCall = - fun args -> - let httpClient = <@ RuntimeHelpers.getDefaultHttpClient defaultHost @> :> Expr - - let args' = - match args with - | [ instance; options ] -> [ instance; httpClient; options ] - | _ -> failwithf $"unexpected arguments received %A{args}" - - (baseCtor, args') - ) - ProvidedConstructor( - [], - invokeCode = (fun _ -> <@@ () @@>), - BaseConstructorCall = - fun args -> - let httpClient = <@ RuntimeHelpers.getDefaultHttpClient defaultHost @> :> Expr - - let args' = - match args with - | [ instance ] -> [ instance; httpClient; <@@ null @@> ] - | _ -> failwithf $"unexpected arguments received %A{args}" - - (baseCtor, args') - ) ] - |> ty.AddMembers - - let methodNameScope = UniqueNameGenerator() - - operations - |> List.map(fun op -> - let skipLength = - if String.IsNullOrEmpty clientName then - 0 - else - clientName.Length + 1 - - let name = OperationCompiler.GetMethodNameCandidate op skipLength ignoreOperationId - compileOperation (methodNameScope.MakeUnique name) op) - |> ty.AddMembers) diff --git a/src/SwaggerProvider.DesignTime/v2/Parser/Parsers.fs b/src/SwaggerProvider.DesignTime/v2/Parser/Parsers.fs deleted file mode 100644 index 5ade60b4..00000000 --- a/src/SwaggerProvider.DesignTime/v2/Parser/Parsers.fs +++ /dev/null @@ -1,512 +0,0 @@ -namespace SwaggerProvider.Internal.v2.Parser - -open System -open SwaggerProvider.Internal.v2.Parser.Schema -open System.Collections.Generic - -module Exceptions = - - type SwaggerSchemaParseException(message) = - inherit Exception(message) - - /// Schema object does not contain the `field` that is Required in Swagger specification. - type FieldNotFoundException<'T>(obj: 'T, field: string, specLink: string) = - inherit SwaggerSchemaParseException $"Object MUST contain field `%s{field}` (See %s{specLink} for more details).\nObject:%A{obj}" - - /// The `field` value is not specified in Swagger specification - type UnknownFieldValueException<'T>(obj: 'T, value: string, field: string, specLink: string) = - inherit - SwaggerSchemaParseException $"Value `%s{value}` is not allowed for field `%s{field}`(See %s{specLink} for more details).\nObject:%A{obj}" - - /// The `value` has unexpected type - type UnexpectedValueTypeException<'T>(obj: 'T, ty: string) = - inherit SwaggerSchemaParseException $"Expected `%s{ty}` type, but received `%A{obj}`" - - /// Unsupported Swagger version - type UnsupportedSwaggerVersionException(version) = - inherit SwaggerSchemaParseException $"SwaggerProviders does not Swagger Specification %s{version}" - - /// Unknown reference - type UnknownSwaggerReferenceException(ref: string) = - inherit SwaggerSchemaParseException $"SwaggerProvider could not resolve `$ref`: %s{ref}" - -[] -type SchemaNode() = - /// Get the boolean value of an element (assuming that value is a boolean) - abstract member AsBoolean: unit -> bool - /// Get the string value of an element (assuming that value is a string) - abstract member AsString: unit -> string - /// Get all elements of Node element. Returns an empty array if the value is not an array - abstract member AsArray: unit -> SchemaNode[] - /// Get the string[] value of an element and exclude 'null' strings (assuming that value is string or string[]) - abstract member AsStringArrayWithoutNull: unit -> string[] - - /// Get the map value of an element (assuming that value is a map) - abstract member Properties: unit -> (string * SchemaNode)[] - /// Try get property values from the map by property name - abstract member TryGetProperty: string -> SchemaNode option - - /// Get field that is `Required` in Swagger specification - member this.GetRequiredField(fieldName, spec) = - match this.TryGetProperty(fieldName) with - | Some(value) -> value - | None -> raise <| Exceptions.FieldNotFoundException(this, fieldName, spec) - - /// Gets the string value of the property if it exists. Empty string otherwise. - member this.GetStringSafe(propertyName) = - match this.TryGetProperty(propertyName) with - | Some(value) -> value.AsString() - | None -> "" - - /// Gets the string array for the property if it exists. Empty array otherwise. - member this.GetStringArraySafe(propertyName) = - match this.TryGetProperty(propertyName) with - | Some(value) -> value.AsArray() |> Array.map(_.AsString()) - | None -> [||] - -module Parsers = - open Exceptions - - let emptyDict = Dictionary>() - - // Type that hold parsing context to resolve `$ref`s - type ParserContext = - { - /// An object to hold type definitions - Definitions: Dictionary> - /// An object to hold parameters that can be used across operations - Parameters: Map - /// An object to hold responses that can be used across operations. - Responses: Map - /// A list of parameters that are applicable for all the operations described under this path. - /// These parameters can be overridden at the operation level, but cannot be removed there. - /// The list MUST NOT include duplicated parameters. A unique parameter is defined by a combination of - /// a name and location. The list can use the Reference Object to link to parameters that are defined - /// at the Swagger Object's parameters. There can be one "body" parameter at most. - ApplicableParameters: ParameterObject[] - } - - /// Resolve ParameterObject by `$ref` if such field exists - member this.ResolveParameterObject(obj: SchemaNode) = - obj.TryGetProperty("$ref") - |> Option.map(fun refObj -> - let ref = refObj.AsString() - - match this.Parameters.TryFind(ref) with - | Some(param) -> - match obj.TryGetProperty("required") with - | Some(req) -> - { param with - Required = req.AsBoolean() } - | _ -> param - | None -> raise <| UnknownSwaggerReferenceException(ref)) - - // Resolve ResponseObject by `$ref` if such field exists - member this.ResolveResponseObject(obj: SchemaNode) = - obj.TryGetProperty("$ref") - |> Option.map(fun refObj -> - let ref = refObj.AsString() - - match this.Responses.TryFind(ref) with - | Some(response) -> response - | None -> - match this.Definitions.TryGetValue(ref) with - | true, def -> // Slightly strange use of `ref` from response to `definitions` rather than to `responses` - let schema = def.Value - - { Description = "" - Schema = Some(schema) } // TODO: extract description from definition object - | _ -> raise <| UnknownSwaggerReferenceException(ref)) - - /// Default empty context - static member Empty = - { Definitions = emptyDict - Parameters = Map.empty<_, _> - Responses = Map.empty<_, _> - ApplicableParameters = [||] } - - - /// Verify if name follows Swagger Schema Extension name pattern - let isSwaggerSchemaExtensionName(name: string) = - name.StartsWith("x-") - - // TODO: ... - /// Parses the SchemaNode as a SchemaObject - let rec parseSchemaObject (definitions: Dictionary>) (obj: SchemaNode) : SchemaObject = - let spec = "http://swagger.io/specification/#schemaObject" - - let (|IsEnum|_|)(obj: SchemaNode) = - // Parse `enum` - http://json-schema.org/latest/json-schema-validation.html#anchor76 - obj.TryGetProperty("enum") - |> Option.map(fun cases -> cases.AsArray() |> Array.map(_.AsString())) - - let (|IsRef|_|)(obj: SchemaNode) = - obj.TryGetProperty("$ref") // Parse `$refs` - |> Option.map(_.AsString()) - - let (|IsArray|_|)(obj: SchemaNode) = - // Parse Arrays - http://json-schema.org/latest/json-schema-validation.html#anchor36 - // TODO: `items` may be an array, `additionalItems` may be filled - obj.TryGetProperty("type") - |> Option.bind(fun ty -> - match ty.AsStringArrayWithoutNull() with - | [| "array" |] -> obj.TryGetProperty("items") - | _ -> None) - |> Option.map(parseSchemaObject definitions) - - let (|IsPrimitive|_|)(obj: SchemaNode) = - // Parse primitive types - obj.TryGetProperty("type") - |> Option.bind(fun ty -> - let format = obj.GetStringSafe("format") - - match ty.AsStringArrayWithoutNull() with - | [| "boolean" |] -> Some Boolean - | [| "integer" |] when format = "int32" -> Some Int32 - | [| "integer" |] -> Some Int64 - | [| "number" |] when format = "float" -> Some Float - | [| "number" |] when format = "int32" -> Some Int32 - | [| "number" |] when format = "int64" -> Some Int64 - | [| "number" |] -> Some Double - | [| "string" |] when format = "date" -> Some Date - | [| "string" |] when format = "date-time" -> Some DateTime - | [| "string" |] when format = "byte" -> Some <| Array Byte - | [| "string" |] -> Some String - | [| "file" |] -> Some File - | _ -> None) - - let (|IsObject|_|)(obj: SchemaNode) = - // TODO: Parse Objects - obj.TryGetProperty("properties") - |> Option.map(fun properties -> - let requiredProperties = - match obj.TryGetProperty("required") with - | None -> Set.empty<_> - | Some(req) -> req.AsArray() |> Array.map(_.AsString()) |> Set.ofArray - - let properties = - properties.Properties() - |> Array.map(fun (name, obj) -> parseDefinitionProperty definitions (name, obj, requiredProperties.Contains name)) - - properties) - - let (|IsDict|_|)(obj: SchemaNode) = - // Parse Object that represent Dictionary - match obj.TryGetProperty("type") with - | Some(ty) when ty.AsStringArrayWithoutNull() = [| "object" |] -> - obj.TryGetProperty("additionalProperties") - |> Option.bind(fun obj -> - match parseSchemaObject definitions obj with - | Object [||] -> None - | schemaObj -> Some schemaObj) - | _ -> None - - let (|IsAllOf|_|)(obj: SchemaNode) = - // Identify composition element 'allOf' - obj.TryGetProperty("allOf") |> Option.map(_.AsArray()) - - let (|IsComposition|_|)(obj: SchemaNode) = - // Models with Object Composition - match obj with - | IsAllOf allOf -> - let components = - allOf - |> Array.map(fun x -> - match parseSchemaObject definitions x with - | Object props -> Some props - | Reference path -> - match definitions.TryGetValue path with - | true, lazeObj -> - match lazeObj.Value with - | Object props -> Some props - | _ -> None - | _ -> failwithf $"Reference to unknown type %s{path}" - | _ -> None) - - if components |> Array.forall(Option.isSome) then - components |> Array.choose id |> Array.concat |> Some - else - None // One of elements is not an Object and we cannot Compose - - | _ -> None - - let (|IsWrapper|_|)(obj: SchemaNode) = - // Support for obj that wrap another obj / primitive - // Sample https://github.com/APIs-guru/openapi-directory/issues/98 - match obj with - | IsAllOf allOf when allOf.Length = 1 -> - parseSchemaObject definitions allOf.[0] - |> function - | Reference path -> - match definitions.TryGetValue path with - | true, lazeObj -> Some <| lazeObj.Value - | _ -> failwithf $"Reference to unknown type %s{path}" - | _ -> None - | _ -> None - - let (|IsPolymorphism|_|)(obj: SchemaNode) = - // Models with Polymorphism Support - obj.TryGetProperty("discriminator") - - match obj with - | IsEnum cases -> - let ty = - obj.TryGetProperty("type") - |> Option.map(_.AsString()) - |> Option.defaultValue "string" - - Enum(cases, ty) - | IsRef ref -> Reference ref - | IsArray itemTy -> Array itemTy - | IsPrimitive ty -> ty - | IsDict itemTy -> SchemaObject.Dictionary itemTy - | IsObject objProps & IsComposition compProps -> Object <| Array.append compProps objProps - | IsObject props -> Object props - | IsComposition props -> Object props - | IsWrapper ty -> ty - | IsPolymorphism _ -> - failwith - "Models with Polymorphism Support is not supported yet. If you see this error please report it on GitHub (https://github.com/fsprojects/SwaggerProvider/issues) with schema example." - | _ -> Object [||] // Default type when parsers could not determine the type based ob schema. - // Example of schema : {} - - - /// Parses DefinitionProperty - and parseDefinitionProperty parsedTys (name, obj, required) : DefinitionProperty = - { Name = name - Type = parseSchemaObject parsedTys obj - IsRequired = required - Description = obj.GetStringSafe("description") } - - /// Parses string as a ParameterObjectLocation. - let parseOperationParameterLocation obj (location: string) : ParameterObjectLocation = - let spec = "http://swagger.io/specification/#parameterObject" - - match location with - | "query" -> Query - | "header" -> Header - | "path" -> Path - | "formData" -> FormData - | "body" -> Body - | _ -> raise <| UnknownFieldValueException(obj, location, "in", spec) - - /// Parses the SchemaNode as a ParameterObject. - let parseParameterObject (definitions: Dictionary>) (obj: SchemaNode) : ParameterObject = - let spec = "http://swagger.io/specification/#parameterObject" - - let location = - obj.GetRequiredField("in", spec).AsString() - |> (parseOperationParameterLocation obj) - - { Name = obj.GetRequiredField("name", spec).AsString() - In = location - Description = obj.GetStringSafe("description") - Required = - match obj.TryGetProperty("required") with - | Some(x) -> x.AsBoolean() - | None -> false - Type = - match location with - | Body -> obj.GetRequiredField("schema", spec) |> parseSchemaObject definitions - | _ -> obj |> parseSchemaObject definitions - // The `type` value MUST be one of "string", "number", "integer", "boolean", "array" or "file" - CollectionFormat = - match location, obj.TryGetProperty("collectionFormat") with - | Body, Some _ -> failwith "The field collectionFormat is not applicable for parameters of type body" - | _, Some x when x.AsString() = "csv" -> Csv - | _, Some x when x.AsString() = "ssv" -> Ssv - | _, Some x when x.AsString() = "tsv" -> Tsv - | _, Some x when x.AsString() = "pipes" -> Pipes - | FormData, Some x when x.AsString() = "multi" -> Multi - | Query, Some x when x.AsString() = "multi" -> Multi - | _, Some x when x.AsString() = "multi" -> failwith "Format `multi` is only supported by Query and FormData" - | _, Some x -> failwithf $"Format `%s{x.AsString()}` is not supported" - | _, None -> Csv // Default value - } - - /// Parse the SchemaNode as a Parameters Definition Object - let parseParametersDefinition (definitions: Dictionary>) (obj: SchemaNode) : Map = - obj.Properties() - |> Array.map(fun (name, obj) -> "#/parameters/" + name, parseParameterObject definitions obj) - |> Map.ofArray - - /// Parses the SchemaNode as a ResponseObject. - let parseResponseObject (context: ParserContext) (obj: SchemaNode) : ResponseObject = - let spec = "http://swagger.io/specification/#responseObject" - - match context.ResolveResponseObject obj with - | Some(response) -> response - | None -> - { Description = obj.GetRequiredField("description", spec).AsString() - Schema = - obj.TryGetProperty("schema") - |> Option.map(parseSchemaObject context.Definitions) } - - /// Parses the SchemaNode as a Responses Definition Object - let parseResponsesDefinition(obj: SchemaNode) : Map = - obj.Properties() - |> Array.map(fun (name, obj) -> "#/responses/" + name, parseResponseObject (ParserContext.Empty) obj) - |> Map.ofSeq - - /// Parses the SchemaNode as a ResponseObject[]. - let parseResponsesObject (context: ParserContext) (obj: SchemaNode) : (Option * ResponseObject)[] = - let spec = "http://swagger.io/specification/#httpCodes" - - obj.Properties() - |> Array.filter(fun (property, _) -> not <| isSwaggerSchemaExtensionName property) - |> Array.map(fun (property, objValue) -> - let code = - if property = "default" then - None - else - match Int32.TryParse(property) with - | true, value -> Some value - | false, _ -> raise(UnknownFieldValueException(obj, property, "HTTP Status Code", spec)) - - code, parseResponseObject context objValue) - - /// Parses the SchemaNode as an OperationObject. - let parseOperationObject (context: ParserContext) path opType (obj: SchemaNode) : OperationObject = - let spec = "http://swagger.io/specification/#operationObject" - - let mergeParameters (specified: ParameterObject[]) (inherited: ParameterObject[]) = - Array.append specified inherited - |> Array.fold - (fun (cache, result) param -> - let key = (param.Name, param.In) - - if Set.contains key cache then - (cache, result) - else - (Set.add key cache, param :: result)) - (Set.empty<_>, []) - |> snd - |> List.rev - |> Array.ofList - - { Path = path - Type = opType - Tags = obj.GetStringArraySafe("tags") - Summary = obj.GetStringSafe("summary") - Description = obj.GetStringSafe("description") - OperationId = obj.GetStringSafe("operationId") - Consumes = obj.GetStringArraySafe("consumes") - Produces = obj.GetStringArraySafe("produces") - Deprecated = - match obj.TryGetProperty("deprecated") with - | Some(value) -> value.AsBoolean() - | None -> false - Responses = - obj.GetRequiredField("responses", spec) - |> (parseResponsesObject context) - Parameters = - mergeParameters - (match obj.TryGetProperty("parameters") with - | Some(parameters) -> - parameters.AsArray() - |> Array.map(fun obj -> - match context.ResolveParameterObject obj with - | Some(param) -> param - | None -> parseParameterObject context.Definitions obj) - | None -> [||]) - context.ApplicableParameters } - - /// Parse the SchemaNode as a PathItemObject[] - let parsePathsObject (context: ParserContext) (obj: SchemaNode) : OperationObject[] = - let parsePathItemObject (context: ParserContext) path (field, obj) = - match field with - | "get" -> Some <| parseOperationObject context path Get obj - | "put" -> Some <| parseOperationObject context path Put obj - | "post" -> Some <| parseOperationObject context path Post obj - | "delete" -> Some <| parseOperationObject context path Delete obj - | "options" -> Some <| parseOperationObject context path Options obj - | "head" -> Some <| parseOperationObject context path Head obj - | "patch" -> Some <| parseOperationObject context path Patch obj - | "$ref" -> failwith "External definition of this path item is not supported yet" - | _ -> None - - let updateContext(pathItemObj: SchemaNode) = - match pathItemObj.TryGetProperty("parameters") with - | None -> context - | Some(parameters) -> - { context with - ApplicableParameters = - parameters.AsArray() - |> Array.map(fun paramObj -> - match context.ResolveParameterObject paramObj with - | Some(param) -> param - | None -> parseParameterObject context.Definitions paramObj) } - - obj.Properties() - |> Array.filter(fun (path, _) -> not <| isSwaggerSchemaExtensionName path) - |> Array.collect(fun (path, pathItemObj) -> - let newContext = updateContext pathItemObj - - pathItemObj.Properties() - |> Array.choose(parsePathItemObject newContext path)) - - /// Parse the SchemaNode as a SchemaObject[] - let parseDefinitionsObject(obj: SchemaNode) : Dictionary> = - let defs = Dictionary>() - - obj.Properties() - |> Array.iter(fun (name, schemaObj) -> defs.Add("#/definitions/" + name, lazy (parseSchemaObject defs schemaObj))) - - defs - - /// Parses the SchemaNode as an InfoObject. - let parseInfoObject(obj: SchemaNode) : InfoObject = - let spec = "http://swagger.io/specification/#infoObject" - - { Title = obj.GetRequiredField("title", spec).AsString() - Description = obj.GetStringSafe("description") - Version = obj.GetRequiredField("version", spec).AsString() } - - /// Parses the SchemaNode as a TagObject. - let parseTagObject(obj: SchemaNode) : TagObject = - let spec = "http://swagger.io/specification/#tagObject" - - { Name = obj.GetRequiredField("name", spec).AsString() - Description = obj.GetStringSafe("description") } - - /// Parses the SchemaNode as a SwaggerSchema. - let parseSwaggerObject(obj: SchemaNode) : SwaggerObject = - let spec = "http://swagger.io/specification/#swaggerObject" - - let swaggerVersion = obj.GetRequiredField("swagger", spec).AsString() - - if swaggerVersion <> "2.0" then - raise <| UnsupportedSwaggerVersionException(swaggerVersion) - - // Context holds parameters and responses that could be referenced from path definitions - let context = - let definitions = - match obj.TryGetProperty("definitions") with - | None -> emptyDict - | Some(definitions) -> parseDefinitionsObject definitions - - { ParserContext.Empty with - Definitions = definitions - Parameters = - match obj.TryGetProperty("parameters") with - | None -> Map.empty<_, _> - | Some(parameters) -> parseParametersDefinition definitions parameters - Responses = - match obj.TryGetProperty("responses") with - | None -> Map.empty<_, _> - | Some(responses) -> parseResponsesDefinition responses } - - { Info = parseInfoObject(obj.GetRequiredField("info", spec)) - Host = obj.GetStringSafe("host") - BasePath = obj.GetStringSafe("basePath") - Schemes = obj.GetStringArraySafe("schemes") - Tags = - match obj.TryGetProperty("tags") with - | None -> [||] - | Some(tags) -> tags.AsArray() |> Array.map parseTagObject - Paths = obj.GetRequiredField("paths", spec) |> (parsePathsObject context) - Definitions = - context.Definitions - |> Seq.map(fun x -> x.Key, x.Value.Value) - |> Seq.sortBy(id) - |> Array.ofSeq } diff --git a/src/SwaggerProvider.DesignTime/v2/Parser/Schema.fs b/src/SwaggerProvider.DesignTime/v2/Parser/Schema.fs deleted file mode 100644 index 7c485972..00000000 --- a/src/SwaggerProvider.DesignTime/v2/Parser/Schema.fs +++ /dev/null @@ -1,242 +0,0 @@ -namespace SwaggerProvider.Internal.v2.Parser.Schema - -/// A data type produced or consumed by operations. -/// http://swagger.io/specification/#schemaObject -type SchemaObject = - /// Boolean. - | Boolean - /// Byte - we need this to support byte[] transfered as base64 encoded string - | Byte - /// Integer (signed 32 bits). - | Int32 - /// Long (signed 64 bits). - | Int64 - /// Float. - | Float - /// Double. - | Double - /// String. - | String - /// Date (As defined by full-date - RFC3339). - | Date - /// Date-Time (As defined by date-time - RFC3339). - | DateTime - /// An additional primitive data type used by the Parameter Object and the Response Object to set the parameter type or the response as being a file. - | File - /// Enumeration - | Enum of values: string[] * ``type``: string - /// Array of items of type itemTy - | Array of itemTy: SchemaObject - /// Object - | Object of DefinitionProperty[] - /// Dictionary - | Dictionary of ty: SchemaObject - /// A reference to an object defined by a Schema Object. - | Reference of name: string - - override this.ToString() = - match this with - | Object _ -> "Object" - | Boolean -> "Boolean" - | Byte -> "Byte" - | Int32 -> "Int32" - | Int64 -> "Int64" - | Float -> "Float" - | Double -> "Double" - | String -> "String" - | Date -> "Date" - | DateTime -> "DateTime" - | Enum(x, ty) -> $"Enum %A{x} represented as %s{ty}" - | Array x -> $"Array {x}" - | Dictionary x -> $"Dictionary {x}" - | File -> "File" - | Reference s -> $"Reference %s{s}" - - -/// The property of a data type. -and DefinitionProperty = - { - /// The name of the property. - Name: string - /// The type of the property. - Type: SchemaObject - /// True if the property is required. - IsRequired: bool - /// A description of the property. - Description: string - } - - -/// The type of the REST call. -/// http://swagger.io/specification/#pathItemObject -[] -type OperationType = - /// Returns en element or collection. - | Get - /// Updates an element. - | Put - /// Adds an element. - | Post - /// Removes an element. - | Delete - | Options - | Head - | Patch - - override this.ToString() = - match this with - | Get -> "GET" - | Put -> "PUT" - | Post -> "POST" - | Delete -> "DELETE" - | Options -> "OPTIONS" - | Head -> "HEAD" - | Patch -> "PATCH" - - -/// Determines the format of the array if type array is used. Array value separator. -[] -type CollectionFormat = - /// Comma separated values. - | Csv - /// Space separated values. - | Ssv - /// Tab separated values. - | Tsv - /// Pipe separated values. - | Pipes - /// Corresponds to multiple parameter instances instead of multiple values for a single instance. - | Multi - - override this.ToString() = - match this with - | Csv -> "," - | Ssv -> " " - | Tsv -> "\t" - | Pipes -> "|" - | Multi -> failwith "CollectionFormat 'Multi' does not support ToString()" - - -/// Required. The location of the parameter. -[] -type ParameterObjectLocation = - /// Parameter that are appended to the URL. For example, in /items?id=###, the query parameter is id. - | Query - /// Custom header that are expected as part of the request. - | Header - /// Used together with Path Templating, where the parameter value is actually part of the operation's URL. This does not include the host or base path of the API. For example, in /items/{itemId}, the path parameter is itemId. - | Path - /// Used to describe the payload of an HTTP request. - | FormData - /// The payload that's appended to the HTTP request. Since there can only be one payload, there can only be one body parameter. The name of the body parameter has no effect on the parameter itself and is used for documentation purposes only. Since Form parameters are also in the payload, body and form parameters cannot exist together for the same operation. - | Body - - -/// Describes a single operation parameter. -/// http://swagger.io/specification/#parameterObject -type ParameterObject = - { - /// Required. The name of the parameter. Parameter names are case sensitive. - /// If in is "path", the name field MUST correspond to the associated path segment from the path field in the Paths Object. See Path Templating for further information. - /// For all other cases, the name corresponds to the parameter name used based on the in property. - Name: string - /// Required. The location of the parameter. - In: ParameterObjectLocation - /// A brief description of the parameter. This could contain examples of use. - Description: string - /// Determines whether this parameter is mandatory. If the parameter is in "path", this property is required and its value MUST be true. Otherwise, the property MAY be included and its default value is false. - Required: bool - /// The type of the parameter. Unlike the corresponding swagger field, this contains the Schema Object if 'in' is of type Body. - Type: SchemaObject - /// Determines the format of the array if type array is used. - CollectionFormat: CollectionFormat - } - - member x.UnambiguousName = $"%s{x.Name}In%A{x.In}" - - -/// Describes a single response from an API Operation. -/// http://swagger.io/specification/#responseObject -type ResponseObject = - { - /// Required. A short description of the response. - Description: string - /// A definition of the response structure. It can be a primitive, an array or an object. If this field does not exist, it means no content is returned as part of the response. - Schema: SchemaObject option - } - - -/// Describes a single API operation on a path. -/// http://swagger.io/specification/#operationObject -type OperationObject = - { - /// The name of the operation. - Path: string - /// The type of the REST call. - Type: OperationType - /// A list of tags for API documentation control. - Tags: string[] - /// A short summary of what the operation does. This field SHOULD be less than 120 characters. - Summary: string - /// A verbose explanation of the operation behavior. - Description: string - /// Unique string used to identify the operation. - OperationId: string - /// A list of MIME types the operation can consume. - Consumes: string[] - /// A list of MIME types the operation can produce. - Produces: string[] - /// Required. The nonempty list of possible status codes and responses as they are returned from executing this operation. - Responses: (Option * ResponseObject)[] - /// A list of parameters that are applicable for this operation. The list MUST NOT include duplicated parameters. - Parameters: ParameterObject[] - /// Declares this operation to be deprecated. - Deprecated: bool - } - - -/// Basic swagger information, relevant to the type provider. -/// http://swagger.io/specification/#infoObject -[] -type InfoObject = - { - /// Required. The title of the application. - Title: string - /// A short description of the application. - Description: string - /// Required. Provides the version of the application API (not to be confused with the specification version). - Version: string - } - - -/// Allows adding meta data to a single tag. -/// http://swagger.io/specification/#tagObject -[] -type TagObject = - { - /// Required. The name of the tag. - Name: string - /// A short description for the tag. - Description: string - } - - -/// This is the main object. -/// http://swagger.io/specification/#swaggerObject -type SwaggerObject = - { - /// Required. Provides metadata about the API. - Info: InfoObject - /// The host (name or ip) serving the API. - Host: string - /// The base path on which the API is served, which is relative to the host. - BasePath: string - /// The transfer protocol of the API. Values MUST be from the list: "http", "https", "ws", "wss". (Only the first element of the list will be used) - Schemes: string[] - /// Required. A list of all operations. - Paths: OperationObject[] - /// An object to hold data types produced and consumed by operations. - Definitions: (string * SchemaObject)[] - /// A list of tags used by the specification with additional metadata. - Tags: TagObject[] - } diff --git a/src/SwaggerProvider.DesignTime/v2/Parser/SchemaParserExceptions.fs b/src/SwaggerProvider.DesignTime/v2/Parser/SchemaParserExceptions.fs deleted file mode 100644 index e0a9a40c..00000000 --- a/src/SwaggerProvider.DesignTime/v2/Parser/SchemaParserExceptions.fs +++ /dev/null @@ -1,26 +0,0 @@ -namespace SwaggerProvider.Internal.v2.Parser - -open System - -type SwaggerSchemaParseException(message) = - inherit Exception(message) - -/// Schema object does not contain the `field` that is Required in Swagger specification. -type FieldNotFoundException<'T>(obj: 'T, field: string, specLink: string) = - inherit SwaggerSchemaParseException $"Object MUST contain field `%s{field}` (See %s{specLink} for more details).\nObject:%A{obj}" - -/// The `field` value is not specified in Swagger specification -type UnknownFieldValueException<'T>(obj: 'T, value: string, field: string, specLink: string) = - inherit SwaggerSchemaParseException $"Value `%s{value}` is not allowed for field `%s{field}`(See %s{specLink} for more details).\nObject:%A{obj}" - -/// The `value` has unexpected type -type UnexpectedValueTypeException<'T>(obj: 'T, ty: string) = - inherit SwaggerSchemaParseException $"Expected `%s{ty}` type, but received `%A{obj}`" - -/// Unsupported Swagger version -type UnsupportedSwaggerVersionException(version) = - inherit SwaggerSchemaParseException $"SwaggerProviders does not Swagger Specification %s{version}" - -/// Unknown reference -type UnknownSwaggerReferenceException(ref: string) = - inherit SwaggerSchemaParseException $"SwaggerProvider could not resolve `$ref`: %s{ref}" diff --git a/src/SwaggerProvider.DesignTime/v2/Parser/SwaggerParser.fs b/src/SwaggerProvider.DesignTime/v2/Parser/SwaggerParser.fs deleted file mode 100644 index 3f5b5601..00000000 --- a/src/SwaggerProvider.DesignTime/v2/Parser/SwaggerParser.fs +++ /dev/null @@ -1,162 +0,0 @@ -namespace SwaggerProvider.Internal.v2.Parser - -open SwaggerProvider.Internal.v2.Parser.Schema -open SwaggerProvider.Internal.v2.Parser.Exceptions - -module internal JsonAdapter = - - open System.Text.Json - - /// Schema node for Swagger schemes in Json format - type JsonNodeAdapter(value: JsonElement) = - inherit SchemaNode() - - override _.AsBoolean() = - value.GetBoolean() - - override _.AsString() = - value.ToString() - - override _.AsArray() = - match value.ValueKind with - | JsonValueKind.Array -> - [| for item in value.EnumerateArray() do - JsonNodeAdapter(item) :> SchemaNode |] - | _ -> raise <| UnexpectedValueTypeException(value, "string") - - override _.AsStringArrayWithoutNull() = - match value.ValueKind with - | JsonValueKind.String -> [| value.GetString() |] - | JsonValueKind.Array -> - [| for item in value.EnumerateArray() do - item.GetString() |] - |> Seq.filter(fun x -> x <> "null") - |> Seq.toArray - | other -> failwithf $"Value: '%A{other}' cannot be converted to StringArray" - - override _.Properties() = - match value.ValueKind with - | JsonValueKind.Object -> - [| for item in value.EnumerateObject() do - item.Name, JsonNodeAdapter(item.Value) :> SchemaNode |] - | _ -> raise <| UnexpectedValueTypeException(value, "Object") - - override _.TryGetProperty(property) = - match value.ValueKind with - | JsonValueKind.Object -> - match value.TryGetProperty(property) with - | true, x -> Some(JsonNodeAdapter(x) :> SchemaNode) - | _ -> None - | _ -> None - - let parse(string: string) = - (JsonDocument.Parse string).RootElement |> JsonNodeAdapter - -module internal YamlAdapter = - - open System - open System.Collections.Generic - open System.IO - open YamlDotNet.Serialization - - let (|List|_|)(node: obj) = - match node with - | :? List as l -> Some l - | _ -> None - - let (|Map|_|)(node: obj) = - match node with - | :? Dictionary as dict -> - dict - |> Seq.choose(fun p -> - match p.Key with - | :? string as key -> Some(key, p.Value) - | _ -> None) - |> Some - | _ -> None - - let (|Scalar|_|)(node: obj) = - match node with - | :? List - | :? Dictionary -> None - | scalar -> - let value = if isNull scalar then "" else scalar.ToString() - - Some(value) - - /// SchemaNode for Swagger schemes in Yaml format - type YamlNodeAdapter(value: obj) = - inherit SchemaNode() - - override _.AsBoolean() = - match value with - | Scalar(x) -> System.Boolean.Parse(x) - | _ -> raise <| UnexpectedValueTypeException(value, "bool") - - override _.AsString() = - match value with - | Scalar(x) -> x - | _ -> raise <| UnexpectedValueTypeException(value, "string") - - override _.AsArray() = - match value with - | List(nodes) -> - nodes - |> Seq.map(fun x -> YamlNodeAdapter(x) :> SchemaNode) - |> Array.ofSeq - | _ -> [||] - - override _.AsStringArrayWithoutNull() = - match value with - | Scalar(x) -> [| x |] - | List(nodes) -> - nodes - |> Seq.map (function - | Scalar(x) -> x - | x -> failwithf $"'%A{x}' cannot be converted to string") - |> Seq.filter(fun x -> x <> "null") - |> Seq.toArray - | other -> failwithf $"Value: '%A{other}' cannot be converted to StringArray" - - override _.Properties() = - match value with - | Map(pairs) -> - pairs - |> Seq.map(fun (a, b) -> (a, YamlNodeAdapter(b) :> SchemaNode)) - |> Array.ofSeq - | _ -> raise <| UnexpectedValueTypeException(value, "map") - - override _.TryGetProperty(prop) = - match value with - | Map(items) -> - items - |> Seq.tryFind(fst >> ((=) prop)) - |> Option.map(fun (_, x) -> YamlNodeAdapter(x) :> SchemaNode) - | _ -> None - - let private deserializer = Deserializer() - - let parse(text: string) = - try - use reader = new StringReader(text) - deserializer.Deserialize(reader) |> YamlNodeAdapter - with - | :? YamlDotNet.Core.YamlException as e when not <| isNull e.InnerException -> e.InnerException.Reraise() // inner exceptions are much more informative - | _ -> reraise() - -module SwaggerParser = - - let parseJson schema = - (JsonAdapter.parse schema) :> SchemaNode - - let parseYaml schema = - (YamlAdapter.parse schema) :> SchemaNode - - let parseSchema(schema: string) : SwaggerObject = - let parse = - if schema.Trim().StartsWith("{") then - parseJson - else - parseYaml - - parse schema |> Parsers.parseSwaggerObject diff --git a/tests/SwaggerProvider.ProviderTests/Schemas/v2/Instagram.json b/tests/SwaggerProvider.ProviderTests/Schemas/Instagram.json similarity index 100% rename from tests/SwaggerProvider.ProviderTests/Schemas/v2/Instagram.json rename to tests/SwaggerProvider.ProviderTests/Schemas/Instagram.json diff --git a/tests/SwaggerProvider.ProviderTests/Schemas/v2/azure-arm-storage.json b/tests/SwaggerProvider.ProviderTests/Schemas/azure-arm-storage.json old mode 100755 new mode 100644 similarity index 100% rename from tests/SwaggerProvider.ProviderTests/Schemas/v2/azure-arm-storage.json rename to tests/SwaggerProvider.ProviderTests/Schemas/azure-arm-storage.json diff --git a/tests/SwaggerProvider.ProviderTests/Schemas/v2/clickmeter.com.json b/tests/SwaggerProvider.ProviderTests/Schemas/clickmeter.com.json similarity index 100% rename from tests/SwaggerProvider.ProviderTests/Schemas/v2/clickmeter.com.json rename to tests/SwaggerProvider.ProviderTests/Schemas/clickmeter.com.json diff --git a/tests/SwaggerProvider.ProviderTests/Schemas/v2/github.json b/tests/SwaggerProvider.ProviderTests/Schemas/github.json similarity index 100% rename from tests/SwaggerProvider.ProviderTests/Schemas/v2/github.json rename to tests/SwaggerProvider.ProviderTests/Schemas/github.json diff --git a/tests/SwaggerProvider.ProviderTests/Schemas/v2/i0027.json b/tests/SwaggerProvider.ProviderTests/Schemas/i0027.json similarity index 100% rename from tests/SwaggerProvider.ProviderTests/Schemas/v2/i0027.json rename to tests/SwaggerProvider.ProviderTests/Schemas/i0027.json diff --git a/tests/SwaggerProvider.ProviderTests/Schemas/v3/issue132.json b/tests/SwaggerProvider.ProviderTests/Schemas/issue132.json similarity index 100% rename from tests/SwaggerProvider.ProviderTests/Schemas/v3/issue132.json rename to tests/SwaggerProvider.ProviderTests/Schemas/issue132.json diff --git a/tests/SwaggerProvider.ProviderTests/Schemas/v3/issue173.json b/tests/SwaggerProvider.ProviderTests/Schemas/issue173.json similarity index 100% rename from tests/SwaggerProvider.ProviderTests/Schemas/v3/issue173.json rename to tests/SwaggerProvider.ProviderTests/Schemas/issue173.json diff --git a/tests/SwaggerProvider.ProviderTests/Schemas/v3/issue181.yaml b/tests/SwaggerProvider.ProviderTests/Schemas/issue181.yaml similarity index 100% rename from tests/SwaggerProvider.ProviderTests/Schemas/v3/issue181.yaml rename to tests/SwaggerProvider.ProviderTests/Schemas/issue181.yaml diff --git a/tests/SwaggerProvider.ProviderTests/Schemas/v3/issue219.yaml b/tests/SwaggerProvider.ProviderTests/Schemas/issue219.yaml similarity index 100% rename from tests/SwaggerProvider.ProviderTests/Schemas/v3/issue219.yaml rename to tests/SwaggerProvider.ProviderTests/Schemas/issue219.yaml diff --git a/tests/SwaggerProvider.ProviderTests/Schemas/v3/issue255.yaml b/tests/SwaggerProvider.ProviderTests/Schemas/issue255.yaml similarity index 100% rename from tests/SwaggerProvider.ProviderTests/Schemas/v3/issue255.yaml rename to tests/SwaggerProvider.ProviderTests/Schemas/issue255.yaml diff --git a/tests/SwaggerProvider.ProviderTests/Schemas/v3/issue279.json b/tests/SwaggerProvider.ProviderTests/Schemas/issue279.json similarity index 100% rename from tests/SwaggerProvider.ProviderTests/Schemas/v3/issue279.json rename to tests/SwaggerProvider.ProviderTests/Schemas/issue279.json diff --git a/tests/SwaggerProvider.ProviderTests/Schemas/v2/my-swashbuckle.json b/tests/SwaggerProvider.ProviderTests/Schemas/my-swashbuckle.json similarity index 100% rename from tests/SwaggerProvider.ProviderTests/Schemas/v2/my-swashbuckle.json rename to tests/SwaggerProvider.ProviderTests/Schemas/my-swashbuckle.json diff --git a/tests/SwaggerProvider.ProviderTests/Schemas/v3/nullable-date.yaml b/tests/SwaggerProvider.ProviderTests/Schemas/nullable-date.yaml similarity index 100% rename from tests/SwaggerProvider.ProviderTests/Schemas/v3/nullable-date.yaml rename to tests/SwaggerProvider.ProviderTests/Schemas/nullable-date.yaml diff --git a/tests/SwaggerProvider.ProviderTests/Schemas/v3/nullable-parameter-issue261.json b/tests/SwaggerProvider.ProviderTests/Schemas/nullable-parameter-issue261.json similarity index 100% rename from tests/SwaggerProvider.ProviderTests/Schemas/v3/nullable-parameter-issue261.json rename to tests/SwaggerProvider.ProviderTests/Schemas/nullable-parameter-issue261.json diff --git a/tests/SwaggerProvider.ProviderTests/Schemas/v2/petstore.json b/tests/SwaggerProvider.ProviderTests/Schemas/petstore-v2.json old mode 100755 new mode 100644 similarity index 100% rename from tests/SwaggerProvider.ProviderTests/Schemas/v2/petstore.json rename to tests/SwaggerProvider.ProviderTests/Schemas/petstore-v2.json diff --git a/tests/SwaggerProvider.ProviderTests/Schemas/v3/petstore.yaml b/tests/SwaggerProvider.ProviderTests/Schemas/petstore.yaml similarity index 100% rename from tests/SwaggerProvider.ProviderTests/Schemas/v3/petstore.yaml rename to tests/SwaggerProvider.ProviderTests/Schemas/petstore.yaml diff --git a/tests/SwaggerProvider.ProviderTests/Schemas/v2/slack.json b/tests/SwaggerProvider.ProviderTests/Schemas/slack.json similarity index 100% rename from tests/SwaggerProvider.ProviderTests/Schemas/v2/slack.json rename to tests/SwaggerProvider.ProviderTests/Schemas/slack.json diff --git a/tests/SwaggerProvider.ProviderTests/Schemas/v2/swashbuckle.json b/tests/SwaggerProvider.ProviderTests/Schemas/swashbuckle.json old mode 100755 new mode 100644 similarity index 100% rename from tests/SwaggerProvider.ProviderTests/Schemas/v2/swashbuckle.json rename to tests/SwaggerProvider.ProviderTests/Schemas/swashbuckle.json diff --git a/tests/SwaggerProvider.ProviderTests/Schemas/v2/gettyimages.com.json b/tests/SwaggerProvider.ProviderTests/Schemas/unsupported/gettyimages.com.json similarity index 100% rename from tests/SwaggerProvider.ProviderTests/Schemas/v2/gettyimages.com.json rename to tests/SwaggerProvider.ProviderTests/Schemas/unsupported/gettyimages.com.json diff --git a/tests/SwaggerProvider.ProviderTests/Schemas/v3/unsupported/issue0204.yaml b/tests/SwaggerProvider.ProviderTests/Schemas/unsupported/issue0204.yaml similarity index 100% rename from tests/SwaggerProvider.ProviderTests/Schemas/v3/unsupported/issue0204.yaml rename to tests/SwaggerProvider.ProviderTests/Schemas/unsupported/issue0204.yaml diff --git a/tests/SwaggerProvider.ProviderTests/v3/Swagger.I0173.Tests.fs b/tests/SwaggerProvider.ProviderTests/Swagger.I0173.Tests.fs similarity index 68% rename from tests/SwaggerProvider.ProviderTests/v3/Swagger.I0173.Tests.fs rename to tests/SwaggerProvider.ProviderTests/Swagger.I0173.Tests.fs index c1d82603..5129544e 100644 --- a/tests/SwaggerProvider.ProviderTests/v3/Swagger.I0173.Tests.fs +++ b/tests/SwaggerProvider.ProviderTests/Swagger.I0173.Tests.fs @@ -3,7 +3,7 @@ module Swagger.I0173.Tests open SwaggerProvider [] -let Schema = __SOURCE_DIRECTORY__ + "/../Schemas/v3/issue173.json" +let Schema = __SOURCE_DIRECTORY__ + "/../Schemas/issue173.json" type OdhApiTourism = OpenApiClientProvider diff --git a/tests/SwaggerProvider.ProviderTests/v3/Swagger.I0181.Tests.fs b/tests/SwaggerProvider.ProviderTests/Swagger.I0181.Tests.fs similarity index 66% rename from tests/SwaggerProvider.ProviderTests/v3/Swagger.I0181.Tests.fs rename to tests/SwaggerProvider.ProviderTests/Swagger.I0181.Tests.fs index af5614ed..e40f7de7 100644 --- a/tests/SwaggerProvider.ProviderTests/v3/Swagger.I0181.Tests.fs +++ b/tests/SwaggerProvider.ProviderTests/Swagger.I0181.Tests.fs @@ -3,7 +3,7 @@ module Swagger.I0181.Tests open SwaggerProvider [] -let Schema = __SOURCE_DIRECTORY__ + "/../Schemas/v3/issue181.yaml" +let Schema = __SOURCE_DIRECTORY__ + "/../Schemas/issue181.yaml" type MyApi = OpenApiClientProvider diff --git a/tests/SwaggerProvider.ProviderTests/v3/Swagger.I0219.Tests.fs b/tests/SwaggerProvider.ProviderTests/Swagger.I0219.Tests.fs similarity index 67% rename from tests/SwaggerProvider.ProviderTests/v3/Swagger.I0219.Tests.fs rename to tests/SwaggerProvider.ProviderTests/Swagger.I0219.Tests.fs index 5a4eeaee..c04644bf 100644 --- a/tests/SwaggerProvider.ProviderTests/v3/Swagger.I0219.Tests.fs +++ b/tests/SwaggerProvider.ProviderTests/Swagger.I0219.Tests.fs @@ -3,7 +3,7 @@ module Swagger.I0219.Tests open SwaggerProvider [] -let Schema = __SOURCE_DIRECTORY__ + "/../Schemas/v3/issue219.yaml" +let Schema = __SOURCE_DIRECTORY__ + "/../Schemas/issue219.yaml" type AcmeApi = OpenApiClientProvider diff --git a/tests/SwaggerProvider.ProviderTests/v3/Swagger.I0279.Tests.fs b/tests/SwaggerProvider.ProviderTests/Swagger.I0279.Tests.fs similarity index 66% rename from tests/SwaggerProvider.ProviderTests/v3/Swagger.I0279.Tests.fs rename to tests/SwaggerProvider.ProviderTests/Swagger.I0279.Tests.fs index 7d72226c..2dfbf18e 100644 --- a/tests/SwaggerProvider.ProviderTests/v3/Swagger.I0279.Tests.fs +++ b/tests/SwaggerProvider.ProviderTests/Swagger.I0279.Tests.fs @@ -3,7 +3,7 @@ module Swagger.I0279.Tests open SwaggerProvider [] -let Schema = __SOURCE_DIRECTORY__ + "/../Schemas/v3/issue279.json" +let Schema = __SOURCE_DIRECTORY__ + "/../Schemas/issue279.json" type Immich = OpenApiClientProvider diff --git a/tests/SwaggerProvider.ProviderTests/v3/Swagger.NullableDate.Tests.fs b/tests/SwaggerProvider.ProviderTests/Swagger.NullableDate.Tests.fs similarity index 97% rename from tests/SwaggerProvider.ProviderTests/v3/Swagger.NullableDate.Tests.fs rename to tests/SwaggerProvider.ProviderTests/Swagger.NullableDate.Tests.fs index a1b0f945..4b8ec37e 100644 --- a/tests/SwaggerProvider.ProviderTests/v3/Swagger.NullableDate.Tests.fs +++ b/tests/SwaggerProvider.ProviderTests/Swagger.NullableDate.Tests.fs @@ -7,7 +7,7 @@ open System.Text.Json open System.Text.Json.Serialization [] -let Schema = __SOURCE_DIRECTORY__ + "/../Schemas/v3/nullable-date.yaml" +let Schema = __SOURCE_DIRECTORY__ + "/../Schemas/nullable-date.yaml" type TestApi = OpenApiClientProvider diff --git a/tests/SwaggerProvider.ProviderTests/v3/Swagger.PetStore.Tests.fs b/tests/SwaggerProvider.ProviderTests/Swagger.PetStore.Tests.fs similarity index 98% rename from tests/SwaggerProvider.ProviderTests/v3/Swagger.PetStore.Tests.fs rename to tests/SwaggerProvider.ProviderTests/Swagger.PetStore.Tests.fs index fdad3284..8c2486af 100644 --- a/tests/SwaggerProvider.ProviderTests/v3/Swagger.PetStore.Tests.fs +++ b/tests/SwaggerProvider.ProviderTests/Swagger.PetStore.Tests.fs @@ -1,4 +1,4 @@ -module Swagger.v3.PetStore.Tests +module Swagger.PetStore.Tests open SwaggerProvider open Swagger diff --git a/tests/SwaggerProvider.ProviderTests/v3/Swagger.SchemaReaderErrors.Tests.fs b/tests/SwaggerProvider.ProviderTests/Swagger.SchemaReaderErrors.Tests.fs similarity index 87% rename from tests/SwaggerProvider.ProviderTests/v3/Swagger.SchemaReaderErrors.Tests.fs rename to tests/SwaggerProvider.ProviderTests/Swagger.SchemaReaderErrors.Tests.fs index f8895580..fcf0fdb5 100644 --- a/tests/SwaggerProvider.ProviderTests/v3/Swagger.SchemaReaderErrors.Tests.fs +++ b/tests/SwaggerProvider.ProviderTests/Swagger.SchemaReaderErrors.Tests.fs @@ -5,12 +5,12 @@ open Xunit open FsUnitTyped [] -let ValidSchema = __SOURCE_DIRECTORY__ + "/../Schemas/v3/petstore.yaml" +let ValidSchema = __SOURCE_DIRECTORY__ + "/../Schemas/petstore.yaml" [] let SchemaWithErrors = __SOURCE_DIRECTORY__ - + "/../Schemas/v3/nullable-parameter-issue261.json" + + "/../Schemas/nullable-parameter-issue261.json" type ValidApi = OpenApiClientProvider diff --git a/tests/SwaggerProvider.ProviderTests/SwaggerProvider.ProviderTests.fsproj b/tests/SwaggerProvider.ProviderTests/SwaggerProvider.ProviderTests.fsproj index 14c56746..e37df186 100644 --- a/tests/SwaggerProvider.ProviderTests/SwaggerProvider.ProviderTests.fsproj +++ b/tests/SwaggerProvider.ProviderTests/SwaggerProvider.ProviderTests.fsproj @@ -11,32 +11,21 @@ false - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + APIs.guru.fs diff --git a/tests/SwaggerProvider.ProviderTests/v3/Swashbuckle.CancellationToken.Tests.fs b/tests/SwaggerProvider.ProviderTests/Swashbuckle.CancellationToken.Tests.fs similarity index 98% rename from tests/SwaggerProvider.ProviderTests/v3/Swashbuckle.CancellationToken.Tests.fs rename to tests/SwaggerProvider.ProviderTests/Swashbuckle.CancellationToken.Tests.fs index 4e1d4bab..203a0f83 100644 --- a/tests/SwaggerProvider.ProviderTests/v3/Swashbuckle.CancellationToken.Tests.fs +++ b/tests/SwaggerProvider.ProviderTests/Swashbuckle.CancellationToken.Tests.fs @@ -1,4 +1,4 @@ -module Swashbuckle.v3.CancellationTokenTests +module Swashbuckle.CancellationTokenTests open Xunit open FsUnitTyped diff --git a/tests/SwaggerProvider.ProviderTests/v3/Swashbuckle.FileController.Tests.fs b/tests/SwaggerProvider.ProviderTests/Swashbuckle.FileController.Tests.fs similarity index 97% rename from tests/SwaggerProvider.ProviderTests/v3/Swashbuckle.FileController.Tests.fs rename to tests/SwaggerProvider.ProviderTests/Swashbuckle.FileController.Tests.fs index 82108ed6..e7355e16 100644 --- a/tests/SwaggerProvider.ProviderTests/v3/Swashbuckle.FileController.Tests.fs +++ b/tests/SwaggerProvider.ProviderTests/Swashbuckle.FileController.Tests.fs @@ -1,4 +1,4 @@ -module Swashbuckle.v3.FileControllersTests +module Swashbuckle.FileControllersTests open Xunit open FsUnitTyped diff --git a/tests/SwaggerProvider.ProviderTests/v3/Swashbuckle.NoContentControllers.Tests.fs b/tests/SwaggerProvider.ProviderTests/Swashbuckle.NoContentControllers.Tests.fs similarity index 93% rename from tests/SwaggerProvider.ProviderTests/v3/Swashbuckle.NoContentControllers.Tests.fs rename to tests/SwaggerProvider.ProviderTests/Swashbuckle.NoContentControllers.Tests.fs index afaa031d..47b119bf 100644 --- a/tests/SwaggerProvider.ProviderTests/v3/Swashbuckle.NoContentControllers.Tests.fs +++ b/tests/SwaggerProvider.ProviderTests/Swashbuckle.NoContentControllers.Tests.fs @@ -1,4 +1,4 @@ -module Swashbuckle.v3.NoContentControllersTests +module Swashbuckle.NoContentControllersTests open FsUnitTyped open Xunit diff --git a/tests/SwaggerProvider.ProviderTests/v3/Swashbuckle.ResourceControllers.Tests.fs b/tests/SwaggerProvider.ProviderTests/Swashbuckle.ResourceControllers.Tests.fs similarity index 100% rename from tests/SwaggerProvider.ProviderTests/v3/Swashbuckle.ResourceControllers.Tests.fs rename to tests/SwaggerProvider.ProviderTests/Swashbuckle.ResourceControllers.Tests.fs diff --git a/tests/SwaggerProvider.ProviderTests/v3/Swashbuckle.ReturnControllers.Tests.fs b/tests/SwaggerProvider.ProviderTests/Swashbuckle.ReturnControllers.Tests.fs similarity index 99% rename from tests/SwaggerProvider.ProviderTests/v3/Swashbuckle.ReturnControllers.Tests.fs rename to tests/SwaggerProvider.ProviderTests/Swashbuckle.ReturnControllers.Tests.fs index 6bb52375..4f070ab1 100644 --- a/tests/SwaggerProvider.ProviderTests/v3/Swashbuckle.ReturnControllers.Tests.fs +++ b/tests/SwaggerProvider.ProviderTests/Swashbuckle.ReturnControllers.Tests.fs @@ -1,4 +1,4 @@ -module Swashbuckle.v3.ReturnControllersTests +module Swashbuckle.ReturnControllersTests open Xunit open FsUnitTyped diff --git a/tests/SwaggerProvider.ProviderTests/v3/Swashbuckle.ReturnTextControllers.Tests.fs b/tests/SwaggerProvider.ProviderTests/Swashbuckle.ReturnTextControllers.Tests.fs similarity index 94% rename from tests/SwaggerProvider.ProviderTests/v3/Swashbuckle.ReturnTextControllers.Tests.fs rename to tests/SwaggerProvider.ProviderTests/Swashbuckle.ReturnTextControllers.Tests.fs index 1d0a06a5..7f8cc8de 100644 --- a/tests/SwaggerProvider.ProviderTests/v3/Swashbuckle.ReturnTextControllers.Tests.fs +++ b/tests/SwaggerProvider.ProviderTests/Swashbuckle.ReturnTextControllers.Tests.fs @@ -1,4 +1,4 @@ -module Swashbuckle.v3.ReturnTextControllersTests +module Swashbuckle.ReturnTextControllersTests open Xunit open FsUnitTyped diff --git a/tests/SwaggerProvider.ProviderTests/v3/Swashbuckle.SpecialCasesControllers.Tests.fs b/tests/SwaggerProvider.ProviderTests/Swashbuckle.SpecialCasesControllers.Tests.fs similarity index 100% rename from tests/SwaggerProvider.ProviderTests/v3/Swashbuckle.SpecialCasesControllers.Tests.fs rename to tests/SwaggerProvider.ProviderTests/Swashbuckle.SpecialCasesControllers.Tests.fs diff --git a/tests/SwaggerProvider.ProviderTests/v3/Swashbuckle.UpdateControllers.Tests.fs b/tests/SwaggerProvider.ProviderTests/Swashbuckle.UpdateControllers.Tests.fs similarity index 99% rename from tests/SwaggerProvider.ProviderTests/v3/Swashbuckle.UpdateControllers.Tests.fs rename to tests/SwaggerProvider.ProviderTests/Swashbuckle.UpdateControllers.Tests.fs index b9e3e311..69de20c4 100644 --- a/tests/SwaggerProvider.ProviderTests/v3/Swashbuckle.UpdateControllers.Tests.fs +++ b/tests/SwaggerProvider.ProviderTests/Swashbuckle.UpdateControllers.Tests.fs @@ -1,4 +1,4 @@ -module Swashbuckle.v3.UpdateControllersTests +module Swashbuckle.UpdateControllersTests open Xunit open FsUnitTyped diff --git a/tests/SwaggerProvider.ProviderTests/v2/Swagger.GitHub.Tests.fs b/tests/SwaggerProvider.ProviderTests/v2/Swagger.GitHub.Tests.fs deleted file mode 100644 index fd52c872..00000000 --- a/tests/SwaggerProvider.ProviderTests/v2/Swagger.GitHub.Tests.fs +++ /dev/null @@ -1,68 +0,0 @@ -module Swagger.GitHub.Tests - -open SwaggerProvider -open Xunit -open FsUnitTyped -open System -open System.Net.Http - -[] -let Schema = __SOURCE_DIRECTORY__ + "/../Schemas/v2/github.json" - -[] -let UserAgent = - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36" - - -[] -let Host = "https://api.github.com" - -type GitHub = SwaggerClientProvider - -let github() = - let client = GitHub.Client() - client.HttpClient.BaseAddress <- Uri Host - - client.HttpClient.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", UserAgent) - |> ignore - - client - - - -type TaskGitHub = SwaggerClientProvider - -let taskGitHub() = - let client = TaskGitHub.Client() - client.HttpClient.BaseAddress <- Uri Host - - client.HttpClient.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", UserAgent) - |> ignore - - client - -let isRateLimitError(ex: exn) = - ex.Message.Contains("rate limit") - || ex.Message.Contains("403 (rate limit") - -[] // Explicit -let ``Get fsprojects from GitHub``() = - task { - try - let! repos = github().OrgRepos("fsprojects") - repos.Length |> shouldBeGreaterThan 0 - with - | :? HttpRequestException as ex when isRateLimitError ex -> Assert.Skip("GitHub API rate limit exceeded - transient CI failure") - | :? AggregateException as aex when isRateLimitError aex -> Assert.Skip("GitHub API rate limit exceeded - transient CI failure") - } - -[] -let ``Get fsproject from GitHub with Task``() = - task { - try - let! repos = taskGitHub().OrgRepos("fsprojects") - repos.Length |> shouldBeGreaterThan 0 - with - | :? HttpRequestException as ex when isRateLimitError ex -> Assert.Skip("GitHub API rate limit exceeded - transient CI failure") - | :? AggregateException as aex when isRateLimitError aex -> Assert.Skip("GitHub API rate limit exceeded - transient CI failure") - } diff --git a/tests/SwaggerProvider.ProviderTests/v2/Swagger.Instagram.Tests.fs b/tests/SwaggerProvider.ProviderTests/v2/Swagger.Instagram.Tests.fs deleted file mode 100644 index 49a46ec1..00000000 --- a/tests/SwaggerProvider.ProviderTests/v2/Swagger.Instagram.Tests.fs +++ /dev/null @@ -1,10 +0,0 @@ -module Swagger.Instagram.Tests - -open SwaggerProvider - -[] -let Schema = __SOURCE_DIRECTORY__ + "/../Schemas/v2/Instagram.json" - -type Instagram = SwaggerClientProvider - -let insta = Instagram.Client() diff --git a/tests/SwaggerProvider.ProviderTests/v2/Swagger.Namespaces.Tests.fs b/tests/SwaggerProvider.ProviderTests/v2/Swagger.Namespaces.Tests.fs deleted file mode 100644 index a6a2b852..00000000 --- a/tests/SwaggerProvider.ProviderTests/v2/Swagger.Namespaces.Tests.fs +++ /dev/null @@ -1,25 +0,0 @@ -module Swagger.Namespaces.Tests - -open SwaggerProvider - -// https://github.com/Microsoft/OpenAPI.NET/issues/253 - -[] -let SchemaGI = __SOURCE_DIRECTORY__ + "/../Schemas/v2/gettyimages.com.json" - -type GI = SwaggerClientProvider - -let c1 = GI.ArtistsClient() -let c2 = GI.CustomersClient() - -let x = GI.GettyImages.Models.Customers() -let y = GI.GettyImages.Models() - -[] -let SchemaCM = __SOURCE_DIRECTORY__ + "/../Schemas/v2/clickmeter.com.json" - -type CM = SwaggerClientProvider -let cm = CM.Client() - -let a = CM.Api.Core.Dto.ClickStream() -let b = CM.ClickMeter.Infrastructure.Validation.ValidationFailure() diff --git a/tests/SwaggerProvider.ProviderTests/v2/Swagger.PetStore.Tests.fs b/tests/SwaggerProvider.ProviderTests/v2/Swagger.PetStore.Tests.fs deleted file mode 100644 index e2a6873d..00000000 --- a/tests/SwaggerProvider.ProviderTests/v2/Swagger.PetStore.Tests.fs +++ /dev/null @@ -1,105 +0,0 @@ -module Swagger.PetStore.Tests - -open SwaggerProvider -open Swagger -open Xunit -open FsUnitTyped -open System - -[] -let Schema = __SOURCE_DIRECTORY__ + "/../Schemas/v2/petstore.json" - -type PetStore = SwaggerClientProvider -type PetStoreTask = SwaggerClientProvider -type PetStoreNullable = SwaggerClientProvider - -type PetStoreOperationId = SwaggerClientProvider -type PetStoreControllerPrefix = SwaggerClientProvider - -let store = PetStore.Client() -let storeTask = PetStoreTask.Client() -let apiKey = "test-key" - -[] -let ``Test provided Host property``() = - let store = PetStore.Client() - - store.HttpClient.BaseAddress.ToString() - |> shouldEqual "https://petstore.swagger.io/" - - store.HttpClient.BaseAddress <- Uri "http://petstore.swagger.io/v3/" - - store.HttpClient.BaseAddress.ToString() - |> shouldEqual "http://petstore.swagger.io/v3/" - -[] -let ``Instantiate provided objects``() = - let pet = PetStore.Pet(Name = "foo") - pet.Name |> shouldEqual "foo" - pet.ToString() |> shouldContainText "foo" - pet.Name <- "bar" - pet.Name |> shouldEqual "bar" - pet.ToString() |> shouldContainText "bar" - -[] -let ``throw custom exceptions from async``() = - task { - try - let! _ = store.GetPetById(-253L) - failwith "Call should fail" - with :? System.AggregateException as aex -> - match aex.InnerException with - | :? System.Net.Http.HttpRequestException as ex -> ex.Message |> shouldContainText "Not Found" - | _ -> raise aex - } - -[] -let ``throw custom exceptions from task``() = - task { - try - let! _ = storeTask.GetPetById(-342L) - failwith "Call should fail" - with :? System.Net.Http.HttpRequestException as ex -> - // Accept "Not Found" (expected HTTP 404) or SSL/network errors (environmental issue) - if not(ex.Message.Contains("Not Found") || ex.Message.Contains("SSL")) then - failwith $"Unexpected error message: {ex.Message}" - } - -[] -let ``call provided methods``() = - task { - let id = 3147L - - try - do! store.DeletePet(id, apiKey) - with _ -> - () - - let tag = PetStore.Tag(None, "foobar") - tag.Name |> shouldEqual "foobar" - let pet = PetStore.Pet("foo", [||], Some id) - pet.ToString() |> shouldContainText(id.ToString()) - - try - do! store.AddPet(pet) - with exn -> - let msg = - if isNull exn.InnerException then - exn.Message - else - exn.InnerException.Message - - failwith $"Adding pet failed with message: %s{msg}" - } - -[] -let ``create types with Nullable properties``() = - let tag = PetStoreNullable.Tag(Nullable<_>(), "foobar") - tag.Name |> shouldEqual "foobar" - let tag2 = PetStoreNullable.Tag(Name = "foobar") - tag2.ToString() |> shouldContainText "foobar" - - let pet = PetStoreNullable.Pet("foo", [||], Nullable(1337L)) - pet.ToString() |> shouldContainText "1337" - let pet2 = PetStoreNullable.Pet(Name = "foo", Id = Nullable(1337L)) - pet2.ToString() |> shouldContainText "1337" diff --git a/tests/SwaggerProvider.ProviderTests/v2/Swagger.Slack.Tests.fs b/tests/SwaggerProvider.ProviderTests/v2/Swagger.Slack.Tests.fs deleted file mode 100644 index b0454239..00000000 --- a/tests/SwaggerProvider.ProviderTests/v2/Swagger.Slack.Tests.fs +++ /dev/null @@ -1,36 +0,0 @@ -module Swagger.Slack.Tests - -open SwaggerProvider -open Xunit -open System - -[] -let Schema = __SOURCE_DIRECTORY__ + "/../Schemas/v2/slack.json" - -[] -let Host = "https://slack.com" - -type Slack = SwaggerClientProvider - -[] -let ``TP Slack Tests``() = - let slack = Slack.Client() - slack.HttpClient.BaseAddress <- Uri Host - - task { - let _ = // do not await intentionally - slack.ChatPostEphemeral( - threadTs = None, - blocks = "", - attachments = "", - asUser = None, - parse = "", - token = "", - text = "Hello", - user = "UNL9PF6P6", - linkNames = None, - channel = "CPDMKJR34" - ) - - return () - } diff --git a/tests/SwaggerProvider.ProviderTests/v2/Swagger.i0027.Tests.fs b/tests/SwaggerProvider.ProviderTests/v2/Swagger.i0027.Tests.fs deleted file mode 100644 index c6d827d6..00000000 --- a/tests/SwaggerProvider.ProviderTests/v2/Swagger.i0027.Tests.fs +++ /dev/null @@ -1,10 +0,0 @@ -module Swagger.I0027.Tests - -open SwaggerProvider - -[] -let Schema = __SOURCE_DIRECTORY__ + "/../Schemas/v2/i0027.json" - -type PSwagger = SwaggerClientProvider - -let inst = PSwagger.Client() diff --git a/tests/SwaggerProvider.ProviderTests/v2/Swashbuckle.NoContentControllers.Tests.fs b/tests/SwaggerProvider.ProviderTests/v2/Swashbuckle.NoContentControllers.Tests.fs deleted file mode 100644 index 06050de3..00000000 --- a/tests/SwaggerProvider.ProviderTests/v2/Swashbuckle.NoContentControllers.Tests.fs +++ /dev/null @@ -1,35 +0,0 @@ -module Swashbuckle.v2.NoContentControllersTests - -open FsUnitTyped -open Xunit -open Swashbuckle.v2.ReturnControllersTests - -[] -let ``Test 204 with GET``() = - task { do! api.GetApiNoContent() } - -[] -let ``Test 204 with POST``() = - task { do! api.PostApiNoContent() } - -[] -let ``Test 204 with PUT``() = - task { do! api.PutApiNoContent() } - -[] -let ``Test 204 with DELETE``() = - task { do! api.DeleteApiNoContent() } - -[] -let ``Test 202 Accepted with GET returns string``() = - task { - let! result = api.GetApiAccepted() - result |> shouldEqual "accepted-value" - } - -[] -let ``Test 202 Accepted with POST returns string``() = - task { - let! result = api.PostApiAccepted() - result |> shouldEqual "accepted-value" - } diff --git a/tests/SwaggerProvider.ProviderTests/v2/Swashbuckle.ResourceControllers.Tests.fs b/tests/SwaggerProvider.ProviderTests/v2/Swashbuckle.ResourceControllers.Tests.fs deleted file mode 100644 index ea62b79c..00000000 --- a/tests/SwaggerProvider.ProviderTests/v2/Swashbuckle.ResourceControllers.Tests.fs +++ /dev/null @@ -1,31 +0,0 @@ -module Swashbuckle.v2.ResourceControllersTests - -open Xunit -open FsUnitTyped -open Swashbuckle.v2.ReturnControllersTests - -[] -let ``ResourceStringString Add and get from resource dictionary``() = - task { - do! api.PutApiResourceStringString("language", "Fsharp") - do! api.GetApiResourceStringString("language") |> asyncEqual "Fsharp" - } - -[] -let ``ResourceStringString Update value in the resource dictionary``() = - task { - do! api.PutApiResourceStringString("name2", "Sergey") - do! api.GetApiResourceStringString("name2") |> asyncEqual "Sergey" - - do! api.PostApiResourceStringString("name2", "Siarhei") - do! api.GetApiResourceStringString("name2") |> asyncEqual "Siarhei" - } - -let ``ResourceStringString Delete from the dictionary``() = - task { - let baseUrl = "http://localhost/" - do! api.PutApiResourceStringString("url", baseUrl) - let! url = api.GetApiResourceStringString("url") - shouldEqual url baseUrl - do! api.DeleteApiResourceStringString("url") - } diff --git a/tests/SwaggerProvider.ProviderTests/v2/Swashbuckle.ReturnControllers.Tests.fs b/tests/SwaggerProvider.ProviderTests/v2/Swashbuckle.ReturnControllers.Tests.fs deleted file mode 100644 index 3c098d92..00000000 --- a/tests/SwaggerProvider.ProviderTests/v2/Swashbuckle.ReturnControllers.Tests.fs +++ /dev/null @@ -1,170 +0,0 @@ -module Swashbuckle.v2.ReturnControllersTests - -open FsUnitTyped -open Xunit -open SwaggerProvider -open System -open System.Net.Http - -type WebAPI = SwaggerClientProvider<"http://localhost:5000/swagger/v1/swagger.json", IgnoreOperationId=true, SsrfProtection=false> - -let api = - let handler = new HttpClientHandler(UseCookies = false) - //handler.ServerCertificateCustomValidationCallback <- Func<_, _, _, _, _>(fun a b c d -> true) - let client = - new HttpClient(handler, true, BaseAddress = Uri("http://localhost:5000")) - - WebAPI.Client(client) - -let asyncEqual expected actualTask = - task { - let! actual = actualTask - actual |> shouldEqual expected - } - -[] -let ``Return Bool GET Test``() = - api.GetApiReturnBoolean() |> asyncEqual true - -[] -let ``Return Bool POST Test``() = - api.PostApiReturnBoolean() |> asyncEqual true - -[] -let ``Return Int32 GET Test"``() = - api.GetApiReturnInt32() |> asyncEqual 42 - -[] -let ``Return Int32 POST Test``() = - api.PostApiReturnInt32() |> asyncEqual 42 - - -[] -let ``Return Int64 GET Test``() = - api.GetApiReturnInt64() |> asyncEqual 42L - -[] -let ``Return Int64 POST Test``() = - api.PostApiReturnInt64() |> asyncEqual 42L - -[] -let ``Return Float GET Test``() = - api.GetApiReturnFloat() |> asyncEqual 42.0f - -[] -let ``Return Float POST Test``() = - api.PostApiReturnFloat() |> asyncEqual 42.0f - - -[] -let ``Return Double GET Test``() = - api.GetApiReturnDouble() |> asyncEqual 42.0 - -[] -let ``Return Double POST Test``() = - api.PostApiReturnDouble() |> asyncEqual 42.0 - - -[] -let ``Return String GET Test``() = - api.GetApiReturnString() |> asyncEqual "Hello world" - -[] -let ``Return String POST Test``() = - api.PostApiReturnString() |> asyncEqual "Hello world" - - -[] -let ``Return DateTime GET Test``() = - api.GetApiReturnDateTime() |> asyncEqual(DateTime(2015, 1, 1)) - -[] -let ``Return DateTime POST Test``() = - api.PostApiReturnDateTime() |> asyncEqual(DateTime(2015, 1, 1)) - -[] -let ``Return Guid GET Test``() = - api.GetApiReturnGuid() |> asyncEqual(Guid.Empty.ToString()) - -[] -let ``Return Guid POST Test``() = - api.PostApiReturnGuid() |> asyncEqual(Guid.Empty.ToString()) - -[] -let ``Return Enum GET Test``() = - api.GetApiReturnEnum() |> asyncEqual "Absolute" - -[] -let ``Return Enum POST Test``() = - api.PostApiReturnEnum() |> asyncEqual "Absolute" - - -[] -let ``Return Array Int GET Test``() = - api.GetApiReturnArrayInt() |> asyncEqual [| 1; 2; 3 |] - -[] -let ``Return Array Int POST Test``() = - api.PostApiReturnArrayInt() |> asyncEqual [| 1; 2; 3 |] - - -[] -let ``Return Array Enum GET Test``() = - api.GetApiReturnArrayEnum() |> asyncEqual [| "Absolute"; "Relative" |] - -[] -let ``Return Array Enum POST Test``() = - api.PostApiReturnArrayEnum() - |> asyncEqual [| "Absolute"; "Relative" |] - - -[] -let ``Return List Int GET Test``() = - api.GetApiReturnListInt() |> asyncEqual [| 1; 2; 3 |] - -[] -let ``Return List Int POST Test``() = - api.PostApiReturnListInt() |> asyncEqual [| 1; 2; 3 |] - - -[] -let ``Return Seq Int GET Test``() = - api.GetApiReturnSeqInt() |> asyncEqual [| 1; 2; 3 |] - -[] -let ``Return Seq Int POST Test``() = - api.PostApiReturnSeqInt() |> asyncEqual [| 1; 2; 3 |] - - -[] -let ``Return Object Point GET Test``() = - task { - let! point = api.GetApiReturnObjectPointClass() - point.X |> shouldEqual(Some 0) - point.Y |> shouldEqual(Some 0) - } - -[] -let ``Return Object Point POST Test``() = - task { - let! point = api.PostApiReturnObjectPointClass() - point.X |> shouldEqual(Some 0) - point.Y |> shouldEqual(Some 0) - } - - -[] -let ``Return FileDescription GET Test``() = - task { - let! file = api.GetApiReturnFileDescription() - file.Name |> shouldEqual("1.txt") - file.Bytes |> shouldEqual([| 1uy; 2uy; 3uy |]) - } - -[] -let ``Return FileDescription POST Test``() = - task { - let! file = api.PostApiReturnFileDescription() - file.Name |> shouldEqual("1.txt") - file.Bytes |> shouldEqual([| 1uy; 2uy; 3uy |]) - } diff --git a/tests/SwaggerProvider.ProviderTests/v2/Swashbuckle.SpecialCasesControllers.Tests.fs b/tests/SwaggerProvider.ProviderTests/v2/Swashbuckle.SpecialCasesControllers.Tests.fs deleted file mode 100644 index aa2276e7..00000000 --- a/tests/SwaggerProvider.ProviderTests/v2/Swashbuckle.SpecialCasesControllers.Tests.fs +++ /dev/null @@ -1,8 +0,0 @@ -module Swashbuckle.SpecialCasesControllersTests - -open Xunit -open Swashbuckle.v2.ReturnControllersTests - -[] -let ``Request response in JSON format from MultiFormatController``() = - task { do! api.GetApiMultiFormat() |> asyncEqual "0.0" } diff --git a/tests/SwaggerProvider.ProviderTests/v2/Swashbuckle.UpdateControllers.Tests.fs b/tests/SwaggerProvider.ProviderTests/v2/Swashbuckle.UpdateControllers.Tests.fs deleted file mode 100644 index a69cbdaa..00000000 --- a/tests/SwaggerProvider.ProviderTests/v2/Swashbuckle.UpdateControllers.Tests.fs +++ /dev/null @@ -1,182 +0,0 @@ -module Swashbuckle.v2.UpdateControllersTests - -open Xunit -open FsUnitTyped -open System -open Swashbuckle.v2.ReturnControllersTests - -let guid = Guid.NewGuid() -let guid2 = Guid.NewGuid() -let guid3 = Guid.NewGuid() - - -[] -let ``Update Bool GET Test``() = - api.GetApiUpdateBool(Some true) |> asyncEqual false - -[] -let ``Update Bool POST Test``() = - api.PostApiUpdateBool(Some false) |> asyncEqual true - - -[] -let ``Update Int32 GET Test``() = - api.GetApiUpdateInt32(Some 0) |> asyncEqual 1 - -[] -let ``Update Int32 POST Test``() = - api.PostApiUpdateInt32(Some 0) |> asyncEqual 1 - - -[] -let ``Update Int64 GET Test``() = - api.GetApiUpdateInt64(Some 10L) |> asyncEqual 11L - -[] -let ``Update Int64 POST Test``() = - api.PostApiUpdateInt64(Some 10L) |> asyncEqual 11L - -[] -let ``Update Float GET Test``() = - api.GetApiUpdateFloat(Some 1.0f) |> asyncEqual 2.0f - -[] -let ``Update Float POST Test``() = - api.PostApiUpdateFloat(Some 1.0f) |> asyncEqual 2.0f - - -[] -let ``Update Double GET Test``() = - api.GetApiUpdateDouble(Some 2.0) |> asyncEqual 3.0 - -[] -let ``Update Double POST Test``() = - api.PostApiUpdateDouble(Some 2.0) |> asyncEqual 3.0 - - -[] -let ``Update String GET Test``() = - api.GetApiUpdateString("Serge") |> asyncEqual "Hello, Serge" - -[] -let ``Update String POST Test``() = - api.PostApiUpdateString("Serge") |> asyncEqual "Hello, Serge" - - -[] -let ``Update DateTime GET Test``() = - api.GetApiUpdateDateTime(Some(DateTime(2015, 1, 1))) - |> asyncEqual(DateTime(2015, 1, 2)) - -[] -let ``Update DateTime POST Test``() = - api.PostApiUpdateDateTime(Some(DateTime(2015, 1, 1))) - |> asyncEqual(DateTime(2015, 1, 2)) - -[] -let ``Update Guid GET Test``() = - api.GetApiUpdateGuid(guid.ToString()) |> asyncEqual(guid.ToString()) - -[] -let ``Update Guid POST Test``() = - api.PostApiUpdateGuid(guid.ToString()) |> asyncEqual(guid.ToString()) - -[] -let ``Update Enum GET Test``() = - api.GetApiUpdateEnum("Absolute") |> asyncEqual "Absolute" - -[] -let ``Update Enum POST Test``() = - api.PostApiUpdateEnum("Absolute") |> asyncEqual "Absolute" - - -[] -let ``Update Array Int GET Test``() = - api.GetApiUpdateArrayInt([| 3; 2; 1 |]) |> asyncEqual [| 1; 2; 3 |] - -[] -let ``Update Array Int POST Test``() = - api.PostApiUpdateArrayInt([| 3; 2; 1 |]) |> asyncEqual [| 1; 2; 3 |] - - -[] -let ``Update Array Enum GET Test``() = - api.GetApiUpdateArrayEnum([| "Relative"; "Absolute" |]) - |> asyncEqual [| "Absolute"; "Relative" |] - -[] -let ``Update Array Enum POST Test``() = - api.PostApiUpdateArrayEnum([| "Relative"; "Absolute" |]) - |> asyncEqual [| "Absolute"; "Relative" |] - -[] -let ``Update Array Guid GET Test``() = - api.GetApiUpdateArrayGuid([| guid.ToString(); guid2.ToString(); guid3.ToString() |]) - |> asyncEqual [| guid3.ToString(); guid2.ToString(); guid.ToString() |] - -[] -let ``Update Array Guid POST Test``() = - api.PostApiUpdateArrayGuid([| guid.ToString(); guid2.ToString(); guid3.ToString() |]) - |> asyncEqual [| guid3.ToString(); guid2.ToString(); guid.ToString() |] - -//TODO: System.InvalidOperationException: Could not create an instance of type 'Microsoft.FSharp.Collections.FSharpList`1[[System.Int32, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]'. Model bound complex types must not be abstract or value types and must have a parameterless constructor. Alternatively, give the 'x' parameter a non-null default value. -// testCaseAsync "Update List Int GET Test" <| -// (api.GetApiUpdateListInt([|3;2;1|]) -// |> asyncEqual [|1;2;3|]) - -[] -let ``Update List Int POST Test``() = - api.PostApiUpdateListInt([| 3; 2; 1 |]) |> asyncEqual [| 1; 2; 3 |] - - -[] -let ``Update Seq Int GET Test``() = - api.GetApiUpdateSeqInt([| 3; 2; 1 |]) |> asyncEqual [| 1; 2; 3 |] - -[] -let ``Update Seq Int POST Test``() = - api.PostApiUpdateSeqInt([| 3; 2; 1 |]) |> asyncEqual [| 1; 2; 3 |] - - -// TODO: Server return point (0,0) -// testCaseAsync "Update Object Point GET Test" <| async { -// let! point = api.GetApiUpdateObjectPointClass(x = Some 1, y = Some 2) -// point.X |> shouldEqual (Some 2) -// point.Y |> shouldEqual (Some 1) -// } - -[] -let ``Update Object Point POST Test``() = - task { - let p = WebAPI.PointClass() - p.X <- Some 1 - p.Y <- Some 2 - let! point = api.PostApiUpdateObjectPointClass(p) - point.X |> shouldEqual(Some 2) - point.Y |> shouldEqual(Some 1) - } - -[] -let ``Send and Receive object with byte[]``() = - task { - let x = WebAPI.FileDescription(Name = "2.txt", Bytes = [| 42uy |]) - let! y = api.PostApiUpdateObjectFileDescriptionClass(x) - x.Name |> shouldEqual y.Name - x.Bytes |> shouldEqual y.Bytes - } - -// System.Net.Http.HttpRequestException: Response status code does not indicate success: 400 (Bad Request). -[] -let ``Send byte[] in query``() = - task { - let bytes = api.Deserialize("\"NDI0Mg==\"", typeof) :?> byte[] // base64 encoded "4242" - let! y = api.GetApiUpdateObjectFileDescriptionClass(bytes) - y.Bytes |> shouldEqual(bytes) - } - -[] -let ``Use Optional param Int``() = - task { - do! api.GetApiUpdateWithOptionalInt(Some 1) |> asyncEqual 2 - do! api.GetApiUpdateWithOptionalInt(Some 1, Some 2) |> asyncEqual 3 - } diff --git a/tests/SwaggerProvider.Tests/PathResolutionTests.fs b/tests/SwaggerProvider.Tests/PathResolutionTests.fs index 669aca1f..1625b165 100644 --- a/tests/SwaggerProvider.Tests/PathResolutionTests.fs +++ b/tests/SwaggerProvider.Tests/PathResolutionTests.fs @@ -25,16 +25,16 @@ module PathResolutionTests = let concatenated = resolutionFolder + (if isWindows then - "\\..\\Schemas\\v2\\petstore.json" + "\\..\\Schemas\\petstore-v2.json" else - "/../Schemas/v2/petstore.json") + "/../Schemas/petstore-v2.json") let result = getAbsolutePath resolutionFolder concatenated // Should keep the path as-is (it's already a full path after concatenation) // Path.GetFullPath will normalize it later Assert.Contains("Schemas", result) - Assert.Contains("petstore.json", result) + Assert.Contains("petstore-v2.json", result) [] let ``getAbsolutePath handles simple relative paths``() = @@ -45,7 +45,7 @@ module PathResolutionTests = else "/home/user/project" - let schemaPath = "../Schemas/v2/petstore.json" + let schemaPath = "../Schemas/petstore-v2.json" let result = getAbsolutePath resolutionFolder schemaPath @@ -62,7 +62,7 @@ module PathResolutionTests = else "/home/user/project" - let schemaPath = "./Schemas/v2/petstore.json" + let schemaPath = "./Schemas/petstore-v2.json" let result = getAbsolutePath resolutionFolder schemaPath @@ -115,7 +115,7 @@ module PathResolutionTests = // Test: Simulates the common pattern: __SOURCE_DIRECTORY__ + "/../Schemas/..." // This should work correctly on both Windows and Unix let sourceDir = __SOURCE_DIRECTORY__ - let relativePart = "/../Schemas/v2/petstore.json" + let relativePart = "/../Schemas/petstore-v2.json" let combined = sourceDir + relativePart // This simulates what happens in test files diff --git a/tests/SwaggerProvider.Tests/v3/Schema.ArrayAndMapTypeMappingTests.fs b/tests/SwaggerProvider.Tests/Schema.ArrayAndMapTypeMappingTests.fs similarity index 98% rename from tests/SwaggerProvider.Tests/v3/Schema.ArrayAndMapTypeMappingTests.fs rename to tests/SwaggerProvider.Tests/Schema.ArrayAndMapTypeMappingTests.fs index 0282b0b8..086c0ee4 100644 --- a/tests/SwaggerProvider.Tests/v3/Schema.ArrayAndMapTypeMappingTests.fs +++ b/tests/SwaggerProvider.Tests/Schema.ArrayAndMapTypeMappingTests.fs @@ -1,4 +1,4 @@ -module SwaggerProvider.Tests.v3_Schema_ArrayAndMapTypeMappingTests +module SwaggerProvider.Tests.Schema_ArrayAndMapTypeMappingTests open System open Xunit diff --git a/tests/SwaggerProvider.Tests/v3/Schema.DefinitionPathTests.fs b/tests/SwaggerProvider.Tests/Schema.DefinitionPathTests.fs similarity index 97% rename from tests/SwaggerProvider.Tests/v3/Schema.DefinitionPathTests.fs rename to tests/SwaggerProvider.Tests/Schema.DefinitionPathTests.fs index e2a72f14..afa9da8d 100644 --- a/tests/SwaggerProvider.Tests/v3/Schema.DefinitionPathTests.fs +++ b/tests/SwaggerProvider.Tests/Schema.DefinitionPathTests.fs @@ -1,10 +1,10 @@ -module SwaggerProvider.Tests.v3_Schema_DefinitionPathTests +module SwaggerProvider.Tests.Schema_DefinitionPathTests /// Unit tests for DefinitionPath.Parse — the function that splits a JSON Reference /// path (e.g. "#/components/schemas/My.Namespace.TypeName") into its namespace list, /// requested type name, and PascalCase candidate name. -open SwaggerProvider.Internal.v3.Compilers +open SwaggerProvider.Internal.Compilers open Xunit open FsUnitTyped diff --git a/tests/SwaggerProvider.Tests/v3/Schema.OperationCompilationTests.fs b/tests/SwaggerProvider.Tests/Schema.OperationCompilationTests.fs similarity index 99% rename from tests/SwaggerProvider.Tests/v3/Schema.OperationCompilationTests.fs rename to tests/SwaggerProvider.Tests/Schema.OperationCompilationTests.fs index 6005b296..c30dad5d 100644 --- a/tests/SwaggerProvider.Tests/v3/Schema.OperationCompilationTests.fs +++ b/tests/SwaggerProvider.Tests/Schema.OperationCompilationTests.fs @@ -1,4 +1,4 @@ -module SwaggerProvider.Tests.v3_Schema_OperationCompilationTests +module SwaggerProvider.Tests.Schema_OperationCompilationTests /// Unit tests for the v3 OperationCompiler — verifying generated method signatures, /// parameter ordering, CancellationToken injection, and return-type resolution. diff --git a/tests/SwaggerProvider.Tests/Schema.Parser.Tests.fs b/tests/SwaggerProvider.Tests/Schema.Parser.Tests.fs index 5fa92459..ceaa423d 100644 --- a/tests/SwaggerProvider.Tests/Schema.Parser.Tests.fs +++ b/tests/SwaggerProvider.Tests/Schema.Parser.Tests.fs @@ -1,4 +1,4 @@ -module SwaggerProvider.Tests.v3 +module SwaggerProvider.Tests.Schema_ParserTests open Microsoft.OpenApi.Reader open Xunit @@ -6,20 +6,8 @@ open FsUnitTyped open System open System.IO -module V2 = - open SwaggerProvider.Internal.v2.Compilers - open SwaggerProvider.Internal.v2.Parser - - let testSchema schemaStr = - let schema = SwaggerParser.parseSchema schemaStr - - let defCompiler = DefinitionCompiler(schema, false, Environment.Version.Major >= 6) - let opCompiler = OperationCompiler(schema, defCompiler, true, false, true) - opCompiler.CompileProvidedClients(defCompiler.Namespace) - ignore <| defCompiler.Namespace.GetProvidedTypes() - module V3 = - open SwaggerProvider.Internal.v3.Compilers + open SwaggerProvider.Internal.Compilers let testSchema schemaStr = let settings = OpenApiReaderSettings() @@ -29,11 +17,7 @@ module V3 = Microsoft.OpenApi.OpenApiDocument.Parse(schemaStr, settings = settings) let schema = readResult.Document - (* if diagnostic.Errors.Count > 0 then - failwithf "Schema parse errors:\n- %s" - (diagnostic.Errors - |> Seq.map (fun e -> e.Message) - |> String.concat ";\n- ")*) + try let defCompiler = DefinitionCompiler(schema, false, Environment.Version.Major >= 6) let opCompiler = OperationCompiler(schema, defCompiler, true, false, true) @@ -51,10 +35,7 @@ let parserTestBody(path: string) = | _ -> failwithf $"Cannot find schema '%s{path}'" if not <| String.IsNullOrEmpty(schemaStr) then - if path.IndexOf("v2") >= 0 then - V2.testSchema schemaStr - else - V3.testSchema schemaStr |> ignore + V3.testSchema schemaStr |> ignore } let rootFolder = @@ -91,14 +72,14 @@ let ``Fail to parse`` file = let ``Parse PetStore``() = parserTestBody( __SOURCE_DIRECTORY__ - + "/../SwaggerProvider.ProviderTests/Schemas/v2/petstore.json" + + "/../SwaggerProvider.ProviderTests/Schemas/petstore-v2.json" ) [] let ``Add definition for schema with only allOf properties``() = let definitions = __SOURCE_DIRECTORY__ - + "/../SwaggerProvider.ProviderTests/Schemas/v3/issue255.yaml" + + "/../SwaggerProvider.ProviderTests/Schemas/issue255.yaml" |> File.ReadAllText |> V3.testSchema @@ -109,7 +90,7 @@ let ``Add definition for schema with only allOf properties``() = let ``Schema with nullable parameter-level property triggers parse errors``() = let schemaPath = __SOURCE_DIRECTORY__ - + "/../SwaggerProvider.ProviderTests/Schemas/v3/nullable-parameter-issue261.json" + + "/../SwaggerProvider.ProviderTests/Schemas/nullable-parameter-issue261.json" let settings = OpenApiReaderSettings() settings.AddYamlReader() @@ -127,7 +108,7 @@ let ``Schema with nullable parameter-level property triggers parse errors``() = let ``Schema with nullable parameter is still parseable despite errors``() = let schemaPath = __SOURCE_DIRECTORY__ - + "/../SwaggerProvider.ProviderTests/Schemas/v3/nullable-parameter-issue261.json" + + "/../SwaggerProvider.ProviderTests/Schemas/nullable-parameter-issue261.json" // Even with diagnostic errors, the schema should still compile without throwing an exception File.ReadAllText schemaPath |> V3.testSchema |> ignore diff --git a/tests/SwaggerProvider.Tests/v3/Schema.TestHelpers.fs b/tests/SwaggerProvider.Tests/Schema.TestHelpers.fs similarity index 97% rename from tests/SwaggerProvider.Tests/v3/Schema.TestHelpers.fs rename to tests/SwaggerProvider.Tests/Schema.TestHelpers.fs index 0550fe28..990e0f38 100644 --- a/tests/SwaggerProvider.Tests/v3/Schema.TestHelpers.fs +++ b/tests/SwaggerProvider.Tests/Schema.TestHelpers.fs @@ -1,9 +1,9 @@ [] -module SwaggerProvider.Tests.v3_Schema_TestHelpers +module SwaggerProvider.Tests.Schema_TestHelpers open System open Microsoft.OpenApi.Reader -open SwaggerProvider.Internal.v3.Compilers +open SwaggerProvider.Internal.Compilers /// Core: parse, validate, and compile an OpenAPI v3 schema string. /// `provideNullable` controls whether optional value-type properties use Nullable. diff --git a/tests/SwaggerProvider.Tests/v3/Schema.TypeMappingTests.fs b/tests/SwaggerProvider.Tests/Schema.TypeMappingTests.fs similarity index 99% rename from tests/SwaggerProvider.Tests/v3/Schema.TypeMappingTests.fs rename to tests/SwaggerProvider.Tests/Schema.TypeMappingTests.fs index b6d41e59..845bdb26 100644 --- a/tests/SwaggerProvider.Tests/v3/Schema.TypeMappingTests.fs +++ b/tests/SwaggerProvider.Tests/Schema.TypeMappingTests.fs @@ -1,4 +1,4 @@ -module SwaggerProvider.Tests.v3_Schema_TypeMappingTests +module SwaggerProvider.Tests.Schema_TypeMappingTests open System open Xunit diff --git a/tests/SwaggerProvider.Tests/v3/Schema.V2SchemaCompilationTests.fs b/tests/SwaggerProvider.Tests/Schema.V2SchemaCompilationTests.fs similarity index 98% rename from tests/SwaggerProvider.Tests/v3/Schema.V2SchemaCompilationTests.fs rename to tests/SwaggerProvider.Tests/Schema.V2SchemaCompilationTests.fs index 490659f6..1b34d532 100644 --- a/tests/SwaggerProvider.Tests/v3/Schema.V2SchemaCompilationTests.fs +++ b/tests/SwaggerProvider.Tests/Schema.V2SchemaCompilationTests.fs @@ -1,4 +1,4 @@ -module SwaggerProvider.Tests.v3_Schema_V2SchemaCompilationTests +module SwaggerProvider.Tests.Schema_V2SchemaCompilationTests /// Tests that verify Swagger 2.0 schemas can be parsed and compiled by the /// v3 DefinitionCompiler and OperationCompiler pipeline via Microsoft.OpenApi. @@ -11,7 +11,7 @@ open System open System.Reflection open Microsoft.FSharp.Quotations open Microsoft.OpenApi.Reader -open SwaggerProvider.Internal.v3.Compilers +open SwaggerProvider.Internal.Compilers open Xunit open FsUnitTyped diff --git a/tests/SwaggerProvider.Tests/v3/Schema.XmlDocTests.fs b/tests/SwaggerProvider.Tests/Schema.XmlDocTests.fs similarity index 97% rename from tests/SwaggerProvider.Tests/v3/Schema.XmlDocTests.fs rename to tests/SwaggerProvider.Tests/Schema.XmlDocTests.fs index b1fe4c7d..13d71e98 100644 --- a/tests/SwaggerProvider.Tests/v3/Schema.XmlDocTests.fs +++ b/tests/SwaggerProvider.Tests/Schema.XmlDocTests.fs @@ -1,8 +1,8 @@ -module SwaggerProvider.Tests.v3_Schema_XmlDocTests +module SwaggerProvider.Tests.Schema_XmlDocTests open System open Microsoft.OpenApi.Reader -open SwaggerProvider.Internal.v3.Compilers +open SwaggerProvider.Internal.Compilers open Xunit open FsUnitTyped diff --git a/tests/SwaggerProvider.Tests/SsrfSecurityTests.fs b/tests/SwaggerProvider.Tests/SsrfSecurityTests.fs index 34be244e..33f5da99 100644 --- a/tests/SwaggerProvider.Tests/SsrfSecurityTests.fs +++ b/tests/SwaggerProvider.Tests/SsrfSecurityTests.fs @@ -270,9 +270,9 @@ module RelativeFilePathTests = task { // Test: Relative file paths using __SOURCE_DIRECTORY__ should work correctly // This ensures that development-time file references like: - // let Schema = __SOURCE_DIRECTORY__ + "/../Schemas/v2/petstore.json" + // let Schema = __SOURCE_DIRECTORY__ + "/../Schemas/petstore-v2.json" // are properly handled (not rejected by SSRF validation) - let schemaPath = __SOURCE_DIRECTORY__ + "/../Schemas/v2/petstore.json" + let schemaPath = __SOURCE_DIRECTORY__ + "/../Schemas/petstore-v2.json" try let! _ = readSchemaPath false "" "" schemaPath diff --git a/tests/SwaggerProvider.Tests/SwaggerProvider.Tests.fsproj b/tests/SwaggerProvider.Tests/SwaggerProvider.Tests.fsproj index f1e24e3d..40e96abd 100644 --- a/tests/SwaggerProvider.Tests/SwaggerProvider.Tests.fsproj +++ b/tests/SwaggerProvider.Tests/SwaggerProvider.Tests.fsproj @@ -10,19 +10,15 @@ false - - - - - - - - - - - + + + + + + + diff --git a/tests/SwaggerProvider.Tests/v2/Schema.DefinitionsTests.fs b/tests/SwaggerProvider.Tests/v2/Schema.DefinitionsTests.fs deleted file mode 100644 index d474aff8..00000000 --- a/tests/SwaggerProvider.Tests/v2/Schema.DefinitionsTests.fs +++ /dev/null @@ -1,134 +0,0 @@ -module SwaggerProvider.Tests.v2.Schema_DefinitionsTests - -open SwaggerProvider.Internal.v2.Parser.Schema -open SwaggerProvider.Internal.v2.Parser -open FsUnitTyped -open Xunit - -let shouldBeEqual (expected: SchemaObject) content = - content - |> SwaggerParser.parseJson - |> Parsers.parseSchemaObject Parsers.emptyDict - |> shouldEqual expected - -[] -let ``parse boolean``() = - """{ - "type" : "boolean" - }""" - |> shouldBeEqual Boolean - -[] -let ``parse int32``() = - """{ - "type" : "integer", - "format" : "int32", - "description" : "User Status" - }""" - |> shouldBeEqual Int32 - -[] -let ``parse int64``() = - """{ - "type" : "integer", - "format" : "int64" - }""" - |> shouldBeEqual Int64 - -[] -let ``parse float``() = - """{ - "type" : "number", - "format" : "float" - }""" - |> shouldBeEqual Float - -[] -let ``parse double``() = - """{ - "type" : "number", - "format" : "double" - }""" - |> shouldBeEqual Double - -[] -let ``parse string``() = - """{"type" : "string"}""" |> shouldBeEqual String - -[] -let ``parse date-time``() = - """{ - "type" : "string", - "format" : "date-time" - }""" - |> shouldBeEqual DateTime - -[] -let ``parse date``() = - """{ - "type" : "string", - "format" : "date" - }""" - |> shouldBeEqual Date - -[] -let ``parse enum``() = - """{ - "type" : "string", - "description" : "pet status in the store", - "enum" : ["available", "pending", "sold"] - }""" - |> shouldBeEqual(Enum([| "available"; "pending"; "sold" |], "string")) - -[] -let ``parse definition reference``() = - """{"$ref" : "#/definitions/Tag"}""" - |> shouldBeEqual(Reference "#/definitions/Tag") - -[] -let ``parse array of definitions``() = - """{ - "type" : "array", - "xml" : { - "name" : "tag", - "wrapped" : true - }, - "items" : { - "$ref" : "#/definitions/Tag" - } - }""" - |> shouldBeEqual(Array(Reference "#/definitions/Tag")) - -[] -let ``parse array of string``() = - """{ - "type" : "array", - "xml" : { - "name" : "photoUrl", - "wrapped" : true - }, - "items" : { - "type" : "string" - } - }""" - |> shouldBeEqual(Array String) - -[] -let ``parse map of definitions``() = - """{ - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/Tag" - } - }""" - |> shouldBeEqual(Dictionary(Reference "#/definitions/Tag")) - -[] -let ``parse map of string``() = - """{ - "type": "object", - "additionalProperties": { - "type": "string" - } - }""" - |> shouldBeEqual(Dictionary String) diff --git a/tests/SwaggerProvider.Tests/v2/Schema.PathsTests.fs b/tests/SwaggerProvider.Tests/v2/Schema.PathsTests.fs deleted file mode 100644 index 472ee2d8..00000000 --- a/tests/SwaggerProvider.Tests/v2/Schema.PathsTests.fs +++ /dev/null @@ -1,45 +0,0 @@ -module SwaggerProvider.Tests.v2.Schema_PathsTests - -open SwaggerProvider.Internal.v2.Parser.Schema -open SwaggerProvider.Internal.v2.Parser -open FsUnitTyped -open Xunit - -let shouldBeEqualToTag (expected: TagObject) content = - content - |> SwaggerParser.parseJson - |> Parsers.parseTagObject - |> shouldEqual expected - -[] -let ``parse simple tag``() = - """{ - "name" : "store", - "description" : "Operations about user" - }""" - |> shouldBeEqualToTag - { Name = "store" - Description = "Operations about user" } - -[] -let ``parse partial tag``() = - """{ - "name" : "store" - }""" - |> shouldBeEqualToTag - { Name = "store" - Description = System.String.Empty } - -[] -let ``parse complex tag``() = - """{ - "name" : "user", - "description" : "Access to Petstore orders", - "externalDocs" : { - "description" : "Find out more about our store", - "url" : "http://swagger.io" - } - }""" - |> shouldBeEqualToTag - { Name = "user" - Description = "Access to Petstore orders" } diff --git a/tests/SwaggerProvider.Tests/v2/Schema.Spec.Json.Tests.fs b/tests/SwaggerProvider.Tests/v2/Schema.Spec.Json.Tests.fs deleted file mode 100644 index 508c5a06..00000000 --- a/tests/SwaggerProvider.Tests/v2/Schema.Spec.Json.Tests.fs +++ /dev/null @@ -1,866 +0,0 @@ -module SwaggerProvider.Tests.v2.Schema_Spec_Json_Tests - -open SwaggerProvider.Internal.v2.Parser.Schema -open SwaggerProvider.Internal.v2.Parser -open FsUnitTyped -open Xunit - -[] -let ``Info Object Example``() = - """{ - "title": "Swagger Sample App", - "description": "This is a sample server Petstore server.", - "termsOfService": "http://swagger.io/terms/", - "contact": { - "name": "API Support", - "url": "http://www.swagger.io/support", - "email": "support@swagger.io" - }, - "license": { - "name": "Apache 2.0", - "url": "http://www.apache.org/licenses/LICENSE-2.0.html" - }, - "version": "1.0.1" - }""" - |> SwaggerParser.parseJson - |> Parsers.parseInfoObject - |> shouldEqual - { Title = "Swagger Sample App" - Description = "This is a sample server Petstore server." - Version = "1.0.1" } - -[] -let ``Paths Object Example``() = - """{ - "/pets": { - "get": { - "description": "Returns all pets from the system that the user has access to", - "produces": [ - "application/json" - ], - "responses": { - "200": { - "description": "A list of pets.", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/pet" - } - } - } - } - } - } - }""" - |> SwaggerParser.parseJson - |> Parsers.parsePathsObject Parsers.ParserContext.Empty - |> shouldEqual - [| { Path = "/pets" - Type = Get - Tags = [||] - Summary = "" - Description = "Returns all pets from the system that the user has access to" - OperationId = "" - Consumes = [||] - Produces = [| "application/json" |] - Responses = - [| Some(200), - { Description = "A list of pets." - Schema = Some <| Array(Reference "#/definitions/pet") } |] - Parameters = [||] - Deprecated = false } |] - -[] -let ``Path Item Object Example``() = - """{"/pets":{ - "get": { - "description": "Returns pets based on ID", - "summary": "Find pets by ID", - "operationId": "getPetsById", - "produces": [ - "application/json", - "text/html" - ], - "responses": { - "200": { - "description": "pet response", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/Pet" - } - } - }, - "default": { - "description": "error payload", - "schema": { - "$ref": "#/definitions/ErrorModel" - } - } - } - }, - "parameters": [ - { - "name": "id", - "in": "path", - "description": "ID of pet to use", - "required": true, - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "csv" - } - ] - }}""" - |> SwaggerParser.parseJson - |> Parsers.parsePathsObject Parsers.ParserContext.Empty - |> shouldEqual - [| { Path = "/pets" - Type = Get - Tags = [||] - Summary = "Find pets by ID" - Description = "Returns pets based on ID" - OperationId = "getPetsById" - Consumes = [||] - Produces = [| "application/json"; "text/html" |] - Responses = - [| Some(200), - { Description = "pet response" - Schema = Some <| Array(Reference "#/definitions/Pet") } - None, - { Description = "error payload" - Schema = Some <| Reference "#/definitions/ErrorModel" } |] - Parameters = - [| { Name = "id" - In = Path - Description = "ID of pet to use" - Required = true - Type = Array String - CollectionFormat = Csv } |] - Deprecated = false } |] - -[] -let ``Operation Object Example``() = - """{ - "tags": [ - "pet" - ], - "summary": "Updates a pet in the store with form data", - "description": "", - "operationId": "updatePetWithForm", - "consumes": [ - "application/x-www-form-urlencoded" - ], - "produces": [ - "application/json", - "application/xml" - ], - "parameters": [ - { - "name": "petId", - "in": "path", - "description": "ID of pet that needs to be updated", - "required": true, - "type": "string" - }, - { - "name": "name", - "in": "formData", - "description": "Updated name of the pet", - "required": false, - "type": "string" - }, - { - "name": "status", - "in": "formData", - "description": "Updated status of the pet", - "required": false, - "type": "string" - } - ], - "responses": { - "200": { - "description": "Pet updated." - }, - "405": { - "description": "Invalid input" - } - }, - "security": [ - { - "petstore_auth": [ - "write:pets", - "read:pets" - ] - } - ] - }""" - |> SwaggerParser.parseJson - |> Parsers.parseOperationObject Parsers.ParserContext.Empty "/" Get - |> shouldEqual - { Path = "/" - Type = Get - Tags = [| "pet" |] - Summary = "Updates a pet in the store with form data" - Description = "" - OperationId = "updatePetWithForm" - Consumes = [| "application/x-www-form-urlencoded" |] - Produces = [| "application/json"; "application/xml" |] - Responses = - [| Some(200), - { Description = "Pet updated." - Schema = None } - Some(405), - { Description = "Invalid input" - Schema = None } |] - Parameters = - [| { Name = "petId" - In = Path - Description = "ID of pet that needs to be updated" - Required = true - Type = String - CollectionFormat = Csv } - { Name = "name" - In = FormData - Description = "Updated name of the pet" - Required = false - Type = String - CollectionFormat = Csv } - { Name = "status" - In = FormData - Description = "Updated status of the pet" - Required = false - Type = String - CollectionFormat = Csv } |] - Deprecated = false } - -[] -let ``Parameter Object Examples: Body Parameters``() = - """{ - "name": "user", - "in": "body", - "description": "user to add to the system", - "required": true, - "schema": { - "$ref": "#/definitions/User" - } - }""" - |> SwaggerParser.parseJson - |> Parsers.parseParameterObject Parsers.emptyDict - |> shouldEqual - { Name = "user" - In = Body - Description = "user to add to the system" - Required = true - Type = Reference "#/definitions/User" - CollectionFormat = Csv } - -[] -let ``Parameter Object Examples: Body Parameters Array``() = - """{ - "name": "user", - "in": "body", - "description": "user to add to the system", - "required": true, - "schema": { - "type": "array", - "items": { - "type": "string" - } - } - }""" - |> SwaggerParser.parseJson - |> Parsers.parseParameterObject Parsers.emptyDict - |> shouldEqual - { Name = "user" - In = Body - Description = "user to add to the system" - Required = true - Type = Array String - CollectionFormat = Csv } - -[] -let ``Parameter Object Examples: Other Parameters``() = - """{ - "name": "token", - "in": "header", - "description": "token to be passed as a header", - "required": true, - "type": "array", - "items": { - "type": "integer", - "format": "int64" - }, - "collectionFormat": "csv" - }""" - |> SwaggerParser.parseJson - |> Parsers.parseParameterObject Parsers.emptyDict - |> shouldEqual - { Name = "token" - In = Header - Description = "token to be passed as a header" - Required = true - Type = Array Int64 - CollectionFormat = Csv } - -[] -let ``Parameter Object Examples: Other Parameters - Path String``() = - """{ - "name": "username", - "in": "path", - "description": "username to fetch", - "required": true, - "type": "string" - }""" - |> SwaggerParser.parseJson - |> Parsers.parseParameterObject Parsers.emptyDict - |> shouldEqual - { Name = "username" - In = Path - Description = "username to fetch" - Required = true - Type = String - CollectionFormat = Csv } - -[] -let ``Parameter Object Examples: Other Parameters - Array String Multi``() = - """{ - "name": "id", - "in": "query", - "description": "ID of the object to fetch", - "required": false, - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "multi" - }""" - |> SwaggerParser.parseJson - |> Parsers.parseParameterObject Parsers.emptyDict - |> shouldEqual - { Name = "id" - In = Query - Description = "ID of the object to fetch" - Required = false - Type = Array String - CollectionFormat = Multi } - -[] -let ``Parameter Object Examples: Other Parameters - File``() = - """{ - "name": "avatar", - "in": "formData", - "description": "The avatar of the user", - "required": true, - "type": "file" - }""" - |> SwaggerParser.parseJson - |> Parsers.parseParameterObject Parsers.emptyDict - |> shouldEqual - { Name = "avatar" - In = FormData - Description = "The avatar of the user" - Required = true - Type = File - CollectionFormat = Csv } - -[] -let ``Response Object Examples: Response of an array of a complex type``() = - """{ - "description": "A complex object array response", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/VeryComplexType" - } - } - }""" - |> SwaggerParser.parseJson - |> Parsers.parseResponseObject(Parsers.ParserContext.Empty) - |> shouldEqual - { Description = "A complex object array response" - Schema = Some <| Array(Reference "#/definitions/VeryComplexType") } - -[] -let ``Response Object Examples: Response with a string type``() = - """{ - "description": "A simple string response", - "schema": { - "type": "string" - } - }""" - |> SwaggerParser.parseJson - |> Parsers.parseResponseObject(Parsers.ParserContext.Empty) - |> shouldEqual - { Description = "A simple string response" - Schema = Some String } - -[] -let ``Response Object Examples: Response with headers``() = - """{ - "description": "A simple string response", - "schema": { - "type": "string" - }, - "headers": { - "X-Rate-Limit-Limit": { - "description": "The number of allowed requests in the current period", - "type": "integer" - }, - "X-Rate-Limit-Remaining": { - "description": "The number of remaining requests in the current period", - "type": "integer" - }, - "X-Rate-Limit-Reset": { - "description": "The number of seconds left in the current period", - "type": "integer" - } - } - }""" - |> SwaggerParser.parseJson - |> Parsers.parseResponseObject(Parsers.ParserContext.Empty) - |> shouldEqual - { Description = "A simple string response" - Schema = Some String } - -[] -let ``Response Object Examples: Response with no return value``() = - """{ - "description": "object created" - }""" - |> SwaggerParser.parseJson - |> Parsers.parseResponseObject(Parsers.ParserContext.Empty) - |> shouldEqual - { Description = "object created" - Schema = None } - -[] -let ``Tag Object Example``() = - """{ - "name": "pet", - "description": "Pets operations" - }""" - |> SwaggerParser.parseJson - |> Parsers.parseTagObject - |> shouldEqual( - { Name = "pet" - Description = "Pets operations" } - : TagObject - ) - - -[] -let ``Tag Object Example Ref``() = - """{ - "$ref": "#/definitions/Pet" - }""" - |> SwaggerParser.parseJson - |> Parsers.parseSchemaObject Parsers.emptyDict - |> shouldEqual(Reference "#/definitions/Pet") - -[] -let ``Schema Object Examples: Primitive Sample``() = - """{ - "type": "string", - "format": "email" - }""" - |> SwaggerParser.parseJson - |> Parsers.parseSchemaObject Parsers.emptyDict - |> shouldEqual String - -[] -let ``Schema Object Examples: Simple Model``() = - """{ - "type": "object", - "required": [ - "name" - ], - "properties": { - "name": { - "type": "string" - }, - "address": { - "$ref": "#/definitions/Address" - }, - "age": { - "type": "integer", - "format": "int32", - "minimum": 0 - } - } - }""" - |> SwaggerParser.parseJson - |> Parsers.parseSchemaObject Parsers.emptyDict - |> shouldEqual( - Object - [| { Name = "name" - Type = String - IsRequired = true - Description = "" } - { Name = "address" - Type = Reference "#/definitions/Address" - IsRequired = false - Description = "" } - { Name = "age" - Type = Int32 - IsRequired = false - Description = "" } |] - ) - -[] -let ``Schema Object Examples: Model with Map/Dictionary Properties: For a simple string to string mapping``() = - """{ - "type": "object", - "additionalProperties": { - "type": "string" - } - }""" - |> SwaggerParser.parseJson - |> Parsers.parseSchemaObject Parsers.emptyDict - |> shouldEqual(Dictionary String) - -[] -let ``Schema Object Examples: Model with Map/Dictionary Properties: For a string to model mapping``() = - """{ - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/ComplexModel" - } - }""" - |> SwaggerParser.parseJson - |> Parsers.parseSchemaObject Parsers.emptyDict - |> shouldEqual(Dictionary(Reference "#/definitions/ComplexModel")) - -[] -let ``Schema Object Examples: Model with Example``() = - """{ - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "name": { - "type": "string" - } - }, - "required": [ - "name" - ], - "example": { - "name": "Puma", - "id": 1 - } - }""" - |> SwaggerParser.parseJson - |> Parsers.parseSchemaObject Parsers.emptyDict - |> shouldEqual( - [| { Name = "id" - Type = Int64 - IsRequired = false - Description = "" } - { Name = "name" - Type = String - IsRequired = true - Description = "" } |] - |> Object - ) - -[] -let ``Schema Object Examples: Models with Composition``() = - """{ - "ErrorModel": { - "type": "object", - "required": [ - "message", - "code" - ], - "properties": { - "message": { - "type": "string" - }, - "code": { - "type": "integer", - "minimum": 100, - "maximum": 600 - } - } - }, - "ExtendedErrorModel": { - "allOf": [ - { - "$ref": "#/definitions/ErrorModel" - }, - { - "type": "object", - "required": [ - "rootCause" - ], - "properties": { - "rootCause": { - "type": "string" - } - } - } - ] - } - }""" - |> SwaggerParser.parseJson - |> Parsers.parseDefinitionsObject - |> Seq.map(fun x -> x.Key, x.Value.Value) - |> Map.ofSeq - |> shouldEqual( - [| "#/definitions/ErrorModel", - (Object - [| { Name = "message" - Type = String - IsRequired = true - Description = "" } - { Name = "code" - Type = Int64 - IsRequired = true - Description = "" } |]) - "#/definitions/ExtendedErrorModel", - (Object - [| { Name = "message" - Type = String - IsRequired = true - Description = "" } - { Name = "code" - Type = Int64 - IsRequired = true - Description = "" } - { Name = "rootCause" - Type = String - IsRequired = true - Description = "" } |]) |] - |> Map.ofArray - ) - -[] -let ``Schema Object Examples: Models with Polymorphism Support``() = - """{ - "definitions": { - "Pet": { - "type": "object", - "discriminator": "petType", - "properties": { - "name": { - "type": "string" - }, - "petType": { - "type": "string" - } - }, - "required": [ - "name", - "petType" - ] - }, - "Cat": { - "description": "A representation of a cat", - "allOf": [ - { - "$ref": "#/definitions/Pet" - }, - { - "type": "object", - "properties": { - "huntingSkill": { - "type": "string", - "description": "The measured skill for hunting", - "default": "lazy", - "enum": [ - "clueless", - "lazy", - "adventurous", - "aggressive" - ] - } - }, - "required": [ - "huntingSkill" - ] - } - ] - }, - "Dog": { - "description": "A representation of a dog", - "allOf": [ - { - "$ref": "#/definitions/Pet" - }, - { - "type": "object", - "properties": { - "packSize": { - "type": "integer", - "format": "int32", - "description": "the size of the pack the dog is from", - "default": 0, - "minimum": 0 - } - }, - "required": [ - "packSize" - ] - } - ] - } - } - }""" - |> SwaggerParser.parseJson - |> Parsers.parseSchemaObject Parsers.emptyDict - |> shouldEqual(Object [||]) - -[] -let ``Definitions Object Example``() = - """{ - "Category": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "name": { - "type": "string" - } - } - }, - "Tag": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "name": { - "type": "string" - } - } - } - }""" - |> SwaggerParser.parseJson - |> Parsers.parseDefinitionsObject - |> Seq.map(fun x -> x.Key, x.Value.Value) - |> Map.ofSeq - |> shouldEqual( - [| "#/definitions/Category", - (Object - [| { Name = "id" - Type = Int64 - IsRequired = false - Description = "" } - { Name = "name" - Type = String - IsRequired = false - Description = "" } |]) - "#/definitions/Tag", - (Object - [| { Name = "id" - Type = Int64 - IsRequired = false - Description = "" } - { Name = "name" - Type = String - IsRequired = false - Description = "" } |]) |] - |> Map.ofArray - ) - -[] -let ``Parameters Definition Object Example``() = - """{ - "skipParam": { - "name": "skip", - "in": "query", - "description": "number of items to skip", - "required": true, - "type": "integer", - "format": "int32" - }, - "limitParam": { - "name": "limit", - "in": "query", - "description": "max records to return", - "required": true, - "type": "integer", - "format": "int32" - } - }""" - |> SwaggerParser.parseJson - |> Parsers.parseParametersDefinition Parsers.emptyDict - |> shouldEqual( - [| "#/parameters/skipParam", - { Name = "skip" - In = Query - Description = "number of items to skip" - Required = true - Type = Int32 - CollectionFormat = Csv } - "#/parameters/limitParam", - { Name = "limit" - In = Query - Description = "max records to return" - Required = true - Type = Int32 - CollectionFormat = Csv } |] - |> Map.ofArray - ) - -[] -let ``Responses Definitions Object Example``() = - """{ - "NotFound": { - "description": "Entity not found." - }, - "IllegalInput": { - "description": "Illegal input for operation." - }, - "GeneralError": { - "description": "General Error", - "schema": { - "$ref": "#/definitions/GeneralError" - } - } - }""" - |> SwaggerParser.parseJson - |> Parsers.parseResponsesDefinition - |> shouldEqual( - [| "#/responses/NotFound", - { Description = "Entity not found." - Schema = None } - "#/responses/IllegalInput", - { Description = "Illegal input for operation." - Schema = None } - "#/responses/GeneralError", - { Description = "General Error" - Schema = Some(Reference "#/definitions/GeneralError") } |] - |> Map.ofArray - ) - -[] -let ``Parameter Map Examples: Body Parameters Map``() = - """{ - "name": "user", - "in": "body", - "description": "user to add to the system", - "required": true, - "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } - } - }""" - |> SwaggerParser.parseJson - |> Parsers.parseParameterObject Parsers.emptyDict - |> shouldEqual - { Name = "user" - In = Body - Description = "user to add to the system" - Required = true - Type = Dictionary String - CollectionFormat = Csv } diff --git a/tests/SwaggerProvider.Tests/v2/Schema.Spec.Yaml.Tests.fs b/tests/SwaggerProvider.Tests/v2/Schema.Spec.Yaml.Tests.fs deleted file mode 100644 index 5986d141..00000000 --- a/tests/SwaggerProvider.Tests/v2/Schema.Spec.Yaml.Tests.fs +++ /dev/null @@ -1,728 +0,0 @@ -module SwaggerProvider.Tests.v2.Schema_Spec_Yaml_Tests - -open SwaggerProvider.Internal.v2.Parser.Schema -open SwaggerProvider.Internal.v2.Parser -open Xunit -open FsUnitTyped - -[] -let ``Info Object Example``() = - """ -title: Swagger Sample App -description: This is a sample server Petstore server. -termsOfService: http://swagger.io/terms/ -contact: - name: API Support - url: http://www.swagger.io/support - email: support@swagger.io -license: - name: Apache 2.0 - url: http://www.apache.org/licenses/LICENSE-2.0.html -version: 1.0.1 - """ - |> SwaggerParser.parseYaml - |> Parsers.parseInfoObject - |> shouldEqual - { Title = "Swagger Sample App" - Description = "This is a sample server Petstore server." - Version = "1.0.1" } - -[] -let ``Paths Object Example``() = - """ -/pets: - get: - description: Returns all pets from the system that the user has access to - produces: - - application/json - responses: - '200': - description: A list of pets. - schema: - type: array - items: - $ref: '#/definitions/pet' - """ - |> SwaggerParser.parseYaml - |> Parsers.parsePathsObject Parsers.ParserContext.Empty - |> shouldEqual - [| { Path = "/pets" - Type = Get - Tags = [||] - Summary = "" - Description = "Returns all pets from the system that the user has access to" - OperationId = "" - Consumes = [||] - Produces = [| "application/json" |] - Responses = - [| Some(200), - { Description = "A list of pets." - Schema = Some <| Array(Reference "#/definitions/pet") } |] - Parameters = [||] - Deprecated = false } |] - -[] -let ``Path Item Object Example``() = - """ -"/pets": - get: - description: Returns pets based on ID - summary: Find pets by ID - operationId: getPetsById - produces: - - application/json - - text/html - responses: - '200': - description: pet response - schema: - type: array - items: - $ref: '#/definitions/Pet' - default: - description: error payload - schema: - $ref: '#/definitions/ErrorModel' - parameters: - - name: id - in: path - description: ID of pet to use - required: true - type: array - items: - type: string - collectionFormat: csv - """ - |> SwaggerParser.parseYaml - |> Parsers.parsePathsObject Parsers.ParserContext.Empty - |> shouldEqual - [| { Path = "/pets" - Type = Get - Tags = [||] - Summary = "Find pets by ID" - Description = "Returns pets based on ID" - OperationId = "getPetsById" - Consumes = [||] - Produces = [| "application/json"; "text/html" |] - Responses = - [| Some(200), - { Description = "pet response" - Schema = Some <| Array(Reference "#/definitions/Pet") } - None, - { Description = "error payload" - Schema = Some <| Reference "#/definitions/ErrorModel" } |] - Parameters = - [| { Name = "id" - In = Path - Description = "ID of pet to use" - Required = true - Type = Array String - CollectionFormat = Csv } |] - Deprecated = false } |] - -[] -let ``Operation Object Example``() = - """ -tags: -- pet -summary: Updates a pet in the store with form data -description: "" -operationId: updatePetWithForm -consumes: -- application/x-www-form-urlencoded -produces: -- application/json -- application/xml -parameters: -- name: petId - in: path - description: ID of pet that needs to be updated - required: true - type: string -- name: name - in: formData - description: Updated name of the pet - required: false - type: string -- name: status - in: formData - description: Updated status of the pet - required: false - type: string -responses: - '200': - description: Pet updated. - '405': - description: Invalid input -security: -- petstore_auth: - - write:pets - - read:pets""" - |> SwaggerParser.parseYaml - |> Parsers.parseOperationObject Parsers.ParserContext.Empty "/" Get - |> shouldEqual - { Path = "/" - Type = Get - Tags = [| "pet" |] - Summary = "Updates a pet in the store with form data" - Description = "" - OperationId = "updatePetWithForm" - Consumes = [| "application/x-www-form-urlencoded" |] - Produces = [| "application/json"; "application/xml" |] - Responses = - [| Some(200), - { Description = "Pet updated." - Schema = None } - Some(405), - { Description = "Invalid input" - Schema = None } |] - Parameters = - [| { Name = "petId" - In = Path - Description = "ID of pet that needs to be updated" - Required = true - Type = String - CollectionFormat = Csv } - { Name = "name" - In = FormData - Description = "Updated name of the pet" - Required = false - Type = String - CollectionFormat = Csv } - { Name = "status" - In = FormData - Description = "Updated status of the pet" - Required = false - Type = String - CollectionFormat = Csv } |] - Deprecated = false } - -[] -let ``Parameter Object Examples: Body Parameters``() = - """ -name: user -in: body -description: user to add to the system -required: true -schema: - $ref: '#/definitions/User' - """ - |> SwaggerParser.parseYaml - |> Parsers.parseParameterObject Parsers.emptyDict - |> shouldEqual - { Name = "user" - In = Body - Description = "user to add to the system" - Required = true - Type = Reference "#/definitions/User" - CollectionFormat = Csv } - -[] -let ``Parameter Object Examples: Body Parameters Array``() = - """ -name: user -in: body -description: user to add to the system -required: true -schema: - type: array - items: - type: string - """ - |> SwaggerParser.parseYaml - |> Parsers.parseParameterObject Parsers.emptyDict - |> shouldEqual - { Name = "user" - In = Body - Description = "user to add to the system" - Required = true - Type = Array String - CollectionFormat = Csv } - -[] -let ``Parameter Object Examples: Other Parameters``() = - """ -name: token -in: header -description: token to be passed as a header -required: true -type: array -items: - type: integer - format: int64 -collectionFormat: csv - """ - |> SwaggerParser.parseYaml - |> Parsers.parseParameterObject Parsers.emptyDict - |> shouldEqual - { Name = "token" - In = Header - Description = "token to be passed as a header" - Required = true - Type = Array Int64 - CollectionFormat = Csv } - -[] -let ``Parameter Object Examples: Other Parameters - Path String``() = - """ -name: username -in: path -description: username to fetch -required: true -type: string - """ - |> SwaggerParser.parseYaml - |> Parsers.parseParameterObject Parsers.emptyDict - |> shouldEqual - { Name = "username" - In = Path - Description = "username to fetch" - Required = true - Type = String - CollectionFormat = Csv } - -[] -let ``Parameter Object Examples: Other Parameters - Array String Multi``() = - """ -name: id -in: query -description: ID of the object to fetch -required: false -type: array -items: - type: string -collectionFormat: multi -""" - |> SwaggerParser.parseYaml - |> Parsers.parseParameterObject Parsers.emptyDict - |> shouldEqual - { Name = "id" - In = Query - Description = "ID of the object to fetch" - Required = false - Type = Array String - CollectionFormat = Multi } - -[] -let ``Parameter Object Examples: Other Parameters - File``() = - """ -name: avatar -in: formData -description: The avatar of the user -required: true -type: file -""" - |> SwaggerParser.parseYaml - |> Parsers.parseParameterObject Parsers.emptyDict - |> shouldEqual - { Name = "avatar" - In = FormData - Description = "The avatar of the user" - Required = true - Type = File - CollectionFormat = Csv } - -[] -let ``Response Object Examples: Response of an array of a complex type``() = - """ -description: A complex object array response -schema: - type: array - items: - $ref: '#/definitions/VeryComplexType' -""" - |> SwaggerParser.parseYaml - |> Parsers.parseResponseObject(Parsers.ParserContext.Empty) - |> shouldEqual - { Description = "A complex object array response" - Schema = Some <| Array(Reference "#/definitions/VeryComplexType") } - -[] -let ``Response Object Examples: Response with a string type``() = - """ -description: A simple string response -schema: - type: string -""" - |> SwaggerParser.parseYaml - |> Parsers.parseResponseObject(Parsers.ParserContext.Empty) - |> shouldEqual - { Description = "A simple string response" - Schema = Some String } - -[] -let ``Response Object Examples: Response with headers``() = - """ -description: A simple string response -schema: - type: string -headers: - X-Rate-Limit-Limit: - description: The number of allowed requests in the current period - type: integer - X-Rate-Limit-Remaining: - description: The number of remaining requests in the current period - type: integer - X-Rate-Limit-Reset: - description: The number of seconds left in the current period - type: integer -""" - |> SwaggerParser.parseYaml - |> Parsers.parseResponseObject(Parsers.ParserContext.Empty) - |> shouldEqual - { Description = "A simple string response" - Schema = Some String } - -[] -let ``Response Object Examples: Response with no return value``() = - """ -description: object created -""" - |> SwaggerParser.parseYaml - |> Parsers.parseResponseObject(Parsers.ParserContext.Empty) - |> shouldEqual - { Description = "object created" - Schema = None } - -[] -let ``Tag Object Example``() = - """ -name: pet -description: Pets operations -""" - |> SwaggerParser.parseYaml - |> Parsers.parseTagObject - |> shouldEqual( - { Name = "pet" - Description = "Pets operations" } - : TagObject - ) - -[] -let ``Reference Object Example``() = - """ -$ref: '#/definitions/Pet' -""" - |> SwaggerParser.parseYaml - |> Parsers.parseSchemaObject Parsers.emptyDict - |> shouldEqual(Reference "#/definitions/Pet") - -[] -let ``Schema Object Examples: Primitive Sample``() = - """ -type: string -format: email -""" - |> SwaggerParser.parseYaml - |> Parsers.parseSchemaObject Parsers.emptyDict - |> shouldEqual String - - -[] -let ``Schema Object Examples: Simple Model``() = - """ -type: object -required: -- name -properties: - name: - type: string - address: - $ref: '#/definitions/Address' - age: - type: integer - format: int32 - minimum: 0 -""" - |> SwaggerParser.parseYaml - |> Parsers.parseSchemaObject Parsers.emptyDict - |> shouldEqual( - Object - [| { Name = "name" - Type = String - IsRequired = true - Description = "" } - { Name = "address" - Type = Reference "#/definitions/Address" - IsRequired = false - Description = "" } - { Name = "age" - Type = Int32 - IsRequired = false - Description = "" } |] - ) - -[] -let ``Schema Object Examples: Model with Map/Dictionary Properties: For a simple string to string mapping``() = - """ -type: object -additionalProperties: - type: string -""" - |> SwaggerParser.parseYaml - |> Parsers.parseSchemaObject Parsers.emptyDict - |> shouldEqual(Dictionary String) - - - -[] -let ``Schema Object Examples: Model with Map/Dictionary Properties: For a string to model mapping``() = - """ -type: object -additionalProperties: - $ref: '#/definitions/ComplexModel' -""" - |> SwaggerParser.parseYaml - |> Parsers.parseSchemaObject Parsers.emptyDict - |> shouldEqual(Dictionary(Reference "#/definitions/ComplexModel")) - -[] -let ``Schema Object Examples: Model with Example``() = - """ -type: object -properties: - id: - type: integer - format: int64 - name: - type: string -required: -- name -example: - name: Puma - id: 1 - """ - |> SwaggerParser.parseYaml - |> Parsers.parseSchemaObject Parsers.emptyDict - |> shouldEqual( - Object - [| { Name = "id" - Type = Int64 - IsRequired = false - Description = "" } - { Name = "name" - Type = String - IsRequired = true - Description = "" } |] - ) - -[] -let ``Schema Object Examples: Models with Composition``() = - """ -ErrorModel: - type: object - required: - - message - - code - properties: - message: - type: string - code: - type: integer - minimum: 100 - maximum: 600 -ExtendedErrorModel: - allOf: - - $ref: '#/definitions/ErrorModel' - - type: object - required: - - rootCause - properties: - rootCause: - type: string - """ - |> SwaggerParser.parseYaml - |> Parsers.parseDefinitionsObject - |> Seq.map(fun x -> x.Key, x.Value.Value) - |> Map.ofSeq - |> shouldEqual( - [| "#/definitions/ErrorModel", - (Object - [| { Name = "message" - Type = String - IsRequired = true - Description = "" } - { Name = "code" - Type = Int64 - IsRequired = true - Description = "" } |]) - "#/definitions/ExtendedErrorModel", - (Object - [| { Name = "message" - Type = String - IsRequired = true - Description = "" } - { Name = "code" - Type = Int64 - IsRequired = true - Description = "" } - { Name = "rootCause" - Type = String - IsRequired = true - Description = "" } |]) |] - |> Map.ofArray - ) - -[] -let ``Schema Object Examples: Models with Polymorphism Support``() = - """ -definitions: - Pet: - type: object - discriminator: petType - properties: - name: - type: string - petType: - type: string - required: - - name - - petType - Cat: - description: A representation of a cat - allOf: - - $ref: '#/definitions/Pet' - - type: object - properties: - huntingSkill: - type: string - description: The measured skill for hunting - default: lazy - enum: - - clueless - - lazy - - adventurous - - aggressive - required: - - huntingSkill - Dog: - description: A representation of a dog - allOf: - - $ref: '#/definitions/Pet' - - type: object - properties: - packSize: - type: integer - format: int32 - description: the size of the pack the dog is from - default: 0 - minimum: 0 - required: - - packSize -""" - |> SwaggerParser.parseYaml - |> Parsers.parseSchemaObject Parsers.emptyDict - |> shouldEqual(Object [||]) - -[] -let ``Definitions Object Example``() = - """ -Category: - type: object - properties: - id: - type: integer - format: int64 - name: - type: string -Tag: - type: object - properties: - id: - type: integer - format: int64 - name: - type: string -""" - |> SwaggerParser.parseYaml - |> Parsers.parseDefinitionsObject - |> Seq.map(fun x -> x.Key, x.Value.Value) - |> Map.ofSeq - |> shouldEqual( - [| "#/definitions/Category", - (Object - [| { Name = "id" - Type = Int64 - IsRequired = false - Description = "" } - { Name = "name" - Type = String - IsRequired = false - Description = "" } |]) - "#/definitions/Tag", - (Object - [| { Name = "id" - Type = Int64 - IsRequired = false - Description = "" } - { Name = "name" - Type = String - IsRequired = false - Description = "" } |]) |] - |> Map.ofArray - ) - -[] -let ``Parameters Definition Object Example``() = - """ -skipParam: - name: skip - in: query - description: number of items to skip - required: true - type: integer - format: int32 -limitParam: - name: limit - in: query - description: max records to return - required: true - type: integer - format: int32 -""" - |> SwaggerParser.parseYaml - |> Parsers.parseParametersDefinition Parsers.emptyDict - |> shouldEqual( - [| "#/parameters/skipParam", - { Name = "skip" - In = Query - Description = "number of items to skip" - Required = true - Type = Int32 - CollectionFormat = Csv } - "#/parameters/limitParam", - { Name = "limit" - In = Query - Description = "max records to return" - Required = true - Type = Int32 - CollectionFormat = Csv } |] - |> Map.ofArray - ) - -[] -let ``Responses Definitions Object Example``() = - """ -NotFound: - description: Entity not found. -IllegalInput: - description: Illegal input for operation. -GeneralError: - description: General Error - schema: - $ref: '#/definitions/GeneralError' -""" - |> SwaggerParser.parseYaml - |> Parsers.parseResponsesDefinition - |> shouldEqual( - [| "#/responses/NotFound", - { Description = "Entity not found." - Schema = None } - "#/responses/IllegalInput", - { Description = "Illegal input for operation." - Schema = None } - "#/responses/GeneralError", - { Description = "General Error" - Schema = Some(Reference "#/definitions/GeneralError") } |] - |> Map.ofArray - ) From 3526f7bef42ecf6bfd872748841e76b0560cbb10 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 13 Apr 2026 16:48:01 +0000 Subject: [PATCH 2/4] ci: trigger checks From 7d42633ef8bd67ab9a7b1295637f649a45e53d0a Mon Sep 17 00:00:00 2001 From: Sergey Tihon Date: Mon, 13 Apr 2026 21:13:05 +0200 Subject: [PATCH 3/4] fix: correct schema paths and stale module reference after v3 folder flattening The folder restructuring in 43311e5 moved test files from v3/ subdirectories to project roots but incorrectly updated relative schema paths (/../Schemas/ instead of /Schemas/) and left a stale Swashbuckle.v3 module reference. --- tests/SwaggerProvider.ProviderTests/Swagger.I0173.Tests.fs | 2 +- tests/SwaggerProvider.ProviderTests/Swagger.I0181.Tests.fs | 2 +- tests/SwaggerProvider.ProviderTests/Swagger.I0219.Tests.fs | 2 +- tests/SwaggerProvider.ProviderTests/Swagger.I0279.Tests.fs | 2 +- .../Swagger.NullableDate.Tests.fs | 2 +- .../Swagger.SchemaReaderErrors.Tests.fs | 5 ++--- .../Swashbuckle.CancellationToken.Tests.fs | 2 +- tests/SwaggerProvider.Tests/PathResolutionTests.fs | 2 +- tests/SwaggerProvider.Tests/SsrfSecurityTests.fs | 6 ++++-- 9 files changed, 13 insertions(+), 12 deletions(-) diff --git a/tests/SwaggerProvider.ProviderTests/Swagger.I0173.Tests.fs b/tests/SwaggerProvider.ProviderTests/Swagger.I0173.Tests.fs index 5129544e..8e728d02 100644 --- a/tests/SwaggerProvider.ProviderTests/Swagger.I0173.Tests.fs +++ b/tests/SwaggerProvider.ProviderTests/Swagger.I0173.Tests.fs @@ -3,7 +3,7 @@ module Swagger.I0173.Tests open SwaggerProvider [] -let Schema = __SOURCE_DIRECTORY__ + "/../Schemas/issue173.json" +let Schema = __SOURCE_DIRECTORY__ + "/Schemas/issue173.json" type OdhApiTourism = OpenApiClientProvider diff --git a/tests/SwaggerProvider.ProviderTests/Swagger.I0181.Tests.fs b/tests/SwaggerProvider.ProviderTests/Swagger.I0181.Tests.fs index e40f7de7..1f991314 100644 --- a/tests/SwaggerProvider.ProviderTests/Swagger.I0181.Tests.fs +++ b/tests/SwaggerProvider.ProviderTests/Swagger.I0181.Tests.fs @@ -3,7 +3,7 @@ module Swagger.I0181.Tests open SwaggerProvider [] -let Schema = __SOURCE_DIRECTORY__ + "/../Schemas/issue181.yaml" +let Schema = __SOURCE_DIRECTORY__ + "/Schemas/issue181.yaml" type MyApi = OpenApiClientProvider diff --git a/tests/SwaggerProvider.ProviderTests/Swagger.I0219.Tests.fs b/tests/SwaggerProvider.ProviderTests/Swagger.I0219.Tests.fs index c04644bf..fadfbdf9 100644 --- a/tests/SwaggerProvider.ProviderTests/Swagger.I0219.Tests.fs +++ b/tests/SwaggerProvider.ProviderTests/Swagger.I0219.Tests.fs @@ -3,7 +3,7 @@ module Swagger.I0219.Tests open SwaggerProvider [] -let Schema = __SOURCE_DIRECTORY__ + "/../Schemas/issue219.yaml" +let Schema = __SOURCE_DIRECTORY__ + "/Schemas/issue219.yaml" type AcmeApi = OpenApiClientProvider diff --git a/tests/SwaggerProvider.ProviderTests/Swagger.I0279.Tests.fs b/tests/SwaggerProvider.ProviderTests/Swagger.I0279.Tests.fs index 2dfbf18e..ac39ac0e 100644 --- a/tests/SwaggerProvider.ProviderTests/Swagger.I0279.Tests.fs +++ b/tests/SwaggerProvider.ProviderTests/Swagger.I0279.Tests.fs @@ -3,7 +3,7 @@ module Swagger.I0279.Tests open SwaggerProvider [] -let Schema = __SOURCE_DIRECTORY__ + "/../Schemas/issue279.json" +let Schema = __SOURCE_DIRECTORY__ + "/Schemas/issue279.json" type Immich = OpenApiClientProvider diff --git a/tests/SwaggerProvider.ProviderTests/Swagger.NullableDate.Tests.fs b/tests/SwaggerProvider.ProviderTests/Swagger.NullableDate.Tests.fs index 4b8ec37e..0e0baeca 100644 --- a/tests/SwaggerProvider.ProviderTests/Swagger.NullableDate.Tests.fs +++ b/tests/SwaggerProvider.ProviderTests/Swagger.NullableDate.Tests.fs @@ -7,7 +7,7 @@ open System.Text.Json open System.Text.Json.Serialization [] -let Schema = __SOURCE_DIRECTORY__ + "/../Schemas/nullable-date.yaml" +let Schema = __SOURCE_DIRECTORY__ + "/Schemas/nullable-date.yaml" type TestApi = OpenApiClientProvider diff --git a/tests/SwaggerProvider.ProviderTests/Swagger.SchemaReaderErrors.Tests.fs b/tests/SwaggerProvider.ProviderTests/Swagger.SchemaReaderErrors.Tests.fs index fcf0fdb5..c767be74 100644 --- a/tests/SwaggerProvider.ProviderTests/Swagger.SchemaReaderErrors.Tests.fs +++ b/tests/SwaggerProvider.ProviderTests/Swagger.SchemaReaderErrors.Tests.fs @@ -5,12 +5,11 @@ open Xunit open FsUnitTyped [] -let ValidSchema = __SOURCE_DIRECTORY__ + "/../Schemas/petstore.yaml" +let ValidSchema = __SOURCE_DIRECTORY__ + "/Schemas/petstore.yaml" [] let SchemaWithErrors = - __SOURCE_DIRECTORY__ - + "/../Schemas/nullable-parameter-issue261.json" + __SOURCE_DIRECTORY__ + "/Schemas/nullable-parameter-issue261.json" type ValidApi = OpenApiClientProvider diff --git a/tests/SwaggerProvider.ProviderTests/Swashbuckle.CancellationToken.Tests.fs b/tests/SwaggerProvider.ProviderTests/Swashbuckle.CancellationToken.Tests.fs index 1d48cda6..e97ef791 100644 --- a/tests/SwaggerProvider.ProviderTests/Swashbuckle.CancellationToken.Tests.fs +++ b/tests/SwaggerProvider.ProviderTests/Swashbuckle.CancellationToken.Tests.fs @@ -6,7 +6,7 @@ open System open System.Net.Http open System.Threading open SwaggerProvider -open Swashbuckle.v3.ReturnControllersTests +open Swashbuckle.ReturnControllersTests type WebAPIAsync = OpenApiClientProvider<"http://localhost:5000/swagger/v1/openapi.json", IgnoreOperationId=true, SsrfProtection=false, PreferAsync=true> diff --git a/tests/SwaggerProvider.Tests/PathResolutionTests.fs b/tests/SwaggerProvider.Tests/PathResolutionTests.fs index 1625b165..cdbf94b1 100644 --- a/tests/SwaggerProvider.Tests/PathResolutionTests.fs +++ b/tests/SwaggerProvider.Tests/PathResolutionTests.fs @@ -115,7 +115,7 @@ module PathResolutionTests = // Test: Simulates the common pattern: __SOURCE_DIRECTORY__ + "/../Schemas/..." // This should work correctly on both Windows and Unix let sourceDir = __SOURCE_DIRECTORY__ - let relativePart = "/../Schemas/petstore-v2.json" + let relativePart = "/../SwaggerProvider.ProviderTests/Schemas/petstore-v2.json" let combined = sourceDir + relativePart // This simulates what happens in test files diff --git a/tests/SwaggerProvider.Tests/SsrfSecurityTests.fs b/tests/SwaggerProvider.Tests/SsrfSecurityTests.fs index 33f5da99..ae9d10b4 100644 --- a/tests/SwaggerProvider.Tests/SsrfSecurityTests.fs +++ b/tests/SwaggerProvider.Tests/SsrfSecurityTests.fs @@ -270,9 +270,11 @@ module RelativeFilePathTests = task { // Test: Relative file paths using __SOURCE_DIRECTORY__ should work correctly // This ensures that development-time file references like: - // let Schema = __SOURCE_DIRECTORY__ + "/../Schemas/petstore-v2.json" + // let Schema = __SOURCE_DIRECTORY__ + "/../SwaggerProvider.ProviderTests/Schemas/petstore-v2.json" // are properly handled (not rejected by SSRF validation) - let schemaPath = __SOURCE_DIRECTORY__ + "/../Schemas/petstore-v2.json" + let schemaPath = + __SOURCE_DIRECTORY__ + + "/../SwaggerProvider.ProviderTests/Schemas/petstore-v2.json" try let! _ = readSchemaPath false "" "" schemaPath From 033fcc20a8cee081bbd0c3e7312d957cb48b0834 Mon Sep 17 00:00:00 2001 From: Sergey Tihon Date: Mon, 13 Apr 2026 21:38:58 +0200 Subject: [PATCH 4/4] fix: remove remaining Swashbuckle.v3 module references in ProviderTests --- .../Swashbuckle.FileController.Tests.fs | 2 +- .../Swashbuckle.NoContentControllers.Tests.fs | 2 +- .../Swashbuckle.ResourceControllers.Tests.fs | 4 ++-- .../Swashbuckle.ReturnTextControllers.Tests.fs | 2 +- .../Swashbuckle.SpecialCasesControllers.Tests.fs | 4 ++-- .../Swashbuckle.UpdateControllers.Tests.fs | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/SwaggerProvider.ProviderTests/Swashbuckle.FileController.Tests.fs b/tests/SwaggerProvider.ProviderTests/Swashbuckle.FileController.Tests.fs index 03f3a190..e328195a 100644 --- a/tests/SwaggerProvider.ProviderTests/Swashbuckle.FileController.Tests.fs +++ b/tests/SwaggerProvider.ProviderTests/Swashbuckle.FileController.Tests.fs @@ -3,7 +3,7 @@ module Swashbuckle.FileControllersTests open Xunit open FsUnitTyped open System.IO -open Swashbuckle.v3.ReturnControllersTests +open Swashbuckle.ReturnControllersTests let text = "This is test file content" diff --git a/tests/SwaggerProvider.ProviderTests/Swashbuckle.NoContentControllers.Tests.fs b/tests/SwaggerProvider.ProviderTests/Swashbuckle.NoContentControllers.Tests.fs index 47b119bf..79d352df 100644 --- a/tests/SwaggerProvider.ProviderTests/Swashbuckle.NoContentControllers.Tests.fs +++ b/tests/SwaggerProvider.ProviderTests/Swashbuckle.NoContentControllers.Tests.fs @@ -2,7 +2,7 @@ module Swashbuckle.NoContentControllersTests open FsUnitTyped open Xunit -open Swashbuckle.v3.ReturnControllersTests +open Swashbuckle.ReturnControllersTests [] let ``Test 204 with GET``() = diff --git a/tests/SwaggerProvider.ProviderTests/Swashbuckle.ResourceControllers.Tests.fs b/tests/SwaggerProvider.ProviderTests/Swashbuckle.ResourceControllers.Tests.fs index 19e91b70..b5f35a57 100644 --- a/tests/SwaggerProvider.ProviderTests/Swashbuckle.ResourceControllers.Tests.fs +++ b/tests/SwaggerProvider.ProviderTests/Swashbuckle.ResourceControllers.Tests.fs @@ -1,8 +1,8 @@ -module Swashbuckle.v3.ResourceControllersTests +module Swashbuckle.ResourceControllersTests open Xunit open FsUnitTyped -open Swashbuckle.v3.ReturnControllersTests +open Swashbuckle.ReturnControllersTests [] let ``ResourceStringString Add and get from resource dictionary``() = diff --git a/tests/SwaggerProvider.ProviderTests/Swashbuckle.ReturnTextControllers.Tests.fs b/tests/SwaggerProvider.ProviderTests/Swashbuckle.ReturnTextControllers.Tests.fs index 7f8cc8de..3d8abb65 100644 --- a/tests/SwaggerProvider.ProviderTests/Swashbuckle.ReturnTextControllers.Tests.fs +++ b/tests/SwaggerProvider.ProviderTests/Swashbuckle.ReturnTextControllers.Tests.fs @@ -6,7 +6,7 @@ open SwaggerProvider open System open System.Net.Http -open Swashbuckle.v3.ReturnControllersTests +open Swashbuckle.ReturnControllersTests [] let ``Return text/plain GET Test``() = diff --git a/tests/SwaggerProvider.ProviderTests/Swashbuckle.SpecialCasesControllers.Tests.fs b/tests/SwaggerProvider.ProviderTests/Swashbuckle.SpecialCasesControllers.Tests.fs index 8650308b..d2858a92 100644 --- a/tests/SwaggerProvider.ProviderTests/Swashbuckle.SpecialCasesControllers.Tests.fs +++ b/tests/SwaggerProvider.ProviderTests/Swashbuckle.SpecialCasesControllers.Tests.fs @@ -1,7 +1,7 @@ -module Swashbuckle.v3.SpecialCasesControllersTests +module Swashbuckle.SpecialCasesControllersTests open Xunit -open Swashbuckle.v3.ReturnControllersTests +open Swashbuckle.ReturnControllersTests [] let ``Request response in JSON format from MultiFormatController``() = diff --git a/tests/SwaggerProvider.ProviderTests/Swashbuckle.UpdateControllers.Tests.fs b/tests/SwaggerProvider.ProviderTests/Swashbuckle.UpdateControllers.Tests.fs index 38c2546d..51dd1788 100644 --- a/tests/SwaggerProvider.ProviderTests/Swashbuckle.UpdateControllers.Tests.fs +++ b/tests/SwaggerProvider.ProviderTests/Swashbuckle.UpdateControllers.Tests.fs @@ -3,7 +3,7 @@ module Swashbuckle.UpdateControllersTests open Xunit open FsUnitTyped open System -open Swashbuckle.v3.ReturnControllersTests +open Swashbuckle.ReturnControllersTests let guid = Guid.NewGuid() let guid2 = Guid.NewGuid()