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; } public int? MaxRequestLogCount { get; set; }
/// <summary> /// <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> /// </summary>
public bool? AllowBodyForAllHttpMethods { get; set; } public bool? AllowBodyForAllHttpMethods { get; set; }
/// <summary> /// <summary>
/// Gets or sets wether to handle all requests synchronously. /// Handle all requests synchronously. (default set to false).
/// </summary> /// </summary>
public bool? HandleRequestsSynchronously { get; set; } 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; } public MatchBehaviour MatchBehaviour { get; }
/// <inheritdoc cref="IMatcher.ThrowException"/>
public bool ThrowException { get; }
private readonly string[] _patterns; private readonly string[] _patterns;
/// <summary> /// <summary>
@@ -49,6 +52,7 @@ namespace WireMock.Matchers
Check.NotNull(patterns, nameof(patterns)); Check.NotNull(patterns, nameof(patterns));
MatchBehaviour = matchBehaviour; MatchBehaviour = matchBehaviour;
ThrowException = false;
_patterns = patterns; _patterns = patterns;
} }
@@ -156,7 +160,7 @@ namespace WireMock.Matchers
#if NETSTANDARD2_0 #if NETSTANDARD2_0
script = csscript.GenericExtensions.CreateObject(assembly, "*"); script = csscript.GenericExtensions.CreateObject(assembly, "*");
#else #else
script = CSScriptLib.ReflectionExtensions.CreateObject(assembly,"*"); script = CSScriptLib.ReflectionExtensions.CreateObject(assembly, "*");
#endif #endif
} }
catch (Exception ex) catch (Exception ex)

View File

@@ -1,73 +1,75 @@
using System.Net.Http.Headers; using System.Net.Http.Headers;
using JetBrains.Annotations; using JetBrains.Annotations;
namespace WireMock.Matchers namespace WireMock.Matchers
{ {
/// <summary> /// <summary>
/// ContentTypeMatcher which accepts also all charsets /// ContentTypeMatcher which accepts also all charsets
/// </summary> /// </summary>
/// <seealso cref="RegexMatcher" /> /// <seealso cref="RegexMatcher" />
public class ContentTypeMatcher : WildcardMatcher public class ContentTypeMatcher : WildcardMatcher
{ {
private readonly string[] _patterns; private readonly string[] _patterns;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ContentTypeMatcher"/> class. /// Initializes a new instance of the <see cref="ContentTypeMatcher"/> class.
/// </summary> /// </summary>
/// <param name="pattern">The pattern.</param> /// <param name="pattern">The pattern.</param>
/// <param name="ignoreCase">IgnoreCase (default false)</param> /// <param name="ignoreCase">IgnoreCase (default false)</param>
public ContentTypeMatcher([NotNull] string pattern, bool ignoreCase = false) : this(new[] { pattern }, ignoreCase) public ContentTypeMatcher([NotNull] string pattern, bool ignoreCase = false) : this(new[] { pattern }, ignoreCase)
{ {
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ContentTypeMatcher"/> class. /// Initializes a new instance of the <see cref="ContentTypeMatcher"/> class.
/// </summary> /// </summary>
/// <param name="matchBehaviour">The match behaviour.</param> /// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="pattern">The pattern.</param> /// <param name="pattern">The pattern.</param>
/// <param name="ignoreCase">IgnoreCase (default false)</param> /// <param name="ignoreCase">IgnoreCase (default false)</param>
public ContentTypeMatcher(MatchBehaviour matchBehaviour, [NotNull] string pattern, bool ignoreCase = false) : this(matchBehaviour, new[] { pattern }, ignoreCase) public ContentTypeMatcher(MatchBehaviour matchBehaviour, [NotNull] string pattern, bool ignoreCase = false) : this(matchBehaviour, new[] { pattern }, ignoreCase)
{ {
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ContentTypeMatcher"/> class. /// Initializes a new instance of the <see cref="ContentTypeMatcher"/> class.
/// </summary> /// </summary>
/// <param name="patterns">The patterns.</param> /// <param name="patterns">The patterns.</param>
/// <param name="ignoreCase">IgnoreCase (default false)</param> /// <param name="ignoreCase">IgnoreCase (default false)</param>
public ContentTypeMatcher([NotNull] string[] patterns, bool ignoreCase = false) : this(MatchBehaviour.AcceptOnMatch, patterns, ignoreCase) public ContentTypeMatcher([NotNull] string[] patterns, bool ignoreCase = false) : this(MatchBehaviour.AcceptOnMatch, patterns, ignoreCase)
{ {
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ContentTypeMatcher"/> class. /// Initializes a new instance of the <see cref="ContentTypeMatcher"/> class.
/// </summary> /// </summary>
/// <param name="matchBehaviour">The match behaviour.</param> /// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="patterns">The patterns.</param> /// <param name="patterns">The patterns.</param>
/// <param name="ignoreCase">IgnoreCase (default false)</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) :
_patterns = patterns; base(matchBehaviour, patterns, ignoreCase, throwException)
} {
_patterns = patterns;
/// <inheritdoc cref="RegexMatcher.IsMatch"/> }
public override double IsMatch(string input)
{ /// <inheritdoc cref="RegexMatcher.IsMatch"/>
if (string.IsNullOrEmpty(input) || !MediaTypeHeaderValue.TryParse(input, out MediaTypeHeaderValue contentType)) public override double IsMatch(string input)
{ {
return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.Mismatch); if (string.IsNullOrEmpty(input) || !MediaTypeHeaderValue.TryParse(input, out MediaTypeHeaderValue contentType))
} {
return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.Mismatch);
return base.IsMatch(contentType.MediaType); }
}
return base.IsMatch(contentType.MediaType);
/// <inheritdoc cref="IStringMatcher.GetPatterns"/> }
public override string[] GetPatterns()
{ /// <inheritdoc cref="IStringMatcher.GetPatterns"/>
return _patterns; public override string[] GetPatterns()
} {
return _patterns;
/// <inheritdoc cref="IMatcher.Name"/> }
public override string Name => "ContentTypeMatcher";
} /// <inheritdoc cref="IMatcher.Name"/>
public override string Name => "ContentTypeMatcher";
}
} }

View File

@@ -1,59 +1,64 @@
using System.Linq; using System.Linq;
using JetBrains.Annotations; using JetBrains.Annotations;
using WireMock.Validation; using WireMock.Validation;
namespace WireMock.Matchers namespace WireMock.Matchers
{ {
/// <summary> /// <summary>
/// ExactMatcher /// ExactMatcher
/// </summary> /// </summary>
/// <seealso cref="IStringMatcher" /> /// <seealso cref="IStringMatcher" />
public class ExactMatcher : IStringMatcher public class ExactMatcher : IStringMatcher
{ {
private readonly string[] _values; private readonly string[] _values;
/// <inheritdoc cref="IMatcher.MatchBehaviour"/> /// <inheritdoc cref="IMatcher.MatchBehaviour"/>
public MatchBehaviour MatchBehaviour { get; } public MatchBehaviour MatchBehaviour { get; }
/// <summary> /// <inheritdoc cref="IMatcher.ThrowException"/>
/// Initializes a new instance of the <see cref="ExactMatcher"/> class. public bool ThrowException { get; }
/// </summary>
/// <param name="values">The values.</param> /// <summary>
public ExactMatcher([NotNull] params string[] values) : this(MatchBehaviour.AcceptOnMatch, values) /// 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, false, values)
/// <summary> {
/// Initializes a new instance of the <see cref="ExactMatcher"/> class. }
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param> /// <summary>
/// <param name="values">The values.</param> /// Initializes a new instance of the <see cref="ExactMatcher"/> class.
public ExactMatcher(MatchBehaviour matchBehaviour, [NotNull] params string[] values) /// </summary>
{ /// <param name="matchBehaviour">The match behaviour.</param>
Check.HasNoNulls(values, nameof(values)); /// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
/// <param name="values">The values.</param>
_values = values; public ExactMatcher(MatchBehaviour matchBehaviour, bool throwException = false, [NotNull] params string[] values)
MatchBehaviour = matchBehaviour; {
} Check.HasNoNulls(values, nameof(values));
/// <inheritdoc cref="IStringMatcher.IsMatch"/> MatchBehaviour = matchBehaviour;
public double IsMatch(string input) ThrowException = throwException;
{ _values = values;
if (_values.Length == 1) }
{
return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.ToScore(_values[0] == input)); /// <inheritdoc cref="IStringMatcher.IsMatch"/>
} public double IsMatch(string input)
{
return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.ToScore(_values.Contains(input))); if (_values.Length == 1)
} {
return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.ToScore(_values[0] == input));
/// <inheritdoc cref="IStringMatcher.GetPatterns"/> }
public string[] GetPatterns()
{ return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.ToScore(_values.Contains(input)));
return _values; }
}
/// <inheritdoc cref="IStringMatcher.GetPatterns"/>
/// <inheritdoc cref="IMatcher.Name"/> public string[] GetPatterns()
public string Name => "ExactMatcher"; {
} return _values;
}
/// <inheritdoc cref="IMatcher.Name"/>
public string Name => "ExactMatcher";
}
} }

View File

@@ -1,78 +1,83 @@
using JetBrains.Annotations; using JetBrains.Annotations;
using System.Linq; using System.Linq;
using WireMock.Validation; using WireMock.Validation;
namespace WireMock.Matchers namespace WireMock.Matchers
{ {
/// <summary> /// <summary>
/// ExactObjectMatcher /// ExactObjectMatcher
/// </summary> /// </summary>
/// <seealso cref="IObjectMatcher" /> /// <seealso cref="IObjectMatcher" />
public class ExactObjectMatcher : IObjectMatcher public class ExactObjectMatcher : IObjectMatcher
{ {
/// <summary> /// <summary>
/// Gets the value as object. /// Gets the value as object.
/// </summary> /// </summary>
public object ValueAsObject { get; } public object ValueAsObject { get; }
/// <summary> /// <summary>
/// Gets the value as byte[]. /// Gets the value as byte[].
/// </summary> /// </summary>
public byte[] ValueAsBytes { get; } public byte[] ValueAsBytes { get; }
/// <inheritdoc cref="IMatcher.MatchBehaviour"/> /// <inheritdoc cref="IMatcher.MatchBehaviour"/>
public MatchBehaviour MatchBehaviour { get; } public MatchBehaviour MatchBehaviour { get; }
/// <summary> /// <inheritdoc cref="IMatcher.ThrowException"/>
/// Initializes a new instance of the <see cref="ExactObjectMatcher"/> class. public bool ThrowException { get; }
/// </summary>
/// <param name="value">The value.</param> /// <summary>
public ExactObjectMatcher([NotNull] object value) : this(MatchBehaviour.AcceptOnMatch, value) /// Initializes a new instance of the <see cref="ExactObjectMatcher"/> class.
{ /// </summary>
} /// <param name="value">The value.</param>
public ExactObjectMatcher([NotNull] object value) : this(MatchBehaviour.AcceptOnMatch, value)
/// <summary> {
/// Initializes a new instance of the <see cref="ExactObjectMatcher"/> class. }
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param> /// <summary>
/// <param name="value">The value.</param> /// Initializes a new instance of the <see cref="ExactObjectMatcher"/> class.
public ExactObjectMatcher(MatchBehaviour matchBehaviour, [NotNull] object value) /// </summary>
{ /// <param name="matchBehaviour">The match behaviour.</param>
Check.NotNull(value, nameof(value)); /// <param name="value">The value.</param>
public ExactObjectMatcher(MatchBehaviour matchBehaviour, [NotNull] object value)
ValueAsObject = value; {
MatchBehaviour = matchBehaviour; Check.NotNull(value, nameof(value));
}
ValueAsObject = value;
/// <summary> MatchBehaviour = matchBehaviour;
/// Initializes a new instance of the <see cref="ExactObjectMatcher"/> class. }
/// </summary>
/// <param name="value">The value.</param> /// <summary>
public ExactObjectMatcher([NotNull] byte[] value) : this(MatchBehaviour.AcceptOnMatch, value) /// Initializes a new instance of the <see cref="ExactObjectMatcher"/> class.
{ /// </summary>
} /// <param name="value">The value.</param>
public ExactObjectMatcher([NotNull] byte[] value) : this(MatchBehaviour.AcceptOnMatch, value)
/// <summary> {
/// Initializes a new instance of the <see cref="ExactObjectMatcher"/> class. }
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param> /// <summary>
/// <param name="value">The value.</param> /// Initializes a new instance of the <see cref="ExactObjectMatcher"/> class.
public ExactObjectMatcher(MatchBehaviour matchBehaviour, [NotNull] byte[] value) /// </summary>
{ /// <param name="matchBehaviour">The match behaviour.</param>
Check.NotNull(value, nameof(value)); /// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
/// <param name="value">The value.</param>
ValueAsBytes = value; public ExactObjectMatcher(MatchBehaviour matchBehaviour, [NotNull] byte[] value, bool throwException = false)
MatchBehaviour = matchBehaviour; {
} Check.NotNull(value, nameof(value));
/// <inheritdoc cref="IObjectMatcher.IsMatch"/> MatchBehaviour = matchBehaviour;
public double IsMatch(object input) ThrowException = throwException;
{ ValueAsBytes = value;
bool equals = ValueAsObject != null ? Equals(ValueAsObject, input) : ValueAsBytes.SequenceEqual((byte[])input); }
return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.ToScore(equals));
} /// <inheritdoc cref="IObjectMatcher.IsMatch"/>
public double IsMatch(object input)
/// <inheritdoc cref="IMatcher.Name"/> {
public string Name => "ExactObjectMatcher"; bool equals = ValueAsObject != null ? Equals(ValueAsObject, input) : ValueAsBytes.SequenceEqual((byte[])input);
} return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.ToScore(equals));
}
/// <inheritdoc cref="IMatcher.Name"/>
public string Name => "ExactObjectMatcher";
}
} }

View File

@@ -1,18 +1,23 @@
namespace WireMock.Matchers namespace WireMock.Matchers
{ {
/// <summary> /// <summary>
/// IMatcher /// IMatcher
/// </summary> /// </summary>
public interface IMatcher public interface IMatcher
{ {
/// <summary> /// <summary>
/// Gets the name. /// Gets the name.
/// </summary> /// </summary>
string Name { get; } string Name { get; }
/// <summary> /// <summary>
/// Gets the match behaviour. /// Gets the match behaviour.
/// </summary> /// </summary>
MatchBehaviour MatchBehaviour { get; } MatchBehaviour MatchBehaviour { get; }
}
/// <summary>
/// Should this matcher throw an exception?
/// </summary>
bool ThrowException { get; }
}
} }

View File

@@ -1,99 +1,110 @@
using System.Linq; using System.Linq;
using JetBrains.Annotations; using JetBrains.Annotations;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using WireMock.Validation; using WireMock.Validation;
namespace WireMock.Matchers namespace WireMock.Matchers
{ {
/// <summary> /// <summary>
/// JsonPathMatcher /// JsonPathMatcher
/// </summary> /// </summary>
/// <seealso cref="IMatcher" /> /// <seealso cref="IMatcher" />
/// <seealso cref="IObjectMatcher" /> /// <seealso cref="IObjectMatcher" />
public class JsonPathMatcher : IStringMatcher, IObjectMatcher public class JsonPathMatcher : IStringMatcher, IObjectMatcher
{ {
private readonly string[] _patterns; private readonly string[] _patterns;
/// <inheritdoc cref="IMatcher.MatchBehaviour"/> /// <inheritdoc cref="IMatcher.MatchBehaviour"/>
public MatchBehaviour MatchBehaviour { get; } public MatchBehaviour MatchBehaviour { get; }
/// <summary> /// <inheritdoc cref="IMatcher.ThrowException"/>
/// Initializes a new instance of the <see cref="JsonPathMatcher"/> class. public bool ThrowException { get; }
/// </summary>
/// <param name="patterns">The patterns.</param> /// <summary>
public JsonPathMatcher([NotNull] params string[] patterns) : this(MatchBehaviour.AcceptOnMatch, patterns) /// 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, false, patterns)
/// <summary> {
/// Initializes a new instance of the <see cref="JsonPathMatcher"/> class. }
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param> /// <summary>
/// <param name="patterns">The patterns.</param> /// Initializes a new instance of the <see cref="JsonPathMatcher"/> class.
public JsonPathMatcher(MatchBehaviour matchBehaviour, [NotNull] params string[] patterns) /// </summary>
{ /// <param name="matchBehaviour">The match behaviour.</param>
Check.NotNull(patterns, nameof(patterns)); /// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
/// <param name="patterns">The patterns.</param>
MatchBehaviour = matchBehaviour; public JsonPathMatcher(MatchBehaviour matchBehaviour, bool throwException = false, [NotNull] params string[] patterns)
_patterns = patterns; {
} Check.NotNull(patterns, nameof(patterns));
/// <inheritdoc cref="IStringMatcher.IsMatch"/> MatchBehaviour = matchBehaviour;
public double IsMatch(string input) ThrowException = throwException;
{ _patterns = patterns;
double match = MatchScores.Mismatch; }
if (input != null)
{ /// <inheritdoc cref="IStringMatcher.IsMatch"/>
try public double IsMatch(string input)
{ {
var jtoken = JToken.Parse(input); double match = MatchScores.Mismatch;
match = IsMatch(jtoken); if (input != null)
} {
catch (JsonException) try
{ {
// just ignore JsonException var jtoken = JToken.Parse(input);
} match = IsMatch(jtoken);
} }
catch (JsonException)
return MatchBehaviourHelper.Convert(MatchBehaviour, match); {
} if (ThrowException)
{
/// <inheritdoc cref="IObjectMatcher.IsMatch"/> throw;
public double IsMatch(object input) }
{ }
double match = MatchScores.Mismatch; }
// When input is null or byte[], return Mismatch. return MatchBehaviourHelper.Convert(MatchBehaviour, match);
if (input != null && !(input is byte[])) }
{
try /// <inheritdoc cref="IObjectMatcher.IsMatch"/>
{ public double IsMatch(object input)
// Check if JToken or object {
JToken jtoken = input is JToken token ? token : JObject.FromObject(input); double match = MatchScores.Mismatch;
match = IsMatch(jtoken);
} // When input is null or byte[], return Mismatch.
catch (JsonException) if (input != null && !(input is byte[]))
{ {
// just ignore JsonException try
} {
} // Check if JToken or object
JToken jtoken = input is JToken token ? token : JObject.FromObject(input);
return MatchBehaviourHelper.Convert(MatchBehaviour, match); match = IsMatch(jtoken);
} }
catch (JsonException)
/// <inheritdoc cref="IStringMatcher.GetPatterns"/> {
public string[] GetPatterns() if (ThrowException)
{ {
return _patterns; throw;
} }
}
/// <inheritdoc cref="IMatcher.Name"/> }
public string Name => "JsonPathMatcher";
return MatchBehaviourHelper.Convert(MatchBehaviour, match);
private double IsMatch(JToken jtoken) }
{
return MatchScores.ToScore(_patterns.Select(pattern => jtoken.SelectToken(pattern) != null)); /// <inheritdoc cref="IStringMatcher.GetPatterns"/>
} public string[] GetPatterns()
} {
return _patterns;
}
/// <inheritdoc cref="IMatcher.Name"/>
public string Name => "JsonPathMatcher";
private double IsMatch(JToken jtoken)
{
return MatchScores.ToScore(_patterns.Select(pattern => jtoken.SelectToken(pattern) != null));
}
}
} }

