mirror of
https://github.com/wiremock/WireMock.Net.git
synced 2026-04-21 07:51:23 +02:00
Add WithBody with IDictionary (form-urlencoded values) (#903)
* . * x * fx * fix * f * tests * fix tests * add tst
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using WireMock.Types;
|
using WireMock.Types;
|
||||||
|
|
||||||
@@ -38,6 +39,11 @@ public interface IBodyData
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
string? BodyAsString { get; set; }
|
string? BodyAsString { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The body as Form UrlEncoded dictionary.
|
||||||
|
/// </summary>
|
||||||
|
IDictionary<string, string>? BodyAsFormUrlEncoded { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The detected body type (detection based on body content).
|
/// The detected body type (detection based on body content).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1,38 +1,42 @@
|
|||||||
namespace WireMock.Types
|
namespace WireMock.Types;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The BodyType
|
||||||
|
/// </summary>
|
||||||
|
public enum BodyType
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The BodyType
|
/// No body present
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum BodyType
|
None,
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// No body present
|
|
||||||
/// </summary>
|
|
||||||
None,
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Body is a String
|
/// Body is a String
|
||||||
/// </summary>
|
/// </summary>
|
||||||
String,
|
String,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Body is a Json object
|
/// Body is a Json object
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Json,
|
Json,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Body is a Byte array
|
/// Body is a Byte array
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Bytes,
|
Bytes,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Body is a File
|
/// Body is a File
|
||||||
/// </summary>
|
/// </summary>
|
||||||
File,
|
File,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Body is a MultiPart
|
/// Body is a MultiPart
|
||||||
/// </summary>
|
/// </summary>
|
||||||
MultiPart
|
MultiPart,
|
||||||
}
|
|
||||||
|
/// <summary>
|
||||||
|
/// Body is a String which is x-www-form-urlencoded.
|
||||||
|
/// </summary>
|
||||||
|
FormUrlEncoded
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using AnyOfTypes;
|
|
||||||
using Stef.Validation;
|
using Stef.Validation;
|
||||||
using WireMock.Models;
|
|
||||||
using WireMock.Types;
|
using WireMock.Types;
|
||||||
using WireMock.Util;
|
using WireMock.Util;
|
||||||
|
|
||||||
@@ -33,6 +32,11 @@ public class RequestMessageBodyMatcher : IRequestMatcher
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public Func<IBodyData?, bool>? BodyDataFunc { get; }
|
public Func<IBodyData?, bool>? BodyDataFunc { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The body data function for FormUrlEncoded
|
||||||
|
/// </summary>
|
||||||
|
public Func<IDictionary<string, string>?, bool>? FormUrlEncodedFunc { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The matchers.
|
/// The matchers.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -109,6 +113,15 @@ public class RequestMessageBodyMatcher : IRequestMatcher
|
|||||||
BodyDataFunc = Guard.NotNull(func);
|
BodyDataFunc = Guard.NotNull(func);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="func">The function.</param>
|
||||||
|
public RequestMessageBodyMatcher(Func<IDictionary<string, string>?, bool> func)
|
||||||
|
{
|
||||||
|
FormUrlEncodedFunc = Guard.NotNull(func);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
|
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -184,7 +197,7 @@ public class RequestMessageBodyMatcher : IRequestMatcher
|
|||||||
if (matcher is IStringMatcher stringMatcher)
|
if (matcher is IStringMatcher stringMatcher)
|
||||||
{
|
{
|
||||||
// If the body is a Json or a String, use the BodyAsString to match on.
|
// If the body is a Json or a String, use the BodyAsString to match on.
|
||||||
if (requestMessage?.BodyData?.DetectedBodyType == BodyType.Json || requestMessage?.BodyData?.DetectedBodyType == BodyType.String)
|
if (requestMessage?.BodyData?.DetectedBodyType is BodyType.Json or BodyType.String)
|
||||||
{
|
{
|
||||||
return stringMatcher.IsMatch(requestMessage.BodyData.BodyAsString);
|
return stringMatcher.IsMatch(requestMessage.BodyData.BodyAsString);
|
||||||
}
|
}
|
||||||
@@ -206,6 +219,11 @@ public class RequestMessageBodyMatcher : IRequestMatcher
|
|||||||
return MatchScores.ToScore(Func(requestMessage.BodyData?.BodyAsString));
|
return MatchScores.ToScore(Func(requestMessage.BodyData?.BodyAsString));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (FormUrlEncodedFunc != null)
|
||||||
|
{
|
||||||
|
return MatchScores.ToScore(FormUrlEncodedFunc(requestMessage.BodyData?.BodyAsFormUrlEncoded));
|
||||||
|
}
|
||||||
|
|
||||||
if (JsonFunc != null)
|
if (JsonFunc != null)
|
||||||
{
|
{
|
||||||
return MatchScores.ToScore(JsonFunc(requestMessage.BodyData?.BodyAsJson));
|
return MatchScores.ToScore(JsonFunc(requestMessage.BodyData?.BodyAsJson));
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using WireMock.Types;
|
using WireMock.Types;
|
||||||
|
|
||||||
@@ -14,6 +15,9 @@ public class BodyData : IBodyData
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string? BodyAsString { get; set; }
|
public string? BodyAsString { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public IDictionary<string, string>? BodyAsFormUrlEncoded { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc cref="IBodyData.BodyAsJson" />
|
/// <inheritdoc cref="IBodyData.BodyAsJson" />
|
||||||
public object? BodyAsJson { get; set; }
|
public object? BodyAsJson { get; set; }
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using WireMock.Matchers;
|
using WireMock.Matchers;
|
||||||
using WireMock.Matchers.Request;
|
using WireMock.Matchers.Request;
|
||||||
using WireMock.Util;
|
using WireMock.Util;
|
||||||
@@ -54,26 +55,33 @@ public interface IBodyRequestBuilder : IRequestMatcher
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="func">The function.</param>
|
/// <param name="func">The function.</param>
|
||||||
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
|
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
|
||||||
IRequestBuilder WithBody(Func<string, bool> func);
|
IRequestBuilder WithBody(Func<string?, bool> func);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// WithBody: func (byte[])
|
/// WithBody: func (byte[])
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="func">The function.</param>
|
/// <param name="func">The function.</param>
|
||||||
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
|
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
|
||||||
IRequestBuilder WithBody(Func<byte[], bool> func);
|
IRequestBuilder WithBody(Func<byte[]?, bool> func);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// WithBody: func (json object)
|
/// WithBody: func (json object)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="func">The function.</param>
|
/// <param name="func">The function.</param>
|
||||||
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
|
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
|
||||||
IRequestBuilder WithBody(Func<object, bool> func);
|
IRequestBuilder WithBody(Func<object?, bool> func);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// WithBody: func (BodyData object)
|
/// WithBody: func (BodyData object)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="func">The function.</param>
|
/// <param name="func">The function.</param>
|
||||||
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
|
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
|
||||||
IRequestBuilder WithBody(Func<IBodyData, bool> func);
|
IRequestBuilder WithBody(Func<IBodyData?, bool> func);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// WithBody: Body as form-urlencoded values.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="func">The form-urlencoded values.</param>
|
||||||
|
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
|
||||||
|
IRequestBuilder WithBody(Func<IDictionary<string, string>?, bool> func);
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
// This source file is based on mock4net by Alexandre Victoor which is licensed under the Apache 2.0 License.
|
// This source file is based on mock4net by Alexandre Victoor which is licensed under the Apache 2.0 License.
|
||||||
// For more details see 'mock4net/LICENSE.txt' and 'mock4net/readme.md' in this project root.
|
// For more details see 'mock4net/LICENSE.txt' and 'mock4net/readme.md' in this project root.
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using WireMock.Matchers;
|
using WireMock.Matchers;
|
||||||
using WireMock.Matchers.Request;
|
using WireMock.Matchers.Request;
|
||||||
using WireMock.Util;
|
using WireMock.Util;
|
||||||
@@ -10,21 +11,21 @@ namespace WireMock.RequestBuilders;
|
|||||||
|
|
||||||
public partial class Request
|
public partial class Request
|
||||||
{
|
{
|
||||||
/// <inheritdoc cref="IBodyRequestBuilder.WithBody(string, MatchBehaviour)"/>
|
/// <inheritdoc />
|
||||||
public IRequestBuilder WithBody(string body, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch)
|
public IRequestBuilder WithBody(string body, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch)
|
||||||
{
|
{
|
||||||
_requestMatchers.Add(new RequestMessageBodyMatcher(matchBehaviour, body));
|
_requestMatchers.Add(new RequestMessageBodyMatcher(matchBehaviour, body));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="IBodyRequestBuilder.WithBody(byte[], MatchBehaviour)"/>
|
/// <inheritdoc />
|
||||||
public IRequestBuilder WithBody(byte[] body, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch)
|
public IRequestBuilder WithBody(byte[] body, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch)
|
||||||
{
|
{
|
||||||
_requestMatchers.Add(new RequestMessageBodyMatcher(matchBehaviour, body));
|
_requestMatchers.Add(new RequestMessageBodyMatcher(matchBehaviour, body));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="IBodyRequestBuilder.WithBody(object, MatchBehaviour)"/>
|
/// <inheritdoc />
|
||||||
public IRequestBuilder WithBody(object body, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch)
|
public IRequestBuilder WithBody(object body, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch)
|
||||||
{
|
{
|
||||||
_requestMatchers.Add(new RequestMessageBodyMatcher(matchBehaviour, body));
|
_requestMatchers.Add(new RequestMessageBodyMatcher(matchBehaviour, body));
|
||||||
@@ -46,39 +47,46 @@ public partial class Request
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="IBodyRequestBuilder.WithBody(Func{string, bool})"/>
|
/// <inheritdoc />
|
||||||
public IRequestBuilder WithBody(Func<string, bool> func)
|
public IRequestBuilder WithBody(Func<string?, bool> func)
|
||||||
{
|
{
|
||||||
Guard.NotNull(func, nameof(func));
|
Guard.NotNull(func);
|
||||||
|
|
||||||
_requestMatchers.Add(new RequestMessageBodyMatcher(func));
|
_requestMatchers.Add(new RequestMessageBodyMatcher(func));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="IBodyRequestBuilder.WithBody(Func{byte[], bool})"/>
|
/// <inheritdoc />
|
||||||
public IRequestBuilder WithBody(Func<byte[], bool> func)
|
public IRequestBuilder WithBody(Func<byte[]?, bool> func)
|
||||||
{
|
{
|
||||||
Guard.NotNull(func, nameof(func));
|
Guard.NotNull(func);
|
||||||
|
|
||||||
_requestMatchers.Add(new RequestMessageBodyMatcher(func));
|
_requestMatchers.Add(new RequestMessageBodyMatcher(func));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="IBodyRequestBuilder.WithBody(Func{object, bool})"/>
|
/// <inheritdoc />
|
||||||
public IRequestBuilder WithBody(Func<object, bool> func)
|
public IRequestBuilder WithBody(Func<object?, bool> func)
|
||||||
{
|
{
|
||||||
Guard.NotNull(func, nameof(func));
|
Guard.NotNull(func);
|
||||||
|
|
||||||
_requestMatchers.Add(new RequestMessageBodyMatcher(func));
|
_requestMatchers.Add(new RequestMessageBodyMatcher(func));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="IBodyRequestBuilder.WithBody(Func{IBodyData, bool})"/>
|
/// <inheritdoc />
|
||||||
public IRequestBuilder WithBody(Func<IBodyData, bool> func)
|
public IRequestBuilder WithBody(Func<IBodyData?, bool> func)
|
||||||
{
|
{
|
||||||
Guard.NotNull(func, nameof(func));
|
Guard.NotNull(func);
|
||||||
|
|
||||||
_requestMatchers.Add(new RequestMessageBodyMatcher(func));
|
_requestMatchers.Add(new RequestMessageBodyMatcher(func));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public IRequestBuilder WithBody(Func<IDictionary<string, string>?, bool> func)
|
||||||
|
{
|
||||||
|
_requestMatchers.Add(new RequestMessageBodyMatcher(Guard.NotNull(func)));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -49,12 +49,14 @@ internal static class BodyParser
|
|||||||
new WildcardMatcher("application/vnd.*+json", true)
|
new WildcardMatcher("application/vnd.*+json", true)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private static readonly IStringMatcher FormUrlEncodedMatcher = new WildcardMatcher("application/x-www-form-urlencoded", true);
|
||||||
|
|
||||||
private static readonly IStringMatcher[] TextContentTypeMatchers =
|
private static readonly IStringMatcher[] TextContentTypeMatchers =
|
||||||
{
|
{
|
||||||
new WildcardMatcher("text/*", true),
|
new WildcardMatcher("text/*", true),
|
||||||
new RegexMatcher("^application\\/(java|type)script$", true),
|
new RegexMatcher("^application\\/(java|type)script$", true),
|
||||||
new WildcardMatcher("application/*xml", true),
|
new WildcardMatcher("application/*xml", true),
|
||||||
new WildcardMatcher("application/x-www-form-urlencoded", true)
|
FormUrlEncodedMatcher
|
||||||
};
|
};
|
||||||
|
|
||||||
public static bool ShouldParseBody(string? httpMethod, bool allowBodyForAllHttpMethods)
|
public static bool ShouldParseBody(string? httpMethod, bool allowBodyForAllHttpMethods)
|
||||||
@@ -69,7 +71,7 @@ internal static class BodyParser
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BodyAllowedForMethods.TryGetValue(httpMethod!.ToUpper(), out bool allowed))
|
if (BodyAllowedForMethods.TryGetValue(httpMethod!.ToUpper(), out var allowed))
|
||||||
{
|
{
|
||||||
return allowed;
|
return allowed;
|
||||||
}
|
}
|
||||||
@@ -88,6 +90,11 @@ internal static class BodyParser
|
|||||||
return BodyType.Bytes;
|
return BodyType.Bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (MatchScores.IsPerfect(FormUrlEncodedMatcher.IsMatch(contentType.MediaType)))
|
||||||
|
{
|
||||||
|
return BodyType.FormUrlEncoded;
|
||||||
|
}
|
||||||
|
|
||||||
if (TextContentTypeMatchers.Any(matcher => MatchScores.IsPerfect(matcher.IsMatch(contentType.MediaType))))
|
if (TextContentTypeMatchers.Any(matcher => MatchScores.IsPerfect(matcher.IsMatch(contentType.MediaType))))
|
||||||
{
|
{
|
||||||
return BodyType.String;
|
return BodyType.String;
|
||||||
@@ -133,13 +140,30 @@ internal static class BodyParser
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to get the body as String or Json
|
// Try to get the body as String, FormUrlEncoded or Json
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
data.BodyAsString = DefaultEncoding.GetString(data.BodyAsBytes);
|
data.BodyAsString = DefaultEncoding.GetString(data.BodyAsBytes);
|
||||||
data.Encoding = DefaultEncoding;
|
data.Encoding = DefaultEncoding;
|
||||||
data.DetectedBodyType = BodyType.String;
|
data.DetectedBodyType = BodyType.String;
|
||||||
|
|
||||||
|
// If string is not null or empty, try to deserialize the string to a IDictionary<string, string>
|
||||||
|
if (settings.DeserializeFormUrlEncoded &&
|
||||||
|
data.DetectedBodyTypeFromContentType == BodyType.FormUrlEncoded &&
|
||||||
|
QueryStringParser.TryParse(data.BodyAsString, false, out var nameValueCollection)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
data.BodyAsFormUrlEncoded = nameValueCollection;
|
||||||
|
data.DetectedBodyType = BodyType.FormUrlEncoded;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Deserialize FormUrlEncoded failed, just ignore.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If string is not null or empty, try to deserialize the string to a JObject
|
// If string is not null or empty, try to deserialize the string to a JObject
|
||||||
if (settings.DeserializeJson && !string.IsNullOrEmpty(data.BodyAsString))
|
if (settings.DeserializeJson && !string.IsNullOrEmpty(data.BodyAsString))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -13,4 +13,6 @@ internal class BodyParserSettings
|
|||||||
public bool DecompressGZipAndDeflate { get; set; } = true;
|
public bool DecompressGZipAndDeflate { get; set; } = true;
|
||||||
|
|
||||||
public bool DeserializeJson { get; set; } = true;
|
public bool DeserializeJson { get; set; } = true;
|
||||||
|
|
||||||
|
public bool DeserializeFormUrlEncoded { get; set; } = true;
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Net;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
using WireMock.Types;
|
using WireMock.Types;
|
||||||
|
|
||||||
namespace WireMock.Util;
|
namespace WireMock.Util;
|
||||||
@@ -13,6 +14,31 @@ internal static class QueryStringParser
|
|||||||
{
|
{
|
||||||
private static readonly Dictionary<string, WireMockList<string>> Empty = new();
|
private static readonly Dictionary<string, WireMockList<string>> Empty = new();
|
||||||
|
|
||||||
|
public static bool TryParse(string? queryString, bool caseIgnore, [NotNullWhen(true)] out IDictionary<string, string>? nameValueCollection)
|
||||||
|
{
|
||||||
|
if (queryString is null)
|
||||||
|
{
|
||||||
|
nameValueCollection = default;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var parts = queryString!
|
||||||
|
.Split(new[] { "&" }, StringSplitOptions.RemoveEmptyEntries)
|
||||||
|
.Select(parameter => parameter.Split('='))
|
||||||
|
.Distinct();
|
||||||
|
|
||||||
|
nameValueCollection = caseIgnore ? new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase) : new Dictionary<string, string>();
|
||||||
|
foreach (var part in parts)
|
||||||
|
{
|
||||||
|
if (part.Length == 2)
|
||||||
|
{
|
||||||
|
nameValueCollection.Add(part[0], part[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public static IDictionary<string, WireMockList<string>> Parse(string? queryString, QueryParameterMultipleValueSupport? support = null)
|
public static IDictionary<string, WireMockList<string>> Parse(string? queryString, QueryParameterMultipleValueSupport? support = null)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(queryString))
|
if (string.IsNullOrEmpty(queryString))
|
||||||
|
|||||||
@@ -431,7 +431,7 @@ public class RequestMessageBodyMatcherTests
|
|||||||
// JSON match +++
|
// JSON match +++
|
||||||
{json, new RequestMessageBodyMatcher((object? o) => ((dynamic) o!).a == "b"), true},
|
{json, new RequestMessageBodyMatcher((object? o) => ((dynamic) o!).a == "b"), true},
|
||||||
{json, new RequestMessageBodyMatcher((string? s) => s == json), true},
|
{json, new RequestMessageBodyMatcher((string? s) => s == json), true},
|
||||||
{json, new RequestMessageBodyMatcher((byte[]? b) => b.SequenceEqual(Encoding.UTF8.GetBytes(json))), true},
|
{json, new RequestMessageBodyMatcher((byte[]? b) => b?.SequenceEqual(Encoding.UTF8.GetBytes(json)) == true), true},
|
||||||
|
|
||||||
// JSON no match ---
|
// JSON no match ---
|
||||||
{json, new RequestMessageBodyMatcher((object? o) => false), false},
|
{json, new RequestMessageBodyMatcher((object? o) => false), false},
|
||||||
@@ -442,7 +442,7 @@ public class RequestMessageBodyMatcherTests
|
|||||||
// string match +++
|
// string match +++
|
||||||
{str, new RequestMessageBodyMatcher((object? o) => o == null), true},
|
{str, new RequestMessageBodyMatcher((object? o) => o == null), true},
|
||||||
{str, new RequestMessageBodyMatcher((string? s) => s == str), true},
|
{str, new RequestMessageBodyMatcher((string? s) => s == str), true},
|
||||||
{str, new RequestMessageBodyMatcher((byte[]? b) => b.SequenceEqual(Encoding.UTF8.GetBytes(str))), true},
|
{str, new RequestMessageBodyMatcher((byte[]? b) => b?.SequenceEqual(Encoding.UTF8.GetBytes(str)) == true), true},
|
||||||
|
|
||||||
// string no match ---
|
// string no match ---
|
||||||
{str, new RequestMessageBodyMatcher((object? o) => false), false},
|
{str, new RequestMessageBodyMatcher((object? o) => false), false},
|
||||||
@@ -453,13 +453,13 @@ public class RequestMessageBodyMatcherTests
|
|||||||
// binary match +++
|
// binary match +++
|
||||||
{bytes, new RequestMessageBodyMatcher((object? o) => o == null), true},
|
{bytes, new RequestMessageBodyMatcher((object? o) => o == null), true},
|
||||||
{bytes, new RequestMessageBodyMatcher((string? s) => s == null), true},
|
{bytes, new RequestMessageBodyMatcher((string? s) => s == null), true},
|
||||||
{bytes, new RequestMessageBodyMatcher((byte[]? b) => b.SequenceEqual(bytes)), true},
|
{bytes, new RequestMessageBodyMatcher((byte[]? b) => b?.SequenceEqual(bytes) == true), true},
|
||||||
|
|
||||||
// binary no match ---
|
// binary no match ---
|
||||||
{bytes, new RequestMessageBodyMatcher((object? o) => false), false},
|
{bytes, new RequestMessageBodyMatcher((object? o) => false), false},
|
||||||
{bytes, new RequestMessageBodyMatcher((string? s) => false), false},
|
{bytes, new RequestMessageBodyMatcher((string? s) => false), false},
|
||||||
{bytes, new RequestMessageBodyMatcher((byte[]? b) => false), false},
|
{bytes, new RequestMessageBodyMatcher((byte[]? b) => false), false},
|
||||||
{bytes, new RequestMessageBodyMatcher(), false },
|
{bytes, new RequestMessageBodyMatcher(), false }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
@@ -55,11 +56,31 @@ namespace WireMock.Net.Tests
|
|||||||
Check.That(requestBuilder.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
Check.That(requestBuilder.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Request_WithBody_FuncFormUrlEncoded()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var requestBuilder = Request.Create().UsingAnyMethod().WithBody((IDictionary<string, string>? values) => values != null);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var body = new BodyData
|
||||||
|
{
|
||||||
|
BodyAsFormUrlEncoded = new Dictionary<string, string>(),
|
||||||
|
DetectedBodyTypeFromContentType = BodyType.FormUrlEncoded,
|
||||||
|
DetectedBodyType = BodyType.FormUrlEncoded
|
||||||
|
};
|
||||||
|
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "POST", ClientIp, body);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var requestMatchResult = new RequestMatchResult();
|
||||||
|
Check.That(requestBuilder.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Request_WithBody_FuncBodyData()
|
public void Request_WithBody_FuncBodyData()
|
||||||
{
|
{
|
||||||
// Assign
|
// Assign
|
||||||
var requestBuilder = Request.Create().UsingAnyMethod().WithBody((IBodyData b) => b != null);
|
var requestBuilder = Request.Create().UsingAnyMethod().WithBody((IBodyData? b) => b != null);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var body = new BodyData
|
var body = new BodyData
|
||||||
@@ -78,7 +99,7 @@ namespace WireMock.Net.Tests
|
|||||||
public void Request_WithBody_FuncByteArray()
|
public void Request_WithBody_FuncByteArray()
|
||||||
{
|
{
|
||||||
// Assign
|
// Assign
|
||||||
var requestBuilder = Request.Create().UsingAnyMethod().WithBody((byte[] b) => b != null);
|
var requestBuilder = Request.Create().UsingAnyMethod().WithBody((byte[]? b) => b != null);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var body = new BodyData
|
var body = new BodyData
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
using FluentAssertions;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using FluentAssertions;
|
||||||
using WireMock.Types;
|
using WireMock.Types;
|
||||||
using WireMock.Util;
|
using WireMock.Util;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
@@ -8,6 +8,36 @@ namespace WireMock.Net.Tests.Util;
|
|||||||
|
|
||||||
public class QueryStringParserTests
|
public class QueryStringParserTests
|
||||||
{
|
{
|
||||||
|
public static IEnumerable<object?[]> QueryStringTestData => new List<object?[]>
|
||||||
|
{
|
||||||
|
new object?[] { null, false, false, null },
|
||||||
|
new object?[] { string.Empty, false, true, new Dictionary<string, string>() },
|
||||||
|
new object?[] { "test", false, true, new Dictionary<string, string>() },
|
||||||
|
new object?[] { "&", false, true, new Dictionary<string, string>() },
|
||||||
|
new object?[] { "&&", false, true, new Dictionary<string, string>() },
|
||||||
|
new object?[] { "a=", false, true, new Dictionary<string, string> { { "a", "" } } },
|
||||||
|
new object?[] { "&a", false, true, new Dictionary<string, string>() },
|
||||||
|
new object?[] { "&a=", false, true, new Dictionary<string, string> { { "a", "" } } },
|
||||||
|
new object?[] { "&key1=value1", false, true, new Dictionary<string, string> { { "key1", "value1" } } },
|
||||||
|
new object?[] { "key1=value1", false, true, new Dictionary<string, string> { { "key1", "value1" } } },
|
||||||
|
new object?[] { "key1=value1&key2=value2", false, true, new Dictionary<string, string> { { "key1", "value1" }, { "key2", "value2" } } },
|
||||||
|
new object?[] { "key1=value1&key2=value2&", false, true, new Dictionary<string, string> { { "key1", "value1" }, { "key2", "value2" } } },
|
||||||
|
new object?[] { "key1=value1&&key2=value2", false, true, new Dictionary<string, string> { { "key1", "value1" }, { "key2", "value2" } } },
|
||||||
|
new object?[] { "&key1=value1&key2=value2&&", false, true, new Dictionary<string, string> { { "key1", "value1" }, { "key2", "value2" } } },
|
||||||
|
};
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[MemberData(nameof(QueryStringTestData))]
|
||||||
|
public void TryParse_Should_Parse_QueryString(string queryString, bool caseIgnore, bool expectedResult, IDictionary<string, string> expectedOutput)
|
||||||
|
{
|
||||||
|
// Act
|
||||||
|
var result = QueryStringParser.TryParse(queryString, caseIgnore, out var actual);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Should().Be(expectedResult);
|
||||||
|
actual.Should().BeEquivalentTo(expectedOutput);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Parse_WithNullString()
|
public void Parse_WithNullString()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
#if !NET452
|
#if !NET452
|
||||||
|
//using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Net.Http.Json;
|
//using System.Net.Http.Json;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
using WireMock.Matchers;
|
using WireMock.Matchers;
|
||||||
@@ -10,61 +12,88 @@ using WireMock.ResponseBuilders;
|
|||||||
using WireMock.Server;
|
using WireMock.Server;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace WireMock.Net.Tests
|
namespace WireMock.Net.Tests;
|
||||||
|
|
||||||
|
public partial class WireMockServerTests
|
||||||
{
|
{
|
||||||
public partial class WireMockServerTests
|
public class DummyClass
|
||||||
{
|
{
|
||||||
public class DummyClass
|
public string? Hi { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task WireMockServer_WithBodyAsJson_Using_PostAsJsonAsync_And_WildcardMatcher_ShouldMatch()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var server = WireMockServer.Start();
|
||||||
|
server.Given(
|
||||||
|
Request.Create().UsingPost().WithPath("/foo").WithBody(new WildcardMatcher("*Hello*"))
|
||||||
|
)
|
||||||
|
.RespondWith(
|
||||||
|
Response.Create().WithStatusCode(200)
|
||||||
|
);
|
||||||
|
|
||||||
|
var jsonObject = new DummyClass
|
||||||
{
|
{
|
||||||
public string Hi { get; set; }
|
Hi = "Hello World!"
|
||||||
}
|
};
|
||||||
|
|
||||||
[Fact]
|
// Act
|
||||||
public async Task WireMockServer_WithBodyAsJson_Using_PostAsJsonAsync_And_WildcardMatcher_ShouldMatch()
|
var response = await new HttpClient().PostAsJsonAsync("http://localhost:" + server.Ports[0] + "/foo", jsonObject).ConfigureAwait(false);
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var server = WireMockServer.Start();
|
|
||||||
server.Given(
|
|
||||||
Request.Create().UsingPost().WithPath("/foo").WithBody(new WildcardMatcher("*Hello*"))
|
|
||||||
)
|
|
||||||
.RespondWith(
|
|
||||||
Response.Create().WithStatusCode(200)
|
|
||||||
);
|
|
||||||
|
|
||||||
var jsonObject = new DummyClass
|
// Assert
|
||||||
{
|
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||||
Hi = "Hello World!"
|
|
||||||
};
|
|
||||||
|
|
||||||
// Act
|
server.Stop();
|
||||||
var response = await new HttpClient().PostAsJsonAsync("http://localhost:" + server.Ports[0] + "/foo", jsonObject).ConfigureAwait(false);
|
}
|
||||||
|
|
||||||
// Assert
|
[Fact]
|
||||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
public async Task WireMockServer_WithBodyAsJson_Using_PostAsync_And_WildcardMatcher_ShouldMatch()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var server = WireMockServer.Start();
|
||||||
|
server.Given(
|
||||||
|
Request.Create().UsingPost().WithPath("/foo").WithBody(new WildcardMatcher("*Hello*"))
|
||||||
|
)
|
||||||
|
.RespondWith(
|
||||||
|
Response.Create().WithStatusCode(200)
|
||||||
|
);
|
||||||
|
|
||||||
server.Stop();
|
// Act
|
||||||
}
|
var response = await new HttpClient().PostAsync("http://localhost:" + server.Ports[0] + "/foo", new StringContent("{ Hi = \"Hello World\" }")).ConfigureAwait(false);
|
||||||
|
|
||||||
[Fact]
|
// Assert
|
||||||
public async Task WireMockServer_WithBodyAsJson_Using_PostAsync_And_WildcardMatcher_ShouldMatch()
|
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var server = WireMockServer.Start();
|
|
||||||
server.Given(
|
|
||||||
Request.Create().UsingPost().WithPath("/foo").WithBody(new WildcardMatcher("*Hello*"))
|
|
||||||
)
|
|
||||||
.RespondWith(
|
|
||||||
Response.Create().WithStatusCode(200)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Act
|
server.Stop();
|
||||||
var response = await new HttpClient().PostAsync("http://localhost:" + server.Ports[0] + "/foo", new StringContent("{ Hi = \"Hello World\" }")).ConfigureAwait(false);
|
}
|
||||||
|
|
||||||
// Assert
|
[Fact]
|
||||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
public async Task WireMockServer_WithBodyAsFormUrlEncoded_Using_PostAsync_And_WithFunc()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var server = WireMockServer.Start();
|
||||||
|
server.Given(
|
||||||
|
Request.Create()
|
||||||
|
.UsingPost()
|
||||||
|
.WithPath("/foo")
|
||||||
|
.WithBody(values => values != null && values["key1"] == "value1")
|
||||||
|
)
|
||||||
|
.RespondWith(
|
||||||
|
Response.Create()
|
||||||
|
);
|
||||||
|
|
||||||
server.Stop();
|
// Act
|
||||||
}
|
var content = new FormUrlEncodedContent(new[] { new KeyValuePair<string, string>("key1", "value1") });
|
||||||
|
var response = await new HttpClient()
|
||||||
|
.PostAsync($"{server.Url}/foo", content)
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||||
|
|
||||||
|
server.Stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
Reference in New Issue
Block a user