Add ThrowExceptionWhenMatcherFails option to all Matchers (#500)

* .

* ut

* IMatcher.ThrowException

* settings

* more tests

* linq matcher throw

* .

* .
This commit is contained in:
Stef Heyenrath
2020-08-13 08:58:18 +02:00
committed by GitHub
parent 0d102f3af4
commit 06be3aff95
29 changed files with 1798 additions and 1607 deletions

View File

@@ -26,13 +26,18 @@
public int? MaxRequestLogCount { get; set; }
/// <summary>
/// Gets or sets wether to allow a body for all HTTP methods.
/// Allow a Body for all HTTP Methods. (default set to false).
/// </summary>
public bool? AllowBodyForAllHttpMethods { get; set; }
/// <summary>
/// Gets or sets wether to handle all requests synchronously.
/// Handle all requests synchronously. (default set to false).
/// </summary>
public bool? HandleRequestsSynchronously { get; set; }
/// <summary>
/// Throw an exception when the Matcher fails because of invalid input. (default set to false).
/// </summary>
public bool? ThrowExceptionWhenMatcherFails { get; set; }
}
}

View File

@@ -29,6 +29,9 @@ namespace WireMock.Matchers
public MatchBehaviour MatchBehaviour { get; }
/// <inheritdoc cref="IMatcher.ThrowException"/>
public bool ThrowException { get; }
private readonly string[] _patterns;
/// <summary>
@@ -49,6 +52,7 @@ namespace WireMock.Matchers
Check.NotNull(patterns, nameof(patterns));
MatchBehaviour = matchBehaviour;
ThrowException = false;
_patterns = patterns;
}

View File

@@ -45,7 +45,9 @@ namespace WireMock.Matchers
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="patterns">The patterns.</param>
/// <param name="ignoreCase">IgnoreCase (default false)</param>
public ContentTypeMatcher(MatchBehaviour matchBehaviour, [NotNull] string[] patterns, bool ignoreCase = false) : base(matchBehaviour, patterns, ignoreCase)
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
public ContentTypeMatcher(MatchBehaviour matchBehaviour, [NotNull] string[] patterns, bool ignoreCase = false, bool throwException = false) :
base(matchBehaviour, patterns, ignoreCase, throwException)
{
_patterns = patterns;
}

View File

@@ -15,11 +15,14 @@ namespace WireMock.Matchers
/// <inheritdoc cref="IMatcher.MatchBehaviour"/>
public MatchBehaviour MatchBehaviour { get; }
/// <inheritdoc cref="IMatcher.ThrowException"/>
public bool ThrowException { get; }
/// <summary>
/// Initializes a new instance of the <see cref="ExactMatcher"/> class.
/// </summary>
/// <param name="values">The values.</param>
public ExactMatcher([NotNull] params string[] values) : this(MatchBehaviour.AcceptOnMatch, values)
public ExactMatcher([NotNull] params string[] values) : this(MatchBehaviour.AcceptOnMatch, false, values)
{
}
@@ -27,13 +30,15 @@ namespace WireMock.Matchers
/// Initializes a new instance of the <see cref="ExactMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
/// <param name="values">The values.</param>
public ExactMatcher(MatchBehaviour matchBehaviour, [NotNull] params string[] values)
public ExactMatcher(MatchBehaviour matchBehaviour, bool throwException = false, [NotNull] params string[] values)
{
Check.HasNoNulls(values, nameof(values));
_values = values;
MatchBehaviour = matchBehaviour;
ThrowException = throwException;
_values = values;
}
/// <inheritdoc cref="IStringMatcher.IsMatch"/>

View File

@@ -23,6 +23,9 @@ namespace WireMock.Matchers
/// <inheritdoc cref="IMatcher.MatchBehaviour"/>
public MatchBehaviour MatchBehaviour { get; }
/// <inheritdoc cref="IMatcher.ThrowException"/>
public bool ThrowException { get; }
/// <summary>
/// Initializes a new instance of the <see cref="ExactObjectMatcher"/> class.
/// </summary>
@@ -56,13 +59,15 @@ namespace WireMock.Matchers
/// Initializes a new instance of the <see cref="ExactObjectMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
/// <param name="value">The value.</param>
public ExactObjectMatcher(MatchBehaviour matchBehaviour, [NotNull] byte[] value)
public ExactObjectMatcher(MatchBehaviour matchBehaviour, [NotNull] byte[] value, bool throwException = false)
{
Check.NotNull(value, nameof(value));
ValueAsBytes = value;
MatchBehaviour = matchBehaviour;
ThrowException = throwException;
ValueAsBytes = value;
}
/// <inheritdoc cref="IObjectMatcher.IsMatch"/>