View File

@@ -1,83 +1,100 @@
using DevLab.JmesPath; using DevLab.JmesPath;
using JetBrains.Annotations; using JetBrains.Annotations;
using Newtonsoft.Json; using Newtonsoft.Json;
using System.Linq; using System.Linq;
using WireMock.Validation; using WireMock.Validation;
namespace WireMock.Matchers namespace WireMock.Matchers
{ {
/// <summary> /// <summary>
/// http://jmespath.org/ /// http://jmespath.org/
/// </summary> /// </summary>
public class JmesPathMatcher : IStringMatcher, IObjectMatcher public class JmesPathMatcher : IStringMatcher, IObjectMatcher
{ {
private readonly string[] _patterns; private readonly string[] _patterns;
/// <inheritdoc cref="IMatcher.MatchBehaviour"/> /// <inheritdoc cref="IMatcher.MatchBehaviour"/>
public MatchBehaviour MatchBehaviour { get; } public MatchBehaviour MatchBehaviour { get; }
/// <summary> /// <inheritdoc cref="IMatcher.ThrowException"/>
/// Initializes a new instance of the <see cref="JmesPathMatcher"/> class. public bool ThrowException { get; }
/// </summary>
/// <param name="patterns">The patterns.</param> /// <summary>
public JmesPathMatcher([NotNull] params string[] patterns) : this(MatchBehaviour.AcceptOnMatch, patterns) /// 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, false, patterns)
/// <summary> {
/// Initializes a new instance of the <see cref="JmesPathMatcher"/> class. }
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param> /// <summary>
/// <param name="patterns">The patterns.</param> /// Initializes a new instance of the <see cref="JmesPathMatcher"/> class.
public JmesPathMatcher(MatchBehaviour matchBehaviour, [NotNull] params string[] patterns) /// </summary>
{ /// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
Check.NotNull(patterns, nameof(patterns)); /// <param name="patterns">The patterns.</param>
public JmesPathMatcher(bool throwException = false, [NotNull] params string[] patterns) : this(MatchBehaviour.AcceptOnMatch, throwException, patterns)
MatchBehaviour = matchBehaviour; {
_patterns = patterns; }
}
/// <summary>
/// <inheritdoc cref="IStringMatcher.IsMatch"/> /// Initializes a new instance of the <see cref="JmesPathMatcher"/> class.
public double IsMatch(string input) /// </summary>
{ /// <param name="matchBehaviour">The match behaviour.</param>
double match = MatchScores.Mismatch; /// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
if (input != null) /// <param name="patterns">The patterns.</param>
{ public JmesPathMatcher(MatchBehaviour matchBehaviour, bool throwException = false, [NotNull] params string[] patterns)
try {
{ Check.NotNull(patterns, nameof(patterns));
match = MatchScores.ToScore(_patterns.Select(pattern => bool.Parse(new JmesPath().Transform(input, pattern))));
} MatchBehaviour = matchBehaviour;
catch (JsonException) ThrowException = throwException;
{ _patterns = patterns;
// just ignore JsonException }
}
} /// <inheritdoc cref="IStringMatcher.IsMatch"/>
public double IsMatch(string input)
return MatchBehaviourHelper.Convert(MatchBehaviour, match); {
} double match = MatchScores.Mismatch;
if (input != null)
/// <inheritdoc cref="IObjectMatcher.IsMatch"/> {
public double IsMatch(object input) try
{ {
double match = MatchScores.Mismatch; match = MatchScores.ToScore(_patterns.Select(pattern => bool.Parse(new JmesPath().Transform(input, pattern))));
}
// When input is null or byte[], return Mismatch. catch (JsonException)
if (input != null && !(input is byte[])) {
{ if (ThrowException)
string inputAsString = JsonConvert.SerializeObject(input); {
return IsMatch(inputAsString); throw;
} }
}
return MatchBehaviourHelper.Convert(MatchBehaviour, match); }
}
return MatchBehaviourHelper.Convert(MatchBehaviour, match);
/// <inheritdoc cref="IStringMatcher.GetPatterns"/> }
public string[] GetPatterns()
{ /// <inheritdoc cref="IObjectMatcher.IsMatch"/>
return _patterns; public double IsMatch(object input)
} {
double match = MatchScores.Mismatch;
/// <inheritdoc cref="IMatcher.Name"/>
public string Name => "JmesPathMatcher"; // When input is null or byte[], return Mismatch.
} if (input != null && !(input is byte[]))
{
string inputAsString = JsonConvert.SerializeObject(input);
return IsMatch(inputAsString);
}
return MatchBehaviourHelper.Convert(MatchBehaviour, match);
}
/// <inheritdoc cref="IStringMatcher.GetPatterns"/>
public string[] GetPatterns()
{
return _patterns;
}
/// <inheritdoc cref="IMatcher.Name"/>
public string Name => "JmesPathMatcher";
}
} }

View File

@@ -1,169 +1,165 @@
using JetBrains.Annotations; using System.Collections;
using Newtonsoft.Json; using System.Linq;
using Newtonsoft.Json.Linq; using JetBrains.Annotations;
using System.Collections; using Newtonsoft.Json;
using System.Linq; using Newtonsoft.Json.Linq;
using WireMock.Util; using WireMock.Util;
using WireMock.Validation; using WireMock.Validation;
namespace WireMock.Matchers namespace WireMock.Matchers
{ {
/// <summary> /// <summary>
/// JsonMatcher /// JsonMatcher
/// </summary> /// </summary>
public class JsonMatcher : IValueMatcher, IIgnoreCaseMatcher public class JsonMatcher : IValueMatcher, IIgnoreCaseMatcher
{ {
/// <inheritdoc cref="IValueMatcher.Value"/> /// <inheritdoc cref="IValueMatcher.Value"/>
public object Value { get; } public object Value { get; }
/// <inheritdoc cref="IMatcher.Name"/> /// <inheritdoc cref="IMatcher.Name"/>
public string Name => "JsonMatcher"; public string Name => "JsonMatcher";
/// <inheritdoc cref="IMatcher.MatchBehaviour"/> /// <inheritdoc cref="IMatcher.MatchBehaviour"/>
public MatchBehaviour MatchBehaviour { get; } public MatchBehaviour MatchBehaviour { get; }
/// <inheritdoc cref="IIgnoreCaseMatcher.IgnoreCase"/> /// <inheritdoc cref="IIgnoreCaseMatcher.IgnoreCase"/>
public bool IgnoreCase { get; } public bool IgnoreCase { get; }
/// <summary> /// <inheritdoc cref="IMatcher.ThrowException"/>
/// Initializes a new instance of the <see cref="JsonMatcher"/> class. public bool ThrowException { get; }
/// </summary>
/// <param name="value">The string value to check for equality.</param> private readonly JToken _valueAsJToken;
/// <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) /// <summary>
{ /// Initializes a new instance of the <see cref="JsonMatcher"/> class.
} /// </summary>
/// <param name="value">The string value to check for equality.</param>
/// <summary> /// <param name="ignoreCase">Ignore the case from the PropertyName and PropertyValue (string only).</param>
/// Initializes a new instance of the <see cref="JsonMatcher"/> class. /// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
/// </summary> public JsonMatcher([NotNull] string value, bool ignoreCase = false, bool throwException = false) : this(MatchBehaviour.AcceptOnMatch, value, ignoreCase, throwException)
/// <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)
{ /// <summary>
} /// Initializes a new instance of the <see cref="JsonMatcher"/> class.
/// </summary>
/// <summary> /// <param name="value">The object value to check for equality.</param>
/// Initializes a new instance of the <see cref="JsonMatcher"/> class. /// <param name="ignoreCase">Ignore the case from the PropertyName and PropertyValue (string only).</param>
/// </summary> /// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
/// <param name="matchBehaviour">The match behaviour.</param> public JsonMatcher([NotNull] object value, bool ignoreCase = false, bool throwException = false) : this(MatchBehaviour.AcceptOnMatch, value, ignoreCase, throwException)
/// <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(MatchBehaviour matchBehaviour, [NotNull] string value, bool ignoreCase = false)
{ /// <summary>
Check.NotNull(value, nameof(value)); /// Initializes a new instance of the <see cref="JsonMatcher"/> class.
/// </summary>
MatchBehaviour = matchBehaviour; /// <param name="matchBehaviour">The match behaviour.</param>
Value = value; /// <param name="value">The value to check for equality.</param>
IgnoreCase = ignoreCase; /// <param name="ignoreCase">Ignore the case from the PropertyName and PropertyValue (string only).</param>
} /// <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)
/// <summary> {
/// Initializes a new instance of the <see cref="JsonMatcher"/> class. Check.NotNull(value, nameof(value));
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param> MatchBehaviour = matchBehaviour;
/// <param name="value">The object value to check for equality.</param> IgnoreCase = ignoreCase;
/// <param name="ignoreCase">Ignore the case from the PropertyName and PropertyValue (string only).</param> ThrowException = throwException;
public JsonMatcher(MatchBehaviour matchBehaviour, [NotNull] object value, bool ignoreCase = false)
{ Value = value;
Check.NotNull(value, nameof(value)); _valueAsJToken = ConvertValueToJToken(value);
}
MatchBehaviour = matchBehaviour;
Value = value; /// <inheritdoc cref="IObjectMatcher.IsMatch"/>
IgnoreCase = ignoreCase; public double IsMatch(object input)
} {
bool match = false;
/// <inheritdoc cref="IObjectMatcher.IsMatch"/>
public double IsMatch(object input) // When input is null or byte[], return Mismatch.
{ if (input != null && !(input is byte[]))
bool match = false; {
try
// When input is null or byte[], return Mismatch. {
if (input != null && !(input is byte[])) var inputAsJToken = ConvertValueToJToken(input);
{
try match = DeepEquals(_valueAsJToken, inputAsJToken);
{ }
// Check if JToken or object catch (JsonException)
JToken jtokenInput = input is JToken tokenInput ? tokenInput : JObject.FromObject(input); {
if (ThrowException)
// Check if JToken, string, IEnumerable or object {
JToken jtokenValue; throw;
switch (Value) }
{ }
case JToken tokenValue: }
jtokenValue = tokenValue;
break; return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.ToScore(match));
}
case string stringValue:
jtokenValue = JsonUtils.Parse(stringValue); private static JToken ConvertValueToJToken(object value)
break; {
// Check if JToken, string, IEnumerable or object
case IEnumerable enumerableValue: switch (value)
jtokenValue = JArray.FromObject(enumerableValue); {
break; case JToken tokenValue:
return tokenValue;
default:
jtokenValue = JObject.FromObject(Value); case string stringValue:
break; return JsonUtils.Parse(stringValue);
}
case IEnumerable enumerableValue:
match = DeepEquals(jtokenValue, jtokenInput); return JArray.FromObject(enumerableValue);
}
catch (JsonException) default:
{ return JObject.FromObject(value);
// just ignore JsonException }
} }
}
private bool DeepEquals(JToken value, JToken input)
return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.ToScore(match)); {
} if (!IgnoreCase)
{
private bool DeepEquals(JToken value, JToken input) return JToken.DeepEquals(value, input);
{ }
if (!IgnoreCase)
{ JToken renamedValue = Rename(value);
return JToken.DeepEquals(value, input); JToken renamedInput = Rename(input);
}
return JToken.DeepEquals(renamedValue, renamedInput);
JToken renamedValue = Rename(value); }
JToken renamedInput = Rename(input);
private static string ToUpper(string input)
return JToken.DeepEquals(renamedValue, renamedInput); {
} return input?.ToUpperInvariant();
}
private static string ToUpper(string input)
{ // https://stackoverflow.com/questions/11679804/json-net-rename-properties
return input?.ToUpperInvariant(); private static JToken Rename(JToken json)
} {
if (json is JProperty property)
// https://stackoverflow.com/questions/11679804/json-net-rename-properties {
private static JToken Rename(JToken json) JToken propertyValue = property.Value;
{ if (propertyValue.Type == JTokenType.String)
if (json is JProperty property) {
{ string stringValue = propertyValue.Value<string>();
JToken propertyValue = property.Value; propertyValue = ToUpper(stringValue);
if (propertyValue.Type == JTokenType.String) }
{
string stringValue = propertyValue.Value<string>(); return new JProperty(ToUpper(property.Name), Rename(propertyValue));
propertyValue = ToUpper(stringValue); }
}
if (json is JArray array)
return new JProperty(ToUpper(property.Name), Rename(propertyValue)); {
} var renamedValues = array.Select(Rename);
return new JArray(renamedValues);
if (json is JArray array) }
{
var renamedValues = array.Select(Rename); if (json is JObject obj)
return new JArray(renamedValues); {
} var renamedProperties = obj.Properties().Select(Rename);
return new JObject(renamedProperties);
if (json is JObject obj) }
{
var renamedProperties = obj.Properties().Select(Rename); return json;
return new JObject(renamedProperties); }
} }
return json;
}
}
} }

