Skip to content

Commit

Permalink
Merge pull request #138 from WireMock-Net/stef_negate_matcher
Browse files Browse the repository at this point in the history
Added Negate matcher logic
  • Loading branch information
alastairtree authored May 16, 2018
2 parents a8ddd31 + d0e76b3 commit c575ca8
Show file tree
Hide file tree
Showing 12 changed files with 209 additions and 125 deletions.
27 changes: 19 additions & 8 deletions src/WireMock.Net/Matchers/Request/RequestMessageBodyMatcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,27 +105,38 @@ public double GetMatchingScore(RequestMessage requestMessage, RequestMatchResult

private double IsMatch(RequestMessage requestMessage)
{
if (requestMessage.Body != null)
{
if (Matcher is IStringMatcher stringMatcher)
{
return stringMatcher.IsMatch(requestMessage.Body);
}
}

// Check if the matcher is a IObjectMatcher
if (Matcher is IObjectMatcher objectMatcher)
{
// If the body is a JSON object, try to match.
if (requestMessage.BodyAsJson != null)
{
return objectMatcher.IsMatch(requestMessage.BodyAsJson);
}

// If the body is a byte array, try to match.
if (requestMessage.BodyAsBytes != null)
{
return objectMatcher.IsMatch(requestMessage.BodyAsBytes);
}
}

// Check if the matcher is a IStringMatcher
if (Matcher is IStringMatcher stringMatcher)
{
// If the body is a JSON object, try to use Body (string) to match.
if (requestMessage.BodyAsJson != null && requestMessage.Body != null)
{
return stringMatcher.IsMatch(requestMessage.Body);
}

// If the string body is defined, try to match.
if (requestMessage.Body != null)
{
return stringMatcher.IsMatch(requestMessage.Body);
}
}

if (Func != null)
{
return MatchScores.ToScore(requestMessage.Body != null && Func(requestMessage.Body));
Expand Down
41 changes: 2 additions & 39 deletions src/WireMock.Net/RequestMessage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public class RequestMessage
public string RawQuery { get; }

/// <summary>
/// The body as string.
/// The original body as string, this is defined when Body or BodyAsJson are not null.
/// </summary>
public string Body { get; }

Expand Down Expand Up @@ -113,7 +113,7 @@ public class RequestMessage
/// <param name="body">The body.</param>
/// <param name="headers">The headers.</param>
/// <param name="cookies">The cookies.</param>
public RequestMessage([NotNull] Uri url, [NotNull] string method, [NotNull] string clientIP, [CanBeNull] BodyData body, [CanBeNull] IDictionary<string, string[]> headers = null, [CanBeNull] IDictionary<string, string> cookies = null)
public RequestMessage([NotNull] Uri url, [NotNull] string method, [NotNull] string clientIP, [CanBeNull] BodyData body = null, [CanBeNull] IDictionary<string, string[]> headers = null, [CanBeNull] IDictionary<string, string> cookies = null)
{
Check.NotNull(url, nameof(url));
Check.NotNull(method, nameof(method));
Expand All @@ -140,43 +140,6 @@ public RequestMessage([NotNull] Uri url, [NotNull] string method, [NotNull] stri
Query = ParseQuery(RawQuery);
}

/// <summary>
/// Initializes a new instance of the <see cref="RequestMessage"/> class.
/// </summary>
/// <param name="url">The original url.</param>
/// <param name="method">The HTTP method.</param>
/// <param name="clientIP">The client IP Address.</param>
/// <param name="bodyAsBytes">The bodyAsBytes byte[].</param>
/// <param name="body">The body string.</param>
/// <param name="bodyEncoding">The body encoding</param>
/// <param name="headers">The headers.</param>
/// <param name="cookies">The cookies.</param>
public RequestMessage([NotNull] Uri url, [NotNull] string method, [NotNull] string clientIP, [CanBeNull] byte[] bodyAsBytes = null, [CanBeNull] string body = null, [CanBeNull] Encoding bodyEncoding = null, [CanBeNull] IDictionary<string, string[]> headers = null, [CanBeNull] IDictionary<string, string> cookies = null)
{
Check.NotNull(url, nameof(url));
Check.NotNull(method, nameof(method));
Check.NotNull(clientIP, nameof(clientIP));

Url = url.ToString();
Protocol = url.Scheme;
Host = url.Host;
Port = url.Port;
Origin = $"{url.Scheme}://{url.Host}:{url.Port}";
Path = WebUtility.UrlDecode(url.AbsolutePath);
PathSegments = Path.Split('/').Skip(1).ToArray();
Method = method.ToLower();
ClientIP = clientIP;

BodyAsBytes = bodyAsBytes;
Body = body;
BodyEncoding = bodyEncoding;

Headers = headers?.ToDictionary(header => header.Key, header => new WireMockList<string>(header.Value));
Cookies = cookies;
RawQuery = WebUtility.UrlDecode(url.Query);
Query = ParseQuery(RawQuery);
}

private static IDictionary<string, WireMockList<string>> ParseQuery(string queryString)
{
if (string.IsNullOrEmpty(queryString))
Expand Down
2 changes: 1 addition & 1 deletion src/WireMock.Net/Util/BodyData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public class BodyData
public Encoding Encoding { get; set; }

/// <summary>
/// The body as string.
/// The body as string, this is defined when BodyAsString or BodyAsJson are not null.
/// </summary>
public string BodyAsString { get; set; }

Expand Down
1 change: 1 addition & 0 deletions src/WireMock.Net/Util/BodyParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ public static async Task<BodyData> Parse([NotNull] Stream stream, [CanBeNull] st
else if (contentTypeHeaderValue != null && contentTypeHeaderValue.StartsWith("application/json", StringComparison.OrdinalIgnoreCase))
{
var stringData = await ReadStringAsync(stream);
data.BodyAsString = stringData.Item1;
data.Encoding = stringData.Item2;

try
Expand Down
38 changes: 37 additions & 1 deletion test/WireMock.Net.Tests/FluentMockServerTests.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using NFluent;
using WireMock.Matchers;
Expand All @@ -18,6 +20,7 @@ namespace WireMock.Net.Tests
public partial class FluentMockServerTests : IDisposable
{
private FluentMockServer _server;
private static string jsonRequestMessage = @"{ ""message"" : ""Hello server"" }";

// For for AppVeyor + OpenCover
private string GetCurrentFolder()
Expand Down Expand Up @@ -348,6 +351,39 @@ public async Task FluentMockServer_Should_respond_to_request_bodyAsBytes()
Check.That(responseAsBytes).ContainsExactly(new byte[] { 48, 49 });
}

public static IEnumerable<object[]> ValidMatchersForHelloServerJsonMessage =>
new List<object[]>
{
new object[] { new WildcardMatcher("*Hello server*"), "application/json" },
new object[] { new WildcardMatcher("*Hello server*"), "text/plain" },
new object[] { new ExactMatcher(jsonRequestMessage), "application/json" },
new object[] { new ExactMatcher(jsonRequestMessage), "text/plain" },
new object[] { new RegexMatcher("Hello server"), "application/json" },
new object[] { new RegexMatcher("Hello server"), "text/plain" },
new object[] { new JsonPathMatcher("$..[?(@.message == 'Hello server')]"), "application/json" },
new object[] { new JsonPathMatcher("$..[?(@.message == 'Hello server')]"), "text/plain" }
};

[Theory]
[MemberData(nameof(ValidMatchersForHelloServerJsonMessage))]
public async Task FluentMockServer_Should_respond_to_valid_matchers_when_sent_json(IMatcher matcher, string contentType)
{
// Assign
_server = FluentMockServer.Start();

_server
.Given(Request.Create().WithPath("/foo").WithBody(matcher))
.RespondWith(Response.Create().WithBody("Hello client"));

// Act
var content = new StringContent(jsonRequestMessage, Encoding.UTF8, contentType);
var response = await new HttpClient().PostAsync("http://localhost:" + _server.Ports[0] + "/foo", content);

// Assert
var responseString = await response.Content.ReadAsStringAsync();
Check.That(responseString).Equals("Hello client");
}

[Fact]
public async Task FluentMockServer_Should_respond_404_for_unexpected_request()
{
Expand Down Expand Up @@ -569,4 +605,4 @@ public void Dispose()
_serverForProxyForwarding?.Stop();
}
}
}
}
2 changes: 1 addition & 1 deletion test/WireMock.Net.Tests/RequestCookieTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public void Request_WithCookie_OK()
var spec = Request.Create().UsingAnyMethod().WithCookie("session", "a*");

// when
var request = new RequestMessage(new Uri("http://localhost/foo"), "PUT", ClientIp, null, null, null, null, new Dictionary<string, string> { { "session", "abc" } });
var request = new RequestMessage(new Uri("http://localhost/foo"), "PUT", ClientIp, null, null, new Dictionary<string, string> { { "session", "abc" } });

// then
var requestMatchResult = new RequestMatchResult();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,34 @@ public void RequestMessageBodyMatcher_GetMatchingScore_BodyAsJson_IStringMatcher
Check.That(score).IsEqualTo(0.0d);

// Verify
stringMatcherMock.Verify(m => m.IsMatch("b"), Times.Never);
stringMatcherMock.Verify(m => m.IsMatch(It.IsAny<string>()), Times.Never);
}

[Fact]
public void RequestMessageBodyMatcher_GetMatchingScore_BodyAsJson_and_BodyAsString_IStringMatcher()
{
// Assign
var body = new BodyData
{
BodyAsJson = new { value = 42 },
BodyAsString = "orig"
};
var stringMatcherMock = new Mock<IStringMatcher>();
stringMatcherMock.Setup(m => m.IsMatch(It.IsAny<string>())).Returns(0.5d);

var requestMessage = new RequestMessage(new Uri("http://localhost"), "GET", "127.0.0.1", body);

var matcher = new RequestMessageBodyMatcher(stringMatcherMock.Object);

// Act
var result = new RequestMatchResult();
double score = matcher.GetMatchingScore(requestMessage, result);

// Assert
Check.That(score).IsEqualTo(0.5d);

// Verify
stringMatcherMock.Verify(m => m.IsMatch(It.IsAny<string>()), Times.Once);
}

[Fact]
Expand Down
44 changes: 26 additions & 18 deletions test/WireMock.Net.Tests/RequestTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Xunit;
using WireMock.RequestBuilders;
using WireMock.Matchers.Request;
using WireMock.Util;

namespace WireMock.Net.Tests
{
Expand Down Expand Up @@ -33,9 +34,11 @@ public void Should_exclude_requests_not_matching_given_headers()
var spec = Request.Create().UsingAnyMethod().WithHeader("X-toto", "tatata");

// when
string bodyAsString = "whatever";
byte[] body = Encoding.UTF8.GetBytes(bodyAsString);
var request = new RequestMessage(new Uri("http://localhost/foo"), "PUT", ClientIp, body, bodyAsString, Encoding.UTF8, new Dictionary<string, string[]> { { "X-toto", new[] { "tata" } } });
var body = new BodyData
{
BodyAsString = "whatever"
};
var request = new RequestMessage(new Uri("http://localhost/foo"), "PUT", ClientIp, body, new Dictionary<string, string[]> { { "X-toto", new[] { "tata" } } });

// then
var requestMatchResult = new RequestMatchResult();
Expand All @@ -49,9 +52,11 @@ public void Should_exclude_requests_not_matching_given_headers_ignorecase()
var spec = Request.Create().UsingAnyMethod().WithHeader("X-toto", "abc", false);

// when
string bodyAsString = "whatever";
byte[] body = Encoding.UTF8.GetBytes(bodyAsString);
var request = new RequestMessage(new Uri("http://localhost/foo"), "PUT", ClientIp, body, bodyAsString, Encoding.UTF8, new Dictionary<string, string[]> { { "X-toto", new[] { "ABC" } } });
var body = new BodyData
{
BodyAsString = "whatever"
};
var request = new RequestMessage(new Uri("http://localhost/foo"), "PUT", ClientIp, body, new Dictionary<string, string[]> { { "X-toto", new[] { "ABC" } } });

// then
var requestMatchResult = new RequestMatchResult();
Expand All @@ -65,44 +70,47 @@ public void Should_specify_requests_matching_given_header_prefix()
var spec = Request.Create().UsingAnyMethod().WithHeader("X-toto", "tata*");

// when
string bodyAsString = "whatever";
byte[] body = Encoding.UTF8.GetBytes(bodyAsString);
var request = new RequestMessage(new Uri("http://localhost/foo"), "PUT", ClientIp, body, bodyAsString, Encoding.UTF8, new Dictionary<string, string[]> { { "X-toto", new[] { "TaTa" } } });
var body = new BodyData
{
BodyAsString = "whatever"
};
var request = new RequestMessage(new Uri("http://localhost/foo"), "PUT", ClientIp, body, new Dictionary<string, string[]> { { "X-toto", new[] { "TaTa" } } });

// then
var requestMatchResult = new RequestMatchResult();
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
}



[Fact]
public void Should_specify_requests_matching_given_body()
{
// given
var spec = Request.Create().UsingAnyMethod().WithBody("Hello world!");

// when
string bodyAsString = "Hello world!";
byte[] body = Encoding.UTF8.GetBytes(bodyAsString);
var request = new RequestMessage(new Uri("http://localhost/foo"), "PUT", ClientIp, body, bodyAsString, Encoding.UTF8);
var body = new BodyData
{
BodyAsString = "Hello world!"
};
var request = new RequestMessage(new Uri("http://localhost/foo"), "PUT", ClientIp, body);

// then
var requestMatchResult = new RequestMatchResult();
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
}


[Fact]
public void Should_exclude_requests_not_matching_given_body()
{
// given
var spec = Request.Create().UsingAnyMethod().WithBody(" Hello world! ");

// when
string bodyAsString = "xxx";
byte[] body = Encoding.UTF8.GetBytes(bodyAsString);
var request = new RequestMessage(new Uri("http://localhost/foo"), "PUT", ClientIp, body, bodyAsString, Encoding.UTF8, new Dictionary<string, string[]> { { "X-toto", new[] { "tata" } } });
var body = new BodyData
{
BodyAsString = "xxx"
};
var request = new RequestMessage(new Uri("http://localhost/foo"), "PUT", ClientIp, body, new Dictionary<string, string[]> { { "X-toto", new[] { "tata" } } });

// then
var requestMatchResult = new RequestMatchResult();
Expand Down
Loading

0 comments on commit c575ca8

Please sign in to comment.