View File

@@ -14,5 +14,10 @@
/// Gets the match behaviour.
/// </summary>
MatchBehaviour MatchBehaviour { get; }
/// <summary>
/// Should this matcher throw an exception?
/// </summary>
bool ThrowException { get; }
}
}

View File

@@ -18,11 +18,14 @@ namespace WireMock.Matchers
/// <inheritdoc cref="IMatcher.MatchBehaviour"/>
public MatchBehaviour MatchBehaviour { get; }
/// <inheritdoc cref="IMatcher.ThrowException"/>
public bool ThrowException { get; }
/// <summary>
/// Initializes a new instance of the <see cref="JsonPathMatcher"/> class.
/// </summary>
/// <param name="patterns">The patterns.</param>
public JsonPathMatcher([NotNull] params string[] patterns) : this(MatchBehaviour.AcceptOnMatch, patterns)
public JsonPathMatcher([NotNull] params string[] patterns) : this(MatchBehaviour.AcceptOnMatch, false, patterns)
{
}
@@ -30,12 +33,14 @@ namespace WireMock.Matchers
/// Initializes a new instance of the <see cref="JsonPathMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
/// <param name="patterns">The patterns.</param>
public JsonPathMatcher(MatchBehaviour matchBehaviour, [NotNull] params string[] patterns)
public JsonPathMatcher(MatchBehaviour matchBehaviour, bool throwException = false, [NotNull] params string[] patterns)
{
Check.NotNull(patterns, nameof(patterns));
MatchBehaviour = matchBehaviour;
ThrowException = throwException;
_patterns = patterns;
}
@@ -52,7 +57,10 @@ namespace WireMock.Matchers
}
catch (JsonException)
{
// just ignore JsonException
if (ThrowException)
{
throw;
}
}
}
@@ -75,7 +83,10 @@ namespace WireMock.Matchers
}
catch (JsonException)
{
// just ignore JsonException
if (ThrowException)
{
throw;
}
}
}

View File

@@ -16,11 +16,23 @@ namespace WireMock.Matchers
/// <inheritdoc cref="IMatcher.MatchBehaviour"/>
public MatchBehaviour MatchBehaviour { get; }
/// <inheritdoc cref="IMatcher.ThrowException"/>
public bool ThrowException { get; }
/// <summary>
/// Initializes a new instance of the <see cref="JmesPathMatcher"/> class.
/// </summary>
/// <param name="patterns">The patterns.</param>
public JmesPathMatcher([NotNull] params string[] patterns) : this(MatchBehaviour.AcceptOnMatch, patterns)
public JmesPathMatcher([NotNull] params string[] patterns) : this(MatchBehaviour.AcceptOnMatch, false, patterns)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="JmesPathMatcher"/> class.
/// </summary>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
/// <param name="patterns">The patterns.</param>
public JmesPathMatcher(bool throwException = false, [NotNull] params string[] patterns) : this(MatchBehaviour.AcceptOnMatch, throwException, patterns)
{
}
@@ -28,12 +40,14 @@ namespace WireMock.Matchers
/// Initializes a new instance of the <see cref="JmesPathMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
/// <param name="patterns">The patterns.</param>
public JmesPathMatcher(MatchBehaviour matchBehaviour, [NotNull] params string[] patterns)
public JmesPathMatcher(MatchBehaviour matchBehaviour, bool throwException = false, [NotNull] params string[] patterns)
{
Check.NotNull(patterns, nameof(patterns));
MatchBehaviour = matchBehaviour;
ThrowException = throwException;
_patterns = patterns;
}
@@ -49,7 +63,10 @@ namespace WireMock.Matchers
}
catch (JsonException)
{
// just ignore JsonException
if (ThrowException)
{
throw;
}
}
}

View File

