mirror of
https://github.com/wiremock/WireMock.Net.git
synced 2026-03-31 22:53:27 +02:00
Create WireMock.Net.MimePart project (#1300)
* Create WireMock.Net.MimePart project * . * REFACTOR * ILRepack * -- * ... * x * x * . * fix * public class MimePartMatcher * shared * min * . * <!--<DelaySign>true</DelaySign>--> * Update README.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -40,6 +40,7 @@ For more info, see also this WIKI page: [What is WireMock.Net](https://github.co
|
|||||||
| | Official | Preview [:information_source:](https://github.com/wiremock/WireMock.Net/wiki/MyGet-preview-versions) |
|
| | Official | Preview [:information_source:](https://github.com/wiremock/WireMock.Net/wiki/MyGet-preview-versions) |
|
||||||
| - | - | - |
|
| - | - | - |
|
||||||
| **WireMock.Net** | [](https://www.nuget.org/packages/WireMock.Net) | [](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net)
|
| **WireMock.Net** | [](https://www.nuget.org/packages/WireMock.Net) | [](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net)
|
||||||
|
| **WireMock.Net.Minimal** 🔺| [](https://www.nuget.org/packages/WireMock.Net.Minimal) | [](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.Minimal)
|
||||||
| **WireMock.Net.StandAlone** | [](https://www.nuget.org/packages/WireMock.Net.StandAlone) | [](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.StandAlone)
|
| **WireMock.Net.StandAlone** | [](https://www.nuget.org/packages/WireMock.Net.StandAlone) | [](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.StandAlone)
|
||||||
| **WireMock.Net.Testcontainers** | [](https://www.nuget.org/packages/WireMock.Net.Testcontainers) | [](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.Testcontainers)
|
| **WireMock.Net.Testcontainers** | [](https://www.nuget.org/packages/WireMock.Net.Testcontainers) | [](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.Testcontainers)
|
||||||
| **WireMock.Net.Aspire** | [](https://www.nuget.org/packages/WireMock.Net.Aspire) | [](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.Aspire)
|
| **WireMock.Net.Aspire** | [](https://www.nuget.org/packages/WireMock.Net.Aspire) | [](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.Aspire)
|
||||||
@@ -52,10 +53,15 @@ For more info, see also this WIKI page: [What is WireMock.Net](https://github.co
|
|||||||
| | | |
|
| | | |
|
||||||
| **WireMock.Net.Matchers.CSharpCode** | [](https://www.nuget.org/packages/WireMock.Net.Matchers.CSharpCode) | [](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.Matchers.CSharpCode)
|
| **WireMock.Net.Matchers.CSharpCode** | [](https://www.nuget.org/packages/WireMock.Net.Matchers.CSharpCode) | [](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.Matchers.CSharpCode)
|
||||||
| **WireMock.Net.OpenApiParser** | [](https://www.nuget.org/packages/WireMock.Net.OpenApiParser) | [](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.OpenApiParser)
|
| **WireMock.Net.OpenApiParser** | [](https://www.nuget.org/packages/WireMock.Net.OpenApiParser) | [](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.OpenApiParser)
|
||||||
|
| **WireMock.Net.MimePart** | [](https://www.nuget.org/packages/WireMock.Net.MimePart) | [](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.MimePart)
|
||||||
| | | |
|
| | | |
|
||||||
| **WireMock.Net.RestClient** | [](https://www.nuget.org/packages/WireMock.Net.RestClient) | [](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.RestClient)
|
| **WireMock.Net.RestClient** | [](https://www.nuget.org/packages/WireMock.Net.RestClient) | [](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.RestClient)
|
||||||
| **WireMock.Org.RestClient** | [](https://www.nuget.org/packages/WireMock.Org.RestClient) | [](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Org.RestClient)
|
| **WireMock.Org.RestClient** | [](https://www.nuget.org/packages/WireMock.Org.RestClient) | [](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Org.RestClient)
|
||||||
|
|
||||||
|
<br />
|
||||||
|
|
||||||
|
🔺 **WireMock.Net.Minimal** does not include: **WireMock.Net.MimePart**
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## :exclamation: Breaking changes
|
## :exclamation: Breaking changes
|
||||||
@@ -65,6 +71,7 @@ A breaking change is introduced which is related to System.Linq.Dynamic.Core Dyn
|
|||||||
- The `LinqMatcher` is not allowed.
|
- The `LinqMatcher` is not allowed.
|
||||||
- The [Handlebars.Net.Helpers.DynamicLinq](https://www.nuget.org/packages/Handlebars.Net.Helpers.DynamicLinq) package is not included anymore.
|
- The [Handlebars.Net.Helpers.DynamicLinq](https://www.nuget.org/packages/Handlebars.Net.Helpers.DynamicLinq) package is not included anymore.
|
||||||
|
|
||||||
|
|
||||||
### 1.8.0
|
### 1.8.0
|
||||||
Some breaking changes are introduced in this version:
|
Some breaking changes are introduced in this version:
|
||||||
|
|
||||||
|
|||||||
@@ -130,6 +130,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.AwesomeAsserti
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.OpenApiParser", "src\WireMock.Net.OpenApiParser\WireMock.Net.OpenApiParser.csproj", "{E5B03EEF-822C-4295-952B-4479AD30082B}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.OpenApiParser", "src\WireMock.Net.OpenApiParser\WireMock.Net.OpenApiParser.csproj", "{E5B03EEF-822C-4295-952B-4479AD30082B}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.MimePart", "src\WireMock.Net.MimePart\WireMock.Net.MimePart.csproj", "{F8B4A93E-46EF-4237-88FE-15FDAB7635D4}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.Shared", "src\WireMock.Net.Shared\WireMock.Net.Shared.csproj", "{D3804228-91F4-4502-9595-39584E5A0177}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WireMock.Net.Minimal", "src\WireMock.Net.Minimal\WireMock.Net.Minimal.csproj", "{BFEF8990-65B3-4274-310F-7355F0B84035}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -308,6 +314,18 @@ Global
|
|||||||
{E5B03EEF-822C-4295-952B-4479AD30082B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{E5B03EEF-822C-4295-952B-4479AD30082B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{E5B03EEF-822C-4295-952B-4479AD30082B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{E5B03EEF-822C-4295-952B-4479AD30082B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{E5B03EEF-822C-4295-952B-4479AD30082B}.Release|Any CPU.Build.0 = Release|Any CPU
|
{E5B03EEF-822C-4295-952B-4479AD30082B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{F8B4A93E-46EF-4237-88FE-15FDAB7635D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{F8B4A93E-46EF-4237-88FE-15FDAB7635D4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{F8B4A93E-46EF-4237-88FE-15FDAB7635D4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{F8B4A93E-46EF-4237-88FE-15FDAB7635D4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{D3804228-91F4-4502-9595-39584E5A0177}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{D3804228-91F4-4502-9595-39584E5A0177}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{D3804228-91F4-4502-9595-39584E5A0177}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{D3804228-91F4-4502-9595-39584E5A0177}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{BFEF8990-65B3-4274-310F-7355F0B84035}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{BFEF8990-65B3-4274-310F-7355F0B84035}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{BFEF8990-65B3-4274-310F-7355F0B84035}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{BFEF8990-65B3-4274-310F-7355F0B84035}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
@@ -358,6 +376,9 @@ Global
|
|||||||
{A5FEF4F7-7DA2-4962-89A8-16BA942886E5} = {0BB8B634-407A-4610-A91F-11586990767A}
|
{A5FEF4F7-7DA2-4962-89A8-16BA942886E5} = {0BB8B634-407A-4610-A91F-11586990767A}
|
||||||
{7753670F-7C7F-44BF-8BC7-08325588E60C} = {8F890C6F-9ACC-438D-928A-AD61CDA862F2}
|
{7753670F-7C7F-44BF-8BC7-08325588E60C} = {8F890C6F-9ACC-438D-928A-AD61CDA862F2}
|
||||||
{E5B03EEF-822C-4295-952B-4479AD30082B} = {8F890C6F-9ACC-438D-928A-AD61CDA862F2}
|
{E5B03EEF-822C-4295-952B-4479AD30082B} = {8F890C6F-9ACC-438D-928A-AD61CDA862F2}
|
||||||
|
{F8B4A93E-46EF-4237-88FE-15FDAB7635D4} = {8F890C6F-9ACC-438D-928A-AD61CDA862F2}
|
||||||
|
{D3804228-91F4-4502-9595-39584E5A0177} = {8F890C6F-9ACC-438D-928A-AD61CDA862F2}
|
||||||
|
{BFEF8990-65B3-4274-310F-7355F0B84035} = {8F890C6F-9ACC-438D-928A-AD61CDA862F2}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {DC539027-9852-430C-B19F-FD035D018458}
|
SolutionGuid = {DC539027-9852-430C-B19F-FD035D018458}
|
||||||
|
|||||||
@@ -339,8 +339,8 @@ namespace WireMock.Net.ConsoleApplication
|
|||||||
});
|
});
|
||||||
System.Console.WriteLine("WireMockServer listening at {0}", string.Join(",", server.Urls));
|
System.Console.WriteLine("WireMockServer listening at {0}", string.Join(",", server.Urls));
|
||||||
|
|
||||||
//server.SetBasicAuthentication("a", "b");
|
server.SetBasicAuthentication("a", "b");
|
||||||
server.SetAzureADAuthentication(Environment.GetEnvironmentVariable("WIREMOCK_AAD_TENANT")!, "api://e083d51a-01a6-446c-8ad5-0c5c7f002208");
|
//server.SetAzureADAuthentication(Environment.GetEnvironmentVariable("WIREMOCK_AAD_TENANT")!, "api://e083d51a-01a6-446c-8ad5-0c5c7f002208");
|
||||||
|
|
||||||
//var http = new HttpClient();
|
//var http = new HttpClient();
|
||||||
//var response = await http.GetAsync($"{_wireMockServer.Url}/pricing");
|
//var response = await http.GetAsync($"{_wireMockServer.Url}/pricing");
|
||||||
|
|||||||
8
src/WireMock.Net.Abstractions/Properties/AssemblyInfo.cs
Normal file
8
src/WireMock.Net.Abstractions/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
[assembly: InternalsVisibleTo("WireMock.Net.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100e138ec44d93acac565953052636eb8d5e7e9f27ddb030590055cd1a0ab2069a5623f1f77ca907d78e0b37066ca0f6d63da7eecc3fcb65b76aa8ebeccf7ebe1d11264b8404cd9b1cbbf2c83f566e033b3e54129f6ef28daffff776ba7aebbc53c0d635ebad8f45f78eb3f7e0459023c218f003416e080f96a1a3c5ffeb56bee9e")]
|
||||||
|
|
||||||
|
// Needed for Moq in the UnitTest project
|
||||||
|
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Description>Commonly used models, enumerations and types.</Description>
|
<Description>Commonly used interfaces, models, enumerations and types.</Description>
|
||||||
<AssemblyTitle>WireMock.Net.Abstractions</AssemblyTitle>
|
<AssemblyTitle>WireMock.Net.Abstractions</AssemblyTitle>
|
||||||
<Authors>Stef Heyenrath</Authors>
|
<Authors>Stef Heyenrath</Authors>
|
||||||
<TargetFrameworks>net45;net451;net461;netstandard1.3;netstandard2.0;netstandard2.1</TargetFrameworks>
|
<TargetFrameworks>net45;net451;net461;netstandard1.3;netstandard2.0;netstandard2.1</TargetFrameworks>
|
||||||
@@ -17,7 +17,6 @@
|
|||||||
<EmbedUntrackedSources>true</EmbedUntrackedSources>
|
<EmbedUntrackedSources>true</EmbedUntrackedSources>
|
||||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||||
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
|
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
|
||||||
<CodeAnalysisRuleSet>../WireMock.Net/WireMock.Net.ruleset</CodeAnalysisRuleSet>
|
|
||||||
<SignAssembly>true</SignAssembly>
|
<SignAssembly>true</SignAssembly>
|
||||||
<AssemblyOriginatorKeyFile>../WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
|
<AssemblyOriginatorKeyFile>../WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
|
||||||
<!--<DelaySign>true</DelaySign>-->
|
<!--<DelaySign>true</DelaySign>-->
|
||||||
@@ -25,6 +24,10 @@
|
|||||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)' == 'Debug - Sonar'">
|
||||||
|
<CodeAnalysisRuleSet>../WireMock.Net/WireMock.Net.ruleset</CodeAnalysisRuleSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||||
<!--<PathMap>$(MSBuildProjectDirectory)=/</PathMap>-->
|
<!--<PathMap>$(MSBuildProjectDirectory)=/</PathMap>-->
|
||||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||||
@@ -35,37 +38,46 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<!-- CVE-2018-8292 -->
|
||||||
|
<PackageReference Include="System.Net.Http " Version="4.3.4" />
|
||||||
|
|
||||||
<!-- See also https://mstack.nl/blog/20210801-source-generators -->
|
<!-- See also https://mstack.nl/blog/20210801-source-generators -->
|
||||||
<PackageReference Include="FluentBuilder" Version="0.10.0">
|
<PackageReference Include="FluentBuilder" Version="0.10.0">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
<PackageReference Include="PolySharp" Version="1.15.0">
|
||||||
<PackageReference Include="PolySharp" Version="1.14.1">
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
<!--<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<!-- CVE-2018-8292 -->
|
<PackageReference Include="Stef.Validation" Version="0.1.1" />
|
||||||
<PackageReference Include="System.Net.Http " Version="4.3.4" />
|
<PackageReference Include="AnyOf" Version="0.4.0" />-->
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup Condition="$(TargetFramework.StartsWith('netstandard')) and '$(TargetFramework)' != 'netstandard1.0'">
|
<ItemGroup Condition="$(TargetFramework.StartsWith('netstandard')) and '$(TargetFramework)' != 'netstandard1.0'">
|
||||||
<PackageReference Include="System.Security.Cryptography.X509Certificates" Version="4.3.0" />
|
<PackageReference Include="System.Security.Cryptography.X509Certificates" Version="4.3.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup Condition="'$(TargetFramework)' == 'net461'">
|
<!--<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies.net46" Version="1.0.2">
|
|
||||||
<PrivateAssets>all</PrivateAssets>
|
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
|
||||||
</PackageReference>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Nullable" Version="1.3.1">
|
<PackageReference Include="Nullable" Version="1.3.1">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
</ItemGroup>-->
|
||||||
|
|
||||||
|
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard1.3' or '$(TargetFramework)' == 'net45' or '$(TargetFramework)' == 'net451' or '$(TargetFramework)' == 'net461'">
|
||||||
|
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
|
||||||
|
|
||||||
|
<!--<PackageReference Include="Nullable" Version="1.3.1">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>-->
|
||||||
|
|
||||||
|
<!--<PackageReference Include="PolySharp" Version="1.14.1">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>-->
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
@@ -16,7 +16,6 @@
|
|||||||
<EmbedUntrackedSources>true</EmbedUntrackedSources>
|
<EmbedUntrackedSources>true</EmbedUntrackedSources>
|
||||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||||
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
|
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
|
||||||
<CodeAnalysisRuleSet>../WireMock.Net/WireMock.Net.ruleset</CodeAnalysisRuleSet>
|
|
||||||
<SignAssembly>true</SignAssembly>
|
<SignAssembly>true</SignAssembly>
|
||||||
<AssemblyOriginatorKeyFile>../WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
|
<AssemblyOriginatorKeyFile>../WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
|
||||||
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
|
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
|
||||||
@@ -25,6 +24,10 @@
|
|||||||
<ApplicationIcon>../../resources/WireMock.Net-LogoAspire.ico</ApplicationIcon>
|
<ApplicationIcon>../../resources/WireMock.Net-LogoAspire.ico</ApplicationIcon>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)' == 'Debug - Sonar'">
|
||||||
|
<CodeAnalysisRuleSet>../WireMock.Net/WireMock.Net.ruleset</CodeAnalysisRuleSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
@@ -16,7 +16,6 @@
|
|||||||
<EmbedUntrackedSources>true</EmbedUntrackedSources>
|
<EmbedUntrackedSources>true</EmbedUntrackedSources>
|
||||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||||
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
|
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
|
||||||
<CodeAnalysisRuleSet>../WireMock.Net/WireMock.Net.ruleset</CodeAnalysisRuleSet>
|
|
||||||
<SignAssembly>true</SignAssembly>
|
<SignAssembly>true</SignAssembly>
|
||||||
<AssemblyOriginatorKeyFile>../WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
|
<AssemblyOriginatorKeyFile>../WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
|
||||||
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
|
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
|
||||||
@@ -31,9 +30,13 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="..\WireMock.Net\Util\EnhancedFileSystemWatcher.cs" Link="Utils\EnhancedFileSystemWatcher.cs" />
|
<Compile Include="..\WireMock.Net.Minimal\Util\EnhancedFileSystemWatcher.cs" Link="Utils\EnhancedFileSystemWatcher.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)' == 'Debug - Sonar'">
|
||||||
|
<CodeAnalysisRuleSet>../WireMock.Net/WireMock.Net.ruleset</CodeAnalysisRuleSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
<EmbedUntrackedSources>true</EmbedUntrackedSources>
|
<EmbedUntrackedSources>true</EmbedUntrackedSources>
|
||||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||||
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
|
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
|
||||||
<CodeAnalysisRuleSet>../WireMock.Net/WireMock.Net.ruleset</CodeAnalysisRuleSet>
|
|
||||||
<SignAssembly>true</SignAssembly>
|
<SignAssembly>true</SignAssembly>
|
||||||
<AssemblyOriginatorKeyFile>../WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
|
<AssemblyOriginatorKeyFile>../WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
|
||||||
<!--<DelaySign>true</DelaySign>-->
|
<!--<DelaySign>true</DelaySign>-->
|
||||||
@@ -24,6 +23,10 @@
|
|||||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)' == 'Debug - Sonar'">
|
||||||
|
<CodeAnalysisRuleSet>../WireMock.Net/WireMock.Net.ruleset</CodeAnalysisRuleSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Description>FluentAssertions extensions for WireMock.Net</Description>
|
<Description>FluentAssertions extensions for WireMock.Net</Description>
|
||||||
@@ -16,7 +16,6 @@
|
|||||||
<EmbedUntrackedSources>true</EmbedUntrackedSources>
|
<EmbedUntrackedSources>true</EmbedUntrackedSources>
|
||||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||||
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
|
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
|
||||||
<CodeAnalysisRuleSet>../WireMock.Net/WireMock.Net.ruleset</CodeAnalysisRuleSet>
|
|
||||||
<SignAssembly>true</SignAssembly>
|
<SignAssembly>true</SignAssembly>
|
||||||
<AssemblyOriginatorKeyFile>../WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
|
<AssemblyOriginatorKeyFile>../WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
|
||||||
<!--<DelaySign>true</DelaySign>-->
|
<!--<DelaySign>true</DelaySign>-->
|
||||||
@@ -24,6 +23,10 @@
|
|||||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)' == 'Debug - Sonar'">
|
||||||
|
<CodeAnalysisRuleSet>../WireMock.Net/WireMock.Net.ruleset</CodeAnalysisRuleSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -25,13 +25,13 @@ internal class CSharpCodeMatcher : ICSharpCodeMatcher
|
|||||||
private const string TemplateForIsMatchWithDynamic = "public class CodeHelper {{ public bool IsMatch(dynamic it) {{ {0} }} }}";
|
private const string TemplateForIsMatchWithDynamic = "public class CodeHelper {{ public bool IsMatch(dynamic it) {{ {0} }} }}";
|
||||||
|
|
||||||
private readonly string[] _usings =
|
private readonly string[] _usings =
|
||||||
{
|
[
|
||||||
"System",
|
"System",
|
||||||
"System.Linq",
|
"System.Linq",
|
||||||
"System.Collections.Generic",
|
"System.Collections.Generic",
|
||||||
"Microsoft.CSharp",
|
"Microsoft.CSharp",
|
||||||
"Newtonsoft.Json.Linq"
|
"Newtonsoft.Json.Linq"
|
||||||
};
|
];
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public MatchBehaviour MatchBehaviour { get; }
|
public MatchBehaviour MatchBehaviour { get; }
|
||||||
|
|||||||
@@ -1,49 +1,52 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Description>A CSharpCodeMatcher which can be used to match WireMock.Net Requests using C# code.</Description>
|
<Description>A CSharpCodeMatcher which can be used to match WireMock.Net Requests using C# code.</Description>
|
||||||
<AssemblyTitle>WireMock.Net.Matchers.CSharpCode</AssemblyTitle>
|
<AssemblyTitle>WireMock.Net.Matchers.CSharpCode</AssemblyTitle>
|
||||||
<Authors>Stef Heyenrath</Authors>
|
<Authors>Stef Heyenrath</Authors>
|
||||||
<TargetFrameworks>net451;net452;net46;net461;netstandard1.3;netstandard2.0;netstandard2.1;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0</TargetFrameworks>
|
<TargetFrameworks>net451;net452;net46;net461;netstandard1.3;netstandard2.0;netstandard2.1;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0</TargetFrameworks>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<PackageTags>wiremock;matchers;matcher;csharp;csharpcode</PackageTags>
|
<PackageTags>wiremock;matchers;matcher;csharp;csharpcode</PackageTags>
|
||||||
<RootNamespace>WireMock</RootNamespace>
|
<RootNamespace>WireMock</RootNamespace>
|
||||||
<ProjectGuid>{B6269AAC-170A-4346-8B9A-444DED3D9A44}</ProjectGuid>
|
<ProjectGuid>{B6269AAC-170A-4346-8B9A-444DED3D9A44}</ProjectGuid>
|
||||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||||
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
|
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
|
||||||
<EmbedUntrackedSources>true</EmbedUntrackedSources>
|
<EmbedUntrackedSources>true</EmbedUntrackedSources>
|
||||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||||
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
|
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
|
||||||
<CodeAnalysisRuleSet>../WireMock.Net/WireMock.Net.ruleset</CodeAnalysisRuleSet>
|
<SignAssembly>true</SignAssembly>
|
||||||
<SignAssembly>true</SignAssembly>
|
<AssemblyOriginatorKeyFile>../WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
|
||||||
<AssemblyOriginatorKeyFile>../WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
|
<!--<DelaySign>true</DelaySign>-->
|
||||||
<!--<DelaySign>true</DelaySign>-->
|
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
|
||||||
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
|
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
</PropertyGroup>
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
<PropertyGroup Condition="'$(Configuration)' == 'Debug - Sonar'">
|
||||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
<CodeAnalysisRuleSet>../WireMock.Net/WireMock.Net.ruleset</CodeAnalysisRuleSet>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<!-- https://github.com/aspnet/RoslynCodeDomProvider/issues/51 -->
|
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||||
<!-- This is needed else we cannot build net452 in Azure DevOps Pipeline -->
|
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||||
<Target Name="CheckIfShouldKillVBCSCompiler" />
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<!-- https://github.com/aspnet/RoslynCodeDomProvider/issues/51 -->
|
||||||
<ProjectReference Include="..\WireMock.Net\WireMock.Net.csproj" />
|
<!-- This is needed else we cannot build net452 in Azure DevOps Pipeline -->
|
||||||
</ItemGroup>
|
<Target Name="CheckIfShouldKillVBCSCompiler" />
|
||||||
|
|
||||||
<ItemGroup Condition=" '$(TargetFramework)' == 'net451' or '$(TargetFramework)' == 'net452' ">
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" Version="3.6.0" />
|
<ProjectReference Include="..\WireMock.Net\WireMock.Net.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup Condition=" '$(TargetFramework)' == 'net46' or '$(TargetFramework)' == 'net461' ">
|
<ItemGroup Condition=" '$(TargetFramework)' == 'net451' or '$(TargetFramework)' == 'net452' ">
|
||||||
<PackageReference Include="CS-Script" Version="3.30.3" />
|
<PackageReference Include="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" Version="3.6.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' or '$(TargetFramework)' == 'netstandard2.1' or '$(TargetFramework)' == 'netcoreapp3.1' or '$(TargetFramework)' == 'net5.0' or '$(TargetFramework)' == 'net6.0' or '$(TargetFramework)' == 'net7.0' or '$(TargetFramework)' == 'net8.0'">
|
<ItemGroup Condition=" '$(TargetFramework)' == 'net46' or '$(TargetFramework)' == 'net461' ">
|
||||||
<PackageReference Include="CS-Script" Version="4.8.17" />
|
<PackageReference Include="CS-Script" Version="3.30.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' or '$(TargetFramework)' == 'netstandard2.1' or '$(TargetFramework)' == 'netcoreapp3.1' or '$(TargetFramework)' == 'net5.0' or '$(TargetFramework)' == 'net6.0' or '$(TargetFramework)' == 'net7.0' or '$(TargetFramework)' == 'net8.0'">
|
||||||
|
<PackageReference Include="CS-Script" Version="4.8.17" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
28
src/WireMock.Net.MimePart/ILRepack.targets
Normal file
28
src/WireMock.Net.MimePart/ILRepack.targets
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
|
||||||
|
<!-- See also https://github.com/ravibpatel/ILRepack.Lib.MSBuild.Task/issues/26 -->
|
||||||
|
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Target Name="ILRepacker" AfterTargets="Build" Condition="'$(Configuration)' == 'Release'">
|
||||||
|
<ItemGroup>
|
||||||
|
<InputAssemblies Include="$(OutputPath)WireMock.Net.MimePart.dll" />
|
||||||
|
<InputAssemblies Include="@(ReferencePathWithRefAssemblies)" Condition="'%(filename)' == 'MimeKitLite'" />
|
||||||
|
<LibraryPath Include="%(ReferencePathWithRefAssemblies.RelativeDir)" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<DoNotInternalizeAssemblies Include="WireMock.Net.MimePart" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ILRepack
|
||||||
|
Parallel="true"
|
||||||
|
Internalize="true"
|
||||||
|
RenameInternalized="true"
|
||||||
|
InternalizeExclude="@(DoNotInternalizeAssemblies)"
|
||||||
|
InputAssemblies="@(InputAssemblies)"
|
||||||
|
LibraryPath="@(LibraryPath)"
|
||||||
|
TargetKind="Dll"
|
||||||
|
KeyFile="../../src/WireMock.Net/WireMock.Net.snk"
|
||||||
|
OutputFile="$(OutputPath)$(AssemblyName).dll"
|
||||||
|
/>
|
||||||
|
</Target>
|
||||||
|
</Project>
|
||||||
@@ -1,12 +1,8 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
#if MIMEKIT
|
|
||||||
using System;
|
using System;
|
||||||
using MimeKit;
|
using MimeKit;
|
||||||
using WireMock.Extensions;
|
|
||||||
using WireMock.Matchers;
|
|
||||||
using WireMock.Matchers.Helpers;
|
using WireMock.Matchers.Helpers;
|
||||||
using WireMock.Models;
|
|
||||||
using WireMock.Util;
|
using WireMock.Util;
|
||||||
|
|
||||||
namespace WireMock.Matchers;
|
namespace WireMock.Matchers;
|
||||||
@@ -14,31 +10,23 @@ namespace WireMock.Matchers;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// MimePartMatcher
|
/// MimePartMatcher
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class MimePartMatcher : IMatcher
|
public class MimePartMatcher : IMimePartMatcher
|
||||||
{
|
{
|
||||||
private readonly Func<MimePart, MatchResult>[] _funcs;
|
private readonly Func<MimePart, MatchResult>[] _funcs;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string Name => nameof(MimePartMatcher);
|
public string Name => nameof(MimePartMatcher);
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc />
|
||||||
/// ContentType Matcher (image/png; name=image.png.)
|
|
||||||
/// </summary>
|
|
||||||
public IStringMatcher? ContentTypeMatcher { get; }
|
public IStringMatcher? ContentTypeMatcher { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc />
|
||||||
/// ContentDisposition Matcher (attachment; filename=image.png)
|
|
||||||
/// </summary>
|
|
||||||
public IStringMatcher? ContentDispositionMatcher { get; }
|
public IStringMatcher? ContentDispositionMatcher { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc />
|
||||||
/// ContentTransferEncoding Matcher (base64)
|
|
||||||
/// </summary>
|
|
||||||
public IStringMatcher? ContentTransferEncodingMatcher { get; }
|
public IStringMatcher? ContentTransferEncodingMatcher { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc />
|
||||||
/// Content Matcher
|
|
||||||
/// </summary>
|
|
||||||
public IMatcher? ContentMatcher { get; }
|
public IMatcher? ContentMatcher { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -70,19 +58,15 @@ public class MimePartMatcher : IMatcher
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc />
|
||||||
/// Determines whether the specified MimePart is match.
|
public MatchResult IsMatch(object value)
|
||||||
/// </summary>
|
|
||||||
/// <param name="mimePart">The MimePart.</param>
|
|
||||||
/// <returns>A value between 0.0 - 1.0 of the similarity.</returns>
|
|
||||||
public MatchResult IsMatch(MimePart mimePart)
|
|
||||||
{
|
{
|
||||||
var score = MatchScores.Mismatch;
|
var score = MatchScores.Mismatch;
|
||||||
Exception? exception = null;
|
Exception? exception = null;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (Array.TrueForAll(_funcs, func => func(mimePart).IsPerfect()))
|
if (value is MimePart mimePart && Array.TrueForAll(_funcs, func => func(mimePart).IsPerfect()))
|
||||||
{
|
{
|
||||||
score = MatchScores.Perfect;
|
score = MatchScores.Perfect;
|
||||||
}
|
}
|
||||||
@@ -125,5 +109,4 @@ public class MimePartMatcher : IMatcher
|
|||||||
{
|
{
|
||||||
return contentType?.ToString().Replace("Content-Type: ", string.Empty);
|
return contentType?.ToString().Replace("Content-Type: ", string.Empty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
5
src/WireMock.Net.MimePart/Properties/AssemblyInfo.cs
Normal file
5
src/WireMock.Net.MimePart/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
[assembly: InternalsVisibleTo("WireMock.Net.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100e138ec44d93acac565953052636eb8d5e7e9f27ddb030590055cd1a0ab2069a5623f1f77ca907d78e0b37066ca0f6d63da7eecc3fcb65b76aa8ebeccf7ebe1d11264b8404cd9b1cbbf2c83f566e033b3e54129f6ef28daffff776ba7aebbc53c0d635ebad8f45f78eb3f7e0459023c218f003416e080f96a1a3c5ffeb56bee9e")]
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
#if MIMEKIT
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -13,9 +13,16 @@ using WireMock.Types;
|
|||||||
|
|
||||||
namespace WireMock.Util;
|
namespace WireMock.Util;
|
||||||
|
|
||||||
internal static class MimeKitUtils
|
internal class MimeKitUtils : IMimeKitUtils
|
||||||
{
|
{
|
||||||
public static bool TryGetMimeMessage(IRequestMessage requestMessage, [NotNullWhen(true)] out MimeMessage? mimeMessage)
|
/// <inheritdoc />
|
||||||
|
public object LoadFromStream(Stream stream)
|
||||||
|
{
|
||||||
|
return MimeMessage.Load(Guard.NotNull(stream));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public bool TryGetMimeMessage(IRequestMessage requestMessage, [NotNullWhen(true)] out object? mimeMessage)
|
||||||
{
|
{
|
||||||
Guard.NotNull(requestMessage);
|
Guard.NotNull(requestMessage);
|
||||||
|
|
||||||
@@ -37,7 +44,7 @@ internal static class MimeKitUtils
|
|||||||
|
|
||||||
var fixedBytes = FixBytes(bytes, contentTypeHeader[0]);
|
var fixedBytes = FixBytes(bytes, contentTypeHeader[0]);
|
||||||
|
|
||||||
mimeMessage = MimeMessage.Load(new MemoryStream(fixedBytes));
|
mimeMessage = LoadFromStream(new MemoryStream(fixedBytes));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,6 +52,19 @@ internal static class MimeKitUtils
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public IReadOnlyList<object> GetBodyParts(object mimeMessage)
|
||||||
|
{
|
||||||
|
if (mimeMessage is not MimeMessage mm)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"The mimeMessage must be of type {nameof(MimeMessage)}", nameof(mimeMessage));
|
||||||
|
}
|
||||||
|
|
||||||
|
return mm.BodyParts
|
||||||
|
.OfType<MimePart>()
|
||||||
|
.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
private static bool StartsWithMultiPart(WireMockList<string> contentTypeHeader)
|
private static bool StartsWithMultiPart(WireMockList<string> contentTypeHeader)
|
||||||
{
|
{
|
||||||
return contentTypeHeader.Any(ct => ct.TrimStart().StartsWith("multipart/", StringComparison.OrdinalIgnoreCase));
|
return contentTypeHeader.Any(ct => ct.TrimStart().StartsWith("multipart/", StringComparison.OrdinalIgnoreCase));
|
||||||
@@ -61,5 +81,4 @@ internal static class MimeKitUtils
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
63
src/WireMock.Net.MimePart/WireMock.Net.MimePart.csproj
Normal file
63
src/WireMock.Net.MimePart/WireMock.Net.MimePart.csproj
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<Description>MultiPart Mime support for WireMock.Net using MimeKitLite</Description>
|
||||||
|
<AssemblyTitle>WireMock.Net.MimePart</AssemblyTitle>
|
||||||
|
<Authors>Stef Heyenrath</Authors>
|
||||||
|
<TargetFrameworks>netstandard2.0;netstandard2.1;net462;net47;net48;net6.0;net8.0</TargetFrameworks>
|
||||||
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
|
<PackageTags>wiremock;matchers;matcher;mime;multipart;mimekit</PackageTags>
|
||||||
|
<RootNamespace>WireMock</RootNamespace>
|
||||||
|
<ProjectGuid>{F8B4A93E-46EF-4237-88FE-15FDAB7635D4}</ProjectGuid>
|
||||||
|
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||||
|
<EmbedUntrackedSources>true</EmbedUntrackedSources>
|
||||||
|
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||||
|
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
|
||||||
|
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||||
|
|
||||||
|
<SignAssembly>true</SignAssembly>
|
||||||
|
<!--<DelaySign>true</DelaySign>-->
|
||||||
|
<AssemblyOriginatorKeyFile>../WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
|
||||||
|
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||||
|
<SignAssembly>true</SignAssembly>
|
||||||
|
<AssemblyOriginatorKeyFile>../WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
|
||||||
|
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)' == 'Debug - Sonar'">
|
||||||
|
<CodeAnalysisRuleSet>../WireMock.Net/WireMock.Net.ruleset</CodeAnalysisRuleSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||||
|
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="PolySharp" Version="1.15.0">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Stef.Validation" Version="0.1.1" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!--<ItemGroup>
|
||||||
|
<PackageReference Include="MimeKitLite" Version="4.12.0" />
|
||||||
|
</ItemGroup>-->
|
||||||
|
|
||||||
|
<ItemGroup Condition="'$(Configuration)' == 'Debug'">
|
||||||
|
<PackageReference Include="MimeKitLite" Version="4.12.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup Condition="'$(Configuration)' == 'Release'">
|
||||||
|
<PackageReference Include="ILRepack.Lib.MSBuild.Task" Version="2.0.40" PrivateAssets="All" />
|
||||||
|
<PackageReference Include="MimeKitLite" Version="4.12.0" PrivateAssets="All" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\WireMock.Net.Shared\WireMock.Net.Shared.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -45,7 +45,7 @@ internal class AzureADAuthenticationMatcher : IStringMatcher
|
|||||||
|
|
||||||
public AnyOf<string, StringPattern>[] GetPatterns()
|
public AnyOf<string, StringPattern>[] GetPatterns()
|
||||||
{
|
{
|
||||||
return EmptyArray<AnyOf<string, StringPattern>>.Value;
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public MatchOperator MatchOperator => MatchOperator.Or;
|
public MatchOperator MatchOperator => MatchOperator.Or;
|
||||||
@@ -57,7 +57,7 @@ internal class AzureADAuthenticationMatcher : IStringMatcher
|
|||||||
return MatchScores.Mismatch;
|
return MatchScores.Mismatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
var token = Regex.Replace(input, BearerPrefix, string.Empty, RegexOptions.IgnoreCase, WireMockConstants.DefaultRegexTimeout);
|
var token = Regex.Replace(input, BearerPrefix, string.Empty, RegexOptions.IgnoreCase, RegexConstants.DefaultTimeout);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -12,7 +12,7 @@ internal static class StringExtensions
|
|||||||
public static string Replace(this string text, string oldValue, string newValue, StringComparison stringComparison)
|
public static string Replace(this string text, string oldValue, string newValue, StringComparison stringComparison)
|
||||||
{
|
{
|
||||||
var options = stringComparison == StringComparison.OrdinalIgnoreCase ? RegexOptions.IgnoreCase : RegexOptions.None;
|
var options = stringComparison == StringComparison.OrdinalIgnoreCase ? RegexOptions.IgnoreCase : RegexOptions.None;
|
||||||
return Regex.Replace(text, oldValue, newValue, options, WireMockConstants.DefaultRegexTimeout);
|
return Regex.Replace(text, oldValue, newValue, options, RegexConstants.DefaultTimeout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -1,13 +1,9 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace WireMock.Constants;
|
namespace WireMock.Constants;
|
||||||
|
|
||||||
internal static class WireMockConstants
|
internal static class WireMockConstants
|
||||||
{
|
{
|
||||||
internal static readonly TimeSpan DefaultRegexTimeout = TimeSpan.FromSeconds(10);
|
|
||||||
|
|
||||||
internal const int AdminPriority = int.MinValue;
|
internal const int AdminPriority = int.MinValue;
|
||||||
internal const int MinPriority = -1_000_000;
|
internal const int MinPriority = -1_000_000;
|
||||||
internal const int ProxyPriority = -2_000_000;
|
internal const int ProxyPriority = -2_000_000;
|
||||||
@@ -61,7 +61,7 @@ internal static class HttpRequestMessageHelper
|
|||||||
if (contentLengthHeaderAllowed)
|
if (contentLengthHeaderAllowed)
|
||||||
{
|
{
|
||||||
// Set Content to empty ByteArray to be able to set the Content-Length on the content in case of a HEAD method.
|
// Set Content to empty ByteArray to be able to set the Content-Length on the content in case of a HEAD method.
|
||||||
httpRequestMessage.Content ??= new ByteArrayContent(EmptyArray<byte>.Value);
|
httpRequestMessage.Content ??= new ByteArrayContent([]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1,122 +1,122 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Stef.Validation;
|
using Stef.Validation;
|
||||||
using WireMock.Models;
|
using WireMock.Models;
|
||||||
using WireMock.Settings;
|
using WireMock.Settings;
|
||||||
using WireMock.Transformers;
|
using WireMock.Transformers;
|
||||||
using WireMock.Transformers.Handlebars;
|
using WireMock.Transformers.Handlebars;
|
||||||
using WireMock.Transformers.Scriban;
|
using WireMock.Transformers.Scriban;
|
||||||
using WireMock.Types;
|
using WireMock.Types;
|
||||||
using WireMock.Util;
|
using WireMock.Util;
|
||||||
|
|
||||||
namespace WireMock.Http;
|
namespace WireMock.Http;
|
||||||
|
|
||||||
internal class WebhookSender
|
internal class WebhookSender
|
||||||
{
|
{
|
||||||
private const string ClientIp = "::1";
|
private const string ClientIp = "::1";
|
||||||
private static readonly ThreadLocal<Random> Random = new(() => new Random(DateTime.UtcNow.Millisecond));
|
private static readonly ThreadLocal<Random> Random = new(() => new Random(DateTime.UtcNow.Millisecond));
|
||||||
|
|
||||||
private readonly WireMockServerSettings _settings;
|
private readonly WireMockServerSettings _settings;
|
||||||
|
|
||||||
public WebhookSender(WireMockServerSettings settings)
|
public WebhookSender(WireMockServerSettings settings)
|
||||||
{
|
{
|
||||||
_settings = Guard.NotNull(settings);
|
_settings = Guard.NotNull(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<HttpResponseMessage> SendAsync(
|
public async Task<HttpResponseMessage> SendAsync(
|
||||||
HttpClient client,
|
HttpClient client,
|
||||||
IMapping mapping,
|
IMapping mapping,
|
||||||
IWebhookRequest webhookRequest,
|
IWebhookRequest webhookRequest,
|
||||||
IRequestMessage originalRequestMessage,
|
IRequestMessage originalRequestMessage,
|
||||||
IResponseMessage originalResponseMessage
|
IResponseMessage originalResponseMessage
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
Guard.NotNull(client);
|
Guard.NotNull(client);
|
||||||
Guard.NotNull(mapping);
|
Guard.NotNull(mapping);
|
||||||
Guard.NotNull(webhookRequest);
|
Guard.NotNull(webhookRequest);
|
||||||
Guard.NotNull(originalRequestMessage);
|
Guard.NotNull(originalRequestMessage);
|
||||||
Guard.NotNull(originalResponseMessage);
|
Guard.NotNull(originalResponseMessage);
|
||||||
|
|
||||||
IBodyData? bodyData;
|
IBodyData? bodyData;
|
||||||
IDictionary<string, WireMockList<string>>? headers;
|
IDictionary<string, WireMockList<string>>? headers;
|
||||||
string requestUrl;
|
string requestUrl;
|
||||||
if (webhookRequest.UseTransformer == true)
|
if (webhookRequest.UseTransformer == true)
|
||||||
{
|
{
|
||||||
ITransformer transformer;
|
ITransformer transformer;
|
||||||
switch (webhookRequest.TransformerType)
|
switch (webhookRequest.TransformerType)
|
||||||
{
|
{
|
||||||
case TransformerType.Handlebars:
|
case TransformerType.Handlebars:
|
||||||
var factoryHandlebars = new HandlebarsContextFactory(_settings);
|
var factoryHandlebars = new HandlebarsContextFactory(_settings);
|
||||||
transformer = new Transformer(_settings, factoryHandlebars);
|
transformer = new Transformer(_settings, factoryHandlebars);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TransformerType.Scriban:
|
case TransformerType.Scriban:
|
||||||
case TransformerType.ScribanDotLiquid:
|
case TransformerType.ScribanDotLiquid:
|
||||||
var factoryDotLiquid = new ScribanContextFactory(_settings.FileSystemHandler, webhookRequest.TransformerType);
|
var factoryDotLiquid = new ScribanContextFactory(_settings.FileSystemHandler, webhookRequest.TransformerType);
|
||||||
transformer = new Transformer(_settings, factoryDotLiquid);
|
transformer = new Transformer(_settings, factoryDotLiquid);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new NotImplementedException($"TransformerType '{webhookRequest.TransformerType}' is not supported.");
|
throw new NotImplementedException($"TransformerType '{webhookRequest.TransformerType}' is not supported.");
|
||||||
}
|
}
|
||||||
|
|
||||||
bodyData = transformer.TransformBody(mapping, originalRequestMessage, originalResponseMessage, webhookRequest.BodyData, webhookRequest.TransformerReplaceNodeOptions);
|
bodyData = transformer.TransformBody(mapping, originalRequestMessage, originalResponseMessage, webhookRequest.BodyData, webhookRequest.TransformerReplaceNodeOptions);
|
||||||
headers = transformer.TransformHeaders(mapping, originalRequestMessage, originalResponseMessage, webhookRequest.Headers);
|
headers = transformer.TransformHeaders(mapping, originalRequestMessage, originalResponseMessage, webhookRequest.Headers);
|
||||||
requestUrl = transformer.TransformString(mapping, originalRequestMessage, originalResponseMessage, webhookRequest.Url);
|
requestUrl = transformer.TransformString(mapping, originalRequestMessage, originalResponseMessage, webhookRequest.Url);
|
||||||
|
|
||||||
mapping.Settings.WebhookSettings?.PostTransform(mapping, requestUrl, bodyData, headers);
|
mapping.Settings.WebhookSettings?.PostTransform(mapping, requestUrl, bodyData, headers);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bodyData = webhookRequest.BodyData;
|
bodyData = webhookRequest.BodyData;
|
||||||
headers = webhookRequest.Headers;
|
headers = webhookRequest.Headers;
|
||||||
requestUrl = webhookRequest.Url;
|
requestUrl = webhookRequest.Url;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create RequestMessage
|
// Create RequestMessage
|
||||||
var requestMessage = new RequestMessage(
|
var requestMessage = new RequestMessage(
|
||||||
new UrlDetails(requestUrl),
|
new UrlDetails(requestUrl),
|
||||||
webhookRequest.Method,
|
webhookRequest.Method,
|
||||||
ClientIp,
|
ClientIp,
|
||||||
bodyData,
|
bodyData,
|
||||||
headers?.ToDictionary(x => x.Key, x => x.Value.ToArray())
|
headers?.ToDictionary(x => x.Key, x => x.Value.ToArray())
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
DateTime = DateTime.UtcNow
|
DateTime = DateTime.UtcNow
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create HttpRequestMessage
|
// Create HttpRequestMessage
|
||||||
var httpRequestMessage = HttpRequestMessageHelper.Create(requestMessage, requestUrl);
|
var httpRequestMessage = HttpRequestMessageHelper.Create(requestMessage, requestUrl);
|
||||||
|
|
||||||
// Delay (if required)
|
// Delay (if required)
|
||||||
if (TryGetDelay(webhookRequest, out var delay))
|
if (TryGetDelay(webhookRequest, out var delay))
|
||||||
{
|
{
|
||||||
await Task.Delay(delay.Value).ConfigureAwait(false);
|
await Task.Delay(delay.Value).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call the URL
|
// Call the URL
|
||||||
return await client.SendAsync(httpRequestMessage).ConfigureAwait(false);
|
return await client.SendAsync(httpRequestMessage).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool TryGetDelay(IWebhookRequest webhookRequest, [NotNullWhen(true)] out int? delay)
|
private static bool TryGetDelay(IWebhookRequest webhookRequest, [NotNullWhen(true)] out int? delay)
|
||||||
{
|
{
|
||||||
delay = webhookRequest.Delay;
|
delay = webhookRequest.Delay;
|
||||||
var minimumDelay = webhookRequest.MinimumRandomDelay;
|
var minimumDelay = webhookRequest.MinimumRandomDelay;
|
||||||
var maximumDelay = webhookRequest.MaximumRandomDelay;
|
var maximumDelay = webhookRequest.MaximumRandomDelay;
|
||||||
|
|
||||||
if (minimumDelay is not null && maximumDelay is not null && maximumDelay >= minimumDelay)
|
if (minimumDelay is not null && maximumDelay is not null && maximumDelay >= minimumDelay)
|
||||||
{
|
{
|
||||||
delay = Random.Value!.Next(minimumDelay.Value, maximumDelay.Value);
|
delay = Random.Value!.Next(minimumDelay.Value, maximumDelay.Value);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return delay is not null;
|
return delay is not null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,39 +1,39 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using WireMock.Matchers.Request;
|
using WireMock.Matchers.Request;
|
||||||
|
|
||||||
namespace WireMock.Logging;
|
namespace WireMock.Logging;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// LogEntry
|
/// LogEntry
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class LogEntry : ILogEntry
|
public class LogEntry : ILogEntry
|
||||||
{
|
{
|
||||||
/// <inheritdoc cref="ILogEntry.Guid" />
|
/// <inheritdoc cref="ILogEntry.Guid" />
|
||||||
public Guid Guid { get; set; }
|
public Guid Guid { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc cref="ILogEntry.RequestMessage" />
|
/// <inheritdoc cref="ILogEntry.RequestMessage" />
|
||||||
public IRequestMessage RequestMessage { get; set; } = null!;
|
public IRequestMessage RequestMessage { get; set; } = null!;
|
||||||
|
|
||||||
/// <inheritdoc cref="ILogEntry.ResponseMessage" />
|
/// <inheritdoc cref="ILogEntry.ResponseMessage" />
|
||||||
public IResponseMessage ResponseMessage { get; set; } = null!;
|
public IResponseMessage ResponseMessage { get; set; } = null!;
|
||||||
|
|
||||||
/// <inheritdoc cref="ILogEntry.RequestMatchResult" />
|
/// <inheritdoc cref="ILogEntry.RequestMatchResult" />
|
||||||
public IRequestMatchResult RequestMatchResult { get; set; } = null!;
|
public IRequestMatchResult RequestMatchResult { get; set; } = null!;
|
||||||
|
|
||||||
/// <inheritdoc cref="ILogEntry.MappingGuid" />
|
/// <inheritdoc cref="ILogEntry.MappingGuid" />
|
||||||
public Guid? MappingGuid { get; set; }
|
public Guid? MappingGuid { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc cref="ILogEntry.MappingTitle" />
|
/// <inheritdoc cref="ILogEntry.MappingTitle" />
|
||||||
public string? MappingTitle { get; set; }
|
public string? MappingTitle { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc cref="ILogEntry.PartialMappingGuid" />
|
/// <inheritdoc cref="ILogEntry.PartialMappingGuid" />
|
||||||
public Guid? PartialMappingGuid { get; set; }
|
public Guid? PartialMappingGuid { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc cref="ILogEntry.PartialMappingTitle" />
|
/// <inheritdoc cref="ILogEntry.PartialMappingTitle" />
|
||||||
public string? PartialMappingTitle { get; set; }
|
public string? PartialMappingTitle { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc cref="ILogEntry.PartialMatchResult" />
|
/// <inheritdoc cref="ILogEntry.PartialMatchResult" />
|
||||||
public IRequestMatchResult PartialMatchResult { get; set; } = null!;
|
public IRequestMatchResult PartialMatchResult { get; set; } = null!;
|
||||||
}
|
}
|
||||||
@@ -1,197 +1,197 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Stef.Validation;
|
using Stef.Validation;
|
||||||
using WireMock.Matchers.Request;
|
using WireMock.Matchers.Request;
|
||||||
using WireMock.Models;
|
using WireMock.Models;
|
||||||
using WireMock.ResponseProviders;
|
using WireMock.ResponseProviders;
|
||||||
using WireMock.Settings;
|
using WireMock.Settings;
|
||||||
|
|
||||||
namespace WireMock;
|
namespace WireMock;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The Mapping.
|
/// The Mapping.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Mapping : IMapping
|
public class Mapping : IMapping
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Guid Guid { get; }
|
public Guid Guid { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public DateTime? UpdatedAt { get; set; }
|
public DateTime? UpdatedAt { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string? Title { get; }
|
public string? Title { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string? Description { get; }
|
public string? Description { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string? Path { get; set; }
|
public string? Path { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public int Priority { get; }
|
public int Priority { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string? Scenario { get; private set; }
|
public string? Scenario { get; private set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string? ExecutionConditionState { get; }
|
public string? ExecutionConditionState { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string? NextState { get; }
|
public string? NextState { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public int? StateTimes { get; }
|
public int? StateTimes { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IRequestMatcher RequestMatcher { get; }
|
public IRequestMatcher RequestMatcher { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IResponseProvider Provider { get; }
|
public IResponseProvider Provider { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public WireMockServerSettings Settings { get; }
|
public WireMockServerSettings Settings { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public bool IsStartState => Scenario == null || Scenario != null && NextState != null && ExecutionConditionState == null;
|
public bool IsStartState => Scenario == null || Scenario != null && NextState != null && ExecutionConditionState == null;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public bool IsAdminInterface => Provider is DynamicResponseProvider or DynamicAsyncResponseProvider or ProxyAsyncResponseProvider;
|
public bool IsAdminInterface => Provider is DynamicResponseProvider or DynamicAsyncResponseProvider or ProxyAsyncResponseProvider;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public bool IsProxy => Provider is ProxyAsyncResponseProvider;
|
public bool IsProxy => Provider is ProxyAsyncResponseProvider;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public bool LogMapping => Provider is not (DynamicResponseProvider or DynamicAsyncResponseProvider);
|
public bool LogMapping => Provider is not (DynamicResponseProvider or DynamicAsyncResponseProvider);
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IWebhook[]? Webhooks { get; }
|
public IWebhook[]? Webhooks { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public bool? UseWebhooksFireAndForget { get; }
|
public bool? UseWebhooksFireAndForget { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public ITimeSettings? TimeSettings { get; }
|
public ITimeSettings? TimeSettings { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public object? Data { get; }
|
public object? Data { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public double? Probability { get; private set; }
|
public double? Probability { get; private set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IdOrTexts? ProtoDefinition { get; private set; }
|
public IdOrTexts? ProtoDefinition { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="Mapping"/> class.
|
/// Initializes a new instance of the <see cref="Mapping"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="guid">The unique identifier.</param>
|
/// <param name="guid">The unique identifier.</param>
|
||||||
/// <param name="updatedAt">The datetime when this mapping was created.</param>
|
/// <param name="updatedAt">The datetime when this mapping was created.</param>
|
||||||
/// <param name="title">The unique title (can be null).</param>
|
/// <param name="title">The unique title (can be null).</param>
|
||||||
/// <param name="description">The description (can be null).</param>
|
/// <param name="description">The description (can be null).</param>
|
||||||
/// <param name="path">The full file path from this mapping title (can be null).</param>
|
/// <param name="path">The full file path from this mapping title (can be null).</param>
|
||||||
/// <param name="settings">The WireMockServerSettings.</param>
|
/// <param name="settings">The WireMockServerSettings.</param>
|
||||||
/// <param name="requestMatcher">The request matcher.</param>
|
/// <param name="requestMatcher">The request matcher.</param>
|
||||||
/// <param name="provider">The provider.</param>
|
/// <param name="provider">The provider.</param>
|
||||||
/// <param name="priority">The priority for this mapping.</param>
|
/// <param name="priority">The priority for this mapping.</param>
|
||||||
/// <param name="scenario">The scenario. [Optional]</param>
|
/// <param name="scenario">The scenario. [Optional]</param>
|
||||||
/// <param name="executionConditionState">State in which the current mapping can occur. [Optional]</param>
|
/// <param name="executionConditionState">State in which the current mapping can occur. [Optional]</param>
|
||||||
/// <param name="nextState">The next state which will occur after the current mapping execution. [Optional]</param>
|
/// <param name="nextState">The next state which will occur after the current mapping execution. [Optional]</param>
|
||||||
/// <param name="stateTimes">Only when the current state is executed this number, the next state which will occur. [Optional]</param>
|
/// <param name="stateTimes">Only when the current state is executed this number, the next state which will occur. [Optional]</param>
|
||||||
/// <param name="webhooks">The Webhooks. [Optional]</param>
|
/// <param name="webhooks">The Webhooks. [Optional]</param>
|
||||||
/// <param name="useWebhooksFireAndForget">Use Fire and Forget for the defined webhook(s). [Optional]</param>
|
/// <param name="useWebhooksFireAndForget">Use Fire and Forget for the defined webhook(s). [Optional]</param>
|
||||||
/// <param name="timeSettings">The TimeSettings. [Optional]</param>
|
/// <param name="timeSettings">The TimeSettings. [Optional]</param>
|
||||||
/// <param name="data">The data object. [Optional]</param>
|
/// <param name="data">The data object. [Optional]</param>
|
||||||
public Mapping
|
public Mapping
|
||||||
(
|
(
|
||||||
Guid guid,
|
Guid guid,
|
||||||
DateTime updatedAt,
|
DateTime updatedAt,
|
||||||
string? title,
|
string? title,
|
||||||
string? description,
|
string? description,
|
||||||
string? path,
|
string? path,
|
||||||
WireMockServerSettings settings,
|
WireMockServerSettings settings,
|
||||||
IRequestMatcher requestMatcher,
|
IRequestMatcher requestMatcher,
|
||||||
IResponseProvider provider,
|
IResponseProvider provider,
|
||||||
int priority,
|
int priority,
|
||||||
string? scenario,
|
string? scenario,
|
||||||
string? executionConditionState,
|
string? executionConditionState,
|
||||||
string? nextState,
|
string? nextState,
|
||||||
int? stateTimes,
|
int? stateTimes,
|
||||||
IWebhook[]? webhooks,
|
IWebhook[]? webhooks,
|
||||||
bool? useWebhooksFireAndForget,
|
bool? useWebhooksFireAndForget,
|
||||||
ITimeSettings? timeSettings,
|
ITimeSettings? timeSettings,
|
||||||
object? data
|
object? data
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
Guid = guid;
|
Guid = guid;
|
||||||
UpdatedAt = updatedAt;
|
UpdatedAt = updatedAt;
|
||||||
Title = title;
|
Title = title;
|
||||||
Description = description;
|
Description = description;
|
||||||
Path = path;
|
Path = path;
|
||||||
Settings = settings;
|
Settings = settings;
|
||||||
RequestMatcher = requestMatcher;
|
RequestMatcher = requestMatcher;
|
||||||
Provider = provider;
|
Provider = provider;
|
||||||
Priority = priority;
|
Priority = priority;
|
||||||
Scenario = scenario;
|
Scenario = scenario;
|
||||||
ExecutionConditionState = executionConditionState;
|
ExecutionConditionState = executionConditionState;
|
||||||
NextState = nextState;
|
NextState = nextState;
|
||||||
StateTimes = stateTimes;
|
StateTimes = stateTimes;
|
||||||
Webhooks = webhooks;
|
Webhooks = webhooks;
|
||||||
UseWebhooksFireAndForget = useWebhooksFireAndForget;
|
UseWebhooksFireAndForget = useWebhooksFireAndForget;
|
||||||
TimeSettings = timeSettings;
|
TimeSettings = timeSettings;
|
||||||
Data = data;
|
Data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Task<(IResponseMessage Message, IMapping? Mapping)> ProvideResponseAsync(IRequestMessage requestMessage)
|
public Task<(IResponseMessage Message, IMapping? Mapping)> ProvideResponseAsync(IRequestMessage requestMessage)
|
||||||
{
|
{
|
||||||
return Provider.ProvideResponseAsync(this, requestMessage, Settings);
|
return Provider.ProvideResponseAsync(this, requestMessage, Settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IRequestMatchResult GetRequestMatchResult(IRequestMessage requestMessage, string? nextState)
|
public IRequestMatchResult GetRequestMatchResult(IRequestMessage requestMessage, string? nextState)
|
||||||
{
|
{
|
||||||
var result = new RequestMatchResult();
|
var result = new RequestMatchResult();
|
||||||
|
|
||||||
RequestMatcher.GetMatchingScore(requestMessage, result);
|
RequestMatcher.GetMatchingScore(requestMessage, result);
|
||||||
|
|
||||||
// Only check state if Scenario is defined
|
// Only check state if Scenario is defined
|
||||||
if (Scenario != null)
|
if (Scenario != null)
|
||||||
{
|
{
|
||||||
var matcher = new RequestMessageScenarioAndStateMatcher(nextState, ExecutionConditionState);
|
var matcher = new RequestMessageScenarioAndStateMatcher(nextState, ExecutionConditionState);
|
||||||
matcher.GetMatchingScore(requestMessage, result);
|
matcher.GetMatchingScore(requestMessage, result);
|
||||||
//// If ExecutionConditionState is null, this means that request is the start from a scenario. So just return.
|
//// If ExecutionConditionState is null, this means that request is the start from a scenario. So just return.
|
||||||
//if (ExecutionConditionState != null)
|
//if (ExecutionConditionState != null)
|
||||||
//{
|
//{
|
||||||
// // ExecutionConditionState is not null, so get score for matching with the nextState.
|
// // ExecutionConditionState is not null, so get score for matching with the nextState.
|
||||||
// var matcher = new RequestMessageScenarioAndStateMatcher(nextState, ExecutionConditionState);
|
// var matcher = new RequestMessageScenarioAndStateMatcher(nextState, ExecutionConditionState);
|
||||||
// matcher.GetMatchingScore(requestMessage, result);
|
// matcher.GetMatchingScore(requestMessage, result);
|
||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IMapping WithProbability(double probability)
|
public IMapping WithProbability(double probability)
|
||||||
{
|
{
|
||||||
Probability = Guard.NotNull(probability);
|
Probability = Guard.NotNull(probability);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IMapping WithScenario(string scenario)
|
public IMapping WithScenario(string scenario)
|
||||||
{
|
{
|
||||||
Scenario = Guard.NotNullOrWhiteSpace(scenario);
|
Scenario = Guard.NotNullOrWhiteSpace(scenario);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IMapping WithProtoDefinition(IdOrTexts protoDefinition)
|
public IMapping WithProtoDefinition(IdOrTexts protoDefinition)
|
||||||
{
|
{
|
||||||
ProtoDefinition = protoDefinition;
|
ProtoDefinition = protoDefinition;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,90 +1,90 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
using AnyOfTypes;
|
using AnyOfTypes;
|
||||||
using Stef.Validation;
|
using Stef.Validation;
|
||||||
using WireMock.Extensions;
|
using WireMock.Extensions;
|
||||||
using WireMock.Models;
|
using WireMock.Models;
|
||||||
using WireMock.Util;
|
using WireMock.Util;
|
||||||
|
|
||||||
namespace WireMock.Matchers;
|
namespace WireMock.Matchers;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ContentTypeMatcher which accepts also all charsets
|
/// ContentTypeMatcher which accepts also all charsets
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <seealso cref="RegexMatcher" />
|
/// <seealso cref="RegexMatcher" />
|
||||||
public class ContentTypeMatcher : WildcardMatcher
|
public class ContentTypeMatcher : WildcardMatcher
|
||||||
{
|
{
|
||||||
private readonly AnyOf<string, StringPattern>[] _patterns;
|
private readonly AnyOf<string, StringPattern>[] _patterns;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="ContentTypeMatcher"/> class.
|
/// Initializes a new instance of the <see cref="ContentTypeMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="pattern">The pattern.</param>
|
/// <param name="pattern">The pattern.</param>
|
||||||
/// <param name="ignoreCase">IgnoreCase (default false)</param>
|
/// <param name="ignoreCase">IgnoreCase (default false)</param>
|
||||||
public ContentTypeMatcher(AnyOf<string, StringPattern> pattern, bool ignoreCase = false) : this([pattern], ignoreCase)
|
public ContentTypeMatcher(AnyOf<string, StringPattern> pattern, bool ignoreCase = false) : this([pattern], ignoreCase)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="ContentTypeMatcher"/> class.
|
/// Initializes a new instance of the <see cref="ContentTypeMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="matchBehaviour">The match behaviour.</param>
|
/// <param name="matchBehaviour">The match behaviour.</param>
|
||||||
/// <param name="pattern">The pattern.</param>
|
/// <param name="pattern">The pattern.</param>
|
||||||
/// <param name="ignoreCase">IgnoreCase (default false)</param>
|
/// <param name="ignoreCase">IgnoreCase (default false)</param>
|
||||||
public ContentTypeMatcher(MatchBehaviour matchBehaviour, AnyOf<string, StringPattern> pattern, bool ignoreCase = false) : this(matchBehaviour,
|
public ContentTypeMatcher(MatchBehaviour matchBehaviour, AnyOf<string, StringPattern> pattern, bool ignoreCase = false) : this(matchBehaviour,
|
||||||
[pattern], ignoreCase)
|
[pattern], ignoreCase)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="ContentTypeMatcher"/> class.
|
/// Initializes a new instance of the <see cref="ContentTypeMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="patterns">The patterns.</param>
|
/// <param name="patterns">The patterns.</param>
|
||||||
/// <param name="ignoreCase">IgnoreCase (default false)</param>
|
/// <param name="ignoreCase">IgnoreCase (default false)</param>
|
||||||
public ContentTypeMatcher(AnyOf<string, StringPattern>[] patterns, bool ignoreCase = false) : this(MatchBehaviour.AcceptOnMatch, patterns, ignoreCase)
|
public ContentTypeMatcher(AnyOf<string, StringPattern>[] patterns, bool ignoreCase = false) : this(MatchBehaviour.AcceptOnMatch, patterns, ignoreCase)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="ContentTypeMatcher"/> class.
|
/// Initializes a new instance of the <see cref="ContentTypeMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="matchBehaviour">The match behaviour.</param>
|
/// <param name="matchBehaviour">The match behaviour.</param>
|
||||||
/// <param name="patterns">The patterns.</param>
|
/// <param name="patterns">The patterns.</param>
|
||||||
/// <param name="ignoreCase">IgnoreCase (default false)</param>
|
/// <param name="ignoreCase">IgnoreCase (default false)</param>
|
||||||
public ContentTypeMatcher(MatchBehaviour matchBehaviour, AnyOf<string, StringPattern>[] patterns, bool ignoreCase = false) : base(matchBehaviour, patterns, ignoreCase)
|
public ContentTypeMatcher(MatchBehaviour matchBehaviour, AnyOf<string, StringPattern>[] patterns, bool ignoreCase = false) : base(matchBehaviour, patterns, ignoreCase)
|
||||||
{
|
{
|
||||||
_patterns = Guard.NotNull(patterns);
|
_patterns = Guard.NotNull(patterns);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override MatchResult IsMatch(string? input)
|
public override MatchResult IsMatch(string? input)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(input) || !MediaTypeHeaderValue.TryParse(input, out var contentType))
|
if (string.IsNullOrEmpty(input) || !MediaTypeHeaderValue.TryParse(input, out var contentType))
|
||||||
{
|
{
|
||||||
return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.Mismatch);
|
return MatchBehaviourHelper.Convert(MatchBehaviour, MatchScores.Mismatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
return base.IsMatch(contentType.MediaType);
|
return base.IsMatch(contentType.MediaType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override AnyOf<string, StringPattern>[] GetPatterns()
|
public override AnyOf<string, StringPattern>[] GetPatterns()
|
||||||
{
|
{
|
||||||
return _patterns;
|
return _patterns;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override string Name => nameof(ContentTypeMatcher);
|
public override string Name => nameof(ContentTypeMatcher);
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override string GetCSharpCodeArguments()
|
public override string GetCSharpCodeArguments()
|
||||||
{
|
{
|
||||||
return $"new {Name}" +
|
return $"new {Name}" +
|
||||||
$"(" +
|
$"(" +
|
||||||
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
|
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
|
||||||
$"{MappingConverterUtils.ToCSharpCodeArguments(_patterns)}, " +
|
$"{MappingConverterUtils.ToCSharpCodeArguments(_patterns)}, " +
|
||||||
$"{CSharpFormatter.ToCSharpBooleanLiteral(IgnoreCase)}" +
|
$"{CSharpFormatter.ToCSharpBooleanLiteral(IgnoreCase)}" +
|
||||||
$")";
|
$")";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,107 +1,107 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using AnyOfTypes;
|
using AnyOfTypes;
|
||||||
using Stef.Validation;
|
using Stef.Validation;
|
||||||
using WireMock.Extensions;
|
using WireMock.Extensions;
|
||||||
using WireMock.Models;
|
using WireMock.Models;
|
||||||
using WireMock.Util;
|
using WireMock.Util;
|
||||||
|
|
||||||
namespace WireMock.Matchers;
|
namespace WireMock.Matchers;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ExactMatcher
|
/// ExactMatcher
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <seealso cref="IStringMatcher" /> and <seealso cref="IIgnoreCaseMatcher" />
|
/// <seealso cref="IStringMatcher" /> and <seealso cref="IIgnoreCaseMatcher" />
|
||||||
public class ExactMatcher : IStringMatcher, IIgnoreCaseMatcher
|
public class ExactMatcher : IStringMatcher, IIgnoreCaseMatcher
|
||||||
{
|
{
|
||||||
private readonly AnyOf<string, StringPattern>[] _values;
|
private readonly AnyOf<string, StringPattern>[] _values;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public MatchBehaviour MatchBehaviour { get; }
|
public MatchBehaviour MatchBehaviour { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="ExactMatcher"/> class.
|
/// Initializes a new instance of the <see cref="ExactMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="matchBehaviour">The match behaviour.</param>
|
/// <param name="matchBehaviour">The match behaviour.</param>
|
||||||
/// <param name="value">The string value.</param>
|
/// <param name="value">The string value.</param>
|
||||||
public ExactMatcher(MatchBehaviour matchBehaviour, string value) : this(matchBehaviour, true, MatchOperator.Or, new AnyOf<string, StringPattern>(value))
|
public ExactMatcher(MatchBehaviour matchBehaviour, string value) : this(matchBehaviour, true, MatchOperator.Or, new AnyOf<string, StringPattern>(value))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="ExactMatcher"/> class.
|
/// Initializes a new instance of the <see cref="ExactMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="values">The values.</param>
|
/// <param name="values">The values.</param>
|
||||||
public ExactMatcher(params AnyOf<string, StringPattern>[] values) : this(MatchBehaviour.AcceptOnMatch, false, MatchOperator.Or, values)
|
public ExactMatcher(params AnyOf<string, StringPattern>[] values) : this(MatchBehaviour.AcceptOnMatch, false, MatchOperator.Or, values)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="ExactMatcher"/> class.
|
/// Initializes a new instance of the <see cref="ExactMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="ignoreCase">Ignore the case from the pattern(s).</param>
|
/// <param name="ignoreCase">Ignore the case from the pattern(s).</param>
|
||||||
/// <param name="values">The values.</param>
|
/// <param name="values">The values.</param>
|
||||||
public ExactMatcher(bool ignoreCase, params AnyOf<string, StringPattern>[] values) : this(MatchBehaviour.AcceptOnMatch, ignoreCase, MatchOperator.Or, values)
|
public ExactMatcher(bool ignoreCase, params AnyOf<string, StringPattern>[] values) : this(MatchBehaviour.AcceptOnMatch, ignoreCase, MatchOperator.Or, values)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="ExactMatcher"/> class.
|
/// Initializes a new instance of the <see cref="ExactMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="matchBehaviour">The match behaviour.</param>
|
/// <param name="matchBehaviour">The match behaviour.</param>
|
||||||
/// <param name="ignoreCase">Ignore the case from the pattern(s).</param>
|
/// <param name="ignoreCase">Ignore the case from the pattern(s).</param>
|
||||||
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param>
|
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param>
|
||||||
/// <param name="values">The values.</param>
|
/// <param name="values">The values.</param>
|
||||||
public ExactMatcher(
|
public ExactMatcher(
|
||||||
MatchBehaviour matchBehaviour,
|
MatchBehaviour matchBehaviour,
|
||||||
bool ignoreCase = false,
|
bool ignoreCase = false,
|
||||||
MatchOperator matchOperator = MatchOperator.Or,
|
MatchOperator matchOperator = MatchOperator.Or,
|
||||||
params AnyOf<string, StringPattern>[] values)
|
params AnyOf<string, StringPattern>[] values)
|
||||||
{
|
{
|
||||||
_values = Guard.NotNull(values);
|
_values = Guard.NotNull(values);
|
||||||
|
|
||||||
MatchBehaviour = matchBehaviour;
|
MatchBehaviour = matchBehaviour;
|
||||||
IgnoreCase = ignoreCase;
|
IgnoreCase = ignoreCase;
|
||||||
MatchOperator = matchOperator;
|
MatchOperator = matchOperator;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public MatchResult IsMatch(string? input)
|
public MatchResult IsMatch(string? input)
|
||||||
{
|
{
|
||||||
Func<string?, bool> equals = IgnoreCase
|
Func<string?, bool> equals = IgnoreCase
|
||||||
? pattern => string.Equals(pattern, input, StringComparison.OrdinalIgnoreCase)
|
? pattern => string.Equals(pattern, input, StringComparison.OrdinalIgnoreCase)
|
||||||
: pattern => pattern == input;
|
: pattern => pattern == input;
|
||||||
|
|
||||||
var score = MatchScores.ToScore(_values.Select(v => equals(v)).ToArray(), MatchOperator);
|
var score = MatchScores.ToScore(_values.Select(v => equals(v)).ToArray(), MatchOperator);
|
||||||
return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score));
|
return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public AnyOf<string, StringPattern>[] GetPatterns()
|
public AnyOf<string, StringPattern>[] GetPatterns()
|
||||||
{
|
{
|
||||||
return _values;
|
return _values;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public MatchOperator MatchOperator { get; }
|
public MatchOperator MatchOperator { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string Name => nameof(ExactMatcher);
|
public string Name => nameof(ExactMatcher);
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public bool IgnoreCase { get; }
|
public bool IgnoreCase { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string GetCSharpCodeArguments()
|
public string GetCSharpCodeArguments()
|
||||||
{
|
{
|
||||||
return $"new {Name}" +
|
return $"new {Name}" +
|
||||||
$"(" +
|
$"(" +
|
||||||
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
|
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
|
||||||
$"{CSharpFormatter.ToCSharpBooleanLiteral(IgnoreCase)}, " +
|
$"{CSharpFormatter.ToCSharpBooleanLiteral(IgnoreCase)}, " +
|
||||||
$"{MatchOperator.GetFullyQualifiedEnumValue()}, " +
|
$"{MatchOperator.GetFullyQualifiedEnumValue()}, " +
|
||||||
$"{MappingConverterUtils.ToCSharpCodeArguments(_values)}" +
|
$"{MappingConverterUtils.ToCSharpCodeArguments(_values)}" +
|
||||||
$")";
|
$")";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,179 +1,179 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using AnyOfTypes;
|
using AnyOfTypes;
|
||||||
using Stef.Validation;
|
using Stef.Validation;
|
||||||
using WireMock.Extensions;
|
using WireMock.Extensions;
|
||||||
using WireMock.Models;
|
using WireMock.Models;
|
||||||
using WireMock.Util;
|
using WireMock.Util;
|
||||||
|
|
||||||
namespace WireMock.Matchers;
|
namespace WireMock.Matchers;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// FormUrl Encoded fields Matcher
|
/// FormUrl Encoded fields Matcher
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <inheritdoc cref="IStringMatcher"/>
|
/// <inheritdoc cref="IStringMatcher"/>
|
||||||
/// <inheritdoc cref="IIgnoreCaseMatcher"/>
|
/// <inheritdoc cref="IIgnoreCaseMatcher"/>
|
||||||
public class FormUrlEncodedMatcher : IStringMatcher, IIgnoreCaseMatcher
|
public class FormUrlEncodedMatcher : IStringMatcher, IIgnoreCaseMatcher
|
||||||
{
|
{
|
||||||
private readonly AnyOf<string, StringPattern>[] _patterns;
|
private readonly AnyOf<string, StringPattern>[] _patterns;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public MatchBehaviour MatchBehaviour { get; }
|
public MatchBehaviour MatchBehaviour { get; }
|
||||||
|
|
||||||
private readonly List<(WildcardMatcher Key, WildcardMatcher? Value)> _pairs = [];
|
private readonly List<(WildcardMatcher Key, WildcardMatcher? Value)> _pairs = [];
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="FormUrlEncodedMatcher"/> class.
|
/// Initializes a new instance of the <see cref="FormUrlEncodedMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="pattern">The pattern.</param>
|
/// <param name="pattern">The pattern.</param>
|
||||||
/// <param name="ignoreCase">Ignore the case from the pattern.</param>
|
/// <param name="ignoreCase">Ignore the case from the pattern.</param>
|
||||||
/// <param name="matchOperator">The <see cref="MatchOperator"/> to use. (default = "Or")</param>
|
/// <param name="matchOperator">The <see cref="MatchOperator"/> to use. (default = "Or")</param>
|
||||||
public FormUrlEncodedMatcher(
|
public FormUrlEncodedMatcher(
|
||||||
AnyOf<string, StringPattern> pattern,
|
AnyOf<string, StringPattern> pattern,
|
||||||
bool ignoreCase = false,
|
bool ignoreCase = false,
|
||||||
MatchOperator matchOperator = MatchOperator.Or) :
|
MatchOperator matchOperator = MatchOperator.Or) :
|
||||||
this(MatchBehaviour.AcceptOnMatch, [pattern], ignoreCase, matchOperator)
|
this(MatchBehaviour.AcceptOnMatch, [pattern], ignoreCase, matchOperator)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="FormUrlEncodedMatcher"/> class.
|
/// Initializes a new instance of the <see cref="FormUrlEncodedMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="matchBehaviour">The match behaviour.</param>
|
/// <param name="matchBehaviour">The match behaviour.</param>
|
||||||
/// <param name="pattern">The pattern.</param>
|
/// <param name="pattern">The pattern.</param>
|
||||||
/// <param name="ignoreCase">Ignore the case from the pattern.</param>
|
/// <param name="ignoreCase">Ignore the case from the pattern.</param>
|
||||||
/// <param name="matchOperator">The <see cref="MatchOperator"/> to use. (default = "Or")</param>
|
/// <param name="matchOperator">The <see cref="MatchOperator"/> to use. (default = "Or")</param>
|
||||||
public FormUrlEncodedMatcher(
|
public FormUrlEncodedMatcher(
|
||||||
MatchBehaviour matchBehaviour,
|
MatchBehaviour matchBehaviour,
|
||||||
AnyOf<string, StringPattern> pattern,
|
AnyOf<string, StringPattern> pattern,
|
||||||
bool ignoreCase = false,
|
bool ignoreCase = false,
|
||||||
MatchOperator matchOperator = MatchOperator.Or) :
|
MatchOperator matchOperator = MatchOperator.Or) :
|
||||||
this(matchBehaviour, [pattern], ignoreCase, matchOperator)
|
this(matchBehaviour, [pattern], ignoreCase, matchOperator)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="FormUrlEncodedMatcher"/> class.
|
/// Initializes a new instance of the <see cref="FormUrlEncodedMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="patterns">The patterns.</param>
|
/// <param name="patterns">The patterns.</param>
|
||||||
/// <param name="ignoreCase">Ignore the case from the pattern.</param>
|
/// <param name="ignoreCase">Ignore the case from the pattern.</param>
|
||||||
/// <param name="matchOperator">The <see cref="MatchOperator"/> to use. (default = "Or")</param>
|
/// <param name="matchOperator">The <see cref="MatchOperator"/> to use. (default = "Or")</param>
|
||||||
public FormUrlEncodedMatcher(
|
public FormUrlEncodedMatcher(
|
||||||
AnyOf<string, StringPattern>[] patterns,
|
AnyOf<string, StringPattern>[] patterns,
|
||||||
bool ignoreCase = false,
|
bool ignoreCase = false,
|
||||||
MatchOperator matchOperator = MatchOperator.Or) :
|
MatchOperator matchOperator = MatchOperator.Or) :
|
||||||
this(MatchBehaviour.AcceptOnMatch, patterns, ignoreCase, matchOperator)
|
this(MatchBehaviour.AcceptOnMatch, patterns, ignoreCase, matchOperator)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="FormUrlEncodedMatcher"/> class.
|
/// Initializes a new instance of the <see cref="FormUrlEncodedMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="matchBehaviour">The match behaviour.</param>
|
/// <param name="matchBehaviour">The match behaviour.</param>
|
||||||
/// <param name="patterns">The patterns.</param>
|
/// <param name="patterns">The patterns.</param>
|
||||||
/// <param name="ignoreCase">Ignore the case from the pattern.</param>
|
/// <param name="ignoreCase">Ignore the case from the pattern.</param>
|
||||||
/// <param name="matchOperator">The <see cref="MatchOperator"/> to use. (default = "Or")</param>
|
/// <param name="matchOperator">The <see cref="MatchOperator"/> to use. (default = "Or")</param>
|
||||||
public FormUrlEncodedMatcher(
|
public FormUrlEncodedMatcher(
|
||||||
MatchBehaviour matchBehaviour,
|
MatchBehaviour matchBehaviour,
|
||||||
AnyOf<string, StringPattern>[] patterns,
|
AnyOf<string, StringPattern>[] patterns,
|
||||||
bool ignoreCase = false,
|
bool ignoreCase = false,
|
||||||
MatchOperator matchOperator = MatchOperator.Or)
|
MatchOperator matchOperator = MatchOperator.Or)
|
||||||
{
|
{
|
||||||
_patterns = Guard.NotNull(patterns);
|
_patterns = Guard.NotNull(patterns);
|
||||||
IgnoreCase = ignoreCase;
|
IgnoreCase = ignoreCase;
|
||||||
MatchBehaviour = matchBehaviour;
|
MatchBehaviour = matchBehaviour;
|
||||||
MatchOperator = matchOperator;
|
MatchOperator = matchOperator;
|
||||||
|
|
||||||
foreach (var pattern in _patterns)
|
foreach (var pattern in _patterns)
|
||||||
{
|
{
|
||||||
if (QueryStringParser.TryParse(pattern, IgnoreCase, out var nameValueCollection))
|
if (QueryStringParser.TryParse(pattern, IgnoreCase, out var nameValueCollection))
|
||||||
{
|
{
|
||||||
foreach (var nameValue in nameValueCollection)
|
foreach (var nameValue in nameValueCollection)
|
||||||
{
|
{
|
||||||
var keyMatcher = new WildcardMatcher(MatchBehaviour.AcceptOnMatch, [nameValue.Key], ignoreCase, MatchOperator);
|
var keyMatcher = new WildcardMatcher(MatchBehaviour.AcceptOnMatch, [nameValue.Key], ignoreCase, MatchOperator);
|
||||||
var valueMatcher = new WildcardMatcher(MatchBehaviour.AcceptOnMatch, [nameValue.Value], ignoreCase, MatchOperator);
|
var valueMatcher = new WildcardMatcher(MatchBehaviour.AcceptOnMatch, [nameValue.Value], ignoreCase, MatchOperator);
|
||||||
_pairs.Add((keyMatcher, valueMatcher));
|
_pairs.Add((keyMatcher, valueMatcher));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public MatchResult IsMatch(string? input)
|
public MatchResult IsMatch(string? input)
|
||||||
{
|
{
|
||||||
// Input is null or empty and if no patterns defined, return Perfect match.
|
// Input is null or empty and if no patterns defined, return Perfect match.
|
||||||
if (string.IsNullOrEmpty(input) && _patterns.Length == 0)
|
if (string.IsNullOrEmpty(input) && _patterns.Length == 0)
|
||||||
{
|
{
|
||||||
return new MatchResult(MatchScores.Perfect);
|
return new MatchResult(MatchScores.Perfect);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!QueryStringParser.TryParse(input, IgnoreCase, out var inputNameValueCollection))
|
if (!QueryStringParser.TryParse(input, IgnoreCase, out var inputNameValueCollection))
|
||||||
{
|
{
|
||||||
return new MatchResult(MatchScores.Mismatch);
|
return new MatchResult(MatchScores.Mismatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
var matches = GetMatches(inputNameValueCollection);
|
var matches = GetMatches(inputNameValueCollection);
|
||||||
|
|
||||||
var score = MatchScores.ToScore(matches, MatchOperator);
|
var score = MatchScores.ToScore(matches, MatchOperator);
|
||||||
return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score));
|
return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score));
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool[] GetMatches(IDictionary<string, string> inputNameValueCollection)
|
private bool[] GetMatches(IDictionary<string, string> inputNameValueCollection)
|
||||||
{
|
{
|
||||||
var matches = new List<bool>();
|
var matches = new List<bool>();
|
||||||
if (_pairs.Count > inputNameValueCollection.Count)
|
if (_pairs.Count > inputNameValueCollection.Count)
|
||||||
{
|
{
|
||||||
matches.AddRange(Enumerable.Repeat(false, _pairs.Count - inputNameValueCollection.Count));
|
matches.AddRange(Enumerable.Repeat(false, _pairs.Count - inputNameValueCollection.Count));
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var inputKeyValuePair in inputNameValueCollection)
|
foreach (var inputKeyValuePair in inputNameValueCollection)
|
||||||
{
|
{
|
||||||
var match = false;
|
var match = false;
|
||||||
foreach (var pair in _pairs)
|
foreach (var pair in _pairs)
|
||||||
{
|
{
|
||||||
var keyMatchResult = pair.Key.IsMatch(inputKeyValuePair.Key).IsPerfect();
|
var keyMatchResult = pair.Key.IsMatch(inputKeyValuePair.Key).IsPerfect();
|
||||||
if (keyMatchResult)
|
if (keyMatchResult)
|
||||||
{
|
{
|
||||||
match = pair.Value?.IsMatch(inputKeyValuePair.Value).IsPerfect() ?? false;
|
match = pair.Value?.IsMatch(inputKeyValuePair.Value).IsPerfect() ?? false;
|
||||||
if (match)
|
if (match)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
matches.Add(match);
|
matches.Add(match);
|
||||||
}
|
}
|
||||||
|
|
||||||
return matches.ToArray();
|
return matches.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public virtual AnyOf<string, StringPattern>[] GetPatterns()
|
public virtual AnyOf<string, StringPattern>[] GetPatterns()
|
||||||
{
|
{
|
||||||
return _patterns;
|
return _patterns;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public virtual string Name => nameof(FormUrlEncodedMatcher);
|
public virtual string Name => nameof(FormUrlEncodedMatcher);
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public bool IgnoreCase { get; }
|
public bool IgnoreCase { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public MatchOperator MatchOperator { get; }
|
public MatchOperator MatchOperator { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string GetCSharpCodeArguments()
|
public string GetCSharpCodeArguments()
|
||||||
{
|
{
|
||||||
return $"new {Name}" +
|
return $"new {Name}" +
|
||||||
$"(" +
|
$"(" +
|
||||||
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
|
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
|
||||||
$"{MappingConverterUtils.ToCSharpCodeArguments(_patterns)}, " +
|
$"{MappingConverterUtils.ToCSharpCodeArguments(_patterns)}, " +
|
||||||
$"{CSharpFormatter.ToCSharpBooleanLiteral(IgnoreCase)}, " +
|
$"{CSharpFormatter.ToCSharpBooleanLiteral(IgnoreCase)}, " +
|
||||||
$"{MatchOperator.GetFullyQualifiedEnumValue()}" +
|
$"{MatchOperator.GetFullyQualifiedEnumValue()}" +
|
||||||
$")";
|
$")";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,167 +1,167 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using AnyOfTypes;
|
using AnyOfTypes;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using Stef.Validation;
|
using Stef.Validation;
|
||||||
using WireMock.Extensions;
|
using WireMock.Extensions;
|
||||||
using WireMock.Models;
|
using WireMock.Models;
|
||||||
using WireMock.Util;
|
using WireMock.Util;
|
||||||
|
|
||||||
namespace WireMock.Matchers;
|
namespace WireMock.Matchers;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// JsonPathMatcher
|
/// JsonPathMatcher
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <seealso cref="IStringMatcher" />
|
/// <seealso cref="IStringMatcher" />
|
||||||
/// <seealso cref="IObjectMatcher" />
|
/// <seealso cref="IObjectMatcher" />
|
||||||
public class JsonPathMatcher : IStringMatcher, IObjectMatcher
|
public class JsonPathMatcher : IStringMatcher, IObjectMatcher
|
||||||
{
|
{
|
||||||
private readonly AnyOf<string, StringPattern>[] _patterns;
|
private readonly AnyOf<string, StringPattern>[] _patterns;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public MatchBehaviour MatchBehaviour { get; }
|
public MatchBehaviour MatchBehaviour { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public object Value { get; }
|
public object Value { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="JsonPathMatcher"/> class.
|
/// Initializes a new instance of the <see cref="JsonPathMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="patterns">The patterns.</param>
|
/// <param name="patterns">The patterns.</param>
|
||||||
public JsonPathMatcher(params string[] patterns) : this(MatchBehaviour.AcceptOnMatch, MatchOperator.Or,
|
public JsonPathMatcher(params string[] patterns) : this(MatchBehaviour.AcceptOnMatch, MatchOperator.Or,
|
||||||
patterns.ToAnyOfPatterns())
|
patterns.ToAnyOfPatterns())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="JsonPathMatcher"/> class.
|
/// Initializes a new instance of the <see cref="JsonPathMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="patterns">The patterns.</param>
|
/// <param name="patterns">The patterns.</param>
|
||||||
public JsonPathMatcher(params AnyOf<string, StringPattern>[] patterns) : this(MatchBehaviour.AcceptOnMatch,
|
public JsonPathMatcher(params AnyOf<string, StringPattern>[] patterns) : this(MatchBehaviour.AcceptOnMatch,
|
||||||
MatchOperator.Or, patterns)
|
MatchOperator.Or, patterns)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="JsonPathMatcher"/> class.
|
/// Initializes a new instance of the <see cref="JsonPathMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="matchBehaviour">The match behaviour.</param>
|
/// <param name="matchBehaviour">The match behaviour.</param>
|
||||||
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param>
|
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param>
|
||||||
/// <param name="patterns">The patterns.</param>
|
/// <param name="patterns">The patterns.</param>
|
||||||
public JsonPathMatcher(
|
public JsonPathMatcher(
|
||||||
MatchBehaviour matchBehaviour,
|
MatchBehaviour matchBehaviour,
|
||||||
MatchOperator matchOperator = MatchOperator.Or,
|
MatchOperator matchOperator = MatchOperator.Or,
|
||||||
params AnyOf<string, StringPattern>[] patterns)
|
params AnyOf<string, StringPattern>[] patterns)
|
||||||
{
|
{
|
||||||
_patterns = Guard.NotNull(patterns);
|
_patterns = Guard.NotNull(patterns);
|
||||||
MatchBehaviour = matchBehaviour;
|
MatchBehaviour = matchBehaviour;
|
||||||
MatchOperator = matchOperator;
|
MatchOperator = matchOperator;
|
||||||
Value = patterns;
|
Value = patterns;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public MatchResult IsMatch(string? input)
|
public MatchResult IsMatch(string? input)
|
||||||
{
|
{
|
||||||
var score = MatchScores.Mismatch;
|
var score = MatchScores.Mismatch;
|
||||||
Exception? exception = null;
|
Exception? exception = null;
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(input))
|
if (!string.IsNullOrWhiteSpace(input))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var jToken = JToken.Parse(input);
|
var jToken = JToken.Parse(input);
|
||||||
score = IsMatch(jToken);
|
score = IsMatch(jToken);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
exception = ex;
|
exception = ex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score), exception);
|
return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score), exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public MatchResult IsMatch(object? input)
|
public MatchResult IsMatch(object? input)
|
||||||
{
|
{
|
||||||
var score = MatchScores.Mismatch;
|
var score = MatchScores.Mismatch;
|
||||||
Exception? exception = null;
|
Exception? exception = null;
|
||||||
|
|
||||||
// When input is null or byte[], return Mismatch.
|
// When input is null or byte[], return Mismatch.
|
||||||
if (input != null && input is not byte[])
|
if (input != null && input is not byte[])
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Check if JToken or object
|
// Check if JToken or object
|
||||||
JToken jToken = input as JToken ?? JObject.FromObject(input);
|
JToken jToken = input as JToken ?? JObject.FromObject(input);
|
||||||
score = IsMatch(jToken);
|
score = IsMatch(jToken);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
exception = ex;
|
exception = ex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score), exception);
|
return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score), exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public AnyOf<string, StringPattern>[] GetPatterns()
|
public AnyOf<string, StringPattern>[] GetPatterns()
|
||||||
{
|
{
|
||||||
return _patterns;
|
return _patterns;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public MatchOperator MatchOperator { get; }
|
public MatchOperator MatchOperator { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string Name => nameof(JsonPathMatcher);
|
public string Name => nameof(JsonPathMatcher);
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string GetCSharpCodeArguments()
|
public string GetCSharpCodeArguments()
|
||||||
{
|
{
|
||||||
return $"new {Name}" +
|
return $"new {Name}" +
|
||||||
$"(" +
|
$"(" +
|
||||||
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
|
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
|
||||||
$"{MatchOperator.GetFullyQualifiedEnumValue()}, " +
|
$"{MatchOperator.GetFullyQualifiedEnumValue()}, " +
|
||||||
$"{MappingConverterUtils.ToCSharpCodeArguments(_patterns)}" +
|
$"{MappingConverterUtils.ToCSharpCodeArguments(_patterns)}" +
|
||||||
$")";
|
$")";
|
||||||
}
|
}
|
||||||
|
|
||||||
private double IsMatch(JToken jToken)
|
private double IsMatch(JToken jToken)
|
||||||
{
|
{
|
||||||
var array = ConvertJTokenToJArrayIfNeeded(jToken);
|
var array = ConvertJTokenToJArrayIfNeeded(jToken);
|
||||||
|
|
||||||
// The SelectToken method can accept a string path to a child token ( i.e. "Manufacturers[0].Products[0].Price").
|
// The SelectToken method can accept a string path to a child token ( i.e. "Manufacturers[0].Products[0].Price").
|
||||||
// In that case it will return a JValue (some type) which does not implement the IEnumerable interface.
|
// In that case it will return a JValue (some type) which does not implement the IEnumerable interface.
|
||||||
var values = _patterns.Select(pattern => array.SelectToken(pattern.GetPattern()) != null).ToArray();
|
var values = _patterns.Select(pattern => array.SelectToken(pattern.GetPattern()) != null).ToArray();
|
||||||
|
|
||||||
return MatchScores.ToScore(values, MatchOperator);
|
return MatchScores.ToScore(values, MatchOperator);
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://github.com/wiremock/WireMock.Net/issues/965
|
// https://github.com/wiremock/WireMock.Net/issues/965
|
||||||
// https://stackoverflow.com/questions/66922188/newtonsoft-jsonpath-with-c-sharp-syntax
|
// https://stackoverflow.com/questions/66922188/newtonsoft-jsonpath-with-c-sharp-syntax
|
||||||
// Filtering using SelectToken() isn't guaranteed to work for objects inside objects -- only objects inside arrays.
|
// Filtering using SelectToken() isn't guaranteed to work for objects inside objects -- only objects inside arrays.
|
||||||
// So this code checks if it's an JArray, if it's not an array, construct a new JArray.
|
// So this code checks if it's an JArray, if it's not an array, construct a new JArray.
|
||||||
private static JToken ConvertJTokenToJArrayIfNeeded(JToken jToken)
|
private static JToken ConvertJTokenToJArrayIfNeeded(JToken jToken)
|
||||||
{
|
{
|
||||||
if (jToken.Count() == 1)
|
if (jToken.Count() == 1)
|
||||||
{
|
{
|
||||||
var property = jToken.First();
|
var property = jToken.First();
|
||||||
var item = property.First();
|
var item = property.First();
|
||||||
if (item is JArray)
|
if (item is JArray)
|
||||||
{
|
{
|
||||||
return jToken;
|
return jToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new JObject
|
return new JObject
|
||||||
{
|
{
|
||||||
[property.Path] = new JArray(item)
|
[property.Path] = new JArray(item)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return jToken;
|
return jToken;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,130 +1,130 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using AnyOfTypes;
|
using AnyOfTypes;
|
||||||
using DevLab.JmesPath;
|
using DevLab.JmesPath;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Stef.Validation;
|
using Stef.Validation;
|
||||||
using WireMock.Extensions;
|
using WireMock.Extensions;
|
||||||
using WireMock.Models;
|
using WireMock.Models;
|
||||||
using WireMock.Util;
|
using WireMock.Util;
|
||||||
|
|
||||||
namespace WireMock.Matchers;
|
namespace WireMock.Matchers;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// http://jmespath.org/
|
/// http://jmespath.org/
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class JmesPathMatcher : IStringMatcher, IObjectMatcher
|
public class JmesPathMatcher : IStringMatcher, IObjectMatcher
|
||||||
{
|
{
|
||||||
private readonly AnyOf<string, StringPattern>[] _patterns;
|
private readonly AnyOf<string, StringPattern>[] _patterns;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public object Value { get; }
|
public object Value { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public MatchBehaviour MatchBehaviour { get; }
|
public MatchBehaviour MatchBehaviour { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="JmesPathMatcher"/> class.
|
/// Initializes a new instance of the <see cref="JmesPathMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="patterns">The patterns.</param>
|
/// <param name="patterns">The patterns.</param>
|
||||||
public JmesPathMatcher(params string[] patterns) : this(MatchBehaviour.AcceptOnMatch, MatchOperator.Or, patterns.ToAnyOfPatterns())
|
public JmesPathMatcher(params string[] patterns) : this(MatchBehaviour.AcceptOnMatch, MatchOperator.Or, patterns.ToAnyOfPatterns())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="JmesPathMatcher"/> class.
|
/// Initializes a new instance of the <see cref="JmesPathMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="patterns">The patterns.</param>
|
/// <param name="patterns">The patterns.</param>
|
||||||
public JmesPathMatcher(params AnyOf<string, StringPattern>[] patterns) : this(MatchBehaviour.AcceptOnMatch, MatchOperator.Or, patterns)
|
public JmesPathMatcher(params AnyOf<string, StringPattern>[] patterns) : this(MatchBehaviour.AcceptOnMatch, MatchOperator.Or, patterns)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="JmesPathMatcher"/> class.
|
/// Initializes a new instance of the <see cref="JmesPathMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use.</param>
|
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use.</param>
|
||||||
/// <param name="patterns">The patterns.</param>
|
/// <param name="patterns">The patterns.</param>
|
||||||
public JmesPathMatcher(MatchOperator matchOperator = MatchOperator.Or, params AnyOf<string, StringPattern>[] patterns) :
|
public JmesPathMatcher(MatchOperator matchOperator = MatchOperator.Or, params AnyOf<string, StringPattern>[] patterns) :
|
||||||
this(MatchBehaviour.AcceptOnMatch, matchOperator, patterns)
|
this(MatchBehaviour.AcceptOnMatch, matchOperator, patterns)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="JmesPathMatcher"/> class.
|
/// Initializes a new instance of the <see cref="JmesPathMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="matchBehaviour">The match behaviour.</param>
|
/// <param name="matchBehaviour">The match behaviour.</param>
|
||||||
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use.</param>
|
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use.</param>
|
||||||
/// <param name="patterns">The patterns.</param>
|
/// <param name="patterns">The patterns.</param>
|
||||||
public JmesPathMatcher(
|
public JmesPathMatcher(
|
||||||
MatchBehaviour matchBehaviour,
|
MatchBehaviour matchBehaviour,
|
||||||
MatchOperator matchOperator = MatchOperator.Or,
|
MatchOperator matchOperator = MatchOperator.Or,
|
||||||
params AnyOf<string, StringPattern>[] patterns)
|
params AnyOf<string, StringPattern>[] patterns)
|
||||||
{
|
{
|
||||||
_patterns = Guard.NotNull(patterns);
|
_patterns = Guard.NotNull(patterns);
|
||||||
MatchBehaviour = matchBehaviour;
|
MatchBehaviour = matchBehaviour;
|
||||||
MatchOperator = matchOperator;
|
MatchOperator = matchOperator;
|
||||||
Value = patterns;
|
Value = patterns;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public MatchResult IsMatch(string? input)
|
public MatchResult IsMatch(string? input)
|
||||||
{
|
{
|
||||||
var score = MatchScores.Mismatch;
|
var score = MatchScores.Mismatch;
|
||||||
Exception? exception = null;
|
Exception? exception = null;
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(input))
|
if (!string.IsNullOrWhiteSpace(input))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var results = _patterns.Select(pattern => bool.Parse(new JmesPath().Transform(input, pattern.GetPattern()))).ToArray();
|
var results = _patterns.Select(pattern => bool.Parse(new JmesPath().Transform(input, pattern.GetPattern()))).ToArray();
|
||||||
score = MatchScores.ToScore(results, MatchOperator);
|
score = MatchScores.ToScore(results, MatchOperator);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
exception = ex;
|
exception = ex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score), exception);
|
return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score), exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public MatchResult IsMatch(object? input)
|
public MatchResult IsMatch(object? input)
|
||||||
{
|
{
|
||||||
var score = MatchScores.Mismatch;
|
var score = MatchScores.Mismatch;
|
||||||
|
|
||||||
// When input is null or byte[], return Mismatch.
|
// When input is null or byte[], return Mismatch.
|
||||||
if (input != null && !(input is byte[]))
|
if (input != null && !(input is byte[]))
|
||||||
{
|
{
|
||||||
var inputAsString = JsonConvert.SerializeObject(input);
|
var inputAsString = JsonConvert.SerializeObject(input);
|
||||||
return IsMatch(inputAsString);
|
return IsMatch(inputAsString);
|
||||||
}
|
}
|
||||||
|
|
||||||
return MatchBehaviourHelper.Convert(MatchBehaviour, score);
|
return MatchBehaviourHelper.Convert(MatchBehaviour, score);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public AnyOf<string, StringPattern>[] GetPatterns()
|
public AnyOf<string, StringPattern>[] GetPatterns()
|
||||||
{
|
{
|
||||||
return _patterns;
|
return _patterns;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public MatchOperator MatchOperator { get; }
|
public MatchOperator MatchOperator { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string Name => nameof(JmesPathMatcher);
|
public string Name => nameof(JmesPathMatcher);
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string GetCSharpCodeArguments()
|
public string GetCSharpCodeArguments()
|
||||||
{
|
{
|
||||||
return $"new {Name}" +
|
return $"new {Name}" +
|
||||||
$"(" +
|
$"(" +
|
||||||
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
|
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
|
||||||
$"{MatchOperator.GetFullyQualifiedEnumValue()}, " +
|
$"{MatchOperator.GetFullyQualifiedEnumValue()}, " +
|
||||||
$"{MappingConverterUtils.ToCSharpCodeArguments(_patterns)}" +
|
$"{MappingConverterUtils.ToCSharpCodeArguments(_patterns)}" +
|
||||||
$")";
|
$")";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,250 +1,250 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using Stef.Validation;
|
using Stef.Validation;
|
||||||
using WireMock.Extensions;
|
using WireMock.Extensions;
|
||||||
using WireMock.Util;
|
using WireMock.Util;
|
||||||
using JsonUtils = WireMock.Util.JsonUtils;
|
using JsonUtils = WireMock.Util.JsonUtils;
|
||||||
|
|
||||||
namespace WireMock.Matchers;
|
namespace WireMock.Matchers;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// JsonMatcher
|
/// JsonMatcher
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class JsonMatcher : IJsonMatcher
|
public class JsonMatcher : IJsonMatcher
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public virtual string Name => nameof(JsonMatcher);
|
public virtual string Name => nameof(JsonMatcher);
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public object Value { get; }
|
public object Value { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public MatchBehaviour MatchBehaviour { get; }
|
public MatchBehaviour MatchBehaviour { get; }
|
||||||
|
|
||||||
/// <inheritdoc cref="IIgnoreCaseMatcher.IgnoreCase"/>
|
/// <inheritdoc cref="IIgnoreCaseMatcher.IgnoreCase"/>
|
||||||
public bool IgnoreCase { get; }
|
public bool IgnoreCase { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Support Regex
|
/// Support Regex
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Regex { get; }
|
public bool Regex { get; }
|
||||||
|
|
||||||
private readonly JToken _valueAsJToken;
|
private readonly JToken _valueAsJToken;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="JsonMatcher"/> class.
|
/// Initializes a new instance of the <see cref="JsonMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="value">The string value to check for equality.</param>
|
/// <param name="value">The string value to check for equality.</param>
|
||||||
/// <param name="ignoreCase">Ignore the case from the PropertyName and PropertyValue (string only).</param>
|
/// <param name="ignoreCase">Ignore the case from the PropertyName and PropertyValue (string only).</param>
|
||||||
/// <param name="regex">Support Regex.</param>
|
/// <param name="regex">Support Regex.</param>
|
||||||
public JsonMatcher(string value, bool ignoreCase = false, bool regex = false) : this(MatchBehaviour.AcceptOnMatch, value, ignoreCase, regex)
|
public JsonMatcher(string value, bool ignoreCase = false, bool regex = false) : this(MatchBehaviour.AcceptOnMatch, value, ignoreCase, regex)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="JsonMatcher"/> class.
|
/// Initializes a new instance of the <see cref="JsonMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="value">The object value to check for equality.</param>
|
/// <param name="value">The object value to check for equality.</param>
|
||||||
/// <param name="ignoreCase">Ignore the case from the PropertyName and PropertyValue (string only).</param>
|
/// <param name="ignoreCase">Ignore the case from the PropertyName and PropertyValue (string only).</param>
|
||||||
/// <param name="regex">Support Regex.</param>
|
/// <param name="regex">Support Regex.</param>
|
||||||
public JsonMatcher(object value, bool ignoreCase = false, bool regex = false) : this(MatchBehaviour.AcceptOnMatch, value, ignoreCase, regex)
|
public JsonMatcher(object value, bool ignoreCase = false, bool regex = false) : this(MatchBehaviour.AcceptOnMatch, value, ignoreCase, regex)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="JsonMatcher"/> class.
|
/// Initializes a new instance of the <see cref="JsonMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="matchBehaviour">The match behaviour.</param>
|
/// <param name="matchBehaviour">The match behaviour.</param>
|
||||||
/// <param name="value">The value to check for equality.</param>
|
/// <param name="value">The value to check for equality.</param>
|
||||||
/// <param name="ignoreCase">Ignore the case from the PropertyName and PropertyValue (string only).</param>
|
/// <param name="ignoreCase">Ignore the case from the PropertyName and PropertyValue (string only).</param>
|
||||||
/// <param name="regex">Support Regex.</param>
|
/// <param name="regex">Support Regex.</param>
|
||||||
public JsonMatcher(MatchBehaviour matchBehaviour, object value, bool ignoreCase = false, bool regex = false)
|
public JsonMatcher(MatchBehaviour matchBehaviour, object value, bool ignoreCase = false, bool regex = false)
|
||||||
{
|
{
|
||||||
Guard.NotNull(value);
|
Guard.NotNull(value);
|
||||||
|
|
||||||
MatchBehaviour = matchBehaviour;
|
MatchBehaviour = matchBehaviour;
|
||||||
IgnoreCase = ignoreCase;
|
IgnoreCase = ignoreCase;
|
||||||
Regex = regex;
|
Regex = regex;
|
||||||
|
|
||||||
Value = value;
|
Value = value;
|
||||||
_valueAsJToken = JsonUtils.ConvertValueToJToken(value);
|
_valueAsJToken = JsonUtils.ConvertValueToJToken(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public MatchResult IsMatch(object? input)
|
public MatchResult IsMatch(object? input)
|
||||||
{
|
{
|
||||||
var score = MatchScores.Mismatch;
|
var score = MatchScores.Mismatch;
|
||||||
Exception? error = null;
|
Exception? error = null;
|
||||||
|
|
||||||
// When input is null or byte[], return Mismatch.
|
// When input is null or byte[], return Mismatch.
|
||||||
if (input != null && input is not byte[])
|
if (input != null && input is not byte[])
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var inputAsJToken = JsonUtils.ConvertValueToJToken(input);
|
var inputAsJToken = JsonUtils.ConvertValueToJToken(input);
|
||||||
|
|
||||||
var match = IsMatch(RenameJToken(_valueAsJToken), RenameJToken(inputAsJToken));
|
var match = IsMatch(RenameJToken(_valueAsJToken), RenameJToken(inputAsJToken));
|
||||||
score = MatchScores.ToScore(match);
|
score = MatchScores.ToScore(match);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
error = ex;
|
error = ex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score), error);
|
return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score), error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public virtual string GetCSharpCodeArguments()
|
public virtual string GetCSharpCodeArguments()
|
||||||
{
|
{
|
||||||
return $"new {Name}" +
|
return $"new {Name}" +
|
||||||
$"(" +
|
$"(" +
|
||||||
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
|
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
|
||||||
$"{CSharpFormatter.ConvertToAnonymousObjectDefinition(Value, 3)}, " +
|
$"{CSharpFormatter.ConvertToAnonymousObjectDefinition(Value, 3)}, " +
|
||||||
$"{CSharpFormatter.ToCSharpBooleanLiteral(IgnoreCase)}, " +
|
$"{CSharpFormatter.ToCSharpBooleanLiteral(IgnoreCase)}, " +
|
||||||
$"{CSharpFormatter.ToCSharpBooleanLiteral(Regex)}" +
|
$"{CSharpFormatter.ToCSharpBooleanLiteral(Regex)}" +
|
||||||
$")";
|
$")";
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Compares the input against the matcher value
|
/// Compares the input against the matcher value
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="value">Matcher value</param>
|
/// <param name="value">Matcher value</param>
|
||||||
/// <param name="input">Input value</param>
|
/// <param name="input">Input value</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
protected virtual bool IsMatch(JToken value, JToken? input)
|
protected virtual bool IsMatch(JToken value, JToken? input)
|
||||||
{
|
{
|
||||||
// If equal, return true.
|
// If equal, return true.
|
||||||
if (input == value)
|
if (input == value)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If input is null, return false.
|
// If input is null, return false.
|
||||||
if (input == null)
|
if (input == null)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If using Regex and the value is a string, use the MatchRegex method.
|
// If using Regex and the value is a string, use the MatchRegex method.
|
||||||
if (Regex && value.Type == JTokenType.String)
|
if (Regex && value.Type == JTokenType.String)
|
||||||
{
|
{
|
||||||
var valueAsString = value.ToString();
|
var valueAsString = value.ToString();
|
||||||
|
|
||||||
var (valid, result) = RegexUtils.MatchRegex(valueAsString, input.ToString());
|
var (valid, result) = RegexUtils.MatchRegex(valueAsString, input.ToString());
|
||||||
if (valid)
|
if (valid)
|
||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the value is a Guid and the input is a string, or vice versa, convert them to strings and compare the string values.
|
// If the value is a Guid and the input is a string, or vice versa, convert them to strings and compare the string values.
|
||||||
if ((value.Type == JTokenType.Guid && input.Type == JTokenType.String) || (value.Type == JTokenType.String && input.Type == JTokenType.Guid))
|
if ((value.Type == JTokenType.Guid && input.Type == JTokenType.String) || (value.Type == JTokenType.String && input.Type == JTokenType.Guid))
|
||||||
{
|
{
|
||||||
return JToken.DeepEquals(value.ToString().ToUpperInvariant(), input.ToString().ToUpperInvariant());
|
return JToken.DeepEquals(value.ToString().ToUpperInvariant(), input.ToString().ToUpperInvariant());
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (value.Type)
|
switch (value.Type)
|
||||||
{
|
{
|
||||||
// If the value is an object, compare all properties.
|
// If the value is an object, compare all properties.
|
||||||
case JTokenType.Object:
|
case JTokenType.Object:
|
||||||
var valueProperties = value.ToObject<Dictionary<string, JToken>>() ?? new Dictionary<string, JToken>();
|
var valueProperties = value.ToObject<Dictionary<string, JToken>>() ?? new Dictionary<string, JToken>();
|
||||||
var inputProperties = input.ToObject<Dictionary<string, JToken>>() ?? new Dictionary<string, JToken>();
|
var inputProperties = input.ToObject<Dictionary<string, JToken>>() ?? new Dictionary<string, JToken>();
|
||||||
|
|
||||||
// If the number of properties is different, return false.
|
// If the number of properties is different, return false.
|
||||||
if (valueProperties.Count != inputProperties.Count)
|
if (valueProperties.Count != inputProperties.Count)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compare all properties. The input must match all properties of the value.
|
// Compare all properties. The input must match all properties of the value.
|
||||||
foreach (var pair in valueProperties)
|
foreach (var pair in valueProperties)
|
||||||
{
|
{
|
||||||
if (!IsMatch(pair.Value, inputProperties[pair.Key]))
|
if (!IsMatch(pair.Value, inputProperties[pair.Key]))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// If the value is an array, compare all elements.
|
// If the value is an array, compare all elements.
|
||||||
case JTokenType.Array:
|
case JTokenType.Array:
|
||||||
var valueArray = value.ToObject<JToken[]>() ?? EmptyArray<JToken>.Value;
|
var valueArray = value.ToObject<JToken[]>() ?? [];
|
||||||
var inputArray = input.ToObject<JToken[]>() ?? EmptyArray<JToken>.Value;
|
var inputArray = input.ToObject<JToken[]>() ?? [];
|
||||||
|
|
||||||
// If the number of elements is different, return false.
|
// If the number of elements is different, return false.
|
||||||
if (valueArray.Length != inputArray.Length)
|
if (valueArray.Length != inputArray.Length)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return !valueArray.Where((valueToken, index) => !IsMatch(valueToken, inputArray[index])).Any();
|
return !valueArray.Where((valueToken, index) => !IsMatch(valueToken, inputArray[index])).Any();
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// Use JToken.DeepEquals() for all other types.
|
// Use JToken.DeepEquals() for all other types.
|
||||||
return JToken.DeepEquals(value, input);
|
return JToken.DeepEquals(value, input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://stackoverflow.com/questions/11679804/json-net-rename-properties
|
// https://stackoverflow.com/questions/11679804/json-net-rename-properties
|
||||||
private JToken RenameJToken(JToken input)
|
private JToken RenameJToken(JToken input)
|
||||||
{
|
{
|
||||||
if (!IgnoreCase)
|
if (!IgnoreCase)
|
||||||
{
|
{
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
|
|
||||||
return input switch
|
return input switch
|
||||||
{
|
{
|
||||||
JProperty property => RenameJProperty(property),
|
JProperty property => RenameJProperty(property),
|
||||||
JArray array => RenameJArray(array),
|
JArray array => RenameJArray(array),
|
||||||
JObject obj => RenameJObject(obj),
|
JObject obj => RenameJObject(obj),
|
||||||
_ => input
|
_ => input
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private JProperty RenameJProperty(JProperty property)
|
private JProperty RenameJProperty(JProperty property)
|
||||||
{
|
{
|
||||||
if (!IgnoreCase)
|
if (!IgnoreCase)
|
||||||
{
|
{
|
||||||
return property;
|
return property;
|
||||||
}
|
}
|
||||||
|
|
||||||
var propertyValue = property.Value;
|
var propertyValue = property.Value;
|
||||||
if (propertyValue.Type == JTokenType.String && !Regex)
|
if (propertyValue.Type == JTokenType.String && !Regex)
|
||||||
{
|
{
|
||||||
var stringValue = propertyValue.Value<string>()!;
|
var stringValue = propertyValue.Value<string>()!;
|
||||||
propertyValue = ToUpper(stringValue);
|
propertyValue = ToUpper(stringValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new JProperty(ToUpper(property.Name)!, RenameJToken(propertyValue));
|
return new JProperty(ToUpper(property.Name)!, RenameJToken(propertyValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
private JArray RenameJArray(JArray array)
|
private JArray RenameJArray(JArray array)
|
||||||
{
|
{
|
||||||
if (Regex)
|
if (Regex)
|
||||||
{
|
{
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
var renamedValues = array.Select(RenameJToken);
|
var renamedValues = array.Select(RenameJToken);
|
||||||
return new JArray(renamedValues);
|
return new JArray(renamedValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
private JObject RenameJObject(JObject obj)
|
private JObject RenameJObject(JObject obj)
|
||||||
{
|
{
|
||||||
var renamedProperties = obj.Properties().Select(RenameJProperty);
|
var renamedProperties = obj.Properties().Select(RenameJProperty);
|
||||||
return new JObject(renamedProperties);
|
return new JObject(renamedProperties);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string? ToUpper(string? input)
|
private static string? ToUpper(string? input)
|
||||||
{
|
{
|
||||||
return input?.ToUpperInvariant();
|
return input?.ToUpperInvariant();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,151 +1,151 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Linq.Dynamic.Core;
|
using System.Linq.Dynamic.Core;
|
||||||
using AnyOfTypes;
|
using AnyOfTypes;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using Stef.Validation;
|
using Stef.Validation;
|
||||||
using WireMock.Extensions;
|
using WireMock.Extensions;
|
||||||
using WireMock.Json;
|
using WireMock.Json;
|
||||||
using WireMock.Models;
|
using WireMock.Models;
|
||||||
using WireMock.Util;
|
using WireMock.Util;
|
||||||
|
|
||||||
namespace WireMock.Matchers;
|
namespace WireMock.Matchers;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// System.Linq.Dynamic.Core Expression Matcher
|
/// System.Linq.Dynamic.Core Expression Matcher
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <inheritdoc cref="IObjectMatcher"/>
|
/// <inheritdoc cref="IObjectMatcher"/>
|
||||||
/// <inheritdoc cref="IStringMatcher"/>
|
/// <inheritdoc cref="IStringMatcher"/>
|
||||||
public class LinqMatcher : IObjectMatcher, IStringMatcher
|
public class LinqMatcher : IObjectMatcher, IStringMatcher
|
||||||
{
|
{
|
||||||
private readonly AnyOf<string, StringPattern>[] _patterns;
|
private readonly AnyOf<string, StringPattern>[] _patterns;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public MatchBehaviour MatchBehaviour { get; }
|
public MatchBehaviour MatchBehaviour { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public object Value { get; }
|
public object Value { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="LinqMatcher"/> class.
|
/// Initializes a new instance of the <see cref="LinqMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="pattern">The pattern.</param>
|
/// <param name="pattern">The pattern.</param>
|
||||||
public LinqMatcher(AnyOf<string, StringPattern> pattern) : this(new[] { pattern })
|
public LinqMatcher(AnyOf<string, StringPattern> pattern) : this(new[] { pattern })
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="LinqMatcher"/> class.
|
/// Initializes a new instance of the <see cref="LinqMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="patterns">The patterns.</param>
|
/// <param name="patterns">The patterns.</param>
|
||||||
public LinqMatcher(params AnyOf<string, StringPattern>[] patterns) : this(MatchBehaviour.AcceptOnMatch, MatchOperator.Or, patterns)
|
public LinqMatcher(params AnyOf<string, StringPattern>[] patterns) : this(MatchBehaviour.AcceptOnMatch, MatchOperator.Or, patterns)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="LinqMatcher"/> class.
|
/// Initializes a new instance of the <see cref="LinqMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="matchBehaviour">The match behaviour.</param>
|
/// <param name="matchBehaviour">The match behaviour.</param>
|
||||||
/// <param name="pattern">The pattern.</param>
|
/// <param name="pattern">The pattern.</param>
|
||||||
public LinqMatcher(MatchBehaviour matchBehaviour, AnyOf<string, StringPattern> pattern) : this(matchBehaviour, MatchOperator.Or, pattern)
|
public LinqMatcher(MatchBehaviour matchBehaviour, AnyOf<string, StringPattern> pattern) : this(matchBehaviour, MatchOperator.Or, pattern)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="LinqMatcher"/> class.
|
/// Initializes a new instance of the <see cref="LinqMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="matchBehaviour">The match behaviour.</param>
|
/// <param name="matchBehaviour">The match behaviour.</param>
|
||||||
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param>
|
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param>
|
||||||
/// <param name="patterns">The patterns.</param>
|
/// <param name="patterns">The patterns.</param>
|
||||||
public LinqMatcher(
|
public LinqMatcher(
|
||||||
MatchBehaviour matchBehaviour,
|
MatchBehaviour matchBehaviour,
|
||||||
MatchOperator matchOperator = MatchOperator.Or,
|
MatchOperator matchOperator = MatchOperator.Or,
|
||||||
params AnyOf<string, StringPattern>[] patterns)
|
params AnyOf<string, StringPattern>[] patterns)
|
||||||
{
|
{
|
||||||
_patterns = Guard.NotNull(patterns);
|
_patterns = Guard.NotNull(patterns);
|
||||||
MatchBehaviour = matchBehaviour;
|
MatchBehaviour = matchBehaviour;
|
||||||
MatchOperator = matchOperator;
|
MatchOperator = matchOperator;
|
||||||
Value = patterns;
|
Value = patterns;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public MatchResult IsMatch(string? input)
|
public MatchResult IsMatch(string? input)
|
||||||
{
|
{
|
||||||
var score = MatchScores.Mismatch;
|
var score = MatchScores.Mismatch;
|
||||||
Exception? error = null;
|
Exception? error = null;
|
||||||
|
|
||||||
// Convert a single input string to a Queryable string-list with 1 entry.
|
// Convert a single input string to a Queryable string-list with 1 entry.
|
||||||
IQueryable queryable = new[] { input }.AsQueryable();
|
IQueryable queryable = new[] { input }.AsQueryable();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Use the Any(...) method to check if the result matches
|
// Use the Any(...) method to check if the result matches
|
||||||
score = MatchScores.ToScore(_patterns.Select(pattern => queryable.Any(pattern.GetPattern())).ToArray(), MatchOperator);
|
score = MatchScores.ToScore(_patterns.Select(pattern => queryable.Any(pattern.GetPattern())).ToArray(), MatchOperator);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
error = e;
|
error = e;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score), error);
|
return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score), error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public MatchResult IsMatch(object? input)
|
public MatchResult IsMatch(object? input)
|
||||||
{
|
{
|
||||||
var score = MatchScores.Mismatch;
|
var score = MatchScores.Mismatch;
|
||||||
Exception? error = null;
|
Exception? error = null;
|
||||||
|
|
||||||
JArray jArray;
|
JArray jArray;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
jArray = new JArray { input };
|
jArray = new JArray { input };
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
jArray = input == null ? new JArray() : new JArray { JToken.FromObject(input) };
|
jArray = input == null ? new JArray() : new JArray { JToken.FromObject(input) };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert a single object to a Queryable JObject-list with 1 entry.
|
// Convert a single object to a Queryable JObject-list with 1 entry.
|
||||||
var queryable = jArray.ToDynamicClassArray().AsQueryable();
|
var queryable = jArray.ToDynamicClassArray().AsQueryable();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var patternsAsStringArray = _patterns.Select(p => p.GetPattern()).ToArray();
|
var patternsAsStringArray = _patterns.Select(p => p.GetPattern()).ToArray();
|
||||||
var scores = patternsAsStringArray.Select(p => queryable.Any(p)).ToArray();
|
var scores = patternsAsStringArray.Select(p => queryable.Any(p)).ToArray();
|
||||||
|
|
||||||
score = MatchScores.ToScore(scores, MatchOperator);
|
score = MatchScores.ToScore(scores, MatchOperator);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
error = e;
|
error = e;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score), error);
|
return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score), error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public AnyOf<string, StringPattern>[] GetPatterns()
|
public AnyOf<string, StringPattern>[] GetPatterns()
|
||||||
{
|
{
|
||||||
return _patterns;
|
return _patterns;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public MatchOperator MatchOperator { get; }
|
public MatchOperator MatchOperator { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string Name => nameof(LinqMatcher);
|
public string Name => nameof(LinqMatcher);
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string GetCSharpCodeArguments()
|
public string GetCSharpCodeArguments()
|
||||||
{
|
{
|
||||||
return $"new {Name}" +
|
return $"new {Name}" +
|
||||||
$"(" +
|
$"(" +
|
||||||
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
|
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
|
||||||
$"{MatchOperator.GetFullyQualifiedEnumValue()}, " +
|
$"{MatchOperator.GetFullyQualifiedEnumValue()}, " +
|
||||||
$"{MappingConverterUtils.ToCSharpCodeArguments(_patterns)}" +
|
$"{MappingConverterUtils.ToCSharpCodeArguments(_patterns)}" +
|
||||||
$")";
|
$")";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,189 +1,189 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Stef.Validation;
|
using Stef.Validation;
|
||||||
using WireMock.Matchers.Helpers;
|
using WireMock.Matchers.Helpers;
|
||||||
using WireMock.Util;
|
using WireMock.Util;
|
||||||
|
|
||||||
namespace WireMock.Matchers.Request;
|
namespace WireMock.Matchers.Request;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The request body matcher.
|
/// The request body matcher.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class RequestMessageBodyMatcher : IRequestMatcher
|
public class RequestMessageBodyMatcher : IRequestMatcher
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The body function
|
/// The body function
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Func<string?, bool>? Func { get; }
|
public Func<string?, bool>? Func { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The body data function for byte[]
|
/// The body data function for byte[]
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Func<byte[]?, bool>? DataFunc { get; }
|
public Func<byte[]?, bool>? DataFunc { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The body data function for json
|
/// The body data function for json
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Func<object?, bool>? JsonFunc { get; }
|
public Func<object?, bool>? JsonFunc { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The body data function for BodyData
|
/// The body data function for BodyData
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Func<IBodyData?, bool>? BodyDataFunc { get; }
|
public Func<IBodyData?, bool>? BodyDataFunc { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The body data function for FormUrlEncoded
|
/// The body data function for FormUrlEncoded
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Func<IDictionary<string, string>?, bool>? FormUrlEncodedFunc { get; }
|
public Func<IDictionary<string, string>?, bool>? FormUrlEncodedFunc { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The matchers.
|
/// The matchers.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IMatcher[]? Matchers { get; }
|
public IMatcher[]? Matchers { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The <see cref="MatchOperator"/>
|
/// The <see cref="MatchOperator"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public MatchOperator MatchOperator { get; } = MatchOperator.Or;
|
public MatchOperator MatchOperator { get; } = MatchOperator.Or;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
|
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="matchBehaviour">The match behaviour.</param>
|
/// <param name="matchBehaviour">The match behaviour.</param>
|
||||||
/// <param name="body">The body.</param>
|
/// <param name="body">The body.</param>
|
||||||
public RequestMessageBodyMatcher(MatchBehaviour matchBehaviour, string body) :
|
public RequestMessageBodyMatcher(MatchBehaviour matchBehaviour, string body) :
|
||||||
this(new[] { new WildcardMatcher(matchBehaviour, body) }.Cast<IMatcher>().ToArray())
|
this(new[] { new WildcardMatcher(matchBehaviour, body) }.Cast<IMatcher>().ToArray())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
|
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="matchBehaviour">The match behaviour.</param>
|
/// <param name="matchBehaviour">The match behaviour.</param>
|
||||||
/// <param name="body">The body.</param>
|
/// <param name="body">The body.</param>
|
||||||
public RequestMessageBodyMatcher(MatchBehaviour matchBehaviour, byte[] body) :
|
public RequestMessageBodyMatcher(MatchBehaviour matchBehaviour, byte[] body) :
|
||||||
this(new[] { new ExactObjectMatcher(matchBehaviour, body) }.Cast<IMatcher>().ToArray())
|
this(new[] { new ExactObjectMatcher(matchBehaviour, body) }.Cast<IMatcher>().ToArray())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
|
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="matchBehaviour">The match behaviour.</param>
|
/// <param name="matchBehaviour">The match behaviour.</param>
|
||||||
/// <param name="body">The body.</param>
|
/// <param name="body">The body.</param>
|
||||||
public RequestMessageBodyMatcher(MatchBehaviour matchBehaviour, object body) :
|
public RequestMessageBodyMatcher(MatchBehaviour matchBehaviour, object body) :
|
||||||
this(new[] { new ExactObjectMatcher(matchBehaviour, body) }.Cast<IMatcher>().ToArray())
|
this(new[] { new ExactObjectMatcher(matchBehaviour, body) }.Cast<IMatcher>().ToArray())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
|
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="func">The function.</param>
|
/// <param name="func">The function.</param>
|
||||||
public RequestMessageBodyMatcher(Func<string?, bool> func)
|
public RequestMessageBodyMatcher(Func<string?, bool> func)
|
||||||
{
|
{
|
||||||
Func = Guard.NotNull(func);
|
Func = Guard.NotNull(func);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
|
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="func">The function.</param>
|
/// <param name="func">The function.</param>
|
||||||
public RequestMessageBodyMatcher(Func<byte[]?, bool> func)
|
public RequestMessageBodyMatcher(Func<byte[]?, bool> func)
|
||||||
{
|
{
|
||||||
DataFunc = Guard.NotNull(func);
|
DataFunc = Guard.NotNull(func);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
|
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="func">The function.</param>
|
/// <param name="func">The function.</param>
|
||||||
public RequestMessageBodyMatcher(Func<object?, bool> func)
|
public RequestMessageBodyMatcher(Func<object?, bool> func)
|
||||||
{
|
{
|
||||||
JsonFunc = Guard.NotNull(func);
|
JsonFunc = Guard.NotNull(func);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
|
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="func">The function.</param>
|
/// <param name="func">The function.</param>
|
||||||
public RequestMessageBodyMatcher(Func<IBodyData?, bool> func)
|
public RequestMessageBodyMatcher(Func<IBodyData?, bool> func)
|
||||||
{
|
{
|
||||||
BodyDataFunc = Guard.NotNull(func);
|
BodyDataFunc = Guard.NotNull(func);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
|
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="func">The function.</param>
|
/// <param name="func">The function.</param>
|
||||||
public RequestMessageBodyMatcher(Func<IDictionary<string, string>?, bool> func)
|
public RequestMessageBodyMatcher(Func<IDictionary<string, string>?, bool> func)
|
||||||
{
|
{
|
||||||
FormUrlEncodedFunc = Guard.NotNull(func);
|
FormUrlEncodedFunc = Guard.NotNull(func);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
|
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="matchers">The matchers.</param>
|
/// <param name="matchers">The matchers.</param>
|
||||||
public RequestMessageBodyMatcher(params IMatcher[] matchers)
|
public RequestMessageBodyMatcher(params IMatcher[] matchers)
|
||||||
{
|
{
|
||||||
Matchers = Guard.NotNull(matchers);
|
Matchers = Guard.NotNull(matchers);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
|
/// Initializes a new instance of the <see cref="RequestMessageBodyMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="matchers">The matchers.</param>
|
/// <param name="matchers">The matchers.</param>
|
||||||
/// <param name="matchOperator">The <see cref="MatchOperator"/> to use.</param>
|
/// <param name="matchOperator">The <see cref="MatchOperator"/> to use.</param>
|
||||||
public RequestMessageBodyMatcher(MatchOperator matchOperator, params IMatcher[] matchers)
|
public RequestMessageBodyMatcher(MatchOperator matchOperator, params IMatcher[] matchers)
|
||||||
{
|
{
|
||||||
Matchers = Guard.NotNull(matchers);
|
Matchers = Guard.NotNull(matchers);
|
||||||
MatchOperator = matchOperator;
|
MatchOperator = matchOperator;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
|
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
|
||||||
{
|
{
|
||||||
var (score, exception) = CalculateMatchScore(requestMessage).Expand();
|
var (score, exception) = CalculateMatchScore(requestMessage).Expand();
|
||||||
return requestMatchResult.AddScore(GetType(), score, exception);
|
return requestMatchResult.AddScore(GetType(), score, exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
private MatchResult CalculateMatchScore(IRequestMessage requestMessage)
|
private MatchResult CalculateMatchScore(IRequestMessage requestMessage)
|
||||||
{
|
{
|
||||||
if (Matchers != null && Matchers.Any())
|
if (Matchers != null && Matchers.Any())
|
||||||
{
|
{
|
||||||
var results = Matchers.Select(matcher => BodyDataMatchScoreCalculator.CalculateMatchScore(requestMessage.BodyData, matcher)).ToArray();
|
var results = Matchers.Select(matcher => BodyDataMatchScoreCalculator.CalculateMatchScore(requestMessage.BodyData, matcher)).ToArray();
|
||||||
return MatchResult.From(results, MatchOperator);
|
return MatchResult.From(results, MatchOperator);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Func != null)
|
if (Func != null)
|
||||||
{
|
{
|
||||||
return MatchScores.ToScore(Func(requestMessage.BodyData?.BodyAsString));
|
return MatchScores.ToScore(Func(requestMessage.BodyData?.BodyAsString));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FormUrlEncodedFunc != null)
|
if (FormUrlEncodedFunc != null)
|
||||||
{
|
{
|
||||||
return MatchScores.ToScore(FormUrlEncodedFunc(requestMessage.BodyData?.BodyAsFormUrlEncoded));
|
return MatchScores.ToScore(FormUrlEncodedFunc(requestMessage.BodyData?.BodyAsFormUrlEncoded));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (JsonFunc != null)
|
if (JsonFunc != null)
|
||||||
{
|
{
|
||||||
return MatchScores.ToScore(JsonFunc(requestMessage.BodyData?.BodyAsJson));
|
return MatchScores.ToScore(JsonFunc(requestMessage.BodyData?.BodyAsJson));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DataFunc != null)
|
if (DataFunc != null)
|
||||||
{
|
{
|
||||||
return MatchScores.ToScore(DataFunc(requestMessage.BodyData?.BodyAsBytes));
|
return MatchScores.ToScore(DataFunc(requestMessage.BodyData?.BodyAsBytes));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BodyDataFunc != null)
|
if (BodyDataFunc != null)
|
||||||
{
|
{
|
||||||
return MatchScores.ToScore(BodyDataFunc(requestMessage.BodyData));
|
return MatchScores.ToScore(BodyDataFunc(requestMessage.BodyData));
|
||||||
}
|
}
|
||||||
|
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Stef.Validation;
|
using Stef.Validation;
|
||||||
using WireMock.Util;
|
using WireMock.Util;
|
||||||
@@ -13,6 +12,8 @@ namespace WireMock.Matchers.Request;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class RequestMessageMultiPartMatcher : IRequestMatcher
|
public class RequestMessageMultiPartMatcher : IRequestMatcher
|
||||||
{
|
{
|
||||||
|
private static readonly IMimeKitUtils MimeKitUtils = TypeLoader.LoadStaticInstance<IMimeKitUtils>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The matchers.
|
/// The matchers.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -53,9 +54,6 @@ public class RequestMessageMultiPartMatcher : IRequestMatcher
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
|
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 score = MatchScores.Mismatch;
|
var score = MatchScores.Mismatch;
|
||||||
Exception? exception = null;
|
Exception? exception = null;
|
||||||
|
|
||||||
@@ -71,12 +69,10 @@ public class RequestMessageMultiPartMatcher : IRequestMatcher
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var mimePartMatchers = Matchers.OfType<MimePartMatcher>().ToArray();
|
foreach (var mimePartMatcher in Matchers.OfType<IMimePartMatcher>().ToArray())
|
||||||
|
|
||||||
foreach (var mimePartMatcher in Matchers.OfType<MimePartMatcher>().ToArray())
|
|
||||||
{
|
{
|
||||||
score = MatchScores.Mismatch;
|
score = MatchScores.Mismatch;
|
||||||
foreach (var mimeBodyPart in message.BodyParts.OfType<MimeKit.MimePart>())
|
foreach (var mimeBodyPart in MimeKitUtils.GetBodyParts(message))
|
||||||
{
|
{
|
||||||
var matchResult = mimePartMatcher.IsMatch(mimeBodyPart);
|
var matchResult = mimePartMatcher.IsMatch(mimeBodyPart);
|
||||||
if (matchResult.IsPerfect())
|
if (matchResult.IsPerfect())
|
||||||
@@ -85,8 +81,8 @@ public class RequestMessageMultiPartMatcher : IRequestMatcher
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((MatchOperator == MatchOperator.Or && MatchScores.IsPerfect(score))
|
|
||||||
|| (MatchOperator == MatchOperator.And && !MatchScores.IsPerfect(score)))
|
if ((MatchOperator == MatchOperator.Or && MatchScores.IsPerfect(score)) || (MatchOperator == MatchOperator.And && !MatchScores.IsPerfect(score)))
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -98,6 +94,5 @@ public class RequestMessageMultiPartMatcher : IRequestMatcher
|
|||||||
}
|
}
|
||||||
|
|
||||||
return requestMatchResult.AddScore(GetType(), score, exception);
|
return requestMatchResult.AddScore(GetType(), score, exception);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,140 +1,140 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using AnyOfTypes;
|
using AnyOfTypes;
|
||||||
using SimMetrics.Net;
|
using SimMetrics.Net;
|
||||||
using SimMetrics.Net.API;
|
using SimMetrics.Net.API;
|
||||||
using SimMetrics.Net.Metric;
|
using SimMetrics.Net.Metric;
|
||||||
using Stef.Validation;
|
using Stef.Validation;
|
||||||
using WireMock.Extensions;
|
using WireMock.Extensions;
|
||||||
using WireMock.Models;
|
using WireMock.Models;
|
||||||
using WireMock.Util;
|
using WireMock.Util;
|
||||||
|
|
||||||
namespace WireMock.Matchers;
|
namespace WireMock.Matchers;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// SimMetricsMatcher
|
/// SimMetricsMatcher
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <seealso cref="IStringMatcher" />
|
/// <seealso cref="IStringMatcher" />
|
||||||
public class SimMetricsMatcher : IStringMatcher
|
public class SimMetricsMatcher : IStringMatcher
|
||||||
{
|
{
|
||||||
private readonly AnyOf<string, StringPattern>[] _patterns;
|
private readonly AnyOf<string, StringPattern>[] _patterns;
|
||||||
private readonly SimMetricType _simMetricType;
|
private readonly SimMetricType _simMetricType;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public MatchBehaviour MatchBehaviour { get; }
|
public MatchBehaviour MatchBehaviour { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="SimMetricsMatcher"/> class.
|
/// Initializes a new instance of the <see cref="SimMetricsMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="pattern">The pattern.</param>
|
/// <param name="pattern">The pattern.</param>
|
||||||
/// <param name="simMetricType">The SimMetric Type</param>
|
/// <param name="simMetricType">The SimMetric Type</param>
|
||||||
public SimMetricsMatcher(AnyOf<string, StringPattern> pattern, SimMetricType simMetricType = SimMetricType.Levenstein) : this(new[] { pattern }, simMetricType)
|
public SimMetricsMatcher(AnyOf<string, StringPattern> pattern, SimMetricType simMetricType = SimMetricType.Levenstein) : this(new[] { pattern }, simMetricType)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="SimMetricsMatcher"/> class.
|
/// Initializes a new instance of the <see cref="SimMetricsMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="matchBehaviour">The match behaviour.</param>
|
/// <param name="matchBehaviour">The match behaviour.</param>
|
||||||
/// <param name="pattern">The pattern.</param>
|
/// <param name="pattern">The pattern.</param>
|
||||||
/// <param name="simMetricType">The SimMetric Type</param>
|
/// <param name="simMetricType">The SimMetric Type</param>
|
||||||
public SimMetricsMatcher(MatchBehaviour matchBehaviour, AnyOf<string, StringPattern> pattern, SimMetricType simMetricType = SimMetricType.Levenstein) : this(matchBehaviour, new[] { pattern }, simMetricType)
|
public SimMetricsMatcher(MatchBehaviour matchBehaviour, AnyOf<string, StringPattern> pattern, SimMetricType simMetricType = SimMetricType.Levenstein) : this(matchBehaviour, new[] { pattern }, simMetricType)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="SimMetricsMatcher"/> class.
|
/// Initializes a new instance of the <see cref="SimMetricsMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="patterns">The patterns.</param>
|
/// <param name="patterns">The patterns.</param>
|
||||||
/// <param name="simMetricType">The SimMetric Type</param>
|
/// <param name="simMetricType">The SimMetric Type</param>
|
||||||
public SimMetricsMatcher(string[] patterns, SimMetricType simMetricType = SimMetricType.Levenstein) : this(MatchBehaviour.AcceptOnMatch, patterns.ToAnyOfPatterns(), simMetricType)
|
public SimMetricsMatcher(string[] patterns, SimMetricType simMetricType = SimMetricType.Levenstein) : this(MatchBehaviour.AcceptOnMatch, patterns.ToAnyOfPatterns(), simMetricType)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="SimMetricsMatcher"/> class.
|
/// Initializes a new instance of the <see cref="SimMetricsMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="patterns">The patterns.</param>
|
/// <param name="patterns">The patterns.</param>
|
||||||
/// <param name="simMetricType">The SimMetric Type</param>
|
/// <param name="simMetricType">The SimMetric Type</param>
|
||||||
public SimMetricsMatcher(AnyOf<string, StringPattern>[] patterns, SimMetricType simMetricType = SimMetricType.Levenstein) : this(MatchBehaviour.AcceptOnMatch, patterns, simMetricType)
|
public SimMetricsMatcher(AnyOf<string, StringPattern>[] patterns, SimMetricType simMetricType = SimMetricType.Levenstein) : this(MatchBehaviour.AcceptOnMatch, patterns, simMetricType)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="SimMetricsMatcher"/> class.
|
/// Initializes a new instance of the <see cref="SimMetricsMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="matchBehaviour">The match behaviour.</param>
|
/// <param name="matchBehaviour">The match behaviour.</param>
|
||||||
/// <param name="patterns">The patterns.</param>
|
/// <param name="patterns">The patterns.</param>
|
||||||
/// <param name="simMetricType">The SimMetric Type</param>
|
/// <param name="simMetricType">The SimMetric Type</param>
|
||||||
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param>
|
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param>
|
||||||
public SimMetricsMatcher(
|
public SimMetricsMatcher(
|
||||||
MatchBehaviour matchBehaviour,
|
MatchBehaviour matchBehaviour,
|
||||||
AnyOf<string, StringPattern>[] patterns,
|
AnyOf<string, StringPattern>[] patterns,
|
||||||
SimMetricType simMetricType = SimMetricType.Levenstein,
|
SimMetricType simMetricType = SimMetricType.Levenstein,
|
||||||
MatchOperator matchOperator = MatchOperator.Average)
|
MatchOperator matchOperator = MatchOperator.Average)
|
||||||
{
|
{
|
||||||
_patterns = Guard.NotNull(patterns);
|
_patterns = Guard.NotNull(patterns);
|
||||||
_simMetricType = simMetricType;
|
_simMetricType = simMetricType;
|
||||||
MatchBehaviour = matchBehaviour;
|
MatchBehaviour = matchBehaviour;
|
||||||
MatchOperator = matchOperator;
|
MatchOperator = matchOperator;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public MatchResult IsMatch(string? input)
|
public MatchResult IsMatch(string? input)
|
||||||
{
|
{
|
||||||
IStringMetric stringMetricType = GetStringMetricType();
|
IStringMetric stringMetricType = GetStringMetricType();
|
||||||
|
|
||||||
var score = MatchScores.ToScore(_patterns.Select(p => stringMetricType.GetSimilarity(p.GetPattern(), input)).ToArray(), MatchOperator);
|
var score = MatchScores.ToScore(_patterns.Select(p => stringMetricType.GetSimilarity(p.GetPattern(), input)).ToArray(), MatchOperator);
|
||||||
return MatchBehaviourHelper.Convert(MatchBehaviour, score);
|
return MatchBehaviourHelper.Convert(MatchBehaviour, score);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public virtual string GetCSharpCodeArguments()
|
public virtual string GetCSharpCodeArguments()
|
||||||
{
|
{
|
||||||
return $"new {Name}" +
|
return $"new {Name}" +
|
||||||
$"(" +
|
$"(" +
|
||||||
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
|
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
|
||||||
$"{MappingConverterUtils.ToCSharpCodeArguments(_patterns)}, " +
|
$"{MappingConverterUtils.ToCSharpCodeArguments(_patterns)}, " +
|
||||||
$"{_simMetricType.GetFullyQualifiedEnumValue()}, " +
|
$"{_simMetricType.GetFullyQualifiedEnumValue()}, " +
|
||||||
$"{MatchOperator.GetFullyQualifiedEnumValue()}" +
|
$"{MatchOperator.GetFullyQualifiedEnumValue()}" +
|
||||||
$")";
|
$")";
|
||||||
}
|
}
|
||||||
|
|
||||||
private IStringMetric GetStringMetricType()
|
private IStringMetric GetStringMetricType()
|
||||||
{
|
{
|
||||||
return _simMetricType switch
|
return _simMetricType switch
|
||||||
{
|
{
|
||||||
SimMetricType.BlockDistance => new BlockDistance(),
|
SimMetricType.BlockDistance => new BlockDistance(),
|
||||||
SimMetricType.ChapmanLengthDeviation => new ChapmanLengthDeviation(),
|
SimMetricType.ChapmanLengthDeviation => new ChapmanLengthDeviation(),
|
||||||
SimMetricType.CosineSimilarity => new CosineSimilarity(),
|
SimMetricType.CosineSimilarity => new CosineSimilarity(),
|
||||||
SimMetricType.DiceSimilarity => new DiceSimilarity(),
|
SimMetricType.DiceSimilarity => new DiceSimilarity(),
|
||||||
SimMetricType.EuclideanDistance => new EuclideanDistance(),
|
SimMetricType.EuclideanDistance => new EuclideanDistance(),
|
||||||
SimMetricType.JaccardSimilarity => new JaccardSimilarity(),
|
SimMetricType.JaccardSimilarity => new JaccardSimilarity(),
|
||||||
SimMetricType.Jaro => new Jaro(),
|
SimMetricType.Jaro => new Jaro(),
|
||||||
SimMetricType.JaroWinkler => new JaroWinkler(),
|
SimMetricType.JaroWinkler => new JaroWinkler(),
|
||||||
SimMetricType.MatchingCoefficient => new MatchingCoefficient(),
|
SimMetricType.MatchingCoefficient => new MatchingCoefficient(),
|
||||||
SimMetricType.MongeElkan => new MongeElkan(),
|
SimMetricType.MongeElkan => new MongeElkan(),
|
||||||
SimMetricType.NeedlemanWunch => new NeedlemanWunch(),
|
SimMetricType.NeedlemanWunch => new NeedlemanWunch(),
|
||||||
SimMetricType.OverlapCoefficient => new OverlapCoefficient(),
|
SimMetricType.OverlapCoefficient => new OverlapCoefficient(),
|
||||||
SimMetricType.QGramsDistance => new QGramsDistance(),
|
SimMetricType.QGramsDistance => new QGramsDistance(),
|
||||||
SimMetricType.SmithWaterman => new SmithWaterman(),
|
SimMetricType.SmithWaterman => new SmithWaterman(),
|
||||||
SimMetricType.SmithWatermanGotoh => new SmithWatermanGotoh(),
|
SimMetricType.SmithWatermanGotoh => new SmithWatermanGotoh(),
|
||||||
SimMetricType.SmithWatermanGotohWindowedAffine => new SmithWatermanGotohWindowedAffine(),
|
SimMetricType.SmithWatermanGotohWindowedAffine => new SmithWatermanGotohWindowedAffine(),
|
||||||
SimMetricType.ChapmanMeanLength => new ChapmanMeanLength(),
|
SimMetricType.ChapmanMeanLength => new ChapmanMeanLength(),
|
||||||
_ => new Levenstein()
|
_ => new Levenstein()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public AnyOf<string, StringPattern>[] GetPatterns()
|
public AnyOf<string, StringPattern>[] GetPatterns()
|
||||||
{
|
{
|
||||||
return _patterns;
|
return _patterns;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public MatchOperator MatchOperator { get; } = MatchOperator.Average;
|
public MatchOperator MatchOperator { get; } = MatchOperator.Average;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string Name => $"SimMetricsMatcher.{_simMetricType}";
|
public string Name => $"SimMetricsMatcher.{_simMetricType}";
|
||||||
}
|
}
|
||||||
@@ -1,184 +1,184 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using System.Xml.XPath;
|
using System.Xml.XPath;
|
||||||
using AnyOfTypes;
|
using AnyOfTypes;
|
||||||
using WireMock.Extensions;
|
using WireMock.Extensions;
|
||||||
using WireMock.Models;
|
using WireMock.Models;
|
||||||
using Stef.Validation;
|
using Stef.Validation;
|
||||||
using WireMock.Admin.Mappings;
|
using WireMock.Admin.Mappings;
|
||||||
using WireMock.Util;
|
using WireMock.Util;
|
||||||
#if !NETSTANDARD1_3
|
#if !NETSTANDARD1_3
|
||||||
using Wmhelp.XPath2;
|
using Wmhelp.XPath2;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace WireMock.Matchers;
|
namespace WireMock.Matchers;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// XPath2Matcher
|
/// XPath2Matcher
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <seealso cref="IStringMatcher" />
|
/// <seealso cref="IStringMatcher" />
|
||||||
public class XPathMatcher : IStringMatcher
|
public class XPathMatcher : IStringMatcher
|
||||||
{
|
{
|
||||||
private readonly AnyOf<string, StringPattern>[] _patterns;
|
private readonly AnyOf<string, StringPattern>[] _patterns;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public MatchBehaviour MatchBehaviour { get; }
|
public MatchBehaviour MatchBehaviour { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Array of namespace prefix and uri.
|
/// Array of namespace prefix and uri.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public XmlNamespace[]? XmlNamespaceMap { get; private set; }
|
public XmlNamespace[]? XmlNamespaceMap { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="XPathMatcher"/> class.
|
/// Initializes a new instance of the <see cref="XPathMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="patterns">The patterns.</param>
|
/// <param name="patterns">The patterns.</param>
|
||||||
public XPathMatcher(params AnyOf<string, StringPattern>[] patterns) : this(MatchBehaviour.AcceptOnMatch, MatchOperator.Or, null, patterns)
|
public XPathMatcher(params AnyOf<string, StringPattern>[] patterns) : this(MatchBehaviour.AcceptOnMatch, MatchOperator.Or, null, patterns)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="XPathMatcher"/> class.
|
/// Initializes a new instance of the <see cref="XPathMatcher"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="matchBehaviour">The match behaviour.</param>
|
/// <param name="matchBehaviour">The match behaviour.</param>
|
||||||
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param>
|
/// <param name="matchOperator">The <see cref="Matchers.MatchOperator"/> to use. (default = "Or")</param>
|
||||||
/// <param name="xmlNamespaceMap">The xml namespaces of the xml document.</param>
|
/// <param name="xmlNamespaceMap">The xml namespaces of the xml document.</param>
|
||||||
/// <param name="patterns">The patterns.</param>
|
/// <param name="patterns">The patterns.</param>
|
||||||
public XPathMatcher(
|
public XPathMatcher(
|
||||||
MatchBehaviour matchBehaviour,
|
MatchBehaviour matchBehaviour,
|
||||||
MatchOperator matchOperator = MatchOperator.Or,
|
MatchOperator matchOperator = MatchOperator.Or,
|
||||||
XmlNamespace[]? xmlNamespaceMap = null,
|
XmlNamespace[]? xmlNamespaceMap = null,
|
||||||
params AnyOf<string, StringPattern>[] patterns)
|
params AnyOf<string, StringPattern>[] patterns)
|
||||||
{
|
{
|
||||||
_patterns = Guard.NotNull(patterns);
|
_patterns = Guard.NotNull(patterns);
|
||||||
XmlNamespaceMap = xmlNamespaceMap;
|
XmlNamespaceMap = xmlNamespaceMap;
|
||||||
MatchBehaviour = matchBehaviour;
|
MatchBehaviour = matchBehaviour;
|
||||||
MatchOperator = matchOperator;
|
MatchOperator = matchOperator;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public MatchResult IsMatch(string? input)
|
public MatchResult IsMatch(string? input)
|
||||||
{
|
{
|
||||||
var score = MatchScores.Mismatch;
|
var score = MatchScores.Mismatch;
|
||||||
|
|
||||||
if (input == null)
|
if (input == null)
|
||||||
{
|
{
|
||||||
return CreateMatchResult(score);
|
return CreateMatchResult(score);
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var xPathEvaluator = new XPathEvaluator();
|
var xPathEvaluator = new XPathEvaluator();
|
||||||
xPathEvaluator.Load(input);
|
xPathEvaluator.Load(input);
|
||||||
|
|
||||||
if (!xPathEvaluator.IsXmlDocumentLoaded)
|
if (!xPathEvaluator.IsXmlDocumentLoaded)
|
||||||
{
|
{
|
||||||
return CreateMatchResult(score);
|
return CreateMatchResult(score);
|
||||||
}
|
}
|
||||||
|
|
||||||
score = MatchScores.ToScore(xPathEvaluator.Evaluate(_patterns, XmlNamespaceMap), MatchOperator);
|
score = MatchScores.ToScore(xPathEvaluator.Evaluate(_patterns, XmlNamespaceMap), MatchOperator);
|
||||||
}
|
}
|
||||||
catch (Exception exception)
|
catch (Exception exception)
|
||||||
{
|
{
|
||||||
return CreateMatchResult(score, exception);
|
return CreateMatchResult(score, exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
return CreateMatchResult(score);
|
return CreateMatchResult(score);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public AnyOf<string, StringPattern>[] GetPatterns()
|
public AnyOf<string, StringPattern>[] GetPatterns()
|
||||||
{
|
{
|
||||||
return _patterns;
|
return _patterns;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public MatchOperator MatchOperator { get; }
|
public MatchOperator MatchOperator { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string Name => nameof(XPathMatcher);
|
public string Name => nameof(XPathMatcher);
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string GetCSharpCodeArguments()
|
public string GetCSharpCodeArguments()
|
||||||
{
|
{
|
||||||
return $"new {Name}" +
|
return $"new {Name}" +
|
||||||
$"(" +
|
$"(" +
|
||||||
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
|
$"{MatchBehaviour.GetFullyQualifiedEnumValue()}, " +
|
||||||
$"{MatchOperator.GetFullyQualifiedEnumValue()}, " +
|
$"{MatchOperator.GetFullyQualifiedEnumValue()}, " +
|
||||||
$"null, " +
|
$"null, " +
|
||||||
$"{MappingConverterUtils.ToCSharpCodeArguments(_patterns)}" +
|
$"{MappingConverterUtils.ToCSharpCodeArguments(_patterns)}" +
|
||||||
$")";
|
$")";
|
||||||
}
|
}
|
||||||
|
|
||||||
private MatchResult CreateMatchResult(double score, Exception? exception = null)
|
private MatchResult CreateMatchResult(double score, Exception? exception = null)
|
||||||
{
|
{
|
||||||
return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score), exception);
|
return new MatchResult(MatchBehaviourHelper.Convert(MatchBehaviour, score), exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
private sealed class XPathEvaluator
|
private sealed class XPathEvaluator
|
||||||
{
|
{
|
||||||
private XmlDocument? _xmlDocument;
|
private XmlDocument? _xmlDocument;
|
||||||
private XPathNavigator? _xpathNavigator;
|
private XPathNavigator? _xpathNavigator;
|
||||||
|
|
||||||
public bool IsXmlDocumentLoaded => _xmlDocument != null;
|
public bool IsXmlDocumentLoaded => _xmlDocument != null;
|
||||||
|
|
||||||
public void Load(string input)
|
public void Load(string input)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_xmlDocument = new XmlDocument { InnerXml = input };
|
_xmlDocument = new XmlDocument { InnerXml = input };
|
||||||
_xpathNavigator = _xmlDocument.CreateNavigator();
|
_xpathNavigator = _xmlDocument.CreateNavigator();
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
_xmlDocument = default;
|
_xmlDocument = default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool[] Evaluate(AnyOf<string, StringPattern>[] patterns, IEnumerable<XmlNamespace>? xmlNamespaceMap)
|
public bool[] Evaluate(AnyOf<string, StringPattern>[] patterns, IEnumerable<XmlNamespace>? xmlNamespaceMap)
|
||||||
{
|
{
|
||||||
return _xpathNavigator == null ? [] : patterns.Select(pattern => true.Equals(Evaluate(_xpathNavigator, pattern, xmlNamespaceMap))).ToArray();
|
return _xpathNavigator == null ? [] : patterns.Select(pattern => true.Equals(Evaluate(_xpathNavigator, pattern, xmlNamespaceMap))).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
private object Evaluate(XPathNavigator navigator, AnyOf<string, StringPattern> pattern, IEnumerable<XmlNamespace>? xmlNamespaceMap)
|
private object Evaluate(XPathNavigator navigator, AnyOf<string, StringPattern> pattern, IEnumerable<XmlNamespace>? xmlNamespaceMap)
|
||||||
{
|
{
|
||||||
var xpath = $"boolean({pattern.GetPattern()})";
|
var xpath = $"boolean({pattern.GetPattern()})";
|
||||||
|
|
||||||
var xmlNamespaceManager = GetXmlNamespaceManager(xmlNamespaceMap);
|
var xmlNamespaceManager = GetXmlNamespaceManager(xmlNamespaceMap);
|
||||||
if (xmlNamespaceManager == null)
|
if (xmlNamespaceManager == null)
|
||||||
{
|
{
|
||||||
#if NETSTANDARD1_3
|
#if NETSTANDARD1_3
|
||||||
return navigator.Evaluate(xpath);
|
return navigator.Evaluate(xpath);
|
||||||
#else
|
#else
|
||||||
return navigator.XPath2Evaluate(xpath);
|
return navigator.XPath2Evaluate(xpath);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if NETSTANDARD1_3
|
#if NETSTANDARD1_3
|
||||||
return navigator.Evaluate(xpath, xmlNamespaceManager);
|
return navigator.Evaluate(xpath, xmlNamespaceManager);
|
||||||
#else
|
#else
|
||||||
return navigator.XPath2Evaluate(xpath, xmlNamespaceManager);
|
return navigator.XPath2Evaluate(xpath, xmlNamespaceManager);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
private XmlNamespaceManager? GetXmlNamespaceManager(IEnumerable<XmlNamespace>? xmlNamespaceMap)
|
private XmlNamespaceManager? GetXmlNamespaceManager(IEnumerable<XmlNamespace>? xmlNamespaceMap)
|
||||||
{
|
{
|
||||||
if (_xpathNavigator == null || xmlNamespaceMap == null)
|
if (_xpathNavigator == null || xmlNamespaceMap == null)
|
||||||
{
|
{
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
|
|
||||||
var nsManager = new XmlNamespaceManager(_xpathNavigator.NameTable);
|
var nsManager = new XmlNamespaceManager(_xpathNavigator.NameTable);
|
||||||
foreach (var xmlNamespace in xmlNamespaceMap)
|
foreach (var xmlNamespace in xmlNamespaceMap)
|
||||||
{
|
{
|
||||||
nsManager.AddNamespace(xmlNamespace.Prefix, xmlNamespace.Uri);
|
nsManager.AddNamespace(xmlNamespace.Prefix, xmlNamespace.Uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
return nsManager;
|
return nsManager;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
namespace WireMock.Models;
|
namespace WireMock.Models;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Webhook
|
/// Webhook
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Webhook : IWebhook
|
public class Webhook : IWebhook
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IWebhookRequest Request { get; set; } = null!;
|
public IWebhookRequest Request { get; set; } = null!;
|
||||||
}
|
}
|
||||||
@@ -1,43 +1,43 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using WireMock.Types;
|
using WireMock.Types;
|
||||||
using WireMock.Util;
|
using WireMock.Util;
|
||||||
|
|
||||||
namespace WireMock.Models;
|
namespace WireMock.Models;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// WebhookRequest
|
/// WebhookRequest
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class WebhookRequest : IWebhookRequest
|
public class WebhookRequest : IWebhookRequest
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string Url { get; set; } = null!;
|
public string Url { get; set; } = null!;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string Method { get; set; } = null!;
|
public string Method { get; set; } = null!;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IDictionary<string, WireMockList<string>>? Headers { get; set; }
|
public IDictionary<string, WireMockList<string>>? Headers { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IBodyData? BodyData { get; set; }
|
public IBodyData? BodyData { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public bool? UseTransformer { get; set; }
|
public bool? UseTransformer { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public TransformerType TransformerType { get; set; }
|
public TransformerType TransformerType { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public ReplaceNodeOptions TransformerReplaceNodeOptions { get; set; }
|
public ReplaceNodeOptions TransformerReplaceNodeOptions { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public int? Delay { get; set; }
|
public int? Delay { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public int? MinimumRandomDelay { get; set; }
|
public int? MinimumRandomDelay { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public int? MaximumRandomDelay { get; set; }
|
public int? MaximumRandomDelay { get; set; }
|
||||||
}
|
}
|
||||||
@@ -1,123 +1,123 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
#if USE_ASPNETCORE && !NETSTANDARD1_3
|
#if USE_ASPNETCORE && !NETSTANDARD1_3
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Core;
|
using Microsoft.AspNetCore.Server.Kestrel.Core;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Https;
|
using Microsoft.AspNetCore.Server.Kestrel.Https;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using CertificateLoader = WireMock.HttpsCertificate.CertificateLoader;
|
using CertificateLoader = WireMock.HttpsCertificate.CertificateLoader;
|
||||||
|
|
||||||
namespace WireMock.Owin
|
namespace WireMock.Owin
|
||||||
{
|
{
|
||||||
internal partial class AspNetCoreSelfHost
|
internal partial class AspNetCoreSelfHost
|
||||||
{
|
{
|
||||||
private static void SetKestrelOptionsLimits(KestrelServerOptions options)
|
private static void SetKestrelOptionsLimits(KestrelServerOptions options)
|
||||||
{
|
{
|
||||||
options.Limits.MaxRequestBodySize = null; // https://stackoverflow.com/questions/46738364/increase-upload-request-length-limit-in-kestrel
|
options.Limits.MaxRequestBodySize = null; // https://stackoverflow.com/questions/46738364/increase-upload-request-length-limit-in-kestrel
|
||||||
options.Limits.MaxRequestBufferSize = null;
|
options.Limits.MaxRequestBufferSize = null;
|
||||||
options.Limits.MaxRequestHeaderCount = 100;
|
options.Limits.MaxRequestHeaderCount = 100;
|
||||||
options.Limits.MaxResponseBufferSize = null;
|
options.Limits.MaxResponseBufferSize = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void SetHttpsAndUrls(KestrelServerOptions kestrelOptions, IWireMockMiddlewareOptions wireMockMiddlewareOptions, IEnumerable<HostUrlDetails> urlDetails)
|
private static void SetHttpsAndUrls(KestrelServerOptions kestrelOptions, IWireMockMiddlewareOptions wireMockMiddlewareOptions, IEnumerable<HostUrlDetails> urlDetails)
|
||||||
{
|
{
|
||||||
foreach (var urlDetail in urlDetails)
|
foreach (var urlDetail in urlDetails)
|
||||||
{
|
{
|
||||||
if (urlDetail.IsHttps)
|
if (urlDetail.IsHttps)
|
||||||
{
|
{
|
||||||
Listen(kestrelOptions, urlDetail, listenOptions =>
|
Listen(kestrelOptions, urlDetail, listenOptions =>
|
||||||
{
|
{
|
||||||
listenOptions.UseHttps(options =>
|
listenOptions.UseHttps(options =>
|
||||||
{
|
{
|
||||||
if (wireMockMiddlewareOptions.CustomCertificateDefined)
|
if (wireMockMiddlewareOptions.CustomCertificateDefined)
|
||||||
{
|
{
|
||||||
options.ServerCertificate = CertificateLoader.LoadCertificate(
|
options.ServerCertificate = CertificateLoader.LoadCertificate(
|
||||||
wireMockMiddlewareOptions.X509StoreName,
|
wireMockMiddlewareOptions.X509StoreName,
|
||||||
wireMockMiddlewareOptions.X509StoreLocation,
|
wireMockMiddlewareOptions.X509StoreLocation,
|
||||||
wireMockMiddlewareOptions.X509ThumbprintOrSubjectName,
|
wireMockMiddlewareOptions.X509ThumbprintOrSubjectName,
|
||||||
wireMockMiddlewareOptions.X509CertificateFilePath,
|
wireMockMiddlewareOptions.X509CertificateFilePath,
|
||||||
wireMockMiddlewareOptions.X509CertificatePassword,
|
wireMockMiddlewareOptions.X509CertificatePassword,
|
||||||
urlDetail.Host
|
urlDetail.Host
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
options.ClientCertificateMode = (ClientCertificateMode)wireMockMiddlewareOptions.ClientCertificateMode;
|
options.ClientCertificateMode = (ClientCertificateMode)wireMockMiddlewareOptions.ClientCertificateMode;
|
||||||
if (wireMockMiddlewareOptions.AcceptAnyClientCertificate)
|
if (wireMockMiddlewareOptions.AcceptAnyClientCertificate)
|
||||||
{
|
{
|
||||||
options.ClientCertificateValidation = (_, _, _) => true;
|
options.ClientCertificateValidation = (_, _, _) => true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (urlDetail.IsHttp2)
|
if (urlDetail.IsHttp2)
|
||||||
{
|
{
|
||||||
listenOptions.Protocols = HttpProtocols.Http2;
|
listenOptions.Protocols = HttpProtocols.Http2;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (urlDetail.IsHttp2)
|
if (urlDetail.IsHttp2)
|
||||||
{
|
{
|
||||||
Listen(kestrelOptions, urlDetail, listenOptions =>
|
Listen(kestrelOptions, urlDetail, listenOptions =>
|
||||||
{
|
{
|
||||||
listenOptions.Protocols = HttpProtocols.Http2;
|
listenOptions.Protocols = HttpProtocols.Http2;
|
||||||
});
|
});
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Listen(kestrelOptions, urlDetail, _ => { });
|
Listen(kestrelOptions, urlDetail, _ => { });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void Listen(KestrelServerOptions kestrelOptions, HostUrlDetails urlDetail, Action<ListenOptions> configure)
|
private static void Listen(KestrelServerOptions kestrelOptions, HostUrlDetails urlDetail, Action<ListenOptions> configure)
|
||||||
{
|
{
|
||||||
// Listens on any IP with the given port.
|
// Listens on any IP with the given port.
|
||||||
if (urlDetail is { Port: > 0, Host: "0.0.0.0" })
|
if (urlDetail is { Port: > 0, Host: "0.0.0.0" })
|
||||||
{
|
{
|
||||||
kestrelOptions.ListenAnyIP(urlDetail.Port, configure);
|
kestrelOptions.ListenAnyIP(urlDetail.Port, configure);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Listens on ::1 and 127.0.0.1 with the given port.
|
// Listens on ::1 and 127.0.0.1 with the given port.
|
||||||
if (urlDetail is { Port: > 0, Host: "localhost" or "127.0.0.1" or "::1" })
|
if (urlDetail is { Port: > 0, Host: "localhost" or "127.0.0.1" or "::1" })
|
||||||
{
|
{
|
||||||
kestrelOptions.ListenLocalhost(urlDetail.Port, configure);
|
kestrelOptions.ListenLocalhost(urlDetail.Port, configure);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to parse the host as a valid IP address and bind to the given IP address and port.
|
// Try to parse the host as a valid IP address and bind to the given IP address and port.
|
||||||
if (IPAddress.TryParse(urlDetail.Host, out var ipAddress))
|
if (IPAddress.TryParse(urlDetail.Host, out var ipAddress))
|
||||||
{
|
{
|
||||||
kestrelOptions.Listen(ipAddress, urlDetail.Port, configure);
|
kestrelOptions.Listen(ipAddress, urlDetail.Port, configure);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, listen on all IPs.
|
// Otherwise, listen on all IPs.
|
||||||
kestrelOptions.ListenAnyIP(urlDetail.Port, configure);
|
kestrelOptions.ListenAnyIP(urlDetail.Port, configure);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static class IWebHostBuilderExtensions
|
internal static class IWebHostBuilderExtensions
|
||||||
{
|
{
|
||||||
internal static IWebHostBuilder ConfigureAppConfigurationUsingEnvironmentVariables(this IWebHostBuilder builder)
|
internal static IWebHostBuilder ConfigureAppConfigurationUsingEnvironmentVariables(this IWebHostBuilder builder)
|
||||||
{
|
{
|
||||||
return builder.ConfigureAppConfiguration(config =>
|
return builder.ConfigureAppConfiguration(config =>
|
||||||
{
|
{
|
||||||
config.AddEnvironmentVariables();
|
config.AddEnvironmentVariables();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static IWebHostBuilder ConfigureKestrelServerOptions(this IWebHostBuilder builder)
|
internal static IWebHostBuilder ConfigureKestrelServerOptions(this IWebHostBuilder builder)
|
||||||
{
|
{
|
||||||
return builder.ConfigureServices((context, services) =>
|
return builder.ConfigureServices((context, services) =>
|
||||||
{
|
{
|
||||||
services.Configure<KestrelServerOptions>(context.Configuration.GetSection("Kestrel"));
|
services.Configure<KestrelServerOptions>(context.Configuration.GetSection("Kestrel"));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -1,67 +1,67 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
#if USE_ASPNETCORE && NETSTANDARD1_3
|
#if USE_ASPNETCORE && NETSTANDARD1_3
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel;
|
using Microsoft.AspNetCore.Server.Kestrel;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Https;
|
using Microsoft.AspNetCore.Server.Kestrel.Https;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using WireMock.HttpsCertificate;
|
using WireMock.HttpsCertificate;
|
||||||
|
|
||||||
namespace WireMock.Owin;
|
namespace WireMock.Owin;
|
||||||
|
|
||||||
internal partial class AspNetCoreSelfHost
|
internal partial class AspNetCoreSelfHost
|
||||||
{
|
{
|
||||||
private static void SetKestrelOptionsLimits(KestrelServerOptions options)
|
private static void SetKestrelOptionsLimits(KestrelServerOptions options)
|
||||||
{
|
{
|
||||||
options.Limits.MaxRequestBufferSize = null;
|
options.Limits.MaxRequestBufferSize = null;
|
||||||
options.Limits.MaxRequestHeaderCount = 100;
|
options.Limits.MaxRequestHeaderCount = 100;
|
||||||
options.Limits.MaxResponseBufferSize = null;
|
options.Limits.MaxResponseBufferSize = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void SetHttpsAndUrls(KestrelServerOptions options, IWireMockMiddlewareOptions wireMockMiddlewareOptions, IEnumerable<HostUrlDetails> urlDetails)
|
private static void SetHttpsAndUrls(KestrelServerOptions options, IWireMockMiddlewareOptions wireMockMiddlewareOptions, IEnumerable<HostUrlDetails> urlDetails)
|
||||||
{
|
{
|
||||||
foreach (var urlDetail in urlDetails)
|
foreach (var urlDetail in urlDetails)
|
||||||
{
|
{
|
||||||
if (urlDetail.IsHttps)
|
if (urlDetail.IsHttps)
|
||||||
{
|
{
|
||||||
options.UseHttps(new HttpsConnectionFilterOptions
|
options.UseHttps(new HttpsConnectionFilterOptions
|
||||||
{
|
{
|
||||||
ServerCertificate = wireMockMiddlewareOptions.CustomCertificateDefined
|
ServerCertificate = wireMockMiddlewareOptions.CustomCertificateDefined
|
||||||
? CertificateLoader.LoadCertificate(
|
? CertificateLoader.LoadCertificate(
|
||||||
wireMockMiddlewareOptions.X509StoreName,
|
wireMockMiddlewareOptions.X509StoreName,
|
||||||
wireMockMiddlewareOptions.X509StoreLocation,
|
wireMockMiddlewareOptions.X509StoreLocation,
|
||||||
wireMockMiddlewareOptions.X509ThumbprintOrSubjectName,
|
wireMockMiddlewareOptions.X509ThumbprintOrSubjectName,
|
||||||
wireMockMiddlewareOptions.X509CertificateFilePath,
|
wireMockMiddlewareOptions.X509CertificateFilePath,
|
||||||
wireMockMiddlewareOptions.X509CertificatePassword,
|
wireMockMiddlewareOptions.X509CertificatePassword,
|
||||||
urlDetail.Host)
|
urlDetail.Host)
|
||||||
: PublicCertificateHelper.GetX509Certificate2(),
|
: PublicCertificateHelper.GetX509Certificate2(),
|
||||||
ClientCertificateMode = (ClientCertificateMode) wireMockMiddlewareOptions.ClientCertificateMode,
|
ClientCertificateMode = (ClientCertificateMode) wireMockMiddlewareOptions.ClientCertificateMode,
|
||||||
ClientCertificateValidation = wireMockMiddlewareOptions.AcceptAnyClientCertificate
|
ClientCertificateValidation = wireMockMiddlewareOptions.AcceptAnyClientCertificate
|
||||||
? (_, _, _) => true
|
? (_, _, _) => true
|
||||||
: null,
|
: null,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static class IWebHostBuilderExtensions
|
internal static class IWebHostBuilderExtensions
|
||||||
{
|
{
|
||||||
internal static IWebHostBuilder ConfigureAppConfigurationUsingEnvironmentVariables(this IWebHostBuilder builder) => builder;
|
internal static IWebHostBuilder ConfigureAppConfigurationUsingEnvironmentVariables(this IWebHostBuilder builder) => builder;
|
||||||
|
|
||||||
internal static IWebHostBuilder ConfigureKestrelServerOptions(this IWebHostBuilder builder)
|
internal static IWebHostBuilder ConfigureKestrelServerOptions(this IWebHostBuilder builder)
|
||||||
{
|
{
|
||||||
var configuration = new ConfigurationBuilder()
|
var configuration = new ConfigurationBuilder()
|
||||||
.AddEnvironmentVariables()
|
.AddEnvironmentVariables()
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
return builder.ConfigureServices(services =>
|
return builder.ConfigureServices(services =>
|
||||||
{
|
{
|
||||||
services.Configure<KestrelServerOptions>(configuration.GetSection("Kestrel"));
|
services.Configure<KestrelServerOptions>(configuration.GetSection("Kestrel"));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,189 +1,189 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
#if USE_ASPNETCORE
|
#if USE_ASPNETCORE
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Stef.Validation;
|
using Stef.Validation;
|
||||||
using WireMock.Logging;
|
using WireMock.Logging;
|
||||||
using WireMock.Owin.Mappers;
|
using WireMock.Owin.Mappers;
|
||||||
using WireMock.Services;
|
using WireMock.Services;
|
||||||
using WireMock.Util;
|
using WireMock.Util;
|
||||||
|
|
||||||
namespace WireMock.Owin;
|
namespace WireMock.Owin;
|
||||||
|
|
||||||
internal partial class AspNetCoreSelfHost : IOwinSelfHost
|
internal partial class AspNetCoreSelfHost : IOwinSelfHost
|
||||||
{
|
{
|
||||||
private const string CorsPolicyName = "WireMock.Net - Policy";
|
private const string CorsPolicyName = "WireMock.Net - Policy";
|
||||||
|
|
||||||
private readonly CancellationTokenSource _cts = new();
|
private readonly CancellationTokenSource _cts = new();
|
||||||
private readonly IWireMockMiddlewareOptions _wireMockMiddlewareOptions;
|
private readonly IWireMockMiddlewareOptions _wireMockMiddlewareOptions;
|
||||||
private readonly IWireMockLogger _logger;
|
private readonly IWireMockLogger _logger;
|
||||||
private readonly HostUrlOptions _urlOptions;
|
private readonly HostUrlOptions _urlOptions;
|
||||||
|
|
||||||
private Exception _runningException;
|
private Exception _runningException;
|
||||||
private IWebHost _host;
|
private IWebHost _host;
|
||||||
|
|
||||||
public bool IsStarted { get; private set; }
|
public bool IsStarted { get; private set; }
|
||||||
|
|
||||||
public List<string> Urls { get; } = new();
|
public List<string> Urls { get; } = new();
|
||||||
|
|
||||||
public List<int> Ports { get; } = new();
|
public List<int> Ports { get; } = new();
|
||||||
|
|
||||||
public Exception RunningException => _runningException;
|
public Exception RunningException => _runningException;
|
||||||
|
|
||||||
public AspNetCoreSelfHost(IWireMockMiddlewareOptions wireMockMiddlewareOptions, HostUrlOptions urlOptions)
|
public AspNetCoreSelfHost(IWireMockMiddlewareOptions wireMockMiddlewareOptions, HostUrlOptions urlOptions)
|
||||||
{
|
{
|
||||||
Guard.NotNull(wireMockMiddlewareOptions);
|
Guard.NotNull(wireMockMiddlewareOptions);
|
||||||
Guard.NotNull(urlOptions);
|
Guard.NotNull(urlOptions);
|
||||||
|
|
||||||
_logger = wireMockMiddlewareOptions.Logger ?? new WireMockConsoleLogger();
|
_logger = wireMockMiddlewareOptions.Logger ?? new WireMockConsoleLogger();
|
||||||
|
|
||||||
_wireMockMiddlewareOptions = wireMockMiddlewareOptions;
|
_wireMockMiddlewareOptions = wireMockMiddlewareOptions;
|
||||||
_urlOptions = urlOptions;
|
_urlOptions = urlOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task StartAsync()
|
public Task StartAsync()
|
||||||
{
|
{
|
||||||
var builder = new WebHostBuilder();
|
var builder = new WebHostBuilder();
|
||||||
|
|
||||||
// Workaround for https://github.com/wiremock/WireMock.Net/issues/292
|
// Workaround for https://github.com/wiremock/WireMock.Net/issues/292
|
||||||
// On some platforms, AppContext.BaseDirectory is null, which causes WebHostBuilder to fail if ContentRoot is not
|
// On some platforms, AppContext.BaseDirectory is null, which causes WebHostBuilder to fail if ContentRoot is not
|
||||||
// specified (even though we don't actually use that base path mechanism, since we have our own way of configuring
|
// specified (even though we don't actually use that base path mechanism, since we have our own way of configuring
|
||||||
// a filesystem handler).
|
// a filesystem handler).
|
||||||
if (string.IsNullOrEmpty(AppContext.BaseDirectory))
|
if (string.IsNullOrEmpty(AppContext.BaseDirectory))
|
||||||
{
|
{
|
||||||
builder.UseContentRoot(Directory.GetCurrentDirectory());
|
builder.UseContentRoot(Directory.GetCurrentDirectory());
|
||||||
}
|
}
|
||||||
|
|
||||||
_host = builder
|
_host = builder
|
||||||
.UseSetting("suppressStatusMessages", "True") // https://andrewlock.net/suppressing-the-startup-and-shutdown-messages-in-asp-net-core/
|
.UseSetting("suppressStatusMessages", "True") // https://andrewlock.net/suppressing-the-startup-and-shutdown-messages-in-asp-net-core/
|
||||||
.ConfigureAppConfigurationUsingEnvironmentVariables()
|
.ConfigureAppConfigurationUsingEnvironmentVariables()
|
||||||
.ConfigureServices(services =>
|
.ConfigureServices(services =>
|
||||||
{
|
{
|
||||||
services.AddSingleton(_wireMockMiddlewareOptions);
|
services.AddSingleton(_wireMockMiddlewareOptions);
|
||||||
services.AddSingleton<IMappingMatcher, MappingMatcher>();
|
services.AddSingleton<IMappingMatcher, MappingMatcher>();
|
||||||
services.AddSingleton<IRandomizerDoubleBetween0And1, RandomizerDoubleBetween0And1>();
|
services.AddSingleton<IRandomizerDoubleBetween0And1, RandomizerDoubleBetween0And1>();
|
||||||
services.AddSingleton<IOwinRequestMapper, OwinRequestMapper>();
|
services.AddSingleton<IOwinRequestMapper, OwinRequestMapper>();
|
||||||
services.AddSingleton<IOwinResponseMapper, OwinResponseMapper>();
|
services.AddSingleton<IOwinResponseMapper, OwinResponseMapper>();
|
||||||
services.AddSingleton<IGuidUtils, GuidUtils>();
|
services.AddSingleton<IGuidUtils, GuidUtils>();
|
||||||
|
|
||||||
#if NETCOREAPP3_1 || NET5_0_OR_GREATER
|
#if NETCOREAPP3_1 || NET5_0_OR_GREATER
|
||||||
AddCors(services);
|
AddCors(services);
|
||||||
#endif
|
#endif
|
||||||
_wireMockMiddlewareOptions.AdditionalServiceRegistration?.Invoke(services);
|
_wireMockMiddlewareOptions.AdditionalServiceRegistration?.Invoke(services);
|
||||||
})
|
})
|
||||||
.Configure(appBuilder =>
|
.Configure(appBuilder =>
|
||||||
{
|
{
|
||||||
appBuilder.UseMiddleware<GlobalExceptionMiddleware>();
|
appBuilder.UseMiddleware<GlobalExceptionMiddleware>();
|
||||||
|
|
||||||
#if NETCOREAPP3_1 || NET5_0_OR_GREATER
|
#if NETCOREAPP3_1 || NET5_0_OR_GREATER
|
||||||
UseCors(appBuilder);
|
UseCors(appBuilder);
|
||||||
#endif
|
#endif
|
||||||
_wireMockMiddlewareOptions.PreWireMockMiddlewareInit?.Invoke(appBuilder);
|
_wireMockMiddlewareOptions.PreWireMockMiddlewareInit?.Invoke(appBuilder);
|
||||||
|
|
||||||
appBuilder.UseMiddleware<WireMockMiddleware>();
|
appBuilder.UseMiddleware<WireMockMiddleware>();
|
||||||
|
|
||||||
_wireMockMiddlewareOptions.PostWireMockMiddlewareInit?.Invoke(appBuilder);
|
_wireMockMiddlewareOptions.PostWireMockMiddlewareInit?.Invoke(appBuilder);
|
||||||
})
|
})
|
||||||
.UseKestrel(options =>
|
.UseKestrel(options =>
|
||||||
{
|
{
|
||||||
SetKestrelOptionsLimits(options);
|
SetKestrelOptionsLimits(options);
|
||||||
|
|
||||||
SetHttpsAndUrls(options, _wireMockMiddlewareOptions, _urlOptions.GetDetails());
|
SetHttpsAndUrls(options, _wireMockMiddlewareOptions, _urlOptions.GetDetails());
|
||||||
})
|
})
|
||||||
.ConfigureKestrelServerOptions()
|
.ConfigureKestrelServerOptions()
|
||||||
|
|
||||||
#if NETSTANDARD1_3
|
#if NETSTANDARD1_3
|
||||||
.UseUrls(_urlOptions.GetDetails().Select(u => u.Url).ToArray())
|
.UseUrls(_urlOptions.GetDetails().Select(u => u.Url).ToArray())
|
||||||
#endif
|
#endif
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
return RunHost(_cts.Token);
|
return RunHost(_cts.Token);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task RunHost(CancellationToken token)
|
private Task RunHost(CancellationToken token)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
#if NETCOREAPP3_1 || NET5_0_OR_GREATER
|
#if NETCOREAPP3_1 || NET5_0_OR_GREATER
|
||||||
var appLifetime = _host.Services.GetRequiredService<Microsoft.Extensions.Hosting.IHostApplicationLifetime>();
|
var appLifetime = _host.Services.GetRequiredService<Microsoft.Extensions.Hosting.IHostApplicationLifetime>();
|
||||||
#else
|
#else
|
||||||
var appLifetime = _host.Services.GetRequiredService<IApplicationLifetime>();
|
var appLifetime = _host.Services.GetRequiredService<IApplicationLifetime>();
|
||||||
#endif
|
#endif
|
||||||
appLifetime.ApplicationStarted.Register(() =>
|
appLifetime.ApplicationStarted.Register(() =>
|
||||||
{
|
{
|
||||||
var addresses = _host.ServerFeatures
|
var addresses = _host.ServerFeatures
|
||||||
.Get<Microsoft.AspNetCore.Hosting.Server.Features.IServerAddressesFeature>()!
|
.Get<Microsoft.AspNetCore.Hosting.Server.Features.IServerAddressesFeature>()!
|
||||||
.Addresses;
|
.Addresses;
|
||||||
|
|
||||||
foreach (var address in addresses)
|
foreach (var address in addresses)
|
||||||
{
|
{
|
||||||
Urls.Add(address.Replace("0.0.0.0", "localhost").Replace("[::]", "localhost"));
|
Urls.Add(address.Replace("0.0.0.0", "localhost").Replace("[::]", "localhost"));
|
||||||
|
|
||||||
PortUtils.TryExtract(address, out _, out _, out _, out _, out var port);
|
PortUtils.TryExtract(address, out _, out _, out _, out _, out var port);
|
||||||
Ports.Add(port);
|
Ports.Add(port);
|
||||||
}
|
}
|
||||||
|
|
||||||
IsStarted = true;
|
IsStarted = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
#if NETSTANDARD1_3
|
#if NETSTANDARD1_3
|
||||||
_logger.Info("Server using netstandard1.3");
|
_logger.Info("Server using netstandard1.3");
|
||||||
#elif NETSTANDARD2_0
|
#elif NETSTANDARD2_0
|
||||||
_logger.Info("Server using netstandard2.0");
|
_logger.Info("Server using netstandard2.0");
|
||||||
#elif NETSTANDARD2_1
|
#elif NETSTANDARD2_1
|
||||||
_logger.Info("Server using netstandard2.1");
|
_logger.Info("Server using netstandard2.1");
|
||||||
#elif NETCOREAPP3_1
|
#elif NETCOREAPP3_1
|
||||||
_logger.Info("Server using .NET Core App 3.1");
|
_logger.Info("Server using .NET Core App 3.1");
|
||||||
#elif NET5_0
|
#elif NET5_0
|
||||||
_logger.Info("Server using .NET 5.0");
|
_logger.Info("Server using .NET 5.0");
|
||||||
#elif NET6_0
|
#elif NET6_0
|
||||||
_logger.Info("Server using .NET 6.0");
|
_logger.Info("Server using .NET 6.0");
|
||||||
#elif NET7_0
|
#elif NET7_0
|
||||||
_logger.Info("Server using .NET 7.0");
|
_logger.Info("Server using .NET 7.0");
|
||||||
#elif NET8_0
|
#elif NET8_0
|
||||||
_logger.Info("Server using .NET 8.0");
|
_logger.Info("Server using .NET 8.0");
|
||||||
#elif NET46
|
#elif NET46
|
||||||
_logger.Info("Server using .NET Framework 4.6.1 or higher");
|
_logger.Info("Server using .NET Framework 4.6.1 or higher");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if NETSTANDARD1_3
|
#if NETSTANDARD1_3
|
||||||
return Task.Run(() =>
|
return Task.Run(() =>
|
||||||
{
|
{
|
||||||
_host.Run(token);
|
_host.Run(token);
|
||||||
});
|
});
|
||||||
#else
|
#else
|
||||||
return _host.RunAsync(token);
|
return _host.RunAsync(token);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
_runningException = e;
|
_runningException = e;
|
||||||
_logger.Error(e.ToString());
|
_logger.Error(e.ToString());
|
||||||
|
|
||||||
IsStarted = false;
|
IsStarted = false;
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task StopAsync()
|
public Task StopAsync()
|
||||||
{
|
{
|
||||||
_cts.Cancel();
|
_cts.Cancel();
|
||||||
|
|
||||||
IsStarted = false;
|
IsStarted = false;
|
||||||
#if NETSTANDARD1_3
|
#if NETSTANDARD1_3
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
#else
|
#else
|
||||||
return _host.StopAsync();
|
return _host.StopAsync();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -1,64 +1,64 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using WireMock.Types;
|
using WireMock.Types;
|
||||||
using WireMock.Util;
|
using WireMock.Util;
|
||||||
|
|
||||||
namespace WireMock.Owin;
|
namespace WireMock.Owin;
|
||||||
|
|
||||||
internal class HostUrlOptions
|
internal class HostUrlOptions
|
||||||
{
|
{
|
||||||
private const string Star = "*";
|
private const string Star = "*";
|
||||||
|
|
||||||
public ICollection<string>? Urls { get; set; }
|
public ICollection<string>? Urls { get; set; }
|
||||||
|
|
||||||
public int? Port { get; set; }
|
public int? Port { get; set; }
|
||||||
|
|
||||||
public HostingScheme HostingScheme { get; set; }
|
public HostingScheme HostingScheme { get; set; }
|
||||||
|
|
||||||
public bool? UseHttp2 { get; set; }
|
public bool? UseHttp2 { get; set; }
|
||||||
|
|
||||||
public IReadOnlyList<HostUrlDetails> GetDetails()
|
public IReadOnlyList<HostUrlDetails> GetDetails()
|
||||||
{
|
{
|
||||||
var list = new List<HostUrlDetails>();
|
var list = new List<HostUrlDetails>();
|
||||||
if (Urls == null)
|
if (Urls == null)
|
||||||
{
|
{
|
||||||
if (HostingScheme is HostingScheme.Http or HostingScheme.Https)
|
if (HostingScheme is HostingScheme.Http or HostingScheme.Https)
|
||||||
{
|
{
|
||||||
var port = Port > 0 ? Port.Value : FindFreeTcpPort();
|
var port = Port > 0 ? Port.Value : FindFreeTcpPort();
|
||||||
var scheme = HostingScheme == HostingScheme.Https ? "https" : "http";
|
var scheme = HostingScheme == HostingScheme.Https ? "https" : "http";
|
||||||
list.Add(new HostUrlDetails { IsHttps = HostingScheme == HostingScheme.Https, IsHttp2 = UseHttp2 == true, Url = $"{scheme}://{Star}:{port}", Scheme = scheme, Host = Star, Port = port });
|
list.Add(new HostUrlDetails { IsHttps = HostingScheme == HostingScheme.Https, IsHttp2 = UseHttp2 == true, Url = $"{scheme}://{Star}:{port}", Scheme = scheme, Host = Star, Port = port });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HostingScheme == HostingScheme.HttpAndHttps)
|
if (HostingScheme == HostingScheme.HttpAndHttps)
|
||||||
{
|
{
|
||||||
var httpPort = Port > 0 ? Port.Value : FindFreeTcpPort();
|
var httpPort = Port > 0 ? Port.Value : FindFreeTcpPort();
|
||||||
list.Add(new HostUrlDetails { IsHttps = false, IsHttp2 = UseHttp2 == true, Url = $"http://{Star}:{httpPort}", Scheme = "http", Host = Star, Port = httpPort });
|
list.Add(new HostUrlDetails { IsHttps = false, IsHttp2 = UseHttp2 == true, Url = $"http://{Star}:{httpPort}", Scheme = "http", Host = Star, Port = httpPort });
|
||||||
|
|
||||||
var httpsPort = FindFreeTcpPort(); // In this scenario, always get a free port for https.
|
var httpsPort = FindFreeTcpPort(); // In this scenario, always get a free port for https.
|
||||||
list.Add(new HostUrlDetails { IsHttps = true, IsHttp2 = UseHttp2 == true, Url = $"https://{Star}:{httpsPort}", Scheme = "https", Host = Star, Port = httpsPort });
|
list.Add(new HostUrlDetails { IsHttps = true, IsHttp2 = UseHttp2 == true, Url = $"https://{Star}:{httpsPort}", Scheme = "https", Host = Star, Port = httpsPort });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
foreach (var url in Urls)
|
foreach (var url in Urls)
|
||||||
{
|
{
|
||||||
if (PortUtils.TryExtract(url, out var isHttps, out var isGrpc, out var protocol, out var host, out var port))
|
if (PortUtils.TryExtract(url, out var isHttps, out var isGrpc, out var protocol, out var host, out var port))
|
||||||
{
|
{
|
||||||
list.Add(new HostUrlDetails { IsHttps = isHttps, IsHttp2 = isGrpc, Url = url, Scheme = protocol, Host = host, Port = port });
|
list.Add(new HostUrlDetails { IsHttps = isHttps, IsHttp2 = isGrpc, Url = url, Scheme = protocol, Host = host, Port = port });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int FindFreeTcpPort()
|
private static int FindFreeTcpPort()
|
||||||
{
|
{
|
||||||
#if USE_ASPNETCORE || NETSTANDARD2_0 || NETSTANDARD2_1
|
#if USE_ASPNETCORE || NETSTANDARD2_0 || NETSTANDARD2_1
|
||||||
return 0;
|
return 0;
|
||||||
#else
|
#else
|
||||||
return PortUtils.FindFreeTcpPort();
|
return PortUtils.FindFreeTcpPort();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
// Copyright © WireMock.Net
|
// Copyright © WireMock.Net
|
||||||
|
|
||||||
namespace WireMock.Owin;
|
namespace WireMock.Owin;
|
||||||
|
|
||||||
internal interface IMappingMatcher
|
internal interface IMappingMatcher
|
||||||
{
|
{
|
||||||
(MappingMatcherResult? Match, MappingMatcherResult? Partial) FindBestMatch(RequestMessage request);
|
(MappingMatcherResult? Match, MappingMatcherResult? Partial) FindBestMatch(RequestMessage request);
|
||||||
}
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user