mirror of
https://github.com/wiremock/WireMock.Net.git
synced 2026-04-05 00:47:21 +02:00
Use ILRepack to include Microsoft.OpenApi as internal (#1290)
* . * Use ILRepack to include Microsoft.OpenApi as internal * ... * OpenApiSpecificationVersion * . * 080 * 4
This commit is contained in:
@@ -128,7 +128,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.Middleware.Tes
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.AwesomeAssertions", "src\WireMock.Net.AwesomeAssertions\WireMock.Net.AwesomeAssertions.csproj", "{7753670F-7C7F-44BF-8BC7-08325588E60C}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.AwesomeAssertions", "src\WireMock.Net.AwesomeAssertions\WireMock.Net.AwesomeAssertions.csproj", "{7753670F-7C7F-44BF-8BC7-08325588E60C}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.OpenApiParser", "src\WireMock.Net.OpenApiParser\WireMock.Net.OpenApiParser.csproj", "{D3804228-91F4-4502-9595-39584E5AADAD}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src-preview", "src-preview", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.OpenApiParser", "src\WireMock.Net.OpenApiParser\WireMock.Net.OpenApiParser.csproj", "{E5B03EEF-822C-4295-952B-4479AD30082B}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
@@ -304,10 +306,10 @@ Global
|
|||||||
{7753670F-7C7F-44BF-8BC7-08325588E60C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{7753670F-7C7F-44BF-8BC7-08325588E60C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{7753670F-7C7F-44BF-8BC7-08325588E60C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{7753670F-7C7F-44BF-8BC7-08325588E60C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{7753670F-7C7F-44BF-8BC7-08325588E60C}.Release|Any CPU.Build.0 = Release|Any CPU
|
{7753670F-7C7F-44BF-8BC7-08325588E60C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{D3804228-91F4-4502-9595-39584E5AADAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{E5B03EEF-822C-4295-952B-4479AD30082B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{D3804228-91F4-4502-9595-39584E5AADAD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{E5B03EEF-822C-4295-952B-4479AD30082B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{D3804228-91F4-4502-9595-39584E5AADAD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{E5B03EEF-822C-4295-952B-4479AD30082B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{D3804228-91F4-4502-9595-39584E5AADAD}.Release|Any CPU.Build.0 = Release|Any CPU
|
{E5B03EEF-822C-4295-952B-4479AD30082B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
@@ -357,7 +359,7 @@ Global
|
|||||||
{6B30AA9F-DA04-4EB5-B03C-45A8EF272ECE} = {0BB8B634-407A-4610-A91F-11586990767A}
|
{6B30AA9F-DA04-4EB5-B03C-45A8EF272ECE} = {0BB8B634-407A-4610-A91F-11586990767A}
|
||||||
{A5FEF4F7-7DA2-4962-89A8-16BA942886E5} = {0BB8B634-407A-4610-A91F-11586990767A}
|
{A5FEF4F7-7DA2-4962-89A8-16BA942886E5} = {0BB8B634-407A-4610-A91F-11586990767A}
|
||||||
{7753670F-7C7F-44BF-8BC7-08325588E60C} = {8F890C6F-9ACC-438D-928A-AD61CDA862F2}
|
{7753670F-7C7F-44BF-8BC7-08325588E60C} = {8F890C6F-9ACC-438D-928A-AD61CDA862F2}
|
||||||
{D3804228-91F4-4502-9595-39584E5AADAD} = {8F890C6F-9ACC-438D-928A-AD61CDA862F2}
|
{E5B03EEF-822C-4295-952B-4479AD30082B} = {8F890C6F-9ACC-438D-928A-AD61CDA862F2}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {DC539027-9852-430C-B19F-FD035D018458}
|
SolutionGuid = {DC539027-9852-430C-B19F-FD035D018458}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
#if NET46 || NET47 || NETSTANDARD2_0
|
#if NET46 || NETSTANDARD2_0
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace WireMock.Net.OpenApiParser.Extensions;
|
namespace WireMock.Net.OpenApiParser.Extensions;
|
||||||
@@ -1,53 +1,60 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.Json;
|
|
||||||
using Microsoft.OpenApi.Any;
|
using Microsoft.OpenApi.Any;
|
||||||
|
using Microsoft.OpenApi.Interfaces;
|
||||||
using Microsoft.OpenApi.Models;
|
using Microsoft.OpenApi.Models;
|
||||||
using Microsoft.OpenApi.Models.Interfaces;
|
|
||||||
using WireMock.Net.OpenApiParser.Types;
|
using WireMock.Net.OpenApiParser.Types;
|
||||||
|
|
||||||
namespace WireMock.Net.OpenApiParser.Extensions;
|
namespace WireMock.Net.OpenApiParser.Extensions;
|
||||||
|
|
||||||
internal static class OpenApiSchemaExtensions
|
internal static class OpenApiSchemaExtensions
|
||||||
{
|
{
|
||||||
public static bool TryGetXNullable(this IOpenApiSchema schema, out bool value)
|
/// <summary>
|
||||||
|
/// https://stackoverflow.com/questions/48111459/how-to-define-a-property-that-can-be-string-or-null-in-openapi-swagger
|
||||||
|
/// </summary>
|
||||||
|
public static bool TryGetXNullable(this OpenApiSchema schema, out bool value)
|
||||||
{
|
{
|
||||||
value = false;
|
value = false;
|
||||||
|
|
||||||
if (schema.Extensions != null && schema.Extensions.TryGetValue(OpenApiConstants.NullableExtension, out var nullExtRawValue) && nullExtRawValue is OpenApiAny { Node: { } jsonNode })
|
if (schema.Extensions.TryGetValue("x-nullable", out var e) && e is OpenApiBoolean openApiBoolean)
|
||||||
{
|
{
|
||||||
value = jsonNode.GetValueKind() == JsonValueKind.True;
|
value = openApiBoolean.Value;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JsonSchemaType? GetSchemaType(this IOpenApiSchema? schema, out bool isNullable)
|
public static SchemaType GetSchemaType(this OpenApiSchema? schema)
|
||||||
{
|
{
|
||||||
isNullable = false;
|
|
||||||
|
|
||||||
if (schema == null)
|
if (schema == null)
|
||||||
{
|
{
|
||||||
return null;
|
return SchemaType.Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (schema.Type == null)
|
if (schema.Type == null)
|
||||||
{
|
{
|
||||||
if (schema.AllOf?.Any() == true || schema.AnyOf?.Any() == true)
|
if (schema.AllOf.Any() || schema.AnyOf.Any())
|
||||||
{
|
{
|
||||||
return JsonSchemaType.Object;
|
return SchemaType.Object;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
isNullable = (schema.Type | JsonSchemaType.Null) == JsonSchemaType.Null || (schema.TryGetXNullable(out var xNullable) && xNullable);
|
return schema.Type switch
|
||||||
|
{
|
||||||
// Removes the Null flag from the schema.Type, ensuring the returned value represents a non-nullable type.
|
"object" => SchemaType.Object,
|
||||||
return schema.Type & ~JsonSchemaType.Null;
|
"array" => SchemaType.Array,
|
||||||
|
"integer" => SchemaType.Integer,
|
||||||
|
"number" => SchemaType.Number,
|
||||||
|
"boolean" => SchemaType.Boolean,
|
||||||
|
"string" => SchemaType.String,
|
||||||
|
"file" => SchemaType.File,
|
||||||
|
_ => SchemaType.Unknown
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SchemaFormat GetSchemaFormat(this IOpenApiSchema? schema)
|
public static SchemaFormat GetSchemaFormat(this OpenApiSchema? schema)
|
||||||
{
|
{
|
||||||
switch (schema?.Format)
|
switch (schema?.Format)
|
||||||
{
|
{
|
||||||
@@ -4,7 +4,7 @@ using System.IO;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Microsoft.OpenApi.Models;
|
using Microsoft.OpenApi.Models;
|
||||||
using Microsoft.OpenApi.Reader;
|
using Microsoft.OpenApi.Readers;
|
||||||
using Stef.Validation;
|
using Stef.Validation;
|
||||||
using WireMock.Net.OpenApiParser.Settings;
|
using WireMock.Net.OpenApiParser.Settings;
|
||||||
using WireMock.Server;
|
using WireMock.Server;
|
||||||
@@ -17,7 +17,7 @@ namespace WireMock.Net.OpenApiParser.Extensions;
|
|||||||
public static class WireMockServerExtensions
|
public static class WireMockServerExtensions
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Register the mappings via an OpenAPI (swagger) V2/V3/V3.1 file.
|
/// Register the mappings via an OpenAPI (swagger) V2 or V3 file.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="server">The WireMockServer instance</param>
|
/// <param name="server">The WireMockServer instance</param>
|
||||||
/// <param name="path">Path containing OpenAPI file to parse and use the mappings.</param>
|
/// <param name="path">Path containing OpenAPI file to parse and use the mappings.</param>
|
||||||
@@ -29,7 +29,7 @@ public static class WireMockServerExtensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Register the mappings via an OpenAPI (swagger) V2/V3/V3.1 file.
|
/// Register the mappings via an OpenAPI (swagger) V2 or V3 file.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="server">The WireMockServer instance</param>
|
/// <param name="server">The WireMockServer instance</param>
|
||||||
/// <param name="path">Path containing OpenAPI file to parse and use the mappings.</param>
|
/// <param name="path">Path containing OpenAPI file to parse and use the mappings.</param>
|
||||||
@@ -47,7 +47,7 @@ public static class WireMockServerExtensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Register the mappings via an OpenAPI (swagger) V2/V3/V3.1 stream.
|
/// Register the mappings via an OpenAPI (swagger) V2 or V3 stream.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="server">The WireMockServer instance</param>
|
/// <param name="server">The WireMockServer instance</param>
|
||||||
/// <param name="stream">Stream containing OpenAPI description to parse and use the mappings.</param>
|
/// <param name="stream">Stream containing OpenAPI description to parse and use the mappings.</param>
|
||||||
@@ -59,7 +59,7 @@ public static class WireMockServerExtensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Register the mappings via an OpenAPI (swagger) V2/V3/V3.1 stream.
|
/// Register the mappings via an OpenAPI (swagger) V2 or V3 stream.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="server">The WireMockServer instance</param>
|
/// <param name="server">The WireMockServer instance</param>
|
||||||
/// <param name="stream">Stream containing OpenAPI description to parse and use the mappings.</param>
|
/// <param name="stream">Stream containing OpenAPI description to parse and use the mappings.</param>
|
||||||
@@ -78,7 +78,7 @@ public static class WireMockServerExtensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Register the mappings via an OpenAPI (swagger) V2/V3/V3.1 document.
|
/// Register the mappings via an OpenAPI (swagger) V2 or V3 document.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="server">The WireMockServer instance</param>
|
/// <param name="server">The WireMockServer instance</param>
|
||||||
/// <param name="document">The OpenAPI document to use as mappings.</param>
|
/// <param name="document">The OpenAPI document to use as mappings.</param>
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Microsoft.OpenApi.Models;
|
using Microsoft.OpenApi.Models;
|
||||||
using Microsoft.OpenApi.Reader;
|
using Microsoft.OpenApi.Readers;
|
||||||
using WireMock.Admin.Mappings;
|
using WireMock.Admin.Mappings;
|
||||||
using WireMock.Net.OpenApiParser.Settings;
|
using WireMock.Net.OpenApiParser.Settings;
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ public interface IWireMockOpenApiParser
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generate <see cref="IReadOnlyList{MappingModel}"/> from a file-path.
|
/// Generate <see cref="IReadOnlyList{MappingModel}"/> from a file-path.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="path">The path to read the OpenApi/Swagger/V2/V3/V31 or Raml file.</param>
|
/// <param name="path">The path to read the OpenApi/Swagger/V2/V3 or Raml file.</param>
|
||||||
/// <param name="diagnostic">OpenApiDiagnostic output</param>
|
/// <param name="diagnostic">OpenApiDiagnostic output</param>
|
||||||
/// <returns>MappingModel</returns>
|
/// <returns>MappingModel</returns>
|
||||||
IReadOnlyList<MappingModel> FromFile(string path, out OpenApiDiagnostic diagnostic);
|
IReadOnlyList<MappingModel> FromFile(string path, out OpenApiDiagnostic diagnostic);
|
||||||
@@ -25,7 +25,7 @@ public interface IWireMockOpenApiParser
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generate <see cref="IReadOnlyList{MappingModel}"/> from a file-path.
|
/// Generate <see cref="IReadOnlyList{MappingModel}"/> from a file-path.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="path">The path to read the OpenApi/Swagger/V2/V3/V31 or Raml file.</param>
|
/// <param name="path">The path to read the OpenApi/Swagger/V2/V3 or Raml file.</param>
|
||||||
/// <param name="settings">Additional settings</param>
|
/// <param name="settings">Additional settings</param>
|
||||||
/// <param name="diagnostic">OpenApiDiagnostic output</param>
|
/// <param name="diagnostic">OpenApiDiagnostic output</param>
|
||||||
/// <returns>MappingModel</returns>
|
/// <returns>MappingModel</returns>
|
||||||
@@ -3,19 +3,20 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.Json;
|
using Microsoft.OpenApi;
|
||||||
using System.Text.Json.Nodes;
|
using Microsoft.OpenApi.Any;
|
||||||
using Microsoft.OpenApi.Models;
|
using Microsoft.OpenApi.Models;
|
||||||
using Microsoft.OpenApi.Models.Interfaces;
|
using Microsoft.OpenApi.Writers;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
using Stef.Validation;
|
using Stef.Validation;
|
||||||
using WireMock.Admin.Mappings;
|
using WireMock.Admin.Mappings;
|
||||||
using WireMock.Net.OpenApiParser.Extensions;
|
using WireMock.Net.OpenApiParser.Extensions;
|
||||||
using WireMock.Net.OpenApiParser.Settings;
|
using WireMock.Net.OpenApiParser.Settings;
|
||||||
using WireMock.Net.OpenApiParser.Types;
|
using WireMock.Net.OpenApiParser.Types;
|
||||||
using WireMock.Net.OpenApiParser.Utils;
|
using WireMock.Net.OpenApiParser.Utils;
|
||||||
using SystemTextJsonSerializer = System.Text.Json.JsonSerializer;
|
|
||||||
|
|
||||||
namespace WireMock.Net.OpenApiParser.Mappers;
|
namespace WireMock.Net.OpenApiParser.Mappers;
|
||||||
|
|
||||||
@@ -38,40 +39,56 @@ internal class OpenApiPathsMapper
|
|||||||
.OrderBy(p => p.Key)
|
.OrderBy(p => p.Key)
|
||||||
.Select(p => MapPath(p.Key, p.Value, servers))
|
.Select(p => MapPath(p.Key, p.Value, servers))
|
||||||
.SelectMany(x => x)
|
.SelectMany(x => x)
|
||||||
.ToArray() ?? [];
|
.ToArray() ??
|
||||||
|
Array.Empty<MappingModel>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private IReadOnlyList<MappingModel> MapPath(string path, IOpenApiPathItem pathItem, IList<OpenApiServer> servers)
|
private IReadOnlyList<MappingModel> MapPaths(OpenApiPaths? paths, IList<OpenApiServer> servers)
|
||||||
{
|
{
|
||||||
return pathItem.Operations?.Select(o => MapOperationToMappingModel(path, o.Key.ToString().ToUpperInvariant(), o.Value, servers)).ToArray() ?? [];
|
return paths?
|
||||||
|
.OrderBy(p => p.Key)
|
||||||
|
.Select(p => MapPath(p.Key, p.Value, servers))
|
||||||
|
.SelectMany(x => x)
|
||||||
|
.ToArray() ??
|
||||||
|
Array.Empty<MappingModel>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private IReadOnlyList<MappingModel> MapPath(string path, OpenApiPathItem pathItem, IList<OpenApiServer> servers)
|
||||||
|
{
|
||||||
|
return pathItem.Operations.Select(o => MapOperationToMappingModel(path, o.Key.ToString().ToUpperInvariant(), o.Value, servers)).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
private MappingModel MapOperationToMappingModel(string path, string httpMethod, OpenApiOperation operation, IList<OpenApiServer> servers)
|
private MappingModel MapOperationToMappingModel(string path, string httpMethod, OpenApiOperation operation, IList<OpenApiServer> servers)
|
||||||
{
|
{
|
||||||
var queryParameters = operation.Parameters?.Where(p => p.In == ParameterLocation.Query) ?? [];
|
var queryParameters = operation.Parameters.Where(p => p.In == ParameterLocation.Query);
|
||||||
var pathParameters = operation.Parameters?.Where(p => p.In == ParameterLocation.Path) ?? [];
|
var pathParameters = operation.Parameters.Where(p => p.In == ParameterLocation.Path);
|
||||||
var headers = operation.Parameters?.Where(p => p.In == ParameterLocation.Header) ?? [];
|
var headers = operation.Parameters.Where(p => p.In == ParameterLocation.Header);
|
||||||
|
|
||||||
var response = operation?.Responses?.FirstOrDefault() ?? new KeyValuePair<string, IOpenApiResponse>();
|
var response = operation.Responses.FirstOrDefault();
|
||||||
|
|
||||||
TryGetContent(response.Value?.Content, out OpenApiMediaType? responseContent, out var responseContentType);
|
TryGetContent(response.Value?.Content, out OpenApiMediaType? responseContent, out string? responseContentType);
|
||||||
var responseSchema = response.Value?.Content?.FirstOrDefault().Value?.Schema;
|
var responseSchema = response.Value?.Content?.FirstOrDefault().Value?.Schema;
|
||||||
var responseExample = responseContent?.Example;
|
var responseExample = responseContent?.Example;
|
||||||
var responseSchemaExample = responseContent?.Schema?.Example;
|
var responseSchemaExample = responseContent?.Schema?.Example;
|
||||||
|
|
||||||
var responseBody = responseExample ?? responseSchemaExample ?? MapSchemaToObject(responseSchema);
|
var body = responseExample != null ? MapOpenApiAnyToJToken(responseExample) :
|
||||||
|
responseSchemaExample != null ? MapOpenApiAnyToJToken(responseSchemaExample) :
|
||||||
|
MapSchemaToObject(responseSchema);
|
||||||
|
|
||||||
var requestBodyModel = new BodyModel();
|
var requestBodyModel = new BodyModel();
|
||||||
if (operation.RequestBody != null && operation.RequestBody.Content != null && operation.RequestBody.Required)
|
if (operation.RequestBody != null && operation.RequestBody.Content != null && operation.RequestBody.Required)
|
||||||
{
|
{
|
||||||
var request = operation.RequestBody.Content;
|
var request = operation.RequestBody.Content;
|
||||||
TryGetContent(request, out var requestContent, out _);
|
TryGetContent(request, out OpenApiMediaType? requestContent, out _);
|
||||||
|
|
||||||
var requestBodySchema = operation.RequestBody.Content.First().Value?.Schema;
|
var requestBodySchema = operation.RequestBody.Content.First().Value?.Schema;
|
||||||
var requestBodyExample = requestContent!.Example;
|
var requestBodyExample = requestContent!.Example;
|
||||||
var requestBodySchemaExample = requestContent.Schema?.Example;
|
var requestBodySchemaExample = requestContent.Schema?.Example;
|
||||||
|
|
||||||
var requestBodyMapped = requestBodyExample ?? requestBodySchemaExample ?? MapSchemaToObject(requestBodySchema);
|
var requestBodyMapped = requestBodyExample != null ? MapOpenApiAnyToJToken(requestBodyExample) :
|
||||||
|
requestBodySchemaExample != null ? MapOpenApiAnyToJToken(requestBodySchemaExample) :
|
||||||
|
MapSchemaToObject(requestBodySchema);
|
||||||
|
|
||||||
requestBodyModel = MapRequestBody(requestBodyMapped);
|
requestBodyModel = MapRequestBody(requestBodyMapped);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,12 +112,12 @@ internal class OpenApiPathsMapper
|
|||||||
{
|
{
|
||||||
StatusCode = httpStatusCode,
|
StatusCode = httpStatusCode,
|
||||||
Headers = MapHeaders(responseContentType, response.Value?.Headers),
|
Headers = MapHeaders(responseContentType, response.Value?.Headers),
|
||||||
BodyAsJson = responseBody != null ? JsonConvert.DeserializeObject(SystemTextJsonSerializer.Serialize(responseBody)) : null
|
BodyAsJson = body
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private BodyModel? MapRequestBody(JsonNode? requestBody)
|
private BodyModel? MapRequestBody(object? requestBody)
|
||||||
{
|
{
|
||||||
if (requestBody == null)
|
if (requestBody == null)
|
||||||
{
|
{
|
||||||
@@ -112,7 +129,7 @@ internal class OpenApiPathsMapper
|
|||||||
Matcher = new MatcherModel
|
Matcher = new MatcherModel
|
||||||
{
|
{
|
||||||
Name = "JsonMatcher",
|
Name = "JsonMatcher",
|
||||||
Pattern = SystemTextJsonSerializer.Serialize(requestBody, new JsonSerializerOptions { WriteIndented = true }),
|
Pattern = JsonConvert.SerializeObject(requestBody, Formatting.Indented),
|
||||||
IgnoreCase = _settings.RequestBodyIgnoreCase
|
IgnoreCase = _settings.RequestBodyIgnoreCase
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -143,103 +160,117 @@ internal class OpenApiPathsMapper
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private JsonNode? MapSchemaToObject(IOpenApiSchema? schema)
|
private object? MapSchemaToObject(OpenApiSchema? schema, string? name = null)
|
||||||
{
|
{
|
||||||
if (schema == null)
|
if (schema == null)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (schema.GetSchemaType(out _))
|
switch (schema.GetSchemaType())
|
||||||
{
|
{
|
||||||
case JsonSchemaType.Array:
|
case SchemaType.Array:
|
||||||
var array = new JsonArray();
|
var jArray = new JArray();
|
||||||
for (var i = 0; i < _settings.NumberOfArrayItems; i++)
|
for (int i = 0; i < _settings.NumberOfArrayItems; i++)
|
||||||
{
|
{
|
||||||
if (schema.Items?.Properties?.Count > 0)
|
if (schema.Items.Properties.Count > 0)
|
||||||
{
|
{
|
||||||
var item = new JsonObject();
|
var arrayItem = new JObject();
|
||||||
foreach (var property in schema.Items.Properties)
|
foreach (var property in schema.Items.Properties)
|
||||||
{
|
{
|
||||||
item[property.Key] = MapSchemaToObject(property.Value);
|
var objectValue = MapSchemaToObject(property.Value, property.Key);
|
||||||
|
if (objectValue is JProperty jp)
|
||||||
|
{
|
||||||
|
arrayItem.Add(jp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
arrayItem.Add(new JProperty(property.Key, objectValue));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
array.Add(item);
|
jArray.Add(arrayItem);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var arrayItem = MapSchemaToObject(schema.Items);
|
var arrayItem = MapSchemaToObject(schema.Items, name: null); // Set name to null to force JObject instead of JProperty
|
||||||
array.Add(arrayItem);
|
jArray.Add(arrayItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (schema.AllOf?.Count > 0)
|
if (schema.AllOf.Count > 0)
|
||||||
{
|
{
|
||||||
array.Add(MapSchemaAllOfToObject(schema));
|
jArray.Add(MapSchemaAllOfToObject(schema));
|
||||||
}
|
}
|
||||||
|
|
||||||
return array;
|
return jArray;
|
||||||
|
|
||||||
case JsonSchemaType.Boolean:
|
case SchemaType.Boolean:
|
||||||
case JsonSchemaType.Integer:
|
case SchemaType.Integer:
|
||||||
case JsonSchemaType.Number:
|
case SchemaType.Number:
|
||||||
case JsonSchemaType.String:
|
case SchemaType.String:
|
||||||
return _exampleValueGenerator.GetExampleValue(schema);
|
return _exampleValueGenerator.GetExampleValue(schema);
|
||||||
|
|
||||||
case JsonSchemaType.Object:
|
case SchemaType.Object:
|
||||||
var propertyAsJsonObject = new JsonObject();
|
var propertyAsJObject = new JObject();
|
||||||
foreach (var schemaProperty in schema.Properties ?? new Dictionary<string, IOpenApiSchema>())
|
foreach (var schemaProperty in schema.Properties)
|
||||||
{
|
{
|
||||||
propertyAsJsonObject[schemaProperty.Key] = MapPropertyAsJsonNode(schemaProperty.Value);
|
propertyAsJObject.Add(MapPropertyAsJObject(schemaProperty.Value, schemaProperty.Key));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (schema.AllOf?.Count > 0)
|
if (schema.AllOf.Count > 0)
|
||||||
{
|
{
|
||||||
foreach (var group in schema.AllOf.SelectMany(p => p.Properties ?? new Dictionary<string, IOpenApiSchema>()).GroupBy(x => x.Key))
|
foreach (var group in schema.AllOf.SelectMany(p => p.Properties).GroupBy(x => x.Key))
|
||||||
{
|
{
|
||||||
propertyAsJsonObject[group.Key] = MapPropertyAsJsonNode(group.First().Value);
|
propertyAsJObject.Add(MapPropertyAsJObject(group.First().Value, group.Key));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return propertyAsJsonObject;
|
return name != null ? new JProperty(name, propertyAsJObject) : propertyAsJObject;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private JsonObject MapSchemaAllOfToObject(IOpenApiSchema schema)
|
private JObject MapSchemaAllOfToObject(OpenApiSchema schema)
|
||||||
{
|
{
|
||||||
var arrayItem = new JsonObject();
|
var arrayItem = new JObject();
|
||||||
foreach (var property in schema.AllOf ?? [])
|
foreach (var property in schema.AllOf)
|
||||||
{
|
{
|
||||||
foreach (var item in property.Properties ?? new Dictionary<string, IOpenApiSchema>())
|
foreach (var item in property.Properties)
|
||||||
{
|
{
|
||||||
arrayItem[item.Key] = MapPropertyAsJsonNode(item.Value);
|
arrayItem.Add(MapPropertyAsJObject(item.Value, item.Key));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return arrayItem;
|
return arrayItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
private JsonNode? MapPropertyAsJsonNode(IOpenApiSchema openApiSchema)
|
private object MapPropertyAsJObject(OpenApiSchema openApiSchema, string key)
|
||||||
{
|
{
|
||||||
var schemaType = openApiSchema.GetSchemaType(out _);
|
if (openApiSchema.GetSchemaType() == SchemaType.Object || openApiSchema.GetSchemaType() == SchemaType.Array)
|
||||||
if (schemaType is JsonSchemaType.Object or JsonSchemaType.Array)
|
|
||||||
{
|
{
|
||||||
return MapSchemaToObject(openApiSchema);
|
var mapped = MapSchemaToObject(openApiSchema, key);
|
||||||
|
if (mapped is JProperty jp)
|
||||||
|
{
|
||||||
|
return jp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new JProperty(key, mapped);
|
||||||
}
|
}
|
||||||
|
|
||||||
return _exampleValueGenerator.GetExampleValue(openApiSchema);
|
// bool propertyIsNullable = openApiSchema.Nullable || (openApiSchema.TryGetXNullable(out bool x) && x);
|
||||||
|
return new JProperty(key, _exampleValueGenerator.GetExampleValue(openApiSchema));
|
||||||
}
|
}
|
||||||
|
|
||||||
private string MapPathWithParameters(string path, IEnumerable<IOpenApiParameter>? parameters)
|
private string MapPathWithParameters(string path, IEnumerable<OpenApiParameter>? parameters)
|
||||||
{
|
{
|
||||||
if (parameters == null)
|
if (parameters == null)
|
||||||
{
|
{
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
var newPath = path;
|
string newPath = path;
|
||||||
foreach (var parameter in parameters)
|
foreach (var parameter in parameters)
|
||||||
{
|
{
|
||||||
var exampleMatcherModel = GetExampleMatcherModel(parameter.Schema, _settings.PathPatternToUse);
|
var exampleMatcherModel = GetExampleMatcherModel(parameter.Schema, _settings.PathPatternToUse);
|
||||||
@@ -249,56 +280,93 @@ internal class OpenApiPathsMapper
|
|||||||
return newPath;
|
return newPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IDictionary<string, object>? MapHeaders(string? responseContentType, IDictionary<string, IOpenApiHeader>? headers)
|
private string MapBasePath(IList<OpenApiServer>? servers)
|
||||||
{
|
{
|
||||||
var mappedHeaders = headers?
|
if (servers == null || servers.Count == 0)
|
||||||
.ToDictionary(item => item.Key, _ => GetExampleMatcherModel(null, _settings.HeaderPatternToUse).Pattern!) ?? new Dictionary<string, object>();
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenApiServer server = servers.First();
|
||||||
|
if (Uri.TryCreate(server.Url, UriKind.RelativeOrAbsolute, out Uri uriResult))
|
||||||
|
{
|
||||||
|
return uriResult.IsAbsoluteUri ? uriResult.AbsolutePath : uriResult.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
private JToken? MapOpenApiAnyToJToken(IOpenApiAny? any)
|
||||||
|
{
|
||||||
|
if (any == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
using var outputString = new StringWriter();
|
||||||
|
var writer = new OpenApiJsonWriter(outputString);
|
||||||
|
any.Write(writer, OpenApiSpecVersion.OpenApi3_0);
|
||||||
|
|
||||||
|
if (any.AnyType == AnyType.Array)
|
||||||
|
{
|
||||||
|
return JArray.Parse(outputString.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return JObject.Parse(outputString.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private IDictionary<string, object>? MapHeaders(string? responseContentType, IDictionary<string, OpenApiHeader>? headers)
|
||||||
|
{
|
||||||
|
var mappedHeaders = headers?.ToDictionary(
|
||||||
|
item => item.Key,
|
||||||
|
_ => GetExampleMatcherModel(null, _settings.HeaderPatternToUse).Pattern!
|
||||||
|
) ?? new Dictionary<string, object>();
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(responseContentType))
|
if (!string.IsNullOrEmpty(responseContentType))
|
||||||
{
|
{
|
||||||
mappedHeaders.TryAdd(HeaderContentType, responseContentType);
|
mappedHeaders.TryAdd(HeaderContentType, responseContentType!);
|
||||||
}
|
}
|
||||||
|
|
||||||
return mappedHeaders.Keys.Any() ? mappedHeaders : null;
|
return mappedHeaders.Keys.Any() ? mappedHeaders : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IList<ParamModel>? MapQueryParameters(IEnumerable<IOpenApiParameter> queryParameters)
|
private IList<ParamModel>? MapQueryParameters(IEnumerable<OpenApiParameter> queryParameters)
|
||||||
{
|
{
|
||||||
var list = queryParameters
|
var list = queryParameters
|
||||||
.Where(req => req.Required)
|
.Where(req => req.Required)
|
||||||
.Select(qp => new ParamModel
|
.Select(qp => new ParamModel
|
||||||
{
|
{
|
||||||
Name = qp.Name ?? string.Empty,
|
Name = qp.Name,
|
||||||
IgnoreCase = _settings.QueryParameterPatternIgnoreCase,
|
IgnoreCase = _settings.QueryParameterPatternIgnoreCase,
|
||||||
Matchers =
|
Matchers = new[]
|
||||||
[
|
{
|
||||||
GetExampleMatcherModel(qp.Schema, _settings.QueryParameterPatternToUse)
|
GetExampleMatcherModel(qp.Schema, _settings.QueryParameterPatternToUse)
|
||||||
]
|
}
|
||||||
})
|
})
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
return list.Any() ? list : null;
|
return list.Any() ? list : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IList<HeaderModel>? MapRequestHeaders(IEnumerable<IOpenApiParameter> headers)
|
private IList<HeaderModel>? MapRequestHeaders(IEnumerable<OpenApiParameter> headers)
|
||||||
{
|
{
|
||||||
var list = headers
|
var list = headers
|
||||||
.Where(req => req.Required)
|
.Where(req => req.Required)
|
||||||
.Select(qp => new HeaderModel
|
.Select(qp => new HeaderModel
|
||||||
{
|
{
|
||||||
Name = qp.Name ?? string.Empty,
|
Name = qp.Name,
|
||||||
IgnoreCase = _settings.HeaderPatternIgnoreCase,
|
IgnoreCase = _settings.HeaderPatternIgnoreCase,
|
||||||
Matchers =
|
Matchers = new[]
|
||||||
[
|
{
|
||||||
GetExampleMatcherModel(qp.Schema, _settings.HeaderPatternToUse)
|
GetExampleMatcherModel(qp.Schema, _settings.HeaderPatternToUse)
|
||||||
]
|
}
|
||||||
})
|
})
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
return list.Any() ? list : null;
|
return list.Any() ? list : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private MatcherModel GetExampleMatcherModel(IOpenApiSchema? schema, ExampleValueType type)
|
private MatcherModel GetExampleMatcherModel(OpenApiSchema? schema, ExampleValueType type)
|
||||||
{
|
{
|
||||||
return type switch
|
return type switch
|
||||||
{
|
{
|
||||||
@@ -317,31 +385,15 @@ internal class OpenApiPathsMapper
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetExampleValueAsStringForSchemaType(IOpenApiSchema? schema)
|
private string GetExampleValueAsStringForSchemaType(OpenApiSchema? schema)
|
||||||
{
|
{
|
||||||
var value = _exampleValueGenerator.GetExampleValue(schema);
|
var value = _exampleValueGenerator.GetExampleValue(schema);
|
||||||
|
|
||||||
if (value.GetValueKind() == JsonValueKind.String)
|
return value switch
|
||||||
{
|
{
|
||||||
return value.GetValue<string>();
|
string valueAsString => valueAsString,
|
||||||
}
|
|
||||||
|
|
||||||
return value.ToString();
|
_ => value.ToString(),
|
||||||
}
|
};
|
||||||
|
|
||||||
private static string MapBasePath(IList<OpenApiServer>? servers)
|
|
||||||
{
|
|
||||||
var server = servers?.FirstOrDefault();
|
|
||||||
if (server == null)
|
|
||||||
{
|
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Uri.TryCreate(server.Url, UriKind.RelativeOrAbsolute, out var uriResult))
|
|
||||||
{
|
|
||||||
return uriResult.IsAbsoluteUri ? uriResult.AbsolutePath : uriResult.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
return string.Empty;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using Microsoft.OpenApi.Models.Interfaces;
|
using Microsoft.OpenApi.Models;
|
||||||
|
|
||||||
namespace WireMock.Net.OpenApiParser.Settings;
|
namespace WireMock.Net.OpenApiParser.Settings;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An interface defining the example values to use for the different types.
|
/// A interface defining the example values to use for the different types.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IWireMockOpenApiParserExampleValues
|
public interface IWireMockOpenApiParserExampleValues
|
||||||
{
|
{
|
||||||
@@ -26,9 +26,9 @@ public interface IWireMockOpenApiParserExampleValues
|
|||||||
float Float { get; }
|
float Float { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An example value for a Decimal.
|
/// An example value for a Double.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
decimal Decimal { get; }
|
double Double { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An example value for a Date.
|
/// An example value for a Date.
|
||||||
@@ -58,5 +58,5 @@ public interface IWireMockOpenApiParserExampleValues
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// OpenApi Schema to generate dynamic examples more accurate
|
/// OpenApi Schema to generate dynamic examples more accurate
|
||||||
/// </summary>
|
/// </summary>
|
||||||
IOpenApiSchema? Schema { get; set; }
|
OpenApiSchema? Schema { get; set; }
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using Microsoft.OpenApi.Models.Interfaces;
|
using Microsoft.OpenApi.Models;
|
||||||
using RandomDataGenerator.FieldOptions;
|
using RandomDataGenerator.FieldOptions;
|
||||||
using RandomDataGenerator.Randomizers;
|
using RandomDataGenerator.Randomizers;
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ public class WireMockOpenApiParserDynamicExampleValues : IWireMockOpenApiParserE
|
|||||||
public virtual float Float => RandomizerFactory.GetRandomizer(new FieldOptionsFloat()).Generate() ?? 4.2f;
|
public virtual float Float => RandomizerFactory.GetRandomizer(new FieldOptionsFloat()).Generate() ?? 4.2f;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public virtual decimal Decimal => SafeConvertFloatToDecimal(RandomizerFactory.GetRandomizer(new FieldOptionsFloat()).Generate() ?? 4.2f);
|
public virtual double Double => RandomizerFactory.GetRandomizer(new FieldOptionsDouble()).Generate() ?? 4.2d;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public virtual Func<DateTime> Date => () => RandomizerFactory.GetRandomizer(new FieldOptionsDateTime()).Generate() ?? System.DateTime.UtcNow.Date;
|
public virtual Func<DateTime> Date => () => RandomizerFactory.GetRandomizer(new FieldOptionsDateTime()).Generate() ?? System.DateTime.UtcNow.Date;
|
||||||
@@ -40,20 +40,5 @@ public class WireMockOpenApiParserDynamicExampleValues : IWireMockOpenApiParserE
|
|||||||
public virtual string String => RandomizerFactory.GetRandomizer(new FieldOptionsTextRegex { Pattern = @"^[0-9]{2}[A-Z]{5}[0-9]{2}" }).Generate() ?? "example-string";
|
public virtual string String => RandomizerFactory.GetRandomizer(new FieldOptionsTextRegex { Pattern = @"^[0-9]{2}[A-Z]{5}[0-9]{2}" }).Generate() ?? "example-string";
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public virtual IOpenApiSchema? Schema { get; set; }
|
public virtual OpenApiSchema? Schema { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Safely converts a float to a decimal, ensuring the value stays within the bounds of a decimal.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value">The float value to convert.</param>
|
|
||||||
/// <returns>A decimal value within the valid range of a decimal.</returns>
|
|
||||||
private static decimal SafeConvertFloatToDecimal(float value)
|
|
||||||
{
|
|
||||||
return value switch
|
|
||||||
{
|
|
||||||
< (float)decimal.MinValue => decimal.MinValue,
|
|
||||||
> (float)decimal.MaxValue => decimal.MaxValue,
|
|
||||||
_ => (decimal)value
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using Microsoft.OpenApi.Models;
|
using Microsoft.OpenApi.Models;
|
||||||
using Microsoft.OpenApi.Models.Interfaces;
|
|
||||||
|
|
||||||
namespace WireMock.Net.OpenApiParser.Settings;
|
namespace WireMock.Net.OpenApiParser.Settings;
|
||||||
|
|
||||||
@@ -21,7 +20,7 @@ public class WireMockOpenApiParserExampleValues : IWireMockOpenApiParserExampleV
|
|||||||
public virtual float Float => 4.2f;
|
public virtual float Float => 4.2f;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public virtual decimal Decimal => 4.2m;
|
public virtual double Double => 4.2d;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public virtual Func<DateTime> Date { get; } = () => System.DateTime.UtcNow.Date;
|
public virtual Func<DateTime> Date { get; } = () => System.DateTime.UtcNow.Date;
|
||||||
@@ -30,7 +29,7 @@ public class WireMockOpenApiParserExampleValues : IWireMockOpenApiParserExampleV
|
|||||||
public virtual Func<DateTime> DateTime { get; } = () => System.DateTime.UtcNow;
|
public virtual Func<DateTime> DateTime { get; } = () => System.DateTime.UtcNow;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public virtual byte[] Bytes { get; } = [48, 49, 50];
|
public virtual byte[] Bytes { get; } = { 48, 49, 50 };
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public virtual object Object => "example-object";
|
public virtual object Object => "example-object";
|
||||||
@@ -39,5 +38,5 @@ public class WireMockOpenApiParserExampleValues : IWireMockOpenApiParserExampleV
|
|||||||
public virtual string String => "example-string";
|
public virtual string String => "example-string";
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public virtual IOpenApiSchema? Schema { get; set; } = new OpenApiSchema();
|
public virtual OpenApiSchema? Schema { get; set; } = new();
|
||||||
}
|
}
|
||||||
@@ -7,16 +7,13 @@ namespace WireMock.Net.OpenApiParser.Utils;
|
|||||||
|
|
||||||
internal static class DateTimeUtils
|
internal static class DateTimeUtils
|
||||||
{
|
{
|
||||||
private const string DateFormat = "yyyy-MM-dd";
|
|
||||||
private const string DateTimeFormat = "yyyy-MM-dd'T'HH:mm:ss.fffzzz";
|
|
||||||
|
|
||||||
public static string ToRfc3339DateTime(DateTime dateTime)
|
public static string ToRfc3339DateTime(DateTime dateTime)
|
||||||
{
|
{
|
||||||
return dateTime.ToString(DateTimeFormat, DateTimeFormatInfo.InvariantInfo);
|
return dateTime.ToString("yyyy-MM-dd'T'HH:mm:ss.fffzzz", DateTimeFormatInfo.InvariantInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string ToRfc3339Date(DateTime dateTime)
|
public static string ToRfc3339Date(DateTime dateTime)
|
||||||
{
|
{
|
||||||
return dateTime.ToString(DateFormat, DateTimeFormatInfo.InvariantInfo);
|
return dateTime.ToString("yyyy-MM-dd", DateTimeFormatInfo.InvariantInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
|
using System.Linq;
|
||||||
|
using Microsoft.OpenApi.Any;
|
||||||
|
using Microsoft.OpenApi.Models;
|
||||||
|
using Stef.Validation;
|
||||||
|
using WireMock.Net.OpenApiParser.Extensions;
|
||||||
|
using WireMock.Net.OpenApiParser.Settings;
|
||||||
|
using WireMock.Net.OpenApiParser.Types;
|
||||||
|
|
||||||
|
namespace WireMock.Net.OpenApiParser.Utils;
|
||||||
|
|
||||||
|
internal class ExampleValueGenerator
|
||||||
|
{
|
||||||
|
private readonly IWireMockOpenApiParserExampleValues _exampleValues;
|
||||||
|
|
||||||
|
public ExampleValueGenerator(WireMockOpenApiParserSettings settings)
|
||||||
|
{
|
||||||
|
Guard.NotNull(settings);
|
||||||
|
|
||||||
|
// Check if user provided an own implementation
|
||||||
|
if (settings.ExampleValues is null)
|
||||||
|
{
|
||||||
|
if (settings.DynamicExamples)
|
||||||
|
{
|
||||||
|
_exampleValues = new WireMockOpenApiParserDynamicExampleValues();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_exampleValues = new WireMockOpenApiParserExampleValues();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_exampleValues = settings.ExampleValues;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public object GetExampleValue(OpenApiSchema? schema)
|
||||||
|
{
|
||||||
|
var schemaExample = schema?.Example;
|
||||||
|
var schemaEnum = schema?.Enum?.FirstOrDefault();
|
||||||
|
|
||||||
|
_exampleValues.Schema = schema;
|
||||||
|
|
||||||
|
switch (schema?.GetSchemaType())
|
||||||
|
{
|
||||||
|
case SchemaType.Boolean:
|
||||||
|
var exampleBoolean = schemaExample as OpenApiBoolean;
|
||||||
|
return exampleBoolean?.Value ?? _exampleValues.Boolean;
|
||||||
|
|
||||||
|
case SchemaType.Integer:
|
||||||
|
switch (schema?.GetSchemaFormat())
|
||||||
|
{
|
||||||
|
case SchemaFormat.Int64:
|
||||||
|
var exampleLong = schemaExample as OpenApiLong;
|
||||||
|
var enumLong = schemaEnum as OpenApiLong;
|
||||||
|
var valueLongEnumOrExample = enumLong?.Value ?? exampleLong?.Value;
|
||||||
|
return valueLongEnumOrExample ?? _exampleValues.Integer;
|
||||||
|
|
||||||
|
default:
|
||||||
|
var exampleInteger = schemaExample as OpenApiInteger;
|
||||||
|
var enumInteger = schemaEnum as OpenApiInteger;
|
||||||
|
var valueIntegerEnumOrExample = enumInteger?.Value ?? exampleInteger?.Value;
|
||||||
|
return valueIntegerEnumOrExample ?? _exampleValues.Integer;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SchemaType.Number:
|
||||||
|
switch (schema?.GetSchemaFormat())
|
||||||
|
{
|
||||||
|
case SchemaFormat.Float:
|
||||||
|
var exampleFloat = schemaExample as OpenApiFloat;
|
||||||
|
var enumFloat = schemaEnum as OpenApiFloat;
|
||||||
|
var valueFloatEnumOrExample = enumFloat?.Value ?? exampleFloat?.Value;
|
||||||
|
return valueFloatEnumOrExample ?? _exampleValues.Float;
|
||||||
|
|
||||||
|
default:
|
||||||
|
var exampleDouble = schemaExample as OpenApiDouble;
|
||||||
|
var enumDouble = schemaEnum as OpenApiDouble;
|
||||||
|
var valueDoubleEnumOrExample = enumDouble?.Value ?? exampleDouble?.Value;
|
||||||
|
return valueDoubleEnumOrExample ?? _exampleValues.Double;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
switch (schema?.GetSchemaFormat())
|
||||||
|
{
|
||||||
|
case SchemaFormat.Date:
|
||||||
|
var exampleDate = schemaExample as OpenApiDate;
|
||||||
|
var enumDate = schemaEnum as OpenApiDate;
|
||||||
|
var valueDateEnumOrExample = enumDate?.Value ?? exampleDate?.Value;
|
||||||
|
return DateTimeUtils.ToRfc3339Date(valueDateEnumOrExample ?? _exampleValues.Date());
|
||||||
|
|
||||||
|
case SchemaFormat.DateTime:
|
||||||
|
var exampleDateTime = schemaExample as OpenApiDateTime;
|
||||||
|
var enumDateTime = schemaEnum as OpenApiDateTime;
|
||||||
|
var valueDateTimeEnumOrExample = enumDateTime?.Value ?? exampleDateTime?.Value;
|
||||||
|
return DateTimeUtils.ToRfc3339DateTime(valueDateTimeEnumOrExample?.DateTime ?? _exampleValues.DateTime());
|
||||||
|
|
||||||
|
case SchemaFormat.Byte:
|
||||||
|
var exampleByte = schemaExample as OpenApiByte;
|
||||||
|
var enumByte = schemaEnum as OpenApiByte;
|
||||||
|
var valueByteEnumOrExample = enumByte?.Value ?? exampleByte?.Value;
|
||||||
|
return valueByteEnumOrExample ?? _exampleValues.Bytes;
|
||||||
|
|
||||||
|
case SchemaFormat.Binary:
|
||||||
|
var exampleBinary = schemaExample as OpenApiBinary;
|
||||||
|
var enumBinary = schemaEnum as OpenApiBinary;
|
||||||
|
var valueBinaryEnumOrExample = enumBinary?.Value ?? exampleBinary?.Value;
|
||||||
|
return valueBinaryEnumOrExample ?? _exampleValues.Object;
|
||||||
|
|
||||||
|
default:
|
||||||
|
var exampleString = schemaExample as OpenApiString;
|
||||||
|
var enumString = schemaEnum as OpenApiString;
|
||||||
|
var valueStringEnumOrExample = enumString?.Value ?? exampleString?.Value;
|
||||||
|
return valueStringEnumOrExample ?? _exampleValues.String;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Description>An OpenApi (swagger) parser to generate MappingModel or mapping.json file.</Description>
|
<Description>An OpenApi (swagger) parser to generate MappingModel or mapping.json file.</Description>
|
||||||
<TargetFrameworks>net47;netstandard2.0;netstandard2.1;net8.0</TargetFrameworks>
|
<TargetFrameworks>net46;netstandard2.0;netstandard2.1</TargetFrameworks>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<PackageTags>wiremock;openapi;OAS;raml;converter;parser;openapiparser</PackageTags>
|
<PackageTags>wiremock;openapi;OAS;raml;converter;parser;openapiparser</PackageTags>
|
||||||
<ProjectGuid>{E5B03EEF-822C-4295-952B-4479AD30082B}</ProjectGuid>
|
<ProjectGuid>{D3804228-91F4-4502-9595-39584E5AADAD}</ProjectGuid>
|
||||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||||
<CodeAnalysisRuleSet>../WireMock.Net/WireMock.Net.ruleset</CodeAnalysisRuleSet>
|
<CodeAnalysisRuleSet>../WireMock.Net/WireMock.Net.ruleset</CodeAnalysisRuleSet>
|
||||||
<SignAssembly>true</SignAssembly>
|
<SignAssembly>true</SignAssembly>
|
||||||
@@ -14,19 +14,18 @@
|
|||||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<!--
|
|
||||||
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
|
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
|
||||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
-->
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
|
<PackageReference Include="Microsoft.OpenApi.Readers" Version="1.2.3" />
|
||||||
<PackageReference Include="Nullable" Version="1.3.1">
|
<PackageReference Include="Nullable" Version="1.3.1">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="RamlToOpenApiConverter" Version="0.7.0" />
|
<PackageReference Include="RamlToOpenApiConverter" Version="0.6.1" />
|
||||||
<PackageReference Include="RandomDataGenerator.Net" Version="1.0.18" />
|
<PackageReference Include="RandomDataGenerator.Net" Version="1.0.18" />
|
||||||
<PackageReference Include="Stef.Validation" Version="0.1.1" />
|
<PackageReference Include="Stef.Validation" Version="0.1.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
@@ -6,8 +6,7 @@ using System.IO;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Microsoft.OpenApi.Models;
|
using Microsoft.OpenApi.Models;
|
||||||
using Microsoft.OpenApi.Reader;
|
using Microsoft.OpenApi.Readers;
|
||||||
using Microsoft.OpenApi.YamlReader;
|
|
||||||
using RamlToOpenApiConverter;
|
using RamlToOpenApiConverter;
|
||||||
using WireMock.Admin.Mappings;
|
using WireMock.Admin.Mappings;
|
||||||
using WireMock.Net.OpenApiParser.Mappers;
|
using WireMock.Net.OpenApiParser.Mappers;
|
||||||
@@ -20,7 +19,7 @@ namespace WireMock.Net.OpenApiParser;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class WireMockOpenApiParser : IWireMockOpenApiParser
|
public class WireMockOpenApiParser : IWireMockOpenApiParser
|
||||||
{
|
{
|
||||||
private static readonly OpenApiReaderSettings ReaderSettings = new();
|
private readonly OpenApiStreamReader _reader = new();
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
@@ -41,7 +40,8 @@ public class WireMockOpenApiParser : IWireMockOpenApiParser
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
document = Read(File.OpenRead(path), out diagnostic);
|
var reader = new OpenApiStreamReader();
|
||||||
|
document = reader.Read(File.OpenRead(path), out diagnostic);
|
||||||
}
|
}
|
||||||
|
|
||||||
return FromDocument(document, settings);
|
return FromDocument(document, settings);
|
||||||
@@ -51,21 +51,21 @@ public class WireMockOpenApiParser : IWireMockOpenApiParser
|
|||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
public IReadOnlyList<MappingModel> FromDocument(OpenApiDocument document, WireMockOpenApiParserSettings? settings = null)
|
public IReadOnlyList<MappingModel> FromDocument(OpenApiDocument document, WireMockOpenApiParserSettings? settings = null)
|
||||||
{
|
{
|
||||||
return new OpenApiPathsMapper(settings ?? new WireMockOpenApiParserSettings()).ToMappingModels(document.Paths, document.Servers ?? []);
|
return new OpenApiPathsMapper(settings ?? new WireMockOpenApiParserSettings()).ToMappingModels(document.Paths, document.Servers);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
public IReadOnlyList<MappingModel> FromStream(Stream stream, out OpenApiDiagnostic diagnostic)
|
public IReadOnlyList<MappingModel> FromStream(Stream stream, out OpenApiDiagnostic diagnostic)
|
||||||
{
|
{
|
||||||
return FromDocument(Read(stream, out diagnostic));
|
return FromDocument(_reader.Read(stream, out diagnostic));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
public IReadOnlyList<MappingModel> FromStream(Stream stream, WireMockOpenApiParserSettings settings, out OpenApiDiagnostic diagnostic)
|
public IReadOnlyList<MappingModel> FromStream(Stream stream, WireMockOpenApiParserSettings settings, out OpenApiDiagnostic diagnostic)
|
||||||
{
|
{
|
||||||
return FromDocument(Read(stream, out diagnostic), settings);
|
return FromDocument(_reader.Read(stream, out diagnostic), settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -81,27 +81,4 @@ public class WireMockOpenApiParser : IWireMockOpenApiParser
|
|||||||
{
|
{
|
||||||
return FromStream(new MemoryStream(Encoding.UTF8.GetBytes(text)), settings, out diagnostic);
|
return FromStream(new MemoryStream(Encoding.UTF8.GetBytes(text)), settings, out diagnostic);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static OpenApiDocument Read(Stream stream, out OpenApiDiagnostic diagnostic)
|
|
||||||
{
|
|
||||||
var reader = new OpenApiYamlReader();
|
|
||||||
|
|
||||||
if (stream is not MemoryStream memoryStream)
|
|
||||||
{
|
|
||||||
memoryStream = ReadStreamIntoMemoryStream(stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
var result = reader.Read(memoryStream, ReaderSettings);
|
|
||||||
|
|
||||||
diagnostic = result.Diagnostic ?? new OpenApiDiagnostic();
|
|
||||||
return result.Document ?? throw new InvalidOperationException("The document is null.");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static MemoryStream ReadStreamIntoMemoryStream(Stream stream)
|
|
||||||
{
|
|
||||||
var memoryStream = new MemoryStream();
|
|
||||||
stream.CopyTo(memoryStream);
|
|
||||||
memoryStream.Position = 0;
|
|
||||||
return memoryStream;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
// Copyright © WireMock.Net
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text.Json.Nodes;
|
|
||||||
using Microsoft.OpenApi.Models;
|
|
||||||
using Microsoft.OpenApi.Models.Interfaces;
|
|
||||||
using Stef.Validation;
|
|
||||||
using WireMock.Net.OpenApiParser.Extensions;
|
|
||||||
using WireMock.Net.OpenApiParser.Settings;
|
|
||||||
using WireMock.Net.OpenApiParser.Types;
|
|
||||||
|
|
||||||
namespace WireMock.Net.OpenApiParser.Utils;
|
|
||||||
|
|
||||||
internal class ExampleValueGenerator
|
|
||||||
{
|
|
||||||
private readonly IWireMockOpenApiParserExampleValues _exampleValues;
|
|
||||||
|
|
||||||
public ExampleValueGenerator(WireMockOpenApiParserSettings settings)
|
|
||||||
{
|
|
||||||
Guard.NotNull(settings);
|
|
||||||
|
|
||||||
// Check if user provided an own implementation
|
|
||||||
if (settings.ExampleValues is null)
|
|
||||||
{
|
|
||||||
if (settings.DynamicExamples)
|
|
||||||
{
|
|
||||||
_exampleValues = new WireMockOpenApiParserDynamicExampleValues();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_exampleValues = new WireMockOpenApiParserExampleValues();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_exampleValues = settings.ExampleValues;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public JsonNode GetExampleValue(IOpenApiSchema? schema)
|
|
||||||
{
|
|
||||||
var schemaExample = schema?.Example;
|
|
||||||
var schemaEnum = schema?.Enum?.FirstOrDefault();
|
|
||||||
|
|
||||||
_exampleValues.Schema = schema;
|
|
||||||
|
|
||||||
switch (schema?.GetSchemaType(out _))
|
|
||||||
{
|
|
||||||
case JsonSchemaType.Boolean:
|
|
||||||
var exampleBoolean = schemaExample?.GetValue<bool>();
|
|
||||||
return exampleBoolean ?? _exampleValues.Boolean;
|
|
||||||
|
|
||||||
case JsonSchemaType.Integer:
|
|
||||||
var exampleInteger = schemaExample?.GetValue<decimal>();
|
|
||||||
var enumInteger = schemaEnum?.GetValue<decimal>();
|
|
||||||
var valueIntegerEnumOrExample = enumInteger ?? exampleInteger;
|
|
||||||
return valueIntegerEnumOrExample ?? _exampleValues.Integer;
|
|
||||||
|
|
||||||
case JsonSchemaType.Number:
|
|
||||||
switch (schema.GetSchemaFormat())
|
|
||||||
{
|
|
||||||
case SchemaFormat.Float:
|
|
||||||
var exampleFloat = schemaExample?.GetValue<float>();
|
|
||||||
var enumFloat = schemaEnum?.GetValue<float>();
|
|
||||||
var valueFloatEnumOrExample = enumFloat ?? exampleFloat;
|
|
||||||
return valueFloatEnumOrExample ?? _exampleValues.Float;
|
|
||||||
|
|
||||||
default:
|
|
||||||
var exampleDecimal = schemaExample?.GetValue<decimal>();
|
|
||||||
var enumDecimal = schemaEnum?.GetValue<decimal>();
|
|
||||||
var valueDecimalEnumOrExample = enumDecimal ?? exampleDecimal;
|
|
||||||
return valueDecimalEnumOrExample ?? _exampleValues.Decimal;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
switch (schema?.GetSchemaFormat())
|
|
||||||
{
|
|
||||||
case SchemaFormat.Date:
|
|
||||||
var exampleDate = schemaExample?.GetValue<string>();
|
|
||||||
var enumDate = schemaEnum?.GetValue<string>();
|
|
||||||
var valueDateEnumOrExample = enumDate ?? exampleDate;
|
|
||||||
return valueDateEnumOrExample ?? DateTimeUtils.ToRfc3339Date(_exampleValues.Date());
|
|
||||||
|
|
||||||
case SchemaFormat.DateTime:
|
|
||||||
var exampleDateTime = schemaExample?.GetValue<string>();
|
|
||||||
var enumDateTime = schemaEnum?.GetValue<string>();
|
|
||||||
var valueDateTimeEnumOrExample = enumDateTime ?? exampleDateTime;
|
|
||||||
return valueDateTimeEnumOrExample ?? DateTimeUtils.ToRfc3339DateTime(_exampleValues.DateTime());
|
|
||||||
|
|
||||||
case SchemaFormat.Byte:
|
|
||||||
var exampleByte = schemaExample?.GetValue<byte[]>();
|
|
||||||
var enumByte = schemaEnum?.GetValue<byte[]>();
|
|
||||||
var valueByteEnumOrExample = enumByte ?? exampleByte;
|
|
||||||
return Convert.ToBase64String(valueByteEnumOrExample ?? _exampleValues.Bytes);
|
|
||||||
|
|
||||||
default:
|
|
||||||
var exampleString = schemaExample?.GetValue<string>();
|
|
||||||
var enumString = schemaEnum?.GetValue<string>();
|
|
||||||
var valueStringEnumOrExample = enumString ?? exampleString;
|
|
||||||
return valueStringEnumOrExample ?? _exampleValues.String;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
#if NET46 || NETSTANDARD2_0
|
#if NET46 || NET47 || NETSTANDARD2_0
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace WireMock.Net.OpenApiParser.Extensions;
|
namespace WireMock.Net.OpenApiParser.Extensions;
|
||||||
|
|||||||
@@ -1,60 +1,62 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.OpenApi.Any;
|
using System.Reflection;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Nodes;
|
||||||
using Microsoft.OpenApi.Interfaces;
|
using Microsoft.OpenApi.Interfaces;
|
||||||
using Microsoft.OpenApi.Models;
|
using Microsoft.OpenApi.Models;
|
||||||
|
using Microsoft.OpenApi.Models.Interfaces;
|
||||||
using WireMock.Net.OpenApiParser.Types;
|
using WireMock.Net.OpenApiParser.Types;
|
||||||
|
|
||||||
namespace WireMock.Net.OpenApiParser.Extensions;
|
namespace WireMock.Net.OpenApiParser.Extensions;
|
||||||
|
|
||||||
internal static class OpenApiSchemaExtensions
|
internal static class OpenApiSchemaExtensions
|
||||||
{
|
{
|
||||||
/// <summary>
|
public static bool TryGetXNullable(this IOpenApiSchema schema, out bool value)
|
||||||
/// https://stackoverflow.com/questions/48111459/how-to-define-a-property-that-can-be-string-or-null-in-openapi-swagger
|
|
||||||
/// </summary>
|
|
||||||
public static bool TryGetXNullable(this OpenApiSchema schema, out bool value)
|
|
||||||
{
|
{
|
||||||
value = false;
|
value = false;
|
||||||
|
|
||||||
if (schema.Extensions.TryGetValue("x-nullable", out var e) && e is OpenApiBoolean openApiBoolean)
|
#pragma warning disable S3011
|
||||||
|
var extensionsProperty = schema.GetType().GetProperty("Extensions", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||||
|
#pragma warning restore S3011
|
||||||
|
if (extensionsProperty?.GetValue(schema) is Dictionary<string, IOpenApiExtension> extensions && extensions.TryGetValue("x-nullable", out var nullExtRawValue))
|
||||||
{
|
{
|
||||||
value = openApiBoolean.Value;
|
var nodeProperty = nullExtRawValue.GetType().GetProperty("Node", BindingFlags.Instance | BindingFlags.Public);
|
||||||
return true;
|
if (nodeProperty?.GetValue(nullExtRawValue) is JsonNode jsonNode)
|
||||||
|
{
|
||||||
|
return jsonNode.GetValueKind() == JsonValueKind.True;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SchemaType GetSchemaType(this OpenApiSchema? schema)
|
public static JsonSchemaType? GetSchemaType(this IOpenApiSchema? schema, out bool isNullable)
|
||||||
{
|
{
|
||||||
|
isNullable = false;
|
||||||
|
|
||||||
if (schema == null)
|
if (schema == null)
|
||||||
{
|
{
|
||||||
return SchemaType.Unknown;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (schema.Type == null)
|
if (schema.Type == null)
|
||||||
{
|
{
|
||||||
if (schema.AllOf.Any() || schema.AnyOf.Any())
|
if (schema.AllOf?.Any() == true || schema.AnyOf?.Any() == true)
|
||||||
{
|
{
|
||||||
return SchemaType.Object;
|
return JsonSchemaType.Object;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return schema.Type switch
|
isNullable = (schema.Type | JsonSchemaType.Null) == JsonSchemaType.Null || (schema.TryGetXNullable(out var xNullable) && xNullable);
|
||||||
{
|
|
||||||
"object" => SchemaType.Object,
|
// Removes the Null flag from the schema.Type, ensuring the returned value represents a non-nullable type.
|
||||||
"array" => SchemaType.Array,
|
return schema.Type & ~JsonSchemaType.Null;
|
||||||
"integer" => SchemaType.Integer,
|
|
||||||
"number" => SchemaType.Number,
|
|
||||||
"boolean" => SchemaType.Boolean,
|
|
||||||
"string" => SchemaType.String,
|
|
||||||
"file" => SchemaType.File,
|
|
||||||
_ => SchemaType.Unknown
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SchemaFormat GetSchemaFormat(this OpenApiSchema? schema)
|
public static SchemaFormat GetSchemaFormat(this IOpenApiSchema? schema)
|
||||||
{
|
{
|
||||||
switch (schema?.Format)
|
switch (schema?.Format)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,9 +3,8 @@
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Microsoft.OpenApi.Models;
|
|
||||||
using Microsoft.OpenApi.Readers;
|
|
||||||
using Stef.Validation;
|
using Stef.Validation;
|
||||||
|
using WireMock.Net.OpenApiParser.Models;
|
||||||
using WireMock.Net.OpenApiParser.Settings;
|
using WireMock.Net.OpenApiParser.Settings;
|
||||||
using WireMock.Server;
|
using WireMock.Server;
|
||||||
|
|
||||||
@@ -17,7 +16,7 @@ namespace WireMock.Net.OpenApiParser.Extensions;
|
|||||||
public static class WireMockServerExtensions
|
public static class WireMockServerExtensions
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Register the mappings via an OpenAPI (swagger) V2 or V3 file.
|
/// Register the mappings via an OpenAPI (swagger) V2/V3/V3.1 file.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="server">The WireMockServer instance</param>
|
/// <param name="server">The WireMockServer instance</param>
|
||||||
/// <param name="path">Path containing OpenAPI file to parse and use the mappings.</param>
|
/// <param name="path">Path containing OpenAPI file to parse and use the mappings.</param>
|
||||||
@@ -29,7 +28,7 @@ public static class WireMockServerExtensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Register the mappings via an OpenAPI (swagger) V2 or V3 file.
|
/// Register the mappings via an OpenAPI (swagger) V2/V3/V3.1 file.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="server">The WireMockServer instance</param>
|
/// <param name="server">The WireMockServer instance</param>
|
||||||
/// <param name="path">Path containing OpenAPI file to parse and use the mappings.</param>
|
/// <param name="path">Path containing OpenAPI file to parse and use the mappings.</param>
|
||||||
@@ -47,7 +46,7 @@ public static class WireMockServerExtensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Register the mappings via an OpenAPI (swagger) V2 or V3 stream.
|
/// Register the mappings via an OpenAPI (swagger) V2/V3/V3.1 stream.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="server">The WireMockServer instance</param>
|
/// <param name="server">The WireMockServer instance</param>
|
||||||
/// <param name="stream">Stream containing OpenAPI description to parse and use the mappings.</param>
|
/// <param name="stream">Stream containing OpenAPI description to parse and use the mappings.</param>
|
||||||
@@ -59,7 +58,7 @@ public static class WireMockServerExtensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Register the mappings via an OpenAPI (swagger) V2 or V3 stream.
|
/// Register the mappings via an OpenAPI (swagger) V2/V3/V3.1 stream.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="server">The WireMockServer instance</param>
|
/// <param name="server">The WireMockServer instance</param>
|
||||||
/// <param name="stream">Stream containing OpenAPI description to parse and use the mappings.</param>
|
/// <param name="stream">Stream containing OpenAPI description to parse and use the mappings.</param>
|
||||||
@@ -78,13 +77,13 @@ public static class WireMockServerExtensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Register the mappings via an OpenAPI (swagger) V2 or V3 document.
|
/// Register the mappings via an OpenAPI (swagger) V2/V3/V3.1 document.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="server">The WireMockServer instance</param>
|
/// <param name="server">The WireMockServer instance</param>
|
||||||
/// <param name="document">The OpenAPI document to use as mappings.</param>
|
/// <param name="document">The OpenAPI document to use as mappings.</param>
|
||||||
/// <param name="settings">Additional settings [optional].</param>
|
/// <param name="settings">Additional settings [optional].</param>
|
||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
public static IWireMockServer WithMappingFromOpenApiDocument(this IWireMockServer server, OpenApiDocument document, WireMockOpenApiParserSettings? settings = null)
|
public static IWireMockServer WithMappingFromOpenApiDocument(this IWireMockServer server, object document, WireMockOpenApiParserSettings? settings = null)
|
||||||
{
|
{
|
||||||
Guard.NotNull(server);
|
Guard.NotNull(server);
|
||||||
Guard.NotNull(document);
|
Guard.NotNull(document);
|
||||||
|
|||||||
29
src/WireMock.Net.OpenApiParser/ILRepack.targets
Normal file
29
src/WireMock.Net.OpenApiParser/ILRepack.targets
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
|
||||||
|
<!-- See also https://github.com/ravibpatel/ILRepack.Lib.MSBuild.Task/issues/26 -->
|
||||||
|
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Target Name="ILRepacker" AfterTargets="Build" Condition="'$(Configuration)' == 'Release'">
|
||||||
|
<ItemGroup>
|
||||||
|
<InputAssemblies Include="$(OutputPath)WireMock.Net.OpenApiParser.dll" />
|
||||||
|
<InputAssemblies Include="@(ReferencePathWithRefAssemblies)" Condition="'%(filename)' == 'Microsoft.OpenApi.YamlReader'" />
|
||||||
|
<InputAssemblies Include="@(ReferencePathWithRefAssemblies)" Condition="'%(filename)' == 'Microsoft.OpenApi'" />
|
||||||
|
<LibraryPath Include="%(ReferencePathWithRefAssemblies.RelativeDir)" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<DoNotInternalizeAssemblies Include="WireMock.Net.OpenApiParser" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ILRepack
|
||||||
|
Parallel="true"
|
||||||
|
Internalize="true"
|
||||||
|
RenameInternalized="true"
|
||||||
|
InternalizeExclude="@(DoNotInternalizeAssemblies)"
|
||||||
|
InputAssemblies="@(InputAssemblies)"
|
||||||
|
LibraryPath="@(LibraryPath)"
|
||||||
|
TargetKind="Dll"
|
||||||
|
KeyFile="../../src/WireMock.Net/WireMock.Net.snk"
|
||||||
|
OutputFile="$(OutputPath)$(AssemblyName).dll"
|
||||||
|
/>
|
||||||
|
</Target>
|
||||||
|
</Project>
|
||||||
@@ -2,9 +2,8 @@
|
|||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Microsoft.OpenApi.Models;
|
|
||||||
using Microsoft.OpenApi.Readers;
|
|
||||||
using WireMock.Admin.Mappings;
|
using WireMock.Admin.Mappings;
|
||||||
|
using WireMock.Net.OpenApiParser.Models;
|
||||||
using WireMock.Net.OpenApiParser.Settings;
|
using WireMock.Net.OpenApiParser.Settings;
|
||||||
|
|
||||||
namespace WireMock.Net.OpenApiParser;
|
namespace WireMock.Net.OpenApiParser;
|
||||||
@@ -17,7 +16,7 @@ public interface IWireMockOpenApiParser
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generate <see cref="IReadOnlyList{MappingModel}"/> from a file-path.
|
/// Generate <see cref="IReadOnlyList{MappingModel}"/> from a file-path.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="path">The path to read the OpenApi/Swagger/V2/V3 or Raml file.</param>
|
/// <param name="path">The path to read the OpenApi/Swagger/V2/V3/V31 or Raml file.</param>
|
||||||
/// <param name="diagnostic">OpenApiDiagnostic output</param>
|
/// <param name="diagnostic">OpenApiDiagnostic output</param>
|
||||||
/// <returns>MappingModel</returns>
|
/// <returns>MappingModel</returns>
|
||||||
IReadOnlyList<MappingModel> FromFile(string path, out OpenApiDiagnostic diagnostic);
|
IReadOnlyList<MappingModel> FromFile(string path, out OpenApiDiagnostic diagnostic);
|
||||||
@@ -25,19 +24,19 @@ public interface IWireMockOpenApiParser
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generate <see cref="IReadOnlyList{MappingModel}"/> from a file-path.
|
/// Generate <see cref="IReadOnlyList{MappingModel}"/> from a file-path.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="path">The path to read the OpenApi/Swagger/V2/V3 or Raml file.</param>
|
/// <param name="path">The path to read the OpenApi/Swagger/V2/V3/V31 or Raml file.</param>
|
||||||
/// <param name="settings">Additional settings</param>
|
/// <param name="settings">Additional settings</param>
|
||||||
/// <param name="diagnostic">OpenApiDiagnostic output</param>
|
/// <param name="diagnostic">OpenApiDiagnostic output</param>
|
||||||
/// <returns>MappingModel</returns>
|
/// <returns>MappingModel</returns>
|
||||||
IReadOnlyList<MappingModel> FromFile(string path, WireMockOpenApiParserSettings settings, out OpenApiDiagnostic diagnostic);
|
IReadOnlyList<MappingModel> FromFile(string path, WireMockOpenApiParserSettings settings, out OpenApiDiagnostic diagnostic);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generate <see cref="IReadOnlyList{MappingModel}"/> from an <seealso cref="OpenApiDocument"/>.
|
/// Generate <see cref="IReadOnlyList{MappingModel}"/> from an Microsoft.OpenApi.Models.OpenApiDocument.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="document">The source OpenApiDocument</param>
|
/// <param name="document">The source OpenApiDocument</param>
|
||||||
/// <param name="settings">Additional settings [optional]</param>
|
/// <param name="settings">Additional settings [optional]</param>
|
||||||
/// <returns>MappingModel</returns>
|
/// <returns>MappingModel</returns>
|
||||||
IReadOnlyList<MappingModel> FromDocument(OpenApiDocument document, WireMockOpenApiParserSettings? settings = null);
|
IReadOnlyList<MappingModel> FromDocument(object document, WireMockOpenApiParserSettings? settings = null);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generate <see cref="IReadOnlyList{MappingModel}"/> from a <seealso cref="Stream"/>.
|
/// Generate <see cref="IReadOnlyList{MappingModel}"/> from a <seealso cref="Stream"/>.
|
||||||
|
|||||||
@@ -3,20 +3,19 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.OpenApi;
|
using System.Text.Json;
|
||||||
using Microsoft.OpenApi.Any;
|
using System.Text.Json.Nodes;
|
||||||
using Microsoft.OpenApi.Models;
|
using Microsoft.OpenApi.Models;
|
||||||
using Microsoft.OpenApi.Writers;
|
using Microsoft.OpenApi.Models.Interfaces;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
using Stef.Validation;
|
using Stef.Validation;
|
||||||
using WireMock.Admin.Mappings;
|
using WireMock.Admin.Mappings;
|
||||||
using WireMock.Net.OpenApiParser.Extensions;
|
using WireMock.Net.OpenApiParser.Extensions;
|
||||||
using WireMock.Net.OpenApiParser.Settings;
|
using WireMock.Net.OpenApiParser.Settings;
|
||||||
using WireMock.Net.OpenApiParser.Types;
|
using WireMock.Net.OpenApiParser.Types;
|
||||||
using WireMock.Net.OpenApiParser.Utils;
|
using WireMock.Net.OpenApiParser.Utils;
|
||||||
|
using SystemTextJsonSerializer = System.Text.Json.JsonSerializer;
|
||||||
|
|
||||||
namespace WireMock.Net.OpenApiParser.Mappers;
|
namespace WireMock.Net.OpenApiParser.Mappers;
|
||||||
|
|
||||||
@@ -39,56 +38,40 @@ internal class OpenApiPathsMapper
|
|||||||
.OrderBy(p => p.Key)
|
.OrderBy(p => p.Key)
|
||||||
.Select(p => MapPath(p.Key, p.Value, servers))
|
.Select(p => MapPath(p.Key, p.Value, servers))
|
||||||
.SelectMany(x => x)
|
.SelectMany(x => x)
|
||||||
.ToArray() ??
|
.ToArray() ?? [];
|
||||||
Array.Empty<MappingModel>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private IReadOnlyList<MappingModel> MapPaths(OpenApiPaths? paths, IList<OpenApiServer> servers)
|
private IReadOnlyList<MappingModel> MapPath(string path, IOpenApiPathItem pathItem, IList<OpenApiServer> servers)
|
||||||
{
|
{
|
||||||
return paths?
|
return pathItem.Operations?.Select(o => MapOperationToMappingModel(path, o.Key.ToString().ToUpperInvariant(), o.Value, servers)).ToArray() ?? [];
|
||||||
.OrderBy(p => p.Key)
|
|
||||||
.Select(p => MapPath(p.Key, p.Value, servers))
|
|
||||||
.SelectMany(x => x)
|
|
||||||
.ToArray() ??
|
|
||||||
Array.Empty<MappingModel>();
|
|
||||||
}
|
|
||||||
|
|
||||||
private IReadOnlyList<MappingModel> MapPath(string path, OpenApiPathItem pathItem, IList<OpenApiServer> servers)
|
|
||||||
{
|
|
||||||
return pathItem.Operations.Select(o => MapOperationToMappingModel(path, o.Key.ToString().ToUpperInvariant(), o.Value, servers)).ToArray();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private MappingModel MapOperationToMappingModel(string path, string httpMethod, OpenApiOperation operation, IList<OpenApiServer> servers)
|
private MappingModel MapOperationToMappingModel(string path, string httpMethod, OpenApiOperation operation, IList<OpenApiServer> servers)
|
||||||
{
|
{
|
||||||
var queryParameters = operation.Parameters.Where(p => p.In == ParameterLocation.Query);
|
var queryParameters = operation.Parameters?.Where(p => p.In == ParameterLocation.Query) ?? [];
|
||||||
var pathParameters = operation.Parameters.Where(p => p.In == ParameterLocation.Path);
|
var pathParameters = operation.Parameters?.Where(p => p.In == ParameterLocation.Path) ?? [];
|
||||||
var headers = operation.Parameters.Where(p => p.In == ParameterLocation.Header);
|
var headers = operation.Parameters?.Where(p => p.In == ParameterLocation.Header) ?? [];
|
||||||
|
|
||||||
var response = operation.Responses.FirstOrDefault();
|
var response = operation.Responses?.FirstOrDefault() ?? new KeyValuePair<string, IOpenApiResponse>();
|
||||||
|
|
||||||
TryGetContent(response.Value?.Content, out OpenApiMediaType? responseContent, out string? responseContentType);
|
TryGetContent(response.Value?.Content, out OpenApiMediaType? responseContent, out var responseContentType);
|
||||||
var responseSchema = response.Value?.Content?.FirstOrDefault().Value?.Schema;
|
var responseSchema = response.Value?.Content?.FirstOrDefault().Value?.Schema;
|
||||||
var responseExample = responseContent?.Example;
|
var responseExample = responseContent?.Example;
|
||||||
var responseSchemaExample = responseContent?.Schema?.Example;
|
var responseSchemaExample = responseContent?.Schema?.Example;
|
||||||
|
|
||||||
var body = responseExample != null ? MapOpenApiAnyToJToken(responseExample) :
|
var responseBody = responseExample ?? responseSchemaExample ?? MapSchemaToObject(responseSchema);
|
||||||
responseSchemaExample != null ? MapOpenApiAnyToJToken(responseSchemaExample) :
|
|
||||||
MapSchemaToObject(responseSchema);
|
|
||||||
|
|
||||||
var requestBodyModel = new BodyModel();
|
var requestBodyModel = new BodyModel();
|
||||||
if (operation.RequestBody != null && operation.RequestBody.Content != null && operation.RequestBody.Required)
|
if (operation.RequestBody != null && operation.RequestBody.Content != null && operation.RequestBody.Required)
|
||||||
{
|
{
|
||||||
var request = operation.RequestBody.Content;
|
var request = operation.RequestBody.Content;
|
||||||
TryGetContent(request, out OpenApiMediaType? requestContent, out _);
|
TryGetContent(request, out var requestContent, out _);
|
||||||
|
|
||||||
var requestBodySchema = operation.RequestBody.Content.First().Value?.Schema;
|
var requestBodySchema = operation.RequestBody.Content.First().Value?.Schema;
|
||||||
var requestBodyExample = requestContent!.Example;
|
var requestBodyExample = requestContent!.Example;
|
||||||
var requestBodySchemaExample = requestContent.Schema?.Example;
|
var requestBodySchemaExample = requestContent.Schema?.Example;
|
||||||
|
|
||||||
var requestBodyMapped = requestBodyExample != null ? MapOpenApiAnyToJToken(requestBodyExample) :
|
var requestBodyMapped = requestBodyExample ?? requestBodySchemaExample ?? MapSchemaToObject(requestBodySchema);
|
||||||
requestBodySchemaExample != null ? MapOpenApiAnyToJToken(requestBodySchemaExample) :
|
|
||||||
MapSchemaToObject(requestBodySchema);
|
|
||||||
|
|
||||||
requestBodyModel = MapRequestBody(requestBodyMapped);
|
requestBodyModel = MapRequestBody(requestBodyMapped);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,12 +95,12 @@ internal class OpenApiPathsMapper
|
|||||||
{
|
{
|
||||||
StatusCode = httpStatusCode,
|
StatusCode = httpStatusCode,
|
||||||
Headers = MapHeaders(responseContentType, response.Value?.Headers),
|
Headers = MapHeaders(responseContentType, response.Value?.Headers),
|
||||||
BodyAsJson = body
|
BodyAsJson = responseBody != null ? JsonConvert.DeserializeObject(SystemTextJsonSerializer.Serialize(responseBody)) : null
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private BodyModel? MapRequestBody(object? requestBody)
|
private BodyModel? MapRequestBody(JsonNode? requestBody)
|
||||||
{
|
{
|
||||||
if (requestBody == null)
|
if (requestBody == null)
|
||||||
{
|
{
|
||||||
@@ -129,7 +112,7 @@ internal class OpenApiPathsMapper
|
|||||||
Matcher = new MatcherModel
|
Matcher = new MatcherModel
|
||||||
{
|
{
|
||||||
Name = "JsonMatcher",
|
Name = "JsonMatcher",
|
||||||
Pattern = JsonConvert.SerializeObject(requestBody, Formatting.Indented),
|
Pattern = SystemTextJsonSerializer.Serialize(requestBody, new JsonSerializerOptions { WriteIndented = true }),
|
||||||
IgnoreCase = _settings.RequestBodyIgnoreCase
|
IgnoreCase = _settings.RequestBodyIgnoreCase
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -160,117 +143,103 @@ internal class OpenApiPathsMapper
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private object? MapSchemaToObject(OpenApiSchema? schema, string? name = null)
|
private JsonNode? MapSchemaToObject(IOpenApiSchema? schema)
|
||||||
{
|
{
|
||||||
if (schema == null)
|
if (schema == null)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (schema.GetSchemaType())
|
switch (schema.GetSchemaType(out _))
|
||||||
{
|
{
|
||||||
case SchemaType.Array:
|
case JsonSchemaType.Array:
|
||||||
var jArray = new JArray();
|
var array = new JsonArray();
|
||||||
for (int i = 0; i < _settings.NumberOfArrayItems; i++)
|
for (var i = 0; i < _settings.NumberOfArrayItems; i++)
|
||||||
{
|
{
|
||||||
if (schema.Items.Properties.Count > 0)
|
if (schema.Items?.Properties?.Count > 0)
|
||||||
{
|
{
|
||||||
var arrayItem = new JObject();
|
var item = new JsonObject();
|
||||||
foreach (var property in schema.Items.Properties)
|
foreach (var property in schema.Items.Properties)
|
||||||
{
|
{
|
||||||
var objectValue = MapSchemaToObject(property.Value, property.Key);
|
item[property.Key] = MapSchemaToObject(property.Value);
|
||||||
if (objectValue is JProperty jp)
|
|
||||||
{
|
|
||||||
arrayItem.Add(jp);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
arrayItem.Add(new JProperty(property.Key, objectValue));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
jArray.Add(arrayItem);
|
array.Add(item);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var arrayItem = MapSchemaToObject(schema.Items, name: null); // Set name to null to force JObject instead of JProperty
|
var arrayItem = MapSchemaToObject(schema.Items);
|
||||||
jArray.Add(arrayItem);
|
array.Add(arrayItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (schema.AllOf.Count > 0)
|
if (schema.AllOf?.Count > 0)
|
||||||
{
|
{
|
||||||
jArray.Add(MapSchemaAllOfToObject(schema));
|
array.Add(MapSchemaAllOfToObject(schema));
|
||||||
}
|
}
|
||||||
|
|
||||||
return jArray;
|
return array;
|
||||||
|
|
||||||
case SchemaType.Boolean:
|
case JsonSchemaType.Boolean:
|
||||||
case SchemaType.Integer:
|
case JsonSchemaType.Integer:
|
||||||
case SchemaType.Number:
|
case JsonSchemaType.Number:
|
||||||
case SchemaType.String:
|
case JsonSchemaType.String:
|
||||||
return _exampleValueGenerator.GetExampleValue(schema);
|
return _exampleValueGenerator.GetExampleValue(schema);
|
||||||
|
|
||||||
case SchemaType.Object:
|
case JsonSchemaType.Object:
|
||||||
var propertyAsJObject = new JObject();
|
var propertyAsJsonObject = new JsonObject();
|
||||||
foreach (var schemaProperty in schema.Properties)
|
foreach (var schemaProperty in schema.Properties ?? new Dictionary<string, IOpenApiSchema>())
|
||||||
{
|
{
|
||||||
propertyAsJObject.Add(MapPropertyAsJObject(schemaProperty.Value, schemaProperty.Key));
|
propertyAsJsonObject[schemaProperty.Key] = MapPropertyAsJsonNode(schemaProperty.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (schema.AllOf.Count > 0)
|
if (schema.AllOf?.Count > 0)
|
||||||
{
|
{
|
||||||
foreach (var group in schema.AllOf.SelectMany(p => p.Properties).GroupBy(x => x.Key))
|
foreach (var group in schema.AllOf.SelectMany(p => p.Properties ?? new Dictionary<string, IOpenApiSchema>()).GroupBy(x => x.Key))
|
||||||
{
|
{
|
||||||
propertyAsJObject.Add(MapPropertyAsJObject(group.First().Value, group.Key));
|
propertyAsJsonObject[group.Key] = MapPropertyAsJsonNode(group.First().Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return name != null ? new JProperty(name, propertyAsJObject) : propertyAsJObject;
|
return propertyAsJsonObject;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private JObject MapSchemaAllOfToObject(OpenApiSchema schema)
|
private JsonObject MapSchemaAllOfToObject(IOpenApiSchema schema)
|
||||||
{
|
{
|
||||||
var arrayItem = new JObject();
|
var arrayItem = new JsonObject();
|
||||||
foreach (var property in schema.AllOf)
|
foreach (var property in schema.AllOf ?? [])
|
||||||
{
|
{
|
||||||
foreach (var item in property.Properties)
|
foreach (var item in property.Properties ?? new Dictionary<string, IOpenApiSchema>())
|
||||||
{
|
{
|
||||||
arrayItem.Add(MapPropertyAsJObject(item.Value, item.Key));
|
arrayItem[item.Key] = MapPropertyAsJsonNode(item.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return arrayItem;
|
return arrayItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
private object MapPropertyAsJObject(OpenApiSchema openApiSchema, string key)
|
private JsonNode? MapPropertyAsJsonNode(IOpenApiSchema openApiSchema)
|
||||||
{
|
{
|
||||||
if (openApiSchema.GetSchemaType() == SchemaType.Object || openApiSchema.GetSchemaType() == SchemaType.Array)
|
var schemaType = openApiSchema.GetSchemaType(out _);
|
||||||
|
if (schemaType is JsonSchemaType.Object or JsonSchemaType.Array)
|
||||||
{
|
{
|
||||||
var mapped = MapSchemaToObject(openApiSchema, key);
|
return MapSchemaToObject(openApiSchema);
|
||||||
if (mapped is JProperty jp)
|
|
||||||
{
|
|
||||||
return jp;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new JProperty(key, mapped);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// bool propertyIsNullable = openApiSchema.Nullable || (openApiSchema.TryGetXNullable(out bool x) && x);
|
return _exampleValueGenerator.GetExampleValue(openApiSchema);
|
||||||
return new JProperty(key, _exampleValueGenerator.GetExampleValue(openApiSchema));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private string MapPathWithParameters(string path, IEnumerable<OpenApiParameter>? parameters)
|
private string MapPathWithParameters(string path, IEnumerable<IOpenApiParameter>? parameters)
|
||||||
{
|
{
|
||||||
if (parameters == null)
|
if (parameters == null)
|
||||||
{
|
{
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
string newPath = path;
|
var newPath = path;
|
||||||
foreach (var parameter in parameters)
|
foreach (var parameter in parameters)
|
||||||
{
|
{
|
||||||
var exampleMatcherModel = GetExampleMatcherModel(parameter.Schema, _settings.PathPatternToUse);
|
var exampleMatcherModel = GetExampleMatcherModel(parameter.Schema, _settings.PathPatternToUse);
|
||||||
@@ -280,93 +249,56 @@ internal class OpenApiPathsMapper
|
|||||||
return newPath;
|
return newPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string MapBasePath(IList<OpenApiServer>? servers)
|
private IDictionary<string, object>? MapHeaders(string? responseContentType, IDictionary<string, IOpenApiHeader>? headers)
|
||||||
{
|
{
|
||||||
if (servers == null || servers.Count == 0)
|
var mappedHeaders = headers?
|
||||||
{
|
.ToDictionary(item => item.Key, _ => GetExampleMatcherModel(null, _settings.HeaderPatternToUse).Pattern!) ?? new Dictionary<string, object>();
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
OpenApiServer server = servers.First();
|
|
||||||
if (Uri.TryCreate(server.Url, UriKind.RelativeOrAbsolute, out Uri uriResult))
|
|
||||||
{
|
|
||||||
return uriResult.IsAbsoluteUri ? uriResult.AbsolutePath : uriResult.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
private JToken? MapOpenApiAnyToJToken(IOpenApiAny? any)
|
|
||||||
{
|
|
||||||
if (any == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
using var outputString = new StringWriter();
|
|
||||||
var writer = new OpenApiJsonWriter(outputString);
|
|
||||||
any.Write(writer, OpenApiSpecVersion.OpenApi3_0);
|
|
||||||
|
|
||||||
if (any.AnyType == AnyType.Array)
|
|
||||||
{
|
|
||||||
return JArray.Parse(outputString.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
return JObject.Parse(outputString.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
private IDictionary<string, object>? MapHeaders(string? responseContentType, IDictionary<string, OpenApiHeader>? headers)
|
|
||||||
{
|
|
||||||
var mappedHeaders = headers?.ToDictionary(
|
|
||||||
item => item.Key,
|
|
||||||
_ => GetExampleMatcherModel(null, _settings.HeaderPatternToUse).Pattern!
|
|
||||||
) ?? new Dictionary<string, object>();
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(responseContentType))
|
if (!string.IsNullOrEmpty(responseContentType))
|
||||||
{
|
{
|
||||||
mappedHeaders.TryAdd(HeaderContentType, responseContentType!);
|
mappedHeaders.TryAdd(HeaderContentType, responseContentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
return mappedHeaders.Keys.Any() ? mappedHeaders : null;
|
return mappedHeaders.Keys.Any() ? mappedHeaders : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IList<ParamModel>? MapQueryParameters(IEnumerable<OpenApiParameter> queryParameters)
|
private IList<ParamModel>? MapQueryParameters(IEnumerable<IOpenApiParameter> queryParameters)
|
||||||
{
|
{
|
||||||
var list = queryParameters
|
var list = queryParameters
|
||||||
.Where(req => req.Required)
|
.Where(req => req.Required)
|
||||||
.Select(qp => new ParamModel
|
.Select(qp => new ParamModel
|
||||||
{
|
{
|
||||||
Name = qp.Name,
|
Name = qp.Name ?? string.Empty,
|
||||||
IgnoreCase = _settings.QueryParameterPatternIgnoreCase,
|
IgnoreCase = _settings.QueryParameterPatternIgnoreCase,
|
||||||
Matchers = new[]
|
Matchers =
|
||||||
{
|
[
|
||||||
GetExampleMatcherModel(qp.Schema, _settings.QueryParameterPatternToUse)
|
GetExampleMatcherModel(qp.Schema, _settings.QueryParameterPatternToUse)
|
||||||
}
|
]
|
||||||
})
|
})
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
return list.Any() ? list : null;
|
return list.Any() ? list : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IList<HeaderModel>? MapRequestHeaders(IEnumerable<OpenApiParameter> headers)
|
private IList<HeaderModel>? MapRequestHeaders(IEnumerable<IOpenApiParameter> headers)
|
||||||
{
|
{
|
||||||
var list = headers
|
var list = headers
|
||||||
.Where(req => req.Required)
|
.Where(req => req.Required)
|
||||||
.Select(qp => new HeaderModel
|
.Select(qp => new HeaderModel
|
||||||
{
|
{
|
||||||
Name = qp.Name,
|
Name = qp.Name ?? string.Empty,
|
||||||
IgnoreCase = _settings.HeaderPatternIgnoreCase,
|
IgnoreCase = _settings.HeaderPatternIgnoreCase,
|
||||||
Matchers = new[]
|
Matchers =
|
||||||
{
|
[
|
||||||
GetExampleMatcherModel(qp.Schema, _settings.HeaderPatternToUse)
|
GetExampleMatcherModel(qp.Schema, _settings.HeaderPatternToUse)
|
||||||
}
|
]
|
||||||
})
|
})
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
return list.Any() ? list : null;
|
return list.Any() ? list : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private MatcherModel GetExampleMatcherModel(OpenApiSchema? schema, ExampleValueType type)
|
private MatcherModel GetExampleMatcherModel(IOpenApiSchema? schema, ExampleValueType type)
|
||||||
{
|
{
|
||||||
return type switch
|
return type switch
|
||||||
{
|
{
|
||||||
@@ -385,15 +317,31 @@ internal class OpenApiPathsMapper
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetExampleValueAsStringForSchemaType(OpenApiSchema? schema)
|
private string GetExampleValueAsStringForSchemaType(IOpenApiSchema? schema)
|
||||||
{
|
{
|
||||||
var value = _exampleValueGenerator.GetExampleValue(schema);
|
var value = _exampleValueGenerator.GetExampleValue(schema);
|
||||||
|
|
||||||
return value switch
|
if (value.GetValueKind() == JsonValueKind.String)
|
||||||
{
|
{
|
||||||
string valueAsString => valueAsString,
|
return value.GetValue<string>();
|
||||||
|
}
|
||||||
|
|
||||||
_ => value.ToString(),
|
return value.ToString();
|
||||||
};
|
}
|
||||||
|
|
||||||
|
private static string MapBasePath(IList<OpenApiServer>? servers)
|
||||||
|
{
|
||||||
|
var server = servers?.FirstOrDefault();
|
||||||
|
if (server == null)
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Uri.TryCreate(server.Url, UriKind.RelativeOrAbsolute, out var uriResult))
|
||||||
|
{
|
||||||
|
return uriResult.IsAbsoluteUri ? uriResult.AbsolutePath : uriResult.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
28
src/WireMock.Net.OpenApiParser/Models/OpenApiDiagnostic.cs
Normal file
28
src/WireMock.Net.OpenApiParser/Models/OpenApiDiagnostic.cs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using RamlToOpenApiConverter;
|
||||||
|
|
||||||
|
namespace WireMock.Net.OpenApiParser.Models;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Object containing all diagnostic information related to Open API parsing.
|
||||||
|
/// </summary>
|
||||||
|
public class OpenApiDiagnostic
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// List of all errors.
|
||||||
|
/// </summary>
|
||||||
|
public List<OpenApiError> Errors { get; set; } = [];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// List of all warnings
|
||||||
|
/// </summary>
|
||||||
|
public List<OpenApiError> Warnings { get; set; } = [];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Open API specification version of the document parsed.
|
||||||
|
/// </summary>
|
||||||
|
public OpenApiSpecificationVersion SpecificationVersion { get; set; }
|
||||||
|
}
|
||||||
46
src/WireMock.Net.OpenApiParser/Models/OpenApiError.cs
Normal file
46
src/WireMock.Net.OpenApiParser/Models/OpenApiError.cs
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
namespace WireMock.Net.OpenApiParser.Models;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Error related to the Open API Document.
|
||||||
|
/// </summary>
|
||||||
|
public class OpenApiError
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes the <see cref="OpenApiError"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public OpenApiError(string? pointer, string message)
|
||||||
|
{
|
||||||
|
Pointer = pointer;
|
||||||
|
Message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a copy of an <see cref="OpenApiError"/> object
|
||||||
|
/// </summary>
|
||||||
|
public OpenApiError(OpenApiError error)
|
||||||
|
{
|
||||||
|
Pointer = error.Pointer;
|
||||||
|
Message = error.Message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Message explaining the error.
|
||||||
|
/// </summary>
|
||||||
|
public string Message { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Pointer to the location of the error.
|
||||||
|
/// </summary>
|
||||||
|
public string? Pointer { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the string representation of <see cref="OpenApiError"/>.
|
||||||
|
/// </summary>
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return Message + (!string.IsNullOrEmpty(Pointer) ? " [" + Pointer + "]" : "");
|
||||||
|
}
|
||||||
|
}
|
||||||
25
src/WireMock.Net.OpenApiParser/Models/OpenApiMapper.cs
Normal file
25
src/WireMock.Net.OpenApiParser/Models/OpenApiMapper.cs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
|
using System.Linq;
|
||||||
|
using RamlToOpenApiConverter;
|
||||||
|
using MicrosoftOpenApiDiagnostic = Microsoft.OpenApi.Reader.OpenApiDiagnostic;
|
||||||
|
|
||||||
|
namespace WireMock.Net.OpenApiParser.Models;
|
||||||
|
|
||||||
|
internal static class OpenApiMapper
|
||||||
|
{
|
||||||
|
internal static OpenApiDiagnostic? Map(MicrosoftOpenApiDiagnostic? openApiDiagnostic)
|
||||||
|
{
|
||||||
|
if (openApiDiagnostic == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new OpenApiDiagnostic
|
||||||
|
{
|
||||||
|
Errors = openApiDiagnostic.Errors.Select(e => new OpenApiError(e.Pointer, e.Message)).ToList(),
|
||||||
|
Warnings = openApiDiagnostic.Warnings.Select(e => new OpenApiError(e.Pointer, e.Message)).ToList(),
|
||||||
|
SpecificationVersion = (OpenApiSpecificationVersion)openApiDiagnostic.SpecificationVersion
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using Microsoft.OpenApi.Models;
|
using Microsoft.OpenApi.Models.Interfaces;
|
||||||
|
|
||||||
namespace WireMock.Net.OpenApiParser.Settings;
|
namespace WireMock.Net.OpenApiParser.Settings;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A interface defining the example values to use for the different types.
|
/// An interface defining the example values to use for the different types.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IWireMockOpenApiParserExampleValues
|
public interface IWireMockOpenApiParserExampleValues
|
||||||
{
|
{
|
||||||
@@ -26,9 +26,9 @@ public interface IWireMockOpenApiParserExampleValues
|
|||||||
float Float { get; }
|
float Float { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An example value for a Double.
|
/// An example value for a Decimal.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
double Double { get; }
|
decimal Decimal { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An example value for a Date.
|
/// An example value for a Date.
|
||||||
@@ -58,5 +58,5 @@ public interface IWireMockOpenApiParserExampleValues
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// OpenApi Schema to generate dynamic examples more accurate
|
/// OpenApi Schema to generate dynamic examples more accurate
|
||||||
/// </summary>
|
/// </summary>
|
||||||
OpenApiSchema? Schema { get; set; }
|
IOpenApiSchema? Schema { get; set; }
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using Microsoft.OpenApi.Models;
|
using Microsoft.OpenApi.Models.Interfaces;
|
||||||
using RandomDataGenerator.FieldOptions;
|
using RandomDataGenerator.FieldOptions;
|
||||||
using RandomDataGenerator.Randomizers;
|
using RandomDataGenerator.Randomizers;
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ public class WireMockOpenApiParserDynamicExampleValues : IWireMockOpenApiParserE
|
|||||||
public virtual float Float => RandomizerFactory.GetRandomizer(new FieldOptionsFloat()).Generate() ?? 4.2f;
|
public virtual float Float => RandomizerFactory.GetRandomizer(new FieldOptionsFloat()).Generate() ?? 4.2f;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public virtual double Double => RandomizerFactory.GetRandomizer(new FieldOptionsDouble()).Generate() ?? 4.2d;
|
public virtual decimal Decimal => SafeConvertFloatToDecimal(RandomizerFactory.GetRandomizer(new FieldOptionsFloat()).Generate() ?? 4.2f);
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public virtual Func<DateTime> Date => () => RandomizerFactory.GetRandomizer(new FieldOptionsDateTime()).Generate() ?? System.DateTime.UtcNow.Date;
|
public virtual Func<DateTime> Date => () => RandomizerFactory.GetRandomizer(new FieldOptionsDateTime()).Generate() ?? System.DateTime.UtcNow.Date;
|
||||||
@@ -40,5 +40,20 @@ public class WireMockOpenApiParserDynamicExampleValues : IWireMockOpenApiParserE
|
|||||||
public virtual string String => RandomizerFactory.GetRandomizer(new FieldOptionsTextRegex { Pattern = @"^[0-9]{2}[A-Z]{5}[0-9]{2}" }).Generate() ?? "example-string";
|
public virtual string String => RandomizerFactory.GetRandomizer(new FieldOptionsTextRegex { Pattern = @"^[0-9]{2}[A-Z]{5}[0-9]{2}" }).Generate() ?? "example-string";
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public virtual OpenApiSchema? Schema { get; set; }
|
public virtual IOpenApiSchema? Schema { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Safely converts a float to a decimal, ensuring the value stays within the bounds of a decimal.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The float value to convert.</param>
|
||||||
|
/// <returns>A decimal value within the valid range of a decimal.</returns>
|
||||||
|
private static decimal SafeConvertFloatToDecimal(float value)
|
||||||
|
{
|
||||||
|
return value switch
|
||||||
|
{
|
||||||
|
< (float)decimal.MinValue => decimal.MinValue,
|
||||||
|
> (float)decimal.MaxValue => decimal.MaxValue,
|
||||||
|
_ => (decimal)value
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using Microsoft.OpenApi.Models;
|
using Microsoft.OpenApi.Models;
|
||||||
|
using Microsoft.OpenApi.Models.Interfaces;
|
||||||
|
|
||||||
namespace WireMock.Net.OpenApiParser.Settings;
|
namespace WireMock.Net.OpenApiParser.Settings;
|
||||||
|
|
||||||
@@ -20,7 +21,7 @@ public class WireMockOpenApiParserExampleValues : IWireMockOpenApiParserExampleV
|
|||||||
public virtual float Float => 4.2f;
|
public virtual float Float => 4.2f;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public virtual double Double => 4.2d;
|
public virtual decimal Decimal => 4.2m;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public virtual Func<DateTime> Date { get; } = () => System.DateTime.UtcNow.Date;
|
public virtual Func<DateTime> Date { get; } = () => System.DateTime.UtcNow.Date;
|
||||||
@@ -29,7 +30,7 @@ public class WireMockOpenApiParserExampleValues : IWireMockOpenApiParserExampleV
|
|||||||
public virtual Func<DateTime> DateTime { get; } = () => System.DateTime.UtcNow;
|
public virtual Func<DateTime> DateTime { get; } = () => System.DateTime.UtcNow;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public virtual byte[] Bytes { get; } = { 48, 49, 50 };
|
public virtual byte[] Bytes { get; } = [48, 49, 50];
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public virtual object Object => "example-object";
|
public virtual object Object => "example-object";
|
||||||
@@ -38,5 +39,5 @@ public class WireMockOpenApiParserExampleValues : IWireMockOpenApiParserExampleV
|
|||||||
public virtual string String => "example-string";
|
public virtual string String => "example-string";
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public virtual OpenApiSchema? Schema { get; set; } = new();
|
public virtual IOpenApiSchema? Schema { get; set; } = new OpenApiSchema();
|
||||||
}
|
}
|
||||||
@@ -7,13 +7,16 @@ namespace WireMock.Net.OpenApiParser.Utils;
|
|||||||
|
|
||||||
internal static class DateTimeUtils
|
internal static class DateTimeUtils
|
||||||
{
|
{
|
||||||
|
private const string DateFormat = "yyyy-MM-dd";
|
||||||
|
private const string DateTimeFormat = "yyyy-MM-dd'T'HH:mm:ss.fffzzz";
|
||||||
|
|
||||||
public static string ToRfc3339DateTime(DateTime dateTime)
|
public static string ToRfc3339DateTime(DateTime dateTime)
|
||||||
{
|
{
|
||||||
return dateTime.ToString("yyyy-MM-dd'T'HH:mm:ss.fffzzz", DateTimeFormatInfo.InvariantInfo);
|
return dateTime.ToString(DateTimeFormat, DateTimeFormatInfo.InvariantInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string ToRfc3339Date(DateTime dateTime)
|
public static string ToRfc3339Date(DateTime dateTime)
|
||||||
{
|
{
|
||||||
return dateTime.ToString("yyyy-MM-dd", DateTimeFormatInfo.InvariantInfo);
|
return dateTime.ToString(DateFormat, DateTimeFormatInfo.InvariantInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.OpenApi.Any;
|
using System.Text.Json.Nodes;
|
||||||
using Microsoft.OpenApi.Models;
|
using Microsoft.OpenApi.Models;
|
||||||
|
using Microsoft.OpenApi.Models.Interfaces;
|
||||||
using Stef.Validation;
|
using Stef.Validation;
|
||||||
using WireMock.Net.OpenApiParser.Extensions;
|
using WireMock.Net.OpenApiParser.Extensions;
|
||||||
using WireMock.Net.OpenApiParser.Settings;
|
using WireMock.Net.OpenApiParser.Settings;
|
||||||
@@ -36,82 +38,66 @@ internal class ExampleValueGenerator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public object GetExampleValue(OpenApiSchema? schema)
|
public JsonNode GetExampleValue(IOpenApiSchema? schema)
|
||||||
{
|
{
|
||||||
var schemaExample = schema?.Example;
|
var schemaExample = schema?.Example;
|
||||||
var schemaEnum = schema?.Enum?.FirstOrDefault();
|
var schemaEnum = schema?.Enum?.FirstOrDefault();
|
||||||
|
|
||||||
_exampleValues.Schema = schema;
|
_exampleValues.Schema = schema;
|
||||||
|
|
||||||
switch (schema?.GetSchemaType())
|
switch (schema?.GetSchemaType(out _))
|
||||||
{
|
{
|
||||||
case SchemaType.Boolean:
|
case JsonSchemaType.Boolean:
|
||||||
var exampleBoolean = schemaExample as OpenApiBoolean;
|
var exampleBoolean = schemaExample?.GetValue<bool>();
|
||||||
return exampleBoolean?.Value ?? _exampleValues.Boolean;
|
return exampleBoolean ?? _exampleValues.Boolean;
|
||||||
|
|
||||||
case SchemaType.Integer:
|
case JsonSchemaType.Integer:
|
||||||
switch (schema?.GetSchemaFormat())
|
var exampleInteger = schemaExample?.GetValue<decimal>();
|
||||||
{
|
var enumInteger = schemaEnum?.GetValue<decimal>();
|
||||||
case SchemaFormat.Int64:
|
var valueIntegerEnumOrExample = enumInteger ?? exampleInteger;
|
||||||
var exampleLong = schemaExample as OpenApiLong;
|
return valueIntegerEnumOrExample ?? _exampleValues.Integer;
|
||||||
var enumLong = schemaEnum as OpenApiLong;
|
|
||||||
var valueLongEnumOrExample = enumLong?.Value ?? exampleLong?.Value;
|
|
||||||
return valueLongEnumOrExample ?? _exampleValues.Integer;
|
|
||||||
|
|
||||||
default:
|
case JsonSchemaType.Number:
|
||||||
var exampleInteger = schemaExample as OpenApiInteger;
|
switch (schema.GetSchemaFormat())
|
||||||
var enumInteger = schemaEnum as OpenApiInteger;
|
|
||||||
var valueIntegerEnumOrExample = enumInteger?.Value ?? exampleInteger?.Value;
|
|
||||||
return valueIntegerEnumOrExample ?? _exampleValues.Integer;
|
|
||||||
}
|
|
||||||
|
|
||||||
case SchemaType.Number:
|
|
||||||
switch (schema?.GetSchemaFormat())
|
|
||||||
{
|
{
|
||||||
case SchemaFormat.Float:
|
case SchemaFormat.Float:
|
||||||
var exampleFloat = schemaExample as OpenApiFloat;
|
var exampleFloat = schemaExample?.GetValue<float>();
|
||||||
var enumFloat = schemaEnum as OpenApiFloat;
|
var enumFloat = schemaEnum?.GetValue<float>();
|
||||||
var valueFloatEnumOrExample = enumFloat?.Value ?? exampleFloat?.Value;
|
var valueFloatEnumOrExample = enumFloat ?? exampleFloat;
|
||||||
return valueFloatEnumOrExample ?? _exampleValues.Float;
|
return valueFloatEnumOrExample ?? _exampleValues.Float;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
var exampleDouble = schemaExample as OpenApiDouble;
|
var exampleDecimal = schemaExample?.GetValue<decimal>();
|
||||||
var enumDouble = schemaEnum as OpenApiDouble;
|
var enumDecimal = schemaEnum?.GetValue<decimal>();
|
||||||
var valueDoubleEnumOrExample = enumDouble?.Value ?? exampleDouble?.Value;
|
var valueDecimalEnumOrExample = enumDecimal ?? exampleDecimal;
|
||||||
return valueDoubleEnumOrExample ?? _exampleValues.Double;
|
return valueDecimalEnumOrExample ?? _exampleValues.Decimal;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
switch (schema?.GetSchemaFormat())
|
switch (schema?.GetSchemaFormat())
|
||||||
{
|
{
|
||||||
case SchemaFormat.Date:
|
case SchemaFormat.Date:
|
||||||
var exampleDate = schemaExample as OpenApiDate;
|
var exampleDate = schemaExample?.GetValue<string>();
|
||||||
var enumDate = schemaEnum as OpenApiDate;
|
var enumDate = schemaEnum?.GetValue<string>();
|
||||||
var valueDateEnumOrExample = enumDate?.Value ?? exampleDate?.Value;
|
var valueDateEnumOrExample = enumDate ?? exampleDate;
|
||||||
return DateTimeUtils.ToRfc3339Date(valueDateEnumOrExample ?? _exampleValues.Date());
|
return valueDateEnumOrExample ?? DateTimeUtils.ToRfc3339Date(_exampleValues.Date());
|
||||||
|
|
||||||
case SchemaFormat.DateTime:
|
case SchemaFormat.DateTime:
|
||||||
var exampleDateTime = schemaExample as OpenApiDateTime;
|
var exampleDateTime = schemaExample?.GetValue<string>();
|
||||||
var enumDateTime = schemaEnum as OpenApiDateTime;
|
var enumDateTime = schemaEnum?.GetValue<string>();
|
||||||
var valueDateTimeEnumOrExample = enumDateTime?.Value ?? exampleDateTime?.Value;
|
var valueDateTimeEnumOrExample = enumDateTime ?? exampleDateTime;
|
||||||
return DateTimeUtils.ToRfc3339DateTime(valueDateTimeEnumOrExample?.DateTime ?? _exampleValues.DateTime());
|
return valueDateTimeEnumOrExample ?? DateTimeUtils.ToRfc3339DateTime(_exampleValues.DateTime());
|
||||||
|
|
||||||
case SchemaFormat.Byte:
|
case SchemaFormat.Byte:
|
||||||
var exampleByte = schemaExample as OpenApiByte;
|
var exampleByte = schemaExample?.GetValue<byte[]>();
|
||||||
var enumByte = schemaEnum as OpenApiByte;
|
var enumByte = schemaEnum?.GetValue<byte[]>();
|
||||||
var valueByteEnumOrExample = enumByte?.Value ?? exampleByte?.Value;
|
var valueByteEnumOrExample = enumByte ?? exampleByte;
|
||||||
return valueByteEnumOrExample ?? _exampleValues.Bytes;
|
return Convert.ToBase64String(valueByteEnumOrExample ?? _exampleValues.Bytes);
|
||||||
|
|
||||||
case SchemaFormat.Binary:
|
|
||||||
var exampleBinary = schemaExample as OpenApiBinary;
|
|
||||||
var enumBinary = schemaEnum as OpenApiBinary;
|
|
||||||
var valueBinaryEnumOrExample = enumBinary?.Value ?? exampleBinary?.Value;
|
|
||||||
return valueBinaryEnumOrExample ?? _exampleValues.Object;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
var exampleString = schemaExample as OpenApiString;
|
var exampleString = schemaExample?.GetValue<string>();
|
||||||
var enumString = schemaEnum as OpenApiString;
|
var enumString = schemaEnum?.GetValue<string>();
|
||||||
var valueStringEnumOrExample = enumString?.Value ?? exampleString?.Value;
|
var valueStringEnumOrExample = enumString ?? exampleString;
|
||||||
return valueStringEnumOrExample ?? _exampleValues.String;
|
return valueStringEnumOrExample ?? _exampleValues.String;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
namespace WireMock.Net.OpenApiParser.Utils;
|
namespace WireMock.Net.OpenApiParser.Utils;
|
||||||
|
|
||||||
internal static class PathUtils
|
internal static class PathUtils
|
||||||
@@ -11,17 +13,17 @@ internal static class PathUtils
|
|||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = paths[0].Trim().TrimEnd('/');
|
var result = new StringBuilder(paths[0].Trim().TrimEnd('/'));
|
||||||
|
|
||||||
for (int i = 1; i < paths.Length; i++)
|
for (var i = 1; i < paths.Length; i++)
|
||||||
{
|
{
|
||||||
var nextPath = paths[i].Trim().TrimStart('/').TrimEnd('/');
|
var nextPath = paths[i].Trim().TrimStart('/').TrimEnd('/');
|
||||||
if (!string.IsNullOrEmpty(nextPath))
|
if (!string.IsNullOrEmpty(nextPath))
|
||||||
{
|
{
|
||||||
result += '/' + nextPath;
|
result.Append('/').Append(nextPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Description>An OpenApi (swagger) parser to generate MappingModel or mapping.json file.</Description>
|
<Description>An OpenApi (swagger) parser to generate MappingModel or mapping.json file.</Description>
|
||||||
<TargetFrameworks>net46;netstandard2.0;netstandard2.1</TargetFrameworks>
|
<TargetFrameworks>netstandard2.0;net8.0</TargetFrameworks>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<PackageTags>wiremock;openapi;OAS;raml;converter;parser;openapiparser</PackageTags>
|
<PackageTags>wiremock;openapi;OAS;raml;converter;parser;openapiparser</PackageTags>
|
||||||
<ProjectGuid>{D3804228-91F4-4502-9595-39584E5AADAD}</ProjectGuid>
|
<ProjectGuid>{E5B03EEF-822C-4295-952B-4479AD30082B}</ProjectGuid>
|
||||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||||
<CodeAnalysisRuleSet>../WireMock.Net/WireMock.Net.ruleset</CodeAnalysisRuleSet>
|
<CodeAnalysisRuleSet>../WireMock.Net/WireMock.Net.ruleset</CodeAnalysisRuleSet>
|
||||||
<SignAssembly>true</SignAssembly>
|
<!--<SignAssembly>true</SignAssembly>
|
||||||
<AssemblyOriginatorKeyFile>../WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
|
<AssemblyOriginatorKeyFile>../WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
|
||||||
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
|
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>-->
|
||||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
@@ -20,18 +20,31 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<PackageReference Include="Microsoft.OpenApi.Readers" Version="1.2.3" />
|
|
||||||
<PackageReference Include="Nullable" Version="1.3.1">
|
<PackageReference Include="Nullable" Version="1.3.1">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="RamlToOpenApiConverter" Version="0.6.1" />
|
<PackageReference Include="RamlToOpenApiConverter.SourceOnly" Version="0.8.0" />
|
||||||
|
<PackageReference Include="YamlDotNet" Version="8.1.0" />
|
||||||
<PackageReference Include="RandomDataGenerator.Net" Version="1.0.18" />
|
<PackageReference Include="RandomDataGenerator.Net" Version="1.0.18" />
|
||||||
<PackageReference Include="Stef.Validation" Version="0.1.1" />
|
<PackageReference Include="Stef.Validation" Version="0.1.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup Condition="'$(Configuration)' == 'Debug'">
|
||||||
|
<PackageReference Include="Microsoft.OpenApi.YamlReader" Version="2.0.0-preview.17" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup Condition="'$(Configuration)' == 'Release'">
|
||||||
|
<PackageReference Include="ILRepack.Lib.MSBuild.Task" Version="2.0.40" PrivateAssets="All" />
|
||||||
|
|
||||||
|
<PackageReference Include="Microsoft.OpenApi" Version="2.0.0-preview.17" PrivateAssets="All" />
|
||||||
|
<PackageReference Include="Microsoft.OpenApi.YamlReader" Version="2.0.0-preview.17" PrivateAssets="All" />
|
||||||
|
<PackageReference Include="System.Text.Json" Version="8.0.5" />
|
||||||
|
<PackageReference Include="SharpYaml" Version="2.1.1" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\WireMock.Net.Abstractions\WireMock.Net.Abstractions.csproj" />
|
<ProjectReference Include="..\..\src\WireMock.Net.Abstractions\WireMock.Net.Abstractions.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
@@ -6,20 +6,35 @@ using System.IO;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Microsoft.OpenApi.Models;
|
using Microsoft.OpenApi.Models;
|
||||||
using Microsoft.OpenApi.Readers;
|
using Microsoft.OpenApi.Reader;
|
||||||
|
using Microsoft.OpenApi.YamlReader;
|
||||||
using RamlToOpenApiConverter;
|
using RamlToOpenApiConverter;
|
||||||
using WireMock.Admin.Mappings;
|
using WireMock.Admin.Mappings;
|
||||||
using WireMock.Net.OpenApiParser.Mappers;
|
using WireMock.Net.OpenApiParser.Mappers;
|
||||||
|
using WireMock.Net.OpenApiParser.Models;
|
||||||
using WireMock.Net.OpenApiParser.Settings;
|
using WireMock.Net.OpenApiParser.Settings;
|
||||||
|
using OpenApiDiagnostic = WireMock.Net.OpenApiParser.Models.OpenApiDiagnostic;
|
||||||
|
|
||||||
namespace WireMock.Net.OpenApiParser;
|
namespace WireMock.Net.OpenApiParser;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Parse a OpenApi/Swagger/V2/V3 or Raml to WireMock.Net MappingModels.
|
/// Parse a OpenApi/Swagger/V2/V3/V3.1 to WireMock.Net MappingModels.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class WireMockOpenApiParser : IWireMockOpenApiParser
|
public class WireMockOpenApiParser : IWireMockOpenApiParser
|
||||||
{
|
{
|
||||||
private readonly OpenApiStreamReader _reader = new();
|
private readonly OpenApiReaderSettings _readerSettings;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="WireMockOpenApiParser"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public WireMockOpenApiParser()
|
||||||
|
{
|
||||||
|
_readerSettings = new OpenApiReaderSettings();
|
||||||
|
_readerSettings.AddMicrosoftExtensionParsers();
|
||||||
|
_readerSettings.AddJsonReader();
|
||||||
|
_readerSettings.TryAddReader(OpenApiConstants.Yaml, new OpenApiYamlReader());
|
||||||
|
_readerSettings.TryAddReader(OpenApiConstants.Yml, new OpenApiYamlReader());
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
@@ -40,8 +55,7 @@ public class WireMockOpenApiParser : IWireMockOpenApiParser
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var reader = new OpenApiStreamReader();
|
document = Read(File.OpenRead(path), out diagnostic);
|
||||||
document = reader.Read(File.OpenRead(path), out diagnostic);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return FromDocument(document, settings);
|
return FromDocument(document, settings);
|
||||||
@@ -49,23 +63,25 @@ public class WireMockOpenApiParser : IWireMockOpenApiParser
|
|||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
public IReadOnlyList<MappingModel> FromDocument(OpenApiDocument document, WireMockOpenApiParserSettings? settings = null)
|
public IReadOnlyList<MappingModel> FromDocument(object document, WireMockOpenApiParserSettings? settings = null)
|
||||||
{
|
{
|
||||||
return new OpenApiPathsMapper(settings ?? new WireMockOpenApiParserSettings()).ToMappingModels(document.Paths, document.Servers);
|
var openApiDocument = document as OpenApiDocument ?? throw new ArgumentException("The document should be a Microsoft.OpenApi.Models.OpenApiDocument", nameof(document));
|
||||||
|
|
||||||
|
return new OpenApiPathsMapper(settings ?? new WireMockOpenApiParserSettings()).ToMappingModels(openApiDocument.Paths, openApiDocument.Servers ?? []);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
public IReadOnlyList<MappingModel> FromStream(Stream stream, out OpenApiDiagnostic diagnostic)
|
public IReadOnlyList<MappingModel> FromStream(Stream stream, out OpenApiDiagnostic diagnostic)
|
||||||
{
|
{
|
||||||
return FromDocument(_reader.Read(stream, out diagnostic));
|
return FromDocument(Read(stream, out diagnostic));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
public IReadOnlyList<MappingModel> FromStream(Stream stream, WireMockOpenApiParserSettings settings, out OpenApiDiagnostic diagnostic)
|
public IReadOnlyList<MappingModel> FromStream(Stream stream, WireMockOpenApiParserSettings settings, out OpenApiDiagnostic diagnostic)
|
||||||
{
|
{
|
||||||
return FromDocument(_reader.Read(stream, out diagnostic), settings);
|
return FromDocument(Read(stream, out diagnostic), settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -81,4 +97,25 @@ public class WireMockOpenApiParser : IWireMockOpenApiParser
|
|||||||
{
|
{
|
||||||
return FromStream(new MemoryStream(Encoding.UTF8.GetBytes(text)), settings, out diagnostic);
|
return FromStream(new MemoryStream(Encoding.UTF8.GetBytes(text)), settings, out diagnostic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private OpenApiDocument Read(Stream stream, out OpenApiDiagnostic diagnostic)
|
||||||
|
{
|
||||||
|
if (stream is not MemoryStream memoryStream)
|
||||||
|
{
|
||||||
|
memoryStream = ReadStreamIntoMemoryStream(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = OpenApiDocument.Load(memoryStream, settings: _readerSettings);
|
||||||
|
|
||||||
|
diagnostic = OpenApiMapper.Map(result.Diagnostic) ?? new OpenApiDiagnostic();
|
||||||
|
return result.Document ?? throw new InvalidOperationException("The document is null.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MemoryStream ReadStreamIntoMemoryStream(Stream stream)
|
||||||
|
{
|
||||||
|
var memoryStream = new MemoryStream();
|
||||||
|
stream.CopyTo(memoryStream);
|
||||||
|
memoryStream.Position = 0;
|
||||||
|
return memoryStream;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
// Copyright © WireMock.Net
|
|
||||||
|
|
||||||
// Copied from https://github.com/Handlebars-Net/Handlebars.Net.Helpers/blob/master/src/Handlebars.Net.Helpers.DynamicLinq
|
|
||||||
|
|
||||||
using System.Linq.Dynamic.Core;
|
|
||||||
|
|
||||||
namespace WireMock.Json;
|
|
||||||
|
|
||||||
internal class DynamicPropertyWithValue : DynamicProperty
|
|
||||||
{
|
|
||||||
public object? Value { get; }
|
|
||||||
|
|
||||||
public DynamicPropertyWithValue(string name, object? value) : base(name, value?.GetType() ?? typeof(object))
|
|
||||||
{
|
|
||||||
Value = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
namespace WireMock.Json;
|
namespace WireMock.Json;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Enum to define how to convert an Float in the Json Object.
|
/// Enum to define how to convert a Float in the Json Object.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal enum FloatBehavior
|
internal enum FloatBehavior
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,202 +0,0 @@
|
|||||||
// Copyright © WireMock.Net
|
|
||||||
|
|
||||||
// Copied from https://github.com/Handlebars-Net/Handlebars.Net.Helpers/blob/master/src/Handlebars.Net.Helpers.DynamicLinq which is copied from https://github.com/StefH/JsonConverter
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Linq.Dynamic.Core;
|
|
||||||
using System.Reflection;
|
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
|
|
||||||
namespace WireMock.Json;
|
|
||||||
|
|
||||||
internal static class JObjectExtensions
|
|
||||||
{
|
|
||||||
private class JTokenResolvers : Dictionary<JTokenType, Func<JToken, DynamicJsonClassOptions?, object?>>;
|
|
||||||
|
|
||||||
private static readonly JTokenResolvers Resolvers = new()
|
|
||||||
{
|
|
||||||
{ JTokenType.Array, ConvertJTokenArray },
|
|
||||||
{ JTokenType.Boolean, (jToken, _) => jToken.Value<bool>() },
|
|
||||||
{ JTokenType.Bytes, (jToken, _) => jToken.Value<byte[]>() },
|
|
||||||
{ JTokenType.Date, (jToken, _) => jToken.Value<DateTime>() },
|
|
||||||
{ JTokenType.Float, ConvertJTokenFloat },
|
|
||||||
{ JTokenType.Guid, (jToken, _) => jToken.Value<Guid>() },
|
|
||||||
{ JTokenType.Integer, ConvertJTokenInteger },
|
|
||||||
{ JTokenType.None, (_, _) => null },
|
|
||||||
{ JTokenType.Null, (_, _) => null },
|
|
||||||
{ JTokenType.Object, ConvertJObject },
|
|
||||||
{ JTokenType.Property, ConvertJTokenProperty },
|
|
||||||
{ JTokenType.String, (jToken, _) => jToken.Value<string>() },
|
|
||||||
{ JTokenType.TimeSpan, (jToken, _) => jToken.Value<TimeSpan>() },
|
|
||||||
{ JTokenType.Undefined, (_, _) => null },
|
|
||||||
{ JTokenType.Uri, (o, _) => o.Value<Uri>() },
|
|
||||||
};
|
|
||||||
|
|
||||||
internal static DynamicClass? ToDynamicJsonClass(this JObject? src, DynamicJsonClassOptions? options = null)
|
|
||||||
{
|
|
||||||
if (src == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var dynamicPropertyWithValues = new List<DynamicPropertyWithValue>();
|
|
||||||
|
|
||||||
foreach (var prop in src.Properties())
|
|
||||||
{
|
|
||||||
var value = Resolvers[prop.Type](prop.Value, options);
|
|
||||||
if (value != null)
|
|
||||||
{
|
|
||||||
dynamicPropertyWithValues.Add(new DynamicPropertyWithValue(prop.Name, value));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return CreateInstance(dynamicPropertyWithValues);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static IEnumerable ToDynamicClassArray(this JArray? src, DynamicJsonClassOptions? options = null)
|
|
||||||
{
|
|
||||||
if (src == null)
|
|
||||||
{
|
|
||||||
return EmptyArray<object?>.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ConvertJTokenArray(src, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static object? ConvertJObject(JToken arg, DynamicJsonClassOptions? options = null)
|
|
||||||
{
|
|
||||||
if (arg is JObject asJObject)
|
|
||||||
{
|
|
||||||
return asJObject.ToDynamicJsonClass(options);
|
|
||||||
}
|
|
||||||
|
|
||||||
return GetResolverFor(arg)(arg, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static object PassThrough(JToken arg, DynamicJsonClassOptions? options)
|
|
||||||
{
|
|
||||||
return arg;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Func<JToken, DynamicJsonClassOptions?, object?> GetResolverFor(JToken arg)
|
|
||||||
{
|
|
||||||
return Resolvers.TryGetValue(arg.Type, out var result) ? result : PassThrough;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static object ConvertJTokenFloat(JToken arg, DynamicJsonClassOptions? options = null)
|
|
||||||
{
|
|
||||||
if (arg.Type != JTokenType.Float)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException($"Unable to convert {nameof(JToken)} of type: {arg.Type} to double or float.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options?.FloatConvertBehavior == FloatBehavior.UseFloat)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return arg.Value<float>();
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return arg.Value<double>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options?.FloatConvertBehavior == FloatBehavior.UseDecimal)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return arg.Value<decimal>();
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return arg.Value<double>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return arg.Value<double>();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static object ConvertJTokenInteger(JToken arg, DynamicJsonClassOptions? options = null)
|
|
||||||
{
|
|
||||||
if (arg.Type != JTokenType.Integer)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException($"Unable to convert {nameof(JToken)} of type: {arg.Type} to long or int.");
|
|
||||||
}
|
|
||||||
|
|
||||||
var longValue = arg.Value<long>();
|
|
||||||
|
|
||||||
if (options is null || options.IntegerConvertBehavior == IntegerBehavior.UseInt)
|
|
||||||
{
|
|
||||||
if (longValue is >= int.MinValue and <= int.MaxValue)
|
|
||||||
{
|
|
||||||
return Convert.ToInt32(longValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return longValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static object? ConvertJTokenProperty(JToken arg, DynamicJsonClassOptions? options = null)
|
|
||||||
{
|
|
||||||
var resolver = GetResolverFor(arg);
|
|
||||||
if (resolver is null)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException($"Unable to handle {nameof(JToken)} of type: {arg.Type}.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return resolver(arg, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IEnumerable ConvertJTokenArray(JToken arg, DynamicJsonClassOptions? options = null)
|
|
||||||
{
|
|
||||||
if (arg is not JArray array)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException($"Unable to convert {nameof(JToken)} of type: {arg.Type} to {nameof(JArray)}.");
|
|
||||||
}
|
|
||||||
|
|
||||||
var result = new List<object?>();
|
|
||||||
foreach (var item in array)
|
|
||||||
{
|
|
||||||
result.Add(ConvertJObject(item));
|
|
||||||
}
|
|
||||||
|
|
||||||
var distinctType = FindSameTypeOf(result);
|
|
||||||
return distinctType == null ? result.ToArray() : ConvertToTypedArray(result, distinctType);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Type? FindSameTypeOf(IEnumerable<object?> src)
|
|
||||||
{
|
|
||||||
var types = src.Select(o => o?.GetType()).Distinct().OfType<Type>().ToArray();
|
|
||||||
return types.Length == 1 ? types[0] : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IEnumerable ConvertToTypedArray(IEnumerable<object?> src, Type newType)
|
|
||||||
{
|
|
||||||
var method = ConvertToTypedArrayGenericMethod.MakeGenericMethod(newType);
|
|
||||||
return (IEnumerable)method.Invoke(null, [src])!;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static readonly MethodInfo ConvertToTypedArrayGenericMethod = typeof(JObjectExtensions).GetMethod(nameof(ConvertToTypedArrayGeneric), BindingFlags.NonPublic | BindingFlags.Static)!;
|
|
||||||
|
|
||||||
private static T[] ConvertToTypedArrayGeneric<T>(IEnumerable<object> src)
|
|
||||||
{
|
|
||||||
return src.Cast<T>().ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static DynamicClass CreateInstance(IList<DynamicPropertyWithValue> dynamicPropertiesWithValue, bool createParameterCtor = true)
|
|
||||||
{
|
|
||||||
var type = DynamicClassFactory.CreateType(dynamicPropertiesWithValue.Cast<DynamicProperty>().ToArray(), createParameterCtor);
|
|
||||||
var dynamicClass = (DynamicClass)Activator.CreateInstance(type)!;
|
|
||||||
foreach (var dynamicPropertyWithValue in dynamicPropertiesWithValue.Where(p => p.Value != null))
|
|
||||||
{
|
|
||||||
dynamicClass.SetDynamicPropertyValue(dynamicPropertyWithValue.Name, dynamicPropertyWithValue.Value!);
|
|
||||||
}
|
|
||||||
|
|
||||||
return dynamicClass;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Description>Lightweight Http Mocking Server for .Net, inspired by WireMock from the Java landscape.</Description>
|
<Description>Lightweight Http Mocking Server for .Net, inspired by WireMock from the Java landscape.</Description>
|
||||||
<AssemblyTitle>WireMock.Net</AssemblyTitle>
|
<AssemblyTitle>WireMock.Net</AssemblyTitle>
|
||||||
@@ -46,7 +46,7 @@
|
|||||||
<DefineConstants>$(DefineConstants);USE_ASPNETCORE;NET46</DefineConstants>
|
<DefineConstants>$(DefineConstants);USE_ASPNETCORE;NET46</DefineConstants>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(TargetFramework)' != 'netstandard1.3' and '$(TargetFramework)' != 'net451' and '$(TargetFramework)' != 'net452'">
|
<PropertyGroup Condition="'$(TargetFramework)' != 'netstandard1.3' and '$(TargetFramework)' != 'net451' and '$(TargetFramework)' != 'net452' and '$(TargetFramework)' != 'net46'">
|
||||||
<DefineConstants>$(DefineConstants);OPENAPIPARSER</DefineConstants>
|
<DefineConstants>$(DefineConstants);OPENAPIPARSER</DefineConstants>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
@@ -59,8 +59,6 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Remove="Json\DynamicPropertyWithValue.cs" />
|
|
||||||
<Compile Remove="Json\JObjectExtensions.cs" />
|
|
||||||
<Compile Remove="Matchers\LinqMatcher.cs" />
|
<Compile Remove="Matchers\LinqMatcher.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
@@ -205,7 +203,7 @@
|
|||||||
<ProjectReference Include="..\WireMock.Org.Abstractions\WireMock.Org.Abstractions.csproj" />
|
<ProjectReference Include="..\WireMock.Org.Abstractions\WireMock.Org.Abstractions.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup Condition="'$(TargetFramework)' != 'netstandard1.3' and '$(TargetFramework)' != 'net451' and '$(TargetFramework)' != 'net452'">
|
<ItemGroup Condition="'$(TargetFramework)' != 'netstandard1.3' and '$(TargetFramework)' != 'net451' and '$(TargetFramework)' != 'net452' and '$(TargetFramework)' != 'net46'">
|
||||||
<ProjectReference Include="..\WireMock.Net.OpenApiParser\WireMock.Net.OpenApiParser.csproj" />
|
<ProjectReference Include="..\WireMock.Net.OpenApiParser\WireMock.Net.OpenApiParser.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
@@ -334,7 +334,7 @@
|
|||||||
"processingTerminalId": "example-string",
|
"processingTerminalId": "example-string",
|
||||||
"order": {
|
"order": {
|
||||||
"orderId": "example-string",
|
"orderId": "example-string",
|
||||||
"dateTime": "2024-06-19T12:34:56.000+00:00",
|
"dateTime": "2024-06-19T12:34:56.000\u002B00:00",
|
||||||
"description": "example-string",
|
"description": "example-string",
|
||||||
"amount": 42,
|
"amount": 42,
|
||||||
"currency": "AED",
|
"currency": "AED",
|
||||||
@@ -1787,7 +1787,7 @@
|
|||||||
"processingTerminalId": "example-string",
|
"processingTerminalId": "example-string",
|
||||||
"order": {
|
"order": {
|
||||||
"orderId": "example-string",
|
"orderId": "example-string",
|
||||||
"dateTime": "2024-06-19T12:34:56.000+00:00",
|
"dateTime": "2024-06-19T12:34:56.000\u002B00:00",
|
||||||
"description": "example-string",
|
"description": "example-string",
|
||||||
"amount": 42,
|
"amount": 42,
|
||||||
"currency": "AED"
|
"currency": "AED"
|
||||||
@@ -2714,7 +2714,7 @@
|
|||||||
"processingTerminalId": "example-string",
|
"processingTerminalId": "example-string",
|
||||||
"order": {
|
"order": {
|
||||||
"orderId": "example-string",
|
"orderId": "example-string",
|
||||||
"dateTime": "2024-06-19T12:34:56.000+00:00",
|
"dateTime": "2024-06-19T12:34:56.000\u002B00:00",
|
||||||
"description": "example-string",
|
"description": "example-string",
|
||||||
"amount": 42,
|
"amount": 42,
|
||||||
"currency": "AED",
|
"currency": "AED",
|
||||||
@@ -2863,7 +2863,7 @@
|
|||||||
"processingTerminalId": "example-string",
|
"processingTerminalId": "example-string",
|
||||||
"order": {
|
"order": {
|
||||||
"orderId": "example-string",
|
"orderId": "example-string",
|
||||||
"dateTime": "2024-06-19T12:34:56.000+00:00",
|
"dateTime": "2024-06-19T12:34:56.000\u002B00:00",
|
||||||
"description": "example-string",
|
"description": "example-string",
|
||||||
"amount": 42,
|
"amount": 42,
|
||||||
"currency": "AED"
|
"currency": "AED"
|
||||||
@@ -6893,7 +6893,7 @@
|
|||||||
"operator": "example-string",
|
"operator": "example-string",
|
||||||
"order": {
|
"order": {
|
||||||
"orderId": "example-string",
|
"orderId": "example-string",
|
||||||
"dateTime": "2024-06-19T12:34:56.000+00:00",
|
"dateTime": "2024-06-19T12:34:56.000\u002B00:00",
|
||||||
"description": "example-string",
|
"description": "example-string",
|
||||||
"amount": 42,
|
"amount": 42,
|
||||||
"currency": "AED",
|
"currency": "AED",
|
||||||
@@ -7093,7 +7093,7 @@
|
|||||||
"offlineProcessing": {
|
"offlineProcessing": {
|
||||||
"operation": "offlineDecline",
|
"operation": "offlineDecline",
|
||||||
"approvalCode": "example-string",
|
"approvalCode": "example-string",
|
||||||
"dateTime": "2024-06-19T12:34:56.000+00:00"
|
"dateTime": "2024-06-19T12:34:56.000\u002B00:00"
|
||||||
},
|
},
|
||||||
"autoCapture": true,
|
"autoCapture": true,
|
||||||
"processAsSale": true
|
"processAsSale": true
|
||||||
@@ -11349,7 +11349,7 @@
|
|||||||
{
|
{
|
||||||
"op": "replace",
|
"op": "replace",
|
||||||
"path": "/a/b/c",
|
"path": "/a/b/c",
|
||||||
"value": "420"
|
"value": 420
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"op": "move",
|
"op": "move",
|
||||||
@@ -11827,7 +11827,7 @@
|
|||||||
{
|
{
|
||||||
"op": "replace",
|
"op": "replace",
|
||||||
"path": "/a/b/c",
|
"path": "/a/b/c",
|
||||||
"value": "420"
|
"value": 420
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"op": "move",
|
"op": "move",
|
||||||
@@ -12541,7 +12541,7 @@
|
|||||||
{
|
{
|
||||||
"op": "replace",
|
"op": "replace",
|
||||||
"path": "/a/b/c",
|
"path": "/a/b/c",
|
||||||
"value": "420"
|
"value": 420
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"op": "move",
|
"op": "move",
|
||||||
@@ -12986,7 +12986,7 @@
|
|||||||
"operator": "example-string",
|
"operator": "example-string",
|
||||||
"order": {
|
"order": {
|
||||||
"orderId": "example-string",
|
"orderId": "example-string",
|
||||||
"dateTime": "2024-06-19T12:34:56.000+00:00",
|
"dateTime": "2024-06-19T12:34:56.000\u002B00:00",
|
||||||
"description": "example-string",
|
"description": "example-string",
|
||||||
"amount": 42,
|
"amount": 42,
|
||||||
"currency": "AED",
|
"currency": "AED",
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ public class WireMockOpenApiParserTests
|
|||||||
_exampleValuesMock.SetupGet(e => e.Boolean).Returns(true);
|
_exampleValuesMock.SetupGet(e => e.Boolean).Returns(true);
|
||||||
_exampleValuesMock.SetupGet(e => e.Integer).Returns(42);
|
_exampleValuesMock.SetupGet(e => e.Integer).Returns(42);
|
||||||
_exampleValuesMock.SetupGet(e => e.Float).Returns(1.1f);
|
_exampleValuesMock.SetupGet(e => e.Float).Returns(1.1f);
|
||||||
_exampleValuesMock.SetupGet(e => e.Double).Returns(2.2);
|
_exampleValuesMock.SetupGet(e => e.Decimal).Returns(2.2m);
|
||||||
_exampleValuesMock.SetupGet(e => e.String).Returns("example-string");
|
_exampleValuesMock.SetupGet(e => e.String).Returns("example-string");
|
||||||
_exampleValuesMock.SetupGet(e => e.Object).Returns("example-object");
|
_exampleValuesMock.SetupGet(e => e.Object).Returns("example-object");
|
||||||
_exampleValuesMock.SetupGet(e => e.Bytes).Returns("Stef"u8.ToArray());
|
_exampleValuesMock.SetupGet(e => e.Bytes).Returns("Stef"u8.ToArray());
|
||||||
|
|||||||
Reference in New Issue
Block a user