@@ -1,8 +1,8 @@
using JetBrains.Annotations;
using System.Collections;
using System.Linq;
using JetBrains.Annotations;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Collections;
using System.Linq;
using WireMock.Util;
using WireMock.Validation;
@@ -25,12 +25,18 @@ namespace WireMock.Matchers
/// <inheritdoc cref="IIgnoreCaseMatcher.IgnoreCase"/>
public bool IgnoreCase { get; }
/// <inheritdoc cref="IMatcher.ThrowException"/>
public bool ThrowException { get; }
private readonly JToken _valueAsJToken;
/// <summary>
/// Initializes a new instance of the <see cref="JsonMatcher"/> class.
/// </summary>
/// <param name="value">The string value to check for equality.</param>
/// <param name="ignoreCase">Ignore the case from the PropertyName and PropertyValue (string only).</param>
public JsonMatcher([NotNull] string value, bool ignoreCase = false) : this(MatchBehaviour.AcceptOnMatch, value, ignoreCase)
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
public JsonMatcher([NotNull] string value, bool ignoreCase = false, bool throwException = false) : this(MatchBehaviour.AcceptOnMatch, value, ignoreCase, throwException)
{
}
@@ -39,7 +45,8 @@ namespace WireMock.Matchers
/// </summary>
/// <param name="value">The object value to check for equality.</param>
/// <param name="ignoreCase">Ignore the case from the PropertyName and PropertyValue (string only).</param>
public JsonMatcher([NotNull] object value, bool ignoreCase = false) : this(MatchBehaviour.AcceptOnMatch, value, ignoreCase)
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
public JsonMatcher([NotNull] object value, bool ignoreCase = false, bool throwException = false) : this(MatchBehaviour.AcceptOnMatch, value, ignoreCase, throwException)
{
}
@@ -47,30 +54,19 @@ namespace WireMock.Matchers
/// Initializes a new instance of the <see cref="JsonMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="value">The string value to check for equality.</param>
/// <param name="value">The value to check for equality.</param>
/// <param name="ignoreCase">Ignore the case from the PropertyName and PropertyValue (string only).</param>
public JsonMatcher(MatchBehaviour matchBehaviour, [NotNull] string value, bool ignoreCase = false)
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
public JsonMatcher(MatchBehaviour matchBehaviour, [NotNull] object value, bool ignoreCase = false, bool throwException = false)
{
Check.NotNull(value, nameof(value));
MatchBehaviour = matchBehaviour;
Value = value;
IgnoreCase = ignoreCase;
}
ThrowException = throwException;
/// <summary>
/// Initializes a new instance of the <see cref="JsonMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="value">The object value to check for equality.</param>
/// <param name="ignoreCase">Ignore the case from the PropertyName and PropertyValue (string only).</param>
public JsonMatcher(MatchBehaviour matchBehaviour, [NotNull] object value, bool ignoreCase = false)
{
Check.NotNull(value, nameof(value));
MatchBehaviour = matchBehaviour;
Value = value;
IgnoreCase = ignoreCase;
_valueAsJToken = ConvertValueToJToken(value);
}
/// <inheritdoc cref="IObjectMatcher.IsMatch"/>
@@ -83,41 +79,41 @@ namespace WireMock.Matchers
{
try
{
// Check if JToken or object
JToken jtokenInput = input is JToken tokenInput ? tokenInput : JObject.FromObject(input);
var inputAsJToken = ConvertValueToJToken(input);
// Check if JToken, string, IEnumerable or object
JToken jtokenValue;
switch (Value)
{
case JToken tokenValue:
jtokenValue = tokenValue;
break;
case string stringValue:
jtokenValue = JsonUtils.Parse(stringValue);
break;
case IEnumerable enumerableValue:
jtokenValue = JArray.FromObject(enumerableValue);
break;
default:
jtokenValue = JObject.FromObject(Value);
break;
}
match = DeepEquals(jtokenValue, jtokenInput);
match = DeepEquals(_valueAsJToken, inputAsJToken);
}
catch (JsonException)
{
// just ignore JsonException
if (ThrowException)
{
throw;
}
}
}
return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.ToScore(match));
}
private static JToken ConvertValueToJToken(object value)
{
// Check if JToken, string, IEnumerable or object
switch (value)
{
case JToken tokenValue:
return tokenValue;
case string stringValue:
return JsonUtils.Parse(stringValue);
case IEnumerable enumerableValue:
return JArray.FromObject(enumerableValue);
default:
return JObject.FromObject(value);
}
}
private bool DeepEquals(JToken value, JToken input)
{
if (!IgnoreCase)

View File

@@ -17,6 +17,8 @@ namespace WireMock.Matchers
/// <inheritdoc cref="IMatcher.MatchBehaviour"/>
public MatchBehaviour MatchBehaviour { get; }
/// <inheritdoc cref="IMatcher.ThrowException"/>
public bool ThrowException { get; }
/// <summary>
/// Initializes a new instance of the <see cref="LinqMatcher"/> class.
@@ -30,7 +32,7 @@ namespace WireMock.Matchers
/// Initializes a new instance of the <see cref="LinqMatcher"/> class.
/// </summary>
/// <param name="patterns">The patterns.</param>
public LinqMatcher([NotNull] string[] patterns) : this(MatchBehaviour.AcceptOnMatch, patterns)
public LinqMatcher([NotNull] params string[] patterns) : this(MatchBehaviour.AcceptOnMatch, false, patterns)
{
}
@@ -39,7 +41,7 @@ namespace WireMock.Matchers
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="pattern">The pattern.</param>
public LinqMatcher(MatchBehaviour matchBehaviour, [NotNull] string pattern) : this(matchBehaviour, new[] { pattern })
public LinqMatcher(MatchBehaviour matchBehaviour, [NotNull] string pattern) : this(matchBehaviour, false, pattern)
{
}
@@ -48,9 +50,11 @@ namespace WireMock.Matchers
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="patterns">The patterns.</param>
public LinqMatcher(MatchBehaviour matchBehaviour, [NotNull] string[] patterns)
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
public LinqMatcher(MatchBehaviour matchBehaviour, bool throwException = false, [NotNull] params string[] patterns)
{
MatchBehaviour = matchBehaviour;
ThrowException = throwException;
_patterns = patterns;
}
@@ -71,8 +75,10 @@ namespace WireMock.Matchers
}
catch
{
// just ignore exception
// TODO add logging?
if (ThrowException)
{
throw;
}
}
return MatchBehaviourHelper.Convert(MatchBehaviour, match);
@@ -113,8 +119,10 @@ namespace WireMock.Matchers
}
catch
{
// just ignore exception
// TODO add logging?
if (ThrowException)
{
throw;
}
}
return MatchBehaviourHelper.Convert(MatchBehaviour, match);

