diff --git a/examples/WireMock.Net.ConsoleApplication/MainApp.cs b/examples/WireMock.Net.ConsoleApplication/MainApp.cs index 206ae130a..1174af95e 100644 --- a/examples/WireMock.Net.ConsoleApplication/MainApp.cs +++ b/examples/WireMock.Net.ConsoleApplication/MainApp.cs @@ -57,12 +57,22 @@ public static void Run() 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 @@ public static void Run() .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 @@ public static void Run() .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 @@ public static void Run() .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 @@ public static void Run() .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)) diff --git a/examples/WireMock.Net.StandAlone.Net452/WireMock.Net.StandAlone.Net452.csproj b/examples/WireMock.Net.StandAlone.Net452/WireMock.Net.StandAlone.Net452.csproj index 1157e0520..9cca970d0 100644 --- a/examples/WireMock.Net.StandAlone.Net452/WireMock.Net.StandAlone.Net452.csproj +++ b/examples/WireMock.Net.StandAlone.Net452/WireMock.Net.StandAlone.Net452.csproj @@ -42,8 +42,18 @@ ..\..\packages\log4net.2.0.8\lib\net45-full\log4net.dll + + ..\..\packages\Microsoft.Owin.Host.HttpListener.4.0.0\lib\net451\Microsoft.Owin.Host.HttpListener.dll + + + ..\..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll + + + + ..\..\packages\Microsoft.AspNet.WebApi.Client.5.2.4\lib\net45\System.Net.Http.Formatting.dll + @@ -53,6 +63,7 @@ + PreserveNewest diff --git a/examples/WireMock.Net.StandAlone.Net452/app.config b/examples/WireMock.Net.StandAlone.Net452/app.config new file mode 100644 index 000000000..dde2c3cc6 --- /dev/null +++ b/examples/WireMock.Net.StandAlone.Net452/app.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/examples/WireMock.Net.StandAlone.Net452/packages.config b/examples/WireMock.Net.StandAlone.Net452/packages.config index a39094923..19875868a 100644 --- a/examples/WireMock.Net.StandAlone.Net452/packages.config +++ b/examples/WireMock.Net.StandAlone.Net452/packages.config @@ -1,4 +1,7 @@  + + + \ No newline at end of file diff --git a/src/WireMock.Net/Admin/Mappings/MatcherModel.cs b/src/WireMock.Net/Admin/Mappings/MatcherModel.cs index 3ffd23d61..e19af2901 100644 --- a/src/WireMock.Net/Admin/Mappings/MatcherModel.cs +++ b/src/WireMock.Net/Admin/Mappings/MatcherModel.cs @@ -11,19 +11,14 @@ public class MatcherModel public string Name { get; set; } /// - /// Gets or sets the value. Used by . + /// Gets or sets the pattern. Can be a string (default) or an object; /// - public string Value { get; set; } + public object Pattern { get; set; } /// - /// Gets or sets the pattern. + /// Gets or sets the patterns. Can be array of strings (default) or an array of objects; /// - public string Pattern { get; set; } - - /// - /// Gets or sets the patterns. - /// - public string[] Patterns { get; set; } + public object[] Patterns { get; set; } /// /// Gets or sets the ignore case. diff --git a/src/WireMock.Net/Matchers/IValueMatcher.cs b/src/WireMock.Net/Matchers/IValueMatcher.cs index 0d21ad129..36426f4f5 100644 --- a/src/WireMock.Net/Matchers/IValueMatcher.cs +++ b/src/WireMock.Net/Matchers/IValueMatcher.cs @@ -7,9 +7,9 @@ public interface IValueMatcher: IObjectMatcher { /// - /// Gets the value. + /// Gets the value (can be a string or an obejct). /// /// Value - string GetValue(); + object Value { get; } } } \ No newline at end of file diff --git a/src/WireMock.Net/Matchers/JsonMatcher.cs b/src/WireMock.Net/Matchers/JsonMatcher.cs index 5e6b734d5..95a88a626 100644 --- a/src/WireMock.Net/Matchers/JsonMatcher.cs +++ b/src/WireMock.Net/Matchers/JsonMatcher.cs @@ -10,7 +10,8 @@ namespace WireMock.Matchers /// public class JsonMatcher : IValueMatcher { - private readonly string _value; + /// + public object Value { get; } /// public string Name => "JsonMatcher"; @@ -21,22 +22,43 @@ public class JsonMatcher : IValueMatcher /// /// Initializes a new instance of the class. /// - /// The value to check for equality. + /// The string value to check for equality. public JsonMatcher([NotNull] string value) : this(MatchBehaviour.AcceptOnMatch, value) { } + /// + /// Initializes a new instance of the class. + /// + /// The object value to check for equality. + public JsonMatcher([NotNull] object value) : this(MatchBehaviour.AcceptOnMatch, value) + { + } + /// /// Initializes a new instance of the class. /// /// The match behaviour. - /// The value to check for equality. + /// The string value to check for equality. public JsonMatcher(MatchBehaviour matchBehaviour, [NotNull] string value) { Check.NotNull(value, nameof(value)); MatchBehaviour = matchBehaviour; - _value = value; + Value = value; + } + + /// + /// Initializes a new instance of the class. + /// + /// The match behaviour. + /// The object value to check for equality. + public JsonMatcher(MatchBehaviour matchBehaviour, [NotNull] object value) + { + Check.NotNull(value, nameof(value)); + + MatchBehaviour = matchBehaviour; + Value = value; } /// @@ -48,9 +70,15 @@ public double IsMatch(object input) 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 @@ public double IsMatch(object input) return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.ToScore(match)); } - - /// - public string GetValue() => _value; } } \ No newline at end of file diff --git a/src/WireMock.Net/Serialization/MatcherMapper.cs b/src/WireMock.Net/Serialization/MatcherMapper.cs index c7475ba8c..2c69104bd 100644 --- a/src/WireMock.Net/Serialization/MatcherMapper.cs +++ b/src/WireMock.Net/Serialization/MatcherMapper.cs @@ -21,28 +21,28 @@ public static IMatcher Map([CanBeNull] MatcherModel matcher) 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().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 @@ public static IMatcher Map([CanBeNull] MatcherModel matcher) 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 @@ public static MatcherModel Map([CanBeNull] IMatcher matcher) 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().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; diff --git a/src/WireMock.Net/Server/FluentMockServer.Admin.cs b/src/WireMock.Net/Server/FluentMockServer.Admin.cs index 1576b4d4e..6146323b3 100644 --- a/src/WireMock.Net/Server/FluentMockServer.Admin.cs +++ b/src/WireMock.Net/Server/FluentMockServer.Admin.cs @@ -238,7 +238,11 @@ private Mapping ToMapping(RequestMessage requestMessage, ResponseMessage respons } }); - 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)); } diff --git a/test/WireMock.Net.Tests/FluentMockServerTests.cs b/test/WireMock.Net.Tests/FluentMockServerTests.cs index 4092c8adf..db3cf277c 100644 --- a/test/WireMock.Net.Tests/FluentMockServerTests.cs +++ b/test/WireMock.Net.Tests/FluentMockServerTests.cs @@ -88,7 +88,7 @@ public void FluentMockServer_ReadStaticMapping_WithResponseBodyFromFile() 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; diff --git a/test/WireMock.Net.Tests/Matchers/JsonMatcherTests.cs b/test/WireMock.Net.Tests/Matchers/JsonMatcherTests.cs index 978fdbb57..14336c3f2 100644 --- a/test/WireMock.Net.Tests/Matchers/JsonMatcherTests.cs +++ b/test/WireMock.Net.Tests/Matchers/JsonMatcherTests.cs @@ -27,7 +27,7 @@ public void JsonMatcher_GetValue() var matcher = new JsonMatcher("{}"); // Act - string value = matcher.GetValue(); + object value = matcher.Value; // Assert Check.That(value).Equals("{}"); @@ -62,7 +62,39 @@ public void JsonMatcher_IsMatch_NullObject() } [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 @@ public void JsonMatcher_IsMatch_JObject() } [Fact] - public void JsonMatcher_IsMatch_JObject_RejectOnMatch() + public void JsonMatcher_IsMatch_JObjectAsString_RejectOnMatch() { // Assign var matcher = new JsonMatcher(MatchBehaviour.RejectOnMatch, "{ \"Id\" : 1, \"Name\" : \"Test\" }"); diff --git a/test/WireMock.Net.Tests/WireMock.Net.Tests.csproj b/test/WireMock.Net.Tests/WireMock.Net.Tests.csproj index e80ec994a..833b03da8 100644 --- a/test/WireMock.Net.Tests/WireMock.Net.Tests.csproj +++ b/test/WireMock.Net.Tests/WireMock.Net.Tests.csproj @@ -31,7 +31,7 @@ - + Always diff --git a/test/WireMock.Net.Tests/ResponseBodyFiles/responsebody.json b/test/WireMock.Net.Tests/responsebody.json similarity index 100% rename from test/WireMock.Net.Tests/ResponseBodyFiles/responsebody.json rename to test/WireMock.Net.Tests/responsebody.json