View File

@@ -1,132 +1,140 @@
using System.Linq; using System.Linq;
using System.Linq.Dynamic.Core; using System.Linq.Dynamic.Core;
using JetBrains.Annotations; using JetBrains.Annotations;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using WireMock.Util; using WireMock.Util;
namespace WireMock.Matchers namespace WireMock.Matchers
{ {
/// <summary> /// <summary>
/// System.Linq.Dynamic.Core Expression Matcher /// System.Linq.Dynamic.Core Expression Matcher
/// </summary> /// </summary>
/// <inheritdoc cref="IObjectMatcher"/> /// <inheritdoc cref="IObjectMatcher"/>
/// <inheritdoc cref="IStringMatcher"/> /// <inheritdoc cref="IStringMatcher"/>
public class LinqMatcher : IObjectMatcher, IStringMatcher public class LinqMatcher : IObjectMatcher, IStringMatcher
{ {
private readonly string[] _patterns; private readonly string[] _patterns;
/// <inheritdoc cref="IMatcher.MatchBehaviour"/> /// <inheritdoc cref="IMatcher.MatchBehaviour"/>
public MatchBehaviour MatchBehaviour { get; } public MatchBehaviour MatchBehaviour { get; }
/// <inheritdoc cref="IMatcher.ThrowException"/>
/// <summary> public bool ThrowException { get; }
/// Initializes a new instance of the <see cref="LinqMatcher"/> class.
/// </summary> /// <summary>
/// <param name="pattern">The pattern.</param> /// Initializes a new instance of the <see cref="LinqMatcher"/> class.
public LinqMatcher([NotNull] string pattern) : this(new[] { pattern }) /// </summary>
{ /// <param name="pattern">The pattern.</param>
} public LinqMatcher([NotNull] string pattern) : this(new[] { pattern })
{
/// <summary> }
/// Initializes a new instance of the <see cref="LinqMatcher"/> class.
/// </summary> /// <summary>
/// <param name="patterns">The patterns.</param> /// Initializes a new instance of the <see cref="LinqMatcher"/> class.
public LinqMatcher([NotNull] string[] patterns) : this(MatchBehaviour.AcceptOnMatch, patterns) /// </summary>
{ /// <param name="patterns">The patterns.</param>
} public LinqMatcher([NotNull] params string[] patterns) : this(MatchBehaviour.AcceptOnMatch, false, patterns)
{
/// <summary> }
/// Initializes a new instance of the <see cref="LinqMatcher"/> class.
/// </summary> /// <summary>
/// <param name="matchBehaviour">The match behaviour.</param> /// Initializes a new instance of the <see cref="LinqMatcher"/> class.
/// <param name="pattern">The pattern.</param> /// </summary>
public LinqMatcher(MatchBehaviour matchBehaviour, [NotNull] string pattern) : this(matchBehaviour, new[] { pattern }) /// <param name="matchBehaviour">The match behaviour.</param>
{ /// <param name="pattern">The pattern.</param>
} public LinqMatcher(MatchBehaviour matchBehaviour, [NotNull] string pattern) : this(matchBehaviour, false, pattern)
{
/// <summary> }
/// Initializes a new instance of the <see cref="LinqMatcher"/> class.
/// </summary> /// <summary>
/// <param name="matchBehaviour">The match behaviour.</param> /// Initializes a new instance of the <see cref="LinqMatcher"/> class.
/// <param name="patterns">The patterns.</param> /// </summary>
public LinqMatcher(MatchBehaviour matchBehaviour, [NotNull] string[] patterns) /// <param name="matchBehaviour">The match behaviour.</param>
{ /// <param name="patterns">The patterns.</param>
MatchBehaviour = matchBehaviour; /// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
_patterns = patterns; public LinqMatcher(MatchBehaviour matchBehaviour, bool throwException = false, [NotNull] params string[] patterns)
} {
MatchBehaviour = matchBehaviour;
/// <inheritdoc cref="IStringMatcher.IsMatch"/> ThrowException = throwException;
public double IsMatch(string input) _patterns = patterns;
{ }
double match = MatchScores.Mismatch;
/// <inheritdoc cref="IStringMatcher.IsMatch"/>
// Convert a single input string to a Queryable string-list with 1 entry. public double IsMatch(string input)
IQueryable queryable = new[] { input }.AsQueryable(); {
double match = MatchScores.Mismatch;
try
{ // Convert a single input string to a Queryable string-list with 1 entry.
// Use the Any(...) method to check if the result matches IQueryable queryable = new[] { input }.AsQueryable();
match = MatchScores.ToScore(_patterns.Select(pattern => queryable.Any(pattern)));
try
return MatchBehaviourHelper.Convert(MatchBehaviour, match); {
} // Use the Any(...) method to check if the result matches
catch match = MatchScores.ToScore(_patterns.Select(pattern => queryable.Any(pattern)));
{
// just ignore exception return MatchBehaviourHelper.Convert(MatchBehaviour, match);
// TODO add logging? }
} catch
{
return MatchBehaviourHelper.Convert(MatchBehaviour, match); if (ThrowException)
} {
throw;
/// <inheritdoc cref="IObjectMatcher.IsMatch"/> }
public double IsMatch(object input) }
{
double match = MatchScores.Mismatch; return MatchBehaviourHelper.Convert(MatchBehaviour, match);
}
JObject value;
switch (input) /// <inheritdoc cref="IObjectMatcher.IsMatch"/>
{ public double IsMatch(object input)
case JObject valueAsJObject: {
value = valueAsJObject; double match = MatchScores.Mismatch;
break;
JObject value;
default: switch (input)
value = JObject.FromObject(input); {
break; case JObject valueAsJObject:
} value = valueAsJObject;
break;
// Convert a single object to a Queryable JObject-list with 1 entry.
var queryable1 = new[] { value }.AsQueryable(); default:
value = JObject.FromObject(input);
try break;
{ }
// Generate the DynamicLinq select statement.
string dynamicSelect = JsonUtils.GenerateDynamicLinqStatement(value); // Convert a single object to a Queryable JObject-list with 1 entry.
var queryable1 = new[] { value }.AsQueryable();
// Execute DynamicLinq Select statement.
var queryable2 = queryable1.Select(dynamicSelect); try
{
// Use the Any(...) method to check if the result matches. // Generate the DynamicLinq select statement.
match = MatchScores.ToScore(_patterns.Select(pattern => queryable2.Any(pattern))); string dynamicSelect = JsonUtils.GenerateDynamicLinqStatement(value);
return MatchBehaviourHelper.Convert(MatchBehaviour, match); // Execute DynamicLinq Select statement.
} var queryable2 = queryable1.Select(dynamicSelect);
catch
{ // Use the Any(...) method to check if the result matches.
// just ignore exception match = MatchScores.ToScore(_patterns.Select(pattern => queryable2.Any(pattern)));
// TODO add logging?
} return MatchBehaviourHelper.Convert(MatchBehaviour, match);
}
return MatchBehaviourHelper.Convert(MatchBehaviour, match); catch
} {
if (ThrowException)
/// <inheritdoc cref="IStringMatcher.GetPatterns"/> {
public string[] GetPatterns() throw;
{ }
return _patterns; }
}
return MatchBehaviourHelper.Convert(MatchBehaviour, match);
/// <inheritdoc cref="IMatcher.Name"/> }
public string Name => "LinqMatcher";
} /// <inheritdoc cref="IStringMatcher.GetPatterns"/>
} public string[] GetPatterns()
{
return _patterns;
}
/// <inheritdoc cref="IMatcher.Name"/>
public string Name => "LinqMatcher";
}
}

View File

@@ -19,6 +19,9 @@ namespace WireMock.Matchers
/// <inheritdoc cref="IMatcher.MatchBehaviour"/> /// <inheritdoc cref="IMatcher.MatchBehaviour"/>
public MatchBehaviour MatchBehaviour { get; } public MatchBehaviour MatchBehaviour { get; }
/// <inheritdoc cref="IMatcher.ThrowException"/>
public bool ThrowException { get; }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="RegexMatcher"/> class. /// Initializes a new instance of the <see cref="RegexMatcher"/> class.
/// </summary> /// </summary>
@@ -53,13 +56,15 @@ namespace WireMock.Matchers
/// <param name="matchBehaviour">The match behaviour.</param> /// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="patterns">The patterns.</param> /// <param name="patterns">The patterns.</param>
/// <param name="ignoreCase">Ignore the case from the pattern.</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)); Check.NotNull(patterns, nameof(patterns));
_patterns = patterns; _patterns = patterns;
IgnoreCase = ignoreCase; IgnoreCase = ignoreCase;
MatchBehaviour = matchBehaviour; MatchBehaviour = matchBehaviour;
ThrowException = throwException;
RegexOptions options = RegexOptions.Compiled | RegexOptions.Multiline; RegexOptions options = RegexOptions.Compiled | RegexOptions.Multiline;
@@ -83,10 +88,13 @@ namespace WireMock.Matchers
} }
catch (Exception) catch (Exception)
{ {
// just ignore exception if (ThrowException)
{
throw;
}
} }
} }
return MatchBehaviourHelper.Convert(MatchBehaviour, match); return MatchBehaviourHelper.Convert(MatchBehaviour, match);
} }