View File

@@ -19,6 +19,9 @@ namespace WireMock.Matchers
/// <inheritdoc cref="IMatcher.MatchBehaviour"/>
public MatchBehaviour MatchBehaviour { get; }
/// <inheritdoc cref="IMatcher.ThrowException"/>
public bool ThrowException { get; }
/// <summary>
/// Initializes a new instance of the <see cref="RegexMatcher"/> class.
/// </summary>
@@ -53,13 +56,15 @@ namespace WireMock.Matchers
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="patterns">The patterns.</param>
/// <param name="ignoreCase">Ignore the case from the pattern.</param>
public RegexMatcher(MatchBehaviour matchBehaviour, [NotNull, RegexPattern] string[] patterns, bool ignoreCase = false)
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
public RegexMatcher(MatchBehaviour matchBehaviour, [NotNull, RegexPattern] string[] patterns, bool ignoreCase = false, bool throwException = false)
{
Check.NotNull(patterns, nameof(patterns));
_patterns = patterns;
IgnoreCase = ignoreCase;
MatchBehaviour = matchBehaviour;
ThrowException = throwException;
RegexOptions options = RegexOptions.Compiled | RegexOptions.Multiline;
@@ -83,7 +88,10 @@ namespace WireMock.Matchers
}
catch (Exception)
{
// just ignore exception
if (ThrowException)
{
throw;
}
}
}

View File

@@ -51,7 +51,7 @@ namespace WireMock.Matchers.Request
/// <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, value)).Cast<IStringMatcher>().ToArray())
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())
{
}

View File

@@ -19,6 +19,9 @@ namespace WireMock.Matchers
/// <inheritdoc cref="IMatcher.MatchBehaviour"/>
public MatchBehaviour MatchBehaviour { get; }
/// <inheritdoc cref="IMatcher.ThrowException"/>
public bool ThrowException { get; }
/// <summary>
/// Initializes a new instance of the <see cref="SimMetricsMatcher"/> class.
/// </summary>
@@ -53,11 +56,14 @@ namespace WireMock.Matchers
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="patterns">The patterns.</param>
/// <param name="simMetricType">The SimMetric Type</param>
public SimMetricsMatcher(MatchBehaviour matchBehaviour, [NotNull] string[] patterns, SimMetricType simMetricType = SimMetricType.Levenstein)
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
public SimMetricsMatcher(MatchBehaviour matchBehaviour, [NotNull] string[] patterns, SimMetricType simMetricType = SimMetricType.Levenstein, bool throwException = false)
{
Check.NotNullOrEmpty(patterns, nameof(patterns));
MatchBehaviour = matchBehaviour;
ThrowException = throwException;
_patterns = patterns;
_simMetricType = simMetricType;
}

View File

@@ -46,7 +46,9 @@ namespace WireMock.Matchers
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="patterns">The patterns.</param>
/// <param name="ignoreCase">IgnoreCase</param>
public WildcardMatcher(MatchBehaviour matchBehaviour, [NotNull] string[] patterns, bool ignoreCase = false) : base(matchBehaviour, patterns.Select(pattern => "^" + Regex.Escape(pattern).Replace(@"\*", ".*").Replace(@"\?", ".") + "$").ToArray(), ignoreCase)
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
public WildcardMatcher(MatchBehaviour matchBehaviour, [NotNull] string[] patterns, bool ignoreCase = false, bool throwException = false) :
base(matchBehaviour, patterns.Select(pattern => "^" + Regex.Escape(pattern).Replace(@"\*", ".*").Replace(@"\?", ".") + "$").ToArray(), ignoreCase, throwException)
{
_patterns = patterns;
}

