diff --git a/src/WireMock.Net.FluentAssertions/Assertions/WireMockAssertions.cs b/src/WireMock.Net.FluentAssertions/Assertions/WireMockAssertions.cs index 1b7e2fa5..5a08f32f 100644 --- a/src/WireMock.Net.FluentAssertions/Assertions/WireMockAssertions.cs +++ b/src/WireMock.Net.FluentAssertions/Assertions/WireMockAssertions.cs @@ -125,20 +125,27 @@ public partial class WireMockAssertions } [CustomAssertion] - public AndConstraint WithHeader(string expectedKey, string value, string because = "", params object[] becauseArgs) - => WithHeader(expectedKey, new[] { value }, because, becauseArgs); - - [CustomAssertion] - public AndConstraint WithHeader(string expectedKey, string[] expectedValues, string because = "", params object[] becauseArgs) + public AndConstraint WitHeaderKey(string expectedKey, string because = "", params object[] becauseArgs) { using (new AssertionScope("headers from requests sent")) { _headers.Select(h => h.Key).Should().Contain(expectedKey, because, becauseArgs); } + return new AndConstraint(this); + } + + [CustomAssertion] + public AndConstraint WithHeader(string expectedKey, string value, string because = "", params object[] becauseArgs) + => WithHeader(expectedKey, new[] { value }, because, becauseArgs); + + [CustomAssertion] + public AndConstraint WithHeader(string expectedKey, string[] expectedValues, string because = "", params object[] becauseArgs) + { using (new AssertionScope($"header \"{expectedKey}\" from requests sent with value(s)")) { - var matchingHeaderValues = _headers.Where(h => h.Key == expectedKey).SelectMany(h => h.Value.ToArray()).ToArray(); + var matchingHeaderValues = _headers.Where(h => h.Key == expectedKey).SelectMany(h => h.Value.ToArray()) + .ToArray(); if (expectedValues.Length == 1) { @@ -157,6 +164,45 @@ public partial class WireMockAssertions return new AndConstraint(this); } + [CustomAssertion] + public AndConstraint WithoutHeaderKey(string unexpectedKey, string because = "", params object[] becauseArgs) + { + using (new AssertionScope("headers from requests sent")) + { + _headers.Select(h => h.Key).Should().NotContain(unexpectedKey, because, becauseArgs); + } + + return new AndConstraint(this); + } + + [CustomAssertion] + public AndConstraint WithoutHeader(string unexpectedKey, string value, string because = "", params object[] becauseArgs) + => WithoutHeader(unexpectedKey, new[] { value }, because, becauseArgs); + + [CustomAssertion] + public AndConstraint WithoutHeader(string unexpectedKey, string[] expectedValues, string because = "", params object[] becauseArgs) + { + using (new AssertionScope($"header \"{unexpectedKey}\" from requests sent with value(s)")) + { + var matchingHeaderValues = _headers.Where(h => h.Key == unexpectedKey).SelectMany(h => h.Value.ToArray()).ToArray(); + + if (expectedValues.Length == 1) + { + matchingHeaderValues.Should().NotContain(expectedValues.First(), because, becauseArgs); + } + else + { + var trimmedHeaderValues = string.Join(",", matchingHeaderValues.Select(x => x)).Split(',').Select(x => x.Trim()).ToList(); + foreach (var expectedValue in expectedValues) + { + trimmedHeaderValues.Should().NotContain(expectedValue, because, becauseArgs); + } + } + } + + return new AndConstraint(this); + } + private (Func, IReadOnlyList> Filter, Func, bool> Condition) BuildFilterAndCondition(Func predicate) { Func, IReadOnlyList> filter = requests => requests.Where(predicate).ToList(); diff --git a/test/WireMock.Net.Tests/FluentAssertions/WireMockAssertionsTests.cs b/test/WireMock.Net.Tests/FluentAssertions/WireMockAssertionsTests.cs index 49605536..c16fa4b9 100644 --- a/test/WireMock.Net.Tests/FluentAssertions/WireMockAssertionsTests.cs +++ b/test/WireMock.Net.Tests/FluentAssertions/WireMockAssertionsTests.cs @@ -130,6 +130,17 @@ public class WireMockAssertionsTests : IDisposable _httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer a"); await _httpClient.GetAsync("").ConfigureAwait(false); + _server.Should() + .HaveReceivedACall() + .WitHeaderKey("Authorization"); + } + + [Fact] + public async Task HaveReceivedACall_WithHeader_WhenACallWasMadeWithExpectedHeaderWithValue_Should_BeOK() + { + _httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer a"); + await _httpClient.GetAsync("").ConfigureAwait(false); + _server.Should() .HaveReceivedACall() .WithHeader("Authorization", "Bearer a"); @@ -163,7 +174,7 @@ public class WireMockAssertionsTests : IDisposable act.Should().Throw() .And.Message.Should() - .Contain("to contain \"Authorization\"."); + .Contain("\"Authorization\""); } [Fact] @@ -240,8 +251,13 @@ public class WireMockAssertionsTests : IDisposable }); // Assert - server.Should().HaveReceivedACall().WithHeader("Authorization", "Bearer invalidToken"); - server.Should().HaveReceivedACall().WithHeader("Authorization", "Bearer validToken"); + server.Should() + .HaveReceivedACall() + .WithHeader("Authorization", "Bearer invalidToken").And.WithoutHeader("x", "y").And.WithoutHeaderKey("a"); + + server.Should(). + HaveReceivedACall() + .WithHeader("Authorization", "Bearer validToken").And.WithoutHeader("Authorization", "y"); } [Fact]