Skip to content

Commit

Permalink
Add JmesPath matcher (#269)
Browse files Browse the repository at this point in the history
* JmesPathMatcher

* netstandard1.3

* update System.Linq.Dynamic.Core

* simplyfy `double IsMatch(object input)`
  • Loading branch information
StefH committed Apr 20, 2019
1 parent dd115a6 commit fdb58b7
Show file tree
Hide file tree
Showing 10 changed files with 261 additions and 7 deletions.
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
</PropertyGroup>

<PropertyGroup>
<VersionPrefix>1.0.13</VersionPrefix>
<VersionPrefix>1.0.14</VersionPrefix>
</PropertyGroup>

<Choose>
Expand Down
1 change: 1 addition & 0 deletions WireMock.Net Solution.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=XUA/@EntryIndexedValue">XUA</s:String>
<s:Boolean x:Key="/Default/UserDictionary/Words/=funcs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Heyenrath/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Jmes/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=randomizer/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Stef/@EntryIndexedValue">True</s:Boolean>
</wpf:ResourceDictionary>
2 changes: 1 addition & 1 deletion examples/WireMock.Net.StandAlone.Net461/App.config
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Linq.Dynamic.Core" publicKeyToken="0f07ec44de6ac832" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.0.11.0" newVersion="1.0.11.0" />
<bindingRedirect oldVersion="0.0.0.0-1.0.12.0" newVersion="1.0.12.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,8 +225,8 @@
<Reference Include="System.IO.Pipelines, Version=4.0.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\..\packages\System.IO.Pipelines.4.5.2\lib\netstandard2.0\System.IO.Pipelines.dll</HintPath>
</Reference>
<Reference Include="System.Linq.Dynamic.Core, Version=1.0.11.0, Culture=neutral, PublicKeyToken=0f07ec44de6ac832, processorArchitecture=MSIL">
<HintPath>..\..\packages\System.Linq.Dynamic.Core.1.0.11\lib\net46\System.Linq.Dynamic.Core.dll</HintPath>
<Reference Include="System.Linq.Dynamic.Core, Version=1.0.12.0, Culture=neutral, PublicKeyToken=0f07ec44de6ac832, processorArchitecture=MSIL">
<HintPath>..\..\packages\System.Linq.Dynamic.Core.1.0.12\lib\net46\System.Linq.Dynamic.Core.dll</HintPath>
</Reference>
<Reference Include="System.Memory, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\..\packages\System.Memory.4.5.1\lib\netstandard2.0\System.Memory.dll</HintPath>
Expand Down
2 changes: 1 addition & 1 deletion examples/WireMock.Net.StandAlone.Net461/packages.config
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
<package id="System.Collections.Immutable" version="1.5.0" targetFramework="net461" />
<package id="System.Diagnostics.DiagnosticSource" version="4.5.0" targetFramework="net461" />
<package id="System.IO.Pipelines" version="4.5.2" targetFramework="net461" />
<package id="System.Linq.Dynamic.Core" version="1.0.11" targetFramework="net461" />
<package id="System.Linq.Dynamic.Core" version="1.0.12" targetFramework="net461" />
<package id="System.Memory" version="4.5.1" targetFramework="net461" />
<package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net461" />
<package id="System.Reflection.Metadata" version="1.6.0" targetFramework="net461" />
Expand Down
83 changes: 83 additions & 0 deletions src/WireMock.Net/Matchers/JmesPathMatcher.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
using DevLab.JmesPath;
using JetBrains.Annotations;
using Newtonsoft.Json;
using System.Linq;
using WireMock.Validation;

namespace WireMock.Matchers
{
/// <summary>
/// http://jmespath.org/
/// </summary>
public class JmesPathMatcher : IStringMatcher, IObjectMatcher
{
private readonly string[] _patterns;

/// <inheritdoc cref="IMatcher.MatchBehaviour"/>
public MatchBehaviour MatchBehaviour { get; }

/// <summary>
/// Initializes a new instance of the <see cref="JmesPathMatcher"/> class.
/// </summary>
/// <param name="patterns">The patterns.</param>
public JmesPathMatcher([NotNull] params string[] patterns) : this(MatchBehaviour.AcceptOnMatch, patterns)
{
}

/// <summary>
/// Initializes a new instance of the <see cref="JmesPathMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="patterns">The patterns.</param>
public JmesPathMatcher(MatchBehaviour matchBehaviour, [NotNull] params string[] patterns)
{
Check.NotNull(patterns, nameof(patterns));

MatchBehaviour = matchBehaviour;
_patterns = patterns;
}

/// <inheritdoc cref="IStringMatcher.IsMatch"/>
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);
}

/// <inheritdoc cref="IObjectMatcher.IsMatch"/>
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);
}

/// <inheritdoc cref="IStringMatcher.GetPatterns"/>
public string[] GetPatterns()
{
return _patterns;
}

/// <inheritdoc cref="IMatcher.Name"/>
public string Name => "JmesPathMatcher";
}
}
3 changes: 3 additions & 0 deletions src/WireMock.Net/Serialization/MatcherMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
3 changes: 2 additions & 1 deletion src/WireMock.Net/WireMock.Net.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,9 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.0.11" />
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.0.12" />
<PackageReference Include="RandomDataGenerator.Net" Version="1.0.7" />
<PackageReference Include="JmesPath.Net" Version="1.0.125" />
</ItemGroup>

<ItemGroup Condition=" '$(TargetFramework)' == 'net451' ">
Expand Down
166 changes: 166 additions & 0 deletions test/WireMock.Net.Tests/Matchers/JmesPathMatcherTests.cs
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
2 changes: 1 addition & 1 deletion test/WireMock.Net.Tests/WireMock.Net.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
<PackageReference Include="OpenCover" Version="4.6.519" />
<PackageReference Include="ReportGenerator" Version="3.1.2" />
<PackageReference Include="SimMetrics.Net" Version="1.0.5" />
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.0.11" />
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.0.12" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
<PrivateAssets>all</PrivateAssets>
Expand Down

0 comments on commit fdb58b7

Please sign in to comment.