View File

@@ -20,11 +20,14 @@ namespace WireMock.Matchers
/// <inheritdoc cref="IMatcher.MatchBehaviour"/>
public MatchBehaviour MatchBehaviour { get; }
/// <inheritdoc cref="IMatcher.ThrowException"/>
public bool ThrowException { get; }
/// <summary>
/// Initializes a new instance of the <see cref="XPathMatcher"/> class.
/// </summary>
/// <param name="patterns">The patterns.</param>
public XPathMatcher([NotNull] params string[] patterns) : this(MatchBehaviour.AcceptOnMatch, patterns)
public XPathMatcher([NotNull] params string[] patterns) : this(MatchBehaviour.AcceptOnMatch, false, patterns)
{
}
@@ -32,12 +35,14 @@ namespace WireMock.Matchers
/// Initializes a new instance of the <see cref="XPathMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
/// <param name="patterns">The patterns.</param>
public XPathMatcher(MatchBehaviour matchBehaviour, [NotNull] params string[] patterns)
public XPathMatcher(MatchBehaviour matchBehaviour, bool throwException = false, [NotNull] params string[] patterns)
{
Check.NotNull(patterns, nameof(patterns));
MatchBehaviour = matchBehaviour;
ThrowException = throwException;
_patterns = patterns;
}
@@ -58,8 +63,10 @@ namespace WireMock.Matchers
}
catch (Exception)
{
// just ignore exception
// TODO add logging?
if (ThrowException)
{
throw;
}
}
}

View File

@@ -38,6 +38,8 @@ namespace WireMock.Serialization
string[] stringPatterns = matcher.Patterns != null ? matcher.Patterns.OfType<string>().ToArray() : new[] { matcher.Pattern as string };
MatchBehaviour matchBehaviour = matcher.RejectOnMatch == true ? MatchBehaviour.RejectOnMatch : MatchBehaviour.AcceptOnMatch;
bool ignoreCase = matcher.IgnoreCase == true;
bool throwExceptionWhenMatcherFails = _settings.ThrowExceptionWhenMatcherFails == true;
switch (matcherName)
{
@@ -50,34 +52,34 @@ namespace WireMock.Serialization
throw new NotSupportedException("It's not allowed to use the 'CSharpCodeMatcher' because IWireMockServerSettings.AllowCSharpCodeMatcher is not set to 'true'.");
case "LinqMatcher":
return new LinqMatcher(matchBehaviour, stringPatterns);
return new LinqMatcher(matchBehaviour, throwExceptionWhenMatcherFails, stringPatterns);
case "ExactMatcher":
return new ExactMatcher(matchBehaviour, stringPatterns);
return new ExactMatcher(matchBehaviour, throwExceptionWhenMatcherFails, stringPatterns);
case "ExactObjectMatcher":
return CreateExactObjectMatcher(matchBehaviour, stringPatterns[0]);
return CreateExactObjectMatcher(matchBehaviour, stringPatterns[0], throwExceptionWhenMatcherFails);
case "RegexMatcher":
return new RegexMatcher(matchBehaviour, stringPatterns, matcher.IgnoreCase == true);
return new RegexMatcher(matchBehaviour, stringPatterns, ignoreCase, throwExceptionWhenMatcherFails);
case "JsonMatcher":
return new JsonMatcher(matchBehaviour, matcher.Pattern, matcher.IgnoreCase == true);
return new JsonMatcher(matchBehaviour, stringPatterns, ignoreCase, throwExceptionWhenMatcherFails);
case "JsonPathMatcher":
return new JsonPathMatcher(matchBehaviour, stringPatterns);
return new JsonPathMatcher(matchBehaviour, throwExceptionWhenMatcherFails, stringPatterns);
case "JmesPathMatcher":
return new JmesPathMatcher(matchBehaviour, stringPatterns);
return new JmesPathMatcher(matchBehaviour, throwExceptionWhenMatcherFails, stringPatterns);
case "XPathMatcher":
return new XPathMatcher(matchBehaviour, stringPatterns);
return new XPathMatcher(matchBehaviour, throwExceptionWhenMatcherFails, stringPatterns);
case "WildcardMatcher":
return new WildcardMatcher(matchBehaviour, stringPatterns, matcher.IgnoreCase == true);
return new WildcardMatcher(matchBehaviour, stringPatterns, ignoreCase, throwExceptionWhenMatcherFails);
case "ContentTypeMatcher":
return new ContentTypeMatcher(matchBehaviour, stringPatterns, matcher.IgnoreCase == true);
return new ContentTypeMatcher(matchBehaviour, stringPatterns, ignoreCase, throwExceptionWhenMatcherFails);
case "SimMetricsMatcher":
SimMetricType type = SimMetricType.Levenstein;
@@ -86,14 +88,14 @@ namespace WireMock.Serialization
throw new NotSupportedException($"Matcher '{matcherName}' with Type '{matcherType}' is not supported.");
}
return new SimMetricsMatcher(matchBehaviour, stringPatterns, type);
return new SimMetricsMatcher(matchBehaviour, stringPatterns, type, throwExceptionWhenMatcherFails);
default:
throw new NotSupportedException($"Matcher '{matcherName}' is not supported.");
}
}
private ExactObjectMatcher CreateExactObjectMatcher(MatchBehaviour matchBehaviour, string stringPattern)
private ExactObjectMatcher CreateExactObjectMatcher(MatchBehaviour matchBehaviour, string stringPattern, bool throwException)
{
byte[] bytePattern;
try
@@ -105,7 +107,7 @@ namespace WireMock.Serialization
throw new ArgumentException($"Matcher 'ExactObjectMatcher' has invalid pattern. The pattern value '{stringPattern}' is not a Base64String.", nameof(stringPattern));
}
return new ExactObjectMatcher(matchBehaviour, bytePattern);
return new ExactObjectMatcher(matchBehaviour, bytePattern, throwException);
}
public MatcherModel[] Map([CanBeNull] IEnumerable<IMatcher> matchers)

