From 6f11cbfa6114f900e973d903b000877c307a9e21 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Tue, 19 Mar 2024 20:23:58 +0100 Subject: [PATCH 1/4] Fix FluentAssertions (actual body is not displayed in error message) --- .../Assertions/WireMockAssertions.WithBody.cs | 26 ++++++++++-- .../WireMockAssertionsTests.cs | 41 ++++++++++++++++++- 2 files changed, 62 insertions(+), 5 deletions(-) diff --git a/src/WireMock.Net.FluentAssertions/Assertions/WireMockAssertions.WithBody.cs b/src/WireMock.Net.FluentAssertions/Assertions/WireMockAssertions.WithBody.cs index 129c1bab0..02b21f424 100644 --- a/src/WireMock.Net.FluentAssertions/Assertions/WireMockAssertions.WithBody.cs +++ b/src/WireMock.Net.FluentAssertions/Assertions/WireMockAssertions.WithBody.cs @@ -1,6 +1,8 @@ #pragma warning disable CS1591 using System; using System.Collections.Generic; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; using WireMock.Matchers; // ReSharper disable once CheckNamespace @@ -9,7 +11,7 @@ namespace WireMock.FluentAssertions; public partial class WireMockAssertions { private const string MessageFormatNoCalls = "Expected {context:wiremockserver} to have been called using body {0}{reason}, but no calls were made."; - private const string MessageFormat = "Expected {context:wiremockserver} to have been called using body {0}{reason}, but didn't find it among the body {1}."; + private const string MessageFormat = "Expected {context:wiremockserver} to have been called using body {0}{reason}, but didn't find it among the body/bodies {1}."; [CustomAssertion] public AndConstraint WithBody(string body, string because = "", params object[] becauseArgs) @@ -104,14 +106,14 @@ private AndConstraint ExecuteAssertionWithBodyAsIObjectMatch .ForCondition(requests => CallsCount == 0 || requests.Any()) .FailWith( MessageFormatNoCalls, - matcher.Value + FormatBody(matcher.Value) ) .Then .ForCondition(condition) .FailWith( MessageFormat, - _ => matcher.Value, - requests => requests.Select(expression) + _ => FormatBody(matcher.Value), + requests => FormatBodies(requests.Select(expression)) ); FilterRequestMessages(filter); @@ -148,4 +150,20 @@ private AndConstraint ExecuteAssertionWithBodyAsBytesExactOb return new AndConstraint(this); } + + private static string? FormatBody(object? body) + { + return body switch + { + null => null, + JObject jObject => jObject.ToString(Formatting.None), + JToken jToken => jToken.ToString(Formatting.None), + _ => JToken.FromObject(body).ToString(Formatting.None) + }; + } + + private static string? FormatBodies(IEnumerable bodies) + { + return string.Join(", ", bodies.Select(FormatBody)); + } } \ 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 266ef6883..fe5b3adf5 100644 --- a/test/WireMock.Net.Tests/FluentAssertions/WireMockAssertionsTests.cs +++ b/test/WireMock.Net.Tests/FluentAssertions/WireMockAssertionsTests.cs @@ -702,7 +702,11 @@ public async Task HaveReceived1Call_WithBodyAsJson() // Act var httpClient = new HttpClient(); - await httpClient.PostAsync($"{server.Url}/a", new StringContent(@"{ ""x"": ""y"" }")); + var requestBody = new + { + x = "y" + }; + await httpClient.PostAsJsonAsync($"{server.Url}/a", requestBody); // Assert server @@ -740,6 +744,41 @@ public async Task HaveReceived1Call_WithBodyAsJson() server.Stop(); } + [Fact] + public async Task WithBodyAsJson_When_NoMatch_ShouldHaveCorrectErrorMessage() + { + // Arrange + var server = WireMockServer.Start(); + + server + .Given(Request.Create().WithPath("/a").UsingPost().WithBodyAsJson(new { x = "y" })) + .RespondWith(Response.Create().WithBody("A response")); + + // Act + var httpClient = new HttpClient(); + + var requestBody = new + { + x = "123" + }; + await httpClient.PostAsJsonAsync($"{server.Url}/a", requestBody); + + // Assert + Action act = () => server + .Should() + .HaveReceived(1) + .Calls() + .WithBodyAsJson(new { x = "y" }) + .And + .UsingPost(); + + act.Should() + .Throw() + .WithMessage("Expected wiremockserver to have been called using body \"{\"x\":\"y\"}\", but didn't find it among the body/bodies \"{\"x\":\"123\"}\"."); + + server.Stop(); + } + [Fact] public async Task HaveReceived1Call_WithBodyAsBytes() { From fe1ecd21b8efe67853c50af452b5bee01e43ef1c Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Tue, 19 Mar 2024 20:32:57 +0100 Subject: [PATCH 2/4] . --- .../Assertions/WireMockAssertions.WithBody.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WireMock.Net.FluentAssertions/Assertions/WireMockAssertions.WithBody.cs b/src/WireMock.Net.FluentAssertions/Assertions/WireMockAssertions.WithBody.cs index 02b21f424..b6926a709 100644 --- a/src/WireMock.Net.FluentAssertions/Assertions/WireMockAssertions.WithBody.cs +++ b/src/WireMock.Net.FluentAssertions/Assertions/WireMockAssertions.WithBody.cs @@ -162,7 +162,7 @@ private AndConstraint ExecuteAssertionWithBodyAsBytesExactOb }; } - private static string? FormatBodies(IEnumerable bodies) + private static string FormatBodies(IEnumerable bodies) { return string.Join(", ", bodies.Select(FormatBody)); } From 9518ac01018624d2fac9cc02175e3ae0e2a47471 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Wed, 20 Mar 2024 07:54:13 +0100 Subject: [PATCH 3/4] . --- .../Assertions/WireMockAssertions.WithBody.cs | 49 ++++---------- .../Extensions/AnyOfExtensions.cs | 20 +++++- .../WireMockAssertionsTests.cs | 64 ++++++++++++++++++- 3 files changed, 95 insertions(+), 38 deletions(-) diff --git a/src/WireMock.Net.FluentAssertions/Assertions/WireMockAssertions.WithBody.cs b/src/WireMock.Net.FluentAssertions/Assertions/WireMockAssertions.WithBody.cs index b6926a709..906195bed 100644 --- a/src/WireMock.Net.FluentAssertions/Assertions/WireMockAssertions.WithBody.cs +++ b/src/WireMock.Net.FluentAssertions/Assertions/WireMockAssertions.WithBody.cs @@ -1,9 +1,12 @@ #pragma warning disable CS1591 using System; using System.Collections.Generic; +using AnyOfTypes; using Newtonsoft.Json; using Newtonsoft.Json.Linq; +using WireMock.Extensions; using WireMock.Matchers; +using WireMock.Models; // ReSharper disable once CheckNamespace namespace WireMock.FluentAssertions; @@ -58,7 +61,7 @@ public AndConstraint WithBodyAsBytes(ExactObjectMatcher matc { var (filter, condition) = BuildFilterAndCondition(r => r.BodyAsBytes, matcher); - return ExecuteAssertionWithBodyAsBytesExactObjectMatcher(matcher, because, becauseArgs, condition, filter, r => r.BodyAsBytes); + return ExecuteAssertionWithBodyAsIObjectMatcher(matcher, because, becauseArgs, condition, filter, r => r.BodyAsBytes); } private AndConstraint ExecuteAssertionWithBodyStringMatcher( @@ -76,14 +79,14 @@ private AndConstraint ExecuteAssertionWithBodyStringMatcher( .ForCondition(requests => CallsCount == 0 || requests.Any()) .FailWith( MessageFormatNoCalls, - matcher.GetPatterns() + FormatBody(matcher.GetPatterns()) ) .Then .ForCondition(condition) .FailWith( MessageFormat, - _ => matcher.GetPatterns(), - requests => requests.Select(expression) + _ => FormatBody(matcher.GetPatterns()), + requests => FormatBodies(requests.Select(expression)) ); FilterRequestMessages(filter); @@ -121,49 +124,23 @@ private AndConstraint ExecuteAssertionWithBodyAsIObjectMatch return new AndConstraint(this); } - private AndConstraint ExecuteAssertionWithBodyAsBytesExactObjectMatcher( - ExactObjectMatcher matcher, - string because, - object[] becauseArgs, - Func, bool> condition, - Func, IReadOnlyList> filter, - Func expression - ) - { - Execute.Assertion - .BecauseOf(because, becauseArgs) - .Given(() => RequestMessages) - .ForCondition(requests => CallsCount == 0 || requests.Any()) - .FailWith( - MessageFormatNoCalls, - matcher.Value - ) - .Then - .ForCondition(condition) - .FailWith( - MessageFormat, - _ => matcher.Value, - requests => requests.Select(expression) - ); - - FilterRequestMessages(filter); - - return new AndConstraint(this); - } - private static string? FormatBody(object? body) { return body switch { null => null, + string str => str, + AnyOf[] stringPatterns => FormatBodies(stringPatterns.Select(p => p.GetPattern())), + byte[] bytes => $"byte[{bytes.Length}] {{...}}", JObject jObject => jObject.ToString(Formatting.None), JToken jToken => jToken.ToString(Formatting.None), _ => JToken.FromObject(body).ToString(Formatting.None) }; } - private static string FormatBodies(IEnumerable bodies) + private static string? FormatBodies(IEnumerable bodies) { - return string.Join(", ", bodies.Select(FormatBody)); + var valueAsArray = bodies as object[] ?? bodies.ToArray(); + return valueAsArray.Length == 1 ? FormatBody(valueAsArray.First()) : $"[ {string.Join(", ", valueAsArray.Select(FormatBody))} ]"; } } \ No newline at end of file diff --git a/src/WireMock.Net/Extensions/AnyOfExtensions.cs b/src/WireMock.Net/Extensions/AnyOfExtensions.cs index 41a752886..2a580227f 100644 --- a/src/WireMock.Net/Extensions/AnyOfExtensions.cs +++ b/src/WireMock.Net/Extensions/AnyOfExtensions.cs @@ -5,18 +5,36 @@ namespace WireMock.Extensions; -internal static class AnyOfExtensions +/// +/// Some extensions for AnyOf. +/// +public static class AnyOfExtensions { + /// + /// Gets the pattern. + /// + /// AnyOf type + /// string value public static string GetPattern(this AnyOf value) { return value.IsFirst ? value.First : value.Second.Pattern; } + /// + /// Converts a string-patterns to AnyOf patterns. + /// + /// The string patterns + /// The AnyOf patterns public static AnyOf[] ToAnyOfPatterns(this IEnumerable patterns) { return patterns.Select(p => p.ToAnyOfPattern()).ToArray(); } + /// + /// Converts a string-pattern to AnyOf pattern. + /// + /// The string pattern + /// The AnyOf pattern public static AnyOf ToAnyOfPattern(this string pattern) { return new AnyOf(pattern); diff --git a/test/WireMock.Net.Tests/FluentAssertions/WireMockAssertionsTests.cs b/test/WireMock.Net.Tests/FluentAssertions/WireMockAssertionsTests.cs index fe5b3adf5..6bb9d8364 100644 --- a/test/WireMock.Net.Tests/FluentAssertions/WireMockAssertionsTests.cs +++ b/test/WireMock.Net.Tests/FluentAssertions/WireMockAssertionsTests.cs @@ -751,7 +751,7 @@ public async Task WithBodyAsJson_When_NoMatch_ShouldHaveCorrectErrorMessage() var server = WireMockServer.Start(); server - .Given(Request.Create().WithPath("/a").UsingPost().WithBodyAsJson(new { x = "y" })) + .Given(Request.Create().WithPath("/a").UsingPost()) .RespondWith(Response.Create().WithBody("A response")); // Act @@ -779,6 +779,68 @@ public async Task WithBodyAsJson_When_NoMatch_ShouldHaveCorrectErrorMessage() server.Stop(); } + [Fact] + public async Task WithBodyAsString_When_NoMatch_ShouldHaveCorrectErrorMessage() + { + // Arrange + var server = WireMockServer.Start(); + + server + .Given(Request.Create().WithPath("/a").UsingPost()) + .RespondWith(Response.Create().WithBody("A response")); + + // Act + var httpClient = new HttpClient(); + + await httpClient.PostAsync($"{server.Url}/a", new StringContent("123")); + + // Assert + Action act = () => server + .Should() + .HaveReceived(1) + .Calls() + .WithBody("abc") + .And + .UsingPost(); + + act.Should() + .Throw() + .WithMessage("Expected wiremockserver to have been called using body \"abc\", but didn't find it among the body/bodies \"123\"."); + + server.Stop(); + } + + [Fact] + public async Task WithBodyAsBytes_When_NoMatch_ShouldHaveCorrectErrorMessage() + { + // Arrange + var server = WireMockServer.Start(); + + server + .Given(Request.Create().WithPath("/a").UsingPost()) + .RespondWith(Response.Create().WithBody("A response")); + + // Act + var httpClient = new HttpClient(); + + await httpClient.PostAsync($"{server.Url}/a", new ByteArrayContent(new byte[] { 5 })); + + // Assert + Action act = () => server + .Should() + .HaveReceived(1) + .Calls() + .WithBodyAsBytes(new byte[] { 1 }) + .And + .UsingPost(); + + act.Should() + .Throw() + .WithMessage("Expected wiremockserver to have been called using body \"byte[1] {...}\", but didn't find it among the body/bodies \"byte[1] {...}\"."); + + server.Stop(); + } + [Fact] public async Task HaveReceived1Call_WithBodyAsBytes() { From f89750b34acf781e419f7ce5e276e86737190499 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Wed, 20 Mar 2024 08:12:14 +0100 Subject: [PATCH 4/4] raw --- .../Assertions/WireMockAssertions.WithBody.cs | 1 - .../FluentAssertions/WireMockAssertionsTests.cs | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/WireMock.Net.FluentAssertions/Assertions/WireMockAssertions.WithBody.cs b/src/WireMock.Net.FluentAssertions/Assertions/WireMockAssertions.WithBody.cs index 906195bed..b9e364fc3 100644 --- a/src/WireMock.Net.FluentAssertions/Assertions/WireMockAssertions.WithBody.cs +++ b/src/WireMock.Net.FluentAssertions/Assertions/WireMockAssertions.WithBody.cs @@ -132,7 +132,6 @@ private AndConstraint ExecuteAssertionWithBodyAsIObjectMatch string str => str, AnyOf[] stringPatterns => FormatBodies(stringPatterns.Select(p => p.GetPattern())), byte[] bytes => $"byte[{bytes.Length}] {{...}}", - JObject jObject => jObject.ToString(Formatting.None), JToken jToken => jToken.ToString(Formatting.None), _ => JToken.FromObject(body).ToString(Formatting.None) }; diff --git a/test/WireMock.Net.Tests/FluentAssertions/WireMockAssertionsTests.cs b/test/WireMock.Net.Tests/FluentAssertions/WireMockAssertionsTests.cs index 6bb9d8364..455535bcd 100644 --- a/test/WireMock.Net.Tests/FluentAssertions/WireMockAssertionsTests.cs +++ b/test/WireMock.Net.Tests/FluentAssertions/WireMockAssertionsTests.cs @@ -774,7 +774,7 @@ public async Task WithBodyAsJson_When_NoMatch_ShouldHaveCorrectErrorMessage() act.Should() .Throw() - .WithMessage("Expected wiremockserver to have been called using body \"{\"x\":\"y\"}\", but didn't find it among the body/bodies \"{\"x\":\"123\"}\"."); + .WithMessage("""Expected wiremockserver to have been called using body "{"x":"y"}", but didn't find it among the body/bodies "{"x":"123"}"."""); server.Stop(); } @@ -805,7 +805,7 @@ public async Task WithBodyAsString_When_NoMatch_ShouldHaveCorrectErrorMessage() act.Should() .Throw() - .WithMessage("Expected wiremockserver to have been called using body \"abc\", but didn't find it among the body/bodies \"123\"."); + .WithMessage("""Expected wiremockserver to have been called using body "abc", but didn't find it among the body/bodies "123"."""); server.Stop(); } @@ -836,7 +836,7 @@ public async Task WithBodyAsBytes_When_NoMatch_ShouldHaveCorrectErrorMessage() act.Should() .Throw() - .WithMessage("Expected wiremockserver to have been called using body \"byte[1] {...}\", but didn't find it among the body/bodies \"byte[1] {...}\"."); + .WithMessage("""Expected wiremockserver to have been called using body "byte[1] {...}", but didn't find it among the body/bodies "byte[1] {...}"."""); server.Stop(); }