From 84ae2a58dfafb274f920b5f572f34333e747742f Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Sat, 27 Jul 2024 10:23:38 +0200 Subject: [PATCH] Fix --- .../Matchers/FormUrlEncodedMatcher.cs | 27 +++++-- .../Serialization/MappingConverter.cs | 25 +++--- .../Serialization/MatcherMapper.cs | 7 +- ...ppingBuilderTests.GetMappings.verified.txt | 76 ++++++++++++++++++- ...derTests.ToCSharpCode_Builder.verified.txt | 30 +++++++- ...lderTests.ToCSharpCode_Server.verified.txt | 30 +++++++- .../MappingBuilderTests.ToJson.verified.txt | 74 +++++++++++++++++- .../WireMock.Net.Tests/MappingBuilderTests.cs | 29 ++++--- .../WireMockServerTests.WithBody.cs | 58 ++++++++++++++ 9 files changed, 319 insertions(+), 37 deletions(-) diff --git a/src/WireMock.Net/Matchers/FormUrlEncodedMatcher.cs b/src/WireMock.Net/Matchers/FormUrlEncodedMatcher.cs index 18446d13e..5c669c448 100644 --- a/src/WireMock.Net/Matchers/FormUrlEncodedMatcher.cs +++ b/src/WireMock.Net/Matchers/FormUrlEncodedMatcher.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; using AnyOfTypes; -using JetBrains.Annotations; using Stef.Validation; using WireMock.Models; using WireMock.Util; @@ -34,7 +33,7 @@ public FormUrlEncodedMatcher( AnyOf pattern, bool ignoreCase = false, MatchOperator matchOperator = MatchOperator.Or) : - this(MatchBehaviour.AcceptOnMatch, new[] { pattern }, ignoreCase, matchOperator) + this(MatchBehaviour.AcceptOnMatch, [pattern], ignoreCase, matchOperator) { } @@ -47,10 +46,24 @@ public FormUrlEncodedMatcher( /// The to use. (default = "Or") public FormUrlEncodedMatcher( MatchBehaviour matchBehaviour, - [RegexPattern] AnyOf pattern, + AnyOf pattern, + bool ignoreCase = false, + MatchOperator matchOperator = MatchOperator.Or) : + this(matchBehaviour, [pattern], ignoreCase, matchOperator) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The patterns. + /// Ignore the case from the pattern. + /// The to use. (default = "Or") + public FormUrlEncodedMatcher( + AnyOf[] patterns, bool ignoreCase = false, MatchOperator matchOperator = MatchOperator.Or) : - this(matchBehaviour, new[] { pattern }, ignoreCase, matchOperator) + this(MatchBehaviour.AcceptOnMatch, patterns, ignoreCase, matchOperator) { } @@ -63,7 +76,7 @@ public FormUrlEncodedMatcher( /// The to use. (default = "Or") public FormUrlEncodedMatcher( MatchBehaviour matchBehaviour, - [RegexPattern] AnyOf[] patterns, + AnyOf[] patterns, bool ignoreCase = false, MatchOperator matchOperator = MatchOperator.Or) { @@ -75,7 +88,7 @@ public FormUrlEncodedMatcher( _pairs = new List<(string, string?)>(); foreach (var pattern in _patterns) { - if (!QueryStringParser.TryParse(pattern, IgnoreCase, out var nameValueCollection)) + if (QueryStringParser.TryParse(pattern, IgnoreCase, out var nameValueCollection)) { foreach (var nameValue in nameValueCollection!) { @@ -123,7 +136,7 @@ public virtual AnyOf[] GetPatterns() } /// - public virtual string Name => nameof(RegexMatcher); + public virtual string Name => nameof(FormUrlEncodedMatcher); /// public bool IgnoreCase { get; } diff --git a/src/WireMock.Net/Serialization/MappingConverter.cs b/src/WireMock.Net/Serialization/MappingConverter.cs index 98e6011aa..6de28f4e5 100644 --- a/src/WireMock.Net/Serialization/MappingConverter.cs +++ b/src/WireMock.Net/Serialization/MappingConverter.cs @@ -147,19 +147,22 @@ public string ToCSharpCode(IMapping mapping, MappingConverterSettings? settings { var firstMatcher = requestMessageBodyMatcher.Matchers.FirstOrDefault(); - if (firstMatcher is WildcardMatcher wildcardMatcher && wildcardMatcher.GetPatterns().Any()) + switch (firstMatcher) { - sb.AppendLine($" .WithBody({GetString(wildcardMatcher)})"); - } + case IStringMatcher stringMatcher when stringMatcher.GetPatterns().Any(): + sb.AppendLine($" .WithBody({GetString(stringMatcher)})"); + break; - if (firstMatcher is JsonMatcher jsonMatcher) - { - var matcherType = jsonMatcher.GetType().Name; - sb.AppendLine($" .WithBody(new {matcherType}("); - sb.AppendLine($" value: {ConvertToAnonymousObjectDefinition(jsonMatcher.Value, 3)},"); - sb.AppendLine($" ignoreCase: {ToCSharpBooleanLiteral(jsonMatcher.IgnoreCase)},"); - sb.AppendLine($" regex: {ToCSharpBooleanLiteral(jsonMatcher.Regex)}"); - sb.AppendLine(@" ))"); + case JsonMatcher jsonMatcher: + { + var matcherType = jsonMatcher.GetType().Name; + sb.AppendLine($" .WithBody(new {matcherType}("); + sb.AppendLine($" value: {ConvertToAnonymousObjectDefinition(jsonMatcher.Value, 3)},"); + sb.AppendLine($" ignoreCase: {ToCSharpBooleanLiteral(jsonMatcher.IgnoreCase)},"); + sb.AppendLine($" regex: {ToCSharpBooleanLiteral(jsonMatcher.Regex)}"); + sb.AppendLine(@" ))"); + break; + } } } diff --git a/src/WireMock.Net/Serialization/MatcherMapper.cs b/src/WireMock.Net/Serialization/MatcherMapper.cs index 370c2a572..b4e661946 100644 --- a/src/WireMock.Net/Serialization/MatcherMapper.cs +++ b/src/WireMock.Net/Serialization/MatcherMapper.cs @@ -111,6 +111,9 @@ public MatcherMapper(WireMockServerSettings settings) case nameof(ContentTypeMatcher): return new ContentTypeMatcher(matchBehaviour, stringPatterns, ignoreCase); + case nameof(FormUrlEncodedMatcher): + return new FormUrlEncodedMatcher(matchBehaviour, stringPatterns, ignoreCase); + case nameof(SimMetricsMatcher): SimMetricType type = SimMetricType.Levenstein; if (!string.IsNullOrEmpty(matcherType) && !Enum.TryParse(matcherType, out type)) @@ -224,7 +227,7 @@ private AnyOf[] ParseStringPatterns(MatcherModel matcher) { if (matcher.Pattern is string patternAsString) { - return new[] { new AnyOf(patternAsString) }; + return [new AnyOf(patternAsString)]; } if (matcher.Pattern is IEnumerable patternAsStringArray) @@ -241,7 +244,7 @@ private AnyOf[] ParseStringPatterns(MatcherModel matcher) { var patternAsFile = matcher.PatternAsFile!; var pattern = _settings.FileSystemHandler.ReadFileAsString(patternAsFile); - return new[] { new AnyOf(new StringPattern { Pattern = pattern, PatternAsFile = patternAsFile }) }; + return [new AnyOf(new StringPattern { Pattern = pattern, PatternAsFile = patternAsFile })]; } return EmptyArray>.Value; diff --git a/test/WireMock.Net.Tests/MappingBuilderTests.GetMappings.verified.txt b/test/WireMock.Net.Tests/MappingBuilderTests.GetMappings.verified.txt index 8812a2fff..5c5c98c8c 100644 --- a/test/WireMock.Net.Tests/MappingBuilderTests.GetMappings.verified.txt +++ b/test/WireMock.Net.Tests/MappingBuilderTests.GetMappings.verified.txt @@ -1,6 +1,6 @@ [ { - Guid: Guid_1, + Guid: 41372914-1838-4c67-916b-b9aacdd096ce, UpdatedAt: 2023-01-14 15:16:17, Request: { Path: { @@ -33,7 +33,7 @@ } }, { - Guid: Guid_2, + Guid: 98fae52e-76df-47d9-876f-2ee32e931002, UpdatedAt: 2023-01-14 15:16:17, Request: { Path: { @@ -61,5 +61,77 @@ } }, Response: {} + }, + { + Guid: 98fae52e-76df-47d9-876f-2ee32e931003, + UpdatedAt: 2023-01-14 15:16:17, + Request: { + Path: { + Matchers: [ + { + Name: WildcardMatcher, + Pattern: /form-urlencoded, + IgnoreCase: false + } + ] + }, + Methods: [ + POST + ], + Headers: [ + { + Name: Content-Type, + Matchers: [ + { + Name: WildcardMatcher, + Pattern: application/x-www-form-urlencoded, + IgnoreCase: true + } + ], + IgnoreCase: true + } + ], + Body: { + Matcher: { + Name: FormUrlEncodedMatcher, + Patterns: [ + name=John Doe, + email=johndoe@example.com + ], + IgnoreCase: false, + MatchOperator: Or + } + } + }, + Response: {} + }, + { + Guid: 98fae52e-76df-47d9-876f-2ee32e931001, + UpdatedAt: 2023-01-14 15:16:17, + Request: { + Path: { + Matchers: [ + { + Name: WildcardMatcher, + Pattern: /users/post1, + IgnoreCase: false + } + ] + }, + Methods: [ + POST + ], + Body: { + Matcher: { + Name: JsonMatcher, + Pattern: { + Request: Hello? + }, + IgnoreCase: false, + Regex: false + } + } + }, + Response: {} } ] \ No newline at end of file diff --git a/test/WireMock.Net.Tests/MappingBuilderTests.ToCSharpCode_Builder.verified.txt b/test/WireMock.Net.Tests/MappingBuilderTests.ToCSharpCode_Builder.verified.txt index be439d3bb..17ef2023b 100644 --- a/test/WireMock.Net.Tests/MappingBuilderTests.ToCSharpCode_Builder.verified.txt +++ b/test/WireMock.Net.Tests/MappingBuilderTests.ToCSharpCode_Builder.verified.txt @@ -24,7 +24,35 @@ builder regex: false )) ) - .WithGuid("98fae52e-76df-47d9-876f-2ee32e931d9b") + .WithGuid("98fae52e-76df-47d9-876f-2ee32e931002") + .RespondWith(Response.Create() + ); + +builder + .Given(Request.Create() + .UsingMethod("POST") + .WithPath("/form-urlencoded") + .WithHeader("Content-Type", "application/x-www-form-urlencoded", true) + .WithBody("name=John Doe") + ) + .WithGuid("98fae52e-76df-47d9-876f-2ee32e931003") + .RespondWith(Response.Create() + ); + +builder + .Given(Request.Create() + .UsingMethod("POST") + .WithPath("/users/post1") + .WithBody(new JsonMatcher( + value: new + { + Request = "Hello?" + }, + ignoreCase: false, + regex: false + )) + ) + .WithGuid("98fae52e-76df-47d9-876f-2ee32e931001") .RespondWith(Response.Create() ); diff --git a/test/WireMock.Net.Tests/MappingBuilderTests.ToCSharpCode_Server.verified.txt b/test/WireMock.Net.Tests/MappingBuilderTests.ToCSharpCode_Server.verified.txt index 6091acbd2..c9e10fa18 100644 --- a/test/WireMock.Net.Tests/MappingBuilderTests.ToCSharpCode_Server.verified.txt +++ b/test/WireMock.Net.Tests/MappingBuilderTests.ToCSharpCode_Server.verified.txt @@ -24,7 +24,35 @@ server regex: false )) ) - .WithGuid("98fae52e-76df-47d9-876f-2ee32e931d9b") + .WithGuid("98fae52e-76df-47d9-876f-2ee32e931002") + .RespondWith(Response.Create() + ); + +server + .Given(Request.Create() + .UsingMethod("POST") + .WithPath("/form-urlencoded") + .WithHeader("Content-Type", "application/x-www-form-urlencoded", true) + .WithBody("name=John Doe") + ) + .WithGuid("98fae52e-76df-47d9-876f-2ee32e931003") + .RespondWith(Response.Create() + ); + +server + .Given(Request.Create() + .UsingMethod("POST") + .WithPath("/users/post1") + .WithBody(new JsonMatcher( + value: new + { + Request = "Hello?" + }, + ignoreCase: false, + regex: false + )) + ) + .WithGuid("98fae52e-76df-47d9-876f-2ee32e931001") .RespondWith(Response.Create() ); diff --git a/test/WireMock.Net.Tests/MappingBuilderTests.ToJson.verified.txt b/test/WireMock.Net.Tests/MappingBuilderTests.ToJson.verified.txt index bf66f9df4..20c083465 100644 --- a/test/WireMock.Net.Tests/MappingBuilderTests.ToJson.verified.txt +++ b/test/WireMock.Net.Tests/MappingBuilderTests.ToJson.verified.txt @@ -1,6 +1,6 @@ [ { - Guid: Guid_1, + Guid: 41372914-1838-4c67-916b-b9aacdd096ce, UpdatedAt: 2023-01-14T15:16:17, Request: { Path: { @@ -33,7 +33,7 @@ } }, { - Guid: Guid_2, + Guid: 98fae52e-76df-47d9-876f-2ee32e931002, UpdatedAt: 2023-01-14T15:16:17, Request: { Path: { @@ -60,5 +60,75 @@ } } } + }, + { + Guid: 98fae52e-76df-47d9-876f-2ee32e931003, + UpdatedAt: 2023-01-14T15:16:17, + Request: { + Path: { + Matchers: [ + { + Name: WildcardMatcher, + Pattern: /form-urlencoded, + IgnoreCase: false + } + ] + }, + Methods: [ + POST + ], + Headers: [ + { + Name: Content-Type, + Matchers: [ + { + Name: WildcardMatcher, + Pattern: application/x-www-form-urlencoded, + IgnoreCase: true + } + ], + IgnoreCase: true + } + ], + Body: { + Matcher: { + Name: FormUrlEncodedMatcher, + Patterns: [ + name=John Doe, + email=johndoe@example.com + ], + IgnoreCase: false, + MatchOperator: Or + } + } + } + }, + { + Guid: 98fae52e-76df-47d9-876f-2ee32e931001, + UpdatedAt: 2023-01-14T15:16:17, + Request: { + Path: { + Matchers: [ + { + Name: WildcardMatcher, + Pattern: /users/post1, + IgnoreCase: false + } + ] + }, + Methods: [ + POST + ], + Body: { + Matcher: { + Name: JsonMatcher, + Pattern: { + Request: Hello? + }, + IgnoreCase: false, + Regex: false + } + } + } } ] \ No newline at end of file diff --git a/test/WireMock.Net.Tests/MappingBuilderTests.cs b/test/WireMock.Net.Tests/MappingBuilderTests.cs index 0b798c8ec..6a62af2f0 100644 --- a/test/WireMock.Net.Tests/MappingBuilderTests.cs +++ b/test/WireMock.Net.Tests/MappingBuilderTests.cs @@ -30,7 +30,6 @@ static MappingBuilderTests() VerifySettings.Init(); } - private static readonly Guid NewGuid = new("98fae52e-76df-47d9-876f-2ee32e931d9b"); private const string MappingGuid = "41372914-1838-4c67-916b-b9aacdd096ce"; private static readonly DateTime UtcNow = new(2023, 1, 14, 15, 16, 17); @@ -43,7 +42,8 @@ public MappingBuilderTests() _fileSystemHandlerMock = new Mock(); var guidUtilsMock = new Mock(); - guidUtilsMock.Setup(g => g.NewGuid()).Returns(NewGuid); + var startGuid = 1000; + guidUtilsMock.Setup(g => g.NewGuid()).Returns(() => new Guid($"98fae52e-76df-47d9-876f-2ee32e93{startGuid++}")); var dateTimeUtilsMock = new Mock(); dateTimeUtilsMock.SetupGet(d => d.UtcNow).Returns(UtcNow); @@ -95,6 +95,13 @@ public MappingBuilderTests() country = "The Netherlands" })) ).RespondWith(Response.Create()); + + _sut.Given(Request.Create() + .UsingPost() + .WithPath("/form-urlencoded") + .WithHeader("Content-Type", "application/x-www-form-urlencoded") + .WithBody(new FormUrlEncodedMatcher(["name=John Doe", "email=johndoe@example.com"])) + ).RespondWith(Response.Create()); } [Fact] @@ -104,7 +111,7 @@ public Task GetMappings() var mappings = _sut.GetMappings(); // Verify - return Verifier.Verify(mappings, VerifySettings); + return Verifier.Verify(mappings, VerifySettings).DontScrubGuids(); } [Fact] @@ -114,7 +121,7 @@ public Task ToJson() var json = _sut.ToJson(); // Verify - return Verifier.VerifyJson(json, VerifySettings); + return Verifier.VerifyJson(json, VerifySettings).DontScrubGuids(); } [Fact] @@ -124,7 +131,7 @@ public Task ToCSharpCode_Server() var code = _sut.ToCSharpCode(MappingConverterType.Server); // Verify - return Verifier.Verify(code, VerifySettings); + return Verifier.Verify(code, VerifySettings).DontScrubGuids(); } [Fact] @@ -134,7 +141,7 @@ public Task ToCSharpCode_Builder() var code = _sut.ToCSharpCode(MappingConverterType.Builder); // Verify - return Verifier.Verify(code, VerifySettings); + return Verifier.Verify(code, VerifySettings).DontScrubGuids(); } [Fact] @@ -183,9 +190,9 @@ public void SaveMappingsToFolder_FolderIsNull() _sut.SaveMappingsToFolder(null); // Verify - _fileSystemHandlerMock.Verify(fs => fs.GetMappingFolder(), Times.Exactly(2)); - _fileSystemHandlerMock.Verify(fs => fs.FolderExists(mappingFolder), Times.Exactly(2)); - _fileSystemHandlerMock.Verify(fs => fs.WriteMappingFile(It.IsAny(), It.IsAny()), Times.Exactly(2)); + _fileSystemHandlerMock.Verify(fs => fs.GetMappingFolder(), Times.Exactly(4)); + _fileSystemHandlerMock.Verify(fs => fs.FolderExists(mappingFolder), Times.Exactly(4)); + _fileSystemHandlerMock.Verify(fs => fs.WriteMappingFile(It.IsAny(), It.IsAny()), Times.Exactly(4)); _fileSystemHandlerMock.VerifyNoOtherCalls(); } @@ -201,8 +208,8 @@ public void SaveMappingsToFolder_FolderExists_IsTrue() // Verify _fileSystemHandlerMock.Verify(fs => fs.GetMappingFolder(), Times.Never); - _fileSystemHandlerMock.Verify(fs => fs.FolderExists(path), Times.Exactly(2)); - _fileSystemHandlerMock.Verify(fs => fs.WriteMappingFile(It.IsAny(), It.IsAny()), Times.Exactly(2)); + _fileSystemHandlerMock.Verify(fs => fs.FolderExists(path), Times.Exactly(4)); + _fileSystemHandlerMock.Verify(fs => fs.WriteMappingFile(It.IsAny(), It.IsAny()), Times.Exactly(4)); _fileSystemHandlerMock.VerifyNoOtherCalls(); } } diff --git a/test/WireMock.Net.Tests/WireMockServerTests.WithBody.cs b/test/WireMock.Net.Tests/WireMockServerTests.WithBody.cs index 525e76880..48a6c4ec5 100644 --- a/test/WireMock.Net.Tests/WireMockServerTests.WithBody.cs +++ b/test/WireMock.Net.Tests/WireMockServerTests.WithBody.cs @@ -225,5 +225,63 @@ public async Task WireMockServer_WithBodyAsFormUrlEncoded_Using_PostAsync_And_Wi server.Stop(); } + + [Fact] + public async Task WireMockServer_WithBodyAsFormUrlEncoded_Using_PostAsync_And_WithFormUrlEncodedMatcher() + { + // Arrange + var matcher = new FormUrlEncodedMatcher(["name=John Doe", "email=johndoe@example.com"]); + var server = WireMockServer.Start(); + server.Given( + Request.Create() + .UsingPost() + .WithPath("/foo") + .WithHeader("Content-Type", "application/x-www-form-urlencoded") + .WithBody(matcher) + ) + .RespondWith( + Response.Create() + ); + + server.Given( + Request.Create() + .UsingPost() + .WithPath("/bar") + .WithHeader("Content-Type", "application/x-www-form-urlencoded") + .WithBody(matcher) + ) + .RespondWith( + Response.Create() + ); + + // Act 1 + var contentOrdered = new FormUrlEncodedContent(new[] + { + new KeyValuePair("name", "John Doe"), + new KeyValuePair("email", "johndoe@example.com") + }); + var responseOrdered = await new HttpClient() + .PostAsync($"{server.Url}/foo", contentOrdered) + .ConfigureAwait(false); + + // Assert 1 + responseOrdered.StatusCode.Should().Be(HttpStatusCode.OK); + + + // Act 2 + var contentUnordered = new FormUrlEncodedContent(new[] + { + new KeyValuePair("email", "johndoe@example.com"), + new KeyValuePair("name", "John Doe"), + }); + var responseUnordered = await new HttpClient() + .PostAsync($"{server.Url}/bar", contentUnordered) + .ConfigureAwait(false); + + // Assert 2 + responseUnordered.StatusCode.Should().Be(HttpStatusCode.OK); + + server.Stop(); + } } #endif \ No newline at end of file