Support for string and object in JsonMatcher. (#157)

* JsonMatcher (#154)

* small update in example code
This commit is contained in:
Stef Heyenrath
2018-06-26 23:20:30 +02:00
committed by GitHub
parent b2690017a8
commit 4283732b6c
13 changed files with 135 additions and 42 deletions

View File

@@ -57,12 +57,22 @@ namespace WireMock.Net.ConsoleApplication
server
.Given(Request
.Create()
.WithPath("/jsonbodytest")
.WithPath("/jsonbodytest1")
.WithBody(new JsonMatcher("{ \"x\": 42, \"s\": \"s\" }"))
.UsingPost())
.WithGuid("debaf408-3b23-4c04-9d18-ef1c020e79f2")
.RespondWith(Response.Create()
.WithBody(@"{ ""result"": ""jsonbodytest"" }"));
.WithBody(@"{ ""result"": ""jsonbodytest1"" }"));
server
.Given(Request
.Create()
.WithPath("/jsonbodytest2")
.WithBody(new JsonMatcher(new { x = 42, s = "s" }))
.UsingPost())
.WithGuid("debaf408-3b23-4c04-9d18-ef1c020e79f3")
.RespondWith(Response.Create()
.WithBody(@"{ ""result"": ""jsonbodytest2"" }"));
server
.Given(Request
@@ -77,7 +87,6 @@ namespace WireMock.Net.ConsoleApplication
.Given(Request.Create().WithPath("/headers", "/headers_test").UsingPost().WithHeader("Content-Type", "application/json*"))
.RespondWith(Response.Create()
.WithStatusCode(201)
//.WithHeader("MyHeader", "application/json", "application/json2")
.WithHeader("Content-Type", "application/json")
.WithBodyAsJson(new { result = "data:headers posted with 201" }));
@@ -184,8 +193,6 @@ namespace WireMock.Net.ConsoleApplication
.WithStatusCode(HttpStatusCode.Unauthorized)
.WithBody(@"{ ""result"": ""api-key missing""}"));
server
.Given(Request.Create().WithPath("/nobody").UsingGet())
.RespondWith(Response.Create().WithDelay(TimeSpan.FromSeconds(1))
@@ -195,7 +202,7 @@ namespace WireMock.Net.ConsoleApplication
.Given(Request.Create().WithPath("/partial").UsingPost().WithBody(new SimMetricsMatcher(new[] { "cat", "dog" })))
.RespondWith(Response.Create().WithStatusCode(200).WithBody("partial = 200"));
// http://localhost:8080/any/any?start=1000&stop=1&stop=2
// http://localhost:8080/trans?start=1000&stop=1&stop=2
server
.Given(Request.Create().WithPath("/trans").UsingGet())
.WithGuid("90356dba-b36c-469a-a17e-669cd84f1f05")
@@ -203,6 +210,7 @@ namespace WireMock.Net.ConsoleApplication
.WithStatusCode(200)
.WithHeader("Content-Type", "application/json")
.WithHeader("Transformed-Postman-Token", "token is {{request.headers.Postman-Token}}")
.WithHeader("xyz_{{request.headers.Postman-Token}}", "token is {{request.headers.Postman-Token}}")
.WithBody(@"{""msg"": ""Hello world CATCH-ALL on /*, {{request.path}}, bykey={{request.query.start}}, bykey={{request.query.stop}}, byidx0={{request.query.stop.[0]}}, byidx1={{request.query.stop.[1]}}"" }")
.WithTransformer()
.WithDelay(TimeSpan.FromMilliseconds(100))

View File

@@ -42,8 +42,18 @@
<Reference Include="log4net, Version=2.0.8.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL">
<HintPath>..\..\packages\log4net.2.0.8\lib\net45-full\log4net.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Owin.Host.HttpListener, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.Owin.Host.HttpListener.4.0.0\lib\net451\Microsoft.Owin.Host.HttpListener.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Net.Http.Formatting, Version=5.2.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.AspNet.WebApi.Client.5.2.4\lib\net45\System.Net.Http.Formatting.dll</HintPath>
</Reference>
<Reference Include="System.Numerics" />
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq" />
@@ -53,6 +63,7 @@
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="log4net.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-10.0.0.0" newVersion="10.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

View File

@@ -1,4 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="log4net" version="2.0.8" targetFramework="net452" />
<package id="Microsoft.AspNet.WebApi.Client" version="5.2.4" targetFramework="net452" />
<package id="Microsoft.Owin.Host.HttpListener" version="4.0.0" targetFramework="net452" />
<package id="Newtonsoft.Json" version="10.0.3" targetFramework="net452" />
</packages>

View File

@@ -11,19 +11,14 @@
public string Name { get; set; }
/// <summary>
/// Gets or sets the value. Used by <see cref="Matchers.JsonMatcher"/>.
/// Gets or sets the pattern. Can be a string (default) or an object;
/// </summary>
public string Value { get; set; }
public object Pattern { get; set; }
/// <summary>
/// Gets or sets the pattern.
/// Gets or sets the patterns. Can be array of strings (default) or an array of objects;
/// </summary>
public string Pattern { get; set; }
/// <summary>
/// Gets or sets the patterns.
/// </summary>
public string[] Patterns { get; set; }
public object[] Patterns { get; set; }
/// <summary>
/// Gets or sets the ignore case.

View File

@@ -7,9 +7,9 @@
public interface IValueMatcher: IObjectMatcher
{
/// <summary>
/// Gets the value.
/// Gets the value (can be a string or an obejct).
/// </summary>
/// <returns>Value</returns>
string GetValue();
object Value { get; }
}
}

View File

@@ -10,7 +10,8 @@ namespace WireMock.Matchers
/// </summary>
public class JsonMatcher : IValueMatcher
{
private readonly string _value;
/// <inheritdoc cref="IValueMatcher.Value"/>
public object Value { get; }
/// <inheritdoc cref="IMatcher.Name"/>
public string Name => "JsonMatcher";
@@ -21,22 +22,43 @@ namespace WireMock.Matchers
/// <summary>
/// Initializes a new instance of the <see cref="JsonMatcher"/> class.
/// </summary>
/// <param name="value">The value to check for equality.</param>
/// <param name="value">The string value to check for equality.</param>
public JsonMatcher([NotNull] string value) : this(MatchBehaviour.AcceptOnMatch, value)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="JsonMatcher"/> class.
/// </summary>
/// <param name="value">The object value to check for equality.</param>
public JsonMatcher([NotNull] object value) : this(MatchBehaviour.AcceptOnMatch, value)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="JsonMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="value">The value to check for equality.</param>
/// <param name="value">The string value to check for equality.</param>
public JsonMatcher(MatchBehaviour matchBehaviour, [NotNull] string value)
{
Check.NotNull(value, nameof(value));
MatchBehaviour = matchBehaviour;
_value = value;
Value = value;
}
/// <summary>
/// Initializes a new instance of the <see cref="JsonMatcher"/> class.
/// </summary>
/// <param name="matchBehaviour">The match behaviour.</param>
/// <param name="value">The object value to check for equality.</param>
public JsonMatcher(MatchBehaviour matchBehaviour, [NotNull] object value)
{
Check.NotNull(value, nameof(value));
MatchBehaviour = matchBehaviour;
Value = value;
}
/// <inheritdoc cref="IObjectMatcher.IsMatch"/>
@@ -48,9 +70,15 @@ namespace WireMock.Matchers
try
{
// Check if JToken or object
JToken jtoken = input is JToken token ? token : JObject.FromObject(input);
JToken jtokenInput = input is JToken tokenInput ? tokenInput : JObject.FromObject(input);
match = JToken.DeepEquals(JToken.Parse(_value), jtoken);
// Check if JToken or string or object
JToken jtokenValue =
Value is JToken tokenValue ? tokenValue :
Value is string stringValue ? JToken.Parse(stringValue) :
JObject.FromObject(input);
match = JToken.DeepEquals(jtokenValue, jtokenInput);
}
catch (JsonException)
{
@@ -60,8 +88,5 @@ namespace WireMock.Matchers
return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.ToScore(match));
}
/// <inheritdoc cref="IValueMatcher.GetValue"/>
public string GetValue() => _value;
}
}