View File

@@ -51,7 +51,7 @@ namespace WireMock.Matchers.Request
/// <param name="key">The key.</param> /// <param name="key">The key.</param>
/// <param name="ignoreCase">Defines if the key should be matched using case-ignore.</param> /// <param name="ignoreCase">Defines if the key should be matched using case-ignore.</param>
/// <param name="values">The values.</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

@@ -1,125 +1,131 @@
using System.Linq; using System.Linq;
using JetBrains.Annotations; using JetBrains.Annotations;
using SimMetrics.Net; using SimMetrics.Net;
using SimMetrics.Net.API; using SimMetrics.Net.API;
using SimMetrics.Net.Metric; using SimMetrics.Net.Metric;
using WireMock.Validation; using WireMock.Validation;
namespace WireMock.Matchers namespace WireMock.Matchers
{ {
/// <summary> /// <summary>
/// SimMetricsMatcher /// SimMetricsMatcher
/// </summary> /// </summary>
/// <seealso cref="IStringMatcher" /> /// <seealso cref="IStringMatcher" />
public class SimMetricsMatcher : IStringMatcher public class SimMetricsMatcher : IStringMatcher
{ {
private readonly string[] _patterns; private readonly string[] _patterns;
private readonly SimMetricType _simMetricType; private readonly SimMetricType _simMetricType;
/// <inheritdoc cref="IMatcher.MatchBehaviour"/> /// <inheritdoc cref="IMatcher.MatchBehaviour"/>
public MatchBehaviour MatchBehaviour { get; } public MatchBehaviour MatchBehaviour { get; }
/// <summary> /// <inheritdoc cref="IMatcher.ThrowException"/>
/// Initializes a new instance of the <see cref="SimMetricsMatcher"/> class. public bool ThrowException { get; }
/// </summary>
/// <param name="pattern">The pattern.</param> /// <summary>
/// <param name="simMetricType">The SimMetric Type</param> /// Initializes a new instance of the <see cref="SimMetricsMatcher"/> class.
public SimMetricsMatcher([NotNull] string pattern, SimMetricType simMetricType = SimMetricType.Levenstein) : this(new[] { pattern }, simMetricType) /// </summary>
{ /// <param name="pattern">The pattern.</param>
} /// <param name="simMetricType">The SimMetric Type</param>
public SimMetricsMatcher([NotNull] string pattern, SimMetricType simMetricType = SimMetricType.Levenstein) : this(new[] { pattern }, simMetricType)
/// <summary> {
/// Initializes a new instance of the <see cref="SimMetricsMatcher"/> class. }
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param> /// <summary>
/// <param name="pattern">The pattern.</param> /// Initializes a new instance of the <see cref="SimMetricsMatcher"/> class.
/// <param name="simMetricType">The SimMetric Type</param> /// </summary>
public SimMetricsMatcher(MatchBehaviour matchBehaviour, [NotNull] string pattern, SimMetricType simMetricType = SimMetricType.Levenstein) : this(matchBehaviour, new[] { pattern }, simMetricType) /// <param name="matchBehaviour">The match behaviour.</param>
{ /// <param name="pattern">The pattern.</param>
} /// <param name="simMetricType">The SimMetric Type</param>
public SimMetricsMatcher(MatchBehaviour matchBehaviour, [NotNull] string pattern, SimMetricType simMetricType = SimMetricType.Levenstein) : this(matchBehaviour, new[] { pattern }, simMetricType)
/// <summary> {
/// Initializes a new instance of the <see cref="SimMetricsMatcher"/> class. }
/// </summary>
/// <param name="patterns">The patterns.</param> /// <summary>
/// <param name="simMetricType">The SimMetric Type</param> /// Initializes a new instance of the <see cref="SimMetricsMatcher"/> class.
public SimMetricsMatcher([NotNull] string[] patterns, SimMetricType simMetricType = SimMetricType.Levenstein) : this(MatchBehaviour.AcceptOnMatch, patterns, simMetricType) /// </summary>
{ /// <param name="patterns">The patterns.</param>
} /// <param name="simMetricType">The SimMetric Type</param>
public SimMetricsMatcher([NotNull] string[] patterns, SimMetricType simMetricType = SimMetricType.Levenstein) : this(MatchBehaviour.AcceptOnMatch, patterns, simMetricType)
/// <summary> {
/// Initializes a new instance of the <see cref="SimMetricsMatcher"/> class. }
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param> /// <summary>
/// <param name="patterns">The patterns.</param> /// Initializes a new instance of the <see cref="SimMetricsMatcher"/> class.
/// <param name="simMetricType">The SimMetric Type</param> /// </summary>
public SimMetricsMatcher(MatchBehaviour matchBehaviour, [NotNull] string[] patterns, SimMetricType simMetricType = SimMetricType.Levenstein) /// <param name="matchBehaviour">The match behaviour.</param>
{ /// <param name="patterns">The patterns.</param>
Check.NotNullOrEmpty(patterns, nameof(patterns)); /// <param name="simMetricType">The SimMetric Type</param>
/// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
MatchBehaviour = matchBehaviour; public SimMetricsMatcher(MatchBehaviour matchBehaviour, [NotNull] string[] patterns, SimMetricType simMetricType = SimMetricType.Levenstein, bool throwException = false)
_patterns = patterns; {
_simMetricType = simMetricType; Check.NotNullOrEmpty(patterns, nameof(patterns));
}
MatchBehaviour = matchBehaviour;
/// <inheritdoc cref="IStringMatcher.IsMatch"/> ThrowException = throwException;
public double IsMatch(string input)
{ _patterns = patterns;
IStringMetric m = GetStringMetricType(); _simMetricType = simMetricType;
}
return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.ToScore(_patterns.Select(p => m.GetSimilarity(p, input))));
} /// <inheritdoc cref="IStringMatcher.IsMatch"/>
public double IsMatch(string input)
private IStringMetric GetStringMetricType() {
{ IStringMetric m = GetStringMetricType();
switch (_simMetricType)
{ return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.ToScore(_patterns.Select(p => m.GetSimilarity(p, input))));
case SimMetricType.BlockDistance: }
return new BlockDistance();
case SimMetricType.ChapmanLengthDeviation: private IStringMetric GetStringMetricType()
return new ChapmanLengthDeviation(); {
case SimMetricType.CosineSimilarity: switch (_simMetricType)
return new CosineSimilarity(); {
case SimMetricType.DiceSimilarity: case SimMetricType.BlockDistance:
return new DiceSimilarity(); return new BlockDistance();
case SimMetricType.EuclideanDistance: case SimMetricType.ChapmanLengthDeviation:
return new EuclideanDistance(); return new ChapmanLengthDeviation();
case SimMetricType.JaccardSimilarity: case SimMetricType.CosineSimilarity:
return new JaccardSimilarity(); return new CosineSimilarity();
case SimMetricType.Jaro: case SimMetricType.DiceSimilarity:
return new Jaro(); return new DiceSimilarity();
case SimMetricType.JaroWinkler: case SimMetricType.EuclideanDistance:
return new JaroWinkler(); return new EuclideanDistance();
case SimMetricType.MatchingCoefficient: case SimMetricType.JaccardSimilarity:
return new MatchingCoefficient(); return new JaccardSimilarity();
case SimMetricType.MongeElkan: case SimMetricType.Jaro:
return new MongeElkan(); return new Jaro();
case SimMetricType.NeedlemanWunch: case SimMetricType.JaroWinkler:
return new NeedlemanWunch(); return new JaroWinkler();
case SimMetricType.OverlapCoefficient: case SimMetricType.MatchingCoefficient:
return new OverlapCoefficient(); return new MatchingCoefficient();
case SimMetricType.QGramsDistance: case SimMetricType.MongeElkan:
return new QGramsDistance(); return new MongeElkan();
case SimMetricType.SmithWaterman: case SimMetricType.NeedlemanWunch:
return new SmithWaterman(); return new NeedlemanWunch();
case SimMetricType.SmithWatermanGotoh: case SimMetricType.OverlapCoefficient:
return new SmithWatermanGotoh(); return new OverlapCoefficient();
case SimMetricType.SmithWatermanGotohWindowedAffine: case SimMetricType.QGramsDistance:
return new SmithWatermanGotohWindowedAffine(); return new QGramsDistance();
case SimMetricType.ChapmanMeanLength: case SimMetricType.SmithWaterman:
return new ChapmanMeanLength(); return new SmithWaterman();
default: case SimMetricType.SmithWatermanGotoh:
return new Levenstein(); return new SmithWatermanGotoh();
} case SimMetricType.SmithWatermanGotohWindowedAffine:
} return new SmithWatermanGotohWindowedAffine();
case SimMetricType.ChapmanMeanLength:
/// <inheritdoc cref="IStringMatcher.GetPatterns"/> return new ChapmanMeanLength();
public string[] GetPatterns() default:
{ return new Levenstein();
return _patterns; }
} }
/// <inheritdoc cref="IMatcher.Name"/> /// <inheritdoc cref="IStringMatcher.GetPatterns"/>
public string Name => $"SimMetricsMatcher.{_simMetricType}"; public string[] GetPatterns()
} {
return _patterns;
}
/// <inheritdoc cref="IMatcher.Name"/>
public string Name => $"SimMetricsMatcher.{_simMetricType}";
}
} }

