Fix match logic (#604)

This commit is contained in:
Stef Heyenrath
2021-04-18 19:30:03 +00:00
committed by GitHub
parent b17840cea9
commit fbecd3b119
3 changed files with 208 additions and 192 deletions

View File

@@ -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;
}
}
} }

View File

@@ -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>();

View File

@@ -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);
} }
} }
} }