mirror of
https://github.com/wiremock/WireMock.Net.git
synced 2026-04-18 15:10:17 +02:00
Fix match logic (#604)
This commit is contained in:
@@ -1,185 +1,195 @@
|
|||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using WireMock.Types;
|
using WireMock.Types;
|
||||||
using WireMock.Util;
|
using WireMock.Util;
|
||||||
using WireMock.Validation;
|
using WireMock.Validation;
|
||||||
|
|
||||||
namespace WireMock.Matchers.Request
|
namespace WireMock.Matchers.Request
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The request body matcher.
|
/// The request body matcher.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class RequestMessageBodyMatcher : IRequestMatcher
|
public class RequestMessageBodyMatcher : IRequestMatcher
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The body function
|
/// The body function
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Func<string, bool> Func { get; }
|
public Func<string, bool> Func { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The body data function for byte[]
|
/// The body data function for byte[]
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Func<byte[], bool> DataFunc { get; }
|
public Func<byte[], bool> DataFunc { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The body data function for json
|
/// The body data function for json
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Func<object, bool> JsonFunc { get; }
|
public Func<object, bool> JsonFunc { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The body data function for BodyData
|
/// The body data function for BodyData
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Func<IBodyData, bool> BodyDataFunc { get; }
|
public Func<IBodyData, bool> BodyDataFunc { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The matchers.
|
/// The matchers.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IMatcher[] Matchers { get; }
|
public IMatcher[] Matchers { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
|
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="matchBehaviour">The match behaviour.</param>
|
/// <param name="matchBehaviour">The match behaviour.</param>
|
||||||
/// <param name="body">The body.</param>
|
/// <param name="body">The body.</param>
|
||||||
public RequestMessageBodyMatcher(MatchBehaviour matchBehaviour, [NotNull] string body) : this(new[] { new WildcardMatcher(matchBehaviour, body) }.Cast<IMatcher>().ToArray())
|
public RequestMessageBodyMatcher(MatchBehaviour matchBehaviour, [NotNull] string body) : this(new[] { new WildcardMatcher(matchBehaviour, body) }.Cast<IMatcher>().ToArray())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
|
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="matchBehaviour">The match behaviour.</param>
|
/// <param name="matchBehaviour">The match behaviour.</param>
|
||||||
/// <param name="body">The body.</param>
|
/// <param name="body">The body.</param>
|
||||||
public RequestMessageBodyMatcher(MatchBehaviour matchBehaviour, [NotNull] byte[] body) : this(new[] { new ExactObjectMatcher(matchBehaviour, body) }.Cast<IMatcher>().ToArray())
|
public RequestMessageBodyMatcher(MatchBehaviour matchBehaviour, [NotNull] byte[] body) : this(new[] { new ExactObjectMatcher(matchBehaviour, body) }.Cast<IMatcher>().ToArray())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
|
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="matchBehaviour">The match behaviour.</param>
|
/// <param name="matchBehaviour">The match behaviour.</param>
|
||||||
/// <param name="body">The body.</param>
|
/// <param name="body">The body.</param>
|
||||||
public RequestMessageBodyMatcher(MatchBehaviour matchBehaviour, [NotNull] object body) : this(new[] { new ExactObjectMatcher(matchBehaviour, body) }.Cast<IMatcher>().ToArray())
|
public RequestMessageBodyMatcher(MatchBehaviour matchBehaviour, [NotNull] object body) : this(new[] { new ExactObjectMatcher(matchBehaviour, body) }.Cast<IMatcher>().ToArray())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
|
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="func">The function.</param>
|
/// <param name="func">The function.</param>
|
||||||
public RequestMessageBodyMatcher([NotNull] Func<string, bool> func)
|
public RequestMessageBodyMatcher([NotNull] Func<string, bool> func)
|
||||||
{
|
{
|
||||||
Check.NotNull(func, nameof(func));
|
Check.NotNull(func, nameof(func));
|
||||||
Func = func;
|
Func = 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>
|
||||||
/// <param name="func">The function.</param>
|
/// <param name="func">The function.</param>
|
||||||
public RequestMessageBodyMatcher([NotNull] Func<byte[], bool> func)
|
public RequestMessageBodyMatcher([NotNull] Func<byte[], bool> func)
|
||||||
{
|
{
|
||||||
Check.NotNull(func, nameof(func));
|
Check.NotNull(func, nameof(func));
|
||||||
DataFunc = func;
|
DataFunc = 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>
|
||||||
/// <param name="func">The function.</param>
|
/// <param name="func">The function.</param>
|
||||||
public RequestMessageBodyMatcher([NotNull] Func<object, bool> func)
|
public RequestMessageBodyMatcher([NotNull] Func<object, bool> func)
|
||||||
{
|
{
|
||||||
Check.NotNull(func, nameof(func));
|
Check.NotNull(func, nameof(func));
|
||||||
JsonFunc = func;
|
JsonFunc = 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>
|
||||||
/// <param name="func">The function.</param>
|
/// <param name="func">The function.</param>
|
||||||
public RequestMessageBodyMatcher([NotNull] Func<IBodyData, bool> func)
|
public RequestMessageBodyMatcher([NotNull] Func<IBodyData, bool> func)
|
||||||
{
|
{
|
||||||
Check.NotNull(func, nameof(func));
|
Check.NotNull(func, nameof(func));
|
||||||
BodyDataFunc = func;
|
BodyDataFunc = 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>
|
||||||
/// <param name="matchers">The matchers.</param>
|
/// <param name="matchers">The matchers.</param>
|
||||||
public RequestMessageBodyMatcher([NotNull] params IMatcher[] matchers)
|
public RequestMessageBodyMatcher([NotNull] params IMatcher[] matchers)
|
||||||
{
|
{
|
||||||
Check.NotNull(matchers, nameof(matchers));
|
Check.NotNull(matchers, nameof(matchers));
|
||||||
Matchers = matchers;
|
Matchers = matchers;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <see cref="IRequestMatcher.GetMatchingScore"/>
|
/// <see cref="IRequestMatcher.GetMatchingScore"/>
|
||||||
public double GetMatchingScore(IRequestMessage requestMessage, RequestMatchResult requestMatchResult)
|
public double GetMatchingScore(IRequestMessage requestMessage, RequestMatchResult requestMatchResult)
|
||||||
{
|
{
|
||||||
double score = CalculateMatchScore(requestMessage);
|
double score = CalculateMatchScore(requestMessage);
|
||||||
return requestMatchResult.AddScore(GetType(), score);
|
return requestMatchResult.AddScore(GetType(), score);
|
||||||
}
|
}
|
||||||
|
|
||||||
private double CalculateMatchScore(IRequestMessage requestMessage, IMatcher matcher)
|
private double CalculateMatchScore(IRequestMessage requestMessage, IMatcher matcher)
|
||||||
{
|
{
|
||||||
// Check if the matcher is a IObjectMatcher
|
if (matcher is ExactObjectMatcher exactObjectMatcher)
|
||||||
if (matcher is IObjectMatcher objectMatcher)
|
{
|
||||||
{
|
// If the body is a byte array, try to match.
|
||||||
// If the body is a JSON object, try to match.
|
var detectedBodyType = requestMessage?.BodyData?.DetectedBodyType;
|
||||||
if (requestMessage?.BodyData?.DetectedBodyType == BodyType.Json)
|
if (detectedBodyType == BodyType.Bytes || detectedBodyType == BodyType.String)
|
||||||
{
|
{
|
||||||
return objectMatcher.IsMatch(requestMessage.BodyData.BodyAsJson);
|
return exactObjectMatcher.IsMatch(requestMessage.BodyData.BodyAsBytes);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// If the body is a byte array, try to match.
|
|
||||||
if (requestMessage?.BodyData?.DetectedBodyType == BodyType.Bytes)
|
// Check if the matcher is a IObjectMatcher
|
||||||
{
|
if (matcher is IObjectMatcher objectMatcher)
|
||||||
return objectMatcher.IsMatch(requestMessage.BodyData.BodyAsBytes);
|
{
|
||||||
}
|
// If the body is a JSON object, try to match.
|
||||||
}
|
if (requestMessage?.BodyData?.DetectedBodyType == BodyType.Json)
|
||||||
|
{
|
||||||
// Check if the matcher is a IStringMatcher
|
return objectMatcher.IsMatch(requestMessage.BodyData.BodyAsJson);
|
||||||
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 byte array, try to match.
|
||||||
if (requestMessage?.BodyData?.DetectedBodyType == BodyType.Json || requestMessage?.BodyData?.DetectedBodyType == BodyType.String)
|
if (requestMessage?.BodyData?.DetectedBodyType == BodyType.Bytes)
|
||||||
{
|
{
|
||||||
return stringMatcher.IsMatch(requestMessage.BodyData.BodyAsString);
|
return objectMatcher.IsMatch(requestMessage.BodyData.BodyAsBytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return MatchScores.Mismatch;
|
// Check if the matcher is a IStringMatcher
|
||||||
}
|
if (matcher is IStringMatcher stringMatcher)
|
||||||
|
{
|
||||||
private double CalculateMatchScore(IRequestMessage requestMessage)
|
// 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 (Matchers != null && Matchers.Any())
|
{
|
||||||
{
|
return stringMatcher.IsMatch(requestMessage.BodyData.BodyAsString);
|
||||||
return Matchers.Max(matcher => CalculateMatchScore(requestMessage, matcher));
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Func != null)
|
return MatchScores.Mismatch;
|
||||||
{
|
}
|
||||||
return MatchScores.ToScore(Func(requestMessage?.BodyData?.BodyAsString));
|
|
||||||
}
|
private double CalculateMatchScore(IRequestMessage requestMessage)
|
||||||
|
{
|
||||||
if (JsonFunc != null)
|
if (Matchers != null && Matchers.Any())
|
||||||
{
|
{
|
||||||
return MatchScores.ToScore(JsonFunc(requestMessage?.BodyData?.BodyAsJson));
|
return Matchers.Max(matcher => CalculateMatchScore(requestMessage, matcher));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DataFunc != null)
|
if (Func != null)
|
||||||
{
|
{
|
||||||
return MatchScores.ToScore(DataFunc(requestMessage?.BodyData?.BodyAsBytes));
|
return MatchScores.ToScore(Func(requestMessage?.BodyData?.BodyAsString));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BodyDataFunc != null)
|
if (JsonFunc != null)
|
||||||
{
|
{
|
||||||
return MatchScores.ToScore(BodyDataFunc(requestMessage?.BodyData));
|
return MatchScores.ToScore(JsonFunc(requestMessage?.BodyData?.BodyAsJson));
|
||||||
}
|
}
|
||||||
|
|
||||||
return MatchScores.Mismatch;
|
if (DataFunc != null)
|
||||||
}
|
{
|
||||||
}
|
return MatchScores.ToScore(DataFunc(requestMessage?.BodyData?.BodyAsBytes));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BodyDataFunc != null)
|
||||||
|
{
|
||||||
|
return MatchScores.ToScore(BodyDataFunc(requestMessage?.BodyData));
|
||||||
|
}
|
||||||
|
|
||||||
|
return MatchScores.Mismatch;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -209,13 +209,15 @@ namespace WireMock.Net.Tests.RequestMatchers
|
|||||||
Check.That(score).IsEqualTo(1.0d);
|
Check.That(score).IsEqualTo(1.0d);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Theory]
|
||||||
public void RequestMessageBodyMatcher_GetMatchingScore_BodyAsBytes_IObjectMatcher()
|
[InlineData(new byte[] { 1 })]
|
||||||
|
[InlineData(new byte[] { 48 })]
|
||||||
|
public void RequestMessageBodyMatcher_GetMatchingScore_BodyAsBytes_IObjectMatcher(byte[] bytes)
|
||||||
{
|
{
|
||||||
// Assign
|
// Assign
|
||||||
var body = new BodyData
|
var body = new BodyData
|
||||||
{
|
{
|
||||||
BodyAsBytes = new byte[] { 1 },
|
BodyAsBytes = bytes,
|
||||||
DetectedBodyType = BodyType.Bytes
|
DetectedBodyType = BodyType.Bytes
|
||||||
};
|
};
|
||||||
var objectMatcherMock = new Mock<IObjectMatcher>();
|
var objectMatcherMock = new Mock<IObjectMatcher>();
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
using NFluent;
|
using NFluent;
|
||||||
using System;
|
using System;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using FluentAssertions;
|
||||||
using WireMock.Matchers;
|
using WireMock.Matchers;
|
||||||
using WireMock.Matchers.Request;
|
using WireMock.Matchers.Request;
|
||||||
using WireMock.Models;
|
using WireMock.Models;
|
||||||
@@ -307,17 +308,20 @@ namespace WireMock.Net.Tests
|
|||||||
Check.That(requestBuilder.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
Check.That(requestBuilder.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Theory]
|
||||||
public void Request_WithBodyAsBytes_ExactObjectMatcher_true()
|
[InlineData(new byte[] { 1 }, BodyType.Bytes)]
|
||||||
|
[InlineData(new byte[] { 48, 49, 50 }, BodyType.Bytes)]
|
||||||
|
[InlineData(new byte[] { 48, 49, 50 }, BodyType.String)]
|
||||||
|
public void Request_WithBodyAsBytes_ExactObjectMatcher_true(byte[] bytes, BodyType detectedBodyType)
|
||||||
{
|
{
|
||||||
// Assign
|
// Assign
|
||||||
byte[] body = { 123 };
|
byte[] body = bytes;
|
||||||
var requestBuilder = Request.Create().UsingAnyMethod().WithBody(body);
|
var requestBuilder = Request.Create().UsingAnyMethod().WithBody(body);
|
||||||
|
|
||||||
var bodyData = new BodyData
|
var bodyData = new BodyData
|
||||||
{
|
{
|
||||||
BodyAsBytes = new byte[] { 123 },
|
BodyAsBytes = bytes,
|
||||||
DetectedBodyType = BodyType.Bytes
|
DetectedBodyType = detectedBodyType
|
||||||
};
|
};
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
@@ -325,7 +329,7 @@ namespace WireMock.Net.Tests
|
|||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var requestMatchResult = new RequestMatchResult();
|
var requestMatchResult = new RequestMatchResult();
|
||||||
Check.That(requestBuilder.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
requestBuilder.GetMatchingScore(request, requestMatchResult).Should().Be(1.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user