Add FormUrlEncodedMatcher (#1147)

* FormUrlEncodedMatcher

* .

* Fix

* new

* support wildcard
This commit is contained in:
Stef Heyenrath
2024-07-27 14:40:23 +02:00
committed by GitHub
parent 926eaaece4
commit 3353be65b5
10 changed files with 530 additions and 30 deletions

View File

@@ -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: {}
}
]

View File

@@ -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()
);

View File

@@ -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()
);

View File

@@ -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
}
}
}
}
]

View File

@@ -30,7 +30,6 @@ public class 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 class MappingBuilderTests
_fileSystemHandlerMock = new Mock<IFileSystemHandler>();
var guidUtilsMock = new Mock<IGuidUtils>();
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<IDateTimeUtils>();
dateTimeUtilsMock.SetupGet(d => d.UtcNow).Returns(UtcNow);
@@ -95,6 +95,13 @@ public class 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 class MappingBuilderTests
var mappings = _sut.GetMappings();
// Verify
return Verifier.Verify(mappings, VerifySettings);
return Verifier.Verify(mappings, VerifySettings).DontScrubGuids();
}
[Fact]
@@ -114,7 +121,7 @@ public class MappingBuilderTests
var json = _sut.ToJson();
// Verify
return Verifier.VerifyJson(json, VerifySettings);
return Verifier.VerifyJson(json, VerifySettings).DontScrubGuids();
}
[Fact]
@@ -124,7 +131,7 @@ public class MappingBuilderTests
var code = _sut.ToCSharpCode(MappingConverterType.Server);
// Verify
return Verifier.Verify(code, VerifySettings);
return Verifier.Verify(code, VerifySettings).DontScrubGuids();
}
[Fact]
@@ -134,7 +141,7 @@ public class MappingBuilderTests
var code = _sut.ToCSharpCode(MappingConverterType.Builder);
// Verify
return Verifier.Verify(code, VerifySettings);
return Verifier.Verify(code, VerifySettings).DontScrubGuids();
}
[Fact]
@@ -183,9 +190,9 @@ public class MappingBuilderTests
_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<string>(), It.IsAny<string>()), 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<string>(), It.IsAny<string>()), Times.Exactly(4));
_fileSystemHandlerMock.VerifyNoOtherCalls();
}
@@ -201,8 +208,8 @@ public class MappingBuilderTests
// Verify
_fileSystemHandlerMock.Verify(fs => fs.GetMappingFolder(), Times.Never);
_fileSystemHandlerMock.Verify(fs => fs.FolderExists(path), Times.Exactly(2));
_fileSystemHandlerMock.Verify(fs => fs.WriteMappingFile(It.IsAny<string>(), It.IsAny<string>()), Times.Exactly(2));
_fileSystemHandlerMock.Verify(fs => fs.FolderExists(path), Times.Exactly(4));
_fileSystemHandlerMock.Verify(fs => fs.WriteMappingFile(It.IsAny<string>(), It.IsAny<string>()), Times.Exactly(4));
_fileSystemHandlerMock.VerifyNoOtherCalls();
}
}

View File

@@ -0,0 +1,78 @@
// Copyright © WireMock.Net
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using AnyOfTypes;
using FluentAssertions;
using WireMock.Matchers;
using WireMock.Models;
using Xunit;
namespace WireMock.Net.Tests.Matchers;
public class FormUrlEncodedMatcherTest
{
[Theory]
[InlineData("*=*")]
[InlineData("name=John Doe")]
[InlineData("name=*")]
[InlineData("*=John Doe")]
[InlineData("email=johndoe@example.com")]
[InlineData("email=*")]
[InlineData("*=johndoe@example.com")]
[InlineData("name=John Doe", "email=johndoe@example.com")]
[InlineData("name=John Doe", "email=*")]
[InlineData("name=*", "email=*")]
[InlineData("*=John Doe", "*=johndoe@example.com")]
public async Task FormUrlEncodedMatcher_IsMatch(params string[] patterns)
{
// Arrange
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("name", "John Doe"),
new KeyValuePair<string, string>("email", "johndoe@example.com")
});
var contentAsString = await content.ReadAsStringAsync();
var matcher = new FormUrlEncodedMatcher(patterns.Select(p => new AnyOf<string, StringPattern>(p)).ToArray());
// Act
var score = matcher.IsMatch(contentAsString).IsPerfect();
// Assert
score.Should().BeTrue();
}
[Theory]
[InlineData(false, "name=John Doe")]
[InlineData(false, "name=*")]
[InlineData(false, "*=John Doe")]
[InlineData(false, "email=johndoe@example.com")]
[InlineData(false, "email=*")]
[InlineData(false, "*=johndoe@example.com")]
[InlineData(true, "name=John Doe", "email=johndoe@example.com")]
[InlineData(true, "name=John Doe", "email=*")]
[InlineData(true, "name=*", "email=*")]
[InlineData(true, "*=John Doe", "*=johndoe@example.com")]
[InlineData(true, "*=*")]
public async Task FormUrlEncodedMatcher_IsMatch_And(bool expected, params string[] patterns)
{
// Arrange
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("name", "John Doe"),
new KeyValuePair<string, string>("email", "johndoe@example.com")
});
var contentAsString = await content.ReadAsStringAsync();
var matcher = new FormUrlEncodedMatcher(patterns.Select(p => new AnyOf<string, StringPattern>(p)).ToArray(), true, MatchOperator.And);
// Act
var score = matcher.IsMatch(contentAsString).IsPerfect();
// Assert
score.Should().Be(expected);
}
}

View File

@@ -225,5 +225,63 @@ public partial class WireMockServerTests
server.Stop();
}
[Fact]
public async Task WireMockServer_WithBodyAsFormUrlEncoded_Using_PostAsync_And_WithFormUrlEncodedMatcher()
{
// Arrange
var matcher = new FormUrlEncodedMatcher(["email=johndoe@example.com", "name=John Doe"]);
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<string, string>("name", "John Doe"),
new KeyValuePair<string, string>("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<string, string>("email", "johndoe@example.com"),
new KeyValuePair<string, string>("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