View File

@@ -1,6 +1,3 @@
using JetBrains.Annotations;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
@@ -9,6 +6,9 @@ using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using WireMock.Admin.Mappings;
using WireMock.Admin.Scenarios;
using WireMock.Admin.Settings;
@@ -274,7 +274,12 @@ namespace WireMock.Server
if (HttpStatusRangeParser.IsMatch(settings.ProxyAndRecordSettings.SaveMappingForStatusCodePattern, responseMessage.StatusCode) &&
(settings.ProxyAndRecordSettings.SaveMapping || settings.ProxyAndRecordSettings.SaveMappingToFile))
{
var mapping = ToMapping(requestMessage, responseMessage, settings.ProxyAndRecordSettings.BlackListedHeaders ?? new string[] { }, settings.ProxyAndRecordSettings.BlackListedCookies ?? new string[] { });
var mapping = ToMapping(
requestMessage,
responseMessage,
settings.ProxyAndRecordSettings.BlackListedHeaders ?? new string[] { },
settings.ProxyAndRecordSettings.BlackListedCookies ?? new string[] { }
);
if (settings.ProxyAndRecordSettings.SaveMapping)
{
@@ -314,18 +319,19 @@ namespace WireMock.Server
}
});
bool throwExceptionWhenMatcherFails = _settings.ThrowExceptionWhenMatcherFails == true;
switch (requestMessage.BodyData?.DetectedBodyType)
{
case BodyType.Json:
request.WithBody(new JsonMatcher(MatchBehaviour.AcceptOnMatch, requestMessage.BodyData.BodyAsJson));
request.WithBody(new JsonMatcher(MatchBehaviour.AcceptOnMatch, requestMessage.BodyData.BodyAsJson, true, throwExceptionWhenMatcherFails));
break;
case BodyType.String:
request.WithBody(new ExactMatcher(MatchBehaviour.AcceptOnMatch, requestMessage.BodyData.BodyAsString));
request.WithBody(new ExactMatcher(MatchBehaviour.AcceptOnMatch, throwExceptionWhenMatcherFails, requestMessage.BodyData.BodyAsString));
break;
case BodyType.Bytes:
request.WithBody(new ExactObjectMatcher(MatchBehaviour.AcceptOnMatch, requestMessage.BodyData.BodyAsBytes));
request.WithBody(new ExactObjectMatcher(MatchBehaviour.AcceptOnMatch, requestMessage.BodyData.BodyAsBytes, throwExceptionWhenMatcherFails));
break;
}
@@ -340,12 +346,13 @@ namespace WireMock.Server
{
var model = new SettingsModel
{
AllowPartialMapping = _options.AllowPartialMapping,
MaxRequestLogCount = _options.MaxRequestLogCount,
RequestLogExpirationDuration = _options.RequestLogExpirationDuration,
AllowPartialMapping = _settings.AllowPartialMapping,
MaxRequestLogCount = _settings.MaxRequestLogCount,
RequestLogExpirationDuration = _settings.RequestLogExpirationDuration,
GlobalProcessingDelay = (int?)_options.RequestProcessingDelay?.TotalMilliseconds,
AllowBodyForAllHttpMethods = _options.AllowBodyForAllHttpMethods,
HandleRequestsSynchronously = _options.HandleRequestsSynchronously
AllowBodyForAllHttpMethods = _settings.AllowBodyForAllHttpMethods,
HandleRequestsSynchronously = _settings.HandleRequestsSynchronously,
ThrowExceptionWhenMatcherFails = _settings.ThrowExceptionWhenMatcherFails
};
return ToJson(model);
@@ -377,6 +384,11 @@ namespace WireMock.Server
_options.HandleRequestsSynchronously = settings.HandleRequestsSynchronously.Value;
}
if (settings.ThrowExceptionWhenMatcherFails != null)
{
_settings.ThrowExceptionWhenMatcherFails = settings.ThrowExceptionWhenMatcherFails.Value;
}
return ResponseMessageBuilder.Create("Settings updated");
}
#endregion Settings