View File

@@ -21,28 +21,28 @@ namespace WireMock.Serialization
string matcherName = parts[0];
string matcherType = parts.Length > 1 ? parts[1] : null;
string[] patterns = matcher.Patterns ?? new[] { matcher.Pattern };
string[] stringPatterns = matcher.Patterns != null ? matcher.Patterns.Cast<string>().ToArray() : new [] { matcher.Pattern as string };
MatchBehaviour matchBehaviour = matcher.RejectOnMatch == true ? MatchBehaviour.RejectOnMatch : MatchBehaviour.AcceptOnMatch;
switch (matcherName)
{
case "ExactMatcher":
return new ExactMatcher(matchBehaviour, patterns);
return new ExactMatcher(matchBehaviour, stringPatterns);
case "RegexMatcher":
return new RegexMatcher(matchBehaviour, patterns, matcher.IgnoreCase == true);
return new RegexMatcher(matchBehaviour, stringPatterns, matcher.IgnoreCase == true);
case "JsonMatcher":
return new JsonMatcher(matchBehaviour, matcher.Pattern);
case "JsonPathMatcher":
return new JsonPathMatcher(matchBehaviour, patterns);
return new JsonPathMatcher(matchBehaviour, stringPatterns);
case "XPathMatcher":
return new XPathMatcher(matchBehaviour, matcher.Pattern);
return new XPathMatcher(matchBehaviour, (string) matcher.Pattern);
case "WildcardMatcher":
return new WildcardMatcher(matchBehaviour, patterns, matcher.IgnoreCase == true);
return new WildcardMatcher(matchBehaviour, stringPatterns, matcher.IgnoreCase == true);
case "SimMetricsMatcher":
SimMetricType type = SimMetricType.Levenstein;
@@ -51,7 +51,7 @@ namespace WireMock.Serialization
throw new NotSupportedException($"Matcher '{matcherName}' with Type '{matcherType}' is not supported.");
}
return new SimMetricsMatcher(matchBehaviour, matcher.Pattern, type);
return new SimMetricsMatcher(matchBehaviour, (string) matcher.Pattern, type);
default:
throw new NotSupportedException($"Matcher '{matcherName}' is not supported.");
@@ -70,9 +70,13 @@ namespace WireMock.Serialization
return null;
}
string[] patterns = matcher is IStringMatcher stringMatcher ?
stringMatcher.GetPatterns() :
matcher is IValueMatcher valueMatcher ? new[] { valueMatcher.GetValue() } : new string[0];
// If the matcher is a IStringMatcher, get the patterns.
// If the matcher is a IValueMatcher, get the value (can be string or object).
// Else empty array
object[] patterns = matcher is IStringMatcher stringMatcher ?
stringMatcher.GetPatterns().Cast<object>().ToArray() :
matcher is IValueMatcher valueMatcher ? new[] { valueMatcher.Value } :
new object[0];
bool? ignorecase = matcher is IIgnoreCaseMatcher ignoreCaseMatcher ? ignoreCaseMatcher.IgnoreCase : (bool?)null;
bool? rejectOnMatch = matcher.MatchBehaviour == MatchBehaviour.RejectOnMatch ? true : (bool?)null;

