mirror of
https://github.com/wiremock/WireMock.Net.git
synced 2026-04-25 10:19:04 +02:00
Cleanup old WireMock.Net.OpenApiParser
This commit is contained in:
@@ -128,8 +128,6 @@ 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("{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}"
|
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
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
// Copyright © WireMock.Net
|
|
||||||
|
|
||||||
#if NET46 || NETSTANDARD2_0
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace WireMock.Net.OpenApiParser.Extensions;
|
|
||||||
|
|
||||||
internal static class DictionaryExtensions
|
|
||||||
{
|
|
||||||
public static bool TryAdd<TKey, TValue>(this Dictionary<TKey, TValue>? dictionary, TKey key, TValue value)
|
|
||||||
{
|
|
||||||
if (dictionary is null || dictionary.ContainsKey(key))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
dictionary[key] = value;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
// Copyright © WireMock.Net
|
|
||||||
|
|
||||||
using System.Linq;
|
|
||||||
using Microsoft.OpenApi.Any;
|
|
||||||
using Microsoft.OpenApi.Interfaces;
|
|
||||||
using Microsoft.OpenApi.Models;
|
|
||||||
using WireMock.Net.OpenApiParser.Types;
|
|
||||||
|
|
||||||
namespace WireMock.Net.OpenApiParser.Extensions;
|
|
||||||
|
|
||||||
internal static class OpenApiSchemaExtensions
|
|
||||||
{
|
|
||||||
/// <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;
|
|
||||||
|
|
||||||
if (schema.Extensions.TryGetValue("x-nullable", out var e) && e is OpenApiBoolean openApiBoolean)
|
|
||||||
{
|
|
||||||
value = openApiBoolean.Value;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SchemaType GetSchemaType(this OpenApiSchema? schema)
|
|
||||||
{
|
|
||||||
if (schema == null)
|
|
||||||
{
|
|
||||||
return SchemaType.Unknown;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (schema.Type == null)
|
|
||||||
{
|
|
||||||
if (schema.AllOf.Any() || schema.AnyOf.Any())
|
|
||||||
{
|
|
||||||
return SchemaType.Object;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return schema.Type switch
|
|
||||||
{
|
|
||||||
"object" => SchemaType.Object,
|
|
||||||
"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 OpenApiSchema? schema)
|
|
||||||
{
|
|
||||||
switch (schema?.Format)
|
|
||||||
{
|
|
||||||
case "float":
|
|
||||||
return SchemaFormat.Float;
|
|
||||||
|
|
||||||
case "double":
|
|
||||||
return SchemaFormat.Double;
|
|
||||||
|
|
||||||
case "int32":
|
|
||||||
return SchemaFormat.Int32;
|
|
||||||
|
|
||||||
case "int64":
|
|
||||||
return SchemaFormat.Int64;
|
|
||||||
|
|
||||||
case "date":
|
|
||||||
return SchemaFormat.Date;
|
|
||||||
|
|
||||||
case "date-time":
|
|
||||||
return SchemaFormat.DateTime;
|
|
||||||
|
|
||||||
case "password":
|
|
||||||
return SchemaFormat.Password;
|
|
||||||
|
|
||||||
case "byte":
|
|
||||||
return SchemaFormat.Byte;
|
|
||||||
|
|
||||||
case "binary":
|
|
||||||
return SchemaFormat.Binary;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return SchemaFormat.Undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
// Copyright © WireMock.Net
|
|
||||||
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using JetBrains.Annotations;
|
|
||||||
using Microsoft.OpenApi.Models;
|
|
||||||
using Microsoft.OpenApi.Readers;
|
|
||||||
using Stef.Validation;
|
|
||||||
using WireMock.Net.OpenApiParser.Settings;
|
|
||||||
using WireMock.Server;
|
|
||||||
|
|
||||||
namespace WireMock.Net.OpenApiParser.Extensions;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Some extension methods for <see cref="IWireMockServer"/>.
|
|
||||||
/// </summary>
|
|
||||||
public static class WireMockServerExtensions
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Register the mappings via an OpenAPI (swagger) V2 or V3 file.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="server">The WireMockServer instance</param>
|
|
||||||
/// <param name="path">Path containing OpenAPI file to parse and use the mappings.</param>
|
|
||||||
/// <param name="diagnostic">Returns diagnostic object containing errors detected during parsing</param>
|
|
||||||
[PublicAPI]
|
|
||||||
public static IWireMockServer WithMappingFromOpenApiFile(this IWireMockServer server, string path, out OpenApiDiagnostic diagnostic)
|
|
||||||
{
|
|
||||||
return WithMappingFromOpenApiFile(server, path, new WireMockOpenApiParserSettings(), out diagnostic);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Register the mappings via an OpenAPI (swagger) V2 or V3 file.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="server">The WireMockServer instance</param>
|
|
||||||
/// <param name="path">Path containing OpenAPI file to parse and use the mappings.</param>
|
|
||||||
/// <param name="settings">Additional settings</param>
|
|
||||||
/// <param name="diagnostic">Returns diagnostic object containing errors detected during parsing</param>
|
|
||||||
[PublicAPI]
|
|
||||||
public static IWireMockServer WithMappingFromOpenApiFile(this IWireMockServer server, string path, WireMockOpenApiParserSettings settings, out OpenApiDiagnostic diagnostic)
|
|
||||||
{
|
|
||||||
Guard.NotNull(server);
|
|
||||||
Guard.NotNullOrEmpty(path);
|
|
||||||
|
|
||||||
var mappings = new WireMockOpenApiParser().FromFile(path, settings, out diagnostic);
|
|
||||||
|
|
||||||
return server.WithMapping(mappings.ToArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Register the mappings via an OpenAPI (swagger) V2 or V3 stream.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="server">The WireMockServer instance</param>
|
|
||||||
/// <param name="stream">Stream containing OpenAPI description to parse and use the mappings.</param>
|
|
||||||
/// <param name="diagnostic">Returns diagnostic object containing errors detected during parsing</param>
|
|
||||||
[PublicAPI]
|
|
||||||
public static IWireMockServer WithMappingFromOpenApiStream(this IWireMockServer server, Stream stream, out OpenApiDiagnostic diagnostic)
|
|
||||||
{
|
|
||||||
return WithMappingFromOpenApiStream(server, stream, new WireMockOpenApiParserSettings(), out diagnostic);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Register the mappings via an OpenAPI (swagger) V2 or V3 stream.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="server">The WireMockServer instance</param>
|
|
||||||
/// <param name="stream">Stream containing OpenAPI description to parse and use the mappings.</param>
|
|
||||||
/// <param name="settings">Additional settings</param>
|
|
||||||
/// <param name="diagnostic">Returns diagnostic object containing errors detected during parsing</param>
|
|
||||||
[PublicAPI]
|
|
||||||
public static IWireMockServer WithMappingFromOpenApiStream(this IWireMockServer server, Stream stream, WireMockOpenApiParserSettings settings, out OpenApiDiagnostic diagnostic)
|
|
||||||
{
|
|
||||||
Guard.NotNull(server);
|
|
||||||
Guard.NotNull(stream);
|
|
||||||
Guard.NotNull(settings);
|
|
||||||
|
|
||||||
var mappings = new WireMockOpenApiParser().FromStream(stream, settings, out diagnostic);
|
|
||||||
|
|
||||||
return server.WithMapping(mappings.ToArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Register the mappings via an OpenAPI (swagger) V2 or V3 document.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="server">The WireMockServer instance</param>
|
|
||||||
/// <param name="document">The OpenAPI document to use as mappings.</param>
|
|
||||||
/// <param name="settings">Additional settings [optional].</param>
|
|
||||||
[PublicAPI]
|
|
||||||
public static IWireMockServer WithMappingFromOpenApiDocument(this IWireMockServer server, OpenApiDocument document, WireMockOpenApiParserSettings? settings = null)
|
|
||||||
{
|
|
||||||
Guard.NotNull(server);
|
|
||||||
Guard.NotNull(document);
|
|
||||||
|
|
||||||
var mappings = new WireMockOpenApiParser().FromDocument(document, settings);
|
|
||||||
|
|
||||||
return server.WithMapping(mappings.ToArray());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
// Copyright © WireMock.Net
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using Microsoft.OpenApi.Models;
|
|
||||||
using Microsoft.OpenApi.Readers;
|
|
||||||
using WireMock.Admin.Mappings;
|
|
||||||
using WireMock.Net.OpenApiParser.Settings;
|
|
||||||
|
|
||||||
namespace WireMock.Net.OpenApiParser;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Parse a OpenApi/Swagger/V2/V3 or Raml to WireMock MappingModels.
|
|
||||||
/// </summary>
|
|
||||||
public interface IWireMockOpenApiParser
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Generate <see cref="IReadOnlyList{MappingModel}"/> from a file-path.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="path">The path to read the OpenApi/Swagger/V2/V3 or Raml file.</param>
|
|
||||||
/// <param name="diagnostic">OpenApiDiagnostic output</param>
|
|
||||||
/// <returns>MappingModel</returns>
|
|
||||||
IReadOnlyList<MappingModel> FromFile(string path, out OpenApiDiagnostic diagnostic);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generate <see cref="IReadOnlyList{MappingModel}"/> from a file-path.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="path">The path to read the OpenApi/Swagger/V2/V3 or Raml file.</param>
|
|
||||||
/// <param name="settings">Additional settings</param>
|
|
||||||
/// <param name="diagnostic">OpenApiDiagnostic output</param>
|
|
||||||
/// <returns>MappingModel</returns>
|
|
||||||
IReadOnlyList<MappingModel> FromFile(string path, WireMockOpenApiParserSettings settings, out OpenApiDiagnostic diagnostic);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generate <see cref="IReadOnlyList{MappingModel}"/> from an <seealso cref="OpenApiDocument"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="document">The source OpenApiDocument</param>
|
|
||||||
/// <param name="settings">Additional settings [optional]</param>
|
|
||||||
/// <returns>MappingModel</returns>
|
|
||||||
IReadOnlyList<MappingModel> FromDocument(OpenApiDocument document, WireMockOpenApiParserSettings? settings = null);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generate <see cref="IReadOnlyList{MappingModel}"/> from a <seealso cref="Stream"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="stream">The source stream</param>
|
|
||||||
/// <param name="diagnostic">OpenApiDiagnostic output</param>
|
|
||||||
/// <returns>MappingModel</returns>
|
|
||||||
IReadOnlyList<MappingModel> FromStream(Stream stream, out OpenApiDiagnostic diagnostic);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generate <see cref="IReadOnlyList{MappingModel}"/> from a <seealso cref="Stream"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="stream">The source stream</param>
|
|
||||||
/// <param name="settings">Additional settings</param>
|
|
||||||
/// <param name="diagnostic">OpenApiDiagnostic output</param>
|
|
||||||
/// <returns>MappingModel</returns>
|
|
||||||
IReadOnlyList<MappingModel> FromStream(Stream stream, WireMockOpenApiParserSettings settings, out OpenApiDiagnostic diagnostic);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generate <see cref="IReadOnlyList{MappingModel}"/> from a <seealso cref="string"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="text">The source text</param>
|
|
||||||
/// <param name="diagnostic">OpenApiDiagnostic output</param>
|
|
||||||
/// <returns>MappingModel</returns>
|
|
||||||
IReadOnlyList<MappingModel> FromText(string text, out OpenApiDiagnostic diagnostic);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generate <see cref="IReadOnlyList{MappingModel}"/> from a <seealso cref="string"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="text">The source text</param>
|
|
||||||
/// <param name="settings">Additional settings</param>
|
|
||||||
/// <param name="diagnostic">OpenApiDiagnostic output</param>
|
|
||||||
/// <returns>MappingModel</returns>
|
|
||||||
IReadOnlyList<MappingModel> FromText(string text, WireMockOpenApiParserSettings settings, out OpenApiDiagnostic diagnostic);
|
|
||||||
}
|
|
||||||
@@ -1,399 +0,0 @@
|
|||||||
// Copyright © WireMock.Net
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using Microsoft.OpenApi;
|
|
||||||
using Microsoft.OpenApi.Any;
|
|
||||||
using Microsoft.OpenApi.Models;
|
|
||||||
using Microsoft.OpenApi.Writers;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
using Stef.Validation;
|
|
||||||
using WireMock.Admin.Mappings;
|
|
||||||
using WireMock.Net.OpenApiParser.Extensions;
|
|
||||||
using WireMock.Net.OpenApiParser.Settings;
|
|
||||||
using WireMock.Net.OpenApiParser.Types;
|
|
||||||
using WireMock.Net.OpenApiParser.Utils;
|
|
||||||
|
|
||||||
namespace WireMock.Net.OpenApiParser.Mappers;
|
|
||||||
|
|
||||||
internal class OpenApiPathsMapper
|
|
||||||
{
|
|
||||||
private const string HeaderContentType = "Content-Type";
|
|
||||||
|
|
||||||
private readonly WireMockOpenApiParserSettings _settings;
|
|
||||||
private readonly ExampleValueGenerator _exampleValueGenerator;
|
|
||||||
|
|
||||||
public OpenApiPathsMapper(WireMockOpenApiParserSettings settings)
|
|
||||||
{
|
|
||||||
_settings = Guard.NotNull(settings);
|
|
||||||
_exampleValueGenerator = new ExampleValueGenerator(settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IReadOnlyList<MappingModel> ToMappingModels(OpenApiPaths? paths, IList<OpenApiServer> servers)
|
|
||||||
{
|
|
||||||
return paths?
|
|
||||||
.OrderBy(p => p.Key)
|
|
||||||
.Select(p => MapPath(p.Key, p.Value, servers))
|
|
||||||
.SelectMany(x => x)
|
|
||||||
.ToArray() ??
|
|
||||||
Array.Empty<MappingModel>();
|
|
||||||
}
|
|
||||||
|
|
||||||
private IReadOnlyList<MappingModel> MapPaths(OpenApiPaths? paths, IList<OpenApiServer> servers)
|
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
var queryParameters = operation.Parameters.Where(p => p.In == ParameterLocation.Query);
|
|
||||||
var pathParameters = operation.Parameters.Where(p => p.In == ParameterLocation.Path);
|
|
||||||
var headers = operation.Parameters.Where(p => p.In == ParameterLocation.Header);
|
|
||||||
|
|
||||||
var response = operation.Responses.FirstOrDefault();
|
|
||||||
|
|
||||||
TryGetContent(response.Value?.Content, out OpenApiMediaType? responseContent, out string? responseContentType);
|
|
||||||
var responseSchema = response.Value?.Content?.FirstOrDefault().Value?.Schema;
|
|
||||||
var responseExample = responseContent?.Example;
|
|
||||||
var responseSchemaExample = responseContent?.Schema?.Example;
|
|
||||||
|
|
||||||
var body = responseExample != null ? MapOpenApiAnyToJToken(responseExample) :
|
|
||||||
responseSchemaExample != null ? MapOpenApiAnyToJToken(responseSchemaExample) :
|
|
||||||
MapSchemaToObject(responseSchema);
|
|
||||||
|
|
||||||
var requestBodyModel = new BodyModel();
|
|
||||||
if (operation.RequestBody != null && operation.RequestBody.Content != null && operation.RequestBody.Required)
|
|
||||||
{
|
|
||||||
var request = operation.RequestBody.Content;
|
|
||||||
TryGetContent(request, out OpenApiMediaType? requestContent, out _);
|
|
||||||
|
|
||||||
var requestBodySchema = operation.RequestBody.Content.First().Value?.Schema;
|
|
||||||
var requestBodyExample = requestContent!.Example;
|
|
||||||
var requestBodySchemaExample = requestContent.Schema?.Example;
|
|
||||||
|
|
||||||
var requestBodyMapped = requestBodyExample != null ? MapOpenApiAnyToJToken(requestBodyExample) :
|
|
||||||
requestBodySchemaExample != null ? MapOpenApiAnyToJToken(requestBodySchemaExample) :
|
|
||||||
MapSchemaToObject(requestBodySchema);
|
|
||||||
|
|
||||||
requestBodyModel = MapRequestBody(requestBodyMapped);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!int.TryParse(response.Key, out var httpStatusCode))
|
|
||||||
{
|
|
||||||
httpStatusCode = 200;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new MappingModel
|
|
||||||
{
|
|
||||||
Guid = Guid.NewGuid(),
|
|
||||||
Request = new RequestModel
|
|
||||||
{
|
|
||||||
Methods = [httpMethod],
|
|
||||||
Path = PathUtils.Combine(MapBasePath(servers), MapPathWithParameters(path, pathParameters)),
|
|
||||||
Params = MapQueryParameters(queryParameters),
|
|
||||||
Headers = MapRequestHeaders(headers),
|
|
||||||
Body = requestBodyModel
|
|
||||||
},
|
|
||||||
Response = new ResponseModel
|
|
||||||
{
|
|
||||||
StatusCode = httpStatusCode,
|
|
||||||
Headers = MapHeaders(responseContentType, response.Value?.Headers),
|
|
||||||
BodyAsJson = body
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private BodyModel? MapRequestBody(object? requestBody)
|
|
||||||
{
|
|
||||||
if (requestBody == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new BodyModel
|
|
||||||
{
|
|
||||||
Matcher = new MatcherModel
|
|
||||||
{
|
|
||||||
Name = "JsonMatcher",
|
|
||||||
Pattern = JsonConvert.SerializeObject(requestBody, Formatting.Indented),
|
|
||||||
IgnoreCase = _settings.RequestBodyIgnoreCase
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool TryGetContent(IDictionary<string, OpenApiMediaType>? contents, [NotNullWhen(true)] out OpenApiMediaType? openApiMediaType, [NotNullWhen(true)] out string? contentType)
|
|
||||||
{
|
|
||||||
openApiMediaType = null;
|
|
||||||
contentType = null;
|
|
||||||
|
|
||||||
if (contents == null || contents.Values.Count == 0)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (contents.TryGetValue("application/json", out var content))
|
|
||||||
{
|
|
||||||
openApiMediaType = content;
|
|
||||||
contentType = "application/json";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var first = contents.FirstOrDefault();
|
|
||||||
openApiMediaType = first.Value;
|
|
||||||
contentType = first.Key;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private object? MapSchemaToObject(OpenApiSchema? schema, string? name = null)
|
|
||||||
{
|
|
||||||
if (schema == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (schema.GetSchemaType())
|
|
||||||
{
|
|
||||||
case SchemaType.Array:
|
|
||||||
var jArray = new JArray();
|
|
||||||
for (int i = 0; i < _settings.NumberOfArrayItems; i++)
|
|
||||||
{
|
|
||||||
if (schema.Items.Properties.Count > 0)
|
|
||||||
{
|
|
||||||
var arrayItem = new JObject();
|
|
||||||
foreach (var property in schema.Items.Properties)
|
|
||||||
{
|
|
||||||
var objectValue = MapSchemaToObject(property.Value, property.Key);
|
|
||||||
if (objectValue is JProperty jp)
|
|
||||||
{
|
|
||||||
arrayItem.Add(jp);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
arrayItem.Add(new JProperty(property.Key, objectValue));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
jArray.Add(arrayItem);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var arrayItem = MapSchemaToObject(schema.Items, name: null); // Set name to null to force JObject instead of JProperty
|
|
||||||
jArray.Add(arrayItem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (schema.AllOf.Count > 0)
|
|
||||||
{
|
|
||||||
jArray.Add(MapSchemaAllOfToObject(schema));
|
|
||||||
}
|
|
||||||
|
|
||||||
return jArray;
|
|
||||||
|
|
||||||
case SchemaType.Boolean:
|
|
||||||
case SchemaType.Integer:
|
|
||||||
case SchemaType.Number:
|
|
||||||
case SchemaType.String:
|
|
||||||
return _exampleValueGenerator.GetExampleValue(schema);
|
|
||||||
|
|
||||||
case SchemaType.Object:
|
|
||||||
var propertyAsJObject = new JObject();
|
|
||||||
foreach (var schemaProperty in schema.Properties)
|
|
||||||
{
|
|
||||||
propertyAsJObject.Add(MapPropertyAsJObject(schemaProperty.Value, schemaProperty.Key));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (schema.AllOf.Count > 0)
|
|
||||||
{
|
|
||||||
foreach (var group in schema.AllOf.SelectMany(p => p.Properties).GroupBy(x => x.Key))
|
|
||||||
{
|
|
||||||
propertyAsJObject.Add(MapPropertyAsJObject(group.First().Value, group.Key));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return name != null ? new JProperty(name, propertyAsJObject) : propertyAsJObject;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private JObject MapSchemaAllOfToObject(OpenApiSchema schema)
|
|
||||||
{
|
|
||||||
var arrayItem = new JObject();
|
|
||||||
foreach (var property in schema.AllOf)
|
|
||||||
{
|
|
||||||
foreach (var item in property.Properties)
|
|
||||||
{
|
|
||||||
arrayItem.Add(MapPropertyAsJObject(item.Value, item.Key));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return arrayItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
private object MapPropertyAsJObject(OpenApiSchema openApiSchema, string key)
|
|
||||||
{
|
|
||||||
if (openApiSchema.GetSchemaType() == SchemaType.Object || openApiSchema.GetSchemaType() == SchemaType.Array)
|
|
||||||
{
|
|
||||||
var mapped = MapSchemaToObject(openApiSchema, key);
|
|
||||||
if (mapped is JProperty jp)
|
|
||||||
{
|
|
||||||
return jp;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new JProperty(key, mapped);
|
|
||||||
}
|
|
||||||
|
|
||||||
// bool propertyIsNullable = openApiSchema.Nullable || (openApiSchema.TryGetXNullable(out bool x) && x);
|
|
||||||
return new JProperty(key, _exampleValueGenerator.GetExampleValue(openApiSchema));
|
|
||||||
}
|
|
||||||
|
|
||||||
private string MapPathWithParameters(string path, IEnumerable<OpenApiParameter>? parameters)
|
|
||||||
{
|
|
||||||
if (parameters == null)
|
|
||||||
{
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
string newPath = path;
|
|
||||||
foreach (var parameter in parameters)
|
|
||||||
{
|
|
||||||
var exampleMatcherModel = GetExampleMatcherModel(parameter.Schema, _settings.PathPatternToUse);
|
|
||||||
newPath = newPath.Replace($"{{{parameter.Name}}}", exampleMatcherModel.Pattern as string);
|
|
||||||
}
|
|
||||||
|
|
||||||
return newPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string MapBasePath(IList<OpenApiServer>? servers)
|
|
||||||
{
|
|
||||||
if (servers == null || servers.Count == 0)
|
|
||||||
{
|
|
||||||
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))
|
|
||||||
{
|
|
||||||
mappedHeaders.TryAdd(HeaderContentType, responseContentType!);
|
|
||||||
}
|
|
||||||
|
|
||||||
return mappedHeaders.Keys.Any() ? mappedHeaders : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private IList<ParamModel>? MapQueryParameters(IEnumerable<OpenApiParameter> queryParameters)
|
|
||||||
{
|
|
||||||
var list = queryParameters
|
|
||||||
.Where(req => req.Required)
|
|
||||||
.Select(qp => new ParamModel
|
|
||||||
{
|
|
||||||
Name = qp.Name,
|
|
||||||
IgnoreCase = _settings.QueryParameterPatternIgnoreCase,
|
|
||||||
Matchers = new[]
|
|
||||||
{
|
|
||||||
GetExampleMatcherModel(qp.Schema, _settings.QueryParameterPatternToUse)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
return list.Any() ? list : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private IList<HeaderModel>? MapRequestHeaders(IEnumerable<OpenApiParameter> headers)
|
|
||||||
{
|
|
||||||
var list = headers
|
|
||||||
.Where(req => req.Required)
|
|
||||||
.Select(qp => new HeaderModel
|
|
||||||
{
|
|
||||||
Name = qp.Name,
|
|
||||||
IgnoreCase = _settings.HeaderPatternIgnoreCase,
|
|
||||||
Matchers = new[]
|
|
||||||
{
|
|
||||||
GetExampleMatcherModel(qp.Schema, _settings.HeaderPatternToUse)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
return list.Any() ? list : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private MatcherModel GetExampleMatcherModel(OpenApiSchema? schema, ExampleValueType type)
|
|
||||||
{
|
|
||||||
return type switch
|
|
||||||
{
|
|
||||||
ExampleValueType.Value => new MatcherModel
|
|
||||||
{
|
|
||||||
Name = "ExactMatcher",
|
|
||||||
Pattern = GetExampleValueAsStringForSchemaType(schema),
|
|
||||||
IgnoreCase = _settings.IgnoreCaseExampleValues
|
|
||||||
},
|
|
||||||
|
|
||||||
_ => new MatcherModel
|
|
||||||
{
|
|
||||||
Name = "WildcardMatcher",
|
|
||||||
Pattern = "*"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetExampleValueAsStringForSchemaType(OpenApiSchema? schema)
|
|
||||||
{
|
|
||||||
var value = _exampleValueGenerator.GetExampleValue(schema);
|
|
||||||
|
|
||||||
return value switch
|
|
||||||
{
|
|
||||||
string valueAsString => valueAsString,
|
|
||||||
|
|
||||||
_ => value.ToString(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
// Copyright © WireMock.Net
|
|
||||||
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
[assembly: InternalsVisibleTo("WireMock.Net.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100e138ec44d93acac565953052636eb8d5e7e9f27ddb030590055cd1a0ab2069a5623f1f77ca907d78e0b37066ca0f6d63da7eecc3fcb65b76aa8ebeccf7ebe1d11264b8404cd9b1cbbf2c83f566e033b3e54129f6ef28daffff776ba7aebbc53c0d635ebad8f45f78eb3f7e0459023c218f003416e080f96a1a3c5ffeb56bee9e")]
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
// Copyright © WireMock.Net
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using Microsoft.OpenApi.Models;
|
|
||||||
|
|
||||||
namespace WireMock.Net.OpenApiParser.Settings;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A interface defining the example values to use for the different types.
|
|
||||||
/// </summary>
|
|
||||||
public interface IWireMockOpenApiParserExampleValues
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// An example value for a Boolean.
|
|
||||||
/// </summary>
|
|
||||||
bool Boolean { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// An example value for an Integer.
|
|
||||||
/// </summary>
|
|
||||||
int Integer { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// An example value for a Float.
|
|
||||||
/// </summary>
|
|
||||||
float Float { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// An example value for a Double.
|
|
||||||
/// </summary>
|
|
||||||
double Double { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// An example value for a Date.
|
|
||||||
/// </summary>
|
|
||||||
Func<DateTime> Date { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// An example value for a DateTime.
|
|
||||||
/// </summary>
|
|
||||||
Func<DateTime> DateTime { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// An example value for Bytes.
|
|
||||||
/// </summary>
|
|
||||||
byte[] Bytes { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// An example value for a Object.
|
|
||||||
/// </summary>
|
|
||||||
object Object { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// An example value for a String.
|
|
||||||
/// </summary>
|
|
||||||
string String { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// OpenApi Schema to generate dynamic examples more accurate
|
|
||||||
/// </summary>
|
|
||||||
OpenApiSchema? Schema { get; set; }
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
// Copyright © WireMock.Net
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using Microsoft.OpenApi.Models;
|
|
||||||
using RandomDataGenerator.FieldOptions;
|
|
||||||
using RandomDataGenerator.Randomizers;
|
|
||||||
|
|
||||||
namespace WireMock.Net.OpenApiParser.Settings;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A class defining the random example values to use for the different types.
|
|
||||||
/// </summary>
|
|
||||||
public class WireMockOpenApiParserDynamicExampleValues : IWireMockOpenApiParserExampleValues
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
public virtual bool Boolean => RandomizerFactory.GetRandomizer(new FieldOptionsBoolean()).Generate() ?? true;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public virtual int Integer => RandomizerFactory.GetRandomizer(new FieldOptionsInteger()).Generate() ?? 42;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public virtual float Float => RandomizerFactory.GetRandomizer(new FieldOptionsFloat()).Generate() ?? 4.2f;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public virtual double Double => RandomizerFactory.GetRandomizer(new FieldOptionsDouble()).Generate() ?? 4.2d;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public virtual Func<DateTime> Date => () => RandomizerFactory.GetRandomizer(new FieldOptionsDateTime()).Generate() ?? System.DateTime.UtcNow.Date;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public virtual Func<DateTime> DateTime => () => RandomizerFactory.GetRandomizer(new FieldOptionsDateTime()).Generate() ?? System.DateTime.UtcNow;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public virtual byte[] Bytes => RandomizerFactory.GetRandomizer(new FieldOptionsBytes()).Generate();
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public virtual object Object => "example-object";
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public virtual string String => RandomizerFactory.GetRandomizer(new FieldOptionsTextRegex { Pattern = @"^[0-9]{2}[A-Z]{5}[0-9]{2}" }).Generate() ?? "example-string";
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public virtual OpenApiSchema? Schema { get; set; }
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
// Copyright © WireMock.Net
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using Microsoft.OpenApi.Models;
|
|
||||||
|
|
||||||
namespace WireMock.Net.OpenApiParser.Settings;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A class defining the example values to use for the different types.
|
|
||||||
/// </summary>
|
|
||||||
public class WireMockOpenApiParserExampleValues : IWireMockOpenApiParserExampleValues
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
public virtual bool Boolean => true;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public virtual int Integer => 42;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public virtual float Float => 4.2f;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public virtual double Double => 4.2d;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public virtual Func<DateTime> Date { get; } = () => System.DateTime.UtcNow.Date;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public virtual Func<DateTime> DateTime { get; } = () => System.DateTime.UtcNow;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public virtual byte[] Bytes { get; } = { 48, 49, 50 };
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public virtual object Object => "example-object";
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public virtual string String => "example-string";
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public virtual OpenApiSchema? Schema { get; set; } = new();
|
|
||||||
}
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
// Copyright © WireMock.Net
|
|
||||||
|
|
||||||
using WireMock.Net.OpenApiParser.Types;
|
|
||||||
|
|
||||||
namespace WireMock.Net.OpenApiParser.Settings;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The WireMockOpenApiParser Settings
|
|
||||||
/// </summary>
|
|
||||||
public class WireMockOpenApiParserSettings
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The number of array items to generate (default is 3).
|
|
||||||
/// </summary>
|
|
||||||
public int NumberOfArrayItems { get; set; } = 3;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The example value type to use when generating a Path
|
|
||||||
/// </summary>
|
|
||||||
public ExampleValueType PathPatternToUse { get; set; } = ExampleValueType.Value;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The example value type to use when generating a Header
|
|
||||||
/// </summary>
|
|
||||||
public ExampleValueType HeaderPatternToUse { get; set; } = ExampleValueType.Value;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The example value type to use when generating a Query Parameter
|
|
||||||
/// </summary>
|
|
||||||
public ExampleValueType QueryParameterPatternToUse { get; set; } = ExampleValueType.Value;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The example values to use.
|
|
||||||
///
|
|
||||||
/// Default implementations are:
|
|
||||||
/// - <see cref="WireMockOpenApiParserExampleValues"/>
|
|
||||||
/// - <see cref="WireMockOpenApiParserDynamicExampleValues"/>
|
|
||||||
/// </summary>
|
|
||||||
public IWireMockOpenApiParserExampleValues? ExampleValues { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Is a Header match case-insensitive?
|
|
||||||
///
|
|
||||||
/// Default is <c>true</c>.
|
|
||||||
/// </summary>
|
|
||||||
public bool HeaderPatternIgnoreCase { get; set; } = true;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Is a Query Parameter match case-insensitive?
|
|
||||||
///
|
|
||||||
/// Default is <c>true</c>.
|
|
||||||
/// </summary>
|
|
||||||
public bool QueryParameterPatternIgnoreCase { get; set; } = true;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Is a Request Body match case-insensitive?
|
|
||||||
///
|
|
||||||
/// Default is <c>true</c>.
|
|
||||||
/// </summary>
|
|
||||||
public bool RequestBodyIgnoreCase { get; set; } = true;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Is a ExampleValue match case-insensitive?
|
|
||||||
///
|
|
||||||
/// Default is <c>true</c>.
|
|
||||||
/// </summary>
|
|
||||||
public bool IgnoreCaseExampleValues { get; set; } = true;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Are examples generated dynamically?
|
|
||||||
/// </summary>
|
|
||||||
public bool DynamicExamples { get; set; }
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
// Copyright © WireMock.Net
|
|
||||||
|
|
||||||
namespace WireMock.Net.OpenApiParser.Types;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The example value to use
|
|
||||||
/// </summary>
|
|
||||||
public enum ExampleValueType
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 1. Use a generated example value based on the SchemaType (default).
|
|
||||||
/// 2. If there is no example value defined in the schema,
|
|
||||||
/// then the <see cref="Settings.IWireMockOpenApiParserExampleValues"/> will be used (custom, fixed or dynamic).
|
|
||||||
/// </summary>
|
|
||||||
Value,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Just use a Wildcard (*) character.
|
|
||||||
/// </summary>
|
|
||||||
Wildcard
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
// Copyright © WireMock.Net
|
|
||||||
|
|
||||||
namespace WireMock.Net.OpenApiParser.Types;
|
|
||||||
|
|
||||||
internal enum SchemaFormat
|
|
||||||
{
|
|
||||||
Float,
|
|
||||||
|
|
||||||
Double,
|
|
||||||
|
|
||||||
Int32,
|
|
||||||
|
|
||||||
Int64,
|
|
||||||
|
|
||||||
Date,
|
|
||||||
|
|
||||||
DateTime,
|
|
||||||
|
|
||||||
Password,
|
|
||||||
|
|
||||||
Byte,
|
|
||||||
|
|
||||||
Binary,
|
|
||||||
|
|
||||||
Undefined
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
// Copyright © WireMock.Net
|
|
||||||
|
|
||||||
namespace WireMock.Net.OpenApiParser.Types;
|
|
||||||
|
|
||||||
internal enum SchemaType
|
|
||||||
{
|
|
||||||
Object,
|
|
||||||
|
|
||||||
Array,
|
|
||||||
|
|
||||||
String,
|
|
||||||
|
|
||||||
Integer,
|
|
||||||
|
|
||||||
Number,
|
|
||||||
|
|
||||||
Boolean,
|
|
||||||
|
|
||||||
File,
|
|
||||||
|
|
||||||
Unknown
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
// Copyright © WireMock.Net
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Globalization;
|
|
||||||
|
|
||||||
namespace WireMock.Net.OpenApiParser.Utils;
|
|
||||||
|
|
||||||
internal static class DateTimeUtils
|
|
||||||
{
|
|
||||||
public static string ToRfc3339DateTime(DateTime dateTime)
|
|
||||||
{
|
|
||||||
return dateTime.ToString("yyyy-MM-dd'T'HH:mm:ss.fffzzz", DateTimeFormatInfo.InvariantInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string ToRfc3339Date(DateTime dateTime)
|
|
||||||
{
|
|
||||||
return dateTime.ToString("yyyy-MM-dd", DateTimeFormatInfo.InvariantInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
// Copyright © WireMock.Net
|
|
||||||
|
|
||||||
namespace WireMock.Net.OpenApiParser.Utils;
|
|
||||||
|
|
||||||
internal static class PathUtils
|
|
||||||
{
|
|
||||||
internal static string Combine(params string[] paths)
|
|
||||||
{
|
|
||||||
if (paths.Length == 0)
|
|
||||||
{
|
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
var result = paths[0].Trim().TrimEnd('/');
|
|
||||||
|
|
||||||
for (int i = 1; i < paths.Length; i++)
|
|
||||||
{
|
|
||||||
var nextPath = paths[i].Trim().TrimStart('/').TrimEnd('/');
|
|
||||||
if (!string.IsNullOrEmpty(nextPath))
|
|
||||||
{
|
|
||||||
result += '/' + nextPath;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<Description>An OpenApi (swagger) parser to generate MappingModel or mapping.json file.</Description>
|
|
||||||
<TargetFrameworks>net46;netstandard2.0;netstandard2.1</TargetFrameworks>
|
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
|
||||||
<PackageTags>wiremock;openapi;OAS;raml;converter;parser;openapiparser</PackageTags>
|
|
||||||
<ProjectGuid>{D3804228-91F4-4502-9595-39584E5AADAD}</ProjectGuid>
|
|
||||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
|
||||||
<CodeAnalysisRuleSet>../WireMock.Net/WireMock.Net.ruleset</CodeAnalysisRuleSet>
|
|
||||||
<SignAssembly>true</SignAssembly>
|
|
||||||
<AssemblyOriginatorKeyFile>../WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
|
|
||||||
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
|
|
||||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
|
|
||||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
|
||||||
<PackageReference Include="Microsoft.OpenApi.Readers" Version="1.2.3" />
|
|
||||||
<PackageReference Include="Nullable" Version="1.3.1">
|
|
||||||
<PrivateAssets>all</PrivateAssets>
|
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
|
||||||
</PackageReference>
|
|
||||||
<PackageReference Include="RamlToOpenApiConverter" Version="0.6.1" />
|
|
||||||
<PackageReference Include="RandomDataGenerator.Net" Version="1.0.18" />
|
|
||||||
<PackageReference Include="Stef.Validation" Version="0.1.1" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\WireMock.Net.Abstractions\WireMock.Net.Abstractions.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
// Copyright © WireMock.Net
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Text;
|
|
||||||
using JetBrains.Annotations;
|
|
||||||
using Microsoft.OpenApi.Models;
|
|
||||||
using Microsoft.OpenApi.Readers;
|
|
||||||
using RamlToOpenApiConverter;
|
|
||||||
using WireMock.Admin.Mappings;
|
|
||||||
using WireMock.Net.OpenApiParser.Mappers;
|
|
||||||
using WireMock.Net.OpenApiParser.Settings;
|
|
||||||
|
|
||||||
namespace WireMock.Net.OpenApiParser;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Parse a OpenApi/Swagger/V2/V3 or Raml to WireMock.Net MappingModels.
|
|
||||||
/// </summary>
|
|
||||||
public class WireMockOpenApiParser : IWireMockOpenApiParser
|
|
||||||
{
|
|
||||||
private readonly OpenApiStreamReader _reader = new();
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
[PublicAPI]
|
|
||||||
public IReadOnlyList<MappingModel> FromFile(string path, out OpenApiDiagnostic diagnostic)
|
|
||||||
{
|
|
||||||
return FromFile(path, new WireMockOpenApiParserSettings(), out diagnostic);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
[PublicAPI]
|
|
||||||
public IReadOnlyList<MappingModel> FromFile(string path, WireMockOpenApiParserSettings settings, out OpenApiDiagnostic diagnostic)
|
|
||||||
{
|
|
||||||
OpenApiDocument document;
|
|
||||||
if (Path.GetExtension(path).EndsWith("raml", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
diagnostic = new OpenApiDiagnostic();
|
|
||||||
document = new RamlConverter().ConvertToOpenApiDocument(path);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var reader = new OpenApiStreamReader();
|
|
||||||
document = reader.Read(File.OpenRead(path), out diagnostic);
|
|
||||||
}
|
|
||||||
|
|
||||||
return FromDocument(document, settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
[PublicAPI]
|
|
||||||
public IReadOnlyList<MappingModel> FromDocument(OpenApiDocument document, WireMockOpenApiParserSettings? settings = null)
|
|
||||||
{
|
|
||||||
return new OpenApiPathsMapper(settings ?? new WireMockOpenApiParserSettings()).ToMappingModels(document.Paths, document.Servers);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
[PublicAPI]
|
|
||||||
public IReadOnlyList<MappingModel> FromStream(Stream stream, out OpenApiDiagnostic diagnostic)
|
|
||||||
{
|
|
||||||
return FromDocument(_reader.Read(stream, out diagnostic));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
[PublicAPI]
|
|
||||||
public IReadOnlyList<MappingModel> FromStream(Stream stream, WireMockOpenApiParserSettings settings, out OpenApiDiagnostic diagnostic)
|
|
||||||
{
|
|
||||||
return FromDocument(_reader.Read(stream, out diagnostic), settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
[PublicAPI]
|
|
||||||
public IReadOnlyList<MappingModel> FromText(string text, out OpenApiDiagnostic diagnostic)
|
|
||||||
{
|
|
||||||
return FromStream(new MemoryStream(Encoding.UTF8.GetBytes(text)), out diagnostic);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
[PublicAPI]
|
|
||||||
public IReadOnlyList<MappingModel> FromText(string text, WireMockOpenApiParserSettings settings, out OpenApiDiagnostic diagnostic)
|
|
||||||
{
|
|
||||||
return FromStream(new MemoryStream(Encoding.UTF8.GetBytes(text)), settings, out diagnostic);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user