View File

@@ -3,6 +3,7 @@ using HandlebarsDotNet;
using JetBrains.Annotations;
using WireMock.Handlers;
using WireMock.Logging;
using WireMock.Matchers;
namespace WireMock.Settings
{
@@ -163,5 +164,11 @@ namespace WireMock.Settings
/// </summary>
[PublicAPI]
bool? HandleRequestsSynchronously { get; set; }
/// <summary>
/// Throw an exception when the <see cref="IMatcher"/> fails because of invalid input. (default set to false).
/// </summary>
[PublicAPI]
bool? ThrowExceptionWhenMatcherFails { get; set; }
}
}

View File

@@ -117,5 +117,9 @@ namespace WireMock.Settings
/// <inheritdoc cref="IWireMockServerSettings.HandleRequestsSynchronously"/>
[PublicAPI]
public bool? HandleRequestsSynchronously { get; set; }
/// <inheritdoc cref="IWireMockServerSettings.ThrowExceptionWhenMatcherFails"/>
[PublicAPI]
public bool? ThrowExceptionWhenMatcherFails { get; set; }
}
}

View File

@@ -37,7 +37,8 @@ namespace WireMock.Settings
AllowBodyForAllHttpMethods = parser.GetBoolValue("AllowBodyForAllHttpMethods"),
AllowOnlyDefinedHttpStatusCodeInResponse = parser.GetBoolValue("AllowOnlyDefinedHttpStatusCodeInResponse"),
DisableJsonBodyParsing = parser.GetBoolValue("DisableJsonBodyParsing"),
HandleRequestsSynchronously = parser.GetBoolValue("HandleRequestsSynchronously")
HandleRequestsSynchronously = parser.GetBoolValue("HandleRequestsSynchronously"),
ThrowExceptionWhenMatcherFails = parser.GetBoolValue("ThrowExceptionWhenMatcherFails")
};
if (logger != null)

View File

@@ -1,5 +1,5 @@
using HandlebarsDotNet;
using System;
using System;
using HandlebarsDotNet;
using WireMock.Handlers;
namespace WireMock.Transformers

View File

@@ -1,11 +1,10 @@
using HandlebarsDotNet;
using System;
using System.Collections.Generic;
using System.Linq;
using HandlebarsDotNet;
using JetBrains.Annotations;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WireMock.Types;
using WireMock.Util;
using WireMock.Validation;

View File

