From 7c07f4387061e874ffbf11f856b40f1c127e99de Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Tue, 20 Feb 2018 21:53:32 +0100 Subject: [PATCH 1/3] Fixes for JsonPath --- src/WireMock.Net/Matchers/ExactMatcher.cs | 20 +--- .../Matchers/ExactObjectMatcher.cs | 34 ++++++ src/WireMock.Net/Matchers/IMatcher.cs | 13 --- src/WireMock.Net/Matchers/IObjectMatcher.cs | 15 +++ src/WireMock.Net/Matchers/IStringMatcher.cs | 21 ++++ src/WireMock.Net/Matchers/JSONPathMatcher.cs | 48 ++++++--- src/WireMock.Net/Matchers/RegexMatcher.cs | 26 ++--- .../Request/RequestMessageBodyMatcher.cs | 101 +++++++++++------- .../Request/RequestMessageClientIPMatcher.cs | 6 +- .../Request/RequestMessageCookieMatcher.cs | 14 ++- .../Request/RequestMessageHeaderMatcher.cs | 16 ++- .../Request/RequestMessagePathMatcher.cs | 10 +- .../Request/RequestMessageUrlMatcher.cs | 10 +- .../Matchers/SimMetricsMatcher.cs | 20 +--- src/WireMock.Net/Matchers/WildcardMatcher.cs | 14 +-- src/WireMock.Net/Matchers/XPathMatcher.cs | 22 ++-- .../Owin/WireMockMiddlewareOptions.cs | 2 +- .../IClientIPRequestBuilder.cs | 2 +- .../IHeadersAndCookiesRequestBuilder.cs | 4 +- .../IUrlAndPathRequestBuilder.cs | 4 +- src/WireMock.Net/RequestBuilders/Request.cs | 10 +- .../Serialization/MappingConverter.cs | 5 +- .../Server/FluentMockServer.Admin.cs | 10 +- .../RequestWithBodyTests.cs | 23 ++++ .../StatefulBehaviorTests.cs | 8 +- 25 files changed, 283 insertions(+), 175 deletions(-) create mode 100644 src/WireMock.Net/Matchers/ExactObjectMatcher.cs create mode 100644 src/WireMock.Net/Matchers/IObjectMatcher.cs create mode 100644 src/WireMock.Net/Matchers/IStringMatcher.cs diff --git a/src/WireMock.Net/Matchers/ExactMatcher.cs b/src/WireMock.Net/Matchers/ExactMatcher.cs index fb5354e4e..5923140e2 100644 --- a/src/WireMock.Net/Matchers/ExactMatcher.cs +++ b/src/WireMock.Net/Matchers/ExactMatcher.cs @@ -7,8 +7,8 @@ namespace WireMock.Matchers /// /// ExactMatcher /// - /// - public class ExactMatcher : IMatcher + /// + public class ExactMatcher : IStringMatcher { private readonly string[] _values; @@ -23,29 +23,19 @@ public ExactMatcher([NotNull] params string[] values) _values = values; } - /// - /// Determines whether the specified input is match. - /// - /// The input. - /// A value between 0.0 - 1.0 of the similarity. + /// public double IsMatch(string input) { return MatchScores.ToScore(_values.Select(value => value.Equals(input))); } - /// - /// Gets the value. - /// - /// Patterns + /// public string[] GetPatterns() { return _values; } - /// - /// Gets the name. - /// - /// Name + /// public string GetName() { return "ExactMatcher"; diff --git a/src/WireMock.Net/Matchers/ExactObjectMatcher.cs b/src/WireMock.Net/Matchers/ExactObjectMatcher.cs new file mode 100644 index 000000000..f7cb66352 --- /dev/null +++ b/src/WireMock.Net/Matchers/ExactObjectMatcher.cs @@ -0,0 +1,34 @@ +using JetBrains.Annotations; + +namespace WireMock.Matchers +{ + /// + /// ExactMatcher + /// + /// + public class ExactObjectMatcher : IObjectMatcher + { + private readonly object _value; + + /// + /// Initializes a new instance of the class. + /// + /// The value. + public ExactObjectMatcher([NotNull] object value) + { + _value = value; + } + + /// + public double IsMatch(object input) + { + return MatchScores.ToScore(Equals(_value, input)); + } + + /// + public string GetName() + { + return "ExactObjectMatcher"; + } + } +} \ No newline at end of file diff --git a/src/WireMock.Net/Matchers/IMatcher.cs b/src/WireMock.Net/Matchers/IMatcher.cs index 4bcd2cff6..7462c1554 100644 --- a/src/WireMock.Net/Matchers/IMatcher.cs +++ b/src/WireMock.Net/Matchers/IMatcher.cs @@ -5,19 +5,6 @@ /// public interface IMatcher { - /// - /// Determines whether the specified input is match. - /// - /// The input. - /// A value between 0.0 - 1.0 of the similarity. - double IsMatch(string input); - - /// - /// Gets the patterns. - /// - /// Patterns - string[] GetPatterns(); - /// /// Gets the name. /// diff --git a/src/WireMock.Net/Matchers/IObjectMatcher.cs b/src/WireMock.Net/Matchers/IObjectMatcher.cs new file mode 100644 index 000000000..883e246d9 --- /dev/null +++ b/src/WireMock.Net/Matchers/IObjectMatcher.cs @@ -0,0 +1,15 @@ +namespace WireMock.Matchers +{ + /// + /// IObjectMatcher + /// + public interface IObjectMatcher : IMatcher + { + /// + /// Determines whether the specified input is match. + /// + /// The input. + /// A value between 0.0 - 1.0 of the similarity. + double IsMatch(object input); + } +} \ No newline at end of file diff --git a/src/WireMock.Net/Matchers/IStringMatcher.cs b/src/WireMock.Net/Matchers/IStringMatcher.cs new file mode 100644 index 000000000..7d1ab3fdb --- /dev/null +++ b/src/WireMock.Net/Matchers/IStringMatcher.cs @@ -0,0 +1,21 @@ +namespace WireMock.Matchers +{ + /// + /// IStringMatcher + /// + public interface IStringMatcher : IMatcher + { + /// + /// Determines whether the specified input is match. + /// + /// The input. + /// A value between 0.0 - 1.0 of the similarity. + double IsMatch(string input); + + /// + /// Gets the patterns. + /// + /// Patterns + string[] GetPatterns(); + } +} \ No newline at end of file diff --git a/src/WireMock.Net/Matchers/JSONPathMatcher.cs b/src/WireMock.Net/Matchers/JSONPathMatcher.cs index c92b01890..aab0b86cc 100644 --- a/src/WireMock.Net/Matchers/JSONPathMatcher.cs +++ b/src/WireMock.Net/Matchers/JSONPathMatcher.cs @@ -10,8 +10,9 @@ namespace WireMock.Matchers /// JSONPathMatcher /// /// - public class JsonPathMatcher : IMatcher + public class JsonPathMatcher : IStringMatcher, IObjectMatcher { + // private readonly object _jsonPattern; private readonly string[] _patterns; /// @@ -25,15 +26,20 @@ public JsonPathMatcher([NotNull] params string[] patterns) _patterns = patterns; } - /// - /// Determines whether the specified input is match. - /// - /// The input string - /// A value between 0.0 - 1.0 of the similarity. + //public JsonPathMatcher([NotNull] object jsonPattern) + //{ + // Check.NotNull(jsonPattern, nameof(jsonPattern)); + + // _jsonPattern = jsonPattern; + //} + + /// public double IsMatch(string input) { if (input == null) + { return MatchScores.Mismatch; + } try { @@ -47,19 +53,33 @@ public double IsMatch(string input) } } - /// - /// Gets the patterns. - /// - /// Pattern + /// + public double IsMatch(object input) + { + if (input == null) + { + return MatchScores.Mismatch; + } + + try + { + var o = input as JObject ?? JObject.FromObject(input); + + return MatchScores.ToScore(_patterns.Select(p => o.SelectToken(p) != null)); + } + catch (Exception) + { + return MatchScores.Mismatch; + } + } + + /// public string[] GetPatterns() { return _patterns; } - /// - /// Gets the name. - /// - /// Name + /// public string GetName() { return "JsonPathMatcher"; diff --git a/src/WireMock.Net/Matchers/RegexMatcher.cs b/src/WireMock.Net/Matchers/RegexMatcher.cs index 918f0e9a2..004c69d92 100644 --- a/src/WireMock.Net/Matchers/RegexMatcher.cs +++ b/src/WireMock.Net/Matchers/RegexMatcher.cs @@ -9,8 +9,8 @@ namespace WireMock.Matchers /// /// Regular Expression Matcher /// - /// - public class RegexMatcher : IMatcher + /// + public class RegexMatcher : IStringMatcher { private readonly string[] _patterns; private readonly Regex[] _expressions; @@ -37,20 +37,20 @@ public RegexMatcher([NotNull, RegexPattern] string[] patterns, bool ignoreCase = RegexOptions options = RegexOptions.Compiled; if (ignoreCase) + { options |= RegexOptions.IgnoreCase; + } _expressions = patterns.Select(p => new Regex(p, options)).ToArray(); } - /// - /// Determines whether the specified input is match. - /// - /// The input string - /// A value between 0.0 - 1.0 of the similarity. + /// public double IsMatch(string input) { if (input == null) + { return MatchScores.Mismatch; + } try { @@ -62,21 +62,13 @@ public double IsMatch(string input) } } - /// - /// Gets the patterns. - /// - /// Pattern + /// public virtual string[] GetPatterns() { return _patterns; } - /// - /// Gets the name. - /// - /// - /// Name - /// + /// public virtual string GetName() { return "RegexMatcher"; diff --git a/src/WireMock.Net/Matchers/Request/RequestMessageBodyMatcher.cs b/src/WireMock.Net/Matchers/Request/RequestMessageBodyMatcher.cs index 2e0891b45..427510e3c 100644 --- a/src/WireMock.Net/Matchers/Request/RequestMessageBodyMatcher.cs +++ b/src/WireMock.Net/Matchers/Request/RequestMessageBodyMatcher.cs @@ -9,21 +9,21 @@ namespace WireMock.Matchers.Request /// public class RequestMessageBodyMatcher : IRequestMatcher { - /// - /// The body as byte[]. - /// - private readonly byte[] _bodyData; - /// /// The body function /// public Func Func { get; } /// - /// The body data function + /// The body data function for byte[] /// public Func DataFunc { get; } + /// + /// The body data function for json + /// + public Func JsonFunc { get; } + /// /// The matcher. /// @@ -32,9 +32,7 @@ public class RequestMessageBodyMatcher : IRequestMatcher /// /// Initializes a new instance of the class. /// - /// - /// The body Regex pattern. - /// + /// The body. public RequestMessageBodyMatcher([NotNull] string body) : this(new SimMetricsMatcher(body)) { } @@ -42,21 +40,23 @@ public RequestMessageBodyMatcher([NotNull] string body) : this(new SimMetricsMat /// /// Initializes a new instance of the class. /// - /// - /// The body Regex pattern. - /// - public RequestMessageBodyMatcher([NotNull] byte[] body) + /// The body. + public RequestMessageBodyMatcher([NotNull] byte[] body) : this(new ExactObjectMatcher(body)) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The body. + public RequestMessageBodyMatcher([NotNull] object body) : this(new ExactObjectMatcher(body)) { - Check.NotNull(body, nameof(body)); - _bodyData = body; } /// /// Initializes a new instance of the class. /// - /// - /// The body func. - /// + /// The function. public RequestMessageBodyMatcher([NotNull] Func func) { Check.NotNull(func, nameof(func)); @@ -66,9 +66,7 @@ public RequestMessageBodyMatcher([NotNull] Func func) /// /// Initializes a new instance of the class. /// - /// - /// The body func. - /// + /// The function. public RequestMessageBodyMatcher([NotNull] Func func) { Check.NotNull(func, nameof(func)); @@ -78,23 +76,24 @@ public RequestMessageBodyMatcher([NotNull] Func func) /// /// Initializes a new instance of the class. /// - /// - /// The body matcher. - /// + /// The function. + public RequestMessageBodyMatcher([NotNull] Func func) + { + Check.NotNull(func, nameof(func)); + JsonFunc = func; + } + + /// + /// Initializes a new instance of the class. + /// + /// The matcher. public RequestMessageBodyMatcher([NotNull] IMatcher matcher) { Check.NotNull(matcher, nameof(matcher)); Matcher = matcher; } - /// - /// Determines whether the specified RequestMessage is match. - /// - /// The RequestMessage. - /// The RequestMatchResult. - /// - /// A value between 0.0 - 1.0 of the similarity. - /// + /// public double GetMatchingScore(RequestMessage requestMessage, RequestMatchResult requestMatchResult) { double score = IsMatch(requestMessage); @@ -103,17 +102,43 @@ public double GetMatchingScore(RequestMessage requestMessage, RequestMatchResult private double IsMatch(RequestMessage requestMessage) { - if (Matcher != null) - return Matcher.IsMatch(requestMessage.Body); + if (requestMessage.Body != null) + { + var stringMatcher = Matcher as IStringMatcher; + if (stringMatcher != null) + { + return stringMatcher.IsMatch(requestMessage.Body); + } + } - if (_bodyData != null) - return MatchScores.ToScore(requestMessage.BodyAsBytes == _bodyData); + var objectMatcher = Matcher as IObjectMatcher; + if (objectMatcher != null) + { + if (requestMessage.BodyAsJson != null) + { + return objectMatcher.IsMatch(requestMessage.BodyAsJson); + } + + if (requestMessage.BodyAsBytes != null) + { + return objectMatcher.IsMatch(requestMessage.BodyAsBytes); + } + } if (Func != null) - return MatchScores.ToScore(requestMessage.Body != null && Func(requestMessage.Body)); + { + return MatchScores.ToScore(Func(requestMessage.Body)); + } - if (DataFunc != null && requestMessage.BodyAsBytes != null) + if (DataFunc != null) + { return MatchScores.ToScore(requestMessage.BodyAsBytes != null && DataFunc(requestMessage.BodyAsBytes)); + } + + if (JsonFunc != null) + { + return MatchScores.ToScore(requestMessage.BodyAsJson != null && JsonFunc(requestMessage.BodyAsJson)); + } return MatchScores.Mismatch; } diff --git a/src/WireMock.Net/Matchers/Request/RequestMessageClientIPMatcher.cs b/src/WireMock.Net/Matchers/Request/RequestMessageClientIPMatcher.cs index ddd283cb2..718326b47 100644 --- a/src/WireMock.Net/Matchers/Request/RequestMessageClientIPMatcher.cs +++ b/src/WireMock.Net/Matchers/Request/RequestMessageClientIPMatcher.cs @@ -14,7 +14,7 @@ public class RequestMessageClientIPMatcher : IRequestMatcher /// /// The matchers. /// - public IReadOnlyList Matchers { get; } + public IReadOnlyList Matchers { get; } /// /// The ClientIP functions. @@ -25,7 +25,7 @@ public class RequestMessageClientIPMatcher : IRequestMatcher /// Initializes a new instance of the class. /// /// The clientIPs. - public RequestMessageClientIPMatcher([NotNull] params string[] clientIPs) : this(clientIPs.Select(ip => new WildcardMatcher(ip)).Cast().ToArray()) + public RequestMessageClientIPMatcher([NotNull] params string[] clientIPs) : this(clientIPs.Select(ip => new WildcardMatcher(ip)).Cast().ToArray()) { } @@ -33,7 +33,7 @@ public class RequestMessageClientIPMatcher : IRequestMatcher /// Initializes a new instance of the class. /// /// The matchers. - public RequestMessageClientIPMatcher([NotNull] params IMatcher[] matchers) + public RequestMessageClientIPMatcher([NotNull] params IStringMatcher[] matchers) { Check.NotNull(matchers, nameof(matchers)); Matchers = matchers; diff --git a/src/WireMock.Net/Matchers/Request/RequestMessageCookieMatcher.cs b/src/WireMock.Net/Matchers/Request/RequestMessageCookieMatcher.cs index d814c0546..f2b0b2e9f 100644 --- a/src/WireMock.Net/Matchers/Request/RequestMessageCookieMatcher.cs +++ b/src/WireMock.Net/Matchers/Request/RequestMessageCookieMatcher.cs @@ -24,7 +24,7 @@ public class RequestMessageCookieMatcher : IRequestMatcher /// /// The matchers. /// - public IMatcher[] Matchers { get; } + public IStringMatcher[] Matchers { get; } /// /// Initializes a new instance of the class. @@ -38,7 +38,7 @@ public RequestMessageCookieMatcher([NotNull] string name, [NotNull] string patte Check.NotNull(pattern, nameof(pattern)); Name = name; - Matchers = new IMatcher[] { new WildcardMatcher(pattern, ignoreCase) }; + Matchers = new IStringMatcher[] { new WildcardMatcher(pattern, ignoreCase) }; } /// @@ -46,7 +46,7 @@ public RequestMessageCookieMatcher([NotNull] string name, [NotNull] string patte /// /// The name. /// The matchers. - public RequestMessageCookieMatcher([NotNull] string name, [NotNull] params IMatcher[] matchers) + public RequestMessageCookieMatcher([NotNull] string name, [NotNull] params IStringMatcher[] matchers) { Check.NotNull(name, nameof(name)); Check.NotNull(matchers, nameof(matchers)); @@ -83,16 +83,24 @@ public double GetMatchingScore(RequestMessage requestMessage, RequestMatchResult private double IsMatch(RequestMessage requestMessage) { if (requestMessage.Cookies == null) + { return MatchScores.Mismatch; + } if (Funcs != null) + { return MatchScores.ToScore(Funcs.Any(f => f(requestMessage.Cookies))); + } if (Matchers == null) + { return MatchScores.Mismatch; + } if (!requestMessage.Cookies.ContainsKey(Name)) + { return MatchScores.Mismatch; + } string value = requestMessage.Cookies[Name]; return Matchers.Max(m => m.IsMatch(value)); diff --git a/src/WireMock.Net/Matchers/Request/RequestMessageHeaderMatcher.cs b/src/WireMock.Net/Matchers/Request/RequestMessageHeaderMatcher.cs index 6774168f4..94800509c 100644 --- a/src/WireMock.Net/Matchers/Request/RequestMessageHeaderMatcher.cs +++ b/src/WireMock.Net/Matchers/Request/RequestMessageHeaderMatcher.cs @@ -26,7 +26,7 @@ public class RequestMessageHeaderMatcher : IRequestMatcher /// /// The matchers. /// - public IMatcher[] Matchers { get; } + public IStringMatcher[] Matchers { get; } /// /// Initializes a new instance of the class. @@ -40,7 +40,7 @@ public RequestMessageHeaderMatcher([NotNull] string name, [NotNull] string patte Check.NotNull(pattern, nameof(pattern)); Name = name; - Matchers = new IMatcher[] { new WildcardMatcher(pattern, ignoreCase) }; + Matchers = new IStringMatcher[] { new WildcardMatcher(pattern, ignoreCase) }; } /// @@ -55,7 +55,7 @@ public RequestMessageHeaderMatcher([NotNull] string name, [NotNull] string[] pat Check.NotNull(patterns, nameof(patterns)); Name = name; - Matchers = patterns.Select(pattern => new WildcardMatcher(pattern, ignoreCase)).Cast().ToArray(); + Matchers = patterns.Select(pattern => new WildcardMatcher(pattern, ignoreCase)).Cast().ToArray(); } /// @@ -63,7 +63,7 @@ public RequestMessageHeaderMatcher([NotNull] string name, [NotNull] string[] pat /// /// The name. /// The matchers. - public RequestMessageHeaderMatcher([NotNull] string name, [NotNull] params IMatcher[] matchers) + public RequestMessageHeaderMatcher([NotNull] string name, [NotNull] params IStringMatcher[] matchers) { Check.NotNull(name, nameof(name)); Check.NotNull(matchers, nameof(matchers)); @@ -93,16 +93,24 @@ public double GetMatchingScore(RequestMessage requestMessage, RequestMatchResult private double IsMatch(RequestMessage requestMessage) { if (requestMessage.Headers == null) + { return MatchScores.Mismatch; + } if (Funcs != null) + { return MatchScores.ToScore(Funcs.Any(f => f(requestMessage.Headers.ToDictionary(entry => entry.Key, entry => entry.Value.ToArray())))); + } if (Matchers == null) + { return MatchScores.Mismatch; + } if (!requestMessage.Headers.ContainsKey(Name)) + { return MatchScores.Mismatch; + } WireMockList list = requestMessage.Headers[Name]; return Matchers.Max(m => list.Max(value => m.IsMatch(value))); // TODO : is this correct ? diff --git a/src/WireMock.Net/Matchers/Request/RequestMessagePathMatcher.cs b/src/WireMock.Net/Matchers/Request/RequestMessagePathMatcher.cs index 692916546..cec66a6af 100644 --- a/src/WireMock.Net/Matchers/Request/RequestMessagePathMatcher.cs +++ b/src/WireMock.Net/Matchers/Request/RequestMessagePathMatcher.cs @@ -14,7 +14,7 @@ public class RequestMessagePathMatcher : IRequestMatcher /// /// The matcher. /// - public IReadOnlyList Matchers { get; } + public IReadOnlyList Matchers { get; } /// /// The path functions @@ -25,7 +25,7 @@ public class RequestMessagePathMatcher : IRequestMatcher /// Initializes a new instance of the class. /// /// The paths. - public RequestMessagePathMatcher([NotNull] params string[] paths) : this(paths.Select(path => new WildcardMatcher(path)).Cast().ToArray()) + public RequestMessagePathMatcher([NotNull] params string[] paths) : this(paths.Select(path => new WildcardMatcher(path)).Cast().ToArray()) { } @@ -33,7 +33,7 @@ public class RequestMessagePathMatcher : IRequestMatcher /// Initializes a new instance of the class. /// /// The matchers. - public RequestMessagePathMatcher([NotNull] params IMatcher[] matchers) + public RequestMessagePathMatcher([NotNull] params IStringMatcher[] matchers) { Check.NotNull(matchers, nameof(matchers)); Matchers = matchers; @@ -59,10 +59,14 @@ public double GetMatchingScore(RequestMessage requestMessage, RequestMatchResult private double IsMatch(RequestMessage requestMessage) { if (Matchers != null) + { return Matchers.Max(m => m.IsMatch(requestMessage.Path)); + } if (Funcs != null) + { return MatchScores.ToScore(requestMessage.Path != null && Funcs.Any(func => func(requestMessage.Path))); + } return MatchScores.Mismatch; } diff --git a/src/WireMock.Net/Matchers/Request/RequestMessageUrlMatcher.cs b/src/WireMock.Net/Matchers/Request/RequestMessageUrlMatcher.cs index 46f73cb20..ea256ddcc 100644 --- a/src/WireMock.Net/Matchers/Request/RequestMessageUrlMatcher.cs +++ b/src/WireMock.Net/Matchers/Request/RequestMessageUrlMatcher.cs @@ -14,7 +14,7 @@ public class RequestMessageUrlMatcher : IRequestMatcher /// /// The matchers. /// - public IReadOnlyList Matchers { get; } + public IReadOnlyList Matchers { get; } /// /// The url functions. @@ -25,7 +25,7 @@ public class RequestMessageUrlMatcher : IRequestMatcher /// Initializes a new instance of the class. /// /// The urls. - public RequestMessageUrlMatcher([NotNull] params string[] urls) : this(urls.Select(url => new WildcardMatcher(url)).Cast().ToArray()) + public RequestMessageUrlMatcher([NotNull] params string[] urls) : this(urls.Select(url => new WildcardMatcher(url)).Cast().ToArray()) { } @@ -33,7 +33,7 @@ public class RequestMessageUrlMatcher : IRequestMatcher /// Initializes a new instance of the class. /// /// The matchers. - public RequestMessageUrlMatcher([NotNull] params IMatcher[] matchers) + public RequestMessageUrlMatcher([NotNull] params IStringMatcher[] matchers) { Check.NotNull(matchers, nameof(matchers)); Matchers = matchers; @@ -59,10 +59,14 @@ public double GetMatchingScore(RequestMessage requestMessage, RequestMatchResult private double IsMatch(RequestMessage requestMessage) { if (Matchers != null) + { return Matchers.Max(matcher => matcher.IsMatch(requestMessage.Url)); + } if (Funcs != null) + { return MatchScores.ToScore(requestMessage.Url != null && Funcs.Any(func => func(requestMessage.Url))); + } return MatchScores.Mismatch; } diff --git a/src/WireMock.Net/Matchers/SimMetricsMatcher.cs b/src/WireMock.Net/Matchers/SimMetricsMatcher.cs index 81789f482..13e6ee028 100644 --- a/src/WireMock.Net/Matchers/SimMetricsMatcher.cs +++ b/src/WireMock.Net/Matchers/SimMetricsMatcher.cs @@ -10,8 +10,8 @@ namespace WireMock.Matchers /// /// SimMetricsMatcher /// - /// - public class SimMetricsMatcher : IMatcher + /// + public class SimMetricsMatcher : IStringMatcher { private readonly string[] _patterns; private readonly SimMetricType _simMetricType; @@ -38,11 +38,7 @@ public SimMetricsMatcher([NotNull] string[] patterns, SimMetricType simMetricTyp _simMetricType = simMetricType; } - /// - /// Determines whether the specified input is match. - /// - /// The input string - /// A value between 0.0 - 1.0 of the similarity. + /// public double IsMatch(string input) { IStringMetric m = GetStringMetricType(); @@ -93,19 +89,13 @@ private IStringMetric GetStringMetricType() } } - /// - /// Gets the pattern. - /// - /// Pattern + /// public string[] GetPatterns() { return _patterns; } - /// - /// Gets the name. - /// - /// Name + /// public string GetName() { return $"SimMetricsMatcher.{_simMetricType}"; diff --git a/src/WireMock.Net/Matchers/WildcardMatcher.cs b/src/WireMock.Net/Matchers/WildcardMatcher.cs index 1ecbe6476..caed77eca 100644 --- a/src/WireMock.Net/Matchers/WildcardMatcher.cs +++ b/src/WireMock.Net/Matchers/WildcardMatcher.cs @@ -7,7 +7,7 @@ namespace WireMock.Matchers /// /// WildcardMatcher /// - /// + /// public class WildcardMatcher : RegexMatcher { private readonly string[] _patterns; @@ -31,21 +31,13 @@ public WildcardMatcher([NotNull] string[] patterns, bool ignoreCase = false) : b _patterns = patterns; } - /// - /// Gets the pattern. - /// - /// Pattern + /// public override string[] GetPatterns() { return _patterns; } - /// - /// Gets the name. - /// - /// - /// Name - /// + /// public override string GetName() { return "WildcardMatcher"; diff --git a/src/WireMock.Net/Matchers/XPathMatcher.cs b/src/WireMock.Net/Matchers/XPathMatcher.cs index ddf4c1f36..6586da898 100644 --- a/src/WireMock.Net/Matchers/XPathMatcher.cs +++ b/src/WireMock.Net/Matchers/XPathMatcher.cs @@ -12,8 +12,8 @@ namespace WireMock.Matchers /// /// XPath2Matcher /// - /// - public class XPathMatcher : IMatcher + /// + public class XPathMatcher : IStringMatcher { private readonly string[] _patterns; @@ -28,15 +28,13 @@ public XPathMatcher([NotNull] params string[] patterns) _patterns = patterns; } - /// - /// Determines whether the specified input is match. - /// - /// The input string - /// A value between 0.0 - 1.0 of the similarity. + /// public double IsMatch(string input) { if (input == null) + { return MatchScores.Mismatch; + } try { @@ -53,19 +51,13 @@ public double IsMatch(string input) } } - /// - /// Gets the patterns. - /// - /// Patterns + /// public string[] GetPatterns() { return _patterns; } - /// - /// Gets the name. - /// - /// Name + /// public string GetName() { return "XPathMatcher"; diff --git a/src/WireMock.Net/Owin/WireMockMiddlewareOptions.cs b/src/WireMock.Net/Owin/WireMockMiddlewareOptions.cs index cbf515a44..05c475162 100644 --- a/src/WireMock.Net/Owin/WireMockMiddlewareOptions.cs +++ b/src/WireMock.Net/Owin/WireMockMiddlewareOptions.cs @@ -17,7 +17,7 @@ internal class WireMockMiddlewareOptions { public TimeSpan? RequestProcessingDelay { get; set; } - public IMatcher AuthorizationMatcher { get; set; } + public IStringMatcher AuthorizationMatcher { get; set; } public bool AllowPartialMapping { get; set; } diff --git a/src/WireMock.Net/RequestBuilders/IClientIPRequestBuilder.cs b/src/WireMock.Net/RequestBuilders/IClientIPRequestBuilder.cs index c3257f843..a830ba68a 100644 --- a/src/WireMock.Net/RequestBuilders/IClientIPRequestBuilder.cs +++ b/src/WireMock.Net/RequestBuilders/IClientIPRequestBuilder.cs @@ -14,7 +14,7 @@ public interface IClientIPRequestBuilder : IUrlAndPathRequestBuilder /// /// The matchers. /// The . - IRequestBuilder WithClientIP([NotNull] params IMatcher[] matchers); + IRequestBuilder WithClientIP([NotNull] params IStringMatcher[] matchers); /// /// The with ClientIP. diff --git a/src/WireMock.Net/RequestBuilders/IHeadersAndCookiesRequestBuilder.cs b/src/WireMock.Net/RequestBuilders/IHeadersAndCookiesRequestBuilder.cs index 55657aed2..78b210eda 100644 --- a/src/WireMock.Net/RequestBuilders/IHeadersAndCookiesRequestBuilder.cs +++ b/src/WireMock.Net/RequestBuilders/IHeadersAndCookiesRequestBuilder.cs @@ -35,7 +35,7 @@ public interface IHeadersAndCookiesRequestBuilder : IBodyRequestBuilder, IReques /// The name. /// The matchers. /// The . - IRequestBuilder WithHeader([NotNull] string name, [NotNull] params IMatcher[] matchers); + IRequestBuilder WithHeader([NotNull] string name, [NotNull] params IStringMatcher[] matchers); /// /// The with header. @@ -59,7 +59,7 @@ public interface IHeadersAndCookiesRequestBuilder : IBodyRequestBuilder, IReques /// The name. /// The matchers. /// The . - IRequestBuilder WithCookie([NotNull] string name, [NotNull] params IMatcher[] matchers); + IRequestBuilder WithCookie([NotNull] string name, [NotNull] params IStringMatcher[] matchers); /// /// The with cookie. diff --git a/src/WireMock.Net/RequestBuilders/IUrlAndPathRequestBuilder.cs b/src/WireMock.Net/RequestBuilders/IUrlAndPathRequestBuilder.cs index 1751b1a7f..1f760fa37 100644 --- a/src/WireMock.Net/RequestBuilders/IUrlAndPathRequestBuilder.cs +++ b/src/WireMock.Net/RequestBuilders/IUrlAndPathRequestBuilder.cs @@ -14,7 +14,7 @@ public interface IUrlAndPathRequestBuilder : IMethodRequestBuilder /// /// The matchers. /// The . - IRequestBuilder WithPath([NotNull] params IMatcher[] matchers); + IRequestBuilder WithPath([NotNull] params IStringMatcher[] matchers); /// /// The with path. @@ -35,7 +35,7 @@ public interface IUrlAndPathRequestBuilder : IMethodRequestBuilder /// /// The matchers. /// The . - IRequestBuilder WithUrl([NotNull] params IMatcher[] matchers); + IRequestBuilder WithUrl([NotNull] params IStringMatcher[] matchers); /// /// The with url. diff --git a/src/WireMock.Net/RequestBuilders/Request.cs b/src/WireMock.Net/RequestBuilders/Request.cs index b65bdee45..c67acf069 100644 --- a/src/WireMock.Net/RequestBuilders/Request.cs +++ b/src/WireMock.Net/RequestBuilders/Request.cs @@ -59,7 +59,7 @@ public T GetRequestMessageMatcher() where T : IRequestMatcher /// /// The matchers. /// The . - public IRequestBuilder WithClientIP(params IMatcher[] matchers) + public IRequestBuilder WithClientIP(params IStringMatcher[] matchers) { Check.NotNullOrEmpty(matchers, nameof(matchers)); @@ -98,7 +98,7 @@ public IRequestBuilder WithClientIP(params Func[] funcs) /// /// The matchers. /// The . - public IRequestBuilder WithPath(params IMatcher[] matchers) + public IRequestBuilder WithPath(params IStringMatcher[] matchers) { Check.NotNullOrEmpty(matchers, nameof(matchers)); @@ -137,7 +137,7 @@ public IRequestBuilder WithPath(params Func[] funcs) /// /// The matchers. /// The . - public IRequestBuilder WithUrl(params IMatcher[] matchers) + public IRequestBuilder WithUrl(params IStringMatcher[] matchers) { Check.NotNullOrEmpty(matchers, nameof(matchers)); @@ -360,7 +360,7 @@ public IRequestBuilder WithHeader(string name, string[] patterns, bool ignoreCas /// The name. /// The matchers. /// The . - public IRequestBuilder WithHeader(string name, params IMatcher[] matchers) + public IRequestBuilder WithHeader(string name, params IStringMatcher[] matchers) { Check.NotNull(name, nameof(name)); Check.NotNullOrEmpty(matchers, nameof(matchers)); @@ -401,7 +401,7 @@ public IRequestBuilder WithCookie(string name, string pattern, bool ignoreCase = /// The name. /// The matchers. /// The . - public IRequestBuilder WithCookie(string name, params IMatcher[] matchers) + public IRequestBuilder WithCookie(string name, params IStringMatcher[] matchers) { Check.NotNullOrEmpty(matchers, nameof(matchers)); diff --git a/src/WireMock.Net/Serialization/MappingConverter.cs b/src/WireMock.Net/Serialization/MappingConverter.cs index d65c365b9..3c4b0a834 100644 --- a/src/WireMock.Net/Serialization/MappingConverter.cs +++ b/src/WireMock.Net/Serialization/MappingConverter.cs @@ -166,7 +166,8 @@ private static MatcherModel Map([CanBeNull] IMatcher matcher) return null; } - var patterns = matcher.GetPatterns(); + IStringMatcher stringMatcher = matcher as IStringMatcher; + string[] patterns = stringMatcher != null ? stringMatcher.GetPatterns() : new string[0]; return new MatcherModel { @@ -192,7 +193,9 @@ private static string Map([CanBeNull] Func func) public static IMatcher Map([CanBeNull] MatcherModel matcher) { if (matcher == null) + { return null; + } var parts = matcher.Name.Split('.'); string matcherName = parts[0]; diff --git a/src/WireMock.Net/Server/FluentMockServer.Admin.cs b/src/WireMock.Net/Server/FluentMockServer.Admin.cs index ad37a16fd..a2b64adab 100644 --- a/src/WireMock.Net/Server/FluentMockServer.Admin.cs +++ b/src/WireMock.Net/Server/FluentMockServer.Admin.cs @@ -606,7 +606,7 @@ private IRequestBuilder InitRequestBuilder(RequestModel requestModel) var clientIPModel = JsonUtils.ParseJTokenToObject(requestModel.ClientIP); if (clientIPModel?.Matchers != null) { - requestBuilder = requestBuilder.WithPath(clientIPModel.Matchers.Select(MappingConverter.Map).ToArray()); + requestBuilder = requestBuilder.WithPath(clientIPModel.Matchers.Select(MappingConverter.Map).Cast().ToArray()); } } } @@ -623,7 +623,7 @@ private IRequestBuilder InitRequestBuilder(RequestModel requestModel) var pathModel = JsonUtils.ParseJTokenToObject(requestModel.Path); if (pathModel?.Matchers != null) { - requestBuilder = requestBuilder.WithPath(pathModel.Matchers.Select(MappingConverter.Map).ToArray()); + requestBuilder = requestBuilder.WithPath(pathModel.Matchers.Select(MappingConverter.Map).Cast().ToArray()); } } } @@ -640,7 +640,7 @@ private IRequestBuilder InitRequestBuilder(RequestModel requestModel) var urlModel = JsonUtils.ParseJTokenToObject(requestModel.Url); if (urlModel?.Matchers != null) { - requestBuilder = requestBuilder.WithUrl(urlModel.Matchers.Select(MappingConverter.Map).ToArray()); + requestBuilder = requestBuilder.WithUrl(urlModel.Matchers.Select(MappingConverter.Map).Cast().ToArray()); } } } @@ -654,7 +654,7 @@ private IRequestBuilder InitRequestBuilder(RequestModel requestModel) { foreach (var headerModel in requestModel.Headers.Where(h => h.Matchers != null)) { - requestBuilder = requestBuilder.WithHeader(headerModel.Name, headerModel.Matchers.Select(MappingConverter.Map).ToArray()); + requestBuilder = requestBuilder.WithHeader(headerModel.Name, headerModel.Matchers.Select(MappingConverter.Map).Cast().ToArray()); } } @@ -662,7 +662,7 @@ private IRequestBuilder InitRequestBuilder(RequestModel requestModel) { foreach (var cookieModel in requestModel.Cookies.Where(c => c.Matchers != null)) { - requestBuilder = requestBuilder.WithCookie(cookieModel.Name, cookieModel.Matchers.Select(MappingConverter.Map).ToArray()); + requestBuilder = requestBuilder.WithCookie(cookieModel.Name, cookieModel.Matchers.Select(MappingConverter.Map).Cast().ToArray()); } } diff --git a/test/WireMock.Net.Tests/RequestWithBodyTests.cs b/test/WireMock.Net.Tests/RequestWithBodyTests.cs index 6942e6b56..b9a06b8d9 100644 --- a/test/WireMock.Net.Tests/RequestWithBodyTests.cs +++ b/test/WireMock.Net.Tests/RequestWithBodyTests.cs @@ -1,10 +1,12 @@ using System; using System.Collections.Generic; using System.Text; +using Newtonsoft.Json; using NFluent; using WireMock.Matchers; using WireMock.Matchers.Request; using WireMock.RequestBuilders; +using WireMock.Util; using Xunit; namespace WireMock.Net.Tests @@ -198,5 +200,26 @@ public void Request_WithBodyJsonPathMatcher_false() var requestMatchResult = new RequestMatchResult(); Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsNotEqualTo(1.0); } + + [Fact] + public void Request_WithBodyAsJson_JsonPathMatcher_true() + { + // given + var spec = Request.Create().UsingAnyVerb().WithBody(new JsonPathMatcher("$.things[?(@.name == 'RequiredThing')]")); + + // when + string jsonString = "{ \"things\": [ { \"name\": \"RequiredThing\" }, { \"name\": \"Wiremock\" } ] }"; + var bodyData = new BodyData + { + BodyAsJson = JsonConvert.DeserializeObject(jsonString), + Encoding = Encoding.UTF8 + }; + + var request = new RequestMessage(new Uri("http://localhost/foo"), "PUT", ClientIp, bodyData); + + // then + var requestMatchResult = new RequestMatchResult(); + Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0); + } } } \ No newline at end of file diff --git a/test/WireMock.Net.Tests/StatefulBehaviorTests.cs b/test/WireMock.Net.Tests/StatefulBehaviorTests.cs index 6437f1d22..ab0c539ca 100644 --- a/test/WireMock.Net.Tests/StatefulBehaviorTests.cs +++ b/test/WireMock.Net.Tests/StatefulBehaviorTests.cs @@ -159,16 +159,16 @@ public async Task Should_process_request_if_equals_state_and_multiple_state_defi // when / then string url = "http://localhost:" + _server.Ports[0]; var http = new HttpClient(); - var responseNoState1 = await http.GetStringAsync(url + "/state1"); + var responseNoState1 = http.GetStringAsync(url + "/state1").Result; Check.That(responseNoState1).Equals("No state msg 1"); - var responseNoState2 = await http.GetStringAsync(url + "/state2"); + var responseNoState2 = http.GetStringAsync(url + "/state2").Result; Check.That(responseNoState2).Equals("No state msg 2"); - var responseWithState1 = await http.GetStringAsync(url + "/foo"); + var responseWithState1 = http.GetStringAsync(url + "/foo").Result; Check.That(responseWithState1).Equals("Test state msg 1"); - var responseWithState2 = await http.GetStringAsync(url + "/foo"); + var responseWithState2 = http.GetStringAsync(url + "/foo").Result; Check.That(responseWithState2).Equals("Test state msg 2"); } From ec190ebb4b37df38e1dca2a135415ddb4c0db3c8 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Wed, 21 Feb 2018 13:17:31 +0100 Subject: [PATCH 2/3] More tests --- .../Matchers/ExactObjectMatcher.cs | 20 +++++++-- .../RequestWithBodyTests.cs | 43 ++++++++++++++++++- .../StatefulBehaviorTests.cs | 19 ++++---- 3 files changed, 67 insertions(+), 15 deletions(-) diff --git a/src/WireMock.Net/Matchers/ExactObjectMatcher.cs b/src/WireMock.Net/Matchers/ExactObjectMatcher.cs index f7cb66352..8963bb5da 100644 --- a/src/WireMock.Net/Matchers/ExactObjectMatcher.cs +++ b/src/WireMock.Net/Matchers/ExactObjectMatcher.cs @@ -1,4 +1,5 @@ -using JetBrains.Annotations; +using System.Linq; +using JetBrains.Annotations; namespace WireMock.Matchers { @@ -8,7 +9,8 @@ namespace WireMock.Matchers /// public class ExactObjectMatcher : IObjectMatcher { - private readonly object _value; + private readonly object _object; + private readonly byte[] _bytes; /// /// Initializes a new instance of the class. @@ -16,13 +18,23 @@ public class ExactObjectMatcher : IObjectMatcher /// The value. public ExactObjectMatcher([NotNull] object value) { - _value = value; + _object = value; + } + + /// + /// Initializes a new instance of the class. + /// + /// The value. + public ExactObjectMatcher([NotNull] byte[] value) + { + _bytes = value; } /// public double IsMatch(object input) { - return MatchScores.ToScore(Equals(_value, input)); + bool equals = _object != null ? Equals(_object, input) : _bytes.SequenceEqual((byte[])input); + return MatchScores.ToScore(equals); } /// diff --git a/test/WireMock.Net.Tests/RequestWithBodyTests.cs b/test/WireMock.Net.Tests/RequestWithBodyTests.cs index b9a06b8d9..5af9aa354 100644 --- a/test/WireMock.Net.Tests/RequestWithBodyTests.cs +++ b/test/WireMock.Net.Tests/RequestWithBodyTests.cs @@ -202,7 +202,7 @@ public void Request_WithBodyJsonPathMatcher_false() } [Fact] - public void Request_WithBodyAsJson_JsonPathMatcher_true() + public void Request_WithBodyAsJson_Object_JsonPathMatcher_true() { // given var spec = Request.Create().UsingAnyVerb().WithBody(new JsonPathMatcher("$.things[?(@.name == 'RequiredThing')]")); @@ -221,5 +221,46 @@ public void Request_WithBodyAsJson_JsonPathMatcher_true() var requestMatchResult = new RequestMatchResult(); Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0); } + [Fact] + public void Request_WithBodyAsJson_Array_JsonPathMatcher_true() + { + // given + var spec = Request.Create().UsingAnyVerb().WithBody(new JsonPathMatcher("$.books[?(@.price < 10)]")); + + // when + string jsonString = "{ \"books\": [ { \"category\": \"test1\", \"price\": 8.95 }, { \"category\": \"test2\", \"price\": 20 } ] }"; + var bodyData = new BodyData + { + BodyAsJson = JsonConvert.DeserializeObject(jsonString), + Encoding = Encoding.UTF8 + }; + + var request = new RequestMessage(new Uri("http://localhost/foo"), "PUT", ClientIp, bodyData); + + // then + var requestMatchResult = new RequestMatchResult(); + Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0); + } + + + [Fact] + public void Request_WithBodyAsBytes_ExactObjectMatcher_true() + { + // Assign + byte[] body = { 123 }; + var requestBuilder = Request.Create().UsingAnyVerb().WithBody(body); + + var bodyData = new BodyData + { + BodyAsBytes = new byte[] { 123 } + }; + + // Act + var request = new RequestMessage(new Uri("http://localhost/foo"), "PUT", ClientIp, bodyData); + + // Assert + var requestMatchResult = new RequestMatchResult(); + Check.That(requestBuilder.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0); + } } } \ No newline at end of file diff --git a/test/WireMock.Net.Tests/StatefulBehaviorTests.cs b/test/WireMock.Net.Tests/StatefulBehaviorTests.cs index ab0c539ca..2e0830c14 100644 --- a/test/WireMock.Net.Tests/StatefulBehaviorTests.cs +++ b/test/WireMock.Net.Tests/StatefulBehaviorTests.cs @@ -69,7 +69,7 @@ public async Task Should_process_request_if_equals_state_and_single_state_define } [Fact] - public async Task Scenario_and_State_TodoList_Example() + public void Scenario_and_State_TodoList_Example() { // Assign _server = FluentMockServer.Start(); @@ -104,18 +104,18 @@ public async Task Scenario_and_State_TodoList_Example() // Act and Assert string url = "http://localhost:" + _server.Ports[0]; - string getResponse1 = await new HttpClient().GetStringAsync(url + "/todo/items"); + string getResponse1 = new HttpClient().GetStringAsync(url + "/todo/items").Result; Check.That(getResponse1).Equals("Buy milk"); - var postResponse = await new HttpClient().PostAsync(url + "/todo/items", new StringContent("Cancel newspaper subscription")); + var postResponse = new HttpClient().PostAsync(url + "/todo/items", new StringContent("Cancel newspaper subscription")).Result; Check.That(postResponse.StatusCode).Equals(HttpStatusCode.Created); - string getResponse2 = await new HttpClient().GetStringAsync(url + "/todo/items"); + string getResponse2 = new HttpClient().GetStringAsync(url + "/todo/items").Result; Check.That(getResponse2).Equals("Buy milk;Cancel newspaper subscription"); } [Fact] - public async Task Should_process_request_if_equals_state_and_multiple_state_defined() + public void Should_process_request_if_equals_state_and_multiple_state_defined() { // given _server = FluentMockServer.Start(); @@ -158,17 +158,16 @@ public async Task Should_process_request_if_equals_state_and_multiple_state_defi // when / then string url = "http://localhost:" + _server.Ports[0]; - var http = new HttpClient(); - var responseNoState1 = http.GetStringAsync(url + "/state1").Result; + var responseNoState1 = new HttpClient().GetStringAsync(url + "/state1").Result; Check.That(responseNoState1).Equals("No state msg 1"); - var responseNoState2 = http.GetStringAsync(url + "/state2").Result; + var responseNoState2 = new HttpClient().GetStringAsync(url + "/state2").Result; Check.That(responseNoState2).Equals("No state msg 2"); - var responseWithState1 = http.GetStringAsync(url + "/foo").Result; + var responseWithState1 = new HttpClient().GetStringAsync(url + "/foo").Result; Check.That(responseWithState1).Equals("Test state msg 1"); - var responseWithState2 = http.GetStringAsync(url + "/foo").Result; + var responseWithState2 = new HttpClient().GetStringAsync(url + "/foo").Result; Check.That(responseWithState2).Equals("Test state msg 2"); } From d2b24a00c0f294aa4d39cdfdd1c0cb1f6642be47 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Wed, 21 Feb 2018 19:35:12 +0100 Subject: [PATCH 3/3] Fixes + added tests --- .../MainApp.cs | 9 +++ .../Request/RequestMessageBodyMatcher.cs | 2 +- .../Request/RequestMessageClientIPMatcher.cs | 4 + .../RequestBuilders/IBodyRequestBuilder.cs | 34 +++++--- src/WireMock.Net/RequestBuilders/Request.cs | 77 +++++++------------ .../RequestWithBodyTests.cs | 19 +++++ .../StatefulBehaviorTests.cs | 3 + 7 files changed, 86 insertions(+), 62 deletions(-) diff --git a/examples/WireMock.Net.ConsoleApplication/MainApp.cs b/examples/WireMock.Net.ConsoleApplication/MainApp.cs index 09e4e290c..0627c0207 100644 --- a/examples/WireMock.Net.ConsoleApplication/MainApp.cs +++ b/examples/WireMock.Net.ConsoleApplication/MainApp.cs @@ -41,6 +41,15 @@ public static void Run() // .RespondWith(Response.Create() // .WithProxy("http://restcountries.eu")); + server + .Given(Request + .Create() + .WithPath("/jsonthings") + .WithBody(new JsonPathMatcher("$.things[?(@.name == 'RequiredThing')]")) + .UsingPut()) + .RespondWith(Response.Create() + .WithBody(@"{ ""result"": ""JsonPathMatcher !!!""}")); + server .Given(Request .Create() diff --git a/src/WireMock.Net/Matchers/Request/RequestMessageBodyMatcher.cs b/src/WireMock.Net/Matchers/Request/RequestMessageBodyMatcher.cs index 427510e3c..c3cad3090 100644 --- a/src/WireMock.Net/Matchers/Request/RequestMessageBodyMatcher.cs +++ b/src/WireMock.Net/Matchers/Request/RequestMessageBodyMatcher.cs @@ -127,7 +127,7 @@ private double IsMatch(RequestMessage requestMessage) if (Func != null) { - return MatchScores.ToScore(Func(requestMessage.Body)); + return MatchScores.ToScore(requestMessage.Body != null && Func(requestMessage.Body)); } if (DataFunc != null) diff --git a/src/WireMock.Net/Matchers/Request/RequestMessageClientIPMatcher.cs b/src/WireMock.Net/Matchers/Request/RequestMessageClientIPMatcher.cs index 718326b47..6b2d5d695 100644 --- a/src/WireMock.Net/Matchers/Request/RequestMessageClientIPMatcher.cs +++ b/src/WireMock.Net/Matchers/Request/RequestMessageClientIPMatcher.cs @@ -59,10 +59,14 @@ public double GetMatchingScore(RequestMessage requestMessage, RequestMatchResult private double IsMatch(RequestMessage requestMessage) { if (Matchers != null) + { return Matchers.Max(matcher => matcher.IsMatch(requestMessage.ClientIP)); + } if (Funcs != null) + { return MatchScores.ToScore(requestMessage.ClientIP != null && Funcs.Any(func => func(requestMessage.ClientIP))); + } return MatchScores.Mismatch; } diff --git a/src/WireMock.Net/RequestBuilders/IBodyRequestBuilder.cs b/src/WireMock.Net/RequestBuilders/IBodyRequestBuilder.cs index c979b91e3..49c4f78f4 100644 --- a/src/WireMock.Net/RequestBuilders/IBodyRequestBuilder.cs +++ b/src/WireMock.Net/RequestBuilders/IBodyRequestBuilder.cs @@ -10,38 +10,52 @@ namespace WireMock.RequestBuilders public interface IBodyRequestBuilder { /// - /// The with body. + /// WithBody: IMatcher /// /// The matcher. /// The . IRequestBuilder WithBody([NotNull] IMatcher matcher); /// - /// The with body. + /// WithBody: Body as string /// /// The body. /// The . IRequestBuilder WithBody(string body); /// - /// The with body byte[]. + /// WithBody: Body as byte[] /// - /// The body as byte[]. + /// The body. /// The . IRequestBuilder WithBody(byte[] body); /// - /// The with body string func. + /// WithBody: Body as object + /// + /// The body. + /// The . + IRequestBuilder WithBody(object body); + + /// + ///WithBody: func (string) + /// + /// The function. + /// The . + IRequestBuilder WithBody([NotNull] Func func); + + /// + ///WithBody: func (byte[]) /// - /// The body string function. + /// The function. /// The . - IRequestBuilder WithBody([NotNull] Func body); + IRequestBuilder WithBody([NotNull] Func func); /// - /// The with body byte[] func. + ///WithBody: func (object) /// - /// The body byte[] function. + /// The function. /// The . - IRequestBuilder WithBody([NotNull] Func body); + IRequestBuilder WithBody([NotNull] Func func); } } \ No newline at end of file diff --git a/src/WireMock.Net/RequestBuilders/Request.cs b/src/WireMock.Net/RequestBuilders/Request.cs index c67acf069..8d527935e 100644 --- a/src/WireMock.Net/RequestBuilders/Request.cs +++ b/src/WireMock.Net/RequestBuilders/Request.cs @@ -234,39 +234,37 @@ public IRequestBuilder UsingVerb(params string[] verbs) return this; } - /// - /// The with body. - /// - /// - /// The body. - /// - /// The . + /// public IRequestBuilder WithBody(string body) { _requestMatchers.Add(new RequestMessageBodyMatcher(body)); return this; } - /// - /// The with body byte[]. - /// - /// - /// The body as byte[]. - /// - /// The . + /// public IRequestBuilder WithBody(byte[] body) { _requestMatchers.Add(new RequestMessageBodyMatcher(body)); return this; } - /// - /// The with body. - /// - /// - /// The body function. - /// - /// The . + /// + public IRequestBuilder WithBody(object body) + { + _requestMatchers.Add(new RequestMessageBodyMatcher(body)); + return this; + } + + /// + public IRequestBuilder WithBody(IMatcher matcher) + { + Check.NotNull(matcher, nameof(matcher)); + + _requestMatchers.Add(new RequestMessageBodyMatcher(matcher)); + return this; + } + + /// public IRequestBuilder WithBody(Func func) { Check.NotNull(func, nameof(func)); @@ -275,13 +273,7 @@ public IRequestBuilder WithBody(Func func) return this; } - /// - /// The with body. - /// - /// - /// The body function. - /// - /// The . + /// public IRequestBuilder WithBody(Func func) { Check.NotNull(func, nameof(func)); @@ -290,29 +282,16 @@ public IRequestBuilder WithBody(Func func) return this; } - /// - /// The with body. - /// - /// The matcher. - /// The . - public IRequestBuilder WithBody(IMatcher matcher) + /// + public IRequestBuilder WithBody(Func func) { - Check.NotNull(matcher, nameof(matcher)); + Check.NotNull(func, nameof(func)); - _requestMatchers.Add(new RequestMessageBodyMatcher(matcher)); + _requestMatchers.Add(new RequestMessageBodyMatcher(func)); return this; } - /// - /// The with parameters. - /// - /// - /// The key. - /// - /// - /// The values. - /// - /// The . + /// public IRequestBuilder WithParam(string key, params string[] values) { Check.NotNull(key, nameof(key)); @@ -321,11 +300,7 @@ public IRequestBuilder WithParam(string key, params string[] values) return this; } - /// - /// The with parameters. - /// - /// The funcs. - /// The . + /// public IRequestBuilder WithParam(params Func>, bool>[] funcs) { Check.NotNullOrEmpty(funcs, nameof(funcs)); diff --git a/test/WireMock.Net.Tests/RequestWithBodyTests.cs b/test/WireMock.Net.Tests/RequestWithBodyTests.cs index 5af9aa354..3287824f2 100644 --- a/test/WireMock.Net.Tests/RequestWithBodyTests.cs +++ b/test/WireMock.Net.Tests/RequestWithBodyTests.cs @@ -242,6 +242,25 @@ public void Request_WithBodyAsJson_Array_JsonPathMatcher_true() Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0); } + [Fact] + public void Request_WithBodyAsObject_ExactObjectMatcher_true() + { + // Assign + object body = DateTime.MinValue; + var requestBuilder = Request.Create().UsingAnyVerb().WithBody(body); + + var bodyData = new BodyData + { + BodyAsJson = DateTime.MinValue + }; + + // Act + var request = new RequestMessage(new Uri("http://localhost/foo"), "PUT", ClientIp, bodyData); + + // Assert + var requestMatchResult = new RequestMatchResult(); + Check.That(requestBuilder.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0); + } [Fact] public void Request_WithBodyAsBytes_ExactObjectMatcher_true() diff --git a/test/WireMock.Net.Tests/StatefulBehaviorTests.cs b/test/WireMock.Net.Tests/StatefulBehaviorTests.cs index 2e0830c14..e0e463c51 100644 --- a/test/WireMock.Net.Tests/StatefulBehaviorTests.cs +++ b/test/WireMock.Net.Tests/StatefulBehaviorTests.cs @@ -1,6 +1,7 @@ using System; using System.Net; using System.Net.Http; +using System.Threading; using System.Threading.Tasks; using NFluent; using WireMock.RequestBuilders; @@ -156,6 +157,8 @@ public void Should_process_request_if_equals_state_and_multiple_state_defined() .RespondWith(Response.Create() .WithBody("Test state msg 2")); + Thread.Sleep(500); + // when / then string url = "http://localhost:" + _server.Ports[0]; var responseNoState1 = new HttpClient().GetStringAsync(url + "/state1").Result;