View File

@@ -1,63 +1,65 @@
using System.Linq; using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using JetBrains.Annotations; using JetBrains.Annotations;
namespace WireMock.Matchers namespace WireMock.Matchers
{ {
/// <summary> /// <summary>
/// WildcardMatcher /// WildcardMatcher
/// </summary> /// </summary>
/// <seealso cref="RegexMatcher" /> /// <seealso cref="RegexMatcher" />
public class WildcardMatcher : RegexMatcher public class WildcardMatcher : RegexMatcher
{ {
private readonly string[] _patterns; private readonly string[] _patterns;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="WildcardMatcher"/> class. /// Initializes a new instance of the <see cref="WildcardMatcher"/> class.
/// </summary> /// </summary>
/// <param name="pattern">The pattern.</param> /// <param name="pattern">The pattern.</param>
/// <param name="ignoreCase">IgnoreCase</param> /// <param name="ignoreCase">IgnoreCase</param>
public WildcardMatcher([NotNull] string pattern, bool ignoreCase = false) : this(new[] { pattern }, ignoreCase) public WildcardMatcher([NotNull] string pattern, bool ignoreCase = false) : this(new[] { pattern }, ignoreCase)
{ {
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="WildcardMatcher"/> class. /// Initializes a new instance of the <see cref="WildcardMatcher"/> class.
/// </summary> /// </summary>
/// <param name="matchBehaviour">The match behaviour.</param> /// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="pattern">The pattern.</param> /// <param name="pattern">The pattern.</param>
/// <param name="ignoreCase">IgnoreCase</param> /// <param name="ignoreCase">IgnoreCase</param>
public WildcardMatcher(MatchBehaviour matchBehaviour, [NotNull] string pattern, bool ignoreCase = false) : this(matchBehaviour, new[] { pattern }, ignoreCase) public WildcardMatcher(MatchBehaviour matchBehaviour, [NotNull] string pattern, bool ignoreCase = false) : this(matchBehaviour, new[] { pattern }, ignoreCase)
{ {
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="WildcardMatcher"/> class. /// Initializes a new instance of the <see cref="WildcardMatcher"/> class.
/// </summary> /// </summary>
/// <param name="patterns">The patterns.</param> /// <param name="patterns">The patterns.</param>
/// <param name="ignoreCase">IgnoreCase</param> /// <param name="ignoreCase">IgnoreCase</param>
public WildcardMatcher([NotNull] string[] patterns, bool ignoreCase = false) : this(MatchBehaviour.AcceptOnMatch, patterns, ignoreCase) public WildcardMatcher([NotNull] string[] patterns, bool ignoreCase = false) : this(MatchBehaviour.AcceptOnMatch, patterns, ignoreCase)
{ {
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="WildcardMatcher"/> class. /// Initializes a new instance of the <see cref="WildcardMatcher"/> class.
/// </summary> /// </summary>
/// <param name="matchBehaviour">The match behaviour.</param> /// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="patterns">The patterns.</param> /// <param name="patterns">The patterns.</param>
/// <param name="ignoreCase">IgnoreCase</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) :
_patterns = patterns; base(matchBehaviour, patterns.Select(pattern => "^" + Regex.Escape(pattern).Replace(@"\*", ".*").Replace(@"\?", ".") + "$").ToArray(), ignoreCase, throwException)
} {
_patterns = patterns;
/// <inheritdoc cref="IStringMatcher.GetPatterns"/> }
public override string[] GetPatterns()
{ /// <inheritdoc cref="IStringMatcher.GetPatterns"/>
return _patterns; public override string[] GetPatterns()
} {
return _patterns;
/// <inheritdoc cref="IMatcher.Name"/> }
public override string Name => "WildcardMatcher";
} /// <inheritdoc cref="IMatcher.Name"/>
public override string Name => "WildcardMatcher";
}
} }

View File

@@ -1,78 +1,85 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Xml; using System.Xml;
using JetBrains.Annotations; using JetBrains.Annotations;
using WireMock.Validation; using WireMock.Validation;
#if !NETSTANDARD1_3 #if !NETSTANDARD1_3
using Wmhelp.XPath2; using Wmhelp.XPath2;
#endif #endif
namespace WireMock.Matchers namespace WireMock.Matchers
{ {
/// <summary> /// <summary>
/// XPath2Matcher /// XPath2Matcher
/// </summary> /// </summary>
/// <seealso cref="IStringMatcher" /> /// <seealso cref="IStringMatcher" />
public class XPathMatcher : IStringMatcher public class XPathMatcher : IStringMatcher
{ {
private readonly string[] _patterns; private readonly string[] _patterns;
/// <inheritdoc cref="IMatcher.MatchBehaviour"/> /// <inheritdoc cref="IMatcher.MatchBehaviour"/>
public MatchBehaviour MatchBehaviour { get; } public MatchBehaviour MatchBehaviour { get; }
/// <summary> /// <inheritdoc cref="IMatcher.ThrowException"/>
/// Initializes a new instance of the <see cref="XPathMatcher"/> class. public bool ThrowException { get; }
/// </summary>
/// <param name="patterns">The patterns.</param> /// <summary>
public XPathMatcher([NotNull] params string[] patterns) : this(MatchBehaviour.AcceptOnMatch, patterns) /// 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, false, patterns)
/// <summary> {
/// Initializes a new instance of the <see cref="XPathMatcher"/> class. }
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param> /// <summary>
/// <param name="patterns">The patterns.</param> /// Initializes a new instance of the <see cref="XPathMatcher"/> class.
public XPathMatcher(MatchBehaviour matchBehaviour, [NotNull] params string[] patterns) /// </summary>
{ /// <param name="matchBehaviour">The match behaviour.</param>
Check.NotNull(patterns, nameof(patterns)); /// <param name="throwException">Throw an exception when the internal matching fails because of invalid input.</param>
/// <param name="patterns">The patterns.</param>
MatchBehaviour = matchBehaviour; public XPathMatcher(MatchBehaviour matchBehaviour, bool throwException = false, [NotNull] params string[] patterns)
_patterns = patterns; {
} Check.NotNull(patterns, nameof(patterns));
/// <inheritdoc cref="IStringMatcher.IsMatch"/> MatchBehaviour = matchBehaviour;
public double IsMatch(string input) ThrowException = throwException;
{ _patterns = patterns;
double match = MatchScores.Mismatch; }
if (input != null)
{ /// <inheritdoc cref="IStringMatcher.IsMatch"/>
try public double IsMatch(string input)
{ {
var nav = new XmlDocument { InnerXml = input }.CreateNavigator(); double match = MatchScores.Mismatch;
#if NETSTANDARD1_3 if (input != null)
match = MatchScores.ToScore(_patterns.Select(p => true.Equals(nav.Evaluate($"boolean({p})")))); {
#else try
match = MatchScores.ToScore(_patterns.Select(p => true.Equals(nav.XPath2Evaluate($"boolean({p})")))); {
#endif var nav = new XmlDocument { InnerXml = input }.CreateNavigator();
} #if NETSTANDARD1_3
catch (Exception) match = MatchScores.ToScore(_patterns.Select(p => true.Equals(nav.Evaluate($"boolean({p})"))));
{ #else
// just ignore exception match = MatchScores.ToScore(_patterns.Select(p => true.Equals(nav.XPath2Evaluate($"boolean({p})"))));
// TODO add logging? #endif
} }
} catch (Exception)
{
return MatchBehaviourHelper.Convert(MatchBehaviour, match); if (ThrowException)
} {
throw;
/// <inheritdoc cref="IStringMatcher.GetPatterns"/> }
public string[] GetPatterns() }
{ }
return _patterns;
} return MatchBehaviourHelper.Convert(MatchBehaviour, match);
}
/// <inheritdoc cref="IMatcher.Name"/>
public string Name => "XPathMatcher"; /// <inheritdoc cref="IStringMatcher.GetPatterns"/>
} public string[] GetPatterns()
{
return _patterns;
}
/// <inheritdoc cref="IMatcher.Name"/>
public string Name => "XPathMatcher";
}
} }

View File

@@ -38,6 +38,8 @@ namespace WireMock.Serialization
string[] stringPatterns = matcher.Patterns != null ? matcher.Patterns.OfType<string>().ToArray() : new[] { matcher.Pattern as string }; string[] stringPatterns = matcher.Patterns != null ? matcher.Patterns.OfType<string>().ToArray() : new[] { matcher.Pattern as string };
MatchBehaviour matchBehaviour = matcher.RejectOnMatch == true ? MatchBehaviour.RejectOnMatch : MatchBehaviour.AcceptOnMatch; MatchBehaviour matchBehaviour = matcher.RejectOnMatch == true ? MatchBehaviour.RejectOnMatch : MatchBehaviour.AcceptOnMatch;
bool ignoreCase = matcher.IgnoreCase == true;
bool throwExceptionWhenMatcherFails = _settings.ThrowExceptionWhenMatcherFails == true;
switch (matcherName) 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'."); throw new NotSupportedException("It's not allowed to use the 'CSharpCodeMatcher' because IWireMockServerSettings.AllowCSharpCodeMatcher is not set to 'true'.");
case "LinqMatcher": case "LinqMatcher":
return new LinqMatcher(matchBehaviour, stringPatterns); return new LinqMatcher(matchBehaviour, throwExceptionWhenMatcherFails, stringPatterns);
case "ExactMatcher": case "ExactMatcher":
return new ExactMatcher(matchBehaviour, stringPatterns); return new ExactMatcher(matchBehaviour, throwExceptionWhenMatcherFails, stringPatterns);
case "ExactObjectMatcher": case "ExactObjectMatcher":
return CreateExactObjectMatcher(matchBehaviour, stringPatterns[0]); return CreateExactObjectMatcher(matchBehaviour, stringPatterns[0], throwExceptionWhenMatcherFails);
case "RegexMatcher": case "RegexMatcher":
return new RegexMatcher(matchBehaviour, stringPatterns, matcher.IgnoreCase == true); return new RegexMatcher(matchBehaviour, stringPatterns, ignoreCase, throwExceptionWhenMatcherFails);
case "JsonMatcher": case "JsonMatcher":
return new JsonMatcher(matchBehaviour, matcher.Pattern, matcher.IgnoreCase == true); return new JsonMatcher(matchBehaviour, stringPatterns, ignoreCase, throwExceptionWhenMatcherFails);
case "JsonPathMatcher": case "JsonPathMatcher":
return new JsonPathMatcher(matchBehaviour, stringPatterns); return new JsonPathMatcher(matchBehaviour, throwExceptionWhenMatcherFails, stringPatterns);
case "JmesPathMatcher": case "JmesPathMatcher":
return new JmesPathMatcher(matchBehaviour, stringPatterns); return new JmesPathMatcher(matchBehaviour, throwExceptionWhenMatcherFails, stringPatterns);
case "XPathMatcher": case "XPathMatcher":
return new XPathMatcher(matchBehaviour, stringPatterns); return new XPathMatcher(matchBehaviour, throwExceptionWhenMatcherFails, stringPatterns);
case "WildcardMatcher": case "WildcardMatcher":
return new WildcardMatcher(matchBehaviour, stringPatterns, matcher.IgnoreCase == true); return new WildcardMatcher(matchBehaviour, stringPatterns, ignoreCase, throwExceptionWhenMatcherFails);
case "ContentTypeMatcher": case "ContentTypeMatcher":
return new ContentTypeMatcher(matchBehaviour, stringPatterns, matcher.IgnoreCase == true); return new ContentTypeMatcher(matchBehaviour, stringPatterns, ignoreCase, throwExceptionWhenMatcherFails);
case "SimMetricsMatcher": case "SimMetricsMatcher":
SimMetricType type = SimMetricType.Levenstein; SimMetricType type = SimMetricType.Levenstein;
@@ -86,14 +88,14 @@ namespace WireMock.Serialization
throw new NotSupportedException($"Matcher '{matcherName}' with Type '{matcherType}' is not supported."); 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: default:
throw new NotSupportedException($"Matcher '{matcherName}' is not supported."); 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; byte[] bytePattern;
try 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)); 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) 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;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
@@ -9,6 +6,9 @@ using System.Net;
using System.Net.Http; using System.Net.Http;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using JetBrains.Annotations;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using WireMock.Admin.Mappings; using WireMock.Admin.Mappings;
using WireMock.Admin.Scenarios; using WireMock.Admin.Scenarios;
using WireMock.Admin.Settings; using WireMock.Admin.Settings;
@@ -274,7 +274,12 @@ namespace WireMock.Server
if (HttpStatusRangeParser.IsMatch(settings.ProxyAndRecordSettings.SaveMappingForStatusCodePattern, responseMessage.StatusCode) && if (HttpStatusRangeParser.IsMatch(settings.ProxyAndRecordSettings.SaveMappingForStatusCodePattern, responseMessage.StatusCode) &&
(settings.ProxyAndRecordSettings.SaveMapping || settings.ProxyAndRecordSettings.SaveMappingToFile)) (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) if (settings.ProxyAndRecordSettings.SaveMapping)
{ {
@@ -314,18 +319,19 @@ namespace WireMock.Server
} }
}); });
bool throwExceptionWhenMatcherFails = _settings.ThrowExceptionWhenMatcherFails == true;
switch (requestMessage.BodyData?.DetectedBodyType) switch (requestMessage.BodyData?.DetectedBodyType)
{ {
case BodyType.Json: case BodyType.Json:
request.WithBody(new JsonMatcher(MatchBehaviour.AcceptOnMatch, requestMessage.BodyData.BodyAsJson)); request.WithBody(new JsonMatcher(MatchBehaviour.AcceptOnMatch, requestMessage.BodyData.BodyAsJson, true, throwExceptionWhenMatcherFails));
break; break;
case BodyType.String: case BodyType.String:
request.WithBody(new ExactMatcher(MatchBehaviour.AcceptOnMatch, requestMessage.BodyData.BodyAsString)); request.WithBody(new ExactMatcher(MatchBehaviour.AcceptOnMatch, throwExceptionWhenMatcherFails, requestMessage.BodyData.BodyAsString));
break; break;
case BodyType.Bytes: case BodyType.Bytes:
request.WithBody(new ExactObjectMatcher(MatchBehaviour.AcceptOnMatch, requestMessage.BodyData.BodyAsBytes)); request.WithBody(new ExactObjectMatcher(MatchBehaviour.AcceptOnMatch, requestMessage.BodyData.BodyAsBytes, throwExceptionWhenMatcherFails));
break; break;
} }
@@ -340,12 +346,13 @@ namespace WireMock.Server
{ {
var model = new SettingsModel var model = new SettingsModel
{ {
AllowPartialMapping = _options.AllowPartialMapping, AllowPartialMapping = _settings.AllowPartialMapping,
MaxRequestLogCount = _options.MaxRequestLogCount, MaxRequestLogCount = _settings.MaxRequestLogCount,
RequestLogExpirationDuration = _options.RequestLogExpirationDuration, RequestLogExpirationDuration = _settings.RequestLogExpirationDuration,
GlobalProcessingDelay = (int?)_options.RequestProcessingDelay?.TotalMilliseconds, GlobalProcessingDelay = (int?)_options.RequestProcessingDelay?.TotalMilliseconds,
AllowBodyForAllHttpMethods = _options.AllowBodyForAllHttpMethods, AllowBodyForAllHttpMethods = _settings.AllowBodyForAllHttpMethods,
HandleRequestsSynchronously = _options.HandleRequestsSynchronously HandleRequestsSynchronously = _settings.HandleRequestsSynchronously,
ThrowExceptionWhenMatcherFails = _settings.ThrowExceptionWhenMatcherFails
}; };
return ToJson(model); return ToJson(model);
@@ -377,6 +384,11 @@ namespace WireMock.Server
_options.HandleRequestsSynchronously = settings.HandleRequestsSynchronously.Value; _options.HandleRequestsSynchronously = settings.HandleRequestsSynchronously.Value;
} }
if (settings.ThrowExceptionWhenMatcherFails != null)
{
_settings.ThrowExceptionWhenMatcherFails = settings.ThrowExceptionWhenMatcherFails.Value;
}
return ResponseMessageBuilder.Create("Settings updated"); return ResponseMessageBuilder.Create("Settings updated");
} }
#endregion Settings #endregion Settings