View File

@@ -238,7 +238,11 @@ namespace WireMock.Server
}
});
if (requestMessage.Body != null)
if (requestMessage.BodyAsJson != null)
{
request.WithBody(new JsonMatcher(MatchBehaviour.AcceptOnMatch, requestMessage.BodyAsJson));
}
else if (requestMessage.Body != null)
{
request.WithBody(new ExactMatcher(MatchBehaviour.AcceptOnMatch, requestMessage.Body));
}

View File

@@ -88,7 +88,7 @@ namespace WireMock.Net.Tests
string folder = Path.Combine(GetCurrentFolder(), "__admin", "mappings", guid + ".json");
string json = File.ReadAllText(folder);
string responseBodyFilePath = Path.Combine(GetCurrentFolder(), "ResponseBodyFiles", "responsebody.json");
string responseBodyFilePath = Path.Combine(GetCurrentFolder(), "responsebody.json");
dynamic jsonObj = JsonConvert.DeserializeObject(json);
jsonObj["Response"]["BodyAsFile"] = responseBodyFilePath;

View File

@@ -27,7 +27,7 @@ namespace WireMock.Net.Tests.Matchers
var matcher = new JsonMatcher("{}");
// Act
string value = matcher.GetValue();
object value = matcher.Value;
// Assert
Check.That(value).Equals("{}");
@@ -62,7 +62,39 @@ namespace WireMock.Net.Tests.Matchers
}
[Fact]
public void JsonMatcher_IsMatch_JObject()
public void JsonMatcher_IsMatch_JObject1()
{
// Assign
var matcher = new JsonMatcher(new { Id = 1, Name = "test" });
// Act
var jobject = new JObject
{
{ "Id", new JValue(1) },
{ "Name", new JValue("Test") }
};
double match = matcher.IsMatch(jobject);
// Assert
Assert.Equal(1.0, match);
}
[Fact]
public void JsonMatcher_IsMatch_JObject2()
{
// Assign
var matcher = new JsonMatcher(new { Id = 1, Name = "test" });
// Act
var jobject = JObject.Parse("{ \"Id\" : 1, \"Name\" : \"Test\" }");
double match = matcher.IsMatch(jobject);
// Assert
Assert.Equal(1.0, match);
}
[Fact]
public void JsonMatcher_IsMatch_JObjectAsString()
{
// Assign
var matcher = new JsonMatcher("{ \"Id\" : 1, \"Name\" : \"Test\" }");
@@ -80,7 +112,7 @@ namespace WireMock.Net.Tests.Matchers
}
[Fact]
public void JsonMatcher_IsMatch_JObject_RejectOnMatch()
public void JsonMatcher_IsMatch_JObjectAsString_RejectOnMatch()
{
// Assign
var matcher = new JsonMatcher(MatchBehaviour.RejectOnMatch, "{ \"Id\" : 1, \"Name\" : \"Test\" }");

View File

@@ -31,7 +31,7 @@
</ItemGroup>
<ItemGroup>
<None Update="ResponseBodyFiles\responsebody.json">
<None Update="responsebody.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="__admin\mappings\00000002-ee28-4f29-ae63-1ac9b0802d86.json">