mirror of
https://github.com/wiremock/WireMock.Net.git
synced 2026-06-12 17:54:27 +02:00
Add MultiPart/MimePart Request Matcher (#981)
* wip * . * mm * x * . * . * . * tests * . * more tests * trans * x * win * fix * . * tests
This commit is contained in:
@@ -111,10 +111,14 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMockAzureQueueExample",
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMockAzureQueueProxy", "examples\WireMockAzureQueueProxy\WireMockAzureQueueProxy.csproj", "{ADB557D8-D66B-4387-912B-3F73E290B478}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMockAzureQueueProxy", "examples\WireMockAzureQueueProxy\WireMockAzureQueueProxy.csproj", "{ADB557D8-D66B-4387-912B-3F73E290B478}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.Testcontainers", "src\WireMock.Net.Testcontainers\WireMock.Net.Testcontainers.csproj", "{12B016A5-9D8B-4EFE-96C2-CA51BE43367D}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WireMock.Net.Testcontainers", "src\WireMock.Net.Testcontainers\WireMock.Net.Testcontainers.csproj", "{12B016A5-9D8B-4EFE-96C2-CA51BE43367D}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.TestcontainersExample", "examples\WireMock.Net.TestcontainersExample\WireMock.Net.TestcontainersExample.csproj", "{56A38798-C48B-4A4A-B805-071E05C02CE1}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.TestcontainersExample", "examples\WireMock.Net.TestcontainersExample\WireMock.Net.TestcontainersExample.csproj", "{56A38798-C48B-4A4A-B805-071E05C02CE1}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{0147029F-FA4A-44B3-B79A-3C3574054EE4}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MultipartUploader", "tools\MultipartUploader\MultipartUploader.csproj", "{07C30227-ADEC-4BDE-8CDC-849D85A690BB}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -277,6 +281,10 @@ Global
|
|||||||
{56A38798-C48B-4A4A-B805-071E05C02CE1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{56A38798-C48B-4A4A-B805-071E05C02CE1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{56A38798-C48B-4A4A-B805-071E05C02CE1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{56A38798-C48B-4A4A-B805-071E05C02CE1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{56A38798-C48B-4A4A-B805-071E05C02CE1}.Release|Any CPU.Build.0 = Release|Any CPU
|
{56A38798-C48B-4A4A-B805-071E05C02CE1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{07C30227-ADEC-4BDE-8CDC-849D85A690BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{07C30227-ADEC-4BDE-8CDC-849D85A690BB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{07C30227-ADEC-4BDE-8CDC-849D85A690BB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{07C30227-ADEC-4BDE-8CDC-849D85A690BB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
@@ -323,6 +331,7 @@ Global
|
|||||||
{ADB557D8-D66B-4387-912B-3F73E290B478} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
|
{ADB557D8-D66B-4387-912B-3F73E290B478} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
|
||||||
{12B016A5-9D8B-4EFE-96C2-CA51BE43367D} = {8F890C6F-9ACC-438D-928A-AD61CDA862F2}
|
{12B016A5-9D8B-4EFE-96C2-CA51BE43367D} = {8F890C6F-9ACC-438D-928A-AD61CDA862F2}
|
||||||
{56A38798-C48B-4A4A-B805-071E05C02CE1} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
|
{56A38798-C48B-4A4A-B805-071E05C02CE1} = {985E0ADB-D4B4-473A-AA40-567E279B7946}
|
||||||
|
{07C30227-ADEC-4BDE-8CDC-849D85A690BB} = {0147029F-FA4A-44B3-B79A-3C3574054EE4}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {DC539027-9852-430C-B19F-FD035D018458}
|
SolutionGuid = {DC539027-9852-430C-B19F-FD035D018458}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<DefineConstants>$(DefineConstants);GRAPHQL;MIMEKIT</DefineConstants>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -29,6 +30,7 @@
|
|||||||
<ProjectReference Include="..\..\src\WireMock.Net\WireMock.Net.csproj" />
|
<ProjectReference Include="..\..\src\WireMock.Net\WireMock.Net.csproj" />
|
||||||
<PackageReference Include="log4net" Version="2.0.15" />
|
<PackageReference Include="log4net" Version="2.0.15" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.0" />
|
||||||
|
<PackageReference Include="MimeKitLite" Version="4.1.0.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ namespace WireMock.Net.ConsoleApplication
|
|||||||
//server.SetAzureADAuthentication("6c2a4722-f3b9-4970-b8fc-fac41e29stef", "8587fde1-7824-42c7-8592-faf92b04stef");
|
//server.SetAzureADAuthentication("6c2a4722-f3b9-4970-b8fc-fac41e29stef", "8587fde1-7824-42c7-8592-faf92b04stef");
|
||||||
|
|
||||||
// server.AllowPartialMapping();
|
// server.AllowPartialMapping();
|
||||||
|
#if GRAPHQL
|
||||||
server
|
server
|
||||||
.Given(Request.Create()
|
.Given(Request.Create()
|
||||||
.WithPath("/graphql")
|
.WithPath("/graphql")
|
||||||
@@ -176,7 +176,41 @@ namespace WireMock.Net.ConsoleApplication
|
|||||||
.RespondWith(Response.Create()
|
.RespondWith(Response.Create()
|
||||||
.WithBody("GraphQL is ok")
|
.WithBody("GraphQL is ok")
|
||||||
);
|
);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MIMEKIT
|
||||||
|
var textPlainContentTypeMatcher = new ContentTypeMatcher("text/plain");
|
||||||
|
var textPlainContentMatcher = new ExactMatcher("This is some plain text");
|
||||||
|
var textPlainMatcher = new MimePartMatcher(MatchBehaviour.AcceptOnMatch, textPlainContentTypeMatcher, null, null, textPlainContentMatcher);
|
||||||
|
|
||||||
|
var textJsonContentTypeMatcher = new ContentTypeMatcher("text/json");
|
||||||
|
var textJsonContentMatcher = new JsonMatcher(new { Key = "Value" }, true);
|
||||||
|
var textJsonMatcher = new MimePartMatcher(MatchBehaviour.AcceptOnMatch, textJsonContentTypeMatcher, null, null, textJsonContentMatcher);
|
||||||
|
|
||||||
|
var imagePngContentTypeMatcher = new ContentTypeMatcher("image/png");
|
||||||
|
var imagePngContentDispositionMatcher = new ExactMatcher("attachment; filename=\"image.png\"");
|
||||||
|
var imagePngContentTransferEncodingMatcher = new ExactMatcher("base64");
|
||||||
|
var imagePngContentMatcher = new ExactObjectMatcher(Convert.FromBase64String("iVBORw0KGgoAAAANSUhEUgAAAAIAAAACAgMAAAAP2OW3AAAADFBMVEX/tID/vpH/pWX/sHidUyjlAAAADElEQVR4XmMQYNgAAADkAMHebX3mAAAAAElFTkSuQmCC"));
|
||||||
|
var imagePngMatcher = new MimePartMatcher(MatchBehaviour.AcceptOnMatch, imagePngContentTypeMatcher, imagePngContentDispositionMatcher, imagePngContentTransferEncodingMatcher, imagePngContentMatcher);
|
||||||
|
|
||||||
|
var matchers = new IMatcher[]
|
||||||
|
{
|
||||||
|
textPlainMatcher,
|
||||||
|
textJsonMatcher,
|
||||||
|
imagePngMatcher
|
||||||
|
};
|
||||||
|
|
||||||
|
server
|
||||||
|
.Given(Request.Create()
|
||||||
|
.WithPath("/multipart")
|
||||||
|
.UsingPost()
|
||||||
|
.WithMultiPart(matchers)
|
||||||
|
)
|
||||||
|
.WithGuid("b9c82182-e469-41da-bcaf-b6e3157fefdb")
|
||||||
|
.RespondWith(Response.Create()
|
||||||
|
.WithBody("MultiPart is ok")
|
||||||
|
);
|
||||||
|
#endif
|
||||||
// 400 ms
|
// 400 ms
|
||||||
server
|
server
|
||||||
.Given(Request.Create()
|
.Given(Request.Create()
|
||||||
@@ -716,8 +750,9 @@ namespace WireMock.Net.ConsoleApplication
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
server.Given(Request.Create().WithPath(new WildcardMatcher("/multi-webhook", true)).UsingPost())
|
server.Given(Request.Create().WithPath(new WildcardMatcher("/multi-webhook", true)).UsingPost())
|
||||||
.WithWebhook(new[] {
|
.WithWebhook
|
||||||
new Webhook()
|
(
|
||||||
|
new Webhook
|
||||||
{
|
{
|
||||||
Request = new WebhookRequest
|
Request = new WebhookRequest
|
||||||
{
|
{
|
||||||
@@ -725,12 +760,13 @@ namespace WireMock.Net.ConsoleApplication
|
|||||||
Method = "post",
|
Method = "post",
|
||||||
BodyData = new BodyData
|
BodyData = new BodyData
|
||||||
{
|
{
|
||||||
BodyAsString = "OK 1!", DetectedBodyType = BodyType.String
|
BodyAsString = "OK 1!",
|
||||||
|
DetectedBodyType = BodyType.String
|
||||||
},
|
},
|
||||||
Delay = 1000
|
Delay = 1000
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new Webhook()
|
new Webhook
|
||||||
{
|
{
|
||||||
Request = new WebhookRequest
|
Request = new WebhookRequest
|
||||||
{
|
{
|
||||||
@@ -745,7 +781,7 @@ namespace WireMock.Net.ConsoleApplication
|
|||||||
MaximumRandomDelay = 7000
|
MaximumRandomDelay = 7000
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
)
|
||||||
.WithWebhookFireAndForget(true)
|
.WithWebhookFireAndForget(true)
|
||||||
.RespondWith(Response.Create().WithBody("a-response"));
|
.RespondWith(Response.Create().WithBody("a-response"));
|
||||||
|
|
||||||
|
|||||||
@@ -39,14 +39,38 @@ public class MatcherModel
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The Operator to use when multiple patterns are defined. Optional.
|
/// The Operator to use when multiple patterns are defined. Optional.
|
||||||
/// - null = Same as "or".
|
/// - null = Same as "or".
|
||||||
/// - "or" = Only one pattern should match.
|
/// - "or" = Only one pattern is required to match.
|
||||||
/// - "and" = All patterns should match.
|
/// - "and" = All patterns should match.
|
||||||
/// - "average" = The average value from all patterns.
|
/// - "average" = The average value from all patterns.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string? MatchOperator { get; set; }
|
public string? MatchOperator { get; set; }
|
||||||
|
|
||||||
|
#region JsonPartialMatcher and JsonPartialWildcardMatcher
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Support Regex, only used for JsonPartialMatcher.
|
/// Support Regex.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool? Regex { get; set; }
|
public bool? Regex { get; set; }
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region MimePartMatcher
|
||||||
|
/// <summary>
|
||||||
|
/// ContentType Matcher (image/png; name=image.png)
|
||||||
|
/// </summary>
|
||||||
|
public MatcherModel? ContentTypeMatcher { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ContentDisposition Matcher (attachment; filename=image.png)
|
||||||
|
/// </summary>
|
||||||
|
public MatcherModel? ContentDispositionMatcher { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ContentTransferEncoding Matcher (base64)
|
||||||
|
/// </summary>
|
||||||
|
public MatcherModel? ContentTransferEncodingMatcher { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Content Matcher
|
||||||
|
/// </summary>
|
||||||
|
public MatcherModel? ContentMatcher { get; set; }
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
@@ -96,32 +96,39 @@ public interface IRequestMessage
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The original body as string. Convenience getter for Handlebars.
|
/// The original body as string. Convenience getter for Handlebars.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string Body { get; }
|
string? Body { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The body (as JSON object). Convenience getter for Handlebars.
|
/// The body (as JSON object). Convenience getter for Handlebars.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
object BodyAsJson { get; }
|
object? BodyAsJson { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The body (as bytearray). Convenience getter for Handlebars.
|
/// The body (as bytearray). Convenience getter for Handlebars.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
byte[] BodyAsBytes { get; }
|
byte[]? BodyAsBytes { get; }
|
||||||
|
|
||||||
|
#if MIMEKIT
|
||||||
|
/// <summary>
|
||||||
|
/// The original body as MimeMessage. Convenience getter for Handlebars.
|
||||||
|
/// </summary>
|
||||||
|
object? BodyAsMimeMessage { get; }
|
||||||
|
#endif
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The detected body type. Convenience getter for Handlebars.
|
/// The detected body type. Convenience getter for Handlebars.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string DetectedBodyType { get; }
|
string? DetectedBodyType { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The detected body type from the Content-Type header. Convenience getter for Handlebars.
|
/// The detected body type from the Content-Type header. Convenience getter for Handlebars.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string DetectedBodyTypeFromContentType { get; }
|
string? DetectedBodyTypeFromContentType { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The detected compression from the Content-Encoding header. Convenience getter for Handlebars.
|
/// The detected compression from the Content-Encoding header. Convenience getter for Handlebars.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string DetectedCompression { get; }
|
string? DetectedCompression { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the Host
|
/// Gets the Host
|
||||||
|
|||||||
@@ -30,6 +30,10 @@
|
|||||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' or '$(TargetFramework)' == 'netstandard2.1'" >
|
||||||
|
<DefineConstants>$(DefineConstants);GRAPHQL;MIMEKIT</DefineConstants>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="JetBrains.Annotations" Version="2022.3.1" PrivateAssets="All" />
|
<PackageReference Include="JetBrains.Annotations" Version="2022.3.1" PrivateAssets="All" />
|
||||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
|
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
|
||||||
|
|||||||
@@ -31,21 +31,14 @@ internal static class HttpRequestMessageHelper
|
|||||||
MediaTypeHeaderValue.TryParse(value, out contentType);
|
MediaTypeHeaderValue.TryParse(value, out contentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (requestMessage.BodyData?.DetectedBodyType)
|
httpRequestMessage.Content = requestMessage.BodyData?.DetectedBodyType switch
|
||||||
{
|
{
|
||||||
case BodyType.Bytes:
|
BodyType.Bytes => ByteArrayContentHelper.Create(requestMessage.BodyData.BodyAsBytes!, contentType),
|
||||||
httpRequestMessage.Content = ByteArrayContentHelper.Create(requestMessage.BodyData.BodyAsBytes!, contentType);
|
BodyType.Json => StringContentHelper.Create(JsonConvert.SerializeObject(requestMessage.BodyData.BodyAsJson), contentType),
|
||||||
break;
|
BodyType.String => StringContentHelper.Create(requestMessage.BodyData.BodyAsString!, contentType),
|
||||||
|
BodyType.FormUrlEncoded => StringContentHelper.Create(requestMessage.BodyData.BodyAsString!, contentType),
|
||||||
case BodyType.Json:
|
_ => httpRequestMessage.Content
|
||||||
httpRequestMessage.Content = StringContentHelper.Create(JsonConvert.SerializeObject(requestMessage.BodyData.BodyAsJson), contentType);
|
};
|
||||||
break;
|
|
||||||
|
|
||||||
case BodyType.String:
|
|
||||||
case BodyType.FormUrlEncoded:
|
|
||||||
httpRequestMessage.Content = StringContentHelper.Create(requestMessage.BodyData.BodyAsString!, contentType);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Overwrite the host header
|
// Overwrite the host header
|
||||||
httpRequestMessage.Headers.Host = new Uri(url).Authority;
|
httpRequestMessage.Headers.Host = new Uri(url).Authority;
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ public class GraphQLMatcher : IStringMatcher
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public MatchOperator MatchOperator { get; }
|
public MatchOperator MatchOperator { get; }
|
||||||
|
|
||||||
/// <inheritdoc cref="IMatcher.Name"/>
|
/// <inheritdoc />
|
||||||
public string Name => nameof(GraphQLMatcher);
|
public string Name => nameof(GraphQLMatcher);
|
||||||
|
|
||||||
private static ISchema BuildSchema(string schema)
|
private static ISchema BuildSchema(string schema)
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
using Stef.Validation;
|
||||||
|
using WireMock.Types;
|
||||||
|
using WireMock.Util;
|
||||||
|
|
||||||
|
namespace WireMock.Matchers.Helpers;
|
||||||
|
|
||||||
|
internal static class BodyDataMatchScoreCalculator
|
||||||
|
{
|
||||||
|
public static double CalculateMatchScore(IBodyData? requestMessage, IMatcher matcher)
|
||||||
|
{
|
||||||
|
Guard.NotNull(matcher);
|
||||||
|
|
||||||
|
if (matcher is NotNullOrEmptyMatcher notNullOrEmptyMatcher)
|
||||||
|
{
|
||||||
|
switch (requestMessage?.DetectedBodyType)
|
||||||
|
{
|
||||||
|
case BodyType.Json:
|
||||||
|
case BodyType.String:
|
||||||
|
case BodyType.FormUrlEncoded:
|
||||||
|
return notNullOrEmptyMatcher.IsMatch(requestMessage.BodyAsString);
|
||||||
|
|
||||||
|
case BodyType.Bytes:
|
||||||
|
return notNullOrEmptyMatcher.IsMatch(requestMessage.BodyAsBytes);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return MatchScores.Mismatch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matcher is ExactObjectMatcher exactObjectMatcher)
|
||||||
|
{
|
||||||
|
// If the body is a byte array, try to match.
|
||||||
|
var detectedBodyType = requestMessage?.DetectedBodyType;
|
||||||
|
if (detectedBodyType is BodyType.Bytes or BodyType.String or BodyType.FormUrlEncoded)
|
||||||
|
{
|
||||||
|
return exactObjectMatcher.IsMatch(requestMessage?.BodyAsBytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the matcher is a IObjectMatcher
|
||||||
|
if (matcher is IObjectMatcher objectMatcher)
|
||||||
|
{
|
||||||
|
// If the body is a JSON object, try to match.
|
||||||
|
if (requestMessage?.DetectedBodyType == BodyType.Json)
|
||||||
|
{
|
||||||
|
return objectMatcher.IsMatch(requestMessage.BodyAsJson);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the body is a byte array, try to match.
|
||||||
|
if (requestMessage?.DetectedBodyType == BodyType.Bytes)
|
||||||
|
{
|
||||||
|
return objectMatcher.IsMatch(requestMessage.BodyAsBytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the matcher is a IStringMatcher
|
||||||
|
if (matcher is IStringMatcher stringMatcher)
|
||||||
|
{
|
||||||
|
// If the body is a Json or a String, use the BodyAsString to match on.
|
||||||
|
if (requestMessage?.DetectedBodyType is BodyType.Json or BodyType.String or BodyType.FormUrlEncoded)
|
||||||
|
{
|
||||||
|
return stringMatcher.IsMatch(requestMessage.BodyAsString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if MIMEKIT_XXX
|
||||||
|
if (matcher is MultiPartMatcher multiPartMatcher)
|
||||||
|
{
|
||||||
|
// If the body is a String or MultiPart, use the BodyAsString to match on.
|
||||||
|
if (requestMessage?.DetectedBodyType is BodyType.String or BodyType.MultiPart)
|
||||||
|
{
|
||||||
|
return multiPartMatcher.IsMatch(requestMessage.BodyAsString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return MatchScores.Mismatch;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
using System;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Linq.Dynamic.Core;
|
using System.Linq.Dynamic.Core;
|
||||||
using AnyOfTypes;
|
using AnyOfTypes;
|
||||||
@@ -122,7 +121,7 @@ public class LinqMatcher : IObjectMatcher, IStringMatcher
|
|||||||
|
|
||||||
return MatchBehaviourHelper.Convert(MatchBehaviour, match);
|
return MatchBehaviourHelper.Convert(MatchBehaviour, match);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch
|
||||||
{
|
{
|
||||||
if (ThrowException)
|
if (ThrowException)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
namespace WireMock.Matchers;
|
namespace WireMock.Matchers;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// MatchBehaviour
|
/// MatchBehaviour (Accept or Reject)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum MatchBehaviour
|
public enum MatchBehaviour
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,125 @@
|
|||||||
|
#if MIMEKIT
|
||||||
|
using System;
|
||||||
|
using MimeKit;
|
||||||
|
using WireMock.Matchers.Helpers;
|
||||||
|
using WireMock.Util;
|
||||||
|
|
||||||
|
namespace WireMock.Matchers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// MimePartMatcher
|
||||||
|
/// </summary>
|
||||||
|
public class MimePartMatcher : IMatcher
|
||||||
|
{
|
||||||
|
private readonly Func<MimePart, double>[] _funcs;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public string Name => nameof(MimePartMatcher);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ContentType Matcher (image/png; name=image.png.)
|
||||||
|
/// </summary>
|
||||||
|
public IStringMatcher? ContentTypeMatcher { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ContentDisposition Matcher (attachment; filename=image.png)
|
||||||
|
/// </summary>
|
||||||
|
public IStringMatcher? ContentDispositionMatcher { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ContentTransferEncoding Matcher (base64)
|
||||||
|
/// </summary>
|
||||||
|
public IStringMatcher? ContentTransferEncodingMatcher { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Content Matcher
|
||||||
|
/// </summary>
|
||||||
|
public IMatcher? ContentMatcher { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public MatchBehaviour MatchBehaviour { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public bool ThrowException { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="MimePartMatcher"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public MimePartMatcher(
|
||||||
|
MatchBehaviour matchBehaviour,
|
||||||
|
IStringMatcher? contentTypeMatcher,
|
||||||
|
IStringMatcher? contentDispositionMatcher,
|
||||||
|
IStringMatcher? contentTransferEncodingMatcher,
|
||||||
|
IMatcher? contentMatcher,
|
||||||
|
bool throwException = false
|
||||||
|
)
|
||||||
|
{
|
||||||
|
MatchBehaviour = matchBehaviour;
|
||||||
|
ContentTypeMatcher = contentTypeMatcher;
|
||||||
|
ContentDispositionMatcher = contentDispositionMatcher;
|
||||||
|
ContentTransferEncodingMatcher = contentTransferEncodingMatcher;
|
||||||
|
ContentMatcher = contentMatcher;
|
||||||
|
ThrowException = throwException;
|
||||||
|
|
||||||
|
_funcs = new[]
|
||||||
|
{
|
||||||
|
mp => ContentTypeMatcher?.IsMatch(GetContentTypeAsString(mp.ContentType)) ?? MatchScores.Perfect,
|
||||||
|
mp => ContentDispositionMatcher?.IsMatch(mp.ContentDisposition.ToString().Replace("Content-Disposition: ", string.Empty)) ?? MatchScores.Perfect,
|
||||||
|
mp => ContentTransferEncodingMatcher?.IsMatch(mp.ContentTransferEncoding.ToString().ToLowerInvariant()) ?? MatchScores.Perfect,
|
||||||
|
MatchOnContent
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether the specified MimePart is match.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="mimePart">The MimePart.</param>
|
||||||
|
/// <returns>A value between 0.0 - 1.0 of the similarity.</returns>
|
||||||
|
public double IsMatch(MimePart mimePart)
|
||||||
|
{
|
||||||
|
var match = MatchScores.Mismatch;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (Array.TrueForAll(_funcs, func => MatchScores.IsPerfect(func(mimePart))))
|
||||||
|
{
|
||||||
|
match = MatchScores.Perfect;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
if (ThrowException)
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return MatchBehaviourHelper.Convert(MatchBehaviour, match);
|
||||||
|
}
|
||||||
|
|
||||||
|
private double MatchOnContent(MimePart mimePart)
|
||||||
|
{
|
||||||
|
if (ContentMatcher == null)
|
||||||
|
{
|
||||||
|
return MatchScores.Perfect;
|
||||||
|
}
|
||||||
|
|
||||||
|
var bodyParserSettings = new BodyParserSettings
|
||||||
|
{
|
||||||
|
Stream = mimePart.Content.Open(),
|
||||||
|
ContentType = GetContentTypeAsString(mimePart.ContentType),
|
||||||
|
DeserializeJson = true,
|
||||||
|
ContentEncoding = null, // mimePart.ContentType.CharsetEncoding.ToString(),
|
||||||
|
DecompressGZipAndDeflate = true
|
||||||
|
};
|
||||||
|
|
||||||
|
var bodyData = BodyParser.ParseAsync(bodyParserSettings).ConfigureAwait(false).GetAwaiter().GetResult();
|
||||||
|
return BodyDataMatchScoreCalculator.CalculateMatchScore(bodyData, ContentMatcher);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string? GetContentTypeAsString(ContentType? contentType)
|
||||||
|
{
|
||||||
|
return contentType?.ToString().Replace("Content-Type: ", string.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -2,7 +2,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Stef.Validation;
|
using Stef.Validation;
|
||||||
using WireMock.Types;
|
using WireMock.Matchers.Helpers;
|
||||||
using WireMock.Util;
|
using WireMock.Util;
|
||||||
|
|
||||||
namespace WireMock.Matchers.Request;
|
namespace WireMock.Matchers.Request;
|
||||||
@@ -149,69 +149,11 @@ public class RequestMessageBodyMatcher : IRequestMatcher
|
|||||||
return requestMatchResult.AddScore(GetType(), score);
|
return requestMatchResult.AddScore(GetType(), score);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static double CalculateMatchScore(IRequestMessage requestMessage, IMatcher matcher)
|
|
||||||
{
|
|
||||||
if (matcher is NotNullOrEmptyMatcher notNullOrEmptyMatcher)
|
|
||||||
{
|
|
||||||
switch (requestMessage.BodyData?.DetectedBodyType)
|
|
||||||
{
|
|
||||||
case BodyType.Json:
|
|
||||||
case BodyType.String:
|
|
||||||
case BodyType.FormUrlEncoded:
|
|
||||||
return notNullOrEmptyMatcher.IsMatch(requestMessage.BodyData.BodyAsString);
|
|
||||||
|
|
||||||
case BodyType.Bytes:
|
|
||||||
return notNullOrEmptyMatcher.IsMatch(requestMessage.BodyData.BodyAsBytes);
|
|
||||||
|
|
||||||
default:
|
|
||||||
return MatchScores.Mismatch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (matcher is ExactObjectMatcher exactObjectMatcher)
|
|
||||||
{
|
|
||||||
// If the body is a byte array, try to match.
|
|
||||||
var detectedBodyType = requestMessage.BodyData?.DetectedBodyType;
|
|
||||||
if (detectedBodyType is BodyType.Bytes or BodyType.String or BodyType.FormUrlEncoded)
|
|
||||||
{
|
|
||||||
return exactObjectMatcher.IsMatch(requestMessage.BodyData?.BodyAsBytes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the matcher is a IObjectMatcher
|
|
||||||
if (matcher is IObjectMatcher objectMatcher)
|
|
||||||
{
|
|
||||||
// If the body is a JSON object, try to match.
|
|
||||||
if (requestMessage?.BodyData?.DetectedBodyType == BodyType.Json)
|
|
||||||
{
|
|
||||||
return objectMatcher.IsMatch(requestMessage.BodyData.BodyAsJson);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the body is a byte array, try to match.
|
|
||||||
if (requestMessage?.BodyData?.DetectedBodyType == BodyType.Bytes)
|
|
||||||
{
|
|
||||||
return objectMatcher.IsMatch(requestMessage.BodyData.BodyAsBytes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the matcher is a IStringMatcher
|
|
||||||
if (matcher is IStringMatcher stringMatcher)
|
|
||||||
{
|
|
||||||
// If the body is a Json or a String, use the BodyAsString to match on.
|
|
||||||
if (requestMessage?.BodyData?.DetectedBodyType is BodyType.Json or BodyType.String or BodyType.FormUrlEncoded)
|
|
||||||
{
|
|
||||||
return stringMatcher.IsMatch(requestMessage.BodyData.BodyAsString);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return MatchScores.Mismatch;
|
|
||||||
}
|
|
||||||
|
|
||||||
private double CalculateMatchScore(IRequestMessage requestMessage)
|
private double CalculateMatchScore(IRequestMessage requestMessage)
|
||||||
{
|
{
|
||||||
if (Matchers != null)
|
if (Matchers != null)
|
||||||
{
|
{
|
||||||
var matchersResult = Matchers.Select(matcher => CalculateMatchScore(requestMessage, matcher)).ToArray();
|
var matchersResult = Matchers.Select(matcher => BodyDataMatchScoreCalculator.CalculateMatchScore(requestMessage.BodyData, matcher)).ToArray();
|
||||||
return MatchScores.ToScore(matchersResult, MatchOperator);
|
return MatchScores.ToScore(matchersResult, MatchOperator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ public class RequestMessageGraphQLMatcher : IRequestMatcher
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="RequestMessageGraphQLMatcher"/> class.
|
/// Initializes a new instance of the <see cref="RequestMessageGraphQLMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -0,0 +1,99 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Stef.Validation;
|
||||||
|
using WireMock.Http;
|
||||||
|
using WireMock.Util;
|
||||||
|
|
||||||
|
namespace WireMock.Matchers.Request;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The request body MultiPart matcher.
|
||||||
|
/// </summary>
|
||||||
|
public class RequestMessageMultiPartMatcher : IRequestMatcher
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The matchers.
|
||||||
|
/// </summary>
|
||||||
|
public IMatcher[]? Matchers { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="MatchOperator"/>
|
||||||
|
/// </summary>
|
||||||
|
public MatchOperator MatchOperator { get; } = MatchOperator.Or;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="MatchBehaviour"/>
|
||||||
|
/// </summary>
|
||||||
|
public MatchBehaviour MatchBehaviour { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="RequestMessageMultiPartMatcher"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="matchers">The matchers.</param>
|
||||||
|
public RequestMessageMultiPartMatcher(params IMatcher[] matchers)
|
||||||
|
{
|
||||||
|
Matchers = Guard.NotNull(matchers);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="RequestMessageMultiPartMatcher"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="matchBehaviour">The match behaviour.</param>
|
||||||
|
/// <param name="matchOperator">The <see cref="MatchOperator"/> to use.</param>
|
||||||
|
/// <param name="matchers">The matchers.</param>
|
||||||
|
public RequestMessageMultiPartMatcher(MatchBehaviour matchBehaviour, MatchOperator matchOperator, params IMatcher[] matchers)
|
||||||
|
{
|
||||||
|
Matchers = Guard.NotNull(matchers);
|
||||||
|
MatchBehaviour = matchBehaviour;
|
||||||
|
MatchOperator = matchOperator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
|
||||||
|
{
|
||||||
|
#if !MIMEKIT
|
||||||
|
throw new System.NotSupportedException("The MultiPartMatcher can not be used for .NETStandard1.3 or .NET Framework 4.6.1 or lower.");
|
||||||
|
#else
|
||||||
|
var match = MatchScores.Mismatch;
|
||||||
|
|
||||||
|
if (Matchers?.Any() != true)
|
||||||
|
{
|
||||||
|
return requestMatchResult.AddScore(GetType(), match);
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var message = MimeKitUtils.GetMimeMessage(requestMessage.BodyData!, requestMessage.Headers![HttpKnownHeaderNames.ContentType].ToString());
|
||||||
|
|
||||||
|
var mimePartMatchers = Matchers.OfType<MimePartMatcher>().ToArray();
|
||||||
|
|
||||||
|
foreach (var mimePart in message.BodyParts.OfType<MimeKit.MimePart>())
|
||||||
|
{
|
||||||
|
var matchesForMimePart = new List<double> { MatchScores.Mismatch };
|
||||||
|
matchesForMimePart.AddRange(mimePartMatchers.Select(matcher => matcher.IsMatch(mimePart)));
|
||||||
|
|
||||||
|
match = matchesForMimePart.Max();
|
||||||
|
|
||||||
|
if (MatchScores.IsPerfect(match))
|
||||||
|
{
|
||||||
|
if (MatchOperator == MatchOperator.Or)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
match = MatchScores.Mismatch;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Empty
|
||||||
|
}
|
||||||
|
|
||||||
|
return requestMatchResult.AddScore(GetType(), match);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -29,17 +29,13 @@ namespace WireMock.Owin.Mappers
|
|||||||
|
|
||||||
var headers = new Dictionary<string, string[]>();
|
var headers = new Dictionary<string, string[]>();
|
||||||
IEnumerable<string>? contentEncodingHeader = null;
|
IEnumerable<string>? contentEncodingHeader = null;
|
||||||
if (request.Headers.Any())
|
foreach (var header in request.Headers)
|
||||||
{
|
{
|
||||||
headers = new Dictionary<string, string[]>();
|
headers.Add(header.Key, header.Value!);
|
||||||
foreach (var header in request.Headers)
|
|
||||||
{
|
|
||||||
headers.Add(header.Key, header.Value);
|
|
||||||
|
|
||||||
if (string.Equals(header.Key, HttpKnownHeaderNames.ContentEncoding, StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(header.Key, HttpKnownHeaderNames.ContentEncoding, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
contentEncodingHeader = header.Value;
|
contentEncodingHeader = header.Value;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
using WireMock.Matchers;
|
using WireMock.Matchers;
|
||||||
using WireMock.Matchers.Request;
|
|
||||||
|
|
||||||
namespace WireMock.RequestBuilders;
|
namespace WireMock.RequestBuilders;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The GraphQLRequestBuilder interface.
|
/// The GraphQLRequestBuilder interface.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IGraphQLRequestBuilder : IRequestMatcher
|
public interface IGraphQLRequestBuilder : IMultiPartRequestBuilder
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// WithGraphQLSchema: The GraphQL schema as a string.
|
/// WithGraphQLSchema: The GraphQL schema as a string.
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
using System;
|
|
||||||
using JetBrains.Annotations;
|
|
||||||
using WireMock.Matchers;
|
using WireMock.Matchers;
|
||||||
|
|
||||||
namespace WireMock.RequestBuilders;
|
namespace WireMock.RequestBuilders;
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
using WireMock.Matchers;
|
||||||
|
using WireMock.Matchers.Request;
|
||||||
|
|
||||||
|
namespace WireMock.RequestBuilders;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The MultiPartRequestBuilder interface.
|
||||||
|
/// </summary>
|
||||||
|
public interface IMultiPartRequestBuilder : IRequestMatcher
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// WithMultiPart: IMatcher
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="matcher">The matcher.</param>
|
||||||
|
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
|
||||||
|
IRequestBuilder WithMultiPart(IMatcher matcher);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// WithMultiPart: IMatcher[], MatchBehaviour and MatchOperator
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="matchers">The matchers.</param>
|
||||||
|
/// <param name="matchBehaviour">The <see cref="MatchBehaviour"/> to use.</param>
|
||||||
|
/// <param name="matchOperator">The <see cref="MatchOperator"/> to use.</param>
|
||||||
|
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
|
||||||
|
IRequestBuilder WithMultiPart(IMatcher[] matchers, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch, MatchOperator matchOperator = MatchOperator.Or);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// WithMultiPart: MatchBehaviour and IMatcher[]
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="matchBehaviour">The <see cref="MatchBehaviour"/> to use.</param>
|
||||||
|
/// <param name="matchers">The matchers.</param>
|
||||||
|
/// <returns>The <see cref="IRequestBuilder"/>.</returns>
|
||||||
|
IRequestBuilder WithMultiPart(MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch, params IMatcher[] matchers);
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
using WireMock.Matchers;
|
||||||
|
using WireMock.Matchers.Request;
|
||||||
|
|
||||||
|
namespace WireMock.RequestBuilders;
|
||||||
|
|
||||||
|
public partial class Request
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public IRequestBuilder WithMultiPart(IMatcher matcher)
|
||||||
|
{
|
||||||
|
_requestMatchers.Add(new RequestMessageMultiPartMatcher(matcher));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public IRequestBuilder WithMultiPart(IMatcher[] matchers, MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch, MatchOperator matchOperator = MatchOperator.Or)
|
||||||
|
{
|
||||||
|
_requestMatchers.Add(new RequestMessageMultiPartMatcher(matchBehaviour, matchOperator, matchers));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public IRequestBuilder WithMultiPart(MatchBehaviour matchBehaviour = MatchBehaviour.AcceptOnMatch, params IMatcher[] matchers)
|
||||||
|
{
|
||||||
|
_requestMatchers.Add(new RequestMessageMultiPartMatcher(matchBehaviour, MatchOperator.Or, matchers));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ using System.Net;
|
|||||||
using System.Security.Cryptography.X509Certificates;
|
using System.Security.Cryptography.X509Certificates;
|
||||||
#endif
|
#endif
|
||||||
using Stef.Validation;
|
using Stef.Validation;
|
||||||
|
using WireMock.Http;
|
||||||
using WireMock.Models;
|
using WireMock.Models;
|
||||||
using WireMock.Owin;
|
using WireMock.Owin;
|
||||||
using WireMock.Types;
|
using WireMock.Types;
|
||||||
@@ -20,40 +21,40 @@ namespace WireMock;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class RequestMessage : IRequestMessage
|
public class RequestMessage : IRequestMessage
|
||||||
{
|
{
|
||||||
/// <inheritdoc cref="IRequestMessage.ClientIP" />
|
/// <inheritdoc />
|
||||||
public string ClientIP { get; }
|
public string ClientIP { get; }
|
||||||
|
|
||||||
/// <inheritdoc cref="IRequestMessage.Url" />
|
/// <inheritdoc />
|
||||||
public string Url { get; }
|
public string Url { get; }
|
||||||
|
|
||||||
/// <inheritdoc cref="IRequestMessage.AbsoluteUrl" />
|
/// <inheritdoc />
|
||||||
public string AbsoluteUrl { get; }
|
public string AbsoluteUrl { get; }
|
||||||
|
|
||||||
/// <inheritdoc cref="IRequestMessage.ProxyUrl" />
|
/// <inheritdoc />
|
||||||
public string? ProxyUrl { get; set; }
|
public string? ProxyUrl { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc cref="IRequestMessage.DateTime" />
|
/// <inheritdoc />
|
||||||
public DateTime DateTime { get; set; }
|
public DateTime DateTime { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc cref="IRequestMessage.Path" />
|
/// <inheritdoc />
|
||||||
public string Path { get; }
|
public string Path { get; }
|
||||||
|
|
||||||
/// <inheritdoc cref="IRequestMessage.AbsolutePath" />
|
/// <inheritdoc />
|
||||||
public string AbsolutePath { get; }
|
public string AbsolutePath { get; }
|
||||||
|
|
||||||
/// <inheritdoc cref="IRequestMessage.PathSegments" />
|
/// <inheritdoc />
|
||||||
public string[] PathSegments { get; }
|
public string[] PathSegments { get; }
|
||||||
|
|
||||||
/// <inheritdoc cref="IRequestMessage.AbsolutePathSegments" />
|
/// <inheritdoc />
|
||||||
public string[] AbsolutePathSegments { get; }
|
public string[] AbsolutePathSegments { get; }
|
||||||
|
|
||||||
/// <inheritdoc cref="IRequestMessage.Method" />
|
/// <inheritdoc />
|
||||||
public string Method { get; }
|
public string Method { get; }
|
||||||
|
|
||||||
/// <inheritdoc cref="IRequestMessage.Headers" />
|
/// <inheritdoc />
|
||||||
public IDictionary<string, WireMockList<string>>? Headers { get; }
|
public IDictionary<string, WireMockList<string>>? Headers { get; }
|
||||||
|
|
||||||
/// <inheritdoc cref="IRequestMessage.Cookies" />
|
/// <inheritdoc />
|
||||||
public IDictionary<string, string>? Cookies { get; }
|
public IDictionary<string, string>? Cookies { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -61,45 +62,50 @@ public class RequestMessage : IRequestMessage
|
|||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IDictionary<string, WireMockList<string>>? QueryIgnoreCase { get; }
|
public IDictionary<string, WireMockList<string>>? QueryIgnoreCase { get; }
|
||||||
|
|
||||||
/// <inheritdoc cref="IRequestMessage.RawQuery" />
|
/// <inheritdoc />
|
||||||
public string RawQuery { get; }
|
public string RawQuery { get; }
|
||||||
|
|
||||||
/// <inheritdoc cref="IRequestMessage.BodyData" />
|
/// <inheritdoc />
|
||||||
public IBodyData? BodyData { get; }
|
public IBodyData? BodyData { get; }
|
||||||
|
|
||||||
/// <inheritdoc cref="IRequestMessage.Body" />
|
/// <inheritdoc />
|
||||||
public string Body { get; }
|
public string? Body { get; }
|
||||||
|
|
||||||
/// <inheritdoc cref="IRequestMessage.BodyAsJson" />
|
/// <inheritdoc />
|
||||||
public object BodyAsJson { get; }
|
public object? BodyAsJson { get; }
|
||||||
|
|
||||||
/// <inheritdoc cref="IRequestMessage.BodyAsBytes" />
|
/// <inheritdoc />
|
||||||
public byte[] BodyAsBytes { get; }
|
public byte[]? BodyAsBytes { get; }
|
||||||
|
|
||||||
/// <inheritdoc cref="IRequestMessage.DetectedBodyType" />
|
#if MIMEKIT
|
||||||
public string DetectedBodyType { get; }
|
/// <inheritdoc />
|
||||||
|
public object? BodyAsMimeMessage { get; }
|
||||||
|
#endif
|
||||||
|
|
||||||
/// <inheritdoc cref="IRequestMessage.DetectedBodyTypeFromContentType" />
|
/// <inheritdoc />
|
||||||
public string DetectedBodyTypeFromContentType { get; }
|
public string? DetectedBodyType { get; }
|
||||||
|
|
||||||
/// <inheritdoc cref="IRequestMessage.DetectedCompression" />
|
/// <inheritdoc />
|
||||||
public string DetectedCompression { get; }
|
public string? DetectedBodyTypeFromContentType { get; }
|
||||||
|
|
||||||
/// <inheritdoc cref="IRequestMessage.Host" />
|
/// <inheritdoc />
|
||||||
|
public string? DetectedCompression { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public string Host { get; }
|
public string Host { get; }
|
||||||
|
|
||||||
/// <inheritdoc cref="IRequestMessage.Protocol" />
|
/// <inheritdoc />
|
||||||
public string Protocol { get; }
|
public string Protocol { get; }
|
||||||
|
|
||||||
/// <inheritdoc cref="IRequestMessage.Port" />
|
/// <inheritdoc />
|
||||||
public int Port { get; }
|
public int Port { get; }
|
||||||
|
|
||||||
/// <inheritdoc cref="IRequestMessage.Origin" />
|
/// <inheritdoc />
|
||||||
public string Origin { get; }
|
public string Origin { get; }
|
||||||
|
|
||||||
#if USE_ASPNETCORE
|
#if USE_ASPNETCORE
|
||||||
/// <inheritdoc cref="IRequestMessage.ClientCertificate" />
|
/// <inheritdoc />
|
||||||
public X509Certificate2? ClientCertificate { get; }
|
public X509Certificate2? ClientCertificate { get; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -139,11 +145,11 @@ public class RequestMessage : IRequestMessage
|
|||||||
#if USE_ASPNETCORE
|
#if USE_ASPNETCORE
|
||||||
, X509Certificate2? clientCertificate = null
|
, X509Certificate2? clientCertificate = null
|
||||||
#endif
|
#endif
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
Guard.NotNull(urlDetails, nameof(urlDetails));
|
Guard.NotNull(urlDetails);
|
||||||
Guard.NotNull(method, nameof(method));
|
Guard.NotNull(method);
|
||||||
Guard.NotNull(clientIP, nameof(clientIP));
|
Guard.NotNull(clientIP);
|
||||||
|
|
||||||
AbsoluteUrl = urlDetails.AbsoluteUrl.ToString();
|
AbsoluteUrl = urlDetails.AbsoluteUrl.ToString();
|
||||||
Url = urlDetails.Url.ToString();
|
Url = urlDetails.Url.ToString();
|
||||||
@@ -166,10 +172,22 @@ public class RequestMessage : IRequestMessage
|
|||||||
Body = BodyData?.BodyAsString;
|
Body = BodyData?.BodyAsString;
|
||||||
BodyAsJson = BodyData?.BodyAsJson;
|
BodyAsJson = BodyData?.BodyAsJson;
|
||||||
BodyAsBytes = BodyData?.BodyAsBytes;
|
BodyAsBytes = BodyData?.BodyAsBytes;
|
||||||
|
|
||||||
DetectedBodyType = BodyData?.DetectedBodyType.ToString();
|
DetectedBodyType = BodyData?.DetectedBodyType.ToString();
|
||||||
DetectedBodyTypeFromContentType = BodyData?.DetectedBodyTypeFromContentType.ToString();
|
DetectedBodyTypeFromContentType = BodyData?.DetectedBodyTypeFromContentType.ToString();
|
||||||
DetectedCompression = BodyData?.DetectedCompression;
|
DetectedCompression = BodyData?.DetectedCompression;
|
||||||
|
|
||||||
|
#if MIMEKIT
|
||||||
|
try
|
||||||
|
{
|
||||||
|
BodyAsMimeMessage = MimeKitUtils.GetMimeMessage(BodyData, headers![HttpKnownHeaderNames.ContentType].First());
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Ignore exception from MimeMessage.Load
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
Headers = headers?.ToDictionary(header => header.Key, header => new WireMockList<string>(header.Value));
|
Headers = headers?.ToDictionary(header => header.Key, header => new WireMockList<string>(header.Value));
|
||||||
Cookies = cookies;
|
Cookies = cookies;
|
||||||
RawQuery = urlDetails.Url.Query;
|
RawQuery = urlDetails.Url.Query;
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ using WireMock.Types;
|
|||||||
using WireMock.Util;
|
using WireMock.Util;
|
||||||
|
|
||||||
using static WireMock.Util.CSharpFormatter;
|
using static WireMock.Util.CSharpFormatter;
|
||||||
|
|
||||||
namespace WireMock.Serialization;
|
namespace WireMock.Serialization;
|
||||||
|
|
||||||
internal class MappingConverter
|
internal class MappingConverter
|
||||||
@@ -48,6 +49,7 @@ internal class MappingConverter
|
|||||||
var methodMatcher = request.GetRequestMessageMatcher<RequestMessageMethodMatcher>();
|
var methodMatcher = request.GetRequestMessageMatcher<RequestMessageMethodMatcher>();
|
||||||
var requestMessageBodyMatcher = request.GetRequestMessageMatcher<RequestMessageBodyMatcher>();
|
var requestMessageBodyMatcher = request.GetRequestMessageMatcher<RequestMessageBodyMatcher>();
|
||||||
var requestMessageGraphQLMatcher = request.GetRequestMessageMatcher<RequestMessageGraphQLMatcher>();
|
var requestMessageGraphQLMatcher = request.GetRequestMessageMatcher<RequestMessageGraphQLMatcher>();
|
||||||
|
var requestMessageMultiPartMatcher = request.GetRequestMessageMatcher<RequestMessageMultiPartMatcher>();
|
||||||
|
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
|
|
||||||
@@ -114,8 +116,18 @@ internal class MappingConverter
|
|||||||
sb.AppendLine($" .WithGraphQLSchema({GetString(graphQLMatcher)})");
|
sb.AppendLine($" .WithGraphQLSchema({GetString(graphQLMatcher)})");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if MIMEKIT
|
||||||
|
if (requestMessageMultiPartMatcher is { Matchers: { } })
|
||||||
|
{
|
||||||
|
if (requestMessageMultiPartMatcher.Matchers.OfType<MimePartMatcher>().Any())
|
||||||
|
{
|
||||||
|
sb.AppendLine(" // .WithMultiPart() is not yet supported");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (requestMessageBodyMatcher is { Matchers: { } })
|
if (requestMessageBodyMatcher is { Matchers: { } })
|
||||||
{
|
{
|
||||||
if (requestMessageBodyMatcher.Matchers.OfType<WildcardMatcher>().FirstOrDefault() is { } wildcardMatcher && wildcardMatcher.GetPatterns().Any())
|
if (requestMessageBodyMatcher.Matchers.OfType<WildcardMatcher>().FirstOrDefault() is { } wildcardMatcher && wildcardMatcher.GetPatterns().Any())
|
||||||
@@ -185,7 +197,7 @@ internal class MappingConverter
|
|||||||
{
|
{
|
||||||
sb.AppendLine($" .WithBody({ToCSharpStringLiteral(bodyStringValue)})");
|
sb.AppendLine($" .WithBody({ToCSharpStringLiteral(bodyStringValue)})");
|
||||||
}
|
}
|
||||||
else if(bodyData.BodyAsJson is {} jsonBody)
|
else if (bodyData.BodyAsJson is { } jsonBody)
|
||||||
{
|
{
|
||||||
var anonymousObjectDefinition = ConvertToAnonymousObjectDefinition(jsonBody);
|
var anonymousObjectDefinition = ConvertToAnonymousObjectDefinition(jsonBody);
|
||||||
sb.AppendLine($" .WithBodyAsJson({anonymousObjectDefinition})");
|
sb.AppendLine($" .WithBodyAsJson({anonymousObjectDefinition})");
|
||||||
@@ -228,6 +240,7 @@ internal class MappingConverter
|
|||||||
var methodMatcher = request.GetRequestMessageMatcher<RequestMessageMethodMatcher>();
|
var methodMatcher = request.GetRequestMessageMatcher<RequestMessageMethodMatcher>();
|
||||||
var bodyMatcher = request.GetRequestMessageMatcher<RequestMessageBodyMatcher>();
|
var bodyMatcher = request.GetRequestMessageMatcher<RequestMessageBodyMatcher>();
|
||||||
var graphQLMatcher = request.GetRequestMessageMatcher<RequestMessageGraphQLMatcher>();
|
var graphQLMatcher = request.GetRequestMessageMatcher<RequestMessageGraphQLMatcher>();
|
||||||
|
var multiPartMatcher = request.GetRequestMessageMatcher<RequestMessageMultiPartMatcher>();
|
||||||
|
|
||||||
var mappingModel = new MappingModel
|
var mappingModel = new MappingModel
|
||||||
{
|
{
|
||||||
@@ -323,19 +336,20 @@ internal class MappingConverter
|
|||||||
mappingModel.Webhooks = mapping.Webhooks.Select(WebhookMapper.Map).ToArray();
|
mappingModel.Webhooks = mapping.Webhooks.Select(WebhookMapper.Map).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
var graphQLOrBodyMatchers = graphQLMatcher?.Matchers ?? bodyMatcher?.Matchers;
|
var bodyMatchers = multiPartMatcher?.Matchers ?? graphQLMatcher?.Matchers ?? bodyMatcher?.Matchers;
|
||||||
var matchOperator = graphQLMatcher?.MatchOperator ?? bodyMatcher?.MatchOperator;
|
var matchOperator = multiPartMatcher?.MatchOperator ?? graphQLMatcher?.MatchOperator ?? bodyMatcher?.MatchOperator;
|
||||||
if (graphQLOrBodyMatchers != null && matchOperator != null)
|
|
||||||
|
if (bodyMatchers != null && matchOperator != null)
|
||||||
{
|
{
|
||||||
mappingModel.Request.Body = new BodyModel();
|
mappingModel.Request.Body = new BodyModel();
|
||||||
|
|
||||||
if (graphQLOrBodyMatchers.Length == 1)
|
if (bodyMatchers.Length == 1)
|
||||||
{
|
{
|
||||||
mappingModel.Request.Body.Matcher = _mapper.Map(graphQLOrBodyMatchers[0]);
|
mappingModel.Request.Body.Matcher = _mapper.Map(bodyMatchers[0]);
|
||||||
}
|
}
|
||||||
else if (graphQLOrBodyMatchers.Length > 1)
|
else if (bodyMatchers.Length > 1)
|
||||||
{
|
{
|
||||||
mappingModel.Request.Body.Matchers = _mapper.Map(graphQLOrBodyMatchers);
|
mappingModel.Request.Body.Matchers = _mapper.Map(bodyMatchers);
|
||||||
mappingModel.Request.Body.MatchOperator = matchOperator.ToString();
|
mappingModel.Request.Body.MatchOperator = matchOperator.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -520,6 +534,4 @@ internal class MappingConverter
|
|||||||
|
|
||||||
return newDictionary;
|
return newDictionary;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -75,6 +75,11 @@ internal class MatcherMapper
|
|||||||
case nameof(GraphQLMatcher):
|
case nameof(GraphQLMatcher):
|
||||||
return new GraphQLMatcher(stringPatterns[0].GetPattern(), matchBehaviour, throwExceptionWhenMatcherFails, matchOperator);
|
return new GraphQLMatcher(stringPatterns[0].GetPattern(), matchBehaviour, throwExceptionWhenMatcherFails, matchOperator);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if MIMEKIT
|
||||||
|
case nameof(MimePartMatcher):
|
||||||
|
return CreateMimePartMatcher(matchBehaviour, matcher, throwExceptionWhenMatcherFails);
|
||||||
|
#endif
|
||||||
case nameof(RegexMatcher):
|
case nameof(RegexMatcher):
|
||||||
return new RegexMatcher(matchBehaviour, stringPatterns, ignoreCase, throwExceptionWhenMatcherFails, useRegexExtended, matchOperator);
|
return new RegexMatcher(matchBehaviour, stringPatterns, ignoreCase, throwExceptionWhenMatcherFails, useRegexExtended, matchOperator);
|
||||||
|
|
||||||
@@ -126,12 +131,7 @@ internal class MatcherMapper
|
|||||||
|
|
||||||
public MatcherModel[]? Map(IEnumerable<IMatcher>? matchers)
|
public MatcherModel[]? Map(IEnumerable<IMatcher>? matchers)
|
||||||
{
|
{
|
||||||
if (matchers == null)
|
return matchers?.Where(m => m != null).Select(Map).ToArray();
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return matchers.Where(m => m != null).Select(Map).ToArray()!;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public MatcherModel? Map(IMatcher? matcher)
|
public MatcherModel? Map(IMatcher? matcher)
|
||||||
@@ -195,6 +195,15 @@ internal class MatcherMapper
|
|||||||
case ExactObjectMatcher exactObjectMatcher:
|
case ExactObjectMatcher exactObjectMatcher:
|
||||||
model.Pattern = exactObjectMatcher.ValueAsObject ?? exactObjectMatcher.ValueAsBytes;
|
model.Pattern = exactObjectMatcher.ValueAsObject ?? exactObjectMatcher.ValueAsBytes;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
#if MIMEKIT
|
||||||
|
case MimePartMatcher mimePartMatcher:
|
||||||
|
model.ContentDispositionMatcher = Map(mimePartMatcher.ContentDispositionMatcher);
|
||||||
|
model.ContentMatcher = Map(mimePartMatcher.ContentMatcher);
|
||||||
|
model.ContentTransferEncodingMatcher = Map(mimePartMatcher.ContentTransferEncodingMatcher);
|
||||||
|
model.ContentTypeMatcher = Map(mimePartMatcher.ContentTypeMatcher);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
return model;
|
return model;
|
||||||
@@ -224,7 +233,7 @@ internal class MatcherMapper
|
|||||||
return new[] { new AnyOf<string, StringPattern>(new StringPattern { Pattern = pattern, PatternAsFile = patternAsFile }) };
|
return new[] { new AnyOf<string, StringPattern>(new StringPattern { Pattern = pattern, PatternAsFile = patternAsFile }) };
|
||||||
}
|
}
|
||||||
|
|
||||||
return new AnyOf<string, StringPattern>[0];
|
return EmptyArray<AnyOf<string, StringPattern>>.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ExactObjectMatcher CreateExactObjectMatcher(MatchBehaviour matchBehaviour, AnyOf<string, StringPattern> stringPattern, bool throwException)
|
private static ExactObjectMatcher CreateExactObjectMatcher(MatchBehaviour matchBehaviour, AnyOf<string, StringPattern> stringPattern, bool throwException)
|
||||||
@@ -241,4 +250,16 @@ internal class MatcherMapper
|
|||||||
|
|
||||||
return new ExactObjectMatcher(matchBehaviour, bytePattern, throwException);
|
return new ExactObjectMatcher(matchBehaviour, bytePattern, throwException);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if MIMEKIT
|
||||||
|
private MimePartMatcher CreateMimePartMatcher(MatchBehaviour matchBehaviour, MatcherModel? matcher, bool throwExceptionWhenMatcherFails)
|
||||||
|
{
|
||||||
|
var contentTypeMatcher = Map(matcher?.ContentTypeMatcher) as IStringMatcher;
|
||||||
|
var contentDispositionMatcher = Map(matcher?.ContentDispositionMatcher) as IStringMatcher;
|
||||||
|
var contentTransferEncodingMatcher = Map(matcher?.ContentTransferEncodingMatcher) as IStringMatcher;
|
||||||
|
var contentMatcher = Map(matcher?.ContentMatcher);
|
||||||
|
|
||||||
|
return new MimePartMatcher(matchBehaviour, contentTypeMatcher, contentDispositionMatcher, contentTransferEncodingMatcher, contentMatcher, throwExceptionWhenMatcherFails);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
#if MIMEKIT
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using MimeKit;
|
||||||
|
using WireMock.Http;
|
||||||
|
using WireMock.Types;
|
||||||
|
|
||||||
|
namespace WireMock.Util;
|
||||||
|
|
||||||
|
internal static class MimeKitUtils
|
||||||
|
{
|
||||||
|
public static MimeMessage GetMimeMessage(IBodyData? bodyData, string contentTypeHeaderValue)
|
||||||
|
{
|
||||||
|
var bytes = bodyData?.DetectedBodyType switch
|
||||||
|
{
|
||||||
|
// If the body is bytes, use the BodyAsBytes to match on.
|
||||||
|
BodyType.Bytes => bodyData.BodyAsBytes!,
|
||||||
|
|
||||||
|
// If the body is a String or MultiPart, use the BodyAsString to match on.
|
||||||
|
BodyType.String or BodyType.MultiPart => Encoding.UTF8.GetBytes(bodyData.BodyAsString!),
|
||||||
|
|
||||||
|
_ => throw new NotSupportedException()
|
||||||
|
};
|
||||||
|
|
||||||
|
var fixedBytes = FixBytes(bytes, contentTypeHeaderValue);
|
||||||
|
return MimeMessage.Load(new MemoryStream(fixedBytes));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] FixBytes(byte[] bytes, WireMockList<string> contentType)
|
||||||
|
{
|
||||||
|
var contentTypeBytes = Encoding.UTF8.GetBytes($"{HttpKnownHeaderNames.ContentType}: {contentType}\r\n\r\n");
|
||||||
|
|
||||||
|
var result = new byte[contentTypeBytes.Length + bytes.Length];
|
||||||
|
|
||||||
|
Buffer.BlockCopy(contentTypeBytes, 0, result, 0, contentTypeBytes.Length);
|
||||||
|
Buffer.BlockCopy(bytes, 0, result, contentTypeBytes.Length, bytes.Length);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace WireMock.Util;
|
||||||
|
|
||||||
|
internal static class StreamUtils
|
||||||
|
{
|
||||||
|
public static Stream CreateStream(string s)
|
||||||
|
{
|
||||||
|
return new MemoryStream(Encoding.UTF8.GetBytes(s));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -51,10 +51,11 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(TargetFramework)' != 'netstandard1.3' and '$(TargetFramework)' != 'net451' and '$(TargetFramework)' != 'net452' and '$(TargetFramework)' != 'net46' and '$(TargetFramework)' != 'net461'">
|
<PropertyGroup Condition="'$(TargetFramework)' != 'netstandard1.3' and '$(TargetFramework)' != 'net451' and '$(TargetFramework)' != 'net452' and '$(TargetFramework)' != 'net46' and '$(TargetFramework)' != 'net461'">
|
||||||
<DefineConstants>$(DefineConstants);GRAPHQL</DefineConstants>
|
<DefineConstants>$(DefineConstants);GRAPHQL;MIMEKIT</DefineConstants>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Remove="Matchers\MultiPartMatcher.cs" />
|
||||||
<Compile Remove="Util\FileSystemWatcherExtensions.cs" />
|
<Compile Remove="Util\FileSystemWatcherExtensions.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
@@ -160,6 +161,7 @@
|
|||||||
<ItemGroup Condition="'$(TargetFramework)' != 'netstandard1.3' and '$(TargetFramework)' != 'net451' and '$(TargetFramework)' != 'net452' and '$(TargetFramework)' != 'net46' and '$(TargetFramework)' != 'net461'">
|
<ItemGroup Condition="'$(TargetFramework)' != 'netstandard1.3' and '$(TargetFramework)' != 'net451' and '$(TargetFramework)' != 'net452' and '$(TargetFramework)' != 'net46' and '$(TargetFramework)' != 'net461'">
|
||||||
<PackageReference Include="GraphQL" Version="7.5.0" />
|
<PackageReference Include="GraphQL" Version="7.5.0" />
|
||||||
<PackageReference Include="GraphQL.NewtonsoftJson" Version="7.5.0" />
|
<PackageReference Include="GraphQL.NewtonsoftJson" Version="7.5.0" />
|
||||||
|
<PackageReference Include="MimeKitLite" Version="4.1.0.1" PrivateAssets="all" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp3.1' ">
|
<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp3.1' ">
|
||||||
|
|||||||
@@ -0,0 +1,99 @@
|
|||||||
|
#if MIMEKIT
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using FluentAssertions;
|
||||||
|
using MimeKit;
|
||||||
|
using WireMock.Matchers;
|
||||||
|
using WireMock.Util;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace WireMock.Net.Tests.Matchers;
|
||||||
|
|
||||||
|
public class MimePartMatcherTests
|
||||||
|
{
|
||||||
|
private const string TestMultiPart = @"From:
|
||||||
|
Date: Sun, 23 Jul 2023 16:13:13 +0200
|
||||||
|
Subject:
|
||||||
|
Message-Id: <HZ3K1HEAJKU4.IO57XCVO4BWV@desktop-6dd5qi2>
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: multipart/mixed; boundary=""=-5XgmpXt0XOfzdtcgNJc2ZQ==""
|
||||||
|
|
||||||
|
--=-5XgmpXt0XOfzdtcgNJc2ZQ==
|
||||||
|
Content-Type: text/plain; charset=utf-8
|
||||||
|
|
||||||
|
This is some plain text
|
||||||
|
--=-5XgmpXt0XOfzdtcgNJc2ZQ==
|
||||||
|
Content-Type: text/json; charset=utf-8
|
||||||
|
|
||||||
|
{
|
||||||
|
""Key"": ""Value""
|
||||||
|
}
|
||||||
|
--=-5XgmpXt0XOfzdtcgNJc2ZQ==
|
||||||
|
Content-Type: image/png; name=image.png
|
||||||
|
Content-Disposition: attachment; filename=image.png
|
||||||
|
Content-Transfer-Encoding: base64
|
||||||
|
|
||||||
|
iVBORw0KGgoAAAANSUhEUgAAAAIAAAACAgMAAAAP2OW3AAAADFBMVEX/tID/vpH/pWX/sHidUyjl
|
||||||
|
AAAADElEQVR4XmMQYNgAAADkAMHebX3mAAAAAElFTkSuQmCC
|
||||||
|
|
||||||
|
--=-5XgmpXt0XOfzdtcgNJc2ZQ==--
|
||||||
|
";
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void MimePartMatcher_IsMatch_Part_TextPlain()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var message = MimeMessage.Load(StreamUtils.CreateStream(TestMultiPart));
|
||||||
|
var part = (MimePart)message.BodyParts.ToArray()[0];
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var contentTypeMatcher = new ContentTypeMatcher("text/plain");
|
||||||
|
var contentMatcher = new ExactMatcher("This is some plain text");
|
||||||
|
|
||||||
|
var matcher = new MimePartMatcher(MatchBehaviour.AcceptOnMatch, contentTypeMatcher, null, null, contentMatcher);
|
||||||
|
var result = matcher.IsMatch(part);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
matcher.Name.Should().Be("MimePartMatcher");
|
||||||
|
result.Should().Be(MatchScores.Perfect);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void MimePartMatcher_IsMatch_Part_TextJson()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var message = MimeMessage.Load(StreamUtils.CreateStream(TestMultiPart));
|
||||||
|
var part = (MimePart)message.BodyParts.ToArray()[1];
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var contentTypeMatcher = new ContentTypeMatcher("text/json");
|
||||||
|
var contentMatcher = new JsonMatcher(new { Key = "Value" }, true);
|
||||||
|
|
||||||
|
var matcher = new MimePartMatcher(MatchBehaviour.AcceptOnMatch, contentTypeMatcher, null, null, contentMatcher);
|
||||||
|
var result = matcher.IsMatch(part);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Should().Be(MatchScores.Perfect);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void MimePartMatcher_IsMatch_Part_ImagePng()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var message = MimeMessage.Load(StreamUtils.CreateStream(TestMultiPart));
|
||||||
|
var part = (MimePart)message.BodyParts.ToArray()[2];
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var contentTypeMatcher = new ContentTypeMatcher("image/png");
|
||||||
|
var contentDispositionMatcher = new ExactMatcher("attachment; filename=\"image.png\"");
|
||||||
|
var contentTransferEncodingMatcher = new ExactMatcher("base64");
|
||||||
|
var contentMatcher = new ExactObjectMatcher(Convert.FromBase64String("iVBORw0KGgoAAAANSUhEUgAAAAIAAAACAgMAAAAP2OW3AAAADFBMVEX/tID/vpH/pWX/sHidUyjlAAAADElEQVR4XmMQYNgAAADkAMHebX3mAAAAAElFTkSuQmCC"));
|
||||||
|
|
||||||
|
var matcher = new MimePartMatcher(MatchBehaviour.AcceptOnMatch, contentTypeMatcher, contentDispositionMatcher, contentTransferEncodingMatcher, contentMatcher);
|
||||||
|
var result = matcher.IsMatch(part);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
result.Should().Be(MatchScores.Perfect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+2
-2
@@ -8,9 +8,9 @@ using WireMock.Types;
|
|||||||
using WireMock.Util;
|
using WireMock.Util;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace WireMock.Net.Tests;
|
namespace WireMock.Net.Tests.RequestBuilders;
|
||||||
|
|
||||||
public class RequestTests
|
public class RequestBuilderTests
|
||||||
{
|
{
|
||||||
private const string ClientIp = "::1";
|
private const string ClientIp = "::1";
|
||||||
|
|
||||||
@@ -1,17 +1,28 @@
|
|||||||
|
using System;
|
||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using JsonConverter.Abstractions;
|
||||||
|
using Moq;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using NFluent;
|
||||||
using WireMock.Matchers;
|
using WireMock.Matchers;
|
||||||
using WireMock.Matchers.Request;
|
using WireMock.Matchers.Request;
|
||||||
|
using WireMock.Models;
|
||||||
using WireMock.RequestBuilders;
|
using WireMock.RequestBuilders;
|
||||||
|
using WireMock.Types;
|
||||||
|
using WireMock.Util;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace WireMock.Net.Tests.RequestBuilders;
|
namespace WireMock.Net.Tests.RequestBuilders;
|
||||||
|
|
||||||
public class RequestBuilderWithBodyTests
|
public class RequestBuilderWithBodyTests
|
||||||
{
|
{
|
||||||
|
private const string ClientIp = "::1";
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void RequestBuilder_WithBody_IMatcher()
|
public void Request_WithBody_IMatcher()
|
||||||
{
|
{
|
||||||
// Assign
|
// Assign
|
||||||
var matcher = new WildcardMatcher("x");
|
var matcher = new WildcardMatcher("x");
|
||||||
@@ -26,7 +37,7 @@ public class RequestBuilderWithBodyTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void RequestBuilder_WithBody_IMatchers()
|
public void Request_WithBody_IMatchers()
|
||||||
{
|
{
|
||||||
// Assign
|
// Assign
|
||||||
var matcher1 = new WildcardMatcher("x");
|
var matcher1 = new WildcardMatcher("x");
|
||||||
@@ -40,4 +51,409 @@ public class RequestBuilderWithBodyTests
|
|||||||
matchers.Should().HaveCount(1);
|
matchers.Should().HaveCount(1);
|
||||||
((RequestMessageBodyMatcher)matchers[0]).Matchers.Should().Contain(new[] { matcher1, matcher2 });
|
((RequestMessageBodyMatcher)matchers[0]).Matchers.Should().Contain(new[] { matcher1, matcher2 });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Request_WithBody_FuncString()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var requestBuilder = Request.Create().UsingAnyMethod().WithBody(b => b != null && b.Contains("b"));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var body = new BodyData
|
||||||
|
{
|
||||||
|
BodyAsString = "b",
|
||||||
|
DetectedBodyType = BodyType.String
|
||||||
|
};
|
||||||
|
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "POST", ClientIp, body);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var requestMatchResult = new RequestMatchResult();
|
||||||
|
Check.That(requestBuilder.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Request_WithBody_FuncJson()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var requestBuilder = Request.Create().UsingAnyMethod().WithBody(b => b != null);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var body = new BodyData
|
||||||
|
{
|
||||||
|
BodyAsJson = 123,
|
||||||
|
DetectedBodyType = BodyType.Json
|
||||||
|
};
|
||||||
|
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "POST", ClientIp, body);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var requestMatchResult = new RequestMatchResult();
|
||||||
|
Check.That(requestBuilder.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Request_WithBody_FuncFormUrlEncoded()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var requestBuilder = Request.Create().UsingAnyMethod().WithBody((IDictionary<string, string>? values) => values != null);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var body = new BodyData
|
||||||
|
{
|
||||||
|
BodyAsFormUrlEncoded = new Dictionary<string, string>(),
|
||||||
|
DetectedBodyTypeFromContentType = BodyType.FormUrlEncoded,
|
||||||
|
DetectedBodyType = BodyType.FormUrlEncoded
|
||||||
|
};
|
||||||
|
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "POST", ClientIp, body);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var requestMatchResult = new RequestMatchResult();
|
||||||
|
Check.That(requestBuilder.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Request_WithBody_FuncBodyData()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var requestBuilder = Request.Create().UsingAnyMethod().WithBody((IBodyData? b) => b != null);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var body = new BodyData
|
||||||
|
{
|
||||||
|
BodyAsJson = 123,
|
||||||
|
DetectedBodyType = BodyType.Json
|
||||||
|
};
|
||||||
|
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "POST", ClientIp, body);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var requestMatchResult = new RequestMatchResult();
|
||||||
|
Check.That(requestBuilder.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Request_WithBody_FuncByteArray()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var requestBuilder = Request.Create().UsingAnyMethod().WithBody((byte[]? b) => b != null);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var body = new BodyData
|
||||||
|
{
|
||||||
|
BodyAsBytes = new byte[0],
|
||||||
|
DetectedBodyType = BodyType.Bytes
|
||||||
|
};
|
||||||
|
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "POST", ClientIp, body);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var requestMatchResult = new RequestMatchResult();
|
||||||
|
Check.That(requestBuilder.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Request_WithBodyExactMatcher()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var requestBuilder = Request.Create().UsingAnyMethod().WithBody(new ExactMatcher("cat"));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var body = new BodyData
|
||||||
|
{
|
||||||
|
BodyAsString = "cat",
|
||||||
|
DetectedBodyType = BodyType.String
|
||||||
|
};
|
||||||
|
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "POST", ClientIp, body);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var requestMatchResult = new RequestMatchResult();
|
||||||
|
Check.That(requestBuilder.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Request_WithBody_BodyDataAsString_Using_WildcardMatcher()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var spec = Request.Create().WithPath("/foo").UsingAnyMethod().WithBody(new WildcardMatcher("H*o*"));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var body = new BodyData
|
||||||
|
{
|
||||||
|
BodyAsString = "Hello world!",
|
||||||
|
DetectedBodyType = BodyType.String
|
||||||
|
};
|
||||||
|
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, body);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var requestMatchResult = new RequestMatchResult();
|
||||||
|
spec.GetMatchingScore(request, requestMatchResult).Should().Be(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Request_WithBody_BodyDataAsJson_Using_WildcardMatcher()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var spec = Request.Create().WithPath("/foo").UsingAnyMethod().WithBody(new WildcardMatcher("*Hello*"));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var body = new BodyData
|
||||||
|
{
|
||||||
|
BodyAsJson = new { Hi = "Hello world!" },
|
||||||
|
BodyAsString = "{ Hi = \"Hello world!\" }",
|
||||||
|
DetectedBodyType = BodyType.Json
|
||||||
|
};
|
||||||
|
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, body);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var requestMatchResult = new RequestMatchResult();
|
||||||
|
spec.GetMatchingScore(request, requestMatchResult).Should().Be(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Request_WithBody_XPathMatcher_true()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var spec = Request.Create().UsingAnyMethod().WithBody(new XPathMatcher("/todo-list[count(todo-item) = 3]"));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var body = new BodyData
|
||||||
|
{
|
||||||
|
BodyAsString = @"
|
||||||
|
<todo-list>
|
||||||
|
<todo-item id='a1'>abc</todo-item>
|
||||||
|
<todo-item id='a2'>def</todo-item>
|
||||||
|
<todo-item id='a3'>xyz</todo-item>
|
||||||
|
</todo-list>",
|
||||||
|
DetectedBodyType = BodyType.String
|
||||||
|
};
|
||||||
|
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, body);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var requestMatchResult = new RequestMatchResult();
|
||||||
|
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Request_WithBody_XPathMatcher_false()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var spec = Request.Create().UsingAnyMethod().WithBody(new XPathMatcher("/todo-list[count(todo-item) = 99]"));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var body = new BodyData
|
||||||
|
{
|
||||||
|
BodyAsString = @"
|
||||||
|
<todo-list>
|
||||||
|
<todo-item id='a1'>abc</todo-item>
|
||||||
|
<todo-item id='a2'>def</todo-item>
|
||||||
|
<todo-item id='a3'>xyz</todo-item>
|
||||||
|
</todo-list>",
|
||||||
|
DetectedBodyType = BodyType.String
|
||||||
|
};
|
||||||
|
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, body);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var requestMatchResult = new RequestMatchResult();
|
||||||
|
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsNotEqualTo(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Request_WithBody_JsonPathMatcher_true()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var spec = Request.Create().UsingAnyMethod().WithBody(new JsonPathMatcher("$..things[?(@.name == 'RequiredThing')]"));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var body = new BodyData
|
||||||
|
{
|
||||||
|
BodyAsString = "{ \"things\": [ { \"name\": \"RequiredThing\" }, { \"name\": \"Wiremock\" } ] }",
|
||||||
|
DetectedBodyType = BodyType.String
|
||||||
|
};
|
||||||
|
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, body);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var requestMatchResult = new RequestMatchResult();
|
||||||
|
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Request_WithBodyJson_PathMatcher_false()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var spec = Request.Create().UsingAnyMethod().WithBody(new JsonPathMatcher("$.things[?(@.name == 'RequiredThing')]"));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var body = new BodyData
|
||||||
|
{
|
||||||
|
BodyAsString = "{ \"things\": { \"name\": \"Wiremock\" } }",
|
||||||
|
DetectedBodyType = BodyType.String
|
||||||
|
};
|
||||||
|
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, body);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var requestMatchResult = new RequestMatchResult();
|
||||||
|
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsNotEqualTo(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Request_WithBodyAsJson_Object_JsonPathMatcher_true()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var spec = Request.Create().UsingAnyMethod().WithBody(new JsonPathMatcher("$..things[?(@.name == 'RequiredThing')]"));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
string jsonString = "{ \"things\": [ { \"name\": \"RequiredThing\" }, { \"name\": \"Wiremock\" } ] }";
|
||||||
|
var bodyData = new BodyData
|
||||||
|
{
|
||||||
|
BodyAsJson = JsonConvert.DeserializeObject(jsonString),
|
||||||
|
BodyAsString = jsonString,
|
||||||
|
Encoding = Encoding.UTF8,
|
||||||
|
DetectedBodyType = BodyType.Json
|
||||||
|
};
|
||||||
|
|
||||||
|
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, bodyData);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var requestMatchResult = new RequestMatchResult();
|
||||||
|
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Request_WithBodyAsJson_Array_JsonPathMatcher_1()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var spec = Request.Create().UsingAnyMethod().WithBody(new JsonPathMatcher("$..books[?(@.price < 10)]"));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
string jsonString = "{ \"books\": [ { \"category\": \"test1\", \"price\": 8.95 }, { \"category\": \"test2\", \"price\": 20 } ] }";
|
||||||
|
var bodyData = new BodyData
|
||||||
|
{
|
||||||
|
BodyAsJson = JsonConvert.DeserializeObject(jsonString),
|
||||||
|
BodyAsString = jsonString,
|
||||||
|
Encoding = Encoding.UTF8,
|
||||||
|
DetectedBodyType = BodyType.Json
|
||||||
|
};
|
||||||
|
|
||||||
|
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, bodyData);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var requestMatchResult = new RequestMatchResult();
|
||||||
|
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Request_WithBodyAsJson_Array_JsonPathMatcher_2()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var spec = Request.Create().UsingAnyMethod().WithBody(new JsonPathMatcher("$..[?(@.Id == 1)]"));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
string jsonString = "{ \"Id\": 1, \"Name\": \"Test\" }";
|
||||||
|
var bodyData = new BodyData
|
||||||
|
{
|
||||||
|
BodyAsJson = JsonConvert.DeserializeObject(jsonString),
|
||||||
|
BodyAsString = jsonString,
|
||||||
|
Encoding = Encoding.UTF8,
|
||||||
|
DetectedBodyType = BodyType.Json
|
||||||
|
};
|
||||||
|
|
||||||
|
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, bodyData);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var requestMatchResult = new RequestMatchResult();
|
||||||
|
double result = spec.GetMatchingScore(request, requestMatchResult);
|
||||||
|
Check.That(result).IsEqualTo(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Request_WithBodyAsObject_ExactObjectMatcher_true()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
object body = DateTime.MinValue;
|
||||||
|
var requestBuilder = Request.Create().UsingAnyMethod().WithBody(body);
|
||||||
|
|
||||||
|
var bodyData = new BodyData
|
||||||
|
{
|
||||||
|
BodyAsJson = DateTime.MinValue,
|
||||||
|
DetectedBodyType = BodyType.Json
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, bodyData);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var requestMatchResult = new RequestMatchResult();
|
||||||
|
Check.That(requestBuilder.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Request_WithBodyAsJson_UsingObject()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
object body = new
|
||||||
|
{
|
||||||
|
Test = "abc"
|
||||||
|
};
|
||||||
|
var requestBuilder = Request.Create().UsingAnyMethod().WithBodyAsJson(body);
|
||||||
|
|
||||||
|
var bodyData = new BodyData
|
||||||
|
{
|
||||||
|
BodyAsString = JsonConvert.SerializeObject(body),
|
||||||
|
DetectedBodyType = BodyType.String
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "POST", ClientIp, bodyData);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var requestMatchResult = new RequestMatchResult();
|
||||||
|
Check.That(requestBuilder.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Request_WithBodyAsJson_WithIJsonConverter_UsingObject()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var jsonConverterMock = new Mock<IJsonConverter>();
|
||||||
|
jsonConverterMock.Setup(j => j.Serialize(It.IsAny<object>(), It.IsAny<JsonConverterOptions>())).Returns("test");
|
||||||
|
object body = new
|
||||||
|
{
|
||||||
|
Any = "key"
|
||||||
|
};
|
||||||
|
var requestBuilder = Request.Create().UsingAnyMethod().WithBodyAsJson(body, jsonConverterMock.Object);
|
||||||
|
|
||||||
|
var bodyData = new BodyData
|
||||||
|
{
|
||||||
|
BodyAsString = "test",
|
||||||
|
DetectedBodyType = BodyType.String
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "POST", ClientIp, bodyData);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var requestMatchResult = new RequestMatchResult();
|
||||||
|
Check.That(requestBuilder.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(new byte[] { 1 }, BodyType.Bytes)]
|
||||||
|
[InlineData(new byte[] { 48, 49, 50 }, BodyType.Bytes)]
|
||||||
|
[InlineData(new byte[] { 48, 49, 50 }, BodyType.String)]
|
||||||
|
public void Request_WithBodyAsBytes_ExactObjectMatcher_true(byte[] bytes, BodyType detectedBodyType)
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
byte[] body = bytes;
|
||||||
|
var requestBuilder = Request.Create().UsingAnyMethod().WithBody(body);
|
||||||
|
|
||||||
|
var bodyData = new BodyData
|
||||||
|
{
|
||||||
|
BodyAsBytes = bytes,
|
||||||
|
DetectedBodyType = detectedBodyType
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, bodyData);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var requestMatchResult = new RequestMatchResult();
|
||||||
|
requestBuilder.GetMatchingScore(request, requestMatchResult).Should().Be(1.0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
using NFluent;
|
||||||
|
using WireMock.Matchers;
|
||||||
|
using WireMock.Matchers.Request;
|
||||||
|
using WireMock.Models;
|
||||||
|
using WireMock.RequestBuilders;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace WireMock.Net.Tests.RequestBuilders;
|
||||||
|
|
||||||
|
public class RequestBuilderWithClientIPTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void Request_WithClientIP_Match_Ok()
|
||||||
|
{
|
||||||
|
// given
|
||||||
|
var spec = Request.Create().WithClientIP("127.0.0.2", "1.1.1.1");
|
||||||
|
|
||||||
|
// when
|
||||||
|
var request = new RequestMessage(new UrlDetails("http://localhost"), "GET", "127.0.0.2");
|
||||||
|
|
||||||
|
// then
|
||||||
|
var requestMatchResult = new RequestMatchResult();
|
||||||
|
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Request_WithClientIP_Match_Fail()
|
||||||
|
{
|
||||||
|
// given
|
||||||
|
var spec = Request.Create().WithClientIP("127.0.0.2");
|
||||||
|
|
||||||
|
// when
|
||||||
|
var request = new RequestMessage(new UrlDetails("http://localhost"), "GET", "192.1.1.1");
|
||||||
|
|
||||||
|
// then
|
||||||
|
var requestMatchResult = new RequestMatchResult();
|
||||||
|
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Request_WithClientIP_WildcardMatcher()
|
||||||
|
{
|
||||||
|
// given
|
||||||
|
var spec = Request.Create().WithClientIP(new WildcardMatcher("127.0.0.2"));
|
||||||
|
|
||||||
|
// when
|
||||||
|
var request = new RequestMessage(new UrlDetails("http://localhost"), "GET", "127.0.0.2");
|
||||||
|
|
||||||
|
// then
|
||||||
|
var requestMatchResult = new RequestMatchResult();
|
||||||
|
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Request_WithClientIP_Func()
|
||||||
|
{
|
||||||
|
// given
|
||||||
|
var spec = Request.Create().WithClientIP(c => c.Contains("."));
|
||||||
|
|
||||||
|
// when
|
||||||
|
var request = new RequestMessage(new UrlDetails("http://localhost"), "GET", "127.0.0.2");
|
||||||
|
|
||||||
|
// then
|
||||||
|
var requestMatchResult = new RequestMatchResult();
|
||||||
|
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
#if MIMEKIT
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using FluentAssertions;
|
||||||
|
using WireMock.Matchers;
|
||||||
|
using WireMock.Matchers.Request;
|
||||||
|
using WireMock.RequestBuilders;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace WireMock.Net.Tests.RequestBuilders;
|
||||||
|
|
||||||
|
public class RequestBuilderWithMultiPartTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void RequestBuilder_WithMultiPart_MimePartMatcher()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var matcher = new MimePartMatcher(MatchBehaviour.AcceptOnMatch, null, null, null, null);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var requestBuilder = (Request)Request.Create().WithMultiPart(matcher);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var matchers = requestBuilder.GetPrivateFieldValue<IList<IRequestMatcher>>("_requestMatchers");
|
||||||
|
matchers.Should().HaveCount(1);
|
||||||
|
((RequestMessageMultiPartMatcher)matchers[0]).Matchers.Should().HaveCount(1).And.ContainItemsAssignableTo<MimePartMatcher>();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void RequestBuilder_WithMultiPart_MimePartMatchers()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var matcher1 = new MimePartMatcher(MatchBehaviour.AcceptOnMatch, null, null, null, null);
|
||||||
|
var matcher2 = new MimePartMatcher(MatchBehaviour.AcceptOnMatch, null, null, null, null);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var requestBuilder = (Request)Request.Create().WithMultiPart(MatchBehaviour.RejectOnMatch, matcher1, matcher2);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var matchers = requestBuilder.GetPrivateFieldValue<IList<IRequestMatcher>>("_requestMatchers");
|
||||||
|
matchers.Should().HaveCount(1);
|
||||||
|
|
||||||
|
var x = ((RequestMessageMultiPartMatcher)matchers[0]);
|
||||||
|
x.MatchBehaviour.Should().Be(MatchBehaviour.RejectOnMatch);
|
||||||
|
x.Matchers.Should().HaveCount(2).And.ContainItemsAssignableTo<MimePartMatcher>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,238 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using NFluent;
|
||||||
|
using WireMock.Matchers;
|
||||||
|
using Xunit;
|
||||||
|
using WireMock.RequestBuilders;
|
||||||
|
using WireMock.Matchers.Request;
|
||||||
|
using WireMock.Models;
|
||||||
|
using WireMock.Util;
|
||||||
|
|
||||||
|
namespace WireMock.Net.Tests.RequestBuilders;
|
||||||
|
|
||||||
|
public class RequestBuilderWithPathTests
|
||||||
|
{
|
||||||
|
private const string ClientIp = "::1";
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Request_WithPath_Spaces()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var spec = Request.Create().WithPath("/path/a b").UsingAnyMethod();
|
||||||
|
|
||||||
|
// when
|
||||||
|
var body = new BodyData();
|
||||||
|
var request = new RequestMessage(new UrlDetails("http://localhost/path/a b"), "GET", ClientIp, body);
|
||||||
|
|
||||||
|
// then
|
||||||
|
var requestMatchResult = new RequestMatchResult();
|
||||||
|
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Request_WithPath_WithHeader_Match()
|
||||||
|
{
|
||||||
|
// given
|
||||||
|
var spec = Request.Create().WithPath("/foo").UsingAnyMethod().WithHeader("X-toto", "tata");
|
||||||
|
|
||||||
|
// when
|
||||||
|
var body = new BodyData
|
||||||
|
{
|
||||||
|
BodyAsString = "abc"
|
||||||
|
};
|
||||||
|
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, body, new Dictionary<string, string[]> { { "X-toto", new[] { "tata" } } });
|
||||||
|
|
||||||
|
// then
|
||||||
|
var requestMatchResult = new RequestMatchResult();
|
||||||
|
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Request_WithPath()
|
||||||
|
{
|
||||||
|
// given
|
||||||
|
var spec = Request.Create().WithPath("/foo");
|
||||||
|
|
||||||
|
// when
|
||||||
|
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "blabla", ClientIp);
|
||||||
|
|
||||||
|
// then
|
||||||
|
var requestMatchResult = new RequestMatchResult();
|
||||||
|
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Request_WithPaths()
|
||||||
|
{
|
||||||
|
var requestBuilder = Request.Create().WithPath("/x1", "/x2");
|
||||||
|
|
||||||
|
var request1 = new RequestMessage(new UrlDetails("http://localhost/x1"), "blabla", ClientIp);
|
||||||
|
var request2 = new RequestMessage(new UrlDetails("http://localhost/x2"), "blabla", ClientIp);
|
||||||
|
|
||||||
|
var requestMatchResult = new RequestMatchResult();
|
||||||
|
Check.That(requestBuilder.GetMatchingScore(request1, requestMatchResult)).IsEqualTo(1.0);
|
||||||
|
Check.That(requestBuilder.GetMatchingScore(request2, requestMatchResult)).IsEqualTo(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Request_WithPathFunc()
|
||||||
|
{
|
||||||
|
// given
|
||||||
|
var spec = Request.Create().WithPath(url => url.EndsWith("/foo"));
|
||||||
|
|
||||||
|
// when
|
||||||
|
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "blabla", ClientIp);
|
||||||
|
|
||||||
|
// then
|
||||||
|
var requestMatchResult = new RequestMatchResult();
|
||||||
|
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Request_WithPath_RegexMatcher_HasMatch()
|
||||||
|
{
|
||||||
|
// given
|
||||||
|
var spec = Request.Create().WithPath(new RegexMatcher("^/foo"));
|
||||||
|
|
||||||
|
// when
|
||||||
|
var request = new RequestMessage(new UrlDetails("http://localhost/foo/bar"), "blabla", ClientIp);
|
||||||
|
|
||||||
|
// then
|
||||||
|
var requestMatchResult = new RequestMatchResult();
|
||||||
|
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Request_WithPathRegexMatcher_HasNoMatch()
|
||||||
|
{
|
||||||
|
// given
|
||||||
|
var spec = Request.Create().WithPath("/foo");
|
||||||
|
|
||||||
|
// when
|
||||||
|
var request = new RequestMessage(new UrlDetails("http://localhost/bar"), "blabla", ClientIp);
|
||||||
|
|
||||||
|
// then
|
||||||
|
var requestMatchResult = new RequestMatchResult();
|
||||||
|
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsNotEqualTo(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Request_WithPath_RegexMatcher_WithPatternAsFile_HasMatch()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var pattern = new StringPattern
|
||||||
|
{
|
||||||
|
Pattern = "^/foo",
|
||||||
|
PatternAsFile = "c:\\x.txt"
|
||||||
|
};
|
||||||
|
var spec = Request.Create().WithPath(new RegexMatcher(pattern));
|
||||||
|
|
||||||
|
// when
|
||||||
|
var request = new RequestMessage(new UrlDetails("http://localhost/foo/bar"), "blabla", ClientIp);
|
||||||
|
|
||||||
|
// then
|
||||||
|
var requestMatchResult = new RequestMatchResult();
|
||||||
|
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Request_WithPath_Should_specify_requests_matching_given_path_and_method_delete()
|
||||||
|
{
|
||||||
|
// given
|
||||||
|
var spec = Request.Create().WithPath("/foo").UsingDelete();
|
||||||
|
|
||||||
|
// when
|
||||||
|
var body = new BodyData
|
||||||
|
{
|
||||||
|
BodyAsString = "whatever"
|
||||||
|
};
|
||||||
|
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "Delete", ClientIp, body);
|
||||||
|
|
||||||
|
// then
|
||||||
|
var requestMatchResult = new RequestMatchResult();
|
||||||
|
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Request_WithPath_Should_specify_requests_matching_given_path_and_method_get()
|
||||||
|
{
|
||||||
|
// given
|
||||||
|
var spec = Request.Create().WithPath("/foo").UsingGet();
|
||||||
|
|
||||||
|
// when
|
||||||
|
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "GET", ClientIp);
|
||||||
|
|
||||||
|
// then
|
||||||
|
var requestMatchResult = new RequestMatchResult();
|
||||||
|
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Request_WithPath_Should_specify_requests_matching_given_path_and_method_head()
|
||||||
|
{
|
||||||
|
// given
|
||||||
|
var spec = Request.Create().WithPath("/foo").UsingHead();
|
||||||
|
|
||||||
|
// when
|
||||||
|
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "HEAD", ClientIp);
|
||||||
|
|
||||||
|
// then
|
||||||
|
var requestMatchResult = new RequestMatchResult();
|
||||||
|
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Request_WithPath_Should_specify_requests_matching_given_path_and_method_post()
|
||||||
|
{
|
||||||
|
// given
|
||||||
|
var spec = Request.Create().WithPath("/foo").UsingPost();
|
||||||
|
|
||||||
|
// when
|
||||||
|
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "POST", ClientIp);
|
||||||
|
|
||||||
|
// then
|
||||||
|
var requestMatchResult = new RequestMatchResult();
|
||||||
|
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Request_WithPath_Should_specify_requests_matching_given_path_and_method_put()
|
||||||
|
{
|
||||||
|
// given
|
||||||
|
var spec = Request.Create().WithPath("/foo").UsingPut();
|
||||||
|
|
||||||
|
// when
|
||||||
|
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp);
|
||||||
|
|
||||||
|
// then
|
||||||
|
var requestMatchResult = new RequestMatchResult();
|
||||||
|
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Request_WithPath_Should_specify_requests_matching_given_path_and_method_patch()
|
||||||
|
{
|
||||||
|
// given
|
||||||
|
var spec = Request.Create().WithPath("/foo").UsingPatch();
|
||||||
|
|
||||||
|
// when
|
||||||
|
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PATCH", ClientIp);
|
||||||
|
|
||||||
|
// then
|
||||||
|
var requestMatchResult = new RequestMatchResult();
|
||||||
|
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Request_WithPath_Should_exclude_requests_matching_given_path_but_not_http_method()
|
||||||
|
{
|
||||||
|
// given
|
||||||
|
var spec = Request.Create().WithPath("/foo").UsingPut();
|
||||||
|
|
||||||
|
// when
|
||||||
|
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "HEAD", ClientIp);
|
||||||
|
|
||||||
|
// then
|
||||||
|
var requestMatchResult = new RequestMatchResult();
|
||||||
|
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsNotEqualTo(1.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
#if MIMEKIT
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using FluentAssertions;
|
||||||
|
using WireMock.Matchers;
|
||||||
|
using WireMock.Matchers.Request;
|
||||||
|
using WireMock.Models;
|
||||||
|
using WireMock.Types;
|
||||||
|
using WireMock.Util;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace WireMock.Net.Tests.RequestMatchers;
|
||||||
|
|
||||||
|
public class RequestMessageMultiPartMatcherTests
|
||||||
|
{
|
||||||
|
private const string TestMultiPart = @"--=-5XgmpXt0XOfzdtcgNJc2ZQ==
|
||||||
|
Content-Type: text/plain; charset=utf-8
|
||||||
|
|
||||||
|
This is some plain text
|
||||||
|
--=-5XgmpXt0XOfzdtcgNJc2ZQ==
|
||||||
|
Content-Type: text/json; charset=utf-8
|
||||||
|
|
||||||
|
{
|
||||||
|
""Key"": ""Value""
|
||||||
|
}
|
||||||
|
--=-5XgmpXt0XOfzdtcgNJc2ZQ==
|
||||||
|
Content-Type: image/png; name=image.png
|
||||||
|
Content-Disposition: attachment; filename=image.png
|
||||||
|
Content-Transfer-Encoding: base64
|
||||||
|
|
||||||
|
iVBORw0KGgoAAAANSUhEUgAAAAIAAAACAgMAAAAP2OW3AAAADFBMVEX/tID/vpH/pWX/sHidUyjl
|
||||||
|
AAAADElEQVR4XmMQYNgAAADkAMHebX3mAAAAAElFTkSuQmCC
|
||||||
|
|
||||||
|
--=-5XgmpXt0XOfzdtcgNJc2ZQ==--
|
||||||
|
";
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void RequestMessageBodyMatcher_GetMatchingScore_BodyAsMultiPart()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var body = new BodyData
|
||||||
|
{
|
||||||
|
BodyAsString = TestMultiPart,
|
||||||
|
DetectedBodyType = BodyType.MultiPart
|
||||||
|
};
|
||||||
|
|
||||||
|
var textPlainContentTypeMatcher = new ContentTypeMatcher("text/plain");
|
||||||
|
var textPlainContentMatcher = new ExactMatcher("This is some plain text");
|
||||||
|
var textPlainMatcher = new MimePartMatcher(MatchBehaviour.AcceptOnMatch, textPlainContentTypeMatcher, null, null, textPlainContentMatcher);
|
||||||
|
|
||||||
|
var partTextJsonContentTypeMatcher = new ContentTypeMatcher("text/json");
|
||||||
|
var partTextJsonContentMatcher = new JsonMatcher(new { Key = "Value" }, true);
|
||||||
|
var partTextMatcher = new MimePartMatcher(MatchBehaviour.AcceptOnMatch, partTextJsonContentTypeMatcher, null, null, partTextJsonContentMatcher);
|
||||||
|
|
||||||
|
var imagePngContentTypeMatcher = new ContentTypeMatcher("image/png");
|
||||||
|
var imagePngContentDispositionMatcher = new ExactMatcher("attachment; filename=\"image.png\"");
|
||||||
|
var imagePngContentTransferEncodingMatcher = new ExactMatcher("base64");
|
||||||
|
var imagePngContentMatcher = new ExactObjectMatcher(Convert.FromBase64String("iVBORw0KGgoAAAANSUhEUgAAAAIAAAACAgMAAAAP2OW3AAAADFBMVEX/tID/vpH/pWX/sHidUyjlAAAADElEQVR4XmMQYNgAAADkAMHebX3mAAAAAElFTkSuQmCC"));
|
||||||
|
var imagePngMatcher = new MimePartMatcher(MatchBehaviour.AcceptOnMatch, imagePngContentTypeMatcher, imagePngContentDispositionMatcher, imagePngContentTransferEncodingMatcher, imagePngContentMatcher);
|
||||||
|
|
||||||
|
var matchers = new IMatcher[]
|
||||||
|
{
|
||||||
|
textPlainMatcher,
|
||||||
|
partTextMatcher,
|
||||||
|
imagePngMatcher
|
||||||
|
};
|
||||||
|
|
||||||
|
var headers = new Dictionary<string, string[]>
|
||||||
|
{
|
||||||
|
{ "Content-Type", new[] { @"multipart/mixed; boundary=""=-5XgmpXt0XOfzdtcgNJc2ZQ==""" } }
|
||||||
|
};
|
||||||
|
var requestMessage = new RequestMessage(new UrlDetails("http://localhost"), "GET", "127.0.0.1", body, headers);
|
||||||
|
|
||||||
|
var matcher = new RequestMessageMultiPartMatcher(matchers);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = new RequestMatchResult();
|
||||||
|
var score = matcher.GetMatchingScore(requestMessage, result);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
score.Should().Be(MatchScores.Perfect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -1,428 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
using FluentAssertions;
|
|
||||||
using JsonConverter.Abstractions;
|
|
||||||
using Moq;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using NFluent;
|
|
||||||
using WireMock.Matchers;
|
|
||||||
using WireMock.Matchers.Request;
|
|
||||||
using WireMock.Models;
|
|
||||||
using WireMock.RequestBuilders;
|
|
||||||
using WireMock.Types;
|
|
||||||
using WireMock.Util;
|
|
||||||
using Xunit;
|
|
||||||
|
|
||||||
namespace WireMock.Net.Tests
|
|
||||||
{
|
|
||||||
public class RequestWithBodyTests
|
|
||||||
{
|
|
||||||
private const string ClientIp = "::1";
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Request_WithBody_FuncString()
|
|
||||||
{
|
|
||||||
// Assign
|
|
||||||
var requestBuilder = Request.Create().UsingAnyMethod().WithBody(b => b.Contains("b"));
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var body = new BodyData
|
|
||||||
{
|
|
||||||
BodyAsString = "b",
|
|
||||||
DetectedBodyType = BodyType.String
|
|
||||||
};
|
|
||||||
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "POST", ClientIp, body);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
var requestMatchResult = new RequestMatchResult();
|
|
||||||
Check.That(requestBuilder.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Request_WithBody_FuncJson()
|
|
||||||
{
|
|
||||||
// Assign
|
|
||||||
var requestBuilder = Request.Create().UsingAnyMethod().WithBody(b => b != null);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var body = new BodyData
|
|
||||||
{
|
|
||||||
BodyAsJson = 123,
|
|
||||||
DetectedBodyType = BodyType.Json
|
|
||||||
};
|
|
||||||
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "POST", ClientIp, body);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
var requestMatchResult = new RequestMatchResult();
|
|
||||||
Check.That(requestBuilder.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Request_WithBody_FuncFormUrlEncoded()
|
|
||||||
{
|
|
||||||
// Assign
|
|
||||||
var requestBuilder = Request.Create().UsingAnyMethod().WithBody((IDictionary<string, string>? values) => values != null);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var body = new BodyData
|
|
||||||
{
|
|
||||||
BodyAsFormUrlEncoded = new Dictionary<string, string>(),
|
|
||||||
DetectedBodyTypeFromContentType = BodyType.FormUrlEncoded,
|
|
||||||
DetectedBodyType = BodyType.FormUrlEncoded
|
|
||||||
};
|
|
||||||
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "POST", ClientIp, body);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
var requestMatchResult = new RequestMatchResult();
|
|
||||||
Check.That(requestBuilder.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Request_WithBody_FuncBodyData()
|
|
||||||
{
|
|
||||||
// Assign
|
|
||||||
var requestBuilder = Request.Create().UsingAnyMethod().WithBody((IBodyData? b) => b != null);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var body = new BodyData
|
|
||||||
{
|
|
||||||
BodyAsJson = 123,
|
|
||||||
DetectedBodyType = BodyType.Json
|
|
||||||
};
|
|
||||||
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "POST", ClientIp, body);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
var requestMatchResult = new RequestMatchResult();
|
|
||||||
Check.That(requestBuilder.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Request_WithBody_FuncByteArray()
|
|
||||||
{
|
|
||||||
// Assign
|
|
||||||
var requestBuilder = Request.Create().UsingAnyMethod().WithBody((byte[]? b) => b != null);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var body = new BodyData
|
|
||||||
{
|
|
||||||
BodyAsBytes = new byte[0],
|
|
||||||
DetectedBodyType = BodyType.Bytes
|
|
||||||
};
|
|
||||||
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "POST", ClientIp, body);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
var requestMatchResult = new RequestMatchResult();
|
|
||||||
Check.That(requestBuilder.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Request_WithBodyExactMatcher()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var requestBuilder = Request.Create().UsingAnyMethod().WithBody(new ExactMatcher("cat"));
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var body = new BodyData
|
|
||||||
{
|
|
||||||
BodyAsString = "cat",
|
|
||||||
DetectedBodyType = BodyType.String
|
|
||||||
};
|
|
||||||
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "POST", ClientIp, body);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
var requestMatchResult = new RequestMatchResult();
|
|
||||||
Check.That(requestBuilder.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Request_WithBody_BodyDataAsString_Using_WildcardMatcher()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var spec = Request.Create().WithPath("/foo").UsingAnyMethod().WithBody(new WildcardMatcher("H*o*"));
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var body = new BodyData
|
|
||||||
{
|
|
||||||
BodyAsString = "Hello world!",
|
|
||||||
DetectedBodyType = BodyType.String
|
|
||||||
};
|
|
||||||
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, body);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
var requestMatchResult = new RequestMatchResult();
|
|
||||||
spec.GetMatchingScore(request, requestMatchResult).Should().Be(1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Request_WithBody_BodyDataAsJson_Using_WildcardMatcher()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var spec = Request.Create().WithPath("/foo").UsingAnyMethod().WithBody(new WildcardMatcher("*Hello*"));
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var body = new BodyData
|
|
||||||
{
|
|
||||||
BodyAsJson = new { Hi = "Hello world!" },
|
|
||||||
BodyAsString = "{ Hi = \"Hello world!\" }",
|
|
||||||
DetectedBodyType = BodyType.Json
|
|
||||||
};
|
|
||||||
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, body);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
var requestMatchResult = new RequestMatchResult();
|
|
||||||
spec.GetMatchingScore(request, requestMatchResult).Should().Be(1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Request_WithBodyXPathMatcher_true()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var spec = Request.Create().UsingAnyMethod().WithBody(new XPathMatcher("/todo-list[count(todo-item) = 3]"));
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var body = new BodyData
|
|
||||||
{
|
|
||||||
BodyAsString = @"
|
|
||||||
<todo-list>
|
|
||||||
<todo-item id='a1'>abc</todo-item>
|
|
||||||
<todo-item id='a2'>def</todo-item>
|
|
||||||
<todo-item id='a3'>xyz</todo-item>
|
|
||||||
</todo-list>",
|
|
||||||
DetectedBodyType = BodyType.String
|
|
||||||
};
|
|
||||||
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, body);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
var requestMatchResult = new RequestMatchResult();
|
|
||||||
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Request_WithBodyXPathMatcher_false()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var spec = Request.Create().UsingAnyMethod().WithBody(new XPathMatcher("/todo-list[count(todo-item) = 99]"));
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var body = new BodyData
|
|
||||||
{
|
|
||||||
BodyAsString = @"
|
|
||||||
<todo-list>
|
|
||||||
<todo-item id='a1'>abc</todo-item>
|
|
||||||
<todo-item id='a2'>def</todo-item>
|
|
||||||
<todo-item id='a3'>xyz</todo-item>
|
|
||||||
</todo-list>",
|
|
||||||
DetectedBodyType = BodyType.String
|
|
||||||
};
|
|
||||||
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, body);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
var requestMatchResult = new RequestMatchResult();
|
|
||||||
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsNotEqualTo(1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Request_WithBodyJsonPathMatcher_true()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var spec = Request.Create().UsingAnyMethod().WithBody(new JsonPathMatcher("$..things[?(@.name == 'RequiredThing')]"));
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var body = new BodyData
|
|
||||||
{
|
|
||||||
BodyAsString = "{ \"things\": [ { \"name\": \"RequiredThing\" }, { \"name\": \"Wiremock\" } ] }",
|
|
||||||
DetectedBodyType = BodyType.String
|
|
||||||
};
|
|
||||||
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, body);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
var requestMatchResult = new RequestMatchResult();
|
|
||||||
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Request_WithBodyJsonPathMatcher_false()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var spec = Request.Create().UsingAnyMethod().WithBody(new JsonPathMatcher("$.things[?(@.name == 'RequiredThing')]"));
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var body = new BodyData
|
|
||||||
{
|
|
||||||
BodyAsString = "{ \"things\": { \"name\": \"Wiremock\" } }",
|
|
||||||
DetectedBodyType = BodyType.String
|
|
||||||
};
|
|
||||||
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, body);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
var requestMatchResult = new RequestMatchResult();
|
|
||||||
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsNotEqualTo(1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Request_WithBodyAsJson_Object_JsonPathMatcher_true()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var spec = Request.Create().UsingAnyMethod().WithBody(new JsonPathMatcher("$..things[?(@.name == 'RequiredThing')]"));
|
|
||||||
|
|
||||||
// Act
|
|
||||||
string jsonString = "{ \"things\": [ { \"name\": \"RequiredThing\" }, { \"name\": \"Wiremock\" } ] }";
|
|
||||||
var bodyData = new BodyData
|
|
||||||
{
|
|
||||||
BodyAsJson = JsonConvert.DeserializeObject(jsonString),
|
|
||||||
BodyAsString = jsonString,
|
|
||||||
Encoding = Encoding.UTF8,
|
|
||||||
DetectedBodyType = BodyType.Json
|
|
||||||
};
|
|
||||||
|
|
||||||
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, bodyData);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
var requestMatchResult = new RequestMatchResult();
|
|
||||||
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Request_WithBodyAsJson_Array_JsonPathMatcher_1()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var spec = Request.Create().UsingAnyMethod().WithBody(new JsonPathMatcher("$..books[?(@.price < 10)]"));
|
|
||||||
|
|
||||||
// Act
|
|
||||||
string jsonString = "{ \"books\": [ { \"category\": \"test1\", \"price\": 8.95 }, { \"category\": \"test2\", \"price\": 20 } ] }";
|
|
||||||
var bodyData = new BodyData
|
|
||||||
{
|
|
||||||
BodyAsJson = JsonConvert.DeserializeObject(jsonString),
|
|
||||||
BodyAsString = jsonString,
|
|
||||||
Encoding = Encoding.UTF8,
|
|
||||||
DetectedBodyType = BodyType.Json
|
|
||||||
};
|
|
||||||
|
|
||||||
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, bodyData);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
var requestMatchResult = new RequestMatchResult();
|
|
||||||
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Request_WithBodyAsJson_Array_JsonPathMatcher_2()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var spec = Request.Create().UsingAnyMethod().WithBody(new JsonPathMatcher("$..[?(@.Id == 1)]"));
|
|
||||||
|
|
||||||
// Act
|
|
||||||
string jsonString = "{ \"Id\": 1, \"Name\": \"Test\" }";
|
|
||||||
var bodyData = new BodyData
|
|
||||||
{
|
|
||||||
BodyAsJson = JsonConvert.DeserializeObject(jsonString),
|
|
||||||
BodyAsString = jsonString,
|
|
||||||
Encoding = Encoding.UTF8,
|
|
||||||
DetectedBodyType = BodyType.Json
|
|
||||||
};
|
|
||||||
|
|
||||||
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, bodyData);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
var requestMatchResult = new RequestMatchResult();
|
|
||||||
double result = spec.GetMatchingScore(request, requestMatchResult);
|
|
||||||
Check.That(result).IsEqualTo(1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Request_WithBodyAsObject_ExactObjectMatcher_true()
|
|
||||||
{
|
|
||||||
// Assign
|
|
||||||
object body = DateTime.MinValue;
|
|
||||||
var requestBuilder = Request.Create().UsingAnyMethod().WithBody(body);
|
|
||||||
|
|
||||||
var bodyData = new BodyData
|
|
||||||
{
|
|
||||||
BodyAsJson = DateTime.MinValue,
|
|
||||||
DetectedBodyType = BodyType.Json
|
|
||||||
};
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, bodyData);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
var requestMatchResult = new RequestMatchResult();
|
|
||||||
Check.That(requestBuilder.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Request_WithBodyAsJson_UsingObject()
|
|
||||||
{
|
|
||||||
// Assign
|
|
||||||
object body = new
|
|
||||||
{
|
|
||||||
Test = "abc"
|
|
||||||
};
|
|
||||||
var requestBuilder = Request.Create().UsingAnyMethod().WithBodyAsJson(body);
|
|
||||||
|
|
||||||
var bodyData = new BodyData
|
|
||||||
{
|
|
||||||
BodyAsString = JsonConvert.SerializeObject(body),
|
|
||||||
DetectedBodyType = BodyType.String
|
|
||||||
};
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "POST", ClientIp, bodyData);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
var requestMatchResult = new RequestMatchResult();
|
|
||||||
Check.That(requestBuilder.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Request_WithBodyAsJson_WithIJsonConverter_UsingObject()
|
|
||||||
{
|
|
||||||
// Assign
|
|
||||||
var jsonConverterMock = new Mock<IJsonConverter>();
|
|
||||||
jsonConverterMock.Setup(j => j.Serialize(It.IsAny<object>(), It.IsAny<JsonConverterOptions>())).Returns("test");
|
|
||||||
object body = new
|
|
||||||
{
|
|
||||||
Any = "key"
|
|
||||||
};
|
|
||||||
var requestBuilder = Request.Create().UsingAnyMethod().WithBodyAsJson(body, jsonConverterMock.Object);
|
|
||||||
|
|
||||||
var bodyData = new BodyData
|
|
||||||
{
|
|
||||||
BodyAsString = "test",
|
|
||||||
DetectedBodyType = BodyType.String
|
|
||||||
};
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "POST", ClientIp, bodyData);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
var requestMatchResult = new RequestMatchResult();
|
|
||||||
Check.That(requestBuilder.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory]
|
|
||||||
[InlineData(new byte[] { 1 }, BodyType.Bytes)]
|
|
||||||
[InlineData(new byte[] { 48, 49, 50 }, BodyType.Bytes)]
|
|
||||||
[InlineData(new byte[] { 48, 49, 50 }, BodyType.String)]
|
|
||||||
public void Request_WithBodyAsBytes_ExactObjectMatcher_true(byte[] bytes, BodyType detectedBodyType)
|
|
||||||
{
|
|
||||||
// Assign
|
|
||||||
byte[] body = bytes;
|
|
||||||
var requestBuilder = Request.Create().UsingAnyMethod().WithBody(body);
|
|
||||||
|
|
||||||
var bodyData = new BodyData
|
|
||||||
{
|
|
||||||
BodyAsBytes = bytes,
|
|
||||||
DetectedBodyType = detectedBodyType
|
|
||||||
};
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, bodyData);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
var requestMatchResult = new RequestMatchResult();
|
|
||||||
requestBuilder.GetMatchingScore(request, requestMatchResult).Should().Be(1.0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
using NFluent;
|
|
||||||
using WireMock.Matchers;
|
|
||||||
using WireMock.Matchers.Request;
|
|
||||||
using WireMock.Models;
|
|
||||||
using WireMock.RequestBuilders;
|
|
||||||
using Xunit;
|
|
||||||
|
|
||||||
namespace WireMock.Net.Tests
|
|
||||||
{
|
|
||||||
public class RequestWithClientIPTests
|
|
||||||
{
|
|
||||||
[Fact]
|
|
||||||
public void Request_WithClientIP_Match_Ok()
|
|
||||||
{
|
|
||||||
// given
|
|
||||||
var spec = Request.Create().WithClientIP("127.0.0.2", "1.1.1.1");
|
|
||||||
|
|
||||||
// when
|
|
||||||
var request = new RequestMessage(new UrlDetails("http://localhost"), "GET", "127.0.0.2");
|
|
||||||
|
|
||||||
// then
|
|
||||||
var requestMatchResult = new RequestMatchResult();
|
|
||||||
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Request_WithClientIP_Match_Fail()
|
|
||||||
{
|
|
||||||
// given
|
|
||||||
var spec = Request.Create().WithClientIP("127.0.0.2");
|
|
||||||
|
|
||||||
// when
|
|
||||||
var request = new RequestMessage(new UrlDetails("http://localhost"), "GET", "192.1.1.1");
|
|
||||||
|
|
||||||
// then
|
|
||||||
var requestMatchResult = new RequestMatchResult();
|
|
||||||
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(0.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Request_WithClientIP_WildcardMatcher()
|
|
||||||
{
|
|
||||||
// given
|
|
||||||
var spec = Request.Create().WithClientIP(new WildcardMatcher("127.0.0.2"));
|
|
||||||
|
|
||||||
// when
|
|
||||||
var request = new RequestMessage(new UrlDetails("http://localhost"), "GET", "127.0.0.2");
|
|
||||||
|
|
||||||
// then
|
|
||||||
var requestMatchResult = new RequestMatchResult();
|
|
||||||
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Request_WithClientIP_Func()
|
|
||||||
{
|
|
||||||
// given
|
|
||||||
var spec = Request.Create().WithClientIP(c => c.Contains("."));
|
|
||||||
|
|
||||||
// when
|
|
||||||
var request = new RequestMessage(new UrlDetails("http://localhost"), "GET", "127.0.0.2");
|
|
||||||
|
|
||||||
// then
|
|
||||||
var requestMatchResult = new RequestMatchResult();
|
|
||||||
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,239 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using NFluent;
|
|
||||||
using WireMock.Matchers;
|
|
||||||
using Xunit;
|
|
||||||
using WireMock.RequestBuilders;
|
|
||||||
using WireMock.Matchers.Request;
|
|
||||||
using WireMock.Models;
|
|
||||||
using WireMock.Util;
|
|
||||||
|
|
||||||
namespace WireMock.Net.Tests
|
|
||||||
{
|
|
||||||
public class RequestWithPathTests
|
|
||||||
{
|
|
||||||
private const string ClientIp = "::1";
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Request_WithPath_Spaces()
|
|
||||||
{
|
|
||||||
// Assign
|
|
||||||
var spec = Request.Create().WithPath("/path/a b").UsingAnyMethod();
|
|
||||||
|
|
||||||
// when
|
|
||||||
var body = new BodyData();
|
|
||||||
var request = new RequestMessage(new UrlDetails("http://localhost/path/a b"), "GET", ClientIp, body);
|
|
||||||
|
|
||||||
// then
|
|
||||||
var requestMatchResult = new RequestMatchResult();
|
|
||||||
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Request_WithPath_WithHeader_Match()
|
|
||||||
{
|
|
||||||
// given
|
|
||||||
var spec = Request.Create().WithPath("/foo").UsingAnyMethod().WithHeader("X-toto", "tata");
|
|
||||||
|
|
||||||
// when
|
|
||||||
var body = new BodyData
|
|
||||||
{
|
|
||||||
BodyAsString = "abc"
|
|
||||||
};
|
|
||||||
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp, body, new Dictionary<string, string[]> { { "X-toto", new[] { "tata" } } });
|
|
||||||
|
|
||||||
// then
|
|
||||||
var requestMatchResult = new RequestMatchResult();
|
|
||||||
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Request_WithPath()
|
|
||||||
{
|
|
||||||
// given
|
|
||||||
var spec = Request.Create().WithPath("/foo");
|
|
||||||
|
|
||||||
// when
|
|
||||||
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "blabla", ClientIp);
|
|
||||||
|
|
||||||
// then
|
|
||||||
var requestMatchResult = new RequestMatchResult();
|
|
||||||
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Request_WithPaths()
|
|
||||||
{
|
|
||||||
var requestBuilder = Request.Create().WithPath("/x1", "/x2");
|
|
||||||
|
|
||||||
var request1 = new RequestMessage(new UrlDetails("http://localhost/x1"), "blabla", ClientIp);
|
|
||||||
var request2 = new RequestMessage(new UrlDetails("http://localhost/x2"), "blabla", ClientIp);
|
|
||||||
|
|
||||||
var requestMatchResult = new RequestMatchResult();
|
|
||||||
Check.That(requestBuilder.GetMatchingScore(request1, requestMatchResult)).IsEqualTo(1.0);
|
|
||||||
Check.That(requestBuilder.GetMatchingScore(request2, requestMatchResult)).IsEqualTo(1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Request_WithPathFunc()
|
|
||||||
{
|
|
||||||
// given
|
|
||||||
var spec = Request.Create().WithPath(url => url.EndsWith("/foo"));
|
|
||||||
|
|
||||||
// when
|
|
||||||
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "blabla", ClientIp);
|
|
||||||
|
|
||||||
// then
|
|
||||||
var requestMatchResult = new RequestMatchResult();
|
|
||||||
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Request_WithPathRegexMatcher_HasMatch()
|
|
||||||
{
|
|
||||||
// given
|
|
||||||
var spec = Request.Create().WithPath(new RegexMatcher("^/foo"));
|
|
||||||
|
|
||||||
// when
|
|
||||||
var request = new RequestMessage(new UrlDetails("http://localhost/foo/bar"), "blabla", ClientIp);
|
|
||||||
|
|
||||||
// then
|
|
||||||
var requestMatchResult = new RequestMatchResult();
|
|
||||||
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Request_WithPathRegexMatcher_HasNoMatch()
|
|
||||||
{
|
|
||||||
// given
|
|
||||||
var spec = Request.Create().WithPath("/foo");
|
|
||||||
|
|
||||||
// when
|
|
||||||
var request = new RequestMessage(new UrlDetails("http://localhost/bar"), "blabla", ClientIp);
|
|
||||||
|
|
||||||
// then
|
|
||||||
var requestMatchResult = new RequestMatchResult();
|
|
||||||
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsNotEqualTo(1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Request_WithPathRegexMatcher_WithPatternAsFile_HasMatch()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var pattern = new StringPattern
|
|
||||||
{
|
|
||||||
Pattern = "^/foo",
|
|
||||||
PatternAsFile = "c:\\x.txt"
|
|
||||||
};
|
|
||||||
var spec = Request.Create().WithPath(new RegexMatcher(pattern));
|
|
||||||
|
|
||||||
// when
|
|
||||||
var request = new RequestMessage(new UrlDetails("http://localhost/foo/bar"), "blabla", ClientIp);
|
|
||||||
|
|
||||||
// then
|
|
||||||
var requestMatchResult = new RequestMatchResult();
|
|
||||||
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Should_specify_requests_matching_given_path_and_method_delete()
|
|
||||||
{
|
|
||||||
// given
|
|
||||||
var spec = Request.Create().WithPath("/foo").UsingDelete();
|
|
||||||
|
|
||||||
// when
|
|
||||||
var body = new BodyData
|
|
||||||
{
|
|
||||||
BodyAsString = "whatever"
|
|
||||||
};
|
|
||||||
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "Delete", ClientIp, body);
|
|
||||||
|
|
||||||
// then
|
|
||||||
var requestMatchResult = new RequestMatchResult();
|
|
||||||
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Should_specify_requests_matching_given_path_and_method_get()
|
|
||||||
{
|
|
||||||
// given
|
|
||||||
var spec = Request.Create().WithPath("/foo").UsingGet();
|
|
||||||
|
|
||||||
// when
|
|
||||||
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "GET", ClientIp);
|
|
||||||
|
|
||||||
// then
|
|
||||||
var requestMatchResult = new RequestMatchResult();
|
|
||||||
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Should_specify_requests_matching_given_path_and_method_head()
|
|
||||||
{
|
|
||||||
// given
|
|
||||||
var spec = Request.Create().WithPath("/foo").UsingHead();
|
|
||||||
|
|
||||||
// when
|
|
||||||
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "HEAD", ClientIp);
|
|
||||||
|
|
||||||
// then
|
|
||||||
var requestMatchResult = new RequestMatchResult();
|
|
||||||
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Should_specify_requests_matching_given_path_and_method_post()
|
|
||||||
{
|
|
||||||
// given
|
|
||||||
var spec = Request.Create().WithPath("/foo").UsingPost();
|
|
||||||
|
|
||||||
// when
|
|
||||||
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "POST", ClientIp);
|
|
||||||
|
|
||||||
// then
|
|
||||||
var requestMatchResult = new RequestMatchResult();
|
|
||||||
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Should_specify_requests_matching_given_path_and_method_put()
|
|
||||||
{
|
|
||||||
// given
|
|
||||||
var spec = Request.Create().WithPath("/foo").UsingPut();
|
|
||||||
|
|
||||||
// when
|
|
||||||
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PUT", ClientIp);
|
|
||||||
|
|
||||||
// then
|
|
||||||
var requestMatchResult = new RequestMatchResult();
|
|
||||||
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Should_specify_requests_matching_given_path_and_method_patch()
|
|
||||||
{
|
|
||||||
// given
|
|
||||||
var spec = Request.Create().WithPath("/foo").UsingPatch();
|
|
||||||
|
|
||||||
// when
|
|
||||||
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "PATCH", ClientIp);
|
|
||||||
|
|
||||||
// then
|
|
||||||
var requestMatchResult = new RequestMatchResult();
|
|
||||||
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsEqualTo(1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Should_exclude_requests_matching_given_path_but_not_http_method()
|
|
||||||
{
|
|
||||||
// given
|
|
||||||
var spec = Request.Create().WithPath("/foo").UsingPut();
|
|
||||||
|
|
||||||
// when
|
|
||||||
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "HEAD", ClientIp);
|
|
||||||
|
|
||||||
// then
|
|
||||||
var requestMatchResult = new RequestMatchResult();
|
|
||||||
Check.That(spec.GetMatchingScore(request, requestMatchResult)).IsNotEqualTo(1.0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -783,6 +783,59 @@ public class ResponseWithTransformerTests
|
|||||||
response.Message.BodyData.Encoding.Should().Be(enc);
|
response.Message.BodyData.Encoding.Should().Be(enc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if MIMEKIT
|
||||||
|
[Theory]
|
||||||
|
[InlineData(TransformerType.Handlebars)]
|
||||||
|
// [InlineData(TransformerType.Scriban)]
|
||||||
|
// [InlineData(TransformerType.ScribanDotLiquid)]
|
||||||
|
public async Task Response_ProvideResponse_Transformer_WithBodyAsMimeMessage(TransformerType transformerType)
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var multiPart = @"--=-5XgmpXt0XOfzdtcgNJc2ZQ==
|
||||||
|
Content-Type: text/plain; charset=utf-8
|
||||||
|
|
||||||
|
This is some plain text
|
||||||
|
--=-5XgmpXt0XOfzdtcgNJc2ZQ==
|
||||||
|
Content-Type: text/json; charset=utf-8
|
||||||
|
|
||||||
|
{
|
||||||
|
""Key"": ""Value""
|
||||||
|
}
|
||||||
|
--=-5XgmpXt0XOfzdtcgNJc2ZQ==
|
||||||
|
Content-Type: image/png; name=image.png
|
||||||
|
Content-Disposition: attachment; filename=image.png
|
||||||
|
Content-Transfer-Encoding: base64
|
||||||
|
|
||||||
|
iVBORw0KGgoAAAANSUhEUgAAAAIAAAACAgMAAAAP2OW3AAAADFBMVEX/tID/vpH/pWX/sHidUyjl
|
||||||
|
AAAADElEQVR4XmMQYNgAAADkAMHebX3mAAAAAElFTkSuQmCC
|
||||||
|
|
||||||
|
--=-5XgmpXt0XOfzdtcgNJc2ZQ==--
|
||||||
|
";
|
||||||
|
|
||||||
|
var bodyData = new BodyData
|
||||||
|
{
|
||||||
|
BodyAsString = multiPart,
|
||||||
|
DetectedBodyType = BodyType.MultiPart
|
||||||
|
};
|
||||||
|
|
||||||
|
var headers = new Dictionary<string, string[]>
|
||||||
|
{
|
||||||
|
{ "Content-Type", new[] { @"multipart/mixed; boundary=""=-5XgmpXt0XOfzdtcgNJc2ZQ=="""} }
|
||||||
|
};
|
||||||
|
var request = new RequestMessage(new UrlDetails("http://localhost/foo_object"), "POST", ClientIp, bodyData, headers);
|
||||||
|
|
||||||
|
var responseBuilder = Response.Create()
|
||||||
|
.WithBody("{{request.BodyAsMimeMessage.BodyParts.[0].ContentType.MimeType}} {{request.BodyAsMimeMessage.BodyParts.[1].ContentType.MimeType}} {{request.BodyAsMimeMessage.BodyParts.[2].FileName}}")
|
||||||
|
.WithTransformer(transformerType);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await responseBuilder.ProvideResponseAsync(_mappingMock.Object, request, _settings).ConfigureAwait(false);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
response.Message.BodyData!.BodyAsString.Should().Be("text/plain text/json image.png");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData("/wiremock-data/1", "one")]
|
[InlineData("/wiremock-data/1", "one")]
|
||||||
[InlineData("/wiremock-data/2", "two")]
|
[InlineData("/wiremock-data/2", "two")]
|
||||||
|
|||||||
@@ -56,6 +56,40 @@ public class MatcherMapperTests
|
|||||||
models.Should().HaveCount(2);
|
models.Should().HaveCount(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if MIMEKIT
|
||||||
|
[Fact]
|
||||||
|
public void MatcherMapper_Map_MimePartMatcher()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var bytes = Convert.FromBase64String("c3RlZg==");
|
||||||
|
var imagePngContentTypeMatcher = new ContentTypeMatcher("image/png");
|
||||||
|
var imagePngContentDispositionMatcher = new ExactMatcher("attachment; filename=\"image.png\"");
|
||||||
|
var imagePngContentTransferEncodingMatcher = new ExactMatcher("base64");
|
||||||
|
var imagePngContentMatcher = new ExactObjectMatcher(bytes);
|
||||||
|
var imagePngMatcher = new MimePartMatcher(MatchBehaviour.AcceptOnMatch, imagePngContentTypeMatcher, imagePngContentDispositionMatcher, imagePngContentTransferEncodingMatcher, imagePngContentMatcher);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var model = _sut.Map(imagePngMatcher)!;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
model.Name.Should().Be(nameof(MimePartMatcher));
|
||||||
|
model.MatchOperator.Should().BeNull();
|
||||||
|
model.RejectOnMatch.Should().BeNull();
|
||||||
|
|
||||||
|
model.ContentTypeMatcher!.Name.Should().Be(nameof(ContentTypeMatcher));
|
||||||
|
model.ContentTypeMatcher.Pattern.Should().Be("image/png");
|
||||||
|
|
||||||
|
model.ContentDispositionMatcher!.Name.Should().Be(nameof(ExactMatcher));
|
||||||
|
model.ContentDispositionMatcher.Pattern.Should().Be("attachment; filename=\"image.png\"");
|
||||||
|
|
||||||
|
model.ContentTransferEncodingMatcher!.Name.Should().Be(nameof(ExactMatcher));
|
||||||
|
model.ContentTransferEncodingMatcher.Pattern.Should().Be("base64");
|
||||||
|
|
||||||
|
model.ContentMatcher!.Name.Should().Be(nameof(ExactObjectMatcher));
|
||||||
|
model.ContentMatcher.Pattern.Should().Be(bytes);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void MatcherMapper_Map_IStringMatcher()
|
public void MatcherMapper_Map_IStringMatcher()
|
||||||
{
|
{
|
||||||
@@ -428,4 +462,64 @@ public class MatcherMapperTests
|
|||||||
matcher.GetPatterns().Should().Contain("p");
|
matcher.GetPatterns().Should().Contain("p");
|
||||||
matcher.IgnoreCase.Should().BeTrue();
|
matcher.IgnoreCase.Should().BeTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void MatcherMapper_Map_MatcherModel_NotNullOrEmptyMatcher()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var model = new MatcherModel
|
||||||
|
{
|
||||||
|
Name = "NotNullOrEmptyMatcher",
|
||||||
|
RejectOnMatch = true
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var matcher = _sut.Map(model)!;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
matcher.Should().BeAssignableTo<NotNullOrEmptyMatcher>();
|
||||||
|
matcher.MatchBehaviour.Should().Be(MatchBehaviour.RejectOnMatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if MIMEKIT
|
||||||
|
[Fact]
|
||||||
|
public void MatcherMapper_Map_MatcherModel_MimePartMatcher()
|
||||||
|
{
|
||||||
|
// Assign
|
||||||
|
var model = new MatcherModel
|
||||||
|
{
|
||||||
|
Name = "MimePartMatcher",
|
||||||
|
ContentMatcher = new MatcherModel
|
||||||
|
{
|
||||||
|
Name = "ExactMatcher",
|
||||||
|
Pattern = "x"
|
||||||
|
},
|
||||||
|
ContentDispositionMatcher = new MatcherModel
|
||||||
|
{
|
||||||
|
Name = "WildcardMatcher",
|
||||||
|
Pattern = "y"
|
||||||
|
},
|
||||||
|
ContentTransferEncodingMatcher = new MatcherModel
|
||||||
|
{
|
||||||
|
Name = "RegexMatcher",
|
||||||
|
Pattern = "z"
|
||||||
|
},
|
||||||
|
ContentTypeMatcher = new MatcherModel
|
||||||
|
{
|
||||||
|
Name = "ContentTypeMatcher",
|
||||||
|
Pattern = "text/json"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var matcher = (MimePartMatcher)_sut.Map(model)!;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
matcher.MatchBehaviour.Should().Be(MatchBehaviour.AcceptOnMatch);
|
||||||
|
matcher.ContentMatcher.Should().BeAssignableTo<ExactMatcher>().Which.GetPatterns().Should().ContainSingle("x");
|
||||||
|
matcher.ContentDispositionMatcher.Should().BeAssignableTo<WildcardMatcher>().Which.GetPatterns().Should().ContainSingle("y");
|
||||||
|
matcher.ContentTransferEncodingMatcher.Should().BeAssignableTo<RegexMatcher>().Which.GetPatterns().Should().ContainSingle("z");
|
||||||
|
matcher.ContentTypeMatcher.Should().BeAssignableTo<ContentTypeMatcher>().Which.GetPatterns().Should().ContainSingle("text/json");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(TargetFramework)' != 'netstandard1.3' and '$(TargetFramework)' != 'net451' and '$(TargetFramework)' != 'net452' and '$(TargetFramework)' != 'net46' and '$(TargetFramework)' != 'net461'">
|
<PropertyGroup Condition="'$(TargetFramework)' != 'netstandard1.3' and '$(TargetFramework)' != 'net451' and '$(TargetFramework)' != 'net452' and '$(TargetFramework)' != 'net46' and '$(TargetFramework)' != 'net461'">
|
||||||
<DefineConstants>$(DefineConstants);GRAPHQL</DefineConstants>
|
<DefineConstants>$(DefineConstants);GRAPHQL;MIMEKIT</DefineConstants>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -95,12 +95,12 @@
|
|||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Verify.Xunit" Version="19.6.0" />
|
<PackageReference Include="Verify.Xunit" Version="19.6.0" />
|
||||||
|
<PackageReference Include="MimeKitLite" Version="4.1.0.1" PrivateAssets="all" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup Condition="'$(TargetFramework)' != 'net452'">
|
<ItemGroup Condition="'$(TargetFramework)' != 'net452'">
|
||||||
<PackageReference Include="System.Net.Http.Json" Version="3.2.1" />
|
<PackageReference Include="System.Net.Http.Json" Version="3.2.1" />
|
||||||
<PackageReference Include="JsonConverter.System.Text.Json" Version="0.4.0" />
|
<PackageReference Include="JsonConverter.System.Text.Json" Version="0.4.0" />
|
||||||
<!--<PackageReference Include="JsonConverter.NewtonSoft.Json" Version="0.4.0" />-->
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -138,5 +138,4 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="Pact\files\" />
|
<Folder Include="Pact\files\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
#if MIMEKIT
|
||||||
|
using System;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Net.Http.Headers;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using FluentAssertions;
|
||||||
|
using WireMock.Matchers;
|
||||||
|
using WireMock.RequestBuilders;
|
||||||
|
using WireMock.ResponseBuilders;
|
||||||
|
using WireMock.Server;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace WireMock.Net.Tests;
|
||||||
|
|
||||||
|
public partial class WireMockServerTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public async Task WireMockServer_WithMultiPartBody_Using_MimePartMatchers()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var server = WireMockServer.Start();
|
||||||
|
|
||||||
|
var textPlainContent = "This is some plain text";
|
||||||
|
var textPlainContentType = "text/plain";
|
||||||
|
var textPlainContentTypeMatcher = new ContentTypeMatcher(textPlainContentType);
|
||||||
|
var textPlainContentMatcher = new ExactMatcher(textPlainContent);
|
||||||
|
var textPlainMatcher = new MimePartMatcher(MatchBehaviour.AcceptOnMatch, textPlainContentTypeMatcher, null, null, textPlainContentMatcher);
|
||||||
|
|
||||||
|
var textJson = "{ \"Key\" : \"Value\" }";
|
||||||
|
var textJsonContentType = "text/json";
|
||||||
|
var textJsonContentTypeMatcher = new ContentTypeMatcher(textJsonContentType);
|
||||||
|
var textJsonContentMatcher = new JsonMatcher(new { Key = "Value" }, true);
|
||||||
|
var jsonMatcher = new MimePartMatcher(MatchBehaviour.AcceptOnMatch, textJsonContentTypeMatcher, null, null, textJsonContentMatcher);
|
||||||
|
|
||||||
|
var imagePngBytes = Convert.FromBase64String("iVBORw0KGgoAAAANSUhEUgAAAAIAAAACAgMAAAAP2OW3AAAADFBMVEX/tID/vpH/pWX/sHidUyjlAAAADElEQVR4XmMQYNgAAADkAMHebX3mAAAAAElFTkSuQmCC");
|
||||||
|
var imagePngContentMatcher = new ExactObjectMatcher(imagePngBytes);
|
||||||
|
var imagePngMatcher = new MimePartMatcher(MatchBehaviour.AcceptOnMatch, null, null, null, imagePngContentMatcher);
|
||||||
|
|
||||||
|
var matchers = new IMatcher[]
|
||||||
|
{
|
||||||
|
textPlainMatcher,
|
||||||
|
jsonMatcher,
|
||||||
|
imagePngMatcher
|
||||||
|
};
|
||||||
|
|
||||||
|
server
|
||||||
|
.Given(
|
||||||
|
Request.Create()
|
||||||
|
.UsingPost()
|
||||||
|
.WithPath("/multipart")
|
||||||
|
.WithMultiPart(matchers))
|
||||||
|
.RespondWith(Response.Create());
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var formDataContent = new MultipartFormDataContent();
|
||||||
|
formDataContent.Add(new StringContent(textPlainContent, Encoding.UTF8, textPlainContentType), "text");
|
||||||
|
formDataContent.Add(new StringContent(textJson, Encoding.UTF8, textJsonContentType), "json");
|
||||||
|
|
||||||
|
var fileContent = new ByteArrayContent(imagePngBytes);
|
||||||
|
fileContent.Headers.ContentType = new MediaTypeHeaderValue("image/png");
|
||||||
|
formDataContent.Add(fileContent, "somefile", "image.png");
|
||||||
|
|
||||||
|
var client = server.CreateClient();
|
||||||
|
|
||||||
|
var response = await client.PostAsync("/multipart", formDataContent);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||||
|
|
||||||
|
server.Stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
+39
@@ -0,0 +1,39 @@
|
|||||||
|
namespace MultipartUploader
|
||||||
|
{
|
||||||
|
partial class Form1
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Required designer variable.
|
||||||
|
/// </summary>
|
||||||
|
private System.ComponentModel.IContainer components = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clean up any resources being used.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing && (components != null))
|
||||||
|
{
|
||||||
|
components.Dispose();
|
||||||
|
}
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Windows Form Designer generated code
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Required method for Designer support - do not modify
|
||||||
|
/// the contents of this method with the code editor.
|
||||||
|
/// </summary>
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
this.components = new System.ComponentModel.Container();
|
||||||
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
|
this.ClientSize = new System.Drawing.Size(800, 450);
|
||||||
|
this.Text = "Form1";
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
namespace MultipartUploader
|
||||||
|
{
|
||||||
|
public partial class Form1 : Form
|
||||||
|
{
|
||||||
|
public Form1()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<!--
|
||||||
|
Microsoft ResX Schema
|
||||||
|
|
||||||
|
Version 2.0
|
||||||
|
|
||||||
|
The primary goals of this format is to allow a simple XML format
|
||||||
|
that is mostly human readable. The generation and parsing of the
|
||||||
|
various data types are done through the TypeConverter classes
|
||||||
|
associated with the data types.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
... ado.net/XML headers & schema ...
|
||||||
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
|
<resheader name="version">2.0</resheader>
|
||||||
|
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||||
|
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||||
|
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||||
|
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||||
|
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
|
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||||
|
</data>
|
||||||
|
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
|
<comment>This is a comment</comment>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
There are any number of "resheader" rows that contain simple
|
||||||
|
name/value pairs.
|
||||||
|
|
||||||
|
Each data row contains a name, and value. The row also contains a
|
||||||
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
|
text/value conversion through the TypeConverter architecture.
|
||||||
|
Classes that don't support this are serialized and stored with the
|
||||||
|
mimetype set.
|
||||||
|
|
||||||
|
The mimetype is used for serialized objects, and tells the
|
||||||
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
|
read any of the formats listed below.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
|
value : The object must be serialized into a byte array
|
||||||
|
: using a System.ComponentModel.TypeConverter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
-->
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:element name="metadata">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="assembly">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:attribute name="alias" type="xsd:string" />
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="data">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="resheader">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>2.0</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
</root>
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>WinExe</OutputType>
|
||||||
|
<TargetFramework>net6.0-windows</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<UseWindowsForms>true</UseWindowsForms>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="MimeKitLite" Version="4.1.0.1" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
namespace MultipartUploader
|
||||||
|
{
|
||||||
|
internal static class Program
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The main entry point for the application.
|
||||||
|
/// </summary>
|
||||||
|
[STAThread]
|
||||||
|
static void Main()
|
||||||
|
{
|
||||||
|
// To customize application configuration such as set high DPI settings or default font,
|
||||||
|
// see https://aka.ms/applicationconfiguration.
|
||||||
|
ApplicationConfiguration.Initialize();
|
||||||
|
Application.Run(new Form1());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user