View File

@@ -3,6 +3,7 @@ using HandlebarsDotNet;
using JetBrains.Annotations; using JetBrains.Annotations;
using WireMock.Handlers; using WireMock.Handlers;
using WireMock.Logging; using WireMock.Logging;
using WireMock.Matchers;
namespace WireMock.Settings namespace WireMock.Settings
{ {
@@ -163,5 +164,11 @@ namespace WireMock.Settings
/// </summary> /// </summary>
[PublicAPI] [PublicAPI]
bool? HandleRequestsSynchronously { get; set; } 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"/> /// <inheritdoc cref="IWireMockServerSettings.HandleRequestsSynchronously"/>
[PublicAPI] [PublicAPI]
public bool? HandleRequestsSynchronously { get; set; } 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"), AllowBodyForAllHttpMethods = parser.GetBoolValue("AllowBodyForAllHttpMethods"),
AllowOnlyDefinedHttpStatusCodeInResponse = parser.GetBoolValue("AllowOnlyDefinedHttpStatusCodeInResponse"), AllowOnlyDefinedHttpStatusCodeInResponse = parser.GetBoolValue("AllowOnlyDefinedHttpStatusCodeInResponse"),
DisableJsonBodyParsing = parser.GetBoolValue("DisableJsonBodyParsing"), DisableJsonBodyParsing = parser.GetBoolValue("DisableJsonBodyParsing"),
HandleRequestsSynchronously = parser.GetBoolValue("HandleRequestsSynchronously") HandleRequestsSynchronously = parser.GetBoolValue("HandleRequestsSynchronously"),
ThrowExceptionWhenMatcherFails = parser.GetBoolValue("ThrowExceptionWhenMatcherFails")
}; };
if (logger != null) if (logger != null)

View File

@@ -1,5 +1,5 @@
using HandlebarsDotNet; using System;
using System; using HandlebarsDotNet;
using WireMock.Handlers; using WireMock.Handlers;
namespace WireMock.Transformers 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 JetBrains.Annotations;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WireMock.Types; using WireMock.Types;
using WireMock.Util; using WireMock.Util;
using WireMock.Validation; using WireMock.Validation;

View File

@@ -1,92 +1,92 @@
using NFluent; using NFluent;
using WireMock.Matchers; using WireMock.Matchers;
using Xunit; using Xunit;
namespace WireMock.Net.Tests.Matchers namespace WireMock.Net.Tests.Matchers
{ {
public class CSharpCodeMatcherTests public class CSharpCodeMatcherTests
{ {
[Fact] [Fact]
public void CSharpCodeMatcher_For_String_SinglePattern_IsMatch_Positive() public void CSharpCodeMatcher_For_String_SinglePattern_IsMatch_Positive()
{ {
// Assign // Assign
string input = "x"; string input = "x";
// Act // Act
var matcher = new CSharpCodeMatcher("return it == \"x\";"); var matcher = new CSharpCodeMatcher("return it == \"x\";");
// Assert // Assert
Check.That(matcher.IsMatch(input)).IsEqualTo(1.0d); Check.That(matcher.IsMatch(input)).IsEqualTo(1.0d);
} }
[Fact] [Fact]
public void CSharpCodeMatcher_For_String_IsMatch_Negative() public void CSharpCodeMatcher_For_String_IsMatch_Negative()
{ {
// Assign // Assign
string input = "y"; string input = "y";
// Act // Act
var matcher = new CSharpCodeMatcher("return it == \"x\";"); var matcher = new CSharpCodeMatcher("return it == \"x\";");
// Assert // Assert
Check.That(matcher.IsMatch(input)).IsEqualTo(0.0d); Check.That(matcher.IsMatch(input)).IsEqualTo(0.0d);
} }
[Fact] [Fact]
public void CSharpCodeMatcher_For_String_IsMatch_RejectOnMatch() public void CSharpCodeMatcher_For_String_IsMatch_RejectOnMatch()
{ {
// Assign // Assign
string input = "x"; string input = "x";
// Act // Act
var matcher = new CSharpCodeMatcher(MatchBehaviour.RejectOnMatch, "return it == \"x\";"); var matcher = new CSharpCodeMatcher(MatchBehaviour.RejectOnMatch, "return it == \"x\";");
// Assert // Assert
Check.That(matcher.IsMatch(input)).IsEqualTo(0.0d); Check.That(matcher.IsMatch(input)).IsEqualTo(0.0d);
} }
[Fact] [Fact]
public void CSharpCodeMatcher_For_Object_IsMatch() public void CSharpCodeMatcher_For_Object_IsMatch()
{ {
// Assign // Assign
var input = new var input = new
{ {
Id = 9, Id = 9,
Name = "Test" Name = "Test"
}; };
// Act // Act
var matcher = new CSharpCodeMatcher("return it.Id > 1 && it.Name == \"Test\";"); var matcher = new CSharpCodeMatcher("return it.Id > 1 && it.Name == \"Test\";");
double match = matcher.IsMatch(input); double match = matcher.IsMatch(input);
// Assert // Assert
Assert.Equal(1.0, match); Assert.Equal(1.0, match);
} }
[Fact] [Fact]
public void CSharpCodeMatcher_GetName() public void CSharpCodeMatcher_GetName()
{ {
// Assign // Assign
var matcher = new CSharpCodeMatcher("x"); var matcher = new CSharpCodeMatcher("x");
// Act // Act
string name = matcher.Name; string name = matcher.Name;
// Assert // Assert
Check.That(name).Equals("CSharpCodeMatcher"); Check.That(name).Equals("CSharpCodeMatcher");
} }
[Fact] [Fact]
public void CSharpCodeMatcher_GetPatterns() public void CSharpCodeMatcher_GetPatterns()
{ {
// Assign // Assign
var matcher = new CSharpCodeMatcher("x"); var matcher = new CSharpCodeMatcher("x");
// Act // Act
string[] patterns = matcher.GetPatterns(); string[] patterns = matcher.GetPatterns();
// Assert // Assert
Check.That(patterns).ContainsExactly("x"); Check.That(patterns).ContainsExactly("x");
} }
} }
} }