@@ -88,7 +88,7 @@ namespace WireMock.Net.Tests.Matchers
public void ExactMatcher_IsMatch_SinglePattern_AcceptOnMatch()
{
// Assign
var matcher = new ExactMatcher(MatchBehaviour.AcceptOnMatch, "cat");
var matcher = new ExactMatcher(MatchBehaviour.AcceptOnMatch, false, "cat");
// Act
double result = matcher.IsMatch("cat");
@@ -101,7 +101,7 @@ namespace WireMock.Net.Tests.Matchers
public void ExactMatcher_IsMatch_SinglePattern_RejectOnMatch()
{
// Assign
var matcher = new ExactMatcher(MatchBehaviour.RejectOnMatch, "cat");
var matcher = new ExactMatcher(MatchBehaviour.RejectOnMatch, false, "cat");
// Act
double result = matcher.IsMatch("cat");

View File

@@ -154,7 +154,7 @@ namespace WireMock.Net.Tests.Matchers
public void JmesPathMatcher_IsMatch_RejectOnMatch()
{
// Assign
var matcher = new JmesPathMatcher(MatchBehaviour.RejectOnMatch, "things.x == 'RequiredThing'");
var matcher = new JmesPathMatcher(MatchBehaviour.RejectOnMatch, false, "things.x == 'RequiredThing'");
// Act
double match = matcher.IsMatch(JObject.Parse("{ \"things\": { \"x\": \"RequiredThing\" } }"));

View File

@@ -1,4 +1,8 @@
using Newtonsoft.Json.Linq;
using System;
using System.IO;
using FluentAssertions;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NFluent;
using WireMock.Matchers;
using Xunit;
@@ -33,6 +37,52 @@ namespace WireMock.Net.Tests.Matchers
Check.That(value).Equals("{}");
}
[Fact]
public void JsonMatcher_WithInvalidStringValue_Should_ThrowException()
{
// Act
Action action = () => new JsonMatcher(MatchBehaviour.AcceptOnMatch, "{ \"Id\"");
// Assert
action.Should().Throw<JsonException>();
}
[Fact]
public void JsonMatcher_WithInvalidObjectValue_Should_ThrowException()
{
// Act
Action action = () => new JsonMatcher(MatchBehaviour.AcceptOnMatch, new MemoryStream());
// Assert
action.Should().Throw<JsonException>();
}
[Fact]
public void JsonMatcher_IsMatch_WithInvalidValue_And_ThrowExceptionIsFalse_Should_ReturnMismatch()
{
// Assign
var matcher = new JsonMatcher("");
// Act
double match = matcher.IsMatch(new MemoryStream());
// Assert
Check.That(match).IsEqualTo(0);
}
[Fact]
public void JsonMatcher_IsMatch_WithInvalidValue_And_ThrowExceptionIsTrue_Should_ReturnMismatch()
{
// Assign
var matcher = new JsonMatcher("", false, true);
// Act
Action action = () => matcher.IsMatch(new MemoryStream());
// Assert
action.Should().Throw<JsonException>();
}
[Fact]
public void JsonMatcher_IsMatch_ByteArray()
{

View File

@@ -150,7 +150,7 @@ namespace WireMock.Net.Tests.Matchers
public void JsonPathMatcher_IsMatch_RejectOnMatch()
{
// Assign
var matcher = new JsonPathMatcher(MatchBehaviour.RejectOnMatch, "$..[?(@.Id == 1)]");
var matcher = new JsonPathMatcher(MatchBehaviour.RejectOnMatch, false, "$..[?(@.Id == 1)]");
// Act
double match = matcher.IsMatch(JObject.Parse("{\"Id\":1,\"Name\":\"Test\"}"));

View File

@@ -57,7 +57,7 @@ namespace WireMock.Net.Tests.Matchers
<todo-list>
<todo-item id='a1'>abc</todo-item>
</todo-list>";
var matcher = new XPathMatcher(MatchBehaviour.RejectOnMatch, "/todo-list[count(todo-item) = 1]");
var matcher = new XPathMatcher(MatchBehaviour.RejectOnMatch, false, "/todo-list[count(todo-item) = 1]");
// Act
double result = matcher.IsMatch(xml);

View File

@@ -1,4 +1,5 @@
using System;
using FluentAssertions;
using NFluent;
using WireMock.Admin.Mappings;
using WireMock.Matchers;
@@ -43,7 +44,8 @@ namespace WireMock.Net.Tests.Serialization
var matcher = (ExactMatcher)_sut.Map(model);
// Assert
Check.That(matcher.GetPatterns()).ContainsExactly("x");
matcher.GetPatterns().Should().ContainSingle("x");
matcher.ThrowException.Should().BeFalse();
}
[Fact]
@@ -63,6 +65,39 @@ namespace WireMock.Net.Tests.Serialization
Check.That(matcher.GetPatterns()).ContainsExactly("x", "y");
}
[Theory]
[InlineData(nameof(LinqMatcher))]
[InlineData(nameof(ExactMatcher))]
[InlineData(nameof(ExactObjectMatcher))]
[InlineData(nameof(RegexMatcher))]
[InlineData(nameof(JsonMatcher))]
[InlineData(nameof(JsonPathMatcher))]
[InlineData(nameof(JmesPathMatcher))]
[InlineData(nameof(XPathMatcher))]
[InlineData(nameof(WildcardMatcher))]
[InlineData(nameof(ContentTypeMatcher))]
[InlineData(nameof(SimMetricsMatcher))]
public void MatcherModelMapper_Map_ThrowExceptionWhenMatcherFails_True(string name)
{
// Assign
var settings = new WireMockServerSettings
{
ThrowExceptionWhenMatcherFails = true
};
var sut = new MatcherMapper(settings);
var model = new MatcherModel
{
Name = name,
Patterns = new[] { "" }
};
// Act
var matcher = sut.Map(model);
// Assert
matcher.ThrowException.Should().BeTrue();
}
[Fact]
public void MatcherModelMapper_Map_ExactObjectMatcher_ValidBase64StringPattern()
{