diff --git a/src/WireMock.Net.FluentAssertions/Assertions/WireMockAssertions.cs b/src/WireMock.Net.FluentAssertions/Assertions/WireMockAssertions.cs index 53f9298c..e811e6dc 100644 --- a/src/WireMock.Net.FluentAssertions/Assertions/WireMockAssertions.cs +++ b/src/WireMock.Net.FluentAssertions/Assertions/WireMockAssertions.cs @@ -29,7 +29,7 @@ public class WireMockAssertions "Expected {context:wiremockserver} to have been called at address matching the absolute url {0}{reason}, but no calls were made.", absoluteUrl) .Then - .ForCondition(x => _callsCount == null && x.Any(y => y.AbsoluteUrl == absoluteUrl) || _callsCount == x.Count(y => y.AbsoluteUrl == absoluteUrl)) + .ForCondition(x => (_callsCount == null && x.Any(y => y.AbsoluteUrl == absoluteUrl)) || (_callsCount == x.Count(y => y.AbsoluteUrl == absoluteUrl))) .FailWith( "Expected {context:wiremockserver} to have been called at address matching the absolute url {0}{reason}, but didn't find it among the calls to {1}.", _ => absoluteUrl, requests => requests.Select(request => request.AbsoluteUrl)); @@ -48,7 +48,7 @@ public class WireMockAssertions "Expected {context:wiremockserver} to have been called at address matching the url {0}{reason}, but no calls were made.", url) .Then - .ForCondition(x => _callsCount == null && x.Any(y => y.Url == url) || _callsCount == x.Count(y => y.Url == url)) + .ForCondition(x => (_callsCount == null && x.Any(y => y.Url == url)) || (_callsCount == x.Count(y => y.Url == url))) .FailWith( "Expected {context:wiremockserver} to have been called at address matching the url {0}{reason}, but didn't find it among the calls to {1}.", _ => url, requests => requests.Select(request => request.Url)); @@ -67,7 +67,7 @@ public class WireMockAssertions "Expected {context:wiremockserver} to have been called with proxy url {0}{reason}, but no calls were made.", proxyUrl) .Then - .ForCondition(x => _callsCount == null && x.Any(y => y.ProxyUrl == proxyUrl) || _callsCount == x.Count(y => y.ProxyUrl == proxyUrl)) + .ForCondition(x => (_callsCount == null && x.Any(y => y.ProxyUrl == proxyUrl)) || (_callsCount == x.Count(y => y.ProxyUrl == proxyUrl))) .FailWith( "Expected {context:wiremockserver} to have been called with proxy url {0}{reason}, but didn't find it among the calls with {1}.", _ => proxyUrl, requests => requests.Select(request => request.ProxyUrl)); @@ -86,7 +86,7 @@ public class WireMockAssertions "Expected {context:wiremockserver} to have been called from client IP {0}{reason}, but no calls were made.", clientIP) .Then - .ForCondition(x => _callsCount == null && x.Any(y => y.ClientIP == clientIP) || _callsCount == x.Count(y => y.ClientIP == clientIP)) + .ForCondition(x => (_callsCount == null && x.Any(y => y.ClientIP == clientIP)) || (_callsCount == x.Count(y => y.ClientIP == clientIP))) .FailWith( "Expected {context:wiremockserver} to have been called from client IP {0}{reason}, but didn't find it among the calls from IP(s) {1}.", _ => clientIP, requests => requests.Select(request => request.ClientIP)); @@ -129,4 +129,59 @@ public class WireMockAssertions return new AndConstraint(this); } + + [CustomAssertion] + public AndConstraint UsingConnect(string because = "", params object[] becauseArgs) + => UsingMethod("CONNECT", because, becauseArgs); + + [CustomAssertion] + public AndConstraint UsingDelete(string because = "", params object[] becauseArgs) + => UsingMethod("DELETE", because, becauseArgs); + + [CustomAssertion] + public AndConstraint UsingGet(string because = "", params object[] becauseArgs) + => UsingMethod("GET", because, becauseArgs); + + [CustomAssertion] + public AndConstraint UsingHead(string because = "", params object[] becauseArgs) + => UsingMethod("HEAD", because, becauseArgs); + + [CustomAssertion] + public AndConstraint UsingOptions(string because = "", params object[] becauseArgs) + => UsingMethod("OPTIONS", because, becauseArgs); + + [CustomAssertion] + public AndConstraint UsingPost(string because = "", params object[] becauseArgs) + => UsingMethod("POST", because, becauseArgs); + + [CustomAssertion] + public AndConstraint UsingPatch(string because = "", params object[] becauseArgs) + => UsingMethod("PATCH", because, becauseArgs); + + [CustomAssertion] + public AndConstraint UsingPut(string because = "", params object[] becauseArgs) + => UsingMethod("PUT", because, becauseArgs); + + [CustomAssertion] + public AndConstraint UsingTrace(string because = "", params object[] becauseArgs) + => UsingMethod("TRACE", because, becauseArgs); + + [CustomAssertion] + public AndConstraint UsingMethod(string method, string because = "", params object[] becauseArgs) + { + Execute.Assertion + .BecauseOf(because, becauseArgs) + .Given(() => _subject.LogEntries.Select(x => x.RequestMessage).ToList()) + .ForCondition(requests => requests.Any()) + .FailWith( + "Expected {context:wiremockserver} to have been called using method {0}{reason}, but no calls were made.", + method) + .Then + .ForCondition(x => (_callsCount == null && x.Any(y => y.Method == method)) || (_callsCount == x.Count(y => y.Method == method))) + .FailWith( + "Expected {context:wiremockserver} to have been called using method {0}{reason}, but didn't find it among the methods {1}.", + _ => method, requests => requests.Select(request => request.Method)); + + return new AndConstraint(this); + } } \ No newline at end of file diff --git a/test/WireMock.Net.Tests/FluentAssertions/WireMockAssertionsTests.cs b/test/WireMock.Net.Tests/FluentAssertions/WireMockAssertionsTests.cs index 9dc59780..0767911e 100644 --- a/test/WireMock.Net.Tests/FluentAssertions/WireMockAssertionsTests.cs +++ b/test/WireMock.Net.Tests/FluentAssertions/WireMockAssertionsTests.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using System.Net; using System.Net.Http; using System.Net.Http.Headers; using System.Threading.Tasks; @@ -320,6 +321,156 @@ public class WireMockAssertionsTests : IDisposable $"Expected _server to have been called from client IP \"different-ip\", but didn't find it among the calls from IP(s) {{\"{clientIP}\"}}."); } + [Fact] + public async Task HaveReceivedNoCalls_UsingPost_WhenACallWasNotMadeUsingPost_Should_BeOK() + { + await _httpClient.GetAsync("anyurl").ConfigureAwait(false); + + _server.Should() + .HaveReceivedNoCalls() + .UsingPost(); + } + + [Fact] + public async Task HaveReceived2Calls_UsingDelete_WhenACallWasMadeUsingDelete_Should_BeOK() + { + await _httpClient.DeleteAsync("anyurl").ConfigureAwait(false); + + await _httpClient.DeleteAsync("anyurl").ConfigureAwait(false); + + await _httpClient.GetAsync("anyurl").ConfigureAwait(false); + + _server.Should() + .HaveReceived(2).Calls() + .UsingDelete(); + } + + [Fact] + public void HaveReceivedACall_UsingPatch_Should_ThrowWhenNoCallsWereMade() + { + Action act = () => _server.Should() + .HaveReceivedACall() + .UsingPatch(); + + act.Should().Throw() + .And.Message.Should() + .Be( + "Expected _server to have been called using method \"PATCH\", but no calls were made."); + } + + [Fact] + public async Task HaveReceivedACall_UsingOptions_Should_ThrowWhenCallsWereNotMadeUsingOptions() + { + await _httpClient.PostAsync("anyurl", new StringContent("anycontent")).ConfigureAwait(false); + + Action act = () => _server.Should() + .HaveReceivedACall() + .UsingOptions(); + + act.Should().Throw() + .And.Message.Should() + .Be( + "Expected _server to have been called using method \"OPTIONS\", but didn't find it among the methods {\"POST\"}."); + } + +#if !NET452 + [Fact] + public async Task HaveReceivedACall_UsingConnect_WhenACallWasMadeUsingConnect_Should_BeOK() + { + _server.ResetMappings(); + _server.Given(Request.Create().UsingAnyMethod()) + .RespondWith(Response.Create().WithStatusCode(HttpStatusCode.Found)); + + _httpClient.DefaultRequestHeaders.Add("Host", new Uri(_server.Urls[0]).Authority); + + await _httpClient.SendAsync(new HttpRequestMessage(new HttpMethod("CONNECT"), "anyurl")).ConfigureAwait(false); + + _server.Should() + .HaveReceivedACall() + .UsingConnect(); + } +#endif + + [Fact] + public async Task HaveReceivedACall_UsingDelete_WhenACallWasMadeUsingDelete_Should_BeOK() + { + await _httpClient.SendAsync(new HttpRequestMessage(new HttpMethod("DELETE"), "anyurl")).ConfigureAwait(false); + + _server.Should() + .HaveReceivedACall() + .UsingDelete(); + } + + [Fact] + public async Task HaveReceivedACall_UsingGet_WhenACallWasMadeUsingGet_Should_BeOK() + { + await _httpClient.SendAsync(new HttpRequestMessage(new HttpMethod("GET"), "anyurl")).ConfigureAwait(false); + + _server.Should() + .HaveReceivedACall() + .UsingGet(); + } + + [Fact] + public async Task HaveReceivedACall_UsingHead_WhenACallWasMadeUsingHead_Should_BeOK() + { + await _httpClient.SendAsync(new HttpRequestMessage(new HttpMethod("HEAD"), "anyurl")).ConfigureAwait(false); + + _server.Should() + .HaveReceivedACall() + .UsingHead(); + } + + [Fact] + public async Task HaveReceivedACall_UsingOptions_WhenACallWasMadeUsingOptions_Should_BeOK() + { + await _httpClient.SendAsync(new HttpRequestMessage(new HttpMethod("OPTIONS"), "anyurl")).ConfigureAwait(false); + + _server.Should() + .HaveReceivedACall() + .UsingOptions(); + } + + [Fact] + public async Task HaveReceivedACall_UsingPost_WhenACallWasMadeUsingPost_Should_BeOK() + { + await _httpClient.SendAsync(new HttpRequestMessage(new HttpMethod("POST"), "anyurl")).ConfigureAwait(false); + + _server.Should() + .HaveReceivedACall() + .UsingPost(); + } + + [Fact] + public async Task HaveReceivedACall_UsingPatch_WhenACallWasMadeUsingPatch_Should_BeOK() + { + await _httpClient.SendAsync(new HttpRequestMessage(new HttpMethod("PATCH"), "anyurl")).ConfigureAwait(false); + + _server.Should() + .HaveReceivedACall() + .UsingPatch(); + } + + [Fact] + public async Task HaveReceivedACall_UsingPut_WhenACallWasMadeUsingPut_Should_BeOK() + { + await _httpClient.SendAsync(new HttpRequestMessage(new HttpMethod("PUT"), "anyurl")).ConfigureAwait(false); + + _server.Should() + .HaveReceivedACall() + .UsingPut(); + } + + [Fact] + public async Task HaveReceivedACall_UsingTrace_WhenACallWasMadeUsingTrace_Should_BeOK() + { + await _httpClient.SendAsync(new HttpRequestMessage(new HttpMethod("TRACE"), "anyurl")).ConfigureAwait(false); + + _server.Should() + .HaveReceivedACall() + .UsingTrace(); + } + public void Dispose() { _server?.Stop();