diff --git a/src/WireMock.Net.Abstractions/Admin/Settings/SettingsModel.cs b/src/WireMock.Net.Abstractions/Admin/Settings/SettingsModel.cs
index 602d0cb1..ea5e628e 100644
--- a/src/WireMock.Net.Abstractions/Admin/Settings/SettingsModel.cs
+++ b/src/WireMock.Net.Abstractions/Admin/Settings/SettingsModel.cs
@@ -89,4 +89,11 @@ public class SettingsModel
/// Don't save the response-string in the LogEntry when WithBody(Func{IRequestMessage, string}) or WithBody(Func{IRequestMessage, Task{string}}) is used. (default set to false).
///
public bool? DoNotSaveDynamicResponseInLogEntry { get; set; }
+
+ ///
+ /// See .
+ ///
+ /// Default value = "All".
+ ///
+ public QueryParameterMultipleValueSupport? QueryParameterMultipleValueSupport { get; set; }
}
\ No newline at end of file
diff --git a/src/WireMock.Net.Abstractions/IRequestMessage.cs b/src/WireMock.Net.Abstractions/IRequestMessage.cs
index ca80ec89..f747f7c5 100644
--- a/src/WireMock.Net.Abstractions/IRequestMessage.cs
+++ b/src/WireMock.Net.Abstractions/IRequestMessage.cs
@@ -28,7 +28,7 @@ public interface IRequestMessage
///
/// The ProxyUrl (if a proxy is used).
///
- string ProxyUrl { get; set; }
+ string? ProxyUrl { get; set; }
///
/// Gets the DateTime.
diff --git a/src/WireMock.Net.Abstractions/Types/QueryParameterMultipleValueSupport.cs b/src/WireMock.Net.Abstractions/Types/QueryParameterMultipleValueSupport.cs
new file mode 100644
index 00000000..b8fe260e
--- /dev/null
+++ b/src/WireMock.Net.Abstractions/Types/QueryParameterMultipleValueSupport.cs
@@ -0,0 +1,28 @@
+using System;
+
+namespace WireMock.Types;
+
+[Flags]
+public enum QueryParameterMultipleValueSupport
+{
+ // Support none
+ None = 0x0,
+
+ // Support "&" as multi-value-separator --> "key=value&key=anotherValue"
+ Ampersand = 0x1,
+
+ // Support ";" as multi-value-separator --> "key=value;key=anotherValue"
+ SemiColon = 0x2,
+
+ // Support "," as multi-value-separator --> "key=1,2"
+ Comma = 0x4,
+
+ // Support "&" and ";" as multi-value-separator --> "key=value&key=anotherValue" and also "key=value;key=anotherValue"
+ AmpersandAndSemiColon = Ampersand | SemiColon,
+
+ // Support "&" and ";" as multi-value-separator
+ NoComma = AmpersandAndSemiColon,
+
+ // Support all multi-value-separators ("&" and ";" and ",")
+ All = Ampersand | SemiColon | Comma
+}
\ No newline at end of file
diff --git a/src/WireMock.Net.OpenApiParser/Extensions/DictionaryExtensions.cs b/src/WireMock.Net.OpenApiParser/Extensions/DictionaryExtensions.cs
index e9924ed1..d81e7aa3 100644
--- a/src/WireMock.Net.OpenApiParser/Extensions/DictionaryExtensions.cs
+++ b/src/WireMock.Net.OpenApiParser/Extensions/DictionaryExtensions.cs
@@ -1,21 +1,20 @@
#if NET46 || NETSTANDARD2_0
using System.Collections.Generic;
-namespace WireMock.Net.OpenApiParser.Extensions
+namespace WireMock.Net.OpenApiParser.Extensions;
+
+internal static class DictionaryExtensions
{
- internal static class DictionaryExtensions
+ public static bool TryAdd(this Dictionary? dictionary, TKey key, TValue value)
{
- public static bool TryAdd(this Dictionary dictionary, TKey key, TValue value)
+ if (dictionary is null || dictionary.ContainsKey(key))
{
- if (dictionary is null || dictionary.ContainsKey(key))
- {
- return false;
- }
-
- dictionary[key] = value;
-
- return true;
+ return false;
}
+
+ dictionary[key] = value;
+
+ return true;
}
}
-#endif
+#endif
\ No newline at end of file
diff --git a/src/WireMock.Net.OpenApiParser/Extensions/OpenApiSchemaExtensions.cs b/src/WireMock.Net.OpenApiParser/Extensions/OpenApiSchemaExtensions.cs
index 2307f7fb..405a282e 100644
--- a/src/WireMock.Net.OpenApiParser/Extensions/OpenApiSchemaExtensions.cs
+++ b/src/WireMock.Net.OpenApiParser/Extensions/OpenApiSchemaExtensions.cs
@@ -1,92 +1,91 @@
-using Microsoft.OpenApi.Any;
+using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Interfaces;
using Microsoft.OpenApi.Models;
using WireMock.Net.OpenApiParser.Types;
-namespace WireMock.Net.OpenApiParser.Extensions
+namespace WireMock.Net.OpenApiParser.Extensions;
+
+internal static class OpenApiSchemaExtensions
{
- internal static class OpenApiSchemaExtensions
+ ///
+ /// https://stackoverflow.com/questions/48111459/how-to-define-a-property-that-can-be-string-or-null-in-openapi-swagger
+ ///
+ public static bool TryGetXNullable(this OpenApiSchema schema, out bool value)
{
- ///
- /// https://stackoverflow.com/questions/48111459/how-to-define-a-property-that-can-be-string-or-null-in-openapi-swagger
- ///
- public static bool TryGetXNullable(this OpenApiSchema schema, out bool value)
+ value = false;
+
+ if (schema.Extensions.TryGetValue("x-nullable", out IOpenApiExtension e) && e is OpenApiBoolean openApiBoolean)
{
- value = false;
-
- if (schema.Extensions.TryGetValue("x-nullable", out IOpenApiExtension e) && e is OpenApiBoolean openApiBoolean)
- {
- value = openApiBoolean.Value;
- return true;
- }
-
- return false;
+ value = openApiBoolean.Value;
+ return true;
}
- public static SchemaType GetSchemaType(this OpenApiSchema schema)
+ return false;
+ }
+
+ public static SchemaType GetSchemaType(this OpenApiSchema? schema)
+ {
+ switch (schema?.Type)
{
- switch (schema?.Type)
- {
- case "object":
- return SchemaType.Object;
+ case "object":
+ return SchemaType.Object;
- case "array":
- return SchemaType.Array;
+ case "array":
+ return SchemaType.Array;
- case "integer":
- return SchemaType.Integer;
+ case "integer":
+ return SchemaType.Integer;
- case "number":
- return SchemaType.Number;
+ case "number":
+ return SchemaType.Number;
- case "boolean":
- return SchemaType.Boolean;
+ case "boolean":
+ return SchemaType.Boolean;
- case "string":
- return SchemaType.String;
+ case "string":
+ return SchemaType.String;
- case "file":
- return SchemaType.File;
+ case "file":
+ return SchemaType.File;
- default:
- return SchemaType.Unknown;
- }
+ default:
+ return SchemaType.Unknown;
}
+ }
- public static SchemaFormat GetSchemaFormat(this OpenApiSchema schema)
+ public static SchemaFormat GetSchemaFormat(this OpenApiSchema? schema)
+ {
+ switch (schema?.Format)
{
- switch (schema?.Format)
- {
- case "float":
- return SchemaFormat.Float;
+ case "float":
+ return SchemaFormat.Float;
- case "double":
- return SchemaFormat.Double;
+ case "double":
+ return SchemaFormat.Double;
- case "int32":
- return SchemaFormat.Int32;
+ case "int32":
+ return SchemaFormat.Int32;
- case "int64":
- return SchemaFormat.Int64;
+ case "int64":
+ return SchemaFormat.Int64;
- case "date":
- return SchemaFormat.Date;
+ case "date":
+ return SchemaFormat.Date;
- case "date-time":
- return SchemaFormat.DateTime;
+ case "date-time":
+ return SchemaFormat.DateTime;
- case "password":
- return SchemaFormat.Password;
+ case "password":
+ return SchemaFormat.Password;
- case "byte":
- return SchemaFormat.Byte;
+ case "byte":
+ return SchemaFormat.Byte;
- case "binary":
- return SchemaFormat.Binary;
+ case "binary":
+ return SchemaFormat.Binary;
- default:
- return SchemaFormat.Undefined;
- }
+ default:
+ return SchemaFormat.Undefined;
}
}
}
\ No newline at end of file
diff --git a/src/WireMock.Net.OpenApiParser/Extensions/WireMockServerExtensions.cs b/src/WireMock.Net.OpenApiParser/Extensions/WireMockServerExtensions.cs
index d195c36c..f174ca18 100644
--- a/src/WireMock.Net.OpenApiParser/Extensions/WireMockServerExtensions.cs
+++ b/src/WireMock.Net.OpenApiParser/Extensions/WireMockServerExtensions.cs
@@ -1,97 +1,94 @@
-using System.IO;
+using System.IO;
using System.Linq;
-using System.Runtime.InteropServices.ComTypes;
using JetBrains.Annotations;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.Readers;
-using SharpYaml.Model;
using Stef.Validation;
using WireMock.Net.OpenApiParser.Settings;
using WireMock.Server;
-namespace WireMock.Net.OpenApiParser.Extensions
+namespace WireMock.Net.OpenApiParser.Extensions;
+
+///
+/// Some extension methods for .
+///
+public static class WireMockServerExtensions
{
///
- /// Some extension methods for .
+ /// Register the mappings via an OpenAPI (swagger) V2 or V3 file.
///
- public static class WireMockServerExtensions
+ /// The WireMockServer instance
+ /// Path containing OpenAPI file to parse and use the mappings.
+ /// Returns diagnostic object containing errors detected during parsing
+ [PublicAPI]
+ public static IWireMockServer WithMappingFromOpenApiFile(this IWireMockServer server, string path, out OpenApiDiagnostic diagnostic)
{
- ///
- /// Register the mappings via an OpenAPI (swagger) V2 or V3 file.
- ///
- /// The WireMockServer instance
- /// Path containing OpenAPI file to parse and use the mappings.
- /// Returns diagnostic object containing errors detected during parsing
- [PublicAPI]
- public static IWireMockServer WithMappingFromOpenApiFile(this IWireMockServer server, string path, out OpenApiDiagnostic diagnostic)
- {
- return WithMappingFromOpenApiFile(server, path, null, out diagnostic);
- }
+ return WithMappingFromOpenApiFile(server, path, new WireMockOpenApiParserSettings(), out diagnostic);
+ }
- ///
- /// Register the mappings via an OpenAPI (swagger) V2 or V3 file.
- ///
- /// The WireMockServer instance
- /// Path containing OpenAPI file to parse and use the mappings.
- /// Returns diagnostic object containing errors detected during parsing
- /// Additional settings
- [PublicAPI]
- public static IWireMockServer WithMappingFromOpenApiFile(this IWireMockServer server, string path, WireMockOpenApiParserSettings settings, out OpenApiDiagnostic diagnostic)
- {
- Guard.NotNull(server, nameof(server));
- Guard.NotNullOrEmpty(path, nameof(path));
+ ///
+ /// Register the mappings via an OpenAPI (swagger) V2 or V3 file.
+ ///
+ /// The WireMockServer instance
+ /// Path containing OpenAPI file to parse and use the mappings.
+ /// Returns diagnostic object containing errors detected during parsing
+ /// Additional settings
+ [PublicAPI]
+ public static IWireMockServer WithMappingFromOpenApiFile(this IWireMockServer server, string path, WireMockOpenApiParserSettings settings, out OpenApiDiagnostic diagnostic)
+ {
+ Guard.NotNull(server, nameof(server));
+ Guard.NotNullOrEmpty(path, nameof(path));
- var mappings = new WireMockOpenApiParser().FromFile(path, settings, out diagnostic);
+ var mappings = new WireMockOpenApiParser().FromFile(path, settings, out diagnostic);
- return server.WithMapping(mappings.ToArray());
- }
+ return server.WithMapping(mappings.ToArray());
+ }
- ///
- /// Register the mappings via an OpenAPI (swagger) V2 or V3 stream.
- ///
- /// The WireMockServer instance
- /// Stream containing OpenAPI description to parse and use the mappings.
- /// Returns diagnostic object containing errors detected during parsing
- [PublicAPI]
- public static IWireMockServer WithMappingFromOpenApiStream(this IWireMockServer server, Stream stream, out OpenApiDiagnostic diagnostic)
- {
- return WithMappingFromOpenApiStream(server, stream, null, out diagnostic);
- }
+ ///
+ /// Register the mappings via an OpenAPI (swagger) V2 or V3 stream.
+ ///
+ /// The WireMockServer instance
+ /// Stream containing OpenAPI description to parse and use the mappings.
+ /// Returns diagnostic object containing errors detected during parsing
+ [PublicAPI]
+ public static IWireMockServer WithMappingFromOpenApiStream(this IWireMockServer server, Stream stream, out OpenApiDiagnostic diagnostic)
+ {
+ return WithMappingFromOpenApiStream(server, stream, new WireMockOpenApiParserSettings(), out diagnostic);
+ }
- ///
- /// Register the mappings via an OpenAPI (swagger) V2 or V3 stream.
- ///
- /// The WireMockServer instance
- /// Stream containing OpenAPI description to parse and use the mappings.
- /// Additional settings
- /// Returns diagnostic object containing errors detected during parsing
- [PublicAPI]
- public static IWireMockServer WithMappingFromOpenApiStream(this IWireMockServer server, Stream stream, WireMockOpenApiParserSettings settings, out OpenApiDiagnostic diagnostic)
- {
- Guard.NotNull(server, nameof(server));
- Guard.NotNull(stream, nameof(stream));
- Guard.NotNull(settings, nameof(settings));
+ ///
+ /// Register the mappings via an OpenAPI (swagger) V2 or V3 stream.
+ ///
+ /// The WireMockServer instance
+ /// Stream containing OpenAPI description to parse and use the mappings.
+ /// Additional settings
+ /// Returns diagnostic object containing errors detected during parsing
+ [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);
+ var mappings = new WireMockOpenApiParser().FromStream(stream, settings, out diagnostic);
- return server.WithMapping(mappings.ToArray());
- }
+ return server.WithMapping(mappings.ToArray());
+ }
- ///
- /// Register the mappings via an OpenAPI (swagger) V2 or V3 document.
- ///
- /// The WireMockServer instance
- /// The OpenAPI document to use as mappings.
- /// Additional settings [optional]
- [PublicAPI]
- public static IWireMockServer WithMappingFromOpenApiDocument(this IWireMockServer server, OpenApiDocument document, WireMockOpenApiParserSettings settings = null)
- {
- Guard.NotNull(server, nameof(server));
- Guard.NotNull(document, nameof(document));
+ ///
+ /// Register the mappings via an OpenAPI (swagger) V2 or V3 document.
+ ///
+ /// The WireMockServer instance
+ /// The OpenAPI document to use as mappings.
+ /// Additional settings [optional]
+ [PublicAPI]
+ public static IWireMockServer WithMappingFromOpenApiDocument(this IWireMockServer server, OpenApiDocument document, WireMockOpenApiParserSettings settings)
+ {
+ Guard.NotNull(server);
+ Guard.NotNull(document);
- var mappings = new WireMockOpenApiParser().FromDocument(document, settings);
+ var mappings = new WireMockOpenApiParser().FromDocument(document, settings);
- return server.WithMapping(mappings.ToArray());
- }
+ return server.WithMapping(mappings.ToArray());
}
}
\ No newline at end of file
diff --git a/src/WireMock.Net.OpenApiParser/IWireMockOpenApiParser.cs b/src/WireMock.Net.OpenApiParser/IWireMockOpenApiParser.cs
index 660f890d..a22e144b 100644
--- a/src/WireMock.Net.OpenApiParser/IWireMockOpenApiParser.cs
+++ b/src/WireMock.Net.OpenApiParser/IWireMockOpenApiParser.cs
@@ -1,4 +1,4 @@
-using System.Collections.Generic;
+using System.Collections.Generic;
using System.IO;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.Readers;
@@ -35,7 +35,7 @@ namespace WireMock.Net.OpenApiParser
/// The source OpenApiDocument
/// Additional settings [optional]
/// MappingModel
- IEnumerable FromDocument(OpenApiDocument document, WireMockOpenApiParserSettings settings = null);
+ IEnumerable FromDocument(OpenApiDocument document, WireMockOpenApiParserSettings? settings = null);
///
/// Generate from a .
diff --git a/src/WireMock.Net.OpenApiParser/Mappers/OpenApiPathsMapper.cs b/src/WireMock.Net.OpenApiParser/Mappers/OpenApiPathsMapper.cs
index 8b1e73b6..ae1701bc 100644
--- a/src/WireMock.Net.OpenApiParser/Mappers/OpenApiPathsMapper.cs
+++ b/src/WireMock.Net.OpenApiParser/Mappers/OpenApiPathsMapper.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using Microsoft.OpenApi;
@@ -15,371 +16,365 @@ using WireMock.Net.OpenApiParser.Settings;
using WireMock.Net.OpenApiParser.Types;
using WireMock.Net.OpenApiParser.Utils;
-namespace WireMock.Net.OpenApiParser.Mappers
+namespace WireMock.Net.OpenApiParser.Mappers;
+
+internal class OpenApiPathsMapper
{
- internal class OpenApiPathsMapper
+ private const string HeaderContentType = "Content-Type";
+
+ private readonly WireMockOpenApiParserSettings _settings;
+ private readonly ExampleValueGenerator _exampleValueGenerator;
+
+ public OpenApiPathsMapper(WireMockOpenApiParserSettings settings)
{
- private const string HeaderContentType = "Content-Type";
+ _settings = Guard.NotNull(settings);
+ _exampleValueGenerator = new ExampleValueGenerator(settings);
+ }
- private readonly WireMockOpenApiParserSettings _settings;
- private readonly ExampleValueGenerator _exampleValueGenerator;
+ public IEnumerable ToMappingModels(OpenApiPaths paths, IList servers)
+ {
+ return paths.Select(p => MapPath(p.Key, p.Value, servers)).SelectMany(x => x);
+ }
- public OpenApiPathsMapper(WireMockOpenApiParserSettings settings)
+ private IEnumerable MapPaths(OpenApiPaths paths, IList servers)
+ {
+ return paths.Select(p => MapPath(p.Key, p.Value, servers)).SelectMany(x => x);
+ }
+
+ private IEnumerable MapPath(string path, OpenApiPathItem pathItem, IList servers)
+ {
+ return pathItem.Operations.Select(o => MapOperationToMappingModel(path, o.Key.ToString().ToUpperInvariant(), o.Value, servers));
+ }
+
+ private MappingModel MapOperationToMappingModel(string path, string httpMethod, OpenApiOperation operation, IList 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)
{
- _settings = Guard.NotNull(settings, nameof(settings));
- _exampleValueGenerator = new ExampleValueGenerator(settings);
+ 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);
}
- public IEnumerable ToMappingModels(OpenApiPaths paths, IList servers)
+ if (!int.TryParse(response.Key, out var httpStatusCode))
{
- return paths.Select(p => MapPath(p.Key, p.Value, servers)).SelectMany(x => x);
+ httpStatusCode = 200;
}
- private IEnumerable MapPaths(OpenApiPaths paths, IList servers)
+ return new MappingModel
{
- return paths.Select(p => MapPath(p.Key, p.Value, servers)).SelectMany(x => x);
- }
-
- private IEnumerable MapPath(string path, OpenApiPathItem pathItem, IList servers)
- {
- return pathItem.Operations.Select(o => MapOperationToMappingModel(path, o.Key.ToString().ToUpperInvariant(), o.Value, servers));
- }
-
- private MappingModel MapOperationToMappingModel(string path, string httpMethod, OpenApiOperation operation, IList 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)
+ Guid = Guid.NewGuid(),
+ Request = new RequestModel
{
- var request = operation.RequestBody.Content;
- TryGetContent(request, out OpenApiMediaType requestContent, out string requestContentType);
-
- 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);
+ Methods = new[] { httpMethod },
+ Path = 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
}
+ };
+ }
- if (!int.TryParse(response.Key, out var httpStatusCode))
+ private BodyModel? MapRequestBody(object? requestBody)
+ {
+ if (requestBody == null)
+ {
+ return null;
+ }
+
+ return new BodyModel
+ {
+ Matcher = new MatcherModel
{
- httpStatusCode = 200;
+ Name = "JsonMatcher",
+ Pattern = JsonConvert.SerializeObject(requestBody, Formatting.Indented),
+ IgnoreCase = _settings.RequestBodyIgnoreCase
}
+ };
+ }
- return new MappingModel
- {
- Guid = Guid.NewGuid(),
- Request = new RequestModel
+ private bool TryGetContent(IDictionary? 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++)
{
- Methods = new[] { httpMethod },
- Path = 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 bool TryGetContent(IDictionary contents, out OpenApiMediaType openApiMediaType, 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)
{
- if (schema.Items.Properties.Count > 0)
+ var arrayItem = new JObject();
+ foreach (var property in schema.Items.Properties)
{
- var arrayItem = new JObject();
- foreach (var property in schema.Items.Properties)
+ var objectValue = MapSchemaToObject(property.Value, property.Key);
+ if (objectValue is JProperty jp)
{
- var objectValue = MapSchemaToObject(property.Value, property.Key);
- if (objectValue is JProperty jp)
- {
- arrayItem.Add(jp);
- }
- else
- {
- arrayItem.Add(new JProperty(property.Key, objectValue));
- }
+ arrayItem.Add(jp);
}
-
- jArray.Add(arrayItem);
- }
- else
- {
- jArray.Add(MapSchemaToObject(schema.Items, name));
- }
- }
-
- 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 property in schema.AllOf)
- {
- foreach (var item in property.Properties)
+ else
{
- propertyAsJObject.Add(MapPropertyAsJObject(item.Value, item.Key));
+ arrayItem.Add(new JProperty(property.Key, objectValue));
}
}
+
+ jArray.Add(arrayItem);
+ }
+ else
+ {
+ jArray.Add(MapSchemaToObject(schema.Items, name));
}
-
- return name != null ? new JProperty(name, propertyAsJObject) : (JToken)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)
+ if (schema.AllOf.Count > 0)
{
- return jp;
+ jArray.Add(MapSchemaAllOfToObject(schema));
}
- else
+
+ 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)
{
- return new JProperty(key, mapped);
+ propertyAsJObject.Add(MapPropertyAsJObject(schemaProperty.Value, schemaProperty.Key));
}
- }
- else
+
+ if (schema.AllOf.Count > 0)
+ {
+ foreach (var property in schema.AllOf)
+ {
+ foreach (var item in property.Properties)
+ {
+ propertyAsJObject.Add(MapPropertyAsJObject(item.Value, item.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)
{
- // bool propertyIsNullable = openApiSchema.Nullable || (openApiSchema.TryGetXNullable(out bool x) && x);
- return new JProperty(key, _exampleValueGenerator.GetExampleValue(openApiSchema));
+ arrayItem.Add(MapPropertyAsJObject(item.Value, item.Key));
}
}
+ return arrayItem;
+ }
- private string MapPathWithParameters(string path, IEnumerable parameters)
+ private object MapPropertyAsJObject(OpenApiSchema openApiSchema, string key)
+ {
+ if (openApiSchema.GetSchemaType() == SchemaType.Object || openApiSchema.GetSchemaType() == SchemaType.Array)
{
- if (parameters == null)
+ var mapped = MapSchemaToObject(openApiSchema, key);
+ if (mapped is JProperty jp)
{
- return path;
+ return jp;
}
- 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;
+ return new JProperty(key, mapped);
}
- private string MapBasePath(IList servers)
+ // bool propertyIsNullable = openApiSchema.Nullable || (openApiSchema.TryGetXNullable(out bool x) && x);
+ return new JProperty(key, _exampleValueGenerator.GetExampleValue(openApiSchema));
+ }
+
+ private string MapPathWithParameters(string path, IEnumerable? parameters)
+ {
+ if (parameters == null)
{
- if (servers == null || servers.Count == 0)
- {
- return string.Empty;
- }
+ return path;
+ }
- OpenApiServer server = servers.First();
- if (Uri.TryCreate(server.Url, UriKind.RelativeOrAbsolute, out Uri uriResult))
- {
- return uriResult.IsAbsoluteUri ? uriResult.AbsolutePath : uriResult.ToString();
- }
+ 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? servers)
+ {
+ if (servers == null || servers.Count == 0)
+ {
return string.Empty;
}
- private JToken MapOpenApiAnyToJToken(IOpenApiAny any)
+ OpenApiServer server = servers.First();
+ if (Uri.TryCreate(server.Url, UriKind.RelativeOrAbsolute, out Uri uriResult))
{
- 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());
- }
- else
- {
- return JObject.Parse(outputString.ToString());
- }
+ return uriResult.IsAbsoluteUri ? uriResult.AbsolutePath : uriResult.ToString();
}
- private IDictionary MapHeaders(string responseContentType, IDictionary headers)
+ return string.Empty;
+ }
+
+ private JToken? MapOpenApiAnyToJToken(IOpenApiAny? any)
+ {
+ if (any == null)
{
- var mappedHeaders = headers.ToDictionary(
- item => item.Key,
- item => GetExampleMatcherModel(null, _settings.HeaderPatternToUse).Pattern
- );
-
- if (!string.IsNullOrEmpty(responseContentType))
- {
- mappedHeaders.TryAdd(HeaderContentType, responseContentType);
- }
-
- return mappedHeaders.Keys.Any() ? mappedHeaders : null;
+ return null;
}
- private IList MapQueryParameters(IEnumerable queryParameters)
+ using var outputString = new StringWriter();
+ var writer = new OpenApiJsonWriter(outputString);
+ any.Write(writer, OpenApiSpecVersion.OpenApi3_0);
+
+ if (any.AnyType == AnyType.Array)
{
- var list = queryParameters
- .Where(req => req.Required)
- .Select(qp => new ParamModel
+ return JArray.Parse(outputString.ToString());
+ }
+
+ return JObject.Parse(outputString.ToString());
+ }
+
+ private IDictionary? MapHeaders(string responseContentType, IDictionary headers)
+ {
+ var mappedHeaders = headers.ToDictionary(
+ item => item.Key,
+ _ => GetExampleMatcherModel(null, _settings.HeaderPatternToUse).Pattern
+ );
+
+ if (!string.IsNullOrEmpty(responseContentType))
+ {
+ mappedHeaders.TryAdd(HeaderContentType, responseContentType);
+ }
+
+ return mappedHeaders.Keys.Any() ? mappedHeaders : null;
+ }
+
+ private IList? MapQueryParameters(IEnumerable queryParameters)
+ {
+ var list = queryParameters
+ .Where(req => req.Required)
+ .Select(qp => new ParamModel
+ {
+ Name = qp.Name,
+ IgnoreCase = _settings.QueryParameterPatternIgnoreCase,
+ Matchers = new[]
{
- Name = qp.Name,
- IgnoreCase = _settings.QueryParameterPatternIgnoreCase,
- Matchers = new[]
- {
- GetExampleMatcherModel(qp.Schema, _settings.QueryParameterPatternToUse)
- }
- })
- .ToList();
+ GetExampleMatcherModel(qp.Schema, _settings.QueryParameterPatternToUse)
+ }
+ })
+ .ToList();
- return list.Any() ? list : null;
- }
+ return list.Any() ? list : null;
+ }
- private IList MapRequestHeaders(IEnumerable headers)
- {
- var list = headers
- .Where(req => req.Required)
- .Select(qp => new HeaderModel
+ private IList? MapRequestHeaders(IEnumerable headers)
+ {
+ var list = headers
+ .Where(req => req.Required)
+ .Select(qp => new HeaderModel
+ {
+ Name = qp.Name,
+ IgnoreCase = _settings.HeaderPatternIgnoreCase,
+ Matchers = new[]
{
- Name = qp.Name,
- IgnoreCase = _settings.HeaderPatternIgnoreCase,
- Matchers = new[]
- {
- GetExampleMatcherModel(qp.Schema, _settings.HeaderPatternToUse)
- }
- })
- .ToList();
+ GetExampleMatcherModel(qp.Schema, _settings.HeaderPatternToUse)
+ }
+ })
+ .ToList();
- return list.Any() ? list : null;
- }
+ return list.Any() ? list : null;
+ }
- private MatcherModel GetExampleMatcherModel(OpenApiSchema schema, ExampleValueType type)
+ private MatcherModel GetExampleMatcherModel(OpenApiSchema? schema, ExampleValueType type)
+ {
+ return type switch
{
- return type switch
- {
- ExampleValueType.Value => new MatcherModel { Name = "ExactMatcher", Pattern = GetExampleValueAsStringForSchemaType(schema), IgnoreCase = _settings.IgnoreCaseExampleValues },
+ ExampleValueType.Value => new MatcherModel { Name = "ExactMatcher", Pattern = GetExampleValueAsStringForSchemaType(schema), IgnoreCase = _settings.IgnoreCaseExampleValues },
- _ => new MatcherModel { Name = "WildcardMatcher", Pattern = "*" }
- };
- }
+ _ => new MatcherModel { Name = "WildcardMatcher", Pattern = "*" }
+ };
+ }
- private string GetExampleValueAsStringForSchemaType(OpenApiSchema schema)
+ private string GetExampleValueAsStringForSchemaType(OpenApiSchema? schema)
+ {
+ var value = _exampleValueGenerator.GetExampleValue(schema);
+
+ return value switch
{
- var value = _exampleValueGenerator.GetExampleValue(schema);
+ string valueAsString => valueAsString,
- return value switch
- {
- string valueAsString => valueAsString,
-
- _ => value.ToString(),
- };
- }
+ _ => value.ToString(),
+ };
}
}
\ No newline at end of file
diff --git a/src/WireMock.Net.OpenApiParser/Settings/IWireMockOpenApiParserExampleValues.cs b/src/WireMock.Net.OpenApiParser/Settings/IWireMockOpenApiParserExampleValues.cs
index cef841f1..be65c13f 100644
--- a/src/WireMock.Net.OpenApiParser/Settings/IWireMockOpenApiParserExampleValues.cs
+++ b/src/WireMock.Net.OpenApiParser/Settings/IWireMockOpenApiParserExampleValues.cs
@@ -1,58 +1,60 @@
-using System;
+using System;
using Microsoft.OpenApi.Models;
-namespace WireMock.Net.OpenApiParser.Settings
-{
- ///
- /// A interface defining the example values to use for the different types.
- ///
- public interface IWireMockOpenApiParserExampleValues
- {
- ///
- /// An example value for a Boolean.
- ///
- bool Boolean { get; set; }
- ///
- /// An example value for an Integer.
- ///
- int Integer { get; set; }
- ///
- /// An example value for a Float.
- ///
- float Float { get; set; }
- ///
- /// An example value for a Double.
- ///
- double Double { get; set; }
-
- ///
- /// An example value for a Date.
- ///
- Func Date { get; set; }
-
- ///
- /// An example value for a DateTime.
- ///
- Func DateTime { get; set; }
-
- ///
- /// An example value for Bytes.
- ///
- byte[] Bytes { get; set; }
-
- ///
- /// An example value for a Object.
- ///
- object Object { get; set; }
-
- ///
- /// An example value for a String.
- ///
- string String { get; set; }
-
- ///
- /// OpenApi Schema to generate dynamic examples more accurate
- ///
- OpenApiSchema Schema { get; set; }
- }
+namespace WireMock.Net.OpenApiParser.Settings;
+
+///
+/// A interface defining the example values to use for the different types.
+///
+public interface IWireMockOpenApiParserExampleValues
+{
+ ///
+ /// An example value for a Boolean.
+ ///
+ bool Boolean { get; set; }
+
+ ///
+ /// An example value for an Integer.
+ ///
+ int Integer { get; set; }
+
+ ///
+ /// An example value for a Float.
+ ///
+ float Float { get; set; }
+
+ ///
+ /// An example value for a Double.
+ ///
+ double Double { get; set; }
+
+ ///
+ /// An example value for a Date.
+ ///
+ Func Date { get; set; }
+
+ ///
+ /// An example value for a DateTime.
+ ///
+ Func DateTime { get; set; }
+
+ ///
+ /// An example value for Bytes.
+ ///
+ byte[] Bytes { get; set; }
+
+ ///
+ /// An example value for a Object.
+ ///
+ object Object { get; set; }
+
+ ///
+ /// An example value for a String.
+ ///
+ string String { get; set; }
+
+ ///
+ /// OpenApi Schema to generate dynamic examples more accurate
+ ///
+ OpenApiSchema? Schema { get; set; }
}
\ No newline at end of file
diff --git a/src/WireMock.Net.OpenApiParser/Settings/WireMockOpenApiParserDynamicExampleValues.cs b/src/WireMock.Net.OpenApiParser/Settings/WireMockOpenApiParserDynamicExampleValues.cs
index 7856b887..1524fed3 100644
--- a/src/WireMock.Net.OpenApiParser/Settings/WireMockOpenApiParserDynamicExampleValues.cs
+++ b/src/WireMock.Net.OpenApiParser/Settings/WireMockOpenApiParserDynamicExampleValues.cs
@@ -1,34 +1,42 @@
-using System;
+using System;
using Microsoft.OpenApi.Models;
-using RandomDataGenerator.FieldOptions;
-using RandomDataGenerator.Randomizers;
-
-namespace WireMock.Net.OpenApiParser.Settings
-{
- ///
- /// A class defining the random example values to use for the different types.
- ///
- public class WireMockOpenApiParserDynamicExampleValues : IWireMockOpenApiParserExampleValues
- {
- ///
- public virtual bool Boolean { get { return RandomizerFactory.GetRandomizer(new FieldOptionsBoolean()).Generate() ?? true; } set { } }
- ///
- public virtual int Integer { get { return RandomizerFactory.GetRandomizer(new FieldOptionsInteger()).Generate() ?? 42; } set { } }
- ///
- public virtual float Float { get { return RandomizerFactory.GetRandomizer(new FieldOptionsFloat()).Generate() ?? 4.2f; } set { } }
- ///
- public virtual double Double { get { return RandomizerFactory.GetRandomizer(new FieldOptionsDouble()).Generate() ?? 4.2d; } set { } }
- ///
- public virtual Func Date { get { return () => RandomizerFactory.GetRandomizer(new FieldOptionsDateTime()).Generate() ?? System.DateTime.UtcNow.Date; } set { } }
- ///
- public virtual Func DateTime { get { return () => RandomizerFactory.GetRandomizer(new FieldOptionsDateTime()).Generate() ?? System.DateTime.UtcNow; } set { } }
- ///
- public virtual byte[] Bytes { get { return RandomizerFactory.GetRandomizer(new FieldOptionsBytes()).Generate(); } set { } }
- ///
- public virtual object Object { get; set; } = "example-object";
- ///
- public virtual string String { get { return RandomizerFactory.GetRandomizer(new FieldOptionsTextRegex { Pattern = @"^[0-9]{2}[A-Z]{5}[0-9]{2}" }).Generate() ?? "example-string"; } set { } }
- ///
- public virtual OpenApiSchema Schema { get; set; }
- }
+using RandomDataGenerator.FieldOptions;
+using RandomDataGenerator.Randomizers;
+
+namespace WireMock.Net.OpenApiParser.Settings;
+
+///
+/// A class defining the random example values to use for the different types.
+///
+public class WireMockOpenApiParserDynamicExampleValues : IWireMockOpenApiParserExampleValues
+{
+ ///
+ public virtual bool Boolean { get => RandomizerFactory.GetRandomizer(new FieldOptionsBoolean()).Generate() ?? true; set { } }
+
+ ///
+ public virtual int Integer { get => RandomizerFactory.GetRandomizer(new FieldOptionsInteger()).Generate() ?? 42; set { } }
+
+ ///
+ public virtual float Float { get => RandomizerFactory.GetRandomizer(new FieldOptionsFloat()).Generate() ?? 4.2f; set { } }
+
+ ///
+ public virtual double Double { get => RandomizerFactory.GetRandomizer(new FieldOptionsDouble()).Generate() ?? 4.2d; set { } }
+
+ ///
+ public virtual Func Date { get { return () => RandomizerFactory.GetRandomizer(new FieldOptionsDateTime()).Generate() ?? System.DateTime.UtcNow.Date; } set { } }
+
+ ///
+ public virtual Func DateTime { get { return () => RandomizerFactory.GetRandomizer(new FieldOptionsDateTime()).Generate() ?? System.DateTime.UtcNow; } set { } }
+
+ ///
+ public virtual byte[] Bytes { get => RandomizerFactory.GetRandomizer(new FieldOptionsBytes()).Generate(); set { } }
+
+ ///
+ public virtual object Object { get; set; } = "example-object";
+
+ ///
+ public virtual string String { get => RandomizerFactory.GetRandomizer(new FieldOptionsTextRegex { Pattern = @"^[0-9]{2}[A-Z]{5}[0-9]{2}" }).Generate() ?? "example-string"; set { } }
+
+ ///
+ public virtual OpenApiSchema? Schema { get; set; }
}
\ No newline at end of file
diff --git a/src/WireMock.Net.OpenApiParser/Settings/WireMockOpenApiParserExampleValues.cs b/src/WireMock.Net.OpenApiParser/Settings/WireMockOpenApiParserExampleValues.cs
index ece47d02..6b3af509 100644
--- a/src/WireMock.Net.OpenApiParser/Settings/WireMockOpenApiParserExampleValues.cs
+++ b/src/WireMock.Net.OpenApiParser/Settings/WireMockOpenApiParserExampleValues.cs
@@ -1,32 +1,40 @@
-using System;
+using System;
using Microsoft.OpenApi.Models;
-namespace WireMock.Net.OpenApiParser.Settings
-{
- ///
- /// A class defining the example values to use for the different types.
- ///
- public class WireMockOpenApiParserExampleValues : IWireMockOpenApiParserExampleValues
- {
- ///
- public virtual bool Boolean { get; set; } = true;
- ///
- public virtual int Integer { get; set; } = 42;
- ///
- public virtual float Float { get; set; } = 4.2f;
- ///
- public virtual double Double { get; set; } = 4.2d;
- ///
- public virtual Func Date { get; set; } = () => System.DateTime.UtcNow.Date;
- ///
- public virtual Func DateTime { get; set; } = () => System.DateTime.UtcNow;
- ///
- public virtual byte[] Bytes { get; set; } = { 48, 49, 50 };
- ///
- public virtual object Object { get; set; } = "example-object";
- ///
- public virtual string String { get; set; } = "example-string";
- ///
- public virtual OpenApiSchema Schema { get; set; } = new OpenApiSchema();
- }
+namespace WireMock.Net.OpenApiParser.Settings;
+
+///
+/// A class defining the example values to use for the different types.
+///
+public class WireMockOpenApiParserExampleValues : IWireMockOpenApiParserExampleValues
+{
+ ///
+ public virtual bool Boolean { get; set; } = true;
+
+ ///
+ public virtual int Integer { get; set; } = 42;
+
+ ///
+ public virtual float Float { get; set; } = 4.2f;
+
+ ///
+ public virtual double Double { get; set; } = 4.2d;
+
+ ///
+ public virtual Func Date { get; set; } = () => System.DateTime.UtcNow.Date;
+
+ ///
+ public virtual Func DateTime { get; set; } = () => System.DateTime.UtcNow;
+
+ ///
+ public virtual byte[] Bytes { get; set; } = { 48, 49, 50 };
+
+ ///
+ public virtual object Object { get; set; } = "example-object";
+
+ ///
+ public virtual string String { get; set; } = "example-string";
+
+ ///
+ public virtual OpenApiSchema? Schema { get; set; } = new OpenApiSchema();
}
\ No newline at end of file
diff --git a/src/WireMock.Net.OpenApiParser/Settings/WireMockOpenApiParserSettings.cs b/src/WireMock.Net.OpenApiParser/Settings/WireMockOpenApiParserSettings.cs
index 1839f6c9..cb91f846 100644
--- a/src/WireMock.Net.OpenApiParser/Settings/WireMockOpenApiParserSettings.cs
+++ b/src/WireMock.Net.OpenApiParser/Settings/WireMockOpenApiParserSettings.cs
@@ -1,64 +1,63 @@
using WireMock.Net.OpenApiParser.Types;
-namespace WireMock.Net.OpenApiParser.Settings
+namespace WireMock.Net.OpenApiParser.Settings;
+
+///
+/// The WireMockOpenApiParser Settings
+///
+public class WireMockOpenApiParserSettings
{
///
- /// The WireMockOpenApiParser Settings
+ /// The number of array items to generate (default is 3).
///
- public class WireMockOpenApiParserSettings
- {
- ///
- /// The number of array items to generate (default is 3).
- ///
- public int NumberOfArrayItems { get; set; } = 3;
+ public int NumberOfArrayItems { get; set; } = 3;
- ///
- /// The example value type to use when generating a Path
- ///
- public ExampleValueType PathPatternToUse { get; set; } = ExampleValueType.Value;
+ ///
+ /// The example value type to use when generating a Path
+ ///
+ public ExampleValueType PathPatternToUse { get; set; } = ExampleValueType.Value;
- ///
- /// The example value type to use when generating a Header
- ///
- public ExampleValueType HeaderPatternToUse { get; set; } = ExampleValueType.Value;
+ ///
+ /// The example value type to use when generating a Header
+ ///
+ public ExampleValueType HeaderPatternToUse { get; set; } = ExampleValueType.Value;
- ///
- /// The example value type to use when generating a Query Parameter
- ///
- public ExampleValueType QueryParameterPatternToUse { get; set; } = ExampleValueType.Value;
+ ///
+ /// The example value type to use when generating a Query Parameter
+ ///
+ public ExampleValueType QueryParameterPatternToUse { get; set; } = ExampleValueType.Value;
- ///
- /// The example values to use.
- ///
- /// Default implementations are:
- /// -
- /// -
- ///
- public IWireMockOpenApiParserExampleValues ExampleValues { get; set; }
+ ///
+ /// The example values to use.
+ ///
+ /// Default implementations are:
+ /// -
+ /// -
+ ///
+ public IWireMockOpenApiParserExampleValues? ExampleValues { get; set; }
- ///
- /// Is a Header match case insensitive? (default is true).
- ///
- public bool HeaderPatternIgnoreCase { get; set; } = true;
+ ///
+ /// Is a Header match case insensitive? (default is true).
+ ///
+ public bool HeaderPatternIgnoreCase { get; set; } = true;
- ///
- /// Is a Query Parameter match case insensitive? (default is true).
- ///
- public bool QueryParameterPatternIgnoreCase { get; set; } = true;
+ ///
+ /// Is a Query Parameter match case insensitive? (default is true).
+ ///
+ public bool QueryParameterPatternIgnoreCase { get; set; } = true;
- ///
- /// Is a Request Body match case insensitive? (default is true).
- ///
- public bool RequestBodyIgnoreCase { get; set; } = true;
+ ///
+ /// Is a Request Body match case insensitive? (default is true).
+ ///
+ public bool RequestBodyIgnoreCase { get; set; } = true;
- ///
- /// Is a ExampleValue match case insensitive? (default is true).
- ///
- public bool IgnoreCaseExampleValues { get; set; } = true;
+ ///
+ /// Is a ExampleValue match case insensitive? (default is true).
+ ///
+ public bool IgnoreCaseExampleValues { get; set; } = true;
- ///
- /// Are examples generated dynamically? (default is false).
- ///
- public bool DynamicExamples { get; set; } = false;
- }
+ ///
+ /// Are examples generated dynamically? (default is false).
+ ///
+ public bool DynamicExamples { get; set; } = false;
}
\ No newline at end of file
diff --git a/src/WireMock.Net.OpenApiParser/Types/ExampleValueType.cs b/src/WireMock.Net.OpenApiParser/Types/ExampleValueType.cs
index 19d63170..aabbfca9 100644
--- a/src/WireMock.Net.OpenApiParser/Types/ExampleValueType.cs
+++ b/src/WireMock.Net.OpenApiParser/Types/ExampleValueType.cs
@@ -1,20 +1,19 @@
-namespace WireMock.Net.OpenApiParser.Types
+namespace WireMock.Net.OpenApiParser.Types;
+
+///
+/// The example value to use
+///
+public enum ExampleValueType
{
///
- /// The example value to use
+ /// 1. Use a generated example value based on the SchemaType (default).
+ /// 2. If there is no example value defined in the schema,
+ /// then the will be used (custom, fixed or dynamic).
///
- public enum ExampleValueType
- {
- ///
- /// 1. Use a generated example value based on the SchemaType (default).
- /// 2. If there is no example value defined in the schema,
- /// then the will be used (custom, fixed or dynamic).
- ///
- Value,
+ Value,
- ///
- /// Just use a Wildcard (*) character.
- ///
- Wildcard
- }
+ ///
+ /// Just use a Wildcard (*) character.
+ ///
+ Wildcard
}
\ No newline at end of file
diff --git a/src/WireMock.Net.OpenApiParser/Types/SchemaFormat.cs b/src/WireMock.Net.OpenApiParser/Types/SchemaFormat.cs
index 20e6b017..0924ed24 100644
--- a/src/WireMock.Net.OpenApiParser/Types/SchemaFormat.cs
+++ b/src/WireMock.Net.OpenApiParser/Types/SchemaFormat.cs
@@ -1,25 +1,24 @@
-namespace WireMock.Net.OpenApiParser.Types
+namespace WireMock.Net.OpenApiParser.Types;
+
+internal enum SchemaFormat
{
- internal enum SchemaFormat
- {
- Float,
+ Float,
- Double,
+ Double,
- Int32,
+ Int32,
- Int64,
+ Int64,
- Date,
+ Date,
- DateTime,
+ DateTime,
- Password,
+ Password,
- Byte,
+ Byte,
- Binary,
+ Binary,
- Undefined
- }
+ Undefined
}
\ No newline at end of file
diff --git a/src/WireMock.Net.OpenApiParser/Types/SchemaType.cs b/src/WireMock.Net.OpenApiParser/Types/SchemaType.cs
index f6152347..7ccb46bf 100644
--- a/src/WireMock.Net.OpenApiParser/Types/SchemaType.cs
+++ b/src/WireMock.Net.OpenApiParser/Types/SchemaType.cs
@@ -1,21 +1,20 @@
-namespace WireMock.Net.OpenApiParser.Types
+namespace WireMock.Net.OpenApiParser.Types;
+
+internal enum SchemaType
{
- internal enum SchemaType
- {
- Object,
+ Object,
- Array,
+ Array,
- String,
+ String,
- Integer,
+ Integer,
- Number,
+ Number,
- Boolean,
+ Boolean,
- File,
+ File,
- Unknown
- }
+ Unknown
}
\ No newline at end of file
diff --git a/src/WireMock.Net.OpenApiParser/Utils/DateTimeUtils.cs b/src/WireMock.Net.OpenApiParser/Utils/DateTimeUtils.cs
index d7ef7435..dbd5d52c 100644
--- a/src/WireMock.Net.OpenApiParser/Utils/DateTimeUtils.cs
+++ b/src/WireMock.Net.OpenApiParser/Utils/DateTimeUtils.cs
@@ -1,18 +1,17 @@
-using System;
+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);
- }
+namespace WireMock.Net.OpenApiParser.Utils;
- public static string ToRfc3339Date(DateTime dateTime)
- {
- return dateTime.ToString("yyyy-MM-dd", DateTimeFormatInfo.InvariantInfo);
- }
+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);
}
}
\ No newline at end of file
diff --git a/src/WireMock.Net.OpenApiParser/Utils/ExampleValueGenerator.cs b/src/WireMock.Net.OpenApiParser/Utils/ExampleValueGenerator.cs
index 55aad19c..2bc15d1a 100644
--- a/src/WireMock.Net.OpenApiParser/Utils/ExampleValueGenerator.cs
+++ b/src/WireMock.Net.OpenApiParser/Utils/ExampleValueGenerator.cs
@@ -7,121 +7,120 @@ using WireMock.Net.OpenApiParser.Extensions;
using WireMock.Net.OpenApiParser.Settings;
using WireMock.Net.OpenApiParser.Types;
-namespace WireMock.Net.OpenApiParser.Utils
+namespace WireMock.Net.OpenApiParser.Utils;
+
+internal class ExampleValueGenerator
{
- internal class ExampleValueGenerator
+ private readonly WireMockOpenApiParserSettings _settings;
+
+ public ExampleValueGenerator(WireMockOpenApiParserSettings settings)
{
- private readonly WireMockOpenApiParserSettings _settings;
+ _settings = Guard.NotNull(settings);
- public ExampleValueGenerator(WireMockOpenApiParserSettings settings)
+ // Check if user provided an own implementation
+ if (settings.ExampleValues is null)
{
- _settings = Guard.NotNull(settings, nameof(settings));
-
- // Check if user provided an own implementation
- if (settings.ExampleValues is null)
+ if (_settings.DynamicExamples)
{
- if (_settings.DynamicExamples)
- {
- _settings.ExampleValues = new WireMockOpenApiParserDynamicExampleValues();
- }
- else
- {
- _settings.ExampleValues = new WireMockOpenApiParserExampleValues();
- }
+ _settings.ExampleValues = new WireMockOpenApiParserDynamicExampleValues();
}
- }
-
- public object GetExampleValue(OpenApiSchema schema)
- {
- var schemaExample = schema?.Example;
- var schemaEnum = GetRandomEnumValue(schema?.Enum);
-
- _settings.ExampleValues.Schema = schema;
-
- switch (schema?.GetSchemaType())
+ else
{
- case SchemaType.Boolean:
- var exampleBoolean = (OpenApiBoolean)schemaExample;
- return exampleBoolean is null ? _settings.ExampleValues.Boolean : exampleBoolean.Value;
-
- case SchemaType.Integer:
- switch (schema?.GetSchemaFormat())
- {
- case SchemaFormat.Int64:
- var exampleLong = (OpenApiLong)schemaExample;
- var enumLong = (OpenApiLong)schemaEnum;
- var valueLongEnumOrExample = enumLong is null ? exampleLong?.Value : enumLong?.Value;
- return valueLongEnumOrExample ?? _settings.ExampleValues.Integer;
-
- default:
- var exampleInteger = (OpenApiInteger)schemaExample;
- var enumInteger = (OpenApiInteger)schemaEnum;
- var valueIntegerEnumOrExample = enumInteger is null ? exampleInteger?.Value : enumInteger?.Value;
- return valueIntegerEnumOrExample ?? _settings.ExampleValues.Integer;
- }
-
- case SchemaType.Number:
- switch (schema?.GetSchemaFormat())
- {
- case SchemaFormat.Float:
- var exampleFloat = (OpenApiFloat)schemaExample;
- var enumFloat = (OpenApiFloat)schemaEnum;
- var valueFloatEnumOrExample = enumFloat is null ? exampleFloat?.Value : enumFloat?.Value;
- return valueFloatEnumOrExample ?? _settings.ExampleValues.Float;
-
- default:
- var exampleDouble = (OpenApiDouble)schemaExample;
- var enumDouble = (OpenApiDouble)schemaEnum;
- var valueDoubleEnumOrExample = enumDouble is null ? exampleDouble?.Value : enumDouble?.Value;
- return valueDoubleEnumOrExample ?? _settings.ExampleValues.Double;
- }
-
- default:
- switch (schema?.GetSchemaFormat())
- {
- case SchemaFormat.Date:
- var exampleDate = (OpenApiDate)schemaExample;
- var enumDate = (OpenApiDate)schemaEnum;
- var valueDateEnumOrExample = enumDate is null ? exampleDate?.Value : enumDate?.Value;
- return DateTimeUtils.ToRfc3339Date(valueDateEnumOrExample ?? _settings.ExampleValues.Date());
-
- case SchemaFormat.DateTime:
- var exampleDateTime = (OpenApiDateTime)schemaExample;
- var enumDateTime = (OpenApiDateTime)schemaEnum;
- var valueDateTimeEnumOrExample = enumDateTime is null ? exampleDateTime?.Value : enumDateTime?.Value;
- return DateTimeUtils.ToRfc3339DateTime(valueDateTimeEnumOrExample?.DateTime ?? _settings.ExampleValues.DateTime());
-
- case SchemaFormat.Byte:
- var exampleByte = (OpenApiByte)schemaExample;
- var enumByte = (OpenApiByte)schemaEnum;
- var valueByteEnumOrExample = enumByte is null ? exampleByte?.Value : enumByte?.Value;
- return valueByteEnumOrExample ?? _settings.ExampleValues.Bytes;
-
- case SchemaFormat.Binary:
- var exampleBinary = (OpenApiBinary)schemaExample;
- var enumBinary = (OpenApiBinary)schemaEnum;
- var valueBinaryEnumOrExample = enumBinary is null ? exampleBinary?.Value : enumBinary?.Value;
- return valueBinaryEnumOrExample ?? _settings.ExampleValues.Object;
-
- default:
- var exampleString = (OpenApiString)schemaExample;
- var enumString = (OpenApiString)schemaEnum;
- var valueStringEnumOrExample = enumString is null ? exampleString?.Value : enumString?.Value;
- return valueStringEnumOrExample ?? _settings.ExampleValues.String;
- }
+ _settings.ExampleValues = new WireMockOpenApiParserExampleValues();
}
}
-
- private static IOpenApiAny GetRandomEnumValue(IList schemaEnum)
- {
- if (schemaEnum?.Count > 0)
- {
- int maxValue = schemaEnum.Count - 1;
- int randomEnum = new Random().Next(0, maxValue);
- return schemaEnum[randomEnum];
- }
-
- return null;
- }
+ }
+
+ public object GetExampleValue(OpenApiSchema? schema)
+ {
+ var schemaExample = schema?.Example;
+ var schemaEnum = GetRandomEnumValue(schema?.Enum);
+
+ _settings.ExampleValues.Schema = schema;
+
+ switch (schema?.GetSchemaType())
+ {
+ case SchemaType.Boolean:
+ var exampleBoolean = schemaExample as OpenApiBoolean;
+ return exampleBoolean is null ? _settings.ExampleValues.Boolean : exampleBoolean.Value;
+
+ case SchemaType.Integer:
+ switch (schema?.GetSchemaFormat())
+ {
+ case SchemaFormat.Int64:
+ var exampleLong = (OpenApiLong)schemaExample;
+ var enumLong = (OpenApiLong)schemaEnum;
+ var valueLongEnumOrExample = enumLong is null ? exampleLong?.Value : enumLong?.Value;
+ return valueLongEnumOrExample ?? _settings.ExampleValues.Integer;
+
+ default:
+ var exampleInteger = (OpenApiInteger)schemaExample;
+ var enumInteger = (OpenApiInteger)schemaEnum;
+ var valueIntegerEnumOrExample = enumInteger is null ? exampleInteger?.Value : enumInteger?.Value;
+ return valueIntegerEnumOrExample ?? _settings.ExampleValues.Integer;
+ }
+
+ case SchemaType.Number:
+ switch (schema?.GetSchemaFormat())
+ {
+ case SchemaFormat.Float:
+ var exampleFloat = (OpenApiFloat)schemaExample;
+ var enumFloat = (OpenApiFloat)schemaEnum;
+ var valueFloatEnumOrExample = enumFloat is null ? exampleFloat?.Value : enumFloat?.Value;
+ return valueFloatEnumOrExample ?? _settings.ExampleValues.Float;
+
+ default:
+ var exampleDouble = (OpenApiDouble)schemaExample;
+ var enumDouble = (OpenApiDouble)schemaEnum;
+ var valueDoubleEnumOrExample = enumDouble is null ? exampleDouble?.Value : enumDouble?.Value;
+ return valueDoubleEnumOrExample ?? _settings.ExampleValues.Double;
+ }
+
+ default:
+ switch (schema?.GetSchemaFormat())
+ {
+ case SchemaFormat.Date:
+ var exampleDate = (OpenApiDate)schemaExample;
+ var enumDate = (OpenApiDate)schemaEnum;
+ var valueDateEnumOrExample = enumDate is null ? exampleDate?.Value : enumDate?.Value;
+ return DateTimeUtils.ToRfc3339Date(valueDateEnumOrExample ?? _settings.ExampleValues.Date());
+
+ case SchemaFormat.DateTime:
+ var exampleDateTime = (OpenApiDateTime)schemaExample;
+ var enumDateTime = (OpenApiDateTime)schemaEnum;
+ var valueDateTimeEnumOrExample = enumDateTime is null ? exampleDateTime?.Value : enumDateTime?.Value;
+ return DateTimeUtils.ToRfc3339DateTime(valueDateTimeEnumOrExample?.DateTime ?? _settings.ExampleValues.DateTime());
+
+ case SchemaFormat.Byte:
+ var exampleByte = (OpenApiByte)schemaExample;
+ var enumByte = (OpenApiByte)schemaEnum;
+ var valueByteEnumOrExample = enumByte is null ? exampleByte?.Value : enumByte?.Value;
+ return valueByteEnumOrExample ?? _settings.ExampleValues.Bytes;
+
+ case SchemaFormat.Binary:
+ var exampleBinary = (OpenApiBinary)schemaExample;
+ var enumBinary = (OpenApiBinary)schemaEnum;
+ var valueBinaryEnumOrExample = enumBinary is null ? exampleBinary?.Value : enumBinary?.Value;
+ return valueBinaryEnumOrExample ?? _settings.ExampleValues.Object;
+
+ default:
+ var exampleString = (OpenApiString)schemaExample;
+ var enumString = (OpenApiString)schemaEnum;
+ var valueStringEnumOrExample = enumString is null ? exampleString?.Value : enumString?.Value;
+ return valueStringEnumOrExample ?? _settings.ExampleValues.String;
+ }
+ }
+ }
+
+ private static IOpenApiAny? GetRandomEnumValue(IList? schemaEnum)
+ {
+ if (schemaEnum?.Count > 0)
+ {
+ int maxValue = schemaEnum.Count - 1;
+ int randomEnum = new Random().Next(0, maxValue);
+ return schemaEnum[randomEnum];
+ }
+
+ return null;
}
}
\ No newline at end of file
diff --git a/src/WireMock.Net.OpenApiParser/WireMock.Net.OpenApiParser.csproj b/src/WireMock.Net.OpenApiParser/WireMock.Net.OpenApiParser.csproj
index 82b29165..93fdc3c9 100644
--- a/src/WireMock.Net.OpenApiParser/WireMock.Net.OpenApiParser.csproj
+++ b/src/WireMock.Net.OpenApiParser/WireMock.Net.OpenApiParser.csproj
@@ -12,7 +12,7 @@
../WireMock.Net/WireMock.Net.snk
true
MIT
- 8.0
+ 10
@@ -22,6 +22,10 @@
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
diff --git a/src/WireMock.Net.OpenApiParser/WireMockOpenApiParser.cs b/src/WireMock.Net.OpenApiParser/WireMockOpenApiParser.cs
index 297c6033..e9ba071c 100644
--- a/src/WireMock.Net.OpenApiParser/WireMockOpenApiParser.cs
+++ b/src/WireMock.Net.OpenApiParser/WireMockOpenApiParser.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections.Generic;
using System.IO;
using JetBrains.Annotations;
@@ -9,60 +9,59 @@ using WireMock.Admin.Mappings;
using WireMock.Net.OpenApiParser.Mappers;
using WireMock.Net.OpenApiParser.Settings;
-namespace WireMock.Net.OpenApiParser
+namespace WireMock.Net.OpenApiParser;
+
+///
+/// Parse a OpenApi/Swagger/V2/V3 or Raml to WireMock.Net MappingModels.
+///
+public class WireMockOpenApiParser : IWireMockOpenApiParser
{
- ///
- /// Parse a OpenApi/Swagger/V2/V3 or Raml to WireMock.Net MappingModels.
- ///
- public class WireMockOpenApiParser : IWireMockOpenApiParser
+ private readonly OpenApiStreamReader _reader = new OpenApiStreamReader();
+
+ ///
+ [PublicAPI]
+ public IEnumerable FromFile(string path, out OpenApiDiagnostic diagnostic)
{
- private readonly OpenApiStreamReader _reader = new OpenApiStreamReader();
+ return FromFile(path, new WireMockOpenApiParserSettings(), out diagnostic);
+ }
- ///
- [PublicAPI]
- public IEnumerable FromFile(string path, out OpenApiDiagnostic diagnostic)
+ ///
+ [PublicAPI]
+ public IEnumerable FromFile(string path, WireMockOpenApiParserSettings settings, out OpenApiDiagnostic diagnostic)
+ {
+ OpenApiDocument document;
+ if (Path.GetExtension(path).EndsWith("raml", StringComparison.OrdinalIgnoreCase))
{
- return FromFile(path, new WireMockOpenApiParserSettings(), out diagnostic);
+ diagnostic = new OpenApiDiagnostic();
+ document = new RamlConverter().ConvertToOpenApiDocument(path);
+ }
+ else
+ {
+ var reader = new OpenApiStreamReader();
+ document = reader.Read(File.OpenRead(path), out diagnostic);
}
- ///
- [PublicAPI]
- public IEnumerable 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);
+ }
- return FromDocument(document, settings);
- }
+ ///
+ [PublicAPI]
+ public IEnumerable FromStream(Stream stream, out OpenApiDiagnostic diagnostic)
+ {
+ return FromDocument(_reader.Read(stream, out diagnostic));
+ }
- ///
- [PublicAPI]
- public IEnumerable FromStream(Stream stream, out OpenApiDiagnostic diagnostic)
- {
- return FromDocument(_reader.Read(stream, out diagnostic));
- }
+ ///
+ [PublicAPI]
+ public IEnumerable FromStream(Stream stream, WireMockOpenApiParserSettings settings, out OpenApiDiagnostic diagnostic)
+ {
+ return FromDocument(_reader.Read(stream, out diagnostic), settings);
+ }
- ///
- [PublicAPI]
- public IEnumerable FromStream(Stream stream, WireMockOpenApiParserSettings settings, out OpenApiDiagnostic diagnostic)
- {
- return FromDocument(_reader.Read(stream, out diagnostic), settings);
- }
-
- ///
- [PublicAPI]
- public IEnumerable FromDocument(OpenApiDocument openApiDocument, WireMockOpenApiParserSettings settings = null)
- {
- return new OpenApiPathsMapper(settings).ToMappingModels(openApiDocument.Paths, openApiDocument.Servers);
- }
+ ///
+ [PublicAPI]
+ public IEnumerable FromDocument(OpenApiDocument openApiDocument, WireMockOpenApiParserSettings? settings = null)
+ {
+ return new OpenApiPathsMapper(settings).ToMappingModels(openApiDocument.Paths, openApiDocument.Servers);
}
}
\ No newline at end of file
diff --git a/src/WireMock.Net.StandAlone/StandAloneApp.cs b/src/WireMock.Net.StandAlone/StandAloneApp.cs
index 07ab2c40..e2272978 100644
--- a/src/WireMock.Net.StandAlone/StandAloneApp.cs
+++ b/src/WireMock.Net.StandAlone/StandAloneApp.cs
@@ -15,7 +15,7 @@ namespace WireMock.Net.StandAlone;
///
public static class StandAloneApp
{
- private static readonly string Version = typeof(StandAloneApp).GetTypeInfo().Assembly.GetName().Version.ToString();
+ private static readonly string Version = typeof(StandAloneApp).GetTypeInfo().Assembly.GetName().Version!.ToString();
///
/// Start WireMock.Net standalone Server based on the WireMockServerSettings.
diff --git a/src/WireMock.Net/Owin/IWireMockMiddlewareOptions.cs b/src/WireMock.Net/Owin/IWireMockMiddlewareOptions.cs
index 929e3994..493df3e2 100644
--- a/src/WireMock.Net/Owin/IWireMockMiddlewareOptions.cs
+++ b/src/WireMock.Net/Owin/IWireMockMiddlewareOptions.cs
@@ -3,13 +3,13 @@ using System.Collections.Concurrent;
using WireMock.Handlers;
using WireMock.Logging;
using WireMock.Matchers;
+using WireMock.Types;
using WireMock.Util;
#if !USE_ASPNETCORE
using Owin;
#else
using IAppBuilder = Microsoft.AspNetCore.Builder.IApplicationBuilder;
using Microsoft.Extensions.DependencyInjection;
-using WireMock.Types;
#endif
namespace WireMock.Owin;
@@ -70,5 +70,7 @@ internal interface IWireMockMiddlewareOptions
bool? SaveUnmatchedRequests { get; set; }
- public bool? DoNotSaveDynamicResponseInLogEntry { get; set; }
+ bool? DoNotSaveDynamicResponseInLogEntry { get; set; }
+
+ QueryParameterMultipleValueSupport? QueryParameterMultipleValueSupport { get; set; }
}
\ No newline at end of file
diff --git a/src/WireMock.Net/Owin/Mappers/OwinResponseMapper.cs b/src/WireMock.Net/Owin/Mappers/OwinResponseMapper.cs
index 1b6c920f..c26c2f78 100644
--- a/src/WireMock.Net/Owin/Mappers/OwinResponseMapper.cs
+++ b/src/WireMock.Net/Owin/Mappers/OwinResponseMapper.cs
@@ -81,11 +81,11 @@ namespace WireMock.Owin.Mappers
var statusCodeType = responseMessage.StatusCode?.GetType();
switch (statusCodeType)
{
- case Type typeAsIntOrEnum when typeAsIntOrEnum == typeof(int) || typeAsIntOrEnum == typeof(int?) || typeAsIntOrEnum.GetTypeInfo().IsEnum:
+ case { } typeAsIntOrEnum when typeAsIntOrEnum == typeof(int) || typeAsIntOrEnum == typeof(int?) || typeAsIntOrEnum.GetTypeInfo().IsEnum:
response.StatusCode = MapStatusCode((int)responseMessage.StatusCode!);
break;
- case Type typeAsString when typeAsString == typeof(string):
+ case { } typeAsString when typeAsString == typeof(string):
// Note: this case will also match on null
int.TryParse(responseMessage.StatusCode as string, out int result);
response.StatusCode = MapStatusCode(result);
@@ -130,7 +130,7 @@ namespace WireMock.Owin.Mappers
switch (responseMessage.BodyData?.DetectedBodyType)
{
case BodyType.String:
- return (responseMessage.BodyData.Encoding ?? _utf8NoBom).GetBytes(responseMessage.BodyData.BodyAsString);
+ return (responseMessage.BodyData.Encoding ?? _utf8NoBom).GetBytes(responseMessage.BodyData.BodyAsString!);
case BodyType.Json:
var formatting = responseMessage.BodyData.BodyAsJsonIndented == true
@@ -143,7 +143,7 @@ namespace WireMock.Owin.Mappers
return responseMessage.BodyData.BodyAsBytes;
case BodyType.File:
- return _options.FileSystemHandler?.ReadResponseBodyAsFile(responseMessage.BodyData.BodyAsFile);
+ return _options.FileSystemHandler?.ReadResponseBodyAsFile(responseMessage.BodyData.BodyAsFile!);
}
return null;
@@ -161,7 +161,7 @@ namespace WireMock.Owin.Mappers
});
// Set other headers
- foreach (var item in responseMessage.Headers)
+ foreach (var item in responseMessage.Headers!)
{
var headerName = item.Key;
var value = item.Value;
diff --git a/src/WireMock.Net/Owin/WireMockMiddlewareOptions.cs b/src/WireMock.Net/Owin/WireMockMiddlewareOptions.cs
index 72cbe3cf..1d2c4a0e 100644
--- a/src/WireMock.Net/Owin/WireMockMiddlewareOptions.cs
+++ b/src/WireMock.Net/Owin/WireMockMiddlewareOptions.cs
@@ -87,4 +87,7 @@ internal class WireMockMiddlewareOptions : IWireMockMiddlewareOptions
///
public bool? DoNotSaveDynamicResponseInLogEntry { get; set; }
+
+ ///
+ public QueryParameterMultipleValueSupport? QueryParameterMultipleValueSupport { get; set; }
}
\ No newline at end of file
diff --git a/src/WireMock.Net/RequestMessage.cs b/src/WireMock.Net/RequestMessage.cs
index 2470ee0f..dd44bb3f 100644
--- a/src/WireMock.Net/RequestMessage.cs
+++ b/src/WireMock.Net/RequestMessage.cs
@@ -6,6 +6,7 @@ using System.Linq;
using System.Net;
using Stef.Validation;
using WireMock.Models;
+using WireMock.Owin;
using WireMock.Types;
using WireMock.Util;
@@ -26,7 +27,7 @@ public class RequestMessage : IRequestMessage
public string AbsoluteUrl { get; }
///
- public string ProxyUrl { get; set; }
+ public string? ProxyUrl { get; set; }
///
public DateTime DateTime { get; set; }
@@ -91,16 +92,36 @@ public class RequestMessage : IRequestMessage
///
public string Origin { get; }
+ ///
+ /// Used for Unit Testing
+ ///
+ public RequestMessage(
+ UrlDetails urlDetails,
+ string method,
+ string clientIP,
+ IBodyData? bodyData = null,
+ IDictionary? headers = null,
+ IDictionary? cookies = null) : this(null, urlDetails, method, clientIP, bodyData, headers, cookies)
+ {
+ }
+
///
/// Initializes a new instance of the class.
///
+ /// The.
/// The original url details.
/// The HTTP method.
/// The client IP Address.
/// The BodyData.
/// The headers.
/// The cookies.
- public RequestMessage(UrlDetails urlDetails, string method, string clientIP, IBodyData? bodyData = null, IDictionary? headers = null, IDictionary? cookies = null)
+ internal RequestMessage(
+ IWireMockMiddlewareOptions? options,
+ UrlDetails urlDetails, string method,
+ string clientIP,
+ IBodyData? bodyData = null,
+ IDictionary? headers = null,
+ IDictionary? cookies = null)
{
Guard.NotNull(urlDetails, nameof(urlDetails));
Guard.NotNull(method, nameof(method));
@@ -134,7 +155,7 @@ public class RequestMessage : IRequestMessage
Headers = headers?.ToDictionary(header => header.Key, header => new WireMockList(header.Value));
Cookies = cookies;
RawQuery = urlDetails.Url.Query;
- Query = QueryStringParser.Parse(RawQuery);
+ Query = QueryStringParser.Parse(RawQuery, options?.QueryParameterMultipleValueSupport);
}
///
diff --git a/src/WireMock.Net/Server/IRespondWithAProvider.cs b/src/WireMock.Net/Server/IRespondWithAProvider.cs
index b73d3389..55751738 100644
--- a/src/WireMock.Net/Server/IRespondWithAProvider.cs
+++ b/src/WireMock.Net/Server/IRespondWithAProvider.cs
@@ -125,9 +125,9 @@ public interface IRespondWithAProvider
///
/// Support FireAndForget for any configured Webhooks
///
- ///
+ ///
///
- IRespondWithAProvider WithWebhookFireAndForget(bool UseWebhooksFireAndForget);
+ IRespondWithAProvider WithWebhookFireAndForget(bool useWebhooksFireAndForget);
///
/// Add a Webhook to call after the response has been generated.
@@ -141,7 +141,7 @@ public interface IRespondWithAProvider
/// The .
IRespondWithAProvider WithWebhook(
string url,
- string? method = "post",
+ string method = "post",
IDictionary>? headers = null,
string? body = null,
bool useTransformer = true,
@@ -160,7 +160,7 @@ public interface IRespondWithAProvider
/// The .
IRespondWithAProvider WithWebhook(
string url,
- string? method = "post",
+ string method = "post",
IDictionary>? headers = null,
object? body = null,
bool useTransformer = true,
diff --git a/src/WireMock.Net/Server/RespondWithAProvider.cs b/src/WireMock.Net/Server/RespondWithAProvider.cs
index d2125bee..25d12286 100644
--- a/src/WireMock.Net/Server/RespondWithAProvider.cs
+++ b/src/WireMock.Net/Server/RespondWithAProvider.cs
@@ -30,7 +30,7 @@ internal class RespondWithAProvider : IRespondWithAProvider
private readonly WireMockServerSettings _settings;
private readonly bool _saveToFile;
- private bool _useWebhookFireAndForget = false;
+ private bool _useWebhookFireAndForget;
public Guid Guid { get; private set; } = Guid.NewGuid();
diff --git a/src/WireMock.Net/Server/WireMockServer.Admin.cs b/src/WireMock.Net/Server/WireMockServer.Admin.cs
index 8fd41124..89a11626 100644
--- a/src/WireMock.Net/Server/WireMockServer.Admin.cs
+++ b/src/WireMock.Net/Server/WireMockServer.Admin.cs
@@ -223,6 +223,7 @@ public partial class WireMockServer
WatchStaticMappingsInSubdirectories = _settings.WatchStaticMappingsInSubdirectories,
HostingScheme = _settings.HostingScheme,
DoNotSaveDynamicResponseInLogEntry = _settings.DoNotSaveDynamicResponseInLogEntry,
+ QueryParameterMultipleValueSupport = _settings.QueryParameterMultipleValueSupport,
#if USE_ASPNETCORE
CorsPolicyOptions = _settings.CorsPolicyOptions?.ToString()
@@ -252,6 +253,7 @@ public partial class WireMockServer
_settings.WatchStaticMappings = settings.WatchStaticMappings;
_settings.WatchStaticMappingsInSubdirectories = settings.WatchStaticMappingsInSubdirectories;
_settings.DoNotSaveDynamicResponseInLogEntry = settings.DoNotSaveDynamicResponseInLogEntry;
+ _settings.QueryParameterMultipleValueSupport = settings.QueryParameterMultipleValueSupport;
InitSettings(_settings);
diff --git a/src/WireMock.Net/Server/WireMockServer.cs b/src/WireMock.Net/Server/WireMockServer.cs
index 085cc073..52e80ef0 100644
--- a/src/WireMock.Net/Server/WireMockServer.cs
+++ b/src/WireMock.Net/Server/WireMockServer.cs
@@ -296,6 +296,7 @@ public partial class WireMockServer : IWireMockServer
_options.HandleRequestsSynchronously = settings.HandleRequestsSynchronously;
_options.SaveUnmatchedRequests = settings.SaveUnmatchedRequests;
_options.DoNotSaveDynamicResponseInLogEntry = settings.DoNotSaveDynamicResponseInLogEntry;
+ _options.QueryParameterMultipleValueSupport = settings.QueryParameterMultipleValueSupport;
if (settings.CustomCertificateDefined)
{
diff --git a/src/WireMock.Net/Settings/WireMockServerSettings.cs b/src/WireMock.Net/Settings/WireMockServerSettings.cs
index 4b525fd2..7422046a 100644
--- a/src/WireMock.Net/Settings/WireMockServerSettings.cs
+++ b/src/WireMock.Net/Settings/WireMockServerSettings.cs
@@ -258,6 +258,14 @@ namespace WireMock.Settings
[PublicAPI]
public bool? DoNotSaveDynamicResponseInLogEntry { get; set; }
+ ///
+ /// See .
+ ///
+ /// Default value = "All".
+ ///
+ [PublicAPI]
+ public QueryParameterMultipleValueSupport? QueryParameterMultipleValueSupport { get; set; }
+
///
/// Custom matcher mappings for static mappings
///
diff --git a/src/WireMock.Net/Settings/WireMockServerSettingsParser.cs b/src/WireMock.Net/Settings/WireMockServerSettingsParser.cs
index f9b77879..7b917d77 100644
--- a/src/WireMock.Net/Settings/WireMockServerSettingsParser.cs
+++ b/src/WireMock.Net/Settings/WireMockServerSettingsParser.cs
@@ -1,4 +1,3 @@
-using System;
using System.Diagnostics.CodeAnalysis;
using JetBrains.Annotations;
using Stef.Validation;
@@ -55,7 +54,8 @@ public static class WireMockServerSettingsParser
WatchStaticMappings = parser.GetBoolValue("WatchStaticMappings"),
WatchStaticMappingsInSubdirectories = parser.GetBoolValue("WatchStaticMappingsInSubdirectories"),
HostingScheme = parser.GetEnumValue(nameof(WireMockServerSettings.HostingScheme)),
- DoNotSaveDynamicResponseInLogEntry = parser.GetBoolValue(nameof(WireMockServerSettings.DoNotSaveDynamicResponseInLogEntry))
+ DoNotSaveDynamicResponseInLogEntry = parser.GetBoolValue(nameof(WireMockServerSettings.DoNotSaveDynamicResponseInLogEntry)),
+ QueryParameterMultipleValueSupport = parser.GetEnumValue(nameof(WireMockServerSettings.QueryParameterMultipleValueSupport))
};
#if USE_ASPNETCORE
diff --git a/src/WireMock.Net/Util/QueryStringParser.cs b/src/WireMock.Net/Util/QueryStringParser.cs
index 293fcd57..8e0e5f14 100644
--- a/src/WireMock.Net/Util/QueryStringParser.cs
+++ b/src/WireMock.Net/Util/QueryStringParser.cs
@@ -11,25 +11,41 @@ namespace WireMock.Util;
///
internal static class QueryStringParser
{
- public static IDictionary> Parse(string queryString)
+ private static readonly Dictionary> Empty = new();
+
+ public static IDictionary> Parse(string? queryString, QueryParameterMultipleValueSupport? support = null)
{
if (string.IsNullOrEmpty(queryString))
{
- return new Dictionary>();
+ return Empty;
}
+ var queryParameterMultipleValueSupport = support ?? QueryParameterMultipleValueSupport.All;
+
string[] JoinParts(string[] parts)
{
if (parts.Length > 1)
{
- return parts[1].Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries); // support "?key=1,2"
+ return queryParameterMultipleValueSupport.HasFlag(QueryParameterMultipleValueSupport.Comma) ?
+ parts[1].Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries) : // Support "?key=1,2"
+ new[] { parts[1] };
}
return new string[0];
}
- return queryString.TrimStart('?')
- .Split(new[] { '&', ';' }, StringSplitOptions.RemoveEmptyEntries) // Support "?key=value;key=anotherValue" and "?key=value&key=anotherValue"
+ var splitOn = new List();
+ if (queryParameterMultipleValueSupport.HasFlag(QueryParameterMultipleValueSupport.Ampersand))
+ {
+ splitOn.Add("&"); // Support "?key=value&key=anotherValue"
+ }
+ if (queryParameterMultipleValueSupport.HasFlag(QueryParameterMultipleValueSupport.SemiColon))
+ {
+ splitOn.Add(";"); // Support "?key=value;key=anotherValue"
+ }
+
+ return queryString!.TrimStart('?')
+ .Split(splitOn.ToArray(), StringSplitOptions.RemoveEmptyEntries)
.Select(parameter => parameter.Split(new[] { '=' }, 2, StringSplitOptions.RemoveEmptyEntries))
.GroupBy(parts => parts[0], JoinParts)
.ToDictionary(grouping => grouping.Key, grouping => new WireMockList(grouping.SelectMany(x => x).Select(WebUtility.UrlDecode)));
diff --git a/test/WireMock.Net.Tests/RequestTests.cs b/test/WireMock.Net.Tests/RequestTests.cs
index 9d4cd716..00e604c7 100644
--- a/test/WireMock.Net.Tests/RequestTests.cs
+++ b/test/WireMock.Net.Tests/RequestTests.cs
@@ -1,243 +1,261 @@
-using NFluent;
+using NFluent;
using System.Collections.Generic;
using WireMock.Matchers.Request;
using WireMock.Models;
+using WireMock.Owin;
using WireMock.RequestBuilders;
using WireMock.Types;
using WireMock.Util;
using Xunit;
-namespace WireMock.Net.Tests
+namespace WireMock.Net.Tests;
+
+public class RequestTests
{
- public class RequestTests
+ private const string ClientIp = "::1";
+
+ [Fact]
+ public void Should_exclude_requests_matching_given_http_method_but_not_url()
{
- private const string ClientIp = "::1";
+ // given
+ var spec = Request.Create().WithPath("/bar").UsingPut();
- [Fact]
- public void Should_exclude_requests_matching_given_http_method_but_not_url()
+ // when
+ var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp);
+
+ // then
+ var requestMatchResult = new RequestMatchResult();
+ Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsNotEqualTo(1.0);
+ }
+
+ [Fact]
+ public void Should_exclude_requests_not_matching_given_headers()
+ {
+ // given
+ var spec = Request.Create().UsingAnyMethod().WithHeader("X-toto", "tatata");
+
+ // when
+ var body = new BodyData
{
- // given
- var spec = Request.Create().WithPath("/bar").UsingPut();
+ BodyAsString = "whatever",
+ DetectedBodyType = BodyType.String
+ };
+ var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, body, new Dictionary { { "X-toto", new[] { "tata" } } });
- // when
- var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp);
+ // then
+ var requestMatchResult = new RequestMatchResult();
+ Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsNotEqualTo(1.0);
+ }
- // then
- var requestMatchResult = new RequestMatchResult();
- Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsNotEqualTo(1.0);
- }
+ [Fact]
+ public void Should_exclude_requests_not_matching_given_headers_ignorecase()
+ {
+ // given
+ var spec = Request.Create().UsingAnyMethod().WithHeader("X-toto", "abc", false);
- [Fact]
- public void Should_exclude_requests_not_matching_given_headers()
+ // when
+ var body = new BodyData
{
- // given
- var spec = Request.Create().UsingAnyMethod().WithHeader("X-toto", "tatata");
+ BodyAsString = "whatever",
+ DetectedBodyType = BodyType.String
+ };
+ var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, body, new Dictionary { { "X-toto", new[] { "ABC" } } });
- // when
- var body = new BodyData
- {
- BodyAsString = "whatever",
- DetectedBodyType = BodyType.String
- };
- var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, body, new Dictionary { { "X-toto", new[] { "tata" } } });
+ // then
+ var requestMatchResult = new RequestMatchResult();
+ Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsNotEqualTo(1.0);
+ }
- // then
- var requestMatchResult = new RequestMatchResult();
- Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsNotEqualTo(1.0);
- }
+ [Fact]
+ public void Should_specify_requests_matching_given_header_prefix()
+ {
+ // given
+ var spec = Request.Create().UsingAnyMethod().WithHeader("X-toto", "tata*");
- [Fact]
- public void Should_exclude_requests_not_matching_given_headers_ignorecase()
+ // when
+ var body = new BodyData
{
- // given
- var spec = Request.Create().UsingAnyMethod().WithHeader("X-toto", "abc", false);
+ BodyAsString = "whatever",
+ DetectedBodyType = BodyType.String
+ };
+ var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, body, new Dictionary { { "X-toto", new[] { "TaTa" } } });
- // when
- var body = new BodyData
- {
- BodyAsString = "whatever",
- DetectedBodyType = BodyType.String
- };
- var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, body, new Dictionary { { "X-toto", new[] { "ABC" } } });
+ // then
+ var requestMatchResult = new RequestMatchResult();
+ Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
+ }
- // then
- var requestMatchResult = new RequestMatchResult();
- Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsNotEqualTo(1.0);
- }
+ [Fact]
+ public void Should_specify_requests_matching_given_wildcard_header()
+ {
+ // given
+ var spec = Request.Create().UsingAnyMethod().WithHeader("X-toto", "*");
- [Fact]
- public void Should_specify_requests_matching_given_header_prefix()
+ // when
+ var body = new BodyData
{
- // given
- var spec = Request.Create().UsingAnyMethod().WithHeader("X-toto", "tata*");
+ BodyAsString = "whatever",
+ DetectedBodyType = BodyType.String
+ };
+ var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, body, new Dictionary { { "X-toto", new[] { "TaTa" } } });
- // when
- var body = new BodyData
- {
- BodyAsString = "whatever",
- DetectedBodyType = BodyType.String
- };
- var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, body, new Dictionary { { "X-toto", new[] { "TaTa" } } });
+ // then
+ var requestMatchResult = new RequestMatchResult();
+ Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
+ }
- // then
- var requestMatchResult = new RequestMatchResult();
- Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
- }
+ [Fact]
+ public void Should_specify_requests_not_matching_given_wildcard_header2()
+ {
+ // given
+ var spec = Request.Create().UsingAnyMethod().WithHeader("X-toto", "*");
- [Fact]
- public void Should_specify_requests_matching_given_wildcard_header()
+ // when
+ var body = new BodyData
{
- // given
- var spec = Request.Create().UsingAnyMethod().WithHeader("X-toto", "*");
+ BodyAsString = "whatever",
+ DetectedBodyType = BodyType.String
+ };
+ var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, body, new Dictionary { { "X-tata", new[] { "ToTo" } } });
- // when
- var body = new BodyData
- {
- BodyAsString = "whatever",
- DetectedBodyType = BodyType.String
- };
- var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, body, new Dictionary { { "X-toto", new[] { "TaTa" } } });
+ // then
+ var requestMatchResult = new RequestMatchResult();
+ Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(0.0);
+ }
- // then
- var requestMatchResult = new RequestMatchResult();
- Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
- }
+ [Fact]
+ public void Should_specify_requests_matching_given_wildcard_header_rejectonmatch()
+ {
+ // given
+ var spec = Request.Create().UsingAnyMethod().WithHeader("X-toto", "*", WireMock.Matchers.MatchBehaviour.RejectOnMatch);
- [Fact]
- public void Should_specify_requests_not_matching_given_wildcard_header2()
+ // when
+ var body = new BodyData
{
- // given
- var spec = Request.Create().UsingAnyMethod().WithHeader("X-toto", "*");
+ BodyAsString = "whatever",
+ DetectedBodyType = BodyType.String
+ };
+ var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, body, new Dictionary { { "X-tata", new[] { "ToTo" } } });
- // when
- var body = new BodyData
- {
- BodyAsString = "whatever",
- DetectedBodyType = BodyType.String
- };
- var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, body, new Dictionary { { "X-tata", new[] { "ToTo" } } });
+ // then
+ var requestMatchResult = new RequestMatchResult();
+ Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
+ }
- // then
- var requestMatchResult = new RequestMatchResult();
- Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(0.0);
- }
+ [Fact]
+ public void Should_specify_requests_not_matching_given_wildcard_header_rejectonmatch()
+ {
+ // given
+ var spec = Request.Create().UsingAnyMethod().WithHeader("X-toto", "*", WireMock.Matchers.MatchBehaviour.RejectOnMatch);
- [Fact]
- public void Should_specify_requests_matching_given_wildcard_header_rejectonmatch()
+ // when
+ var body = new BodyData
{
- // given
- var spec = Request.Create().UsingAnyMethod().WithHeader("X-toto", "*", WireMock.Matchers.MatchBehaviour.RejectOnMatch);
+ BodyAsString = "whatever",
+ DetectedBodyType = BodyType.String
+ };
+ var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, body, new Dictionary { { "X-toto", new[] { "TaTa" } } });
- // when
- var body = new BodyData
- {
- BodyAsString = "whatever",
- DetectedBodyType = BodyType.String
- };
- var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, body, new Dictionary { { "X-tata", new[] { "ToTo" } } });
+ // then
+ var requestMatchResult = new RequestMatchResult();
+ Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(0.0);
+ }
- // then
- var requestMatchResult = new RequestMatchResult();
- Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
- }
+ [Fact]
+ public void Should_specify_requests_matching_given_body()
+ {
+ // given
+ var spec = Request.Create().UsingAnyMethod().WithBody("Hello world!");
- [Fact]
- public void Should_specify_requests_not_matching_given_wildcard_header_rejectonmatch()
+ // when
+ var body = new BodyData
{
- // given
- var spec = Request.Create().UsingAnyMethod().WithHeader("X-toto", "*", WireMock.Matchers.MatchBehaviour.RejectOnMatch);
+ BodyAsString = "Hello world!",
+ DetectedBodyType = BodyType.String
+ };
+ var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, body);
- // when
- var body = new BodyData
- {
- BodyAsString = "whatever",
- DetectedBodyType = BodyType.String
- };
- var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, body, new Dictionary { { "X-toto", new[] { "TaTa" } } });
+ // then
+ var requestMatchResult = new RequestMatchResult();
+ Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
+ }
- // then
- var requestMatchResult = new RequestMatchResult();
- Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(0.0);
- }
+ [Fact]
+ public void Should_exclude_requests_not_matching_given_body()
+ {
+ // given
+ var spec = Request.Create().UsingAnyMethod().WithBody(" Hello world! ");
- [Fact]
- public void Should_specify_requests_matching_given_body()
+ // when
+ var body = new BodyData
{
- // given
- var spec = Request.Create().UsingAnyMethod().WithBody("Hello world!");
+ BodyAsString = "xxx",
+ DetectedBodyType = BodyType.String
+ };
+ var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, body, new Dictionary { { "X-toto", new[] { "tata" } } });
- // when
- var body = new BodyData
- {
- BodyAsString = "Hello world!",
- DetectedBodyType = BodyType.String
- };
- var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, body);
+ // then
+ var requestMatchResult = new RequestMatchResult();
+ Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsNotEqualTo(1.0);
+ }
- // then
- var requestMatchResult = new RequestMatchResult();
- Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
- }
+ [Fact]
+ public void Should_specify_requests_matching_given_param()
+ {
+ // given
+ var spec = Request.Create().WithParam("bar", "1", "2");
- [Fact]
- public void Should_exclude_requests_not_matching_given_body()
+ // when
+ var request = new RequestMessage(new UrlDetails("http://localhost/foo?bar=1&bar=2"), "PUT", ClientIp);
+
+ // then
+ var requestMatchResult = new RequestMatchResult();
+ Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
+ }
+
+ [Fact]
+ public void Should_specify_requests_matching_given_param_WithComma()
+ {
+ // given
+ var options = new WireMockMiddlewareOptions
{
- // given
- var spec = Request.Create().UsingAnyMethod().WithBody(" Hello world! ");
+ QueryParameterMultipleValueSupport = QueryParameterMultipleValueSupport.NoComma
+ };
+ var spec = Request.Create().WithParam("$filter", "startswith(name,'testName')");
- // when
- var body = new BodyData
- {
- BodyAsString = "xxx",
- DetectedBodyType = BodyType.String
- };
- var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, body, new Dictionary { { "X-toto", new[] { "tata" } } });
+ // when
+ var request = new RequestMessage(options, new UrlDetails("http://localhost/?$filter=startswith(name,'testName')"), "PUT", ClientIp);
- // then
- var requestMatchResult = new RequestMatchResult();
- Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsNotEqualTo(1.0);
- }
+ // then
+ var requestMatchResult = new RequestMatchResult();
+ Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
+ }
- [Fact]
- public void Should_specify_requests_matching_given_param()
- {
- // given
- var spec = Request.Create().WithParam("bar", "1", "2");
+ [Fact]
+ public void Should_specify_requests_matching_given_param_func()
+ {
+ // given
+ var spec = Request.Create().UsingAnyMethod().WithParam(p => p.ContainsKey("bar"));
- // when
- var request = new RequestMessage(new UrlDetails("http://localhost/foo?bar=1&bar=2"), "PUT", ClientIp);
+ // when
+ var request = new RequestMessage(new UrlDetails("http://localhost/foo?bar=1&bar=2"), "PUT", ClientIp);
- // then
- var requestMatchResult = new RequestMatchResult();
- Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
- }
+ // then
+ var requestMatchResult = new RequestMatchResult();
+ Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
+ }
- [Fact]
- public void Should_specify_requests_matching_given_param_func()
- {
- // given
- var spec = Request.Create().UsingAnyMethod().WithParam(p => p.ContainsKey("bar"));
+ [Fact]
+ public void Should_exclude_requests_not_matching_given_params()
+ {
+ // given
+ var spec = Request.Create().WithParam("bar", "1");
- // when
- var request = new RequestMessage(new UrlDetails("http://localhost/foo?bar=1&bar=2"), "PUT", ClientIp);
+ // when
+ var request = new RequestMessage(new UrlDetails("http://localhost/test=7"), "PUT", ClientIp);
- // then
- var requestMatchResult = new RequestMatchResult();
- Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
- }
-
- [Fact]
- public void Should_exclude_requests_not_matching_given_params()
- {
- // given
- var spec = Request.Create().WithParam("bar", "1");
-
- // when
- var request = new RequestMessage(new UrlDetails("http://localhost/test=7"), "PUT", ClientIp);
-
- // then
- var requestMatchResult = new RequestMatchResult();
- Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsNotEqualTo(1.0);
- }
+ // then
+ var requestMatchResult = new RequestMatchResult();
+ Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsNotEqualTo(1.0);
}
}
\ No newline at end of file
diff --git a/test/WireMock.Net.Tests/Util/QueryStringParserTests.cs b/test/WireMock.Net.Tests/Util/QueryStringParserTests.cs
index 14b3a0ff..c273c297 100644
--- a/test/WireMock.Net.Tests/Util/QueryStringParserTests.cs
+++ b/test/WireMock.Net.Tests/Util/QueryStringParserTests.cs
@@ -1,267 +1,308 @@
-using FluentAssertions;
+using FluentAssertions;
using System.Collections.Generic;
using WireMock.Types;
using WireMock.Util;
using Xunit;
-namespace WireMock.Net.Tests.Util
+namespace WireMock.Net.Tests.Util;
+
+public class QueryStringParserTests
{
- public class QueryStringParserTests
+ [Fact]
+ public void Parse_WithNullString()
{
- [Fact]
- public void Parse_WithNullString()
- {
- // Assign
- string query = null;
+ // Assign
+ string? query = null;
- // Act
- var result = QueryStringParser.Parse(query);
+ // Act
+ var result = QueryStringParser.Parse(query);
- // Assert
- result.Should().Equal(new Dictionary>());
- }
+ // Assert
+ result.Should().Equal(new Dictionary>());
+ }
- [Fact]
- public void Parse_WithEmptyString()
- {
- // Assign
- string query = "";
+ [Fact]
+ public void Parse_WithEmptyString()
+ {
+ // Assign
+ string query = "";
- // Act
- var result = QueryStringParser.Parse(query);
+ // Act
+ var result = QueryStringParser.Parse(query);
- // Assert
- result.Should().Equal(new Dictionary>());
- }
+ // Assert
+ result.Should().Equal(new Dictionary>());
+ }
- [Fact]
- public void Parse_WithQuestionMark()
- {
- // Assign
- string query = "?";
+ [Fact]
+ public void Parse_WithQuestionMark()
+ {
+ // Assign
+ string query = "?";
- // Act
- var result = QueryStringParser.Parse(query);
+ // Act
+ var result = QueryStringParser.Parse(query);
- // Assert
- result.Should().Equal(new Dictionary>());
- }
+ // Assert
+ result.Should().Equal(new Dictionary>());
+ }
- [Fact]
- public void Parse_With1Param()
- {
- // Assign
- string query = "?key=bla/blub.xml";
+ [Fact]
+ public void Parse_With1Param()
+ {
+ // Assign
+ string query = "?key=bla/blub.xml";
- // Act
- var result = QueryStringParser.Parse(query);
+ // Act
+ var result = QueryStringParser.Parse(query);
- // Assert
- result.Count.Should().Be(1);
- result["key"].Should().Equal(new WireMockList("bla/blub.xml"));
- }
+ // Assert
+ result.Count.Should().Be(1);
+ result["key"].Should().Equal(new WireMockList("bla/blub.xml"));
+ }
- [Fact]
- public void Parse_With2Params()
- {
- // Assign
- string query = "?x=1&y=2";
+ [Fact]
+ public void Parse_With2Params()
+ {
+ // Assign
+ string query = "?x=1&y=2";
- // Act
- var result = QueryStringParser.Parse(query);
+ // Act
+ var result = QueryStringParser.Parse(query);
- // Assert
- result.Count.Should().Be(2);
- result["x"].Should().Equal(new WireMockList("1"));
- result["y"].Should().Equal(new WireMockList("2"));
- }
+ // Assert
+ result.Count.Should().Be(2);
+ result["x"].Should().Equal(new WireMockList("1"));
+ result["y"].Should().Equal(new WireMockList("2"));
+ }
- [Fact]
- public void Parse_With1ParamNoValue()
- {
- // Assign
- string query = "?empty";
+ [Fact]
+ public void Parse_With1ParamNoValue()
+ {
+ // Assign
+ string query = "?empty";
- // Act
- var result = QueryStringParser.Parse(query);
+ // Act
+ var result = QueryStringParser.Parse(query);
- // Assert
- result.Count.Should().Be(1);
- result["empty"].Should().Equal(new WireMockList());
- }
+ // Assert
+ result.Count.Should().Be(1);
+ result["empty"].Should().Equal(new WireMockList());
+ }
- [Fact]
- public void Parse_With1ParamNoValueWithEqualSign()
- {
- // Assign
- string query = "?empty=";
+ [Fact]
+ public void Parse_With1ParamNoValueWithEqualSign()
+ {
+ // Assign
+ string query = "?empty=";
- // Act
- var result = QueryStringParser.Parse(query);
+ // Act
+ var result = QueryStringParser.Parse(query);
- // Assert
- result.Count.Should().Be(1);
- result["empty"].Should().Equal(new WireMockList());
- }
+ // Assert
+ result.Count.Should().Be(1);
+ result["empty"].Should().Equal(new WireMockList());
+ }
- [Fact]
- public void Parse_With1ParamAndJustAndSign()
- {
- // Assign
- string query = "?key=1&";
+ [Fact]
+ public void Parse_With1ParamAndJustAndSign()
+ {
+ // Assign
+ string query = "?key=1&";
- // Act
- var result = QueryStringParser.Parse(query);
+ // Act
+ var result = QueryStringParser.Parse(query);
- // Assert
- result.Count.Should().Be(1);
- result["key"].Should().Equal(new WireMockList("1"));
- }
+ // Assert
+ result.Count.Should().Be(1);
+ result["key"].Should().Equal(new WireMockList("1"));
+ }
- [Fact]
- public void Parse_With2ParamsAndWhereOneHasAQuestion()
- {
- // Assign
- string query = "?key=value?&b=c";
+ [Fact]
+ public void Parse_With2ParamsAndWhereOneHasAQuestion()
+ {
+ // Assign
+ string query = "?key=value?&b=c";
- // Act
- var result = QueryStringParser.Parse(query);
+ // Act
+ var result = QueryStringParser.Parse(query);
- // Assert
- result.Count.Should().Be(2);
- result["key"].Should().Equal(new WireMockList("value?"));
- result["b"].Should().Equal(new WireMockList("c"));
- }
+ // Assert
+ result.Count.Should().Be(2);
+ result["key"].Should().Equal(new WireMockList("value?"));
+ result["b"].Should().Equal(new WireMockList("c"));
+ }
- [Fact]
- public void Parse_With1ParamWithEqualSign()
- {
- // Assign
- string query = "?key=value=what";
+ [Fact]
+ public void Parse_With1ParamWithEqualSign()
+ {
+ // Assign
+ string query = "?key=value=what";
- // Act
- var result = QueryStringParser.Parse(query);
+ // Act
+ var result = QueryStringParser.Parse(query);
- // Assert
- result.Count.Should().Be(1);
- result["key"].Should().Equal(new WireMockList("value=what"));
- }
+ // Assert
+ result.Count.Should().Be(1);
+ result["key"].Should().Equal(new WireMockList("value=what"));
+ }
- [Fact]
- public void Parse_With1ParamWithTwoEqualSigns()
- {
- // Assign
- string query = "?key=value==what";
+ [Fact]
+ public void Parse_With1ParamWithTwoEqualSigns()
+ {
+ // Assign
+ string query = "?key=value==what";
- // Act
- var result = QueryStringParser.Parse(query);
+ // Act
+ var result = QueryStringParser.Parse(query);
- // Assert
- result.Count.Should().Be(1);
- result["key"].Should().Equal(new WireMockList("value==what"));
- }
+ // Assert
+ result.Count.Should().Be(1);
+ result["key"].Should().Equal(new WireMockList("value==what"));
+ }
- [Fact]
- public void Parse_WithMultipleParamWithSameKeySeparatedBySemiColon()
- {
- // Assign
- string query = "?key=value;key=anotherValue";
+ [Fact]
+ public void Parse_WithMultipleParamWithSameKeySeparatedBySemiColon()
+ {
+ // Assign
+ string query = "?key=value;key=anotherValue";
- // Act
- var result = QueryStringParser.Parse(query);
+ // Act
+ var result = QueryStringParser.Parse(query);
- // Assert
- result.Count.Should().Be(1);
- result["key"].Should().Equal(new WireMockList(new[] { "value", "anotherValue" }));
- }
+ // Assert
+ result.Count.Should().Be(1);
+ result["key"].Should().Equal(new WireMockList("value", "anotherValue"));
+ }
- [Fact]
- public void Parse_With1ParamContainingComma()
- {
- // Assign
- string query = "?key=1,2&key=3";
+ [Fact]
+ public void Parse_WithMultipleParamWithSameKeySeparatedByAmp()
+ {
+ // Assign
+ string query = "?key=1&key=2";
- // Act
- var result = QueryStringParser.Parse(query);
+ // Act
+ var result = QueryStringParser.Parse(query);
- // Assert
- result.Count.Should().Be(1);
- result["key"].Should().Equal(new WireMockList(new[] { "1", "2", "3" }));
- }
+ // Assert
+ result.Count.Should().Be(1);
+ result["key"].Should().Equal(new WireMockList("1", "2"));
+ }
- [Fact]
- public void Parse_With1ParamContainingEscapedAnd()
- {
- // Assign
- string query = "?winkel=C%26A";
+ [Fact]
+ public void Parse_With1ParamContainingComma_When_SupportMultiValueUsingComma_Is_True()
+ {
+ // Assign
+ string query = "?key=1,2,3";
- // Act
- var result = QueryStringParser.Parse(query);
+ // Act
+ var result = QueryStringParser.Parse(query);
- // Assert
- result.Count.Should().Be(1);
- result["winkel"].Should().Equal(new WireMockList(new[] { "C&A" }));
- }
+ // Assert
+ result.Count.Should().Be(1);
+ result["key"].Should().Equal(new WireMockList("1", "2", "3"));
+ }
- [Fact]
- public void Parse_With1ParamContainingParentheses()
- {
- // Assign
- string query = "?Transaction=(123)";
+ [Fact]
+ public void Parse_With1ParamContainingCommaAndAmpCombined_When_SupportMultiValueUsingComma_Is_Comma()
+ {
+ // Assign
+ string query = "?key=1,2&key=3";
- // Act
- var result = QueryStringParser.Parse(query);
+ // Act
+ var result = QueryStringParser.Parse(query);
- // Assert
- result.Count.Should().Be(1);
- result["Transaction"].Should().Equal(new WireMockList(new[] { "(123)" }));
- }
+ // Assert
+ result.Count.Should().Be(1);
+ result["key"].Should().Equal(new WireMockList("1", "2", "3"));
+ }
- [Fact]
- public void Parse_WithMultipleParamWithSameKey()
- {
- // Assign
- string query = "?key=value&key=anotherValue";
+ [Fact]
+ public void Parse_With1ParamContainingComma_SupportMultiValueUsingComma_Is_AmpersandAndSemiColon()
+ {
+ // Assign
+ string query = "?$filter=startswith(name,'testName')";
- // Act
- var result = QueryStringParser.Parse(query);
+ // Act
+ var result = QueryStringParser.Parse(query, QueryParameterMultipleValueSupport.AmpersandAndSemiColon);
- // Assert
- result.Count.Should().Be(1);
- result["key"].Should().Equal(new WireMockList(new[] { "value", "anotherValue" }));
- }
+ // Assert
+ result.Count.Should().Be(1);
+ result["$filter"].Should().Equal(new WireMockList("startswith(name,'testName')"));
+ }
- [Fact]
- public void Parse_With1ParamContainingSpacesAndEqualSign()
- {
- // Assign
- string query = "?q=SELECT Id from User where username='user@gmail.com'";
+ [Fact]
+ public void Parse_With1ParamContainingEscapedAnd()
+ {
+ // Assign
+ string query = "?winkel=C%26A";
- // Act
- var result = QueryStringParser.Parse(query);
+ // Act
+ var result = QueryStringParser.Parse(query);
- // Assert
- result.Count.Should().Be(1);
- result["q"].Should().Equal(new WireMockList("SELECT Id from User where username='user@gmail.com'"));
- }
+ // Assert
+ result.Count.Should().Be(1);
+ result["winkel"].Should().Equal(new WireMockList("C&A"));
+ }
- [Fact]
- public void Parse_WithComplex()
- {
- // Assign
- string query = "?q=energy+edge&rls=com.microsoft:en-au&ie=UTF-8&oe=UTF-8&startIndex=&startPage=1%22";
+ [Fact]
+ public void Parse_With1ParamContainingParentheses()
+ {
+ // Assign
+ string query = "?Transaction=(123)";
- // Act
- var result = QueryStringParser.Parse(query);
+ // Act
+ var result = QueryStringParser.Parse(query);
- // Assert
- result.Count.Should().Be(6);
- result["q"].Should().Equal(new WireMockList("energy edge"));
- result["rls"].Should().Equal(new WireMockList("com.microsoft:en-au"));
- result["ie"].Should().Equal(new WireMockList("UTF-8"));
- result["oe"].Should().Equal(new WireMockList("UTF-8"));
- result["startIndex"].Should().Equal(new WireMockList());
- result["startPage"].Should().Equal(new WireMockList("1\""));
- }
+ // Assert
+ result.Count.Should().Be(1);
+ result["Transaction"].Should().Equal(new WireMockList("(123)"));
+ }
+
+ [Fact]
+ public void Parse_WithMultipleParamWithSameKey()
+ {
+ // Assign
+ string query = "?key=value&key=anotherValue";
+
+ // Act
+ var result = QueryStringParser.Parse(query);
+
+ // Assert
+ result.Count.Should().Be(1);
+ result["key"].Should().Equal(new WireMockList("value", "anotherValue"));
+ }
+
+ [Fact]
+ public void Parse_With1ParamContainingSpacesAndEqualSign()
+ {
+ // Assign
+ string query = "?q=SELECT Id from User where username='user@gmail.com'";
+
+ // Act
+ var result = QueryStringParser.Parse(query);
+
+ // Assert
+ result.Count.Should().Be(1);
+ result["q"].Should().Equal(new WireMockList("SELECT Id from User where username='user@gmail.com'"));
+ }
+
+ [Fact]
+ public void Parse_WithComplex()
+ {
+ // Assign
+ string query = "?q=energy+edge&rls=com.microsoft:en-au&ie=UTF-8&oe=UTF-8&startIndex=&startPage=1%22";
+
+ // Act
+ var result = QueryStringParser.Parse(query);
+
+ // Assert
+ result.Count.Should().Be(6);
+ result["q"].Should().Equal(new WireMockList("energy edge"));
+ result["rls"].Should().Equal(new WireMockList("com.microsoft:en-au"));
+ result["ie"].Should().Equal(new WireMockList("UTF-8"));
+ result["oe"].Should().Equal(new WireMockList("UTF-8"));
+ result["startIndex"].Should().Equal(new WireMockList());
+ result["startPage"].Should().Equal(new WireMockList("1\""));
}
}
\ No newline at end of file