View File

@@ -1,113 +1,113 @@
using NFluent; using NFluent;
using WireMock.Matchers; using WireMock.Matchers;
using Xunit; using Xunit;
namespace WireMock.Net.Tests.Matchers namespace WireMock.Net.Tests.Matchers
{ {
public class ExactMatcherTests public class ExactMatcherTests
{ {
[Fact] [Fact]
public void ExactMatcher_GetName() public void ExactMatcher_GetName()
{ {
// Assign // Assign
var matcher = new ExactMatcher("X"); var matcher = new ExactMatcher("X");
// Act // Act
string name = matcher.Name; string name = matcher.Name;
// Assert // Assert
Check.That(name).Equals("ExactMatcher"); Check.That(name).Equals("ExactMatcher");
} }
[Fact] [Fact]
public void ExactMatcher_GetPatterns() public void ExactMatcher_GetPatterns()
{ {
// Assign // Assign
var matcher = new ExactMatcher("X"); var matcher = new ExactMatcher("X");
// Act // Act
string[] patterns = matcher.GetPatterns(); string[] patterns = matcher.GetPatterns();
// Assert // Assert
Check.That(patterns).ContainsExactly("X"); Check.That(patterns).ContainsExactly("X");
} }
[Fact] [Fact]
public void ExactMatcher_IsMatch_WithSinglePattern_ReturnsMatch1_0() public void ExactMatcher_IsMatch_WithSinglePattern_ReturnsMatch1_0()
{ {
// Assign // Assign
var matcher = new ExactMatcher("x"); var matcher = new ExactMatcher("x");
// Act // Act
double result = matcher.IsMatch("x"); double result = matcher.IsMatch("x");
// Assert // Assert
Check.That(result).IsEqualTo(1.0); Check.That(result).IsEqualTo(1.0);
} }
[Fact] [Fact]
public void ExactMatcher_IsMatch_WithSinglePattern_ReturnsMatch0_0() public void ExactMatcher_IsMatch_WithSinglePattern_ReturnsMatch0_0()
{ {
// Assign // Assign
var matcher = new ExactMatcher("x"); var matcher = new ExactMatcher("x");
// Act // Act
double result = matcher.IsMatch("y"); double result = matcher.IsMatch("y");
// Assert // Assert
Check.That(result).IsEqualTo(0.0); Check.That(result).IsEqualTo(0.0);
} }
[Fact] [Fact]
public void ExactMatcher_IsMatch_WithMultiplePatterns_ReturnsMatch0_5() public void ExactMatcher_IsMatch_WithMultiplePatterns_ReturnsMatch0_5()
{ {
// Assign // Assign
var matcher = new ExactMatcher("x", "y"); var matcher = new ExactMatcher("x", "y");
// Act // Act
double result = matcher.IsMatch("x"); double result = matcher.IsMatch("x");
// Assert // Assert
Check.That(result).IsEqualTo(1.0); Check.That(result).IsEqualTo(1.0);
} }
[Fact] [Fact]
public void ExactMatcher_IsMatch_SinglePattern() public void ExactMatcher_IsMatch_SinglePattern()
{ {
// Assign // Assign
var matcher = new ExactMatcher("cat"); var matcher = new ExactMatcher("cat");
// Act // Act
double result = matcher.IsMatch("caR"); double result = matcher.IsMatch("caR");
// Assert // Assert
Check.That(result).IsEqualTo(0.0); Check.That(result).IsEqualTo(0.0);
} }
[Fact] [Fact]
public void ExactMatcher_IsMatch_SinglePattern_AcceptOnMatch() public void ExactMatcher_IsMatch_SinglePattern_AcceptOnMatch()
{ {
// Assign // Assign
var matcher = new ExactMatcher(MatchBehaviour.AcceptOnMatch, "cat"); var matcher = new ExactMatcher(MatchBehaviour.AcceptOnMatch, false, "cat");
// Act // Act
double result = matcher.IsMatch("cat"); double result = matcher.IsMatch("cat");
// Assert // Assert
Check.That(result).IsEqualTo(1.0); Check.That(result).IsEqualTo(1.0);
} }
[Fact] [Fact]
public void ExactMatcher_IsMatch_SinglePattern_RejectOnMatch() public void ExactMatcher_IsMatch_SinglePattern_RejectOnMatch()
{ {
// Assign // Assign
var matcher = new ExactMatcher(MatchBehaviour.RejectOnMatch, "cat"); var matcher = new ExactMatcher(MatchBehaviour.RejectOnMatch, false, "cat");
// Act // Act
double result = matcher.IsMatch("cat"); double result = matcher.IsMatch("cat");
// Assert // Assert
Check.That(result).IsEqualTo(0.0); Check.That(result).IsEqualTo(0.0);
} }
} }
} }

View File

