diff --git a/Directory.Build.props b/Directory.Build.props index 2e22d82ff..36db2bfbe 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -4,7 +4,7 @@ - 1.0.13 + 1.0.14 diff --git a/WireMock.Net Solution.sln.DotSettings b/WireMock.Net Solution.sln.DotSettings index 4556d123c..8f9aa5d2d 100644 --- a/WireMock.Net Solution.sln.DotSettings +++ b/WireMock.Net Solution.sln.DotSettings @@ -10,6 +10,7 @@ XUA True True + True True True \ No newline at end of file diff --git a/examples/WireMock.Net.StandAlone.Net461/App.config b/examples/WireMock.Net.StandAlone.Net461/App.config index 4be9c6eff..0b11f8d0b 100644 --- a/examples/WireMock.Net.StandAlone.Net461/App.config +++ b/examples/WireMock.Net.StandAlone.Net461/App.config @@ -44,7 +44,7 @@ - + diff --git a/examples/WireMock.Net.StandAlone.Net461/WireMock.Net.StandAlone.Net461.csproj b/examples/WireMock.Net.StandAlone.Net461/WireMock.Net.StandAlone.Net461.csproj index cc1988ce5..4a9309c97 100644 --- a/examples/WireMock.Net.StandAlone.Net461/WireMock.Net.StandAlone.Net461.csproj +++ b/examples/WireMock.Net.StandAlone.Net461/WireMock.Net.StandAlone.Net461.csproj @@ -225,8 +225,8 @@ ..\..\packages\System.IO.Pipelines.4.5.2\lib\netstandard2.0\System.IO.Pipelines.dll - - ..\..\packages\System.Linq.Dynamic.Core.1.0.11\lib\net46\System.Linq.Dynamic.Core.dll + + ..\..\packages\System.Linq.Dynamic.Core.1.0.12\lib\net46\System.Linq.Dynamic.Core.dll ..\..\packages\System.Memory.4.5.1\lib\netstandard2.0\System.Memory.dll diff --git a/examples/WireMock.Net.StandAlone.Net461/packages.config b/examples/WireMock.Net.StandAlone.Net461/packages.config index 9ff4575ad..679c143cd 100644 --- a/examples/WireMock.Net.StandAlone.Net461/packages.config +++ b/examples/WireMock.Net.StandAlone.Net461/packages.config @@ -65,7 +65,7 @@ - + diff --git a/src/WireMock.Net/Matchers/JmesPathMatcher.cs b/src/WireMock.Net/Matchers/JmesPathMatcher.cs new file mode 100644 index 000000000..a01308f0c --- /dev/null +++ b/src/WireMock.Net/Matchers/JmesPathMatcher.cs @@ -0,0 +1,83 @@ +using DevLab.JmesPath; +using JetBrains.Annotations; +using Newtonsoft.Json; +using System.Linq; +using WireMock.Validation; + +namespace WireMock.Matchers +{ + /// + /// http://jmespath.org/ + /// + public class JmesPathMatcher : IStringMatcher, IObjectMatcher + { + private readonly string[] _patterns; + + /// + public MatchBehaviour MatchBehaviour { get; } + + /// + /// Initializes a new instance of the class. + /// + /// The patterns. + public JmesPathMatcher([NotNull] params string[] patterns) : this(MatchBehaviour.AcceptOnMatch, patterns) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The match behaviour. + /// The patterns. + public JmesPathMatcher(MatchBehaviour matchBehaviour, [NotNull] params string[] patterns) + { + Check.NotNull(patterns, nameof(patterns)); + + MatchBehaviour = matchBehaviour; + _patterns = patterns; + } + + /// + public double IsMatch(string input) + { + double match = MatchScores.Mismatch; + if (input != null) + { + try + { + match = MatchScores.ToScore(_patterns.Select(pattern => bool.Parse(new JmesPath().Transform(input, pattern)))); + } + catch (JsonException) + { + // just ignore JsonException + } + } + + return MatchBehaviourHelper.Convert(MatchBehaviour, match); + } + + /// + public double IsMatch(object input) + { + double match = MatchScores.Mismatch; + + // 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); + } + + /// + public string[] GetPatterns() + { + return _patterns; + } + + /// + public string Name => "JmesPathMatcher"; + } +} \ No newline at end of file diff --git a/src/WireMock.Net/Serialization/MatcherMapper.cs b/src/WireMock.Net/Serialization/MatcherMapper.cs index 57b128e5f..14154c7f2 100644 --- a/src/WireMock.Net/Serialization/MatcherMapper.cs +++ b/src/WireMock.Net/Serialization/MatcherMapper.cs @@ -45,6 +45,9 @@ public static IMatcher Map([CanBeNull] MatcherModel matcher) case "JsonPathMatcher": return new JsonPathMatcher(matchBehaviour, stringPatterns); + case "JmesPathMatcher": + return new JmesPathMatcher(matchBehaviour, stringPatterns); + case "XPathMatcher": return new XPathMatcher(matchBehaviour, (string)matcher.Pattern); diff --git a/src/WireMock.Net/WireMock.Net.csproj b/src/WireMock.Net/WireMock.Net.csproj index 6b4054811..f8e012e41 100644 --- a/src/WireMock.Net/WireMock.Net.csproj +++ b/src/WireMock.Net/WireMock.Net.csproj @@ -57,8 +57,9 @@ all runtime; build; native; contentfiles; analyzers - + + diff --git a/test/WireMock.Net.Tests/Matchers/JmesPathMatcherTests.cs b/test/WireMock.Net.Tests/Matchers/JmesPathMatcherTests.cs new file mode 100644 index 000000000..bef4724fc --- /dev/null +++ b/test/WireMock.Net.Tests/Matchers/JmesPathMatcherTests.cs @@ -0,0 +1,166 @@ +using Newtonsoft.Json.Linq; +using NFluent; +using WireMock.Matchers; +using Xunit; + +namespace WireMock.Net.Tests.Matchers +{ + public class JmesPathMatcherTests + { + [Fact] + public void JmesPathMatcher_GetName() + { + // Assign + var matcher = new JmesPathMatcher("X"); + + // Act + string name = matcher.Name; + + // Assert + Check.That(name).Equals("JmesPathMatcher"); + } + + [Fact] + public void JmesPathMatcher_GetPatterns() + { + // Assign + var matcher = new JmesPathMatcher("X"); + + // Act + string[] patterns = matcher.GetPatterns(); + + // Assert + Check.That(patterns).ContainsExactly("X"); + } + + [Fact] + public void JmesPathMatcher_IsMatch_ByteArray() + { + // Assign + var bytes = new byte[0]; + var matcher = new JmesPathMatcher(""); + + // Act + double match = matcher.IsMatch(bytes); + + // Assert + Check.That(match).IsEqualTo(0); + } + + [Fact] + public void JmesPathMatcher_IsMatch_NullString() + { + // Assign + string s = null; + var matcher = new JmesPathMatcher(""); + + // Act + double match = matcher.IsMatch(s); + + // Assert + Check.That(match).IsEqualTo(0); + } + + [Fact] + public void JmesPathMatcher_IsMatch_NullObject() + { + // Assign + object o = null; + var matcher = new JmesPathMatcher(""); + + // Act + double match = matcher.IsMatch(o); + + // Assert + Check.That(match).IsEqualTo(0); + } + + [Fact] + public void JmesPathMatcher_IsMatch_String_Exception_Mismatch() + { + // Assign + var matcher = new JmesPathMatcher("xxx"); + + // Act + double match = matcher.IsMatch(""); + + // Assert + Check.That(match).IsEqualTo(0); + } + + [Fact] + public void JmesPathMatcher_IsMatch_Object_Exception_Mismatch() + { + // Assign + var matcher = new JmesPathMatcher(""); + + // Act + double match = matcher.IsMatch("x"); + + // Assert + Check.That(match).IsEqualTo(0); + } + + [Fact] + public void JmesPathMatcher_IsMatch_AnonymousObject() + { + // Assign + var matcher = new JmesPathMatcher("things.name == 'RequiredThing'"); + + // Act + double match = matcher.IsMatch(new { things = new { name = "RequiredThing" } }); + + // Assert + Check.That(match).IsEqualTo(1); + } + + [Fact] + public void JmesPathMatcher_IsMatch_JObject() + { + // Assign + string[] patterns = { "things.x == 'RequiredThing'" }; + var matcher = new JmesPathMatcher(patterns); + + // Act + var sub = new JObject + { + { "x", new JValue("RequiredThing") } + }; + var jobject = new JObject + { + { "Id", new JValue(1) }, + { "things", sub } + }; + double match = matcher.IsMatch(jobject); + + // Assert + Check.That(match).IsEqualTo(1); + } + + [Fact] + public void JmesPathMatcher_IsMatch_JObject_Parsed() + { + // Assign + var matcher = new JmesPathMatcher("things.x == 'RequiredThing'"); + + // Act + double match = matcher.IsMatch(JObject.Parse("{ \"things\": { \"x\": \"RequiredThing\" } }")); + + // Assert + Check.That(match).IsEqualTo(1); + } + + [Fact] + public void JmesPathMatcher_IsMatch_RejectOnMatch() + { + // Assign + var matcher = new JmesPathMatcher(MatchBehaviour.RejectOnMatch, "things.x == 'RequiredThing'"); + + // Act + double match = matcher.IsMatch(JObject.Parse("{ \"things\": { \"x\": \"RequiredThing\" } }")); + + // Assert + Check.That(match).IsEqualTo(0.0); + } + } +} \ No newline at end of file diff --git a/test/WireMock.Net.Tests/WireMock.Net.Tests.csproj b/test/WireMock.Net.Tests/WireMock.Net.Tests.csproj index d8e5e9ea9..16306f97d 100644 --- a/test/WireMock.Net.Tests/WireMock.Net.Tests.csproj +++ b/test/WireMock.Net.Tests/WireMock.Net.Tests.csproj @@ -36,7 +36,7 @@ - + all