From 609f237b7e2d5913c5d3c221a84e984734aa80c0 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Sun, 22 Dec 2024 16:53:42 +0100 Subject: [PATCH] Add overloads to AtUrl and AtAbsoluteUrl which can use a IStringMatcher --- .../Assertions/WireMockAssertions.AtUrl.cs | 31 ++++++++++-- .../Matchers/MatcherExtensions.cs | 20 ++++++++ .../WireMockAssertionsTests.cs | 48 +++++++++++++++---- 3 files changed, 84 insertions(+), 15 deletions(-) create mode 100644 src/WireMock.Net/Matchers/MatcherExtensions.cs diff --git a/src/WireMock.Net.FluentAssertions/Assertions/WireMockAssertions.AtUrl.cs b/src/WireMock.Net.FluentAssertions/Assertions/WireMockAssertions.AtUrl.cs index 2bbd27fc..b9e7ef14 100644 --- a/src/WireMock.Net.FluentAssertions/Assertions/WireMockAssertions.AtUrl.cs +++ b/src/WireMock.Net.FluentAssertions/Assertions/WireMockAssertions.AtUrl.cs @@ -1,7 +1,8 @@ // Copyright © WireMock.Net #pragma warning disable CS1591 -using System; +using WireMock.Extensions; +using WireMock.Matchers; // ReSharper disable once CheckNamespace namespace WireMock.FluentAssertions; @@ -11,7 +12,17 @@ public partial class WireMockAssertions [CustomAssertion] public AndWhichConstraint AtAbsoluteUrl(string absoluteUrl, string because = "", params object[] becauseArgs) { - var (filter, condition) = BuildFilterAndCondition(request => string.Equals(request.AbsoluteUrl, absoluteUrl, StringComparison.OrdinalIgnoreCase)); + _ = AtAbsoluteUrl(new ExactMatcher(true, absoluteUrl), because, becauseArgs); + + return new AndWhichConstraint(this, absoluteUrl); + } + + [CustomAssertion] + public AndWhichConstraint AtAbsoluteUrl(IStringMatcher absoluteUrlMatcher, string because = "", params object[] becauseArgs) + { + var (filter, condition) = BuildFilterAndCondition(request => absoluteUrlMatcher.IsPerfectMatch(request.AbsoluteUrl)); + + var absoluteUrl = absoluteUrlMatcher.GetPatterns().FirstOrDefault().GetPattern(); Execute.Assertion .BecauseOf(because, becauseArgs) @@ -31,13 +42,23 @@ public AndWhichConstraint AtAbsoluteUrl(string absol FilterRequestMessages(filter); - return new AndWhichConstraint(this, absoluteUrl); + return new AndWhichConstraint(this, absoluteUrlMatcher); } [CustomAssertion] public AndWhichConstraint AtUrl(string url, string because = "", params object[] becauseArgs) { - var (filter, condition) = BuildFilterAndCondition(request => string.Equals(request.Url, url, StringComparison.OrdinalIgnoreCase)); + _ = AtUrl(new ExactMatcher(true, url), because, becauseArgs); + + return new AndWhichConstraint(this, url); + } + + [CustomAssertion] + public AndWhichConstraint AtUrl(IStringMatcher urlMatcher, string because = "", params object[] becauseArgs) + { + var (filter, condition) = BuildFilterAndCondition(request => urlMatcher.IsPerfectMatch(request.Url)); + + var url = urlMatcher.GetPatterns().FirstOrDefault().GetPattern(); Execute.Assertion .BecauseOf(because, becauseArgs) @@ -57,6 +78,6 @@ public AndWhichConstraint AtUrl(string url, string b FilterRequestMessages(filter); - return new AndWhichConstraint(this, url); + return new AndWhichConstraint(this, urlMatcher); } } \ No newline at end of file diff --git a/src/WireMock.Net/Matchers/MatcherExtensions.cs b/src/WireMock.Net/Matchers/MatcherExtensions.cs new file mode 100644 index 00000000..2c085546 --- /dev/null +++ b/src/WireMock.Net/Matchers/MatcherExtensions.cs @@ -0,0 +1,20 @@ +// Copyright © WireMock.Net + +namespace WireMock.Matchers; + +/// +/// Provides some extension methods for matchers. +/// +public static class MatcherExtensions +{ + /// + /// Determines if the match result is a perfect match. + /// + /// The string matcher. + /// The input string to match. + /// true> if the match is perfect; otherwise, false>. + public static bool IsPerfectMatch(this IStringMatcher matcher, string? input) + { + return matcher.IsMatch(input).IsPerfect(); + } +} \ 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 90eab6cc..93148dc3 100644 --- a/test/WireMock.Net.Tests/FluentAssertions/WireMockAssertionsTests.cs +++ b/test/WireMock.Net.Tests/FluentAssertions/WireMockAssertionsTests.cs @@ -102,6 +102,16 @@ public async Task HaveReceivedACall_AtAbsoluteUrl_WhenACallWasMadeToAbsoluteUrl_ { await _httpClient.GetAsync("anyurl").ConfigureAwait(false); + _server.Should() + .HaveReceivedACall() + .AtAbsoluteUrl(new WildcardMatcher($"http://localhost:{_portUsed}/any*")); + } + + [Fact] + public async Task HaveReceivedACall_AtAbsoluteUrlWilcardMAtcher_WhenACallWasMadeToAbsoluteUrl_Should_BeOK() + { + await _httpClient.GetAsync("anyurl").ConfigureAwait(false); + _server.Should() .HaveReceivedACall() .AtAbsoluteUrl($"http://localhost:{_portUsed}/anyurl"); @@ -231,7 +241,7 @@ public async Task HaveReceivedACall_WithHeader_ShouldCheckAllRequests() using var client2 = server.CreateClient(handler); // Act 1 - await client1.SendAsync(new HttpRequestMessage(HttpMethod.Get, "/") + var task1 = client1.SendAsync(new HttpRequestMessage(HttpMethod.Get, "/") { Headers = { @@ -240,7 +250,7 @@ await client1.SendAsync(new HttpRequestMessage(HttpMethod.Get, "/") }); // Act 2 - await client2.SendAsync(new HttpRequestMessage(HttpMethod.Get, "/") + var task2 = client2.SendAsync(new HttpRequestMessage(HttpMethod.Get, "/") { Headers = { @@ -248,6 +258,8 @@ await client2.SendAsync(new HttpRequestMessage(HttpMethod.Get, "/") } }); + await Task.WhenAll(task1, task2); + // Assert server.Should() .HaveReceivedACall() @@ -268,6 +280,16 @@ public async Task HaveReceivedACall_AtUrl_WhenACallWasMadeToUrl_Should_BeOK() .AtUrl($"http://localhost:{_portUsed}/anyurl"); } + [Fact] + public async Task HaveReceivedACall_AtUrlWildcardMatcher_WhenACallWasMadeToUrl_Should_BeOK() + { + await _httpClient.GetAsync("anyurl").ConfigureAwait(false); + + _server.Should() + .HaveReceivedACall() + .AtUrl(new WildcardMatcher($"http://localhost:{_portUsed}/AN*", true)); + } + [Fact] public void HaveReceivedACall_AtUrl_Should_ThrowWhenNoCallsWereMade() { @@ -393,11 +415,14 @@ public async Task HaveReceivedNoCalls_UsingPost_WhenACallWasNotMadeUsingPost_Sho [Fact] public async Task HaveReceived2Calls_UsingDelete_WhenACallWasMadeUsingDelete_Should_BeOK() { - await _httpClient.DeleteAsync("anyurl").ConfigureAwait(false); - - await _httpClient.DeleteAsync("anyurl").ConfigureAwait(false); + var tasks = new[] + { + _httpClient.DeleteAsync("anyurl"), + _httpClient.DeleteAsync("anyurl"), + _httpClient.GetAsync("anyurl") + }; - await _httpClient.GetAsync("anyurl").ConfigureAwait(false); + await Task.WhenAll(tasks); _server.Should() .HaveReceived(2).Calls() @@ -521,11 +546,14 @@ public async Task HaveReceived1Calls_AtAbsoluteUrlUsingPost_ShouldChain() // Act var httpClient = new HttpClient(); - await httpClient.GetAsync($"{server.Url}/a"); - - await httpClient.PostAsync($"{server.Url}/b", new StringContent("B")); + var tasks = new[] + { + httpClient.GetAsync($"{server.Url}/a"), + httpClient.PostAsync($"{server.Url}/b", new StringContent("B")), + httpClient.PostAsync($"{server.Url}/c", new StringContent("C")) + }; - await httpClient.PostAsync($"{server.Url}/c", new StringContent("C")); + await Task.WhenAll(tasks); // Assert server