@@ -1,166 +1,166 @@
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using NFluent; using NFluent;
using WireMock.Matchers; using WireMock.Matchers;
using Xunit; using Xunit;
namespace WireMock.Net.Tests.Matchers namespace WireMock.Net.Tests.Matchers
{ {
public class JmesPathMatcherTests public class JmesPathMatcherTests
{ {
[Fact] [Fact]
public void JmesPathMatcher_GetName() public void JmesPathMatcher_GetName()
{ {
// Assign // Assign
var matcher = new JmesPathMatcher("X"); var matcher = new JmesPathMatcher("X");
// Act // Act
string name = matcher.Name; string name = matcher.Name;
// Assert // Assert
Check.That(name).Equals("JmesPathMatcher"); Check.That(name).Equals("JmesPathMatcher");
} }
[Fact] [Fact]
public void JmesPathMatcher_GetPatterns() public void JmesPathMatcher_GetPatterns()
{ {
// Assign // Assign
var matcher = new JmesPathMatcher("X"); var matcher = new JmesPathMatcher("X");
// Act // Act
string[] patterns = matcher.GetPatterns(); string[] patterns = matcher.GetPatterns();
// Assert // Assert
Check.That(patterns).ContainsExactly("X"); Check.That(patterns).ContainsExactly("X");
} }
[Fact] [Fact]
public void JmesPathMatcher_IsMatch_ByteArray() public void JmesPathMatcher_IsMatch_ByteArray()
{ {
// Assign // Assign
var bytes = new byte[0]; var bytes = new byte[0];
var matcher = new JmesPathMatcher(""); var matcher = new JmesPathMatcher("");
// Act // Act
double match = matcher.IsMatch(bytes); double match = matcher.IsMatch(bytes);
// Assert // Assert
Check.That(match).IsEqualTo(0); Check.That(match).IsEqualTo(0);
} }
[Fact] [Fact]
public void JmesPathMatcher_IsMatch_NullString() public void JmesPathMatcher_IsMatch_NullString()
{ {
// Assign // Assign
string s = null; string s = null;
var matcher = new JmesPathMatcher(""); var matcher = new JmesPathMatcher("");
// Act // Act
double match = matcher.IsMatch(s); double match = matcher.IsMatch(s);
// Assert // Assert
Check.That(match).IsEqualTo(0); Check.That(match).IsEqualTo(0);
} }
[Fact] [Fact]
public void JmesPathMatcher_IsMatch_NullObject() public void JmesPathMatcher_IsMatch_NullObject()
{ {
// Assign // Assign
object o = null; object o = null;
var matcher = new JmesPathMatcher(""); var matcher = new JmesPathMatcher("");
// Act // Act
double match = matcher.IsMatch(o); double match = matcher.IsMatch(o);
// Assert // Assert
Check.That(match).IsEqualTo(0); Check.That(match).IsEqualTo(0);
} }
[Fact] [Fact]
public void JmesPathMatcher_IsMatch_String_Exception_Mismatch() public void JmesPathMatcher_IsMatch_String_Exception_Mismatch()
{ {
// Assign // Assign
var matcher = new JmesPathMatcher("xxx"); var matcher = new JmesPathMatcher("xxx");
// Act // Act
double match = matcher.IsMatch(""); double match = matcher.IsMatch("");
// Assert // Assert
Check.That(match).IsEqualTo(0); Check.That(match).IsEqualTo(0);
} }
[Fact] [Fact]
public void JmesPathMatcher_IsMatch_Object_Exception_Mismatch() public void JmesPathMatcher_IsMatch_Object_Exception_Mismatch()
{ {
// Assign // Assign
var matcher = new JmesPathMatcher(""); var matcher = new JmesPathMatcher("");
// Act // Act
double match = matcher.IsMatch("x"); double match = matcher.IsMatch("x");
// Assert // Assert
Check.That(match).IsEqualTo(0); Check.That(match).IsEqualTo(0);
} }
[Fact] [Fact]
public void JmesPathMatcher_IsMatch_AnonymousObject() public void JmesPathMatcher_IsMatch_AnonymousObject()
{ {
// Assign // Assign
var matcher = new JmesPathMatcher("things.name == 'RequiredThing'"); var matcher = new JmesPathMatcher("things.name == 'RequiredThing'");
// Act // Act
double match = matcher.IsMatch(new { things = new { name = "RequiredThing" } }); double match = matcher.IsMatch(new { things = new { name = "RequiredThing" } });
// Assert // Assert
Check.That(match).IsEqualTo(1); Check.That(match).IsEqualTo(1);
} }
[Fact] [Fact]
public void JmesPathMatcher_IsMatch_JObject() public void JmesPathMatcher_IsMatch_JObject()
{ {
// Assign // Assign
string[] patterns = { "things.x == 'RequiredThing'" }; string[] patterns = { "things.x == 'RequiredThing'" };
var matcher = new JmesPathMatcher(patterns); var matcher = new JmesPathMatcher(patterns);
// Act // Act
var sub = new JObject var sub = new JObject
{ {
{ "x", new JValue("RequiredThing") } { "x", new JValue("RequiredThing") }
}; };
var jobject = new JObject var jobject = new JObject
{ {
{ "Id", new JValue(1) }, { "Id", new JValue(1) },
{ "things", sub } { "things", sub }
}; };
double match = matcher.IsMatch(jobject); double match = matcher.IsMatch(jobject);
// Assert // Assert
Check.That(match).IsEqualTo(1); Check.That(match).IsEqualTo(1);
} }
[Fact] [Fact]
public void JmesPathMatcher_IsMatch_JObject_Parsed() public void JmesPathMatcher_IsMatch_JObject_Parsed()
{ {
// Assign // Assign
var matcher = new JmesPathMatcher("things.x == 'RequiredThing'"); var matcher = new JmesPathMatcher("things.x == 'RequiredThing'");
// Act // Act
double match = matcher.IsMatch(JObject.Parse("{ \"things\": { \"x\": \"RequiredThing\" } }")); double match = matcher.IsMatch(JObject.Parse("{ \"things\": { \"x\": \"RequiredThing\" } }"));
// Assert // Assert
Check.That(match).IsEqualTo(1); Check.That(match).IsEqualTo(1);
} }
[Fact] [Fact]
public void JmesPathMatcher_IsMatch_RejectOnMatch() public void JmesPathMatcher_IsMatch_RejectOnMatch()
{ {
// Assign // Assign
var matcher = new JmesPathMatcher(MatchBehaviour.RejectOnMatch, "things.x == 'RequiredThing'"); var matcher = new JmesPathMatcher(MatchBehaviour.RejectOnMatch, false, "things.x == 'RequiredThing'");
// Act // Act
double match = matcher.IsMatch(JObject.Parse("{ \"things\": { \"x\": \"RequiredThing\" } }")); double match = matcher.IsMatch(JObject.Parse("{ \"things\": { \"x\": \"RequiredThing\" } }"));
// Assert // Assert
Check.That(match).IsEqualTo(0.0); Check.That(match).IsEqualTo(0.0);
} }
} }
} }

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 NFluent;
using WireMock.Matchers; using WireMock.Matchers;
using Xunit; using Xunit;
@@ -33,6 +37,52 @@ namespace WireMock.Net.Tests.Matchers
Check.That(value).Equals("{}"); 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] [Fact]
public void JsonMatcher_IsMatch_ByteArray() public void JsonMatcher_IsMatch_ByteArray()
{ {

View File

@@ -1,162 +1,162 @@
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using NFluent; using NFluent;
using WireMock.Matchers; using WireMock.Matchers;
using Xunit; using Xunit;
namespace WireMock.Net.Tests.Matchers namespace WireMock.Net.Tests.Matchers
{ {
public class JsonPathMatcherTests public class JsonPathMatcherTests
{ {
[Fact] [Fact]
public void JsonPathMatcher_GetName() public void JsonPathMatcher_GetName()
{ {
// Assign // Assign
var matcher = new JsonPathMatcher("X"); var matcher = new JsonPathMatcher("X");
// Act // Act
string name = matcher.Name; string name = matcher.Name;
// Assert // Assert
Check.That(name).Equals("JsonPathMatcher"); Check.That(name).Equals("JsonPathMatcher");
} }
[Fact] [Fact]
public void JsonPathMatcher_GetPatterns() public void JsonPathMatcher_GetPatterns()
{ {
// Assign // Assign
var matcher = new JsonPathMatcher("X"); var matcher = new JsonPathMatcher("X");
// Act // Act
string[] patterns = matcher.GetPatterns(); string[] patterns = matcher.GetPatterns();
// Assert // Assert
Check.That(patterns).ContainsExactly("X"); Check.That(patterns).ContainsExactly("X");
} }
[Fact] [Fact]
public void JsonPathMatcher_IsMatch_ByteArray() public void JsonPathMatcher_IsMatch_ByteArray()
{ {
// Assign // Assign
var bytes = new byte[0]; var bytes = new byte[0];
var matcher = new JsonPathMatcher(""); var matcher = new JsonPathMatcher("");
// Act // Act
double match = matcher.IsMatch(bytes); double match = matcher.IsMatch(bytes);
// Assert // Assert
Check.That(match).IsEqualTo(0); Check.That(match).IsEqualTo(0);
} }
[Fact] [Fact]
public void JsonPathMatcher_IsMatch_NullString() public void JsonPathMatcher_IsMatch_NullString()
{ {
// Assign // Assign
string s = null; string s = null;
var matcher = new JsonPathMatcher(""); var matcher = new JsonPathMatcher("");
// Act // Act
double match = matcher.IsMatch(s); double match = matcher.IsMatch(s);
// Assert // Assert
Check.That(match).IsEqualTo(0); Check.That(match).IsEqualTo(0);
} }
[Fact] [Fact]
public void JsonPathMatcher_IsMatch_NullObject() public void JsonPathMatcher_IsMatch_NullObject()
{ {
// Assign // Assign
object o = null; object o = null;
var matcher = new JsonPathMatcher(""); var matcher = new JsonPathMatcher("");
// Act // Act
double match = matcher.IsMatch(o); double match = matcher.IsMatch(o);
// Assert // Assert
Check.That(match).IsEqualTo(0); Check.That(match).IsEqualTo(0);
} }
[Fact] [Fact]
public void JsonPathMatcher_IsMatch_String_Exception_Mismatch() public void JsonPathMatcher_IsMatch_String_Exception_Mismatch()
{ {
// Assign // Assign
var matcher = new JsonPathMatcher("xxx"); var matcher = new JsonPathMatcher("xxx");
// Act // Act
double match = matcher.IsMatch(""); double match = matcher.IsMatch("");
// Assert // Assert
Check.That(match).IsEqualTo(0); Check.That(match).IsEqualTo(0);
} }
[Fact] [Fact]
public void JsonPathMatcher_IsMatch_Object_Exception_Mismatch() public void JsonPathMatcher_IsMatch_Object_Exception_Mismatch()
{ {
// Assign // Assign
var matcher = new JsonPathMatcher(""); var matcher = new JsonPathMatcher("");
// Act // Act
double match = matcher.IsMatch("x"); double match = matcher.IsMatch("x");
// Assert // Assert
Check.That(match).IsEqualTo(0); Check.That(match).IsEqualTo(0);
} }
[Fact] [Fact]
public void JsonPathMatcher_IsMatch_AnonymousObject() public void JsonPathMatcher_IsMatch_AnonymousObject()
{ {
// Assign // Assign
var matcher = new JsonPathMatcher("$..[?(@.Id == 1)]"); var matcher = new JsonPathMatcher("$..[?(@.Id == 1)]");
// Act // Act
double match = matcher.IsMatch(new { Id = 1, Name = "Test" }); double match = matcher.IsMatch(new { Id = 1, Name = "Test" });
// Assert // Assert
Check.That(match).IsEqualTo(1); Check.That(match).IsEqualTo(1);
} }
[Fact] [Fact]
public void JsonPathMatcher_IsMatch_JObject() public void JsonPathMatcher_IsMatch_JObject()
{ {
// Assign // Assign
string[] patterns = { "$..[?(@.Id == 1)]" }; string[] patterns = { "$..[?(@.Id == 1)]" };
var matcher = new JsonPathMatcher(patterns); var matcher = new JsonPathMatcher(patterns);
// Act // Act
var jobject = new JObject var jobject = new JObject
{ {
{ "Id", new JValue(1) }, { "Id", new JValue(1) },
{ "Name", new JValue("Test") } { "Name", new JValue("Test") }
}; };
double match = matcher.IsMatch(jobject); double match = matcher.IsMatch(jobject);
// Assert // Assert
Check.That(match).IsEqualTo(1); Check.That(match).IsEqualTo(1);
} }
[Fact] [Fact]
public void JsonPathMatcher_IsMatch_JObject_Parsed() public void JsonPathMatcher_IsMatch_JObject_Parsed()
{ {
// Assign // Assign
var matcher = new JsonPathMatcher("$..[?(@.Id == 1)]"); var matcher = new JsonPathMatcher("$..[?(@.Id == 1)]");
// Act // Act
double match = matcher.IsMatch(JObject.Parse("{\"Id\":1,\"Name\":\"Test\"}")); double match = matcher.IsMatch(JObject.Parse("{\"Id\":1,\"Name\":\"Test\"}"));
// Assert // Assert
Check.That(match).IsEqualTo(1); Check.That(match).IsEqualTo(1);
} }
[Fact] [Fact]
public void JsonPathMatcher_IsMatch_RejectOnMatch() public void JsonPathMatcher_IsMatch_RejectOnMatch()
{ {
// Assign // Assign
var matcher = new JsonPathMatcher(MatchBehaviour.RejectOnMatch, "$..[?(@.Id == 1)]"); var matcher = new JsonPathMatcher(MatchBehaviour.RejectOnMatch, false, "$..[?(@.Id == 1)]");
// Act // Act
double match = matcher.IsMatch(JObject.Parse("{\"Id\":1,\"Name\":\"Test\"}")); double match = matcher.IsMatch(JObject.Parse("{\"Id\":1,\"Name\":\"Test\"}"));
// Assert // Assert
Check.That(match).IsEqualTo(0.0); Check.That(match).IsEqualTo(0.0);
} }
} }
} }

View File

@@ -1,69 +1,69 @@
using NFluent; using NFluent;
using WireMock.Matchers; using WireMock.Matchers;
using Xunit; using Xunit;
namespace WireMock.Net.Tests.Matchers namespace WireMock.Net.Tests.Matchers
{ {
public class XPathMatcherTests public class XPathMatcherTests
{ {
[Fact] [Fact]
public void XPathMatcher_GetName() public void XPathMatcher_GetName()
{ {
// Assign // Assign
var matcher = new XPathMatcher("X"); var matcher = new XPathMatcher("X");
// Act // Act
string name = matcher.Name; string name = matcher.Name;
// Assert // Assert
Check.That(name).Equals("XPathMatcher"); Check.That(name).Equals("XPathMatcher");
} }
[Fact] [Fact]
public void XPathMatcher_GetPatterns() public void XPathMatcher_GetPatterns()
{ {
// Assign // Assign
var matcher = new XPathMatcher("X"); var matcher = new XPathMatcher("X");
// Act // Act
string[] patterns = matcher.GetPatterns(); string[] patterns = matcher.GetPatterns();
// Assert // Assert
Check.That(patterns).ContainsExactly("X"); Check.That(patterns).ContainsExactly("X");
} }
[Fact] [Fact]
public void XPathMatcher_IsMatch_AcceptOnMatch() public void XPathMatcher_IsMatch_AcceptOnMatch()
{ {
// Assign // Assign
string xml = @" string xml = @"
<todo-list> <todo-list>
<todo-item id='a1'>abc</todo-item> <todo-item id='a1'>abc</todo-item>
</todo-list>"; </todo-list>";
var matcher = new XPathMatcher("/todo-list[count(todo-item) = 1]"); var matcher = new XPathMatcher("/todo-list[count(todo-item) = 1]");
// Act // Act
double result = matcher.IsMatch(xml); double result = matcher.IsMatch(xml);
// Assert // Assert
Check.That(result).IsEqualTo(1.0); Check.That(result).IsEqualTo(1.0);
} }
[Fact] [Fact]
public void XPathMatcher_IsMatch_RejectOnMatch() public void XPathMatcher_IsMatch_RejectOnMatch()
{ {
// Assign // Assign
string xml = @" string xml = @"
<todo-list> <todo-list>
<todo-item id='a1'>abc</todo-item> <todo-item id='a1'>abc</todo-item>
</todo-list>"; </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 // Act
double result = matcher.IsMatch(xml); double result = matcher.IsMatch(xml);
// Assert // Assert
Check.That(result).IsEqualTo(0.0); Check.That(result).IsEqualTo(0.0);
} }
} }
} }

View File

@@ -1,4 +1,5 @@
using System; using System;
using FluentAssertions;
using NFluent; using NFluent;
using WireMock.Admin.Mappings; using WireMock.Admin.Mappings;
using WireMock.Matchers; using WireMock.Matchers;
@@ -43,7 +44,8 @@ namespace WireMock.Net.Tests.Serialization
var matcher = (ExactMatcher)_sut.Map(model); var matcher = (ExactMatcher)_sut.Map(model);
// Assert // Assert
Check.That(matcher.GetPatterns()).ContainsExactly("x"); matcher.GetPatterns().Should().ContainSingle("x");
matcher.ThrowException.Should().BeFalse();
} }
[Fact] [Fact]
@@ -63,6 +65,39 @@ namespace WireMock.Net.Tests.Serialization
Check.That(matcher.GetPatterns()).ContainsExactly("x", "y"); 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] [Fact]
public void MatcherModelMapper_Map_ExactObjectMatcher_ValidBase64StringPattern() public void MatcherModelMapper_Map_ExactObjectMatcher_ValidBase64StringPattern()
{ {