Add MatchOperator "Or", "And" and "Average" for patterns (#755)

* wip

* ...

* .

* ...

* ...

* path

* url

* b

* t

* client

* .

* RequestMessageMethodMatcherTests

* .

* h

* .

* fix tests

* .
This commit is contained in:
Stef Heyenrath
2022-06-09 21:31:54 +02:00
committed by GitHub
parent 1f23022460
commit 0441c1d85e
95 changed files with 5736 additions and 5111 deletions

View File

@@ -1,211 +1,226 @@
using JetBrains.Annotations;
using System;
using System.Linq;
using AnyOfTypes;
using Stef.Validation;
using WireMock.Models;
using WireMock.Types;
using WireMock.Util;
using Stef.Validation;
namespace WireMock.Matchers.Request
namespace WireMock.Matchers.Request;
/// <summary>
/// The request body matcher.
/// </summary>
public class RequestMessageBodyMatcher : IRequestMatcher
{
/// <summary>
/// The request body matcher.
/// The body function
/// </summary>
public class RequestMessageBodyMatcher : IRequestMatcher
public Func<string, bool>? Func { get; }
/// <summary>
/// The body data function for byte[]
/// </summary>
public Func<byte[], bool>? DataFunc { get; }
/// <summary>
/// The body data function for json
/// </summary>
public Func<object, bool>? JsonFunc { get; }
/// <summary>
/// The body data function for BodyData
/// </summary>
public Func<IBodyData, bool>? BodyDataFunc { get; }
/// <summary>
/// The matchers.
/// </summary>
public IMatcher[]? Matchers { get; }
/// <summary>
/// The <see cref="MatchOperator"/>
/// </summary>
public MatchOperator MatchOperator { get; } = MatchOperator.Or;
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="body">The body.</param>
public RequestMessageBodyMatcher(MatchBehaviour matchBehaviour, string body) :
this(new[] { new WildcardMatcher(matchBehaviour, body) }.Cast<IMatcher>().ToArray())
{
/// <summary>
/// The body function
/// </summary>
public Func<string, bool> Func { get; }
}
/// <summary>
/// The body data function for byte[]
/// </summary>
public Func<byte[], bool> DataFunc { get; }
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="body">The body.</param>
public RequestMessageBodyMatcher(MatchBehaviour matchBehaviour, byte[] body) :
this(new[] { new ExactObjectMatcher(matchBehaviour, body) }.Cast<IMatcher>().ToArray())
{
}
/// <summary>
/// The body data function for json
/// </summary>
public Func<object, bool> JsonFunc { get; }
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="body">The body.</param>
public RequestMessageBodyMatcher(MatchBehaviour matchBehaviour, object body) :
this(new[] { new ExactObjectMatcher(matchBehaviour, body) }.Cast<IMatcher>().ToArray())
{
}
/// <summary>
/// The body data function for BodyData
/// </summary>
public Func<IBodyData, bool> BodyDataFunc { get; }
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
/// </summary>
/// <param name="func">The function.</param>
public RequestMessageBodyMatcher(Func<string, bool> func)
{
Func = Guard.NotNull(func);
}
/// <summary>
/// The matchers.
/// </summary>
public IMatcher[] Matchers { get; }
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
/// </summary>
/// <param name="func">The function.</param>
public RequestMessageBodyMatcher(Func<byte[], bool> func)
{
DataFunc = Guard.NotNull(func);
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="body">The body.</param>
public RequestMessageBodyMatcher(MatchBehaviour matchBehaviour, [NotNull] string body) : this(new[] { new WildcardMatcher(matchBehaviour, body) }.Cast<IMatcher>().ToArray())
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
/// </summary>
/// <param name="func">The function.</param>
public RequestMessageBodyMatcher(Func<object, bool> func)
{
JsonFunc = Guard.NotNull(func);
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
/// </summary>
/// <param name="func">The function.</param>
public RequestMessageBodyMatcher(Func<IBodyData, bool> func)
{
BodyDataFunc = Guard.NotNull(func);
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
/// </summary>
/// <param name="matchers">The matchers.</param>
public RequestMessageBodyMatcher(params IMatcher[] matchers)
{
Matchers = Guard.NotNull(matchers);
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
/// </summary>
/// <param name="matchers">The matchers.</param>
/// <param name="matchOperator">The <see cref="MatchOperator"/> to use.</param>
public RequestMessageBodyMatcher(MatchOperator matchOperator, params IMatcher[] matchers)
{
Matchers = Guard.NotNull(matchers);
MatchOperator = matchOperator;
}
/// <inheritdoc />
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
{
double score = CalculateMatchScore(requestMessage);
return requestMatchResult.AddScore(GetType(), score);
}
private static double CalculateMatchScore(IRequestMessage requestMessage, IMatcher matcher)
{
if (matcher is NotNullOrEmptyMatcher notNullOrEmptyMatcher)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="body">The body.</param>
public RequestMessageBodyMatcher(MatchBehaviour matchBehaviour, [NotNull] byte[] body) : this(new[] { new ExactObjectMatcher(matchBehaviour, body) }.Cast<IMatcher>().ToArray())
{
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="body">The body.</param>
public RequestMessageBodyMatcher(MatchBehaviour matchBehaviour, [NotNull] object body) : this(new[] { new ExactObjectMatcher(matchBehaviour, body) }.Cast<IMatcher>().ToArray())
{
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
/// </summary>
/// <param name="func">The function.</param>
public RequestMessageBodyMatcher([NotNull] Func<string, bool> func)
{
Guard.NotNull(func, nameof(func));
Func = func;
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
/// </summary>
/// <param name="func">The function.</param>
public RequestMessageBodyMatcher([NotNull] Func<byte[], bool> func)
{
Guard.NotNull(func, nameof(func));
DataFunc = func;
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
/// </summary>
/// <param name="func">The function.</param>
public RequestMessageBodyMatcher([NotNull] Func<object, bool> func)
{
Guard.NotNull(func, nameof(func));
JsonFunc = func;
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
/// </summary>
/// <param name="func">The function.</param>
public RequestMessageBodyMatcher([NotNull] Func<IBodyData, bool> func)
{
Guard.NotNull(func, nameof(func));
BodyDataFunc = func;
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
/// </summary>
/// <param name="matchers">The matchers.</param>
public RequestMessageBodyMatcher([NotNull] params IMatcher[] matchers)
{
Guard.NotNull(matchers, nameof(matchers));
Matchers = matchers;
}
/// <inheritdoc />
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
{
double score = CalculateMatchScore(requestMessage);
return requestMatchResult.AddScore(GetType(), score);
}
private double CalculateMatchScore(IRequestMessage requestMessage, IMatcher matcher)
{
if (matcher is NotNullOrEmptyMatcher notNullOrEmptyMatcher)
switch (requestMessage.BodyData?.DetectedBodyType)
{
switch (requestMessage?.BodyData?.DetectedBodyType)
{
case BodyType.Json:
case BodyType.String:
return notNullOrEmptyMatcher.IsMatch(requestMessage.BodyData.BodyAsString);
case BodyType.Json:
case BodyType.String:
return notNullOrEmptyMatcher.IsMatch(requestMessage.BodyData.BodyAsString);
case BodyType.Bytes:
return notNullOrEmptyMatcher.IsMatch(requestMessage.BodyData.BodyAsBytes);
case BodyType.Bytes:
return notNullOrEmptyMatcher.IsMatch(requestMessage.BodyData.BodyAsBytes);
default:
return MatchScores.Mismatch;
}
default:
return MatchScores.Mismatch;
}
}
if (matcher is ExactObjectMatcher exactObjectMatcher)
{
// If the body is a byte array, try to match.
var detectedBodyType = requestMessage.BodyData?.DetectedBodyType;
if (detectedBodyType == BodyType.Bytes || detectedBodyType == BodyType.String)
{
return exactObjectMatcher.IsMatch(requestMessage.BodyData.BodyAsBytes);
}
}
// Check if the matcher is a IObjectMatcher
if (matcher is IObjectMatcher objectMatcher)
{
// If the body is a JSON object, try to match.
if (requestMessage?.BodyData?.DetectedBodyType == BodyType.Json)
{
return objectMatcher.IsMatch(requestMessage.BodyData.BodyAsJson);
}
if (matcher is ExactObjectMatcher exactObjectMatcher)
// If the body is a byte array, try to match.
if (requestMessage?.BodyData?.DetectedBodyType == BodyType.Bytes)
{
// If the body is a byte array, try to match.
var detectedBodyType = requestMessage?.BodyData?.DetectedBodyType;
if (detectedBodyType == BodyType.Bytes || detectedBodyType == BodyType.String)
{
return exactObjectMatcher.IsMatch(requestMessage.BodyData.BodyAsBytes);
}
return objectMatcher.IsMatch(requestMessage.BodyData.BodyAsBytes);
}
// Check if the matcher is a IObjectMatcher
if (matcher is IObjectMatcher objectMatcher)
{
// If the body is a JSON object, try to match.
if (requestMessage?.BodyData?.DetectedBodyType == BodyType.Json)
{
return objectMatcher.IsMatch(requestMessage.BodyData.BodyAsJson);
}
// If the body is a byte array, try to match.
if (requestMessage?.BodyData?.DetectedBodyType == BodyType.Bytes)
{
return objectMatcher.IsMatch(requestMessage.BodyData.BodyAsBytes);
}
}
// Check if the matcher is a IStringMatcher
if (matcher is IStringMatcher stringMatcher)
{
// 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)
{
return stringMatcher.IsMatch(requestMessage.BodyData.BodyAsString);
}
}
return MatchScores.Mismatch;
}
private double CalculateMatchScore(IRequestMessage requestMessage)
// Check if the matcher is a IStringMatcher
if (matcher is IStringMatcher stringMatcher)
{
if (Matchers != null && Matchers.Any())
// 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)
{
return Matchers.Max(matcher => CalculateMatchScore(requestMessage, matcher));
return stringMatcher.IsMatch(requestMessage.BodyData.BodyAsString);
}
if (Func != null)
{
return MatchScores.ToScore(Func(requestMessage?.BodyData?.BodyAsString));
}
if (JsonFunc != null)
{
return MatchScores.ToScore(JsonFunc(requestMessage?.BodyData?.BodyAsJson));
}
if (DataFunc != null)
{
return MatchScores.ToScore(DataFunc(requestMessage?.BodyData?.BodyAsBytes));
}
if (BodyDataFunc != null)
{
return MatchScores.ToScore(BodyDataFunc(requestMessage?.BodyData));
}
return MatchScores.Mismatch;
}
return MatchScores.Mismatch;
}
private double CalculateMatchScore(IRequestMessage requestMessage)
{
if (Matchers != null)
{
var matchersResult = Matchers.Select(matcher => CalculateMatchScore(requestMessage, matcher)).ToArray();
return MatchScores.ToScore(matchersResult, MatchOperator);
}
if (Func != null)
{
return MatchScores.ToScore(Func(requestMessage.BodyData?.BodyAsString));
}
if (JsonFunc != null)
{
return MatchScores.ToScore(JsonFunc(requestMessage.BodyData?.BodyAsJson));
}
if (DataFunc != null)
{
return MatchScores.ToScore(DataFunc(requestMessage.BodyData?.BodyAsBytes));
}
if (BodyDataFunc != null)
{
return MatchScores.ToScore(BodyDataFunc(requestMessage.BodyData));
}
return MatchScores.Mismatch;
}
}

View File

@@ -1,75 +1,98 @@
using System;
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using AnyOfTypes;
using Stef.Validation;
using WireMock.Models;
namespace WireMock.Matchers.Request
namespace WireMock.Matchers.Request;
/// <summary>
/// The request clientIP matcher.
/// </summary>
public class RequestMessageClientIPMatcher : IRequestMatcher
{
/// <summary>
/// The request ClientIP matcher.
/// The matchers
/// </summary>
public class RequestMessageClientIPMatcher : IRequestMatcher
public IReadOnlyList<IStringMatcher>? Matchers { get; }
/// <summary>
/// The clientIP functions
/// </summary>
public Func<string, bool>[]? Funcs { get; }
/// <summary>
/// The <see cref="MatchBehaviour"/>
/// </summary>
public MatchBehaviour Behaviour { get; }
/// <summary>
/// The <see cref="MatchOperator"/>
/// </summary>
public MatchOperator MatchOperator { get; }
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageClientIPMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="matchOperator">The <see cref="MatchOperator"/> to use.</param>
/// <param name="clientIPs">The clientIPs.</param>
public RequestMessageClientIPMatcher(
MatchBehaviour matchBehaviour,
MatchOperator matchOperator,
params string[] clientIPs) :
this(matchBehaviour, matchOperator, clientIPs
.Select(clientIP => new WildcardMatcher(matchBehaviour, new AnyOf<string, StringPattern>[] { clientIP }, false, false, matchOperator))
.Cast<IStringMatcher>().ToArray())
{
/// <summary>
/// The matchers.
/// </summary>
public IReadOnlyList<IStringMatcher> Matchers { get; }
Behaviour = matchBehaviour;
MatchOperator = matchOperator;
}
/// <summary>
/// The ClientIP functions.
/// </summary>
public Func<string, bool>[] Funcs { get; }
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageClientIPMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="matchOperator">The <see cref="MatchOperator"/> to use.</param>
/// <param name="matchers">The matchers.</param>
public RequestMessageClientIPMatcher(MatchBehaviour matchBehaviour, MatchOperator matchOperator, params IStringMatcher[] matchers)
{
Matchers = Guard.NotNull(matchers);
Behaviour = matchBehaviour;
MatchOperator = matchOperator;
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageClientIPMatcher"/> class.
/// </summary>
/// <param name="clientIPs">The clientIPs.</param>
/// <param name="matchBehaviour">The match behaviour.</param>
public RequestMessageClientIPMatcher(MatchBehaviour matchBehaviour, [NotNull] params string[] clientIPs) : this(clientIPs.Select(ip => new WildcardMatcher(matchBehaviour, ip)).Cast<IStringMatcher>().ToArray())
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageClientIPMatcher"/> class.
/// </summary>
/// <param name="funcs">The clientIP functions.</param>
public RequestMessageClientIPMatcher(params Func<string, bool>[] funcs)
{
Funcs = Guard.NotNull(funcs);
}
/// <inheritdoc />
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
{
double score = IsMatch(requestMessage);
return requestMatchResult.AddScore(GetType(), score);
}
private double IsMatch(IRequestMessage requestMessage)
{
if (Matchers != null)
{
var results = Matchers.Select(m => m.IsMatch(requestMessage.ClientIP)).ToArray();
return MatchScores.ToScore(results, MatchOperator);
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageClientIPMatcher"/> class.
/// </summary>
/// <param name="matchers">The matchers.</param>
public RequestMessageClientIPMatcher([NotNull] params IStringMatcher[] matchers)
if (Funcs != null)
{
Guard.NotNull(matchers, nameof(matchers));
Matchers = matchers;
var results = Funcs.Select(func => func(requestMessage.ClientIP)).ToArray();
return MatchScores.ToScore(results, MatchOperator);
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageClientIPMatcher"/> class.
/// </summary>
/// <param name="funcs">The clientIP functions.</param>
public RequestMessageClientIPMatcher([NotNull] params Func<string, bool>[] funcs)
{
Guard.NotNull(funcs, nameof(funcs));
Funcs = funcs;
}
/// <inheritdoc />
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
{
double score = IsMatch(requestMessage);
return requestMatchResult.AddScore(GetType(), score);
}
private double IsMatch(IRequestMessage requestMessage)
{
if (Matchers != null)
{
return Matchers.Max(matcher => matcher.IsMatch(requestMessage.ClientIP));
}
if (Funcs != null)
{
return MatchScores.ToScore(requestMessage.ClientIP != null && Funcs.Any(func => func(requestMessage.ClientIP)));
}
return MatchScores.Mismatch;
}
return MatchScores.Mismatch;
}
}

View File

@@ -1,130 +1,142 @@
using JetBrains.Annotations;
using System;
using System.Collections.Generic;
using System.Linq;
using WireMock.Types;
using Stef.Validation;
using WireMock.Types;
namespace WireMock.Matchers.Request
namespace WireMock.Matchers.Request;
/// <summary>
/// The request header matcher.
/// </summary>
/// <inheritdoc cref="IRequestMatcher"/>
public class RequestMessageHeaderMatcher : IRequestMatcher
{
private readonly MatchBehaviour _matchBehaviour;
private readonly bool _ignoreCase;
/// <summary>
/// The request header matcher.
/// The functions
/// </summary>
/// <inheritdoc cref="IRequestMatcher"/>
public class RequestMessageHeaderMatcher : IRequestMatcher
public Func<IDictionary<string, string[]>, bool>[]? Funcs { get; }
/// <summary>
/// The name
/// </summary>
public string? Name { get; }
/// <value>
/// The matchers.
/// </value>
public IStringMatcher[]? Matchers { get; }
/// <summary>
/// The <see cref="MatchOperator"/>
/// </summary>
public MatchOperator MatchOperator { get; } = MatchOperator.Or;
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageHeaderMatcher"/> class.
/// </summary>
/// <param name="name">The name.</param>
/// <param name="pattern">The pattern.</param>
/// <param name="ignoreCase">Ignore the case from the pattern.</param>
/// <param name="matchBehaviour">The match behaviour.</param>
public RequestMessageHeaderMatcher(MatchBehaviour matchBehaviour, string name, string pattern, bool ignoreCase)
{
private readonly MatchBehaviour _matchBehaviour;
private readonly bool _ignoreCase;
Guard.NotNull(name);
Guard.NotNull(pattern);
/// <summary>
/// The functions
/// </summary>
public Func<IDictionary<string, string[]>, bool>[] Funcs { get; }
_matchBehaviour = matchBehaviour;
_ignoreCase = ignoreCase;
Name = name;
Matchers = new IStringMatcher[] { new WildcardMatcher(matchBehaviour, pattern, ignoreCase) };
}
/// <summary>
/// The name
/// </summary>
public string Name { get; }
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageHeaderMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="matchOperator">The <see cref="MatchOperator"/> to use.</param>
/// <param name="name">The name.</param>
/// <param name="patterns">The patterns.</param>
/// <param name="ignoreCase">Ignore the case from the pattern.</param>
public RequestMessageHeaderMatcher(MatchBehaviour matchBehaviour, MatchOperator matchOperator, string name, bool ignoreCase, params string[] patterns) :
this(matchBehaviour, matchOperator, name, ignoreCase, patterns.Select(pattern => new WildcardMatcher(matchBehaviour, pattern, ignoreCase)).Cast<IStringMatcher>().ToArray())
{
Guard.NotNull(patterns);
}
/// <value>
/// The matchers.
/// </value>
public IStringMatcher[] Matchers { get; }
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageHeaderMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="matchOperator">The <see cref="MatchOperator"/> to use.</param>
/// <param name="name">The name.</param>
/// <param name="matchers">The matchers.</param>
/// <param name="ignoreCase">Ignore the case from the pattern.</param>
public RequestMessageHeaderMatcher(MatchBehaviour matchBehaviour, MatchOperator matchOperator, string name, bool ignoreCase, params IStringMatcher[] matchers)
{
Guard.NotNull(name);
Guard.NotNull(matchers);
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageHeaderMatcher"/> class.
/// </summary>
/// <param name="name">The name.</param>
/// <param name="pattern">The pattern.</param>
/// <param name="ignoreCase">Ignore the case from the pattern.</param>
/// <param name="matchBehaviour">The match behaviour.</param>
public RequestMessageHeaderMatcher(MatchBehaviour matchBehaviour, [NotNull] string name, [NotNull] string pattern, bool ignoreCase)
_matchBehaviour = matchBehaviour;
MatchOperator = matchOperator;
Name = name;
Matchers = matchers;
_ignoreCase = ignoreCase;
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageHeaderMatcher"/> class.
/// </summary>
/// <param name="funcs">The funcs.</param>
public RequestMessageHeaderMatcher(params Func<IDictionary<string, string[]>, bool>[] funcs)
{
Funcs = Guard.NotNull(funcs);
}
/// <inheritdoc />
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
{
double score = IsMatch(requestMessage);
return requestMatchResult.AddScore(GetType(), score);
}
private double IsMatch(IRequestMessage requestMessage)
{
if (requestMessage.Headers == null)
{
Guard.NotNull(name, nameof(name));
Guard.NotNull(pattern, nameof(pattern));
_matchBehaviour = matchBehaviour;
_ignoreCase = ignoreCase;
Name = name;
Matchers = new IStringMatcher[] { new WildcardMatcher(matchBehaviour, pattern, ignoreCase) };
return MatchBehaviourHelper.Convert(_matchBehaviour, MatchScores.Mismatch);
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageHeaderMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="name">The name.</param>
/// <param name="patterns">The patterns.</param>
/// <param name="ignoreCase">Ignore the case from the pattern.</param>
public RequestMessageHeaderMatcher(MatchBehaviour matchBehaviour, [NotNull] string name, bool ignoreCase, [NotNull] params string[] patterns) :
this(matchBehaviour, name, ignoreCase, patterns.Select(pattern => new WildcardMatcher(matchBehaviour, pattern, ignoreCase)).Cast<IStringMatcher>().ToArray())
// Check if we want to use IgnoreCase to compare the Header-Name and Header-Value(s)
var headers = !_ignoreCase ? requestMessage.Headers : new Dictionary<string, WireMockList<string>>(requestMessage.Headers, StringComparer.OrdinalIgnoreCase);
if (Funcs != null)
{
Guard.NotNull(patterns, nameof(patterns));
var funcResults = Funcs.Select(f => f(headers.ToDictionary(entry => entry.Key, entry => entry.Value.ToArray()))).ToArray();
return MatchScores.ToScore(funcResults, MatchOperator);
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageHeaderMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="name">The name.</param>
/// <param name="matchers">The matchers.</param>
/// <param name="ignoreCase">Ignore the case from the pattern.</param>
public RequestMessageHeaderMatcher(MatchBehaviour matchBehaviour, [NotNull] string name, bool ignoreCase, [NotNull] params IStringMatcher[] matchers)
if (Matchers != null)
{
Guard.NotNull(name, nameof(name));
Guard.NotNull(matchers, nameof(matchers));
_matchBehaviour = matchBehaviour;
Name = name;
Matchers = matchers;
_ignoreCase = ignoreCase;
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageHeaderMatcher"/> class.
/// </summary>
/// <param name="funcs">The funcs.</param>
public RequestMessageHeaderMatcher([NotNull] params Func<IDictionary<string, string[]>, bool>[] funcs)
{
Guard.NotNull(funcs, nameof(funcs));
Funcs = funcs;
}
/// <inheritdoc />
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
{
double score = IsMatch(requestMessage);
return requestMatchResult.AddScore(GetType(), score);
}
private double IsMatch(IRequestMessage requestMessage)
{
if (requestMessage.Headers == null)
if (!headers.ContainsKey(Name!))
{
return MatchBehaviourHelper.Convert(_matchBehaviour, MatchScores.Mismatch);
}
// Check if we want to use IgnoreCase to compare the Header-Name and Header-Value(s)
var headers = !_ignoreCase ? requestMessage.Headers : new Dictionary<string, WireMockList<string>>(requestMessage.Headers, StringComparer.OrdinalIgnoreCase);
if (Funcs != null)
var results = new List<double>();
foreach (var matcher in Matchers)
{
return MatchScores.ToScore(Funcs.Any(f => f(headers.ToDictionary(entry => entry.Key, entry => entry.Value.ToArray()))));
var resultsPerMatcher = headers[Name!].Select(v => matcher.IsMatch(v)).ToArray();
results.Add(MatchScores.ToScore(resultsPerMatcher, MatchOperator.And));
}
if (Matchers == null)
{
return MatchScores.Mismatch;
}
if (!headers.ContainsKey(Name))
{
return MatchBehaviourHelper.Convert(_matchBehaviour, MatchScores.Mismatch);
}
WireMockList<string> list = headers[Name];
return Matchers.Max(m => list.Max(m.IsMatch)); // TODO : is this correct ?
return MatchBehaviourHelper.Convert(_matchBehaviour, MatchScores.ToScore(results, MatchOperator));
}
return MatchBehaviourHelper.Convert(_matchBehaviour, MatchScores.Mismatch);
}
}

View File

@@ -1,45 +1,52 @@
using System;
using System.Linq;
using JetBrains.Annotations;
using Stef.Validation;
namespace WireMock.Matchers.Request
namespace WireMock.Matchers.Request;
/// <summary>
/// The request method matcher.
/// </summary>
internal class RequestMessageMethodMatcher : IRequestMatcher
{
/// <summary>
/// The request verb matcher.
/// The <see cref="Matchers.MatchBehaviour"/>
/// </summary>
internal class RequestMessageMethodMatcher : IRequestMatcher
public MatchBehaviour MatchBehaviour { get; }
/// <summary>
/// The <see cref="Matchers.MatchOperator"/>
/// </summary>
public MatchOperator MatchOperator { get; }
/// <summary>
/// The methods
/// </summary>
public string[] Methods { get; }
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageMethodMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use.</param>
/// <param name="methods">The methods.</param>
public RequestMessageMethodMatcher(MatchBehaviour matchBehaviour, MatchOperator matchOperator, params string[] methods)
{
private readonly MatchBehaviour _matchBehaviour;
Methods = Guard.NotNull(methods);
MatchBehaviour = matchBehaviour;
MatchOperator = matchOperator;
}
/// <summary>
/// The methods
/// </summary>
public string[] Methods { get; }
/// <inheritdoc />
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
{
double score = MatchBehaviourHelper.Convert(MatchBehaviour, IsMatch(requestMessage));
return requestMatchResult.AddScore(GetType(), score);
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageMethodMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="methods">The methods.</param>
public RequestMessageMethodMatcher(MatchBehaviour matchBehaviour, [NotNull] params string[] methods)
{
Guard.NotNull(methods, nameof(methods));
_matchBehaviour = matchBehaviour;
Methods = methods;
}
/// <inheritdoc />
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
{
double score = MatchBehaviourHelper.Convert(_matchBehaviour, IsMatch(requestMessage));
return requestMatchResult.AddScore(GetType(), score);
}
private double IsMatch(IRequestMessage requestMessage)
{
return MatchScores.ToScore(Methods.Contains(requestMessage.Method, StringComparer.OrdinalIgnoreCase));
}
private double IsMatch(IRequestMessage requestMessage)
{
var scores = Methods.Select(m => string.Equals(m, requestMessage.Method, StringComparison.OrdinalIgnoreCase)).ToArray();
return MatchScores.ToScore(scores, MatchOperator);
}
}

View File

@@ -1,152 +1,146 @@
using JetBrains.Annotations;
using System;
using System.Collections.Generic;
using System.Linq;
using WireMock.Types;
using Stef.Validation;
using WireMock.Types;
namespace WireMock.Matchers.Request
namespace WireMock.Matchers.Request;
/// <summary>
/// The request parameters matcher.
/// </summary>
public class RequestMessageParamMatcher : IRequestMatcher
{
private readonly MatchBehaviour _matchBehaviour;
/// <summary>
/// The request parameters matcher.
/// The funcs
/// </summary>
public class RequestMessageParamMatcher : IRequestMatcher
public Func<IDictionary<string, WireMockList<string>>, bool>[]? Funcs { get; }
/// <summary>
/// The key
/// </summary>
public string? Key { get; }
/// <summary>
/// Defines if the key should be matched using case-ignore.
/// </summary>
public bool? IgnoreCase { get; }
/// <summary>
/// The matchers.
/// </summary>
public IReadOnlyList<IStringMatcher>? Matchers { get; }
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageParamMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="key">The key.</param>
/// <param name="ignoreCase">Defines if the key should be matched using case-ignore.</param>
public RequestMessageParamMatcher(MatchBehaviour matchBehaviour, string key, bool ignoreCase) : this(matchBehaviour, key, ignoreCase, (IStringMatcher[]?)null)
{
private readonly MatchBehaviour _matchBehaviour;
}
/// <summary>
/// The funcs
/// </summary>
public Func<IDictionary<string, WireMockList<string>>, bool>[] Funcs { get; }
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageParamMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="key">The key.</param>
/// <param name="ignoreCase">Defines if the key should be matched using case-ignore.</param>
/// <param name="values">The values.</param>
public RequestMessageParamMatcher(MatchBehaviour matchBehaviour, string key, bool ignoreCase, string[]? values) : this(matchBehaviour, key, ignoreCase, values?.Select(value => new ExactMatcher(matchBehaviour, false, MatchOperator.And, value)).Cast<IStringMatcher>().ToArray())
{
}
/// <summary>
/// The key
/// </summary>
public string Key { get; }
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageParamMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="key">The key.</param>
/// <param name="ignoreCase">Defines if the key should be matched using case-ignore.</param>
/// <param name="matchers">The matchers.</param>
public RequestMessageParamMatcher(MatchBehaviour matchBehaviour, string key, bool ignoreCase, IStringMatcher[]? matchers)
{
_matchBehaviour = matchBehaviour;
Key = Guard.NotNull(key);
IgnoreCase = ignoreCase;
Matchers = matchers;
}
/// <summary>
/// Defines if the key should be matched using case-ignore.
/// </summary>
public bool? IgnoreCase { get; private set; }
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageParamMatcher"/> class.
/// </summary>
/// <param name="funcs">The funcs.</param>
public RequestMessageParamMatcher(params Func<IDictionary<string, WireMockList<string>>, bool>[] funcs)
{
Funcs = Guard.NotNull(funcs);
}
/// <summary>
/// The matchers.
/// </summary>
public IReadOnlyList<IStringMatcher> Matchers { get; }
/// <inheritdoc />
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
{
double score = MatchBehaviourHelper.Convert(_matchBehaviour, IsMatch(requestMessage));
return requestMatchResult.AddScore(GetType(), score);
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageParamMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="key">The key.</param>
/// <param name="ignoreCase">Defines if the key should be matched using case-ignore.</param>
public RequestMessageParamMatcher(MatchBehaviour matchBehaviour, [NotNull] string key, bool ignoreCase) : this(matchBehaviour, key, ignoreCase, (IStringMatcher[])null)
private double IsMatch(IRequestMessage requestMessage)
{
if (Funcs != null)
{
return MatchScores.ToScore(requestMessage.Query != null && Funcs.Any(f => f(requestMessage.Query)));
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageParamMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="key">The key.</param>
/// <param name="ignoreCase">Defines if the key should be matched using case-ignore.</param>
/// <param name="values">The values.</param>
public RequestMessageParamMatcher(MatchBehaviour matchBehaviour, [NotNull] string key, bool ignoreCase, [CanBeNull] string[] values) : this(matchBehaviour, key, ignoreCase, values?.Select(value => new ExactMatcher(matchBehaviour, false, value)).Cast<IStringMatcher>().ToArray())
WireMockList<string> valuesPresentInRequestMessage = ((RequestMessage)requestMessage).GetParameter(Key, IgnoreCase ?? false);
if (valuesPresentInRequestMessage == null)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageParamMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="key">The key.</param>
/// <param name="ignoreCase">Defines if the key should be matched using case-ignore.</param>
/// <param name="matchers">The matchers.</param>
public RequestMessageParamMatcher(MatchBehaviour matchBehaviour, [NotNull] string key, bool ignoreCase, [CanBeNull] IStringMatcher[] matchers)
{
Guard.NotNull(key, nameof(key));
_matchBehaviour = matchBehaviour;
Key = key;
IgnoreCase = ignoreCase;
Matchers = matchers;
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageParamMatcher"/> class.
/// </summary>
/// <param name="funcs">The funcs.</param>
public RequestMessageParamMatcher([NotNull] params Func<IDictionary<string, WireMockList<string>>, bool>[] funcs)
{
Guard.NotNull(funcs, nameof(funcs));
Funcs = funcs;
}
/// <inheritdoc />
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
{
double score = MatchBehaviourHelper.Convert(_matchBehaviour, IsMatch(requestMessage));
return requestMatchResult.AddScore(GetType(), score);
}
private double IsMatch(IRequestMessage requestMessage)
{
if (Funcs != null)
{
return MatchScores.ToScore(requestMessage.Query != null && Funcs.Any(f => f(requestMessage.Query)));
}
WireMockList<string> valuesPresentInRequestMessage = ((RequestMessage) requestMessage).GetParameter(Key, IgnoreCase ?? false);
if (valuesPresentInRequestMessage == null)
{
// Key is not present at all, just return Mismatch
return MatchScores.Mismatch;
}
if (Matchers != null && Matchers.Any())
{
// Return the score based on Matchers and valuesPresentInRequestMessage
return CalculateScore(valuesPresentInRequestMessage);
}
if (Matchers == null || !Matchers.Any())
{
// Matchers are null or not defined, and Key is present, just return Perfect.
return MatchScores.Perfect;
}
// Key is not present at all, just return Mismatch
return MatchScores.Mismatch;
}
private double CalculateScore(WireMockList<string> valuesPresentInRequestMessage)
if (Matchers != null && Matchers.Any())
{
var total = new List<double>();
// Return the score based on Matchers and valuesPresentInRequestMessage
return CalculateScore(valuesPresentInRequestMessage);
}
// If the total patterns in all matchers > values in message, use the matcher as base
if (Matchers.Sum(m => m.GetPatterns().Length) > valuesPresentInRequestMessage.Count)
{
foreach (var matcher in Matchers)
{
double score = 0d;
foreach (string valuePresentInRequestMessage in valuesPresentInRequestMessage)
{
score += matcher.IsMatch(valuePresentInRequestMessage) / matcher.GetPatterns().Length;
}
if (Matchers == null || !Matchers.Any())
{
// Matchers are null or not defined, and Key is present, just return Perfect.
return MatchScores.Perfect;
}
total.Add(score);
}
}
else
return MatchScores.Mismatch;
}
private double CalculateScore(WireMockList<string> valuesPresentInRequestMessage)
{
var total = new List<double>();
// If the total patterns in all matchers > values in message, use the matcher as base
if (Matchers.Sum(m => m.GetPatterns().Length) > valuesPresentInRequestMessage.Count)
{
foreach (var matcher in Matchers)
{
double score = 0d;
foreach (string valuePresentInRequestMessage in valuesPresentInRequestMessage)
{
double score = Matchers.Max(m => m.IsMatch(valuePresentInRequestMessage));
total.Add(score);
score += matcher.IsMatch(valuePresentInRequestMessage) / matcher.GetPatterns().Length;
}
}
return total.Any() ? MatchScores.ToScore(total) : MatchScores.Mismatch;
total.Add(score);
}
}
else
{
foreach (string valuePresentInRequestMessage in valuesPresentInRequestMessage)
{
double score = Matchers.Max(m => m.IsMatch(valuePresentInRequestMessage));
total.Add(score);
}
}
return total.Any() ? MatchScores.ToScore(total, MatchOperator.Average) : MatchScores.Mismatch;
}
}

View File

@@ -1,77 +1,98 @@
using System;
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using AnyOfTypes;
using Stef.Validation;
using WireMock.Models;
namespace WireMock.Matchers.Request
namespace WireMock.Matchers.Request;
/// <summary>
/// The request path matcher.
/// </summary>
public class RequestMessagePathMatcher : IRequestMatcher
{
/// <summary>
/// The request path matcher.
/// The matchers
/// </summary>
public class RequestMessagePathMatcher : IRequestMatcher
public IReadOnlyList<IStringMatcher>? Matchers { get; }
/// <summary>
/// The path functions
/// </summary>
public Func<string, bool>[]? Funcs { get; }
/// <summary>
/// The <see cref="MatchBehaviour"/>
/// </summary>
public MatchBehaviour Behaviour { get; }
/// <summary>
/// The <see cref="MatchOperator"/>
/// </summary>
public MatchOperator MatchOperator { get; }
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessagePathMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="matchOperator">The <see cref="MatchOperator"/> to use.</param>
/// <param name="paths">The paths.</param>
public RequestMessagePathMatcher(
MatchBehaviour matchBehaviour,
MatchOperator matchOperator,
params string[] paths) :
this(matchBehaviour, matchOperator, paths
.Select(path => new WildcardMatcher(matchBehaviour, new AnyOf<string, StringPattern>[] { path }, false, false, matchOperator))
.Cast<IStringMatcher>().ToArray())
{
/// <summary>
/// The matchers
/// </summary>
public IReadOnlyList<IStringMatcher> Matchers { get; }
Behaviour = matchBehaviour;
MatchOperator = matchOperator;
}
/// <summary>
/// The path functions
/// </summary>
public Func<string, bool>[] Funcs { get; }
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessagePathMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="matchOperator">The <see cref="MatchOperator"/> to use.</param>
/// <param name="matchers">The matchers.</param>
public RequestMessagePathMatcher(MatchBehaviour matchBehaviour, MatchOperator matchOperator, params IStringMatcher[] matchers)
{
Matchers = Guard.NotNull(matchers);
Behaviour = matchBehaviour;
MatchOperator = matchOperator;
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessagePathMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="paths">The paths.</param>
public RequestMessagePathMatcher(MatchBehaviour matchBehaviour, [NotNull] params string[] paths) : this(paths.Select(path => new WildcardMatcher(matchBehaviour, path)).Cast<IStringMatcher>().ToArray())
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessagePathMatcher"/> class.
/// </summary>
/// <param name="funcs">The path functions.</param>
public RequestMessagePathMatcher(params Func<string, bool>[] funcs)
{
Funcs = Guard.NotNull(funcs);
}
/// <inheritdoc />
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
{
double score = IsMatch(requestMessage);
return requestMatchResult.AddScore(GetType(), score);
}
private double IsMatch(IRequestMessage requestMessage)
{
if (Matchers != null)
{
var results = Matchers.Select(m => m.IsMatch(requestMessage.Path)).ToArray();
return MatchScores.ToScore(results, MatchOperator);
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessagePathMatcher"/> class.
/// </summary>
/// <param name="matchers">The matchers.</param>
public RequestMessagePathMatcher([NotNull] params IStringMatcher[] matchers)
if (Funcs != null)
{
Guard.NotNull(matchers, nameof(matchers));
Matchers = matchers;
var results = Funcs.Select(func => func(requestMessage.Path)).ToArray();
return MatchScores.ToScore(results, MatchOperator);
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessagePathMatcher"/> class.
/// </summary>
/// <param name="funcs">The path functions.</param>
public RequestMessagePathMatcher([NotNull] params Func<string, bool>[] funcs)
{
Guard.NotNull(funcs, nameof(funcs));
Funcs = funcs;
}
/// <inheritdoc cref="IRequestMatcher.GetMatchingScore"/>
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
{
double score = IsMatch(requestMessage);
return requestMatchResult.AddScore(GetType(), score);
}
private double IsMatch(IRequestMessage requestMessage)
{
if (Matchers != null)
{
return Matchers.Max(m => m.IsMatch(requestMessage.Path));
}
if (Funcs != null)
{
return MatchScores.ToScore(requestMessage.Path != null && Funcs.Any(func => func(requestMessage.Path)));
}
return MatchScores.Mismatch;
}
return MatchScores.Mismatch;
}
}

View File

@@ -1,75 +1,98 @@
using System;
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using AnyOfTypes;
using Stef.Validation;
using WireMock.Models;
namespace WireMock.Matchers.Request
namespace WireMock.Matchers.Request;
/// <summary>
/// The request url matcher.
/// </summary>
public class RequestMessageUrlMatcher : IRequestMatcher
{
/// <summary>
/// The request url matcher.
/// The matchers
/// </summary>
public class RequestMessageUrlMatcher : IRequestMatcher
public IReadOnlyList<IStringMatcher>? Matchers { get; }
/// <summary>
/// The url functions
/// </summary>
public Func<string, bool>[]? Funcs { get; }
/// <summary>
/// The <see cref="MatchBehaviour"/>
/// </summary>
public MatchBehaviour Behaviour { get; }
/// <summary>
/// The <see cref="MatchOperator"/>
/// </summary>
public MatchOperator MatchOperator { get; }
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageUrlMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="matchOperator">The <see cref="MatchOperator"/> to use.</param>
/// <param name="urls">The urls.</param>
public RequestMessageUrlMatcher(
MatchBehaviour matchBehaviour,
MatchOperator matchOperator,
params string[] urls) :
this(matchBehaviour, matchOperator, urls
.Select(url => new WildcardMatcher(matchBehaviour, new AnyOf<string, StringPattern>[] { url }, false, false, matchOperator))
.Cast<IStringMatcher>().ToArray())
{
/// <summary>
/// The matchers.
/// </summary>
public IReadOnlyList<IStringMatcher> Matchers { get; }
Behaviour = matchBehaviour;
MatchOperator = matchOperator;
}
/// <summary>
/// The url functions.
/// </summary>
public Func<string, bool>[] Funcs { get; }
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageUrlMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="matchOperator">The <see cref="MatchOperator"/> to use. (default = "Or")</param>
/// <param name="matchers">The matchers.</param>
public RequestMessageUrlMatcher(MatchBehaviour matchBehaviour, MatchOperator matchOperator, params IStringMatcher[] matchers)
{
Matchers = Guard.NotNull(matchers);
Behaviour = matchBehaviour;
MatchOperator = matchOperator;
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageUrlMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="urls">The urls.</param>
public RequestMessageUrlMatcher(MatchBehaviour matchBehaviour, [NotNull] params string[] urls) : this(urls.Select(url => new WildcardMatcher(matchBehaviour, url)).Cast<IStringMatcher>().ToArray())
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageUrlMatcher"/> class.
/// </summary>
/// <param name="funcs">The url functions.</param>
public RequestMessageUrlMatcher(params Func<string, bool>[] funcs)
{
Funcs = Guard.NotNull(funcs);
}
/// <inheritdoc />
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
{
double score = IsMatch(requestMessage);
return requestMatchResult.AddScore(GetType(), score);
}
private double IsMatch(IRequestMessage requestMessage)
{
if (Matchers != null)
{
var results = Matchers.Select(m => m.IsMatch(requestMessage.Url)).ToArray();
return MatchScores.ToScore(results, MatchOperator);
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageUrlMatcher"/> class.
/// </summary>
/// <param name="matchers">The matchers.</param>
public RequestMessageUrlMatcher([NotNull] params IStringMatcher[] matchers)
if (Funcs != null)
{
Guard.NotNull(matchers, nameof(matchers));
Matchers = matchers;
var results = Funcs.Select(func => func(requestMessage.Url)).ToArray();
return MatchScores.ToScore(results, MatchOperator);
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageUrlMatcher"/> class.
/// </summary>
/// <param name="funcs">The url functions.</param>
public RequestMessageUrlMatcher([NotNull] params Func<string, bool>[] funcs)
{
Guard.NotNull(funcs, nameof(funcs));
Funcs = funcs;
}
/// <inheritdoc />
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
{
double score = IsMatch(requestMessage);
return requestMatchResult.AddScore(GetType(), score);
}
private double IsMatch(IRequestMessage requestMessage)
{
if (Matchers != null)
{
return Matchers.Max(matcher => matcher.IsMatch(requestMessage.Url));
}
if (Funcs != null)
{
return MatchScores.ToScore(requestMessage.Url != null && Funcs.Any(func => func(requestMessage.Url)));
}
return MatchScores.Mismatch;
}
return MatchScores.